aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ide.c14
-rw-r--r--drivers/block/sandbox.c6
-rw-r--r--drivers/clk/aspeed/clk_ast2600.c46
-rw-r--r--drivers/clk/clk_scmi.c3
-rw-r--r--drivers/clk/mpc83xx_clk.h4
-rw-r--r--drivers/core/device-remove.c9
-rw-r--r--drivers/core/device.c40
-rw-r--r--drivers/core/lists.c2
-rw-r--r--drivers/core/of_access.c3
-rw-r--r--drivers/core/of_extra.c12
-rw-r--r--drivers/core/ofnode.c26
-rw-r--r--drivers/core/read.c6
-rw-r--r--drivers/core/root.c7
-rw-r--r--drivers/core/uclass.c42
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/aspeed/Kconfig20
-rw-r--r--drivers/crypto/aspeed/Makefile2
-rw-r--r--drivers/crypto/aspeed/aspeed_acry.c190
-rw-r--r--drivers/crypto/aspeed/aspeed_hace.c381
-rw-r--r--drivers/crypto/hash/Kconfig8
-rw-r--r--drivers/ddr/fsl/Kconfig92
-rw-r--r--drivers/ddr/marvell/axp/ddr3_hw_training.h1
-rw-r--r--drivers/ddr/marvell/axp/ddr3_init.c40
-rw-r--r--drivers/ddr/marvell/axp/ddr3_init.h3
-rw-r--r--drivers/ddr/marvell/axp/ddr3_spd.c16
-rw-r--r--drivers/firmware/scmi/Kconfig28
-rw-r--r--drivers/firmware/scmi/Makefile5
-rw-r--r--drivers/firmware/scmi/mailbox_agent.c16
-rw-r--r--drivers/firmware/scmi/optee_agent.c312
-rw-r--r--drivers/firmware/scmi/smccc_agent.c16
-rw-r--r--drivers/gpio/Kconfig5
-rw-r--r--drivers/i2c/fsl_i2c.c4
-rw-r--r--drivers/input/Kconfig9
-rw-r--r--drivers/misc/Kconfig5
-rw-r--r--drivers/misc/fsl_portals.c10
-rw-r--r--drivers/mmc/mmc-uclass.c4
-rw-r--r--drivers/mmc/mtk-sd.c15
-rw-r--r--drivers/mmc/sandbox_mmc.c60
-rw-r--r--drivers/mmc/stm32_sdmmc2.c63
-rw-r--r--drivers/mtd/nand/raw/Kconfig40
-rw-r--r--drivers/mtd/nand/raw/davinci_nand.c2
-rw-r--r--drivers/mtd/nand/raw/nand.c4
-rw-r--r--drivers/mtd/spi/Kconfig2
-rw-r--r--drivers/net/Kconfig24
-rw-r--r--drivers/net/Makefile77
-rw-r--r--drivers/net/aspeed_mdio.c128
-rw-r--r--drivers/net/bnxt/Kconfig7
-rw-r--r--drivers/net/bnxt/Makefile5
-rw-r--r--drivers/net/bnxt/bnxt.c1708
-rw-r--r--drivers/net/bnxt/bnxt.h390
-rw-r--r--drivers/net/bnxt/bnxt_dbg.h536
-rw-r--r--drivers/net/bnxt/bnxt_hsi.h889
-rw-r--r--drivers/net/fec_mxc.h2
-rw-r--r--drivers/net/fm/fm.c6
-rw-r--r--drivers/net/mscc_eswitch/felix_switch.c23
-rw-r--r--drivers/net/pfe_eth/Kconfig16
-rw-r--r--drivers/net/pfe_eth/pfe_firmware.c8
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/cortina.c8
-rw-r--r--drivers/net/phy/mscc.c56
-rw-r--r--drivers/net/phy/realtek.c69
-rw-r--r--drivers/net/sja1105.c3376
-rw-r--r--drivers/net/tsec.c22
-rw-r--r--drivers/pci/Kconfig6
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/fsl_pci_init.c936
-rw-r--r--drivers/pci/pci-aardvark.c15
-rw-r--r--drivers/pci/pci_mvebu.c28
-rw-r--r--drivers/pci/pcie_ecam_generic.c17
-rw-r--r--drivers/pci/pcie_ecam_synquacer.c6
-rw-r--r--drivers/pci/pcie_layerscape_fixup.c8
-rw-r--r--drivers/pci/pcie_layerscape_gen4_fixup.c8
-rw-r--r--drivers/pci/pcie_phytium.c8
-rw-r--r--drivers/pci/pcie_rockchip.c13
-rw-r--r--drivers/pci/pcie_xilinx.c5
-rw-r--r--drivers/phy/cadence/phy-cadence-torrent.c4
-rw-r--r--drivers/phy/marvell/comphy_a3700.c133
-rw-r--r--drivers/phy/marvell/comphy_core.c59
-rw-r--r--drivers/phy/marvell/comphy_core.h23
-rw-r--r--drivers/phy/marvell/comphy_cp110.c58
-rw-r--r--drivers/pinctrl/Kconfig20
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/aspeed/Makefile1
-rw-r--r--drivers/pinctrl/aspeed/pinctrl_ast2600.c459
-rw-r--r--drivers/pinctrl/pinctrl-apple.c207
-rw-r--r--drivers/pinctrl/pinctrl-stmfx.c4
-rw-r--r--drivers/power/regulator/scmi_regulator.c3
-rw-r--r--drivers/ram/stm32mp1/Makefile1
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.c69
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.h22
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr_regs.h66
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_interactive.c37
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ram.c217
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tests.h3
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tuning.c1540
-rw-r--r--drivers/reset/reset-scmi.c3
-rw-r--r--drivers/serial/arm_dcc.c2
-rw-r--r--drivers/serial/serial_efi.c11
-rw-r--r--drivers/serial/serial_lpuart.c7
-rw-r--r--drivers/serial/serial_mvebu_a3700.c1
-rw-r--r--drivers/spi/atmel-quadspi.c597
-rw-r--r--drivers/tee/optee/optee_msg.h12
-rw-r--r--drivers/timer/ostm_timer.c3
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c1
-rw-r--r--drivers/video/Kconfig11
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/cfb_console.c325
-rw-r--r--drivers/video/console_truetype.c21
-rw-r--r--drivers/video/sandbox_sdl.c77
-rw-r--r--drivers/video/stm32/stm32_ltdc.c5
-rw-r--r--drivers/video/u_boot_logo.bmpbin0 -> 6932 bytes
-rw-r--r--drivers/video/video-uclass.c49
-rw-r--r--drivers/video/video_bmp.c249
114 files changed, 10778 insertions, 3513 deletions
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index c99076c6f45..085aa356fee 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -45,10 +45,6 @@ struct blk_desc ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
-#ifndef CONFIG_SYS_ATA_PORT_ADDR
-#define CONFIG_SYS_ATA_PORT_ADDR(port) (port)
-#endif
-
#ifdef CONFIG_IDE_RESET
extern void ide_set_reset(int idereset);
@@ -678,8 +674,7 @@ static void ide_ident(struct blk_desc *dev_desc)
__weak void ide_outb(int dev, int port, unsigned char val)
{
debug("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n",
- dev, port, val,
- (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+ dev, port, val, ATA_CURR_BASE(dev) + port);
#if defined(CONFIG_IDE_AHB)
if (port) {
@@ -690,7 +685,7 @@ __weak void ide_outb(int dev, int port, unsigned char val)
outb(val, (ATA_CURR_BASE(dev)));
}
#else
- outb(val, (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+ outb(val, ATA_CURR_BASE(dev) + port);
#endif
}
@@ -701,12 +696,11 @@ __weak unsigned char ide_inb(int dev, int port)
#if defined(CONFIG_IDE_AHB)
val = ide_read_register(dev, port);
#else
- val = inb((ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+ val = inb(ATA_CURR_BASE(dev) + port);
#endif
debug("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n",
- dev, port,
- (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)), val);
+ dev, port, ATA_CURR_BASE(dev) + port, val);
return val;
}
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 1c2c3b4f886..53925ce9b69 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -19,11 +19,11 @@
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_BLK
-static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
+static struct host_block_dev host_devices[SANDBOX_HOST_MAX_DEVICES];
static struct host_block_dev *find_host_device(int dev)
{
- if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
+ if (dev >= 0 && dev < SANDBOX_HOST_MAX_DEVICES)
return &host_devices[dev];
return NULL;
@@ -259,7 +259,7 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
U_BOOT_LEGACY_BLK(sandbox_host) = {
.if_typename = "host",
.if_type = IF_TYPE_HOST,
- .max_devs = CONFIG_HOST_MAX_DEVICES,
+ .max_devs = SANDBOX_HOST_MAX_DEVICES,
.get_dev = host_get_dev_err,
};
#endif
diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c
index 3a92739f5cf..42ca39421cf 100644
--- a/drivers/clk/aspeed/clk_ast2600.c
+++ b/drivers/clk/aspeed/clk_ast2600.c
@@ -1013,6 +1013,46 @@ static ulong ast2600_enable_usbbhclk(struct ast2600_scu *scu)
return 0;
}
+static ulong ast2600_enable_haceclk(struct ast2600_scu *scu)
+{
+ uint32_t reset_bit;
+ uint32_t clkgate_bit;
+
+ /* share the same reset control bit with ACRY */
+ reset_bit = BIT(ASPEED_RESET_HACE);
+ clkgate_bit = SCU_CLKGATE1_HACE;
+
+ /*
+ * we don't do reset assertion here as HACE
+ * shares the same reset control with ACRY
+ */
+ writel(clkgate_bit, &scu->clkgate_clr1);
+ mdelay(20);
+ writel(reset_bit, &scu->modrst_clr1);
+
+ return 0;
+}
+
+static ulong ast2600_enable_rsaclk(struct ast2600_scu *scu)
+{
+ uint32_t reset_bit;
+ uint32_t clkgate_bit;
+
+ /* same reset control bit with HACE */
+ reset_bit = BIT(ASPEED_RESET_HACE);
+ clkgate_bit = SCU_CLKGATE1_ACRY;
+
+ /*
+ * we don't do reset assertion here as HACE
+ * shares the same reset control with ACRY
+ */
+ writel(clkgate_bit, &scu->clkgate_clr1);
+ mdelay(20);
+ writel(reset_bit, &scu->modrst_clr1);
+
+ return 0;
+}
+
static int ast2600_clk_enable(struct clk *clk)
{
struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
@@ -1051,6 +1091,12 @@ static int ast2600_clk_enable(struct clk *clk)
case ASPEED_CLK_GATE_USBPORT2CLK:
ast2600_enable_usbbhclk(priv->scu);
break;
+ case ASPEED_CLK_GATE_YCLK:
+ ast2600_enable_haceclk(priv->scu);
+ break;
+ case ASPEED_CLK_GATE_RSACLK:
+ ast2600_enable_rsaclk(priv->scu);
+ break;
default:
pr_err("can't enable clk\n");
return -ENOENT;
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index 93a4819501c..9a0a6f66434 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_CLK
+
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
diff --git a/drivers/clk/mpc83xx_clk.h b/drivers/clk/mpc83xx_clk.h
index 8a31a4c868f..c06a51ecd43 100644
--- a/drivers/clk/mpc83xx_clk.h
+++ b/drivers/clk/mpc83xx_clk.h
@@ -317,7 +317,7 @@ static inline u32 get_pci_sync_in(immap_t *im)
u8 clkin_div;
clkin_div = (get_spmr(im) & SPMR_CKID) >> SPMR_CKID_SHIFT;
- return CONFIG_SYS_CLK_FREQ / (1 + clkin_div);
+ return get_board_sys_clk() / (1 + clkin_div);
}
/**
@@ -331,7 +331,7 @@ static inline u32 get_csb_clk(immap_t *im)
u8 spmf;
spmf = (get_spmr(im) & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
- return CONFIG_SYS_CLK_FREQ * spmf;
+ return get_board_sys_clk() * spmf;
}
/**
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 11d3959d20f..69c50da44a9 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev)
if (ret)
return log_msg_ret("child unbind", ret);
+ ret = uclass_pre_unbind_device(dev);
+ if (ret)
+ return log_msg_ret("uc", ret);
if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
free(dev_get_plat(dev));
dev_set_plat(dev, NULL);
@@ -142,10 +145,8 @@ void device_free(struct udevice *dev)
}
if (dev->parent) {
size = dev->parent->driver->per_child_auto;
- if (!size) {
- size = dev->parent->uclass->uc_drv->
- per_child_auto;
- }
+ if (!size)
+ size = dev->parent->uclass->uc_drv->per_child_auto;
if (size) {
free(dev_get_parent_priv(dev));
dev_set_parent_priv(dev, NULL);
diff --git a/drivers/core/device.c b/drivers/core/device.c
index efd07176e37..4873c47d10b 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -533,8 +533,12 @@ int device_probe(struct udevice *dev)
* is set just above. However, the PCI bus' probe() method and
* associated uclass methods have not yet been called.
*/
- if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
- pinctrl_select_state(dev, "default");
+ if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) {
+ ret = pinctrl_select_state(dev, "default");
+ if (ret && ret != -ENOSYS)
+ log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n",
+ dev->name, ret, errno_str(ret));
+ }
if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
(device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) &&
@@ -586,8 +590,12 @@ int device_probe(struct udevice *dev)
if (ret)
goto fail_uclass;
- if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
- pinctrl_select_state(dev, "default");
+ if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) {
+ ret = pinctrl_select_state(dev, "default");
+ if (ret && ret != -ENOSYS)
+ log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n",
+ dev->name, ret, errno_str(ret));
+ }
return 0;
fail_uclass:
@@ -731,6 +739,17 @@ int device_get_child_count(const struct udevice *parent)
return count;
}
+int device_get_decendent_count(const struct udevice *parent)
+{
+ const struct udevice *dev;
+ int count = 1;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node)
+ count += device_get_decendent_count(dev);
+
+ return count;
+}
+
int device_find_child_by_seq(const struct udevice *parent, int seq,
struct udevice **devp)
{
@@ -902,15 +921,16 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
return -ENODEV;
}
-int device_find_child_by_name(const struct udevice *parent, const char *name,
- struct udevice **devp)
+int device_find_child_by_namelen(const struct udevice *parent, const char *name,
+ int len, struct udevice **devp)
{
struct udevice *dev;
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
- if (!strcmp(dev->name, name)) {
+ if (!strncmp(dev->name, name, len) &&
+ strlen(dev->name) == len) {
*devp = dev;
return 0;
}
@@ -919,6 +939,12 @@ int device_find_child_by_name(const struct udevice *parent, const char *name,
return -ENODEV;
}
+int device_find_child_by_name(const struct udevice *parent, const char *name,
+ struct udevice **devp)
+{
+ return device_find_child_by_namelen(parent, name, strlen(name), devp);
+}
+
int device_first_child_err(struct udevice *parent, struct udevice **devp)
{
struct udevice *dev;
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 5d4f2ea0e3a..d2e9dc5719b 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -58,7 +58,7 @@ static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only)
const int n_ents = ll_entry_count(struct driver_info, driver_info);
bool missing_parent = false;
int result = 0;
- uint idx;
+ int idx;
/*
* Do one iteration through the driver_info records. For of-platdata,
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 9960e6b310b..3707143ae66 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -581,7 +581,8 @@ int of_property_match_string(const struct device_node *np, const char *propname,
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
- * @skip: Number of strings to skip over at beginning of list.
+ * @skip: Number of strings to skip over at beginning of list (cannot be
+ * negative)
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.
diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c
index 632a1c2210e..59ce9174ad0 100644
--- a/drivers/core/of_extra.c
+++ b/drivers/core/of_extra.c
@@ -155,3 +155,15 @@ bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node)
return true;
}
+
+bool ofnode_eth_uses_inband_aneg(ofnode eth_node)
+{
+ bool inband_aneg = false;
+ const char *managed;
+
+ managed = ofnode_read_string(eth_node, "managed");
+ if (managed && !strcmp(managed, "in-band-status"))
+ inband_aneg = true;
+
+ return inband_aneg;
+}
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 08705ef8d99..709bea272a6 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -456,6 +456,32 @@ int ofnode_read_string_count(ofnode node, const char *property)
}
}
+int ofnode_read_string_list(ofnode node, const char *property,
+ const char ***listp)
+{
+ const char **prop;
+ int count;
+ int i;
+
+ *listp = NULL;
+ count = ofnode_read_string_count(node, property);
+ if (count < 0)
+ return count;
+ if (!count)
+ return 0;
+
+ prop = calloc(count + 1, sizeof(char *));
+ if (!prop)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++)
+ ofnode_read_string_index(node, property, i, &prop[i]);
+ prop[count] = NULL;
+ *listp = prop;
+
+ return count;
+}
+
static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
struct ofnode_phandle_args *out)
{
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 4307ca45799..31f9e78a062 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -205,6 +205,12 @@ int dev_read_string_count(const struct udevice *dev, const char *propname)
return ofnode_read_string_count(dev_ofnode(dev), propname);
}
+int dev_read_string_list(const struct udevice *dev, const char *propname,
+ const char ***listp)
+{
+ return ofnode_read_string_list(dev_ofnode(dev), propname, listp);
+}
+
int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name,
const char *cells_name, int cell_count,
int index, struct ofnode_phandle_args *out_args)
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 26b8195faa3..815173f86eb 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -26,6 +26,7 @@
#include <dm/read.h>
#include <dm/root.h>
#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
#include <dm/util.h>
#include <linux/list.h>
@@ -407,6 +408,12 @@ int dm_init_and_scan(bool pre_reloc_only)
return 0;
}
+void dm_get_stats(int *device_countp, int *uclass_countp)
+{
+ *device_countp = device_get_decendent_count(gd->dm_root);
+ *uclass_countp = uclass_get_count();
+}
+
#ifdef CONFIG_ACPIGEN
static int root_acpi_get_name(const struct udevice *dev, char *out_name)
{
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index c5a50952fd0..336ea8d243d 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -180,20 +180,25 @@ void uclass_set_priv(struct uclass *uc, void *priv)
uc->priv_ = priv;
}
-enum uclass_id uclass_get_by_name(const char *name)
+enum uclass_id uclass_get_by_name_len(const char *name, int len)
{
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
- if (uc_drv && !strcmp(uc_drv->name, name))
+ if (uc_drv && !strncmp(uc_drv->name, name, len))
return i;
}
return UCLASS_INVALID;
}
+enum uclass_id uclass_get_by_name(const char *name)
+{
+ return uclass_get_by_name_len(name, strlen(name));
+}
+
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
{
struct udevice *iter;
@@ -638,6 +643,19 @@ int uclass_next_device_check(struct udevice **devp)
return device_probe(*devp);
}
+int uclass_get_count(void)
+{
+ const struct uclass *uc;
+ int count = 0;
+
+ if (gd->dm_root) {
+ list_for_each_entry(uc, gd->uclass_root, sibling_node)
+ count++;
+ }
+
+ return count;
+}
+
int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
struct udevice **devp)
{
@@ -682,7 +700,7 @@ err:
}
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
-int uclass_unbind_device(struct udevice *dev)
+int uclass_pre_unbind_device(struct udevice *dev)
{
struct uclass *uc;
int ret;
@@ -694,7 +712,13 @@ int uclass_unbind_device(struct udevice *dev)
return ret;
}
+ return 0;
+}
+
+int uclass_unbind_device(struct udevice *dev)
+{
list_del(&dev->uclass_node);
+
return 0;
}
#endif
@@ -783,6 +807,18 @@ int uclass_probe_all(enum uclass_id id)
return 0;
}
+int uclass_id_count(enum uclass_id id)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int count = 0;
+
+ uclass_id_foreach_dev(id, dev, uc)
+ count++;
+
+ return count;
+}
+
UCLASS_DRIVER(nop) = {
.id = UCLASS_NOP,
.name = "nop",
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 0082177c21f..675081ecd37 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -4,4 +4,6 @@ source drivers/crypto/hash/Kconfig
source drivers/crypto/fsl/Kconfig
+source drivers/crypto/aspeed/Kconfig
+
endmenu
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index e8bae43e3f0..6b762565a1f 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o
obj-y += rsa_mod_exp/
obj-y += fsl/
obj-y += hash/
+obj-y += aspeed/
diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig
new file mode 100644
index 00000000000..9bf317177aa
--- /dev/null
+++ b/drivers/crypto/aspeed/Kconfig
@@ -0,0 +1,20 @@
+config ASPEED_HACE
+ bool "ASPEED Hash and Crypto Engine"
+ depends on DM_HASH
+ help
+ Select this option to enable a driver for using the SHA engine in
+ the ASPEED BMC SoCs.
+
+ Enabling this allows the use of SHA operations in hardware without
+ requiring the SHA software implementations. It also improves performance
+ and saves code size.
+
+config ASPEED_ACRY
+ bool "ASPEED RSA and ECC Engine"
+ depends on ASPEED_AST2600
+ help
+ Select this option to enable a driver for using the RSA/ECC engine in
+ the ASPEED BMC SoCs.
+
+ Enabling this allows the use of RSA/ECC operations in hardware without requiring the
+ software implementations. It also improves performance and saves code size.
diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile
new file mode 100644
index 00000000000..58b55fc46e4
--- /dev/null
+++ b/drivers/crypto/aspeed/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o
+obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o
diff --git a/drivers/crypto/aspeed/aspeed_acry.c b/drivers/crypto/aspeed/aspeed_acry.c
new file mode 100644
index 00000000000..c28cdf374b6
--- /dev/null
+++ b/drivers/crypto/aspeed/aspeed_acry.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 ASPEED Technology Inc.
+ */
+#include <config.h>
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/fdtaddr.h>
+#include <linux/delay.h>
+#include <u-boot/rsa-mod-exp.h>
+
+/* ACRY register offsets */
+#define ACRY_CTRL1 0x00
+#define ACRY_CTRL1_RSA_DMA BIT(1)
+#define ACRY_CTRL1_RSA_START BIT(0)
+#define ACRY_CTRL2 0x44
+#define ACRY_CTRL3 0x48
+#define ACRY_CTRL3_SRAM_AHB_ACCESS BIT(8)
+#define ACRY_CTRL3_ECC_RSA_MODE_MASK GENMASK(5, 4)
+#define ACRY_CTRL3_ECC_RSA_MODE_SHIFT 4
+#define ACRY_DMA_DRAM_SADDR 0x4c
+#define ACRY_DMA_DMEM_TADDR 0x50
+#define ACRY_DMA_DMEM_TADDR_LEN_MASK GENMASK(15, 0)
+#define ACRY_DMA_DMEM_TADDR_LEN_SHIFT 0
+#define ACRY_RSA_PARAM 0x58
+#define ACRY_RSA_PARAM_EXP_MASK GENMASK(31, 16)
+#define ACRY_RSA_PARAM_EXP_SHIFT 16
+#define ACRY_RSA_PARAM_MOD_MASK GENMASK(15, 0)
+#define ACRY_RSA_PARAM_MOD_SHIFT 0
+#define ACRY_RSA_INT_EN 0x3f8
+#define ACRY_RSA_INT_EN_RSA_READY BIT(2)
+#define ACRY_RSA_INT_EN_RSA_CMPLT BIT(1)
+#define ACRY_RSA_INT_STS 0x3fc
+#define ACRY_RSA_INT_STS_RSA_READY BIT(2)
+#define ACRY_RSA_INT_STS_RSA_CMPLT BIT(1)
+
+/* misc. constant */
+#define ACRY_ECC_MODE 2
+#define ACRY_RSA_MODE 3
+#define ACRY_CTX_BUFSZ 0x600
+
+struct aspeed_acry {
+ phys_addr_t base;
+ phys_addr_t sram_base; /* internal sram */
+ struct clk clk;
+};
+
+static int aspeed_acry_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+ struct key_prop *prop, uint8_t *out)
+{
+ int i, j;
+ u8 *ctx;
+ u8 *ptr;
+ u32 reg;
+ struct aspeed_acry *acry = dev_get_priv(dev);
+
+ ctx = memalign(16, ACRY_CTX_BUFSZ);
+ if (!ctx)
+ return -ENOMEM;
+
+ memset(ctx, 0, ACRY_CTX_BUFSZ);
+
+ ptr = (u8 *)prop->public_exponent;
+ for (i = prop->exp_len - 1, j = 0; i >= 0; --i) {
+ ctx[j] = ptr[i];
+ j++;
+ j = (j % 16) ? j : j + 32;
+ }
+
+ ptr = (u8 *)prop->modulus;
+ for (i = (prop->num_bits >> 3) - 1, j = 0; i >= 0; --i) {
+ ctx[j + 16] = ptr[i];
+ j++;
+ j = (j % 16) ? j : j + 32;
+ }
+
+ ptr = (u8 *)sig;
+ for (i = sig_len - 1, j = 0; i >= 0; --i) {
+ ctx[j + 32] = ptr[i];
+ j++;
+ j = (j % 16) ? j : j + 32;
+ }
+
+ writel((u32)ctx, acry->base + ACRY_DMA_DRAM_SADDR);
+
+ reg = (((prop->exp_len << 3) << ACRY_RSA_PARAM_EXP_SHIFT) & ACRY_RSA_PARAM_EXP_MASK) |
+ ((prop->num_bits << ACRY_RSA_PARAM_MOD_SHIFT) & ACRY_RSA_PARAM_MOD_MASK);
+ writel(reg, acry->base + ACRY_RSA_PARAM);
+
+ reg = (ACRY_CTX_BUFSZ << ACRY_DMA_DMEM_TADDR_LEN_SHIFT) & ACRY_DMA_DMEM_TADDR_LEN_MASK;
+ writel(reg, acry->base + ACRY_DMA_DMEM_TADDR);
+
+ reg = (ACRY_RSA_MODE << ACRY_CTRL3_ECC_RSA_MODE_SHIFT) & ACRY_CTRL3_ECC_RSA_MODE_MASK;
+ writel(reg, acry->base + ACRY_CTRL3);
+
+ writel(ACRY_CTRL1_RSA_DMA | ACRY_CTRL1_RSA_START, acry->base + ACRY_CTRL1);
+
+ /* polling RSA status */
+ while (1) {
+ reg = readl(acry->base + ACRY_RSA_INT_STS);
+ if ((reg & ACRY_RSA_INT_STS_RSA_READY) && (reg & ACRY_RSA_INT_STS_RSA_CMPLT)) {
+ writel(reg, ACRY_RSA_INT_STS);
+ break;
+ }
+ udelay(20);
+ }
+
+ /* grant SRAM access permission to CPU */
+ writel(0x0, acry->base + ACRY_CTRL1);
+ writel(ACRY_CTRL3_SRAM_AHB_ACCESS, acry->base + ACRY_CTRL3);
+ udelay(20);
+
+ for (i = (prop->num_bits / 8) - 1, j = 0; i >= 0; --i) {
+ out[i] = readb(acry->sram_base + (j + 32));
+ j++;
+ j = (j % 16) ? j : j + 32;
+ }
+
+ /* return SRAM access permission to ACRY */
+ writel(0, acry->base + ACRY_CTRL3);
+
+ free(ctx);
+
+ return 0;
+}
+
+static int aspeed_acry_probe(struct udevice *dev)
+{
+ struct aspeed_acry *acry = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &acry->clk);
+ if (ret < 0) {
+ debug("Can't get clock for %s: %d\n", dev->name, ret);
+ return ret;
+ }
+
+ ret = clk_enable(&acry->clk);
+ if (ret) {
+ debug("Failed to enable acry clock (%d)\n", ret);
+ return ret;
+ }
+
+ acry->base = devfdt_get_addr_index(dev, 0);
+ if (acry->base == FDT_ADDR_T_NONE) {
+ debug("Failed to get acry base\n");
+ return acry->base;
+ }
+
+ acry->sram_base = devfdt_get_addr_index(dev, 1);
+ if (acry->sram_base == FDT_ADDR_T_NONE) {
+ debug("Failed to get acry SRAM base\n");
+ return acry->sram_base;
+ }
+
+ return ret;
+}
+
+static int aspeed_acry_remove(struct udevice *dev)
+{
+ struct aspeed_acry *acry = dev_get_priv(dev);
+
+ clk_disable(&acry->clk);
+
+ return 0;
+}
+
+static const struct mod_exp_ops aspeed_acry_ops = {
+ .mod_exp = aspeed_acry_mod_exp,
+};
+
+static const struct udevice_id aspeed_acry_ids[] = {
+ { .compatible = "aspeed,ast2600-acry" },
+ { }
+};
+
+U_BOOT_DRIVER(aspeed_acry) = {
+ .name = "aspeed_acry",
+ .id = UCLASS_MOD_EXP,
+ .of_match = aspeed_acry_ids,
+ .probe = aspeed_acry_probe,
+ .remove = aspeed_acry_remove,
+ .priv_auto = sizeof(struct aspeed_acry),
+ .ops = &aspeed_acry_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/crypto/aspeed/aspeed_hace.c b/drivers/crypto/aspeed/aspeed_hace.c
new file mode 100644
index 00000000000..1178cc6a769
--- /dev/null
+++ b/drivers/crypto/aspeed/aspeed_hace.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 ASPEED Technology Inc.
+ */
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <log.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <u-boot/hash.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/iopoll.h>
+
+/* register offsets*/
+#define HACE_STS 0x1C
+#define HACE_HASH_DATA_OVF BIT(23)
+#define HACE_HASH_INT BIT(9)
+#define HACE_HASH_BUSY BIT(0)
+#define HACE_HASH_DATA 0x20
+#define HACE_HASH_DIGEST 0x24
+#define HACE_HASH_HMAC_KEY 0x28
+#define HACE_HASH_DATA_LEN 0x2C
+#define HACE_HASH_CMD 0x30
+#define HACE_HASH_MODE_ACCUM BIT(8)
+#define HACE_HASH_ALGO_SHA1 BIT(5)
+#define HACE_HASH_ALGO_SHA256 (BIT(6) | BIT(4))
+#define HACE_HASH_ALGO_SHA384 (BIT(10) | BIT(6) | BIT(5))
+#define HACE_HASH_ALGO_SHA512 (BIT(6) | BIT(5))
+#define HACE_HASH_SHA_BE_EN BIT(3)
+
+/* buffer size based on SHA-512 need*/
+#define HASH_BLOCK_BUFSZ 128
+#define HASH_DIGEST_BUFSZ 64
+
+struct aspeed_hace_ctx {
+ uint8_t digest[HASH_DIGEST_BUFSZ];
+
+ uint32_t cmd;
+ enum HASH_ALGO algo;
+
+ uint32_t blk_size;
+ uint32_t pad_size;
+ uint64_t total[2];
+
+ uint8_t buf[HASH_BLOCK_BUFSZ];
+ uint32_t buf_cnt;
+} __aligned((8));
+
+struct aspeed_hace {
+ phys_addr_t base;
+ struct clk clk;
+};
+
+static const uint32_t iv_sha1[8] = {
+ 0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
+ 0xf0e1d2c3, 0, 0, 0
+};
+
+static const uint32_t iv_sha256[8] = {
+ 0x67e6096a, 0x85ae67bb, 0x72f36e3c, 0x3af54fa5,
+ 0x7f520e51, 0x8c68059b, 0xabd9831f, 0x19cde05bUL
+};
+
+static const uint32_t iv_sha384[16] = {
+ 0x5d9dbbcb, 0xd89e05c1, 0x2a299a62, 0x07d57c36,
+ 0x5a015991, 0x17dd7030, 0xd8ec2f15, 0x39590ef7,
+ 0x67263367, 0x310bc0ff, 0x874ab48e, 0x11155868,
+ 0x0d2e0cdb, 0xa78ff964, 0x1d48b547, 0xa44ffabeUL
+};
+
+static const uint32_t iv_sha512[16] = {
+ 0x67e6096a, 0x08c9bcf3, 0x85ae67bb, 0x3ba7ca84,
+ 0x72f36e3c, 0x2bf894fe, 0x3af54fa5, 0xf1361d5f,
+ 0x7f520e51, 0xd182e6ad, 0x8c68059b, 0x1f6c3e2b,
+ 0xabd9831f, 0x6bbd41fb, 0x19cde05b, 0x79217e13UL
+};
+
+static int aspeed_hace_wait_completion(uint32_t reg, uint32_t flag, int timeout_us)
+{
+ uint32_t val;
+
+ return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us);
+}
+
+static int aspeed_hace_process(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
+{
+ struct aspeed_hace *hace = dev_get_priv(dev);
+ struct aspeed_hace_ctx *hace_ctx = (struct aspeed_hace_ctx *)ctx;
+ uint32_t sts = readl(hace->base + HACE_STS);
+
+ if (sts & HACE_HASH_BUSY) {
+ debug("HACE engine busy\n");
+ return -EBUSY;
+ }
+
+ writel(HACE_HASH_INT, hace->base + HACE_STS);
+
+ writel((uint32_t)ibuf, hace->base + HACE_HASH_DATA);
+ writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_DIGEST);
+ writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_HMAC_KEY);
+ writel(ilen, hace->base + HACE_HASH_DATA_LEN);
+ writel(hace_ctx->cmd, hace->base + HACE_HASH_CMD);
+
+ return aspeed_hace_wait_completion(hace->base + HACE_STS,
+ HACE_HASH_INT,
+ 1000 + (ilen >> 3));
+}
+
+static int aspeed_hace_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
+{
+ struct aspeed_hace_ctx *hace_ctx;
+
+ hace_ctx = memalign(8, sizeof(struct aspeed_hace_ctx));
+ if (!hace_ctx)
+ return -ENOMEM;
+
+ memset(hace_ctx, 0, sizeof(struct aspeed_hace_ctx));
+
+ hace_ctx->algo = algo;
+ hace_ctx->cmd = HACE_HASH_MODE_ACCUM | HACE_HASH_SHA_BE_EN;
+
+ switch (algo) {
+ case HASH_ALGO_SHA1:
+ hace_ctx->blk_size = 64;
+ hace_ctx->pad_size = 8;
+ hace_ctx->cmd |= HACE_HASH_ALGO_SHA1;
+ memcpy(hace_ctx->digest, iv_sha1, sizeof(iv_sha1));
+ break;
+ case HASH_ALGO_SHA256:
+ hace_ctx->blk_size = 64;
+ hace_ctx->pad_size = 8;
+ hace_ctx->cmd |= HACE_HASH_ALGO_SHA256;
+ memcpy(hace_ctx->digest, iv_sha256, sizeof(iv_sha256));
+ break;
+ case HASH_ALGO_SHA384:
+ hace_ctx->blk_size = 128;
+ hace_ctx->pad_size = 16;
+ hace_ctx->cmd |= HACE_HASH_ALGO_SHA384;
+ memcpy(hace_ctx->digest, iv_sha384, sizeof(iv_sha384));
+ break;
+ case HASH_ALGO_SHA512:
+ hace_ctx->blk_size = 128;
+ hace_ctx->pad_size = 16;
+ hace_ctx->cmd |= HACE_HASH_ALGO_SHA512;
+ memcpy(hace_ctx->digest, iv_sha512, sizeof(iv_sha512));
+ break;
+ default:
+ debug("Unsupported hash algorithm '%s'\n", hash_algo_name(algo));
+ goto free_n_out;
+ };
+
+ *ctxp = hace_ctx;
+
+ return 0;
+
+free_n_out:
+ free(hace_ctx);
+
+ return -EINVAL;
+}
+
+static int aspeed_hace_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
+{
+ int rc;
+ uint32_t left, fill;
+ struct aspeed_hace_ctx *hace_ctx = ctx;
+
+ left = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
+ fill = hace_ctx->blk_size - left;
+
+ hace_ctx->total[0] += ilen;
+ if (hace_ctx->total[0] < ilen)
+ hace_ctx->total[1]++;
+
+ if (left && ilen >= fill) {
+ memcpy(hace_ctx->buf + left, ibuf, fill);
+ rc = aspeed_hace_process(dev, ctx, hace_ctx->buf, hace_ctx->blk_size);
+ if (rc) {
+ debug("failed to process hash, rc=%d\n", rc);
+ return rc;
+ }
+ ilen -= fill;
+ ibuf += fill;
+ left = 0;
+ }
+
+ while (ilen >= hace_ctx->blk_size) {
+ rc = aspeed_hace_process(dev, ctx, ibuf, hace_ctx->blk_size);
+ if (rc) {
+ debug("failed to process hash, rc=%d\n", rc);
+ return rc;
+ }
+
+ ibuf += hace_ctx->blk_size;
+ ilen -= hace_ctx->blk_size;
+ }
+
+ if (ilen)
+ memcpy(hace_ctx->buf + left, ibuf, ilen);
+
+ return 0;
+}
+
+static int aspeed_hace_finish(struct udevice *dev, void *ctx, void *obuf)
+{
+ int rc = 0;
+ uint8_t pad[HASH_BLOCK_BUFSZ * 2];
+ uint32_t last, padn;
+ uint64_t ibits_h, ibits_l;
+ uint64_t ibits_be_h, ibits_be_l;
+ struct aspeed_hace_ctx *hace_ctx = ctx;
+
+ memset(pad, 0, sizeof(pad));
+ pad[0] = 0x80;
+
+ ibits_h = (hace_ctx->total[0] >> 61) | (hace_ctx->total[1] << 3);
+ ibits_be_h = cpu_to_be64(ibits_h);
+
+ ibits_l = (hace_ctx->total[0] << 3);
+ ibits_be_l = cpu_to_be64(ibits_l);
+
+ last = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
+
+ switch (hace_ctx->algo) {
+ case HASH_ALGO_SHA1:
+ case HASH_ALGO_SHA256:
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ rc = aspeed_hace_update(dev, ctx, pad, padn);
+ if (rc) {
+ debug("failed to append padding, rc=%d\n", rc);
+ goto free_n_out;
+ }
+
+ rc = aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
+ if (rc) {
+ debug("failed to append message bits length, rc=%d\n", rc);
+ goto free_n_out;
+ }
+
+ break;
+ case HASH_ALGO_SHA384:
+ case HASH_ALGO_SHA512:
+ padn = (last < 112) ? (112 - last) : (240 - last);
+
+ rc = aspeed_hace_update(dev, ctx, pad, padn);
+ if (rc) {
+ debug("failed to append padding, rc=%d\n", rc);
+ goto free_n_out;
+ }
+
+ rc = aspeed_hace_update(dev, ctx, &ibits_be_h, sizeof(ibits_be_h)) |
+ aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
+ if (rc) {
+ debug("failed to append message bits length, rc=%d\n", rc);
+ goto free_n_out;
+ }
+
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ memcpy(obuf, hace_ctx->digest, hash_algo_digest_size(hace_ctx->algo));
+
+free_n_out:
+ free(ctx);
+
+ return rc;
+}
+
+static int aspeed_hace_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
+ const void *ibuf, const uint32_t ilen,
+ void *obuf, uint32_t chunk_sz)
+{
+ int rc;
+ void *ctx;
+ const void *cur, *end;
+ uint32_t chunk;
+
+ rc = aspeed_hace_init(dev, algo, &ctx);
+ if (rc)
+ return rc;
+
+ if (CONFIG_IS_ENABLED(HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
+ cur = ibuf;
+ end = ibuf + ilen;
+
+ while (cur < end) {
+ chunk = end - cur;
+ if (chunk > chunk_sz)
+ chunk = chunk_sz;
+
+ rc = aspeed_hace_update(dev, ctx, cur, chunk);
+ if (rc)
+ return rc;
+
+ cur += chunk;
+ WATCHDOG_RESET();
+ }
+ } else {
+ rc = aspeed_hace_update(dev, ctx, ibuf, ilen);
+ if (rc)
+ return rc;
+ }
+
+ rc = aspeed_hace_finish(dev, ctx, obuf);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int aspeed_hace_digest(struct udevice *dev, enum HASH_ALGO algo,
+ const void *ibuf, const uint32_t ilen,
+ void *obuf)
+{
+ /* re-use the watchdog version with input length as the chunk_sz */
+ return aspeed_hace_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
+}
+
+static int aspeed_hace_probe(struct udevice *dev)
+{
+ int rc;
+ struct aspeed_hace *hace = dev_get_priv(dev);
+
+ rc = clk_get_by_index(dev, 0, &hace->clk);
+ if (rc < 0) {
+ debug("cannot get clock for %s: %d\n", dev->name, rc);
+ return rc;
+ }
+
+ rc = clk_enable(&hace->clk);
+ if (rc) {
+ debug("cannot enable clock for %s: %d\n", dev->name, rc);
+ return rc;
+ }
+
+ hace->base = devfdt_get_addr(dev);
+
+ return rc;
+}
+
+static int aspeed_hace_remove(struct udevice *dev)
+{
+ struct aspeed_hace *hace = dev_get_priv(dev);
+
+ clk_disable(&hace->clk);
+
+ return 0;
+}
+
+static const struct hash_ops aspeed_hace_ops = {
+ .hash_init = aspeed_hace_init,
+ .hash_update = aspeed_hace_update,
+ .hash_finish = aspeed_hace_finish,
+ .hash_digest_wd = aspeed_hace_digest_wd,
+ .hash_digest = aspeed_hace_digest,
+};
+
+static const struct udevice_id aspeed_hace_ids[] = {
+ { .compatible = "aspeed,ast2600-hace" },
+ { }
+};
+
+U_BOOT_DRIVER(aspeed_hace) = {
+ .name = "aspeed_hace",
+ .id = UCLASS_HASH,
+ .of_match = aspeed_hace_ids,
+ .ops = &aspeed_hace_ops,
+ .probe = aspeed_hace_probe,
+ .remove = aspeed_hace_remove,
+ .priv_auto = sizeof(struct aspeed_hace),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/crypto/hash/Kconfig b/drivers/crypto/hash/Kconfig
index cd29a5c6a4f..bf9540eca67 100644
--- a/drivers/crypto/hash/Kconfig
+++ b/drivers/crypto/hash/Kconfig
@@ -14,3 +14,11 @@ config HASH_SOFTWARE
help
Enable driver for hashing operations in software. Currently
it support multiple hash algorithm including CRC/MD5/SHA.
+
+config HASH_ASPEED
+ bool "Enable Hash with ASPEED hash accelerator"
+ depends on DM_HASH
+ select ASPEED_HACE
+ help
+ Enable this to support HW-assisted hashing operations using ASPEED Hash
+ and Crypto engine - HACE
diff --git a/drivers/ddr/fsl/Kconfig b/drivers/ddr/fsl/Kconfig
index fe3d6fc9700..b0e6df8be41 100644
--- a/drivers/ddr/fsl/Kconfig
+++ b/drivers/ddr/fsl/Kconfig
@@ -163,6 +163,98 @@ config ECC_INIT_VIA_DDRCONTROLLER
endif
+menu "PowerPC / M68K initial memory controller definitions (FLASH, SDRAM, etc)"
+ depends on MCF52x2 || MPC8xx || MPC83xx || MPC85xx
+
+config SYS_BR0_PRELIM_BOOL
+ bool "Define Bank 0"
+
+config SYS_BR0_PRELIM
+ hex "Preliminary value for BR0"
+ depends on SYS_BR0_PRELIM_BOOL
+
+config SYS_OR0_PRELIM
+ hex "Preliminary value for OR0"
+ depends on SYS_BR0_PRELIM_BOOL
+
+config SYS_BR1_PRELIM_BOOL
+ bool "Define Bank 1"
+
+config SYS_BR1_PRELIM
+ hex "Preliminary value for BR1"
+ depends on SYS_BR1_PRELIM_BOOL
+
+config SYS_OR1_PRELIM
+ hex "Preliminary value for OR1"
+ depends on SYS_BR1_PRELIM_BOOL
+
+config SYS_BR2_PRELIM_BOOL
+ bool "Define Bank 2"
+
+config SYS_BR2_PRELIM
+ hex "Preliminary value for BR2"
+ depends on SYS_BR2_PRELIM_BOOL
+
+config SYS_OR2_PRELIM
+ hex "Preliminary value for OR2"
+ depends on SYS_BR2_PRELIM_BOOL
+
+config SYS_BR3_PRELIM_BOOL
+ bool "Define Bank 3"
+
+config SYS_BR3_PRELIM
+ hex "Preliminary value for BR3"
+ depends on SYS_BR3_PRELIM_BOOL
+
+config SYS_OR3_PRELIM
+ hex "Preliminary value for OR3"
+ depends on SYS_BR3_PRELIM_BOOL
+
+config SYS_BR4_PRELIM_BOOL
+ bool "Define Bank 4"
+
+config SYS_BR4_PRELIM
+ hex "Preliminary value for BR4"
+ depends on SYS_BR4_PRELIM_BOOL
+
+config SYS_OR4_PRELIM
+ hex "Preliminary value for OR4"
+ depends on SYS_BR4_PRELIM_BOOL
+
+config SYS_BR5_PRELIM_BOOL
+ bool "Define Bank 5"
+
+config SYS_BR5_PRELIM
+ hex "Preliminary value for BR5"
+ depends on SYS_BR5_PRELIM_BOOL
+
+config SYS_OR5_PRELIM
+ hex "Preliminary value for OR5"
+ depends on SYS_BR5_PRELIM_BOOL
+
+config SYS_BR6_PRELIM_BOOL
+ bool "Define Bank 6"
+
+config SYS_BR6_PRELIM
+ hex "Preliminary value for BR6"
+ depends on SYS_BR6_PRELIM_BOOL
+
+config SYS_OR6_PRELIM
+ hex "Preliminary value for OR6"
+ depends on SYS_BR6_PRELIM_BOOL
+
+config SYS_BR7_PRELIM_BOOL
+ bool "Define Bank 7"
+
+config SYS_BR7_PRELIM
+ hex "Preliminary value for BR7"
+ depends on SYS_BR7_PRELIM_BOOL
+
+config SYS_OR7_PRELIM
+ hex "Preliminary value for OR7"
+ depends on SYS_BR7_PRELIM_BOOL
+endmenu
+
config SYS_FSL_ERRATUM_A008378
bool
diff --git a/drivers/ddr/marvell/axp/ddr3_hw_training.h b/drivers/ddr/marvell/axp/ddr3_hw_training.h
index 30daaa9831b..fcdef792c76 100644
--- a/drivers/ddr/marvell/axp/ddr3_hw_training.h
+++ b/drivers/ddr/marvell/axp/ddr3_hw_training.h
@@ -373,7 +373,6 @@ int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info);
void ddr3_static_training_init(void);
-u8 ddr3_get_eprom_fabric(void);
void ddr3_set_performance_params(MV_DRAM_INFO *dram_info);
int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len);
void ddr3_save_training(MV_DRAM_INFO *dram_info);
diff --git a/drivers/ddr/marvell/axp/ddr3_init.c b/drivers/ddr/marvell/axp/ddr3_init.c
index 607f3e12c3a..a9dcb74cecb 100644
--- a/drivers/ddr/marvell/axp/ddr3_init.c
+++ b/drivers/ddr/marvell/axp/ddr3_init.c
@@ -361,12 +361,18 @@ static u32 ddr3_init_main(void)
__maybe_unused u32 ddr_width = BUS_WIDTH;
__maybe_unused int status;
__maybe_unused u32 win_backup[16];
+ __maybe_unused struct udevice *udev;
+ __maybe_unused int ret;
/* SoC/Board special Initializtions */
fab_opt = ddr3_get_fab_opt();
#ifdef CONFIG_SPD_EEPROM
- i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ ret = i2c_get_chip_for_busnum(0, BUS_WIDTH_ECC_TWSI_ADDR, 1, &udev);
+ if (ret) {
+ printf("Cannot find SPD EEPROM\n");
+ return MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP;
+ }
#endif
ddr3_print_version();
@@ -438,7 +444,7 @@ static u32 ddr3_init_main(void)
#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
ecc = 0;
- if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_ECC))
+ if (ddr3_check_config(udev, CONFIG_ECC))
ecc = 1;
#endif
@@ -483,7 +489,7 @@ static u32 ddr3_init_main(void)
* Dynamically Set 32Bit and ECC for AXP (Relevant only for
* Marvell DB boards)
*/
- if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_BUS_WIDTH)) {
+ if (ddr3_check_config(udev, CONFIG_BUS_WIDTH)) {
ddr_width = 32;
DEBUG_INIT_S("DDR3 Training Sequence - DRAM bus width 32Bit\n");
}
@@ -904,7 +910,7 @@ void ddr3_static_mc_init(void)
* Notes: Only Available for ArmadaXP/Armada 370 DB boards
* Returns: None.
*/
-int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
+int ddr3_check_config(struct udevice *udev, MV_CONFIG_TYPE config_type)
{
#ifdef AUTO_DETECTION_SUPPORT
u8 data = 0;
@@ -916,7 +922,7 @@ int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
else
offset = 0;
- ret = i2c_read(twsi_addr, offset, 1, (u8 *)&data, 1);
+ ret = dm_i2c_read(udev, offset, &data, 1);
if (!ret) {
switch (config_type) {
case CONFIG_ECC:
@@ -943,30 +949,6 @@ int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
return 0;
}
-#if defined(DB_88F78X60_REV2)
-/*
- * Name: ddr3_get_eprom_fabric - Get Fabric configuration from EPROM
- * Desc:
- * Args: twsi Address
- * Notes: Only Available for ArmadaXP DB Rev2 boards
- * Returns: None.
- */
-u8 ddr3_get_eprom_fabric(void)
-{
-#ifdef AUTO_DETECTION_SUPPORT
- u8 data = 0;
- int ret;
-
- ret = i2c_read(NEW_FABRIC_TWSI_ADDR, 1, 1, (u8 *)&data, 1);
- if (!ret)
- return data & 0x1F;
-#endif
-
- return 0;
-}
-
-#endif
-
/*
* Name: ddr3_cl_to_valid_cl - this return register matching CL value
* Desc:
diff --git a/drivers/ddr/marvell/axp/ddr3_init.h b/drivers/ddr/marvell/axp/ddr3_init.h
index 569a14b7184..a26bd2a120e 100644
--- a/drivers/ddr/marvell/axp/ddr3_init.h
+++ b/drivers/ddr/marvell/axp/ddr3_init.h
@@ -98,11 +98,10 @@ int ddr3_hw_training(u32 target_freq, u32 ddr_width,
void ddr3_print_version(void);
void fix_pll_val(u8 target_fab);
-u8 ddr3_get_eprom_fabric(void);
u32 ddr3_get_fab_opt(void);
u32 ddr3_get_cpu_freq(void);
u32 ddr3_get_vco_freq(void);
-int ddr3_check_config(u32 addr, MV_CONFIG_TYPE config_type);
+int ddr3_check_config(struct udevice *udev, MV_CONFIG_TYPE config_type);
u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
u32 mask2);
u32 ddr3_cl_to_valid_cl(u32 cl);
diff --git a/drivers/ddr/marvell/axp/ddr3_spd.c b/drivers/ddr/marvell/axp/ddr3_spd.c
index dd772e63ab1..4763403c127 100644
--- a/drivers/ddr/marvell/axp/ddr3_spd.c
+++ b/drivers/ddr/marvell/axp/ddr3_spd.c
@@ -209,13 +209,19 @@ static u32 ddr3_get_dimm_num(u32 *dimm_addr)
/* Read the dimm eeprom */
for (dimm_cur_addr = MAX_DIMM_ADDR; dimm_cur_addr > MIN_DIMM_ADDR;
dimm_cur_addr--) {
+ struct udevice *udev;
+
data[SPD_DEV_TYPE_BYTE] = 0;
/* Far-End DIMM must be connected */
if ((dimm_num == 0) && (dimm_cur_addr < FAR_END_DIMM_ADDR))
return 0;
- ret = i2c_read(dimm_cur_addr, 0, 1, (uchar *)data, 3);
+ ret = i2c_get_chip_for_busnum(0, dimm_cur_addr, 1, &udev);
+ if (ret)
+ continue;
+
+ ret = dm_i2c_read(udev, 0, data, 3);
if (!ret) {
if (data[SPD_DEV_TYPE_BYTE] == SPD_MEM_TYPE_DDR3) {
dimm_addr[dimm_num] = dimm_cur_addr;
@@ -245,9 +251,15 @@ int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width)
__maybe_unused u8 vendor_high, vendor_low;
if (dimm_addr != 0) {
+ struct udevice *udev;
+
memset(spd_data, 0, SPD_SIZE * sizeof(u8));
- ret = i2c_read(dimm_addr, 0, 1, (uchar *)spd_data, SPD_SIZE);
+ ret = i2c_get_chip_for_busnum(0, dimm_addr, 1, &udev);
+ if (ret)
+ return MV_DDR3_TRAINING_ERR_TWSI_FAIL;
+
+ ret = dm_i2c_read(udev, 0, spd_data, SPD_SIZE);
if (ret)
return MV_DDR3_TRAINING_ERR_TWSI_FAIL;
}
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
index c3a109beac7..8cf85f0d7a1 100644
--- a/drivers/firmware/scmi/Kconfig
+++ b/drivers/firmware/scmi/Kconfig
@@ -2,7 +2,7 @@ config SCMI_FIRMWARE
bool "Enable SCMI support"
select FIRMWARE
select OF_TRANSLATE
- depends on SANDBOX || DM_MAILBOX || ARM_SMCCC
+ depends on SANDBOX || DM_MAILBOX || ARM_SMCCC || OPTEE
help
System Control and Management Interface (SCMI) is a communication
protocol that defines standard interfaces for power, performance
@@ -14,6 +14,30 @@ config SCMI_FIRMWARE
or a companion host in the CPU system.
Communications between agent (client) and the SCMI server are
- based on message exchange. Messages can be exchange over tranport
+ based on message exchange. Messages can be exchanged over transport
channels as a mailbox device or an Arm SMCCC service with some
piece of identified shared memory.
+
+config SCMI_AGENT_MAILBOX
+ bool "Enable SCMI agent mailbox"
+ depends on SCMI_FIRMWARE && DM_MAILBOX
+ default y
+ help
+ Enable the SCMI communication channel based on mailbox
+ for compatible "arm,scmi".
+
+config SCMI_AGENT_SMCCC
+ bool "Enable SCMI agent SMCCC"
+ depends on SCMI_FIRMWARE && ARM_SMCCC
+ default y
+ help
+ Enable the SCMI communication channel based on Arm SMCCC service for
+ compatible "arm,scmi-smc".
+
+config SCMI_AGENT_OPTEE
+ bool "Enable SCMI agent OP-TEE"
+ depends on SCMI_FIRMWARE && OPTEE
+ default y
+ help
+ Enable the SCMI communication channel based on OP-TEE transport
+ for compatible "linaro,scmi-optee".
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index 966475ec10a..b2ff483c75a 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -1,5 +1,6 @@
obj-y += scmi_agent-uclass.o
obj-y += smt.o
-obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o
-obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o
+obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o
+obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o
+obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o
obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
index ea35e7e09ed..8e4af0c8faf 100644
--- a/drivers/firmware/scmi/mailbox_agent.c
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -33,7 +33,7 @@ struct scmi_mbox_channel {
static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
- struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ struct scmi_mbox_channel *chan = dev_get_plat(dev);
int ret;
ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
@@ -62,9 +62,9 @@ out:
return ret;
}
-int scmi_mbox_probe(struct udevice *dev)
+int scmi_mbox_of_to_plat(struct udevice *dev)
{
- struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ struct scmi_mbox_channel *chan = dev_get_plat(dev);
int ret;
chan->timeout_us = TIMEOUT_US_10MS;
@@ -72,17 +72,13 @@ int scmi_mbox_probe(struct udevice *dev)
ret = mbox_get_by_index(dev, 0, &chan->mbox);
if (ret) {
dev_err(dev, "Failed to find mailbox: %d\n", ret);
- goto out;
+ return ret;
}
ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
if (ret)
dev_err(dev, "Failed to get shm resources: %d\n", ret);
-out:
- if (ret)
- devm_kfree(dev, chan);
-
return ret;
}
@@ -99,7 +95,7 @@ U_BOOT_DRIVER(scmi_mbox) = {
.name = "scmi-over-mailbox",
.id = UCLASS_SCMI_AGENT,
.of_match = scmi_mbox_ids,
- .priv_auto = sizeof(struct scmi_mbox_channel),
- .probe = scmi_mbox_probe,
+ .plat_auto = sizeof(struct scmi_mbox_channel),
+ .of_to_plat = scmi_mbox_of_to_plat,
.ops = &scmi_mbox_ops,
};
diff --git a/drivers/firmware/scmi/optee_agent.c b/drivers/firmware/scmi/optee_agent.c
new file mode 100644
index 00000000000..1f265922343
--- /dev/null
+++ b/drivers/firmware/scmi/optee_agent.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 Linaro Limited.
+ */
+
+#define LOG_CATEGORY UCLASS_SCMI_AGENT
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <string.h>
+#include <tee.h>
+#include <asm/types.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/arm-smccc.h>
+#include <linux/bug.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define SCMI_SHM_SIZE 128
+
+/**
+ * struct scmi_optee_channel - Description of an SCMI OP-TEE transport
+ * @channel_id: Channel identifier
+ * @smt: Shared memory buffer with synchronisation protocol
+ * @dyn_shm: True if using dynamically allocated shared memory
+ */
+struct scmi_optee_channel {
+ unsigned int channel_id;
+ struct scmi_smt smt;
+ bool dyn_shm;
+};
+
+/**
+ * struct channel_session - Aggreates SCMI service session context references
+ * @tee: OP-TEE device to invoke
+ * @tee_session: OP-TEE session identifier
+ * @tee_shm: Dynamically allocated OP-TEE shared memory, or NULL
+ * @channel_hdl: Channel handle provided by OP-TEE SCMI service
+ */
+struct channel_session {
+ struct udevice *tee;
+ u32 tee_session;
+ struct tee_shm *tee_shm;
+ u32 channel_hdl;
+};
+
+#define TA_SCMI_UUID { 0xa8cfe406, 0xd4f5, 0x4a2e, \
+ { 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99 } }
+
+enum optee_smci_pta_cmd {
+ /*
+ * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities
+ *
+ * [out] value[0].a: Capability bit mask (enum pta_scmi_caps)
+ * [out] value[0].b: Extended capabilities or 0
+ */
+ PTA_SCMI_CMD_CAPABILITIES = 0,
+
+ /*
+ * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer
+ *
+ * [in] value[0].a: Channel handle
+ *
+ * Shared memory used for SCMI message/response exhange is expected
+ * already identified and bound to channel handle in both SCMI agent
+ * and SCMI server (OP-TEE) parts.
+ * The memory uses SMT header to carry SCMI meta-data (protocol ID and
+ * protocol message ID).
+ */
+ PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,
+
+ /*
+ * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message
+ *
+ * [in] value[0].a: Channel handle
+ * [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)
+ *
+ * Shared memory used for SCMI message/response is a SMT buffer
+ * referenced by param[1]. It shall be 128 bytes large to fit response
+ * payload whatever message playload size.
+ * The memory uses SMT header to carry SCMI meta-data (protocol ID and
+ * protocol message ID).
+ */
+ PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,
+
+ /*
+ * PTA_SCMI_CMD_GET_CHANNEL - Get channel handle
+ *
+ * SCMI shm information are 0 if agent expects to use OP-TEE regular SHM
+ *
+ * [in] value[0].a: Channel identifier
+ * [out] value[0].a: Returned channel handle
+ * [in] value[0].b: Requested capabilities mask (enum pta_scmi_caps)
+ */
+ PTA_SCMI_CMD_GET_CHANNEL = 3,
+};
+
+/*
+ * OP-TEE SCMI service capabilities bit flags (32bit)
+ *
+ * PTA_SCMI_CAPS_SMT_HEADER
+ * When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in
+ * shared memory buffers to carry SCMI protocol synchronisation information.
+ */
+#define PTA_SCMI_CAPS_NONE 0
+#define PTA_SCMI_CAPS_SMT_HEADER BIT(0)
+
+static int open_channel(struct udevice *dev, struct channel_session *sess)
+{
+ const struct tee_optee_ta_uuid uuid = TA_SCMI_UUID;
+ struct scmi_optee_channel *chan = dev_get_plat(dev);
+ struct tee_open_session_arg sess_arg = { };
+ struct tee_invoke_arg cmd_arg = { };
+ struct tee_param param[1] = { };
+ int ret;
+
+ memset(sess, 0, sizeof(sess));
+
+ sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
+ if (!sess->tee)
+ return -ENODEV;
+
+ sess_arg.clnt_login = TEE_LOGIN_REE_KERNEL;
+ tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid);
+
+ ret = tee_open_session(sess->tee, &sess_arg, 0, NULL);
+ if (ret) {
+ dev_err(dev, "can't open session: %d\n", ret);
+ return ret;
+ }
+
+ cmd_arg.func = PTA_SCMI_CMD_GET_CHANNEL;
+ cmd_arg.session = sess_arg.session;
+
+ param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT;
+ param[0].u.value.a = chan->channel_id;
+ param[0].u.value.b = PTA_SCMI_CAPS_SMT_HEADER;
+
+ ret = tee_invoke_func(sess->tee, &cmd_arg, ARRAY_SIZE(param), param);
+ if (ret || cmd_arg.ret) {
+ dev_err(dev, "Invoke failed: %d, 0x%x\n", ret, cmd_arg.ret);
+ if (!ret)
+ ret = -EPROTO;
+
+ tee_close_session(sess->tee, sess_arg.session);
+ return ret;
+ }
+
+ sess->tee_session = sess_arg.session;
+ sess->channel_hdl = param[0].u.value.a;
+
+ return 0;
+}
+
+static void close_channel(struct channel_session *sess)
+{
+ tee_close_session(sess->tee, sess->tee_session);
+}
+
+static int invoke_cmd(struct udevice *dev, struct channel_session *sess,
+ struct scmi_msg *msg)
+{
+ struct scmi_optee_channel *chan = dev_get_plat(dev);
+ struct tee_invoke_arg arg = { };
+ struct tee_param param[2] = { };
+ int ret;
+
+ scmi_write_msg_to_smt(dev, &chan->smt, msg);
+
+ arg.session = sess->tee_session;
+ param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = sess->channel_hdl;
+
+ if (chan->dyn_shm) {
+ arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
+ param[1].u.memref.shm = sess->tee_shm;
+ param[1].u.memref.size = SCMI_SHM_SIZE;
+ } else {
+ arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL;
+ }
+
+ ret = tee_invoke_func(sess->tee, &arg, ARRAY_SIZE(param), param);
+ if (ret || arg.ret) {
+ if (!ret)
+ ret = -EPROTO;
+ } else {
+ ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+ }
+
+ scmi_clear_smt_channel(&chan->smt);
+
+ return ret;
+}
+
+static int prepare_shm(struct udevice *dev, struct channel_session *sess)
+{
+ struct scmi_optee_channel *chan = dev_get_plat(dev);
+ int ret;
+
+ /* Static shm is already prepared by the firmware: nothing to do */
+ if (!chan->dyn_shm)
+ return 0;
+
+ chan->smt.size = SCMI_SHM_SIZE;
+
+ ret = tee_shm_alloc(sess->tee, chan->smt.size, 0, &sess->tee_shm);
+ if (ret) {
+ dev_err(dev, "Failed to allocated shmem: %d\n", ret);
+ return ret;
+ }
+
+ chan->smt.buf = sess->tee_shm->addr;
+
+ /* Initialize shm buffer for message exchanges */
+ scmi_clear_smt_channel(&chan->smt);
+
+ return 0;
+}
+
+static void release_shm(struct udevice *dev, struct channel_session *sess)
+{
+ struct scmi_optee_channel *chan = dev_get_plat(dev);
+
+ if (chan->dyn_shm)
+ tee_shm_free(sess->tee_shm);
+}
+
+static int scmi_optee_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct channel_session sess;
+ int ret;
+
+ ret = open_channel(dev, &sess);
+ if (ret)
+ return ret;
+
+ ret = prepare_shm(dev, &sess);
+ if (ret)
+ goto out;
+
+ ret = invoke_cmd(dev, &sess, msg);
+
+ release_shm(dev, &sess);
+
+out:
+ close_channel(&sess);
+
+ return ret;
+}
+
+static int scmi_optee_of_to_plat(struct udevice *dev)
+{
+ struct scmi_optee_channel *chan = dev_get_plat(dev);
+ int ret;
+
+ if (dev_read_u32(dev, "linaro,optee-channel-id", &chan->channel_id)) {
+ dev_err(dev, "Missing property linaro,optee-channel-id\n");
+ return -EINVAL;
+ }
+
+ if (dev_read_prop(dev, "shmem", NULL)) {
+ ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+ if (ret) {
+ dev_err(dev, "Failed to get smt resources: %d\n", ret);
+ return ret;
+ }
+ chan->dyn_shm = false;
+ } else {
+ chan->dyn_shm = true;
+ }
+
+ return 0;
+}
+
+static int scmi_optee_probe(struct udevice *dev)
+{
+ struct channel_session sess;
+ int ret;
+
+ /* Check OP-TEE service acknowledges the SCMI channel */
+ ret = open_channel(dev, &sess);
+ if (!ret)
+ close_channel(&sess);
+
+ return ret;
+}
+
+static const struct udevice_id scmi_optee_ids[] = {
+ { .compatible = "linaro,scmi-optee" },
+ { }
+};
+
+static const struct scmi_agent_ops scmi_optee_ops = {
+ .process_msg = scmi_optee_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_optee) = {
+ .name = "scmi-over-optee",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = scmi_optee_ids,
+ .plat_auto = sizeof(struct scmi_optee_channel),
+ .of_to_plat = scmi_optee_of_to_plat,
+ .probe = scmi_optee_probe,
+ .flags = DM_FLAG_OS_PREPARE,
+ .ops = &scmi_optee_ops,
+};
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
index f185891e8fd..5e166ca93ee 100644
--- a/drivers/firmware/scmi/smccc_agent.c
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -32,7 +32,7 @@ struct scmi_smccc_channel {
static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
- struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ struct scmi_smccc_channel *chan = dev_get_plat(dev);
struct arm_smccc_res res;
int ret;
@@ -51,9 +51,9 @@ static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
return ret;
}
-static int scmi_smccc_probe(struct udevice *dev)
+static int scmi_smccc_of_to_plat(struct udevice *dev)
{
- struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ struct scmi_smccc_channel *chan = dev_get_plat(dev);
u32 func_id;
int ret;
@@ -65,12 +65,10 @@ static int scmi_smccc_probe(struct udevice *dev)
chan->func_id = func_id;
ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
- if (ret) {
+ if (ret)
dev_err(dev, "Failed to get smt resources: %d\n", ret);
- return ret;
- }
- return 0;
+ return ret;
}
static const struct udevice_id scmi_smccc_ids[] = {
@@ -86,7 +84,7 @@ U_BOOT_DRIVER(scmi_smccc) = {
.name = "scmi-over-smccc",
.id = UCLASS_SCMI_AGENT,
.of_match = scmi_smccc_ids,
- .priv_auto = sizeof(struct scmi_smccc_channel),
- .probe = scmi_smccc_probe,
+ .plat_auto = sizeof(struct scmi_smccc_channel),
+ .of_to_plat = scmi_smccc_of_to_plat,
.ops = &scmi_smccc_ops,
};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 40abc33772e..b41a755fc75 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -177,6 +177,11 @@ config HSDK_CREG_GPIO
help
This driver supports CREG GPIOs on Synopsys HSDK SOC.
+config KIRKWOOD_GPIO
+ bool "Kirkwood GPIO driver"
+ help
+ This drdiver supports GPIOs on Kirkwood platforms
+
config LPC32XX_GPIO
bool "LPC32XX GPIO driver"
depends on DM
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index eafd801cdc3..9a3c8241bc6 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -40,6 +40,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_M68K
+#define CONFIG_SYS_IMMR CONFIG_SYS_MBAR
+#endif
+
#if !CONFIG_IS_ENABLED(DM_I2C)
static const struct fsl_i2c_base *i2c_base[4] = {
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index a17e55e9972..0b753f37bf4 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -38,6 +38,15 @@ config TPL_DM_KEYBOARD
includes methods to start/stop the device, check for available
input and update LEDs if the keyboard has them.
+config KEYBOARD
+ bool "Enable legacy keyboard support (deprecated)"
+ help
+ Enable this to enable a custom keyboard support.
+ This simply calls drv_keyboard_init() which must be
+ defined in your board-specific files. This option is deprecated
+ and is only used by novena. For new boards, use driver model
+ instead.
+
config CROS_EC_KEYB
bool "Enable Chrome OS EC keyboard support"
depends on INPUT
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3bae0720058..a8baaeaf5cf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -416,7 +416,7 @@ if I2C_EEPROM
config SYS_I2C_EEPROM_ADDR_OVERFLOW
hex "EEPROM Address Overflow"
- default 0
+ default 0x0
help
EEPROM chips that implement "address overflow" are ones
like Catalyst 24WC04/08/16 which has 9/10/11 bits of
@@ -500,4 +500,7 @@ config ESM_PMIC
Support ESM (Error Signal Monitor) on PMIC devices. ESM is used
typically to reboot the board in error condition.
+config FSL_IFC
+ bool
+
endmenu
diff --git a/drivers/misc/fsl_portals.c b/drivers/misc/fsl_portals.c
index 632430e4209..02bc3f86cae 100644
--- a/drivers/misc/fsl_portals.c
+++ b/drivers/misc/fsl_portals.c
@@ -106,7 +106,7 @@ static int fdt_qportal(void *blob, int off, int id, char *name,
enum fsl_dpaa_dev dev, int create)
{
int childoff, dev_off, ret = 0;
- u32 dev_handle;
+ unsigned int dev_handle;
#ifdef CONFIG_FSL_CORENET
int num;
u32 liodns[2];
@@ -142,11 +142,9 @@ static int fdt_qportal(void *blob, int off, int id, char *name,
if (childoff > 0) {
dev_handle = fdt_get_phandle(blob, dev_off);
if (dev_handle <= 0) {
- dev_handle = fdt_alloc_phandle(blob);
- ret = fdt_set_phandle(blob, dev_off,
- dev_handle);
- if (ret < 0)
- return ret;
+ dev_handle = fdt_create_phandle(blob, dev_off);
+ if (!dev_handle)
+ return -FDT_ERR_NOPHANDLES;
}
ret = fdt_setprop(blob, childoff, "dev-handle",
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 3ee92d03ca2..b80e838066c 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -320,7 +320,7 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
struct blk_desc *desc;
struct udevice *dev;
- device_find_first_child(mmc->dev, &dev);
+ device_find_first_child_by_uclass(mmc->dev, UCLASS_BLK, &dev);
if (!dev)
return NULL;
desc = dev_get_uclass_plat(dev);
@@ -425,7 +425,7 @@ int mmc_unbind(struct udevice *dev)
{
struct udevice *bdev;
- device_find_first_child(dev, &bdev);
+ device_find_first_child_by_uclass(dev, UCLASS_BLK, &bdev);
if (bdev) {
device_remove(bdev, DM_REMOVE_NORMAL);
device_unbind(bdev);
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index 8599f095bcd..97182ffd7f5 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -1724,6 +1724,20 @@ static int msdc_drv_bind(struct udevice *dev)
return mmc_bind(dev, &plat->mmc, &plat->cfg);
}
+static int msdc_ops_wait_dat0(struct udevice *dev, int state, int timeout_us)
+{
+ struct msdc_host *host = dev_get_priv(dev);
+ int ret;
+ u32 reg;
+
+ ret = readl_poll_sleep_timeout(&host->base->msdc_ps, reg,
+ !!(reg & MSDC_PS_DAT0) == !!state,
+ 1000, /* 1 ms */
+ timeout_us);
+
+ return ret;
+}
+
static const struct dm_mmc_ops msdc_ops = {
.send_cmd = msdc_ops_send_cmd,
.set_ios = msdc_ops_set_ios,
@@ -1732,6 +1746,7 @@ static const struct dm_mmc_ops msdc_ops = {
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = msdc_execute_tuning,
#endif
+ .wait_dat0 = msdc_ops_wait_dat0,
};
static const struct msdc_compatible mt7620_compat = {
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index 895fbffecfc..451fe4a4e5a 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -9,23 +9,26 @@
#include <errno.h>
#include <fdtdec.h>
#include <log.h>
+#include <malloc.h>
#include <mmc.h>
+#include <os.h>
#include <asm/test.h>
struct sandbox_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
+ const char *fname;
};
-#define MMC_CSIZE 0
-#define MMC_CMULT 8 /* 8 because the card is high-capacity */
-#define MMC_BL_LEN_SHIFT 10
-#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
-#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
- * MMC_BL_LEN) /* 1 MiB */
+#define MMC_CMULT 8 /* 8 because the card is high-capacity */
+#define MMC_BL_LEN_SHIFT 10
+#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
+#define SIZE_MULTIPLE ((1 << (MMC_CMULT + 2)) * MMC_BL_LEN)
struct sandbox_mmc_priv {
- u8 buf[MMC_CAPACITY];
+ char *buf;
+ int csize; /* CSIZE value to report */
+ int size;
};
/**
@@ -60,8 +63,8 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
case MMC_CMD_SEND_CSD:
cmd->response[0] = 0;
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
- ((MMC_CSIZE >> 16) & 0x3f);
- cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
+ ((priv->csize >> 16) & 0x3f);
+ cmd->response[2] = (priv->csize & 0xffff) << 16;
cmd->response[3] = 0;
break;
case SD_CMD_SWITCH_FUNC: {
@@ -143,6 +146,8 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
struct blk_desc *blk;
int ret;
+ plat->fname = dev_read_string(dev, "filename");
+
ret = mmc_of_parse(dev, cfg);
if (ret)
return ret;
@@ -156,10 +161,46 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
static int sandbox_mmc_probe(struct udevice *dev)
{
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
+ struct sandbox_mmc_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (plat->fname) {
+ ret = os_map_file(plat->fname, OS_O_RDWR | OS_O_CREAT,
+ (void **)&priv->buf, &priv->size);
+ if (ret) {
+ log_err("%s: Unable to map file '%s'\n", dev->name,
+ plat->fname);
+ return ret;
+ }
+ priv->csize = priv->size / SIZE_MULTIPLE - 1;
+ } else {
+ priv->csize = 0;
+ priv->size = (priv->csize + 1) * SIZE_MULTIPLE; /* 1 MiB */
+
+ priv->buf = malloc(priv->size);
+ if (!priv->buf) {
+ log_err("%s: Not enough memory (%x bytes)\n",
+ dev->name, priv->size);
+ return -ENOMEM;
+ }
+ }
return mmc_init(&plat->mmc);
}
+static int sandbox_mmc_remove(struct udevice *dev)
+{
+ struct sandbox_mmc_plat *plat = dev_get_plat(dev);
+ struct sandbox_mmc_priv *priv = dev_get_priv(dev);
+
+ if (plat->fname)
+ os_unmap(priv->buf, priv->size);
+ else
+ free(priv->buf);
+
+ return 0;
+}
+
static int sandbox_mmc_bind(struct udevice *dev)
{
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
@@ -196,6 +237,7 @@ U_BOOT_DRIVER(mmc_sandbox) = {
.unbind = sandbox_mmc_unbind,
.of_to_plat = sandbox_mmc_of_to_plat,
.probe = sandbox_mmc_probe,
+ .remove = sandbox_mmc_remove,
.priv_auto = sizeof(struct sandbox_mmc_priv),
.plat_auto = sizeof(struct sandbox_mmc_plat),
};
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index a3cdf7bcd9f..44bfc911af2 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -16,6 +16,7 @@
#include <asm/bitops.h>
#include <asm/cache.h>
#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/libfdt.h>
@@ -645,6 +646,66 @@ static const struct dm_mmc_ops stm32_sdmmc2_ops = {
.host_power_cycle = stm32_sdmmc2_host_power_cycle,
};
+static int stm32_sdmmc2_probe_level_translator(struct udevice *dev)
+{
+ struct stm32_sdmmc2_priv *priv = dev_get_priv(dev);
+ struct gpio_desc cmd_gpio;
+ struct gpio_desc ck_gpio;
+ struct gpio_desc ckin_gpio;
+ int clk_hi, clk_lo, ret;
+
+ /*
+ * Assume the level translator is present if st,use-ckin is set.
+ * This is to cater for DTs which do not implement this test.
+ */
+ priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
+
+ ret = gpio_request_by_name(dev, "st,cmd-gpios", 0, &cmd_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ goto exit_cmd;
+
+ ret = gpio_request_by_name(dev, "st,ck-gpios", 0, &ck_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ goto exit_ck;
+
+ ret = gpio_request_by_name(dev, "st,ckin-gpios", 0, &ckin_gpio,
+ GPIOD_IS_IN);
+ if (ret)
+ goto exit_ckin;
+
+ /* All GPIOs are valid, test whether level translator works */
+
+ /* Sample CKIN */
+ clk_hi = !!dm_gpio_get_value(&ckin_gpio);
+
+ /* Set CK low */
+ dm_gpio_set_value(&ck_gpio, 0);
+
+ /* Sample CKIN */
+ clk_lo = !!dm_gpio_get_value(&ckin_gpio);
+
+ /* Tristate all */
+ dm_gpio_set_dir_flags(&cmd_gpio, GPIOD_IS_IN);
+ dm_gpio_set_dir_flags(&ck_gpio, GPIOD_IS_IN);
+
+ /* Level translator is present if CK signal is propagated to CKIN */
+ if (!clk_hi || clk_lo)
+ priv->clk_reg_msk &= ~SDMMC_CLKCR_SELCLKRX_CKIN;
+
+ dm_gpio_free(dev, &ckin_gpio);
+
+exit_ckin:
+ dm_gpio_free(dev, &ck_gpio);
+exit_ck:
+ dm_gpio_free(dev, &cmd_gpio);
+exit_cmd:
+ pinctrl_select_state(dev, "default");
+
+ return 0;
+}
+
static int stm32_sdmmc2_probe(struct udevice *dev)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
@@ -662,7 +723,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
if (dev_read_bool(dev, "st,sig-dir"))
priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL;
if (dev_read_bool(dev, "st,use-ckin"))
- priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
+ stm32_sdmmc2_probe_level_translator(dev);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index df9eae1691c..0e826c19298 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -9,10 +9,24 @@ config SYS_NAND_SELF_INIT
This option, if enabled, provides more flexible and linux-like
NAND initialization process.
-config SYS_NAND_DRIVER_ECC_LAYOUT
+config SPL_SYS_NAND_SELF_INIT
+ bool
+ depends on !SPL_NAND_SIMPLE
+ help
+ This option, if enabled, provides more flexible and linux-like
+ NAND initialization process, in SPL.
+
+config TPL_SYS_NAND_SELF_INIT
bool
+ depends on TPL_NAND_SUPPORT
+ help
+ This option, if enabled, provides more flexible and linux-like
+ NAND initialization process, in SPL.
+
+config SYS_NAND_DRIVER_ECC_LAYOUT
+ bool "Omit standard ECC layouts to save space"
help
- Omit standard ECC layouts to safe space. Select this if your driver
+ Omit standard ECC layouts to save space. Select this if your driver
is known to provide its own ECC layout.
config SYS_NAND_USE_FLASH_BBT
@@ -22,6 +36,7 @@ config SYS_NAND_USE_FLASH_BBT
config NAND_ATMEL
bool "Support Atmel NAND controller"
+ select SYS_NAND_SELF_INIT
imply SYS_NAND_USE_FLASH_BBT
help
Enable this driver for NAND flash platforms using an Atmel NAND
@@ -65,6 +80,7 @@ endif
config NAND_BRCMNAND
bool "Support Broadcom NAND controller"
depends on OF_CONTROL && DM && DM_MTD
+ select SYS_NAND_SELF_INIT
help
Enable the driver for NAND flash on platforms using a Broadcom NAND
controller.
@@ -101,6 +117,7 @@ config NAND_BRCMNAND_63158
config NAND_DAVINCI
bool "Support TI Davinci NAND controller"
+ select SYS_NAND_SELF_INIT if TARGET_DA850EVM
help
Enable this driver for NAND flash controllers available in TI Davinci
and Keystone2 platforms
@@ -128,17 +145,25 @@ config NAND_DENALI_DT
config NAND_FSL_ELBC
bool "Support Freescale Enhanced Local Bus Controller FCM NAND driver"
+ select TPL_SYS_NAND_SELF_INIT if TPL_NAND_SUPPORT
+ select SPL_SYS_NAND_SELF_INIT
+ select SYS_NAND_SELF_INIT
depends on FSL_ELBC
help
Enable the Freescale Enhanced Local Bus Controller FCM NAND driver.
config NAND_FSL_IFC
bool "Support Freescale Integrated Flash Controller NAND driver"
+ select TPL_SYS_NAND_SELF_INIT if TPL_NAND_SUPPORT
+ select SPL_SYS_NAND_SELF_INIT
+ select SYS_NAND_SELF_INIT
+ select FSL_IFC
help
Enable the Freescale Integrated Flash Controller NAND driver.
config NAND_LPC32XX_MLC
bool "Support LPC32XX_MLC controller"
+ select SYS_NAND_SELF_INIT
help
Enable the LPC32XX MLC NAND controller.
@@ -330,6 +355,7 @@ config NAND_SUNXI
select SYS_NAND_SELF_INIT
select SYS_NAND_U_BOOT_LOCATIONS
select SPL_NAND_SUPPORT
+ select SPL_SYS_NAND_SELF_INIT
imply CMD_NAND
---help---
Enable support for NAND. This option enables the standard and
@@ -374,6 +400,7 @@ config NAND_MXC
config NAND_MXS
bool "MXS NAND support"
depends on MX23 || MX28 || MX6 || MX7 || IMX8 || IMX8M
+ select SPL_SYS_NAND_SELF_INIT
select SYS_NAND_SELF_INIT
imply CMD_NAND
select APBH_DMA
@@ -406,6 +433,7 @@ config NAND_MXIC
config NAND_ZYNQ
bool "Support for Zynq Nand controller"
+ select SPL_SYS_NAND_SELF_INIT
select SYS_NAND_SELF_INIT
select DM_MTD
imply CMD_NAND
@@ -475,6 +503,14 @@ config ROCKCHIP_NAND
NFC v800: RK3308, RV1108
NFC v900: PX30, RK3326
+config TEGRA_NAND
+ bool "Support for NAND controller on Tegra SoCs"
+ depends on ARCH_TEGRA
+ select SYS_NAND_SELF_INIT
+ imply CMD_NAND
+ help
+ Enables support for NAND Flash chips on Tegra SoCs platforms.
+
comment "Generic NAND options"
config SYS_NAND_BLOCK_SIZE
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index ef7ee395c0c..9158d94de25 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -788,7 +788,7 @@ static void davinci_nand_init(struct nand_chip *nand)
nand->dev_ready = nand_davinci_dev_ready;
}
-#ifdef CONFIG_SYS_NAND_SELF_INIT
+#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
static int davinci_nand_probe(struct udevice *dev)
{
struct nand_chip *nand = dev_get_priv(dev);
diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c
index 59ad1392b0e..4b5560dd24c 100644
--- a/drivers/mtd/nand/raw/nand.c
+++ b/drivers/mtd/nand/raw/nand.c
@@ -76,7 +76,7 @@ int nand_register(int devnum, struct mtd_info *mtd)
return 0;
}
-#ifndef CONFIG_SYS_NAND_SELF_INIT
+#if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
static void nand_init_chip(int i)
{
struct nand_chip *nand = &nand_chip[i];
@@ -155,7 +155,7 @@ void nand_init(void)
return;
initialized = 1;
-#ifdef CONFIG_SYS_NAND_SELF_INIT
+#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
board_nand_init();
#else
int i;
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 2f56d46a384..f350c7e5dc2 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -57,7 +57,7 @@ config SF_DEFAULT_CS
config SF_DEFAULT_MODE
hex "SPI Flash default mode (see include/spi.h)"
depends on SPI_FLASH || DM_SPI_FLASH
- default 0
+ default 0x0
help
The default mode may be provided by the platform
to handle the common case when only a single serial
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c1a49173c28..71e0cbafb41 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1,6 +1,7 @@
source "drivers/net/phy/Kconfig"
source "drivers/net/pfe_eth/Kconfig"
source "drivers/net/fsl-mc/Kconfig"
+source "drivers/net/bnxt/Kconfig"
config ETH
def_bool y
@@ -554,6 +555,22 @@ config RTL8169
This driver supports Realtek 8169 series gigabit ethernet family of
PCI/PCIe chipsets/adapters.
+config SJA1105
+ bool "NXP SJA1105 Ethernet switch family driver"
+ depends on DM_DSA && DM_SPI
+ select BITREVERSE
+ help
+ This is the driver for the NXP SJA1105 automotive Ethernet switch
+ family. These are 5-port devices and are managed over an SPI
+ interface. Probing is handled based on OF bindings. The driver
+ supports the following revisions:
+ - SJA1105E (Gen. 1, No TT-Ethernet)
+ - SJA1105T (Gen. 1, TT-Ethernet)
+ - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
+ - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
+ - SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
+ - SJA1105S (Gen. 2, SGMII, TT-Ethernet)
+
config SMC911X
bool "SMSC LAN911x and LAN921x controller driver"
@@ -835,6 +852,13 @@ config FSL_LS_MDIO
This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and
on the mEMAC (which supports both Clauses 22 and 45).
+config ASPEED_MDIO
+ bool "Aspeed MDIO interface support"
+ depends on DM_MDIO
+ help
+ This driver supports the MDIO bus of Aspeed AST2600 SOC. The driver
+ currently supports Clause 22.
+
config MDIO_MUX_MMIOREG
bool "MDIO MUX accessed as a MMIO register access"
depends on DM_MDIO_MUX
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e4078d15a99..a6d0c23f02d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -3,43 +3,53 @@
# (C) Copyright 2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-y += phy/
-obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
obj-$(CONFIG_AG7XXX) += ag7xxx.o
+obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o
obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
obj-$(CONFIG_BCM6368_ETH) += bcm6368-eth.o
obj-$(CONFIG_BCMGENET) += bcmgenet.o
-obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
+obj-$(CONFIG_BNXT_ETH) += bnxt/
obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
obj-$(CONFIG_CS8900) += cs8900.o
-obj-$(CONFIG_TULIP) += dc2114x.o
-obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
-obj-$(CONFIG_ETH_DESIGNWARE_MESON8B) += dwmac_meson8b.o
-obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
-obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o
-obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
+obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
obj-$(CONFIG_DNET) += dnet.o
+obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
+obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
-obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
+obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
obj-$(CONFIG_E1000) += e1000.o
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
obj-$(CONFIG_EEPRO100) += eepro100.o
-obj-$(CONFIG_SUN4I_EMAC) += sunxi_emac.o
-obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
obj-$(CONFIG_EP93XX) += ep93xx_eth.o
obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
+obj-$(CONFIG_ETH_DESIGNWARE_MESON8B) += dwmac_meson8b.o
+obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o
+obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
+obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
+obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o
+obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
obj-$(CONFIG_FMAN_ENET) += fm/
+obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
+obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
+obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o
+obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
+obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
+obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
+obj-$(CONFIG_FSL_PFE) += pfe_eth/
obj-$(CONFIG_FTGMAC100) += ftgmac100.o
-obj-$(CONFIG_FTMAC110) += ftmac110.o
obj-$(CONFIG_FTMAC100) += ftmac100.o
+obj-$(CONFIG_FTMAC110) += ftmac110.o
obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o
+obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_KSZ9477) += ksz9477.o
obj-$(CONFIG_LAN91C96) += lan91c96.o
@@ -51,6 +61,8 @@ obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o
obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o
obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
+obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
+obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o
obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
@@ -60,44 +72,35 @@ obj-$(CONFIG_MVNETA) += mvneta.o
obj-$(CONFIG_MVPP2) += mvpp2.o
obj-$(CONFIG_NATSEMI) += natsemi.o
obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_NET_OCTEONTX) += octeontx/
+obj-$(CONFIG_NET_OCTEONTX2) += octeontx2/
obj-$(CONFIG_NS8382X) += ns8382x.o
+obj-$(CONFIG_OCTEONTX2_CGX_INTF) += octeontx2/cgx_intf.o
+obj-$(CONFIG_OCTEONTX_SMI) += octeontx/smi.o
obj-$(CONFIG_PCH_GBE) += pch_gbe.o
obj-$(CONFIG_PCNET) += pcnet.o
+obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
+obj-$(CONFIG_RENESAS_RAVB) += ravb.o
obj-$(CONFIG_RTL8139) += rtl8139.o
obj-$(CONFIG_RTL8169) += rtl8169.o
-obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
-obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
-obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o
obj-$(CONFIG_SH_ETHER) += sh_eth.o
-obj-$(CONFIG_RENESAS_RAVB) += ravb.o
+obj-$(CONFIG_SJA1105) += sja1105.o
obj-$(CONFIG_SMC91111) += smc91111.o
obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_SNI_AVE) += sni_ave.o
+obj-$(CONFIG_SNI_NETSEC) += sni_netsec.o
+obj-$(CONFIG_SUN4I_EMAC) += sunxi_emac.o
+obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
-obj-$(CONFIG_NET_OCTEONTX) += octeontx/
-obj-$(CONFIG_NET_OCTEONTX2) += octeontx2/
-obj-$(CONFIG_OCTEONTX_SMI) += octeontx/smi.o
-obj-$(CONFIG_OCTEONTX2_CGX_INTF) += octeontx2/cgx_intf.o
-obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
+obj-$(CONFIG_TULIP) += dc2114x.o
obj-$(CONFIG_ULI526X) += uli526x.o
obj-$(CONFIG_VSC7385_ENET) += vsc7385.o
+obj-$(CONFIG_VSC9953) += vsc9953.o
obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o
obj-$(CONFIG_XILINX_AXIMRMAC) += xilinx_axi_mrmac.o
obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o
-obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
-obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
-obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
-obj-$(CONFIG_VSC9953) += vsc9953.o
-obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
-obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
-obj-$(CONFIG_FSL_PFE) += pfe_eth/
+obj-y += mscc_eswitch/
+obj-y += phy/
obj-y += qe/
-obj-$(CONFIG_SNI_AVE) += sni_ave.o
-obj-$(CONFIG_SNI_NETSEC) += sni_netsec.o
obj-y += ti/
-obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
-obj-y += mscc_eswitch/
-obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
-obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
-obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
-obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o
diff --git a/drivers/net/aspeed_mdio.c b/drivers/net/aspeed_mdio.c
new file mode 100644
index 00000000000..a99715a7282
--- /dev/null
+++ b/drivers/net/aspeed_mdio.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Aspeed MDIO driver
+ *
+ * (C) Copyright 2021 Aspeed Technology Inc.
+ *
+ * This file is inspired from the Linux kernel driver drivers/net/phy/mdio-aspeed.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <miiphy.h>
+#include <net.h>
+#include <reset.h>
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define ASPEED_MDIO_CTRL 0x0
+#define ASPEED_MDIO_CTRL_FIRE BIT(31)
+#define ASPEED_MDIO_CTRL_ST BIT(28)
+#define ASPEED_MDIO_CTRL_ST_C45 0
+#define ASPEED_MDIO_CTRL_ST_C22 1
+#define ASPEED_MDIO_CTRL_OP GENMASK(27, 26)
+#define MDIO_C22_OP_WRITE 0b01
+#define MDIO_C22_OP_READ 0b10
+#define ASPEED_MDIO_CTRL_PHYAD GENMASK(25, 21)
+#define ASPEED_MDIO_CTRL_REGAD GENMASK(20, 16)
+#define ASPEED_MDIO_CTRL_MIIWDATA GENMASK(15, 0)
+
+#define ASPEED_MDIO_DATA 0x4
+#define ASPEED_MDIO_DATA_MDC_THRES GENMASK(31, 24)
+#define ASPEED_MDIO_DATA_MDIO_EDGE BIT(23)
+#define ASPEED_MDIO_DATA_MDIO_LATCH GENMASK(22, 20)
+#define ASPEED_MDIO_DATA_IDLE BIT(16)
+#define ASPEED_MDIO_DATA_MIIRDATA GENMASK(15, 0)
+
+#define ASPEED_MDIO_TIMEOUT_US 1000
+
+struct aspeed_mdio_priv {
+ void *base;
+};
+
+static int aspeed_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
+{
+ struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
+ u32 ctrl;
+ u32 data;
+ int rc;
+
+ if (devad != MDIO_DEVAD_NONE)
+ return -EOPNOTSUPP;
+
+ ctrl = ASPEED_MDIO_CTRL_FIRE
+ | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg);
+
+ writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
+
+ rc = readl_poll_timeout(priv->base + ASPEED_MDIO_DATA, data,
+ data & ASPEED_MDIO_DATA_IDLE,
+ ASPEED_MDIO_TIMEOUT_US);
+
+ if (rc < 0)
+ return rc;
+
+ return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
+}
+
+static int aspeed_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
+{
+ struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
+ u32 ctrl;
+
+ if (devad != MDIO_DEVAD_NONE)
+ return -EOPNOTSUPP;
+
+ ctrl = ASPEED_MDIO_CTRL_FIRE
+ | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg)
+ | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
+
+ writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
+
+ return readl_poll_timeout(priv->base + ASPEED_MDIO_CTRL, ctrl,
+ !(ctrl & ASPEED_MDIO_CTRL_FIRE),
+ ASPEED_MDIO_TIMEOUT_US);
+}
+
+static const struct mdio_ops aspeed_mdio_ops = {
+ .read = aspeed_mdio_read,
+ .write = aspeed_mdio_write,
+};
+
+static int aspeed_mdio_probe(struct udevice *dev)
+{
+ struct aspeed_mdio_priv *priv = dev_get_priv(dev);
+ struct reset_ctl reset_ctl;
+ int ret = 0;
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ ret = reset_get_by_index(dev, 0, &reset_ctl);
+ reset_deassert(&reset_ctl);
+
+ return 0;
+}
+
+static const struct udevice_id aspeed_mdio_ids[] = {
+ { .compatible = "aspeed,ast2600-mdio" },
+ { }
+};
+
+U_BOOT_DRIVER(aspeed_mdio) = {
+ .name = "aspeed_mdio",
+ .id = UCLASS_MDIO,
+ .of_match = aspeed_mdio_ids,
+ .probe = aspeed_mdio_probe,
+ .ops = &aspeed_mdio_ops,
+ .plat_auto = sizeof(struct mdio_perdev_priv),
+ .priv_auto = sizeof(struct aspeed_mdio_priv),
+};
diff --git a/drivers/net/bnxt/Kconfig b/drivers/net/bnxt/Kconfig
new file mode 100644
index 00000000000..412ecd43033
--- /dev/null
+++ b/drivers/net/bnxt/Kconfig
@@ -0,0 +1,7 @@
+config BNXT_ETH
+ bool "BNXT PCI support"
+ depends on DM_ETH
+ select PCI_INIT_R
+ help
+ This driver implements support for bnxt pci controller
+ driver of ethernet class.
diff --git a/drivers/net/bnxt/Makefile b/drivers/net/bnxt/Makefile
new file mode 100644
index 00000000000..a9d6ce00d5e
--- /dev/null
+++ b/drivers/net/bnxt/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2019-2021 Broadcom.
+
+# Broadcom nxe Ethernet driver
+obj-y += bnxt.o
diff --git a/drivers/net/bnxt/bnxt.c b/drivers/net/bnxt/bnxt.c
new file mode 100644
index 00000000000..9844e96072e
--- /dev/null
+++ b/drivers/net/bnxt/bnxt.c
@@ -0,0 +1,1708 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 Broadcom.
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <memalign.h>
+#include <net.h>
+
+#include "bnxt.h"
+#include "bnxt_dbg.h"
+
+#define bnxt_down_chip(bp) bnxt_hwrm_run(down_chip, bp, 0)
+#define bnxt_bring_chip(bp) bnxt_hwrm_run(bring_chip, bp, 1)
+
+/* Broadcom ethernet driver PCI APIs. */
+static void bnxt_bring_pci(struct bnxt *bp)
+{
+ u16 cmd_reg = 0;
+
+ dm_pci_read_config16(bp->pdev, PCI_VENDOR_ID, &bp->vendor_id);
+ dm_pci_read_config16(bp->pdev, PCI_DEVICE_ID, &bp->device_id);
+ dm_pci_read_config16(bp->pdev, PCI_SUBSYSTEM_VENDOR_ID, &bp->subsystem_vendor);
+ dm_pci_read_config16(bp->pdev, PCI_SUBSYSTEM_ID, &bp->subsystem_device);
+ dm_pci_read_config16(bp->pdev, PCI_COMMAND, &bp->cmd_reg);
+ dm_pci_read_config8(bp->pdev, PCI_INTERRUPT_LINE, &bp->irq);
+ bp->bar0 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ bp->bar1 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
+ bp->bar2 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_4, PCI_REGION_MEM);
+ cmd_reg = bp->cmd_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ cmd_reg |= PCI_COMMAND_INTX_DISABLE; /* disable intr */
+ dm_pci_write_config16(bp->pdev, PCI_COMMAND, cmd_reg);
+ dm_pci_read_config16(bp->pdev, PCI_COMMAND, &cmd_reg);
+ dbg_pci(bp, __func__, cmd_reg);
+}
+
+int bnxt_free_rx_iob(struct bnxt *bp)
+{
+ unsigned int i;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_RX_IOB)))
+ return STATUS_SUCCESS;
+
+ for (i = 0; i < bp->rx.buf_cnt; i++) {
+ if (bp->rx.iob[i]) {
+ free(bp->rx.iob[i]);
+ bp->rx.iob[i] = NULL;
+ }
+ }
+
+ FLAG_RESET(bp->flag_hwrm, VALID_RX_IOB);
+
+ return STATUS_SUCCESS;
+}
+
+static void set_rx_desc(u8 *buf, void *iob, u16 cons_id, u32 iob_idx)
+{
+ struct rx_prod_pkt_bd *desc;
+ u16 off = cons_id * sizeof(struct rx_prod_pkt_bd);
+
+ desc = (struct rx_prod_pkt_bd *)&buf[off];
+ desc->flags_type = RX_PROD_PKT_BD_TYPE_RX_PROD_PKT;
+ desc->len = MAX_ETHERNET_PACKET_BUFFER_SIZE;
+ desc->opaque = iob_idx;
+ desc->dma.addr = virt_to_bus(iob);
+}
+
+static int bnxt_alloc_rx_iob(struct bnxt *bp, u16 cons_id, u16 iob_idx)
+{
+ void *iob;
+
+ iob = memalign(BNXT_DMA_ALIGNMENT, RX_STD_DMA_ALIGNED);
+ if (!iob)
+ return -ENOMEM;
+
+ dbg_rx_iob(iob, iob_idx, cons_id);
+ set_rx_desc((u8 *)bp->rx.bd_virt, iob, cons_id, (u32)iob_idx);
+ bp->rx.iob[iob_idx] = iob;
+
+ return 0;
+}
+
+void bnxt_mm_init(struct bnxt *bp, const char *func)
+{
+ memset(bp->hwrm_addr_req, 0, REQ_BUFFER_SIZE);
+ memset(bp->hwrm_addr_resp, 0, RESP_BUFFER_SIZE);
+ memset(bp->cq.bd_virt, 0, CQ_RING_DMA_BUFFER_SIZE);
+ memset(bp->tx.bd_virt, 0, TX_RING_DMA_BUFFER_SIZE);
+ memset(bp->rx.bd_virt, 0, RX_RING_DMA_BUFFER_SIZE);
+
+ bp->data_addr_mapping = virt_to_bus(bp->hwrm_addr_data);
+ bp->req_addr_mapping = virt_to_bus(bp->hwrm_addr_req);
+ bp->resp_addr_mapping = virt_to_bus(bp->hwrm_addr_resp);
+ bp->wait_link_timeout = LINK_DEFAULT_TIMEOUT;
+ bp->link_status = STATUS_LINK_DOWN;
+ bp->media_change = 1;
+ bp->mtu = MAX_ETHERNET_PACKET_BUFFER_SIZE;
+ bp->hwrm_max_req_len = HWRM_MAX_REQ_LEN;
+ bp->rx.buf_cnt = NUM_RX_BUFFERS;
+ bp->rx.ring_cnt = MAX_RX_DESC_CNT;
+ bp->tx.ring_cnt = MAX_TX_DESC_CNT;
+ bp->cq.ring_cnt = MAX_CQ_DESC_CNT;
+ bp->cq.completion_bit = 0x1;
+ bp->link_set = LINK_SPEED_DRV_100G;
+ dbg_mem(bp, func);
+}
+
+void bnxt_free_mem(struct bnxt *bp)
+{
+ if (bp->cq.bd_virt) {
+ free(bp->cq.bd_virt);
+ bp->cq.bd_virt = NULL;
+ }
+
+ if (bp->rx.bd_virt) {
+ free(bp->rx.bd_virt);
+ bp->rx.bd_virt = NULL;
+ }
+
+ if (bp->tx.bd_virt) {
+ free(bp->tx.bd_virt);
+ bp->tx.bd_virt = NULL;
+ }
+
+ if (bp->hwrm_addr_resp) {
+ free(bp->hwrm_addr_resp);
+ bp->resp_addr_mapping = 0;
+ bp->hwrm_addr_resp = NULL;
+ }
+
+ if (bp->hwrm_addr_req) {
+ free(bp->hwrm_addr_req);
+ bp->req_addr_mapping = 0;
+ bp->hwrm_addr_req = NULL;
+ }
+
+ if (bp->hwrm_addr_data) {
+ free(bp->hwrm_addr_data);
+ bp->data_addr_mapping = 0;
+ bp->hwrm_addr_data = NULL;
+ }
+
+ dbg_mem_free_done(__func__);
+}
+
+int bnxt_alloc_mem(struct bnxt *bp)
+{
+ bp->hwrm_addr_data = memalign(BNXT_DMA_ALIGNMENT, DMA_BUF_SIZE_ALIGNED);
+ bp->hwrm_addr_req = memalign(BNXT_DMA_ALIGNMENT, REQ_BUF_SIZE_ALIGNED);
+ bp->hwrm_addr_resp = MEM_HWRM_RESP;
+
+ memset(&bp->tx, 0, sizeof(struct lm_tx_info_t));
+ memset(&bp->rx, 0, sizeof(struct lm_rx_info_t));
+ memset(&bp->cq, 0, sizeof(struct lm_cmp_info_t));
+
+ bp->tx.bd_virt = memalign(BNXT_DMA_ALIGNMENT, TX_RING_DMA_BUFFER_SIZE);
+ bp->rx.bd_virt = memalign(BNXT_DMA_ALIGNMENT, RX_RING_DMA_BUFFER_SIZE);
+ bp->cq.bd_virt = memalign(BNXT_DMA_ALIGNMENT, CQ_RING_DMA_BUFFER_SIZE);
+
+ if (bp->hwrm_addr_req &&
+ bp->hwrm_addr_resp &&
+ bp->hwrm_addr_data &&
+ bp->tx.bd_virt &&
+ bp->rx.bd_virt &&
+ bp->cq.bd_virt) {
+ bnxt_mm_init(bp, __func__);
+ return STATUS_SUCCESS;
+ }
+
+ dbg_mem_alloc_fail(__func__);
+ bnxt_free_mem(bp);
+
+ return -ENOMEM;
+}
+
+static void hwrm_init(struct bnxt *bp, struct input *req, u16 cmd, u16 len)
+{
+ memset(req, 0, len);
+ req->req_type = cmd;
+ req->cmpl_ring = (u16)HWRM_NA_SIGNATURE;
+ req->target_id = (u16)HWRM_NA_SIGNATURE;
+ req->resp_addr = bp->resp_addr_mapping;
+ req->seq_id = bp->seq_id++;
+}
+
+static void hwrm_write_req(struct bnxt *bp, void *req, u32 cnt)
+{
+ u32 i = 0;
+
+ for (i = 0; i < cnt; i++)
+ writel(((u32 *)req)[i], bp->bar0 + GRC_COM_CHAN_BASE + (i * 4));
+
+ writel(0x1, (bp->bar0 + GRC_COM_CHAN_BASE + GRC_COM_CHAN_TRIG));
+}
+
+static void short_hwrm_cmd_req(struct bnxt *bp, u16 len)
+{
+ struct hwrm_short_input sreq;
+
+ memset(&sreq, 0, sizeof(struct hwrm_short_input));
+ sreq.req_type = (u16)((struct input *)bp->hwrm_addr_req)->req_type;
+ sreq.signature = SHORT_REQ_SIGNATURE_SHORT_CMD;
+ sreq.size = len;
+ sreq.req_addr = bp->req_addr_mapping;
+ dbg_short_cmd((u8 *)&sreq, __func__, sizeof(struct hwrm_short_input));
+ hwrm_write_req(bp, &sreq, sizeof(struct hwrm_short_input) / 4);
+}
+
+static int wait_resp(struct bnxt *bp, u32 tmo, u16 len, const char *func)
+{
+ struct input *req = (struct input *)bp->hwrm_addr_req;
+ struct output *resp = (struct output *)bp->hwrm_addr_resp;
+ u8 *ptr = (u8 *)resp;
+ u32 idx;
+ u32 wait_cnt = HWRM_CMD_DEFAULT_MULTIPLAYER((u32)tmo);
+ u16 resp_len = 0;
+ u16 ret = STATUS_TIMEOUT;
+
+ if (len > bp->hwrm_max_req_len)
+ short_hwrm_cmd_req(bp, len);
+ else
+ hwrm_write_req(bp, req, (u32)(len / 4));
+
+ for (idx = 0; idx < wait_cnt; idx++) {
+ resp_len = resp->resp_len;
+ if (resp->seq_id == req->seq_id && resp->req_type == req->req_type &&
+ ptr[resp_len - 1] == 1) {
+ bp->last_resp_code = resp->error_code;
+ ret = resp->error_code;
+ break;
+ }
+
+ udelay(HWRM_CMD_POLL_WAIT_TIME);
+ }
+
+ dbg_hw_cmd(bp, func, len, resp_len, tmo, ret);
+
+ return (int)ret;
+}
+
+static void bnxt_db_cq(struct bnxt *bp)
+{
+ writel(CQ_DOORBELL_KEY_IDX(bp->cq.cons_idx), bp->bar1);
+}
+
+static void bnxt_db_rx(struct bnxt *bp, u32 idx)
+{
+ writel(RX_DOORBELL_KEY_RX | idx, bp->bar1);
+}
+
+static void bnxt_db_tx(struct bnxt *bp, u32 idx)
+{
+ writel((u32)(TX_DOORBELL_KEY_TX | idx), bp->bar1);
+}
+
+int iob_pad(void *packet, int length)
+{
+ if (length >= ETH_ZLEN)
+ return length;
+
+ memset(((u8 *)packet + length), 0x00, (ETH_ZLEN - length));
+
+ return ETH_ZLEN;
+}
+
+static inline u32 bnxt_tx_avail(struct bnxt *bp)
+{
+ barrier();
+
+ return TX_AVAIL(bp->tx.ring_cnt) -
+ ((bp->tx.prod_id - bp->tx.cons_id) &
+ (bp->tx.ring_cnt - 1));
+}
+
+void set_txq(struct bnxt *bp, int entry, dma_addr_t mapping, int len)
+{
+ struct tx_bd_short *prod_bd;
+
+ prod_bd = (struct tx_bd_short *)BD_NOW(bp->tx.bd_virt,
+ entry,
+ sizeof(struct tx_bd_short));
+ if (len < 512)
+ prod_bd->flags_type = TX_BD_SHORT_FLAGS_LHINT_LT512;
+ else if (len < 1024)
+ prod_bd->flags_type = TX_BD_SHORT_FLAGS_LHINT_LT1K;
+ else if (len < 2048)
+ prod_bd->flags_type = TX_BD_SHORT_FLAGS_LHINT_LT2K;
+ else
+ prod_bd->flags_type = TX_BD_SHORT_FLAGS_LHINT_GTE2K;
+
+ prod_bd->flags_type |= TX_BD_FLAGS;
+ prod_bd->dma.addr = mapping;
+ prod_bd->len = len;
+ prod_bd->opaque = (u32)entry;
+ dump_tx_bd(prod_bd, (u16)(sizeof(struct tx_bd_short)));
+}
+
+static void bnxt_tx_complete(struct bnxt *bp)
+{
+ bp->tx.cons_id = NEXT_IDX(bp->tx.cons_id, bp->tx.ring_cnt);
+ bp->tx.cnt++;
+ dump_tx_stat(bp);
+}
+
+int post_rx_buffers(struct bnxt *bp)
+{
+ u16 cons_id = (bp->rx.cons_idx % bp->rx.ring_cnt);
+ u16 iob_idx;
+
+ while (bp->rx.iob_cnt < bp->rx.buf_cnt) {
+ iob_idx = (cons_id % bp->rx.buf_cnt);
+ if (!bp->rx.iob[iob_idx]) {
+ if (bnxt_alloc_rx_iob(bp, cons_id, iob_idx) < 0) {
+ dbg_rx_alloc_iob_fail(iob_idx, cons_id);
+ break;
+ }
+ }
+
+ cons_id = NEXT_IDX(cons_id, bp->rx.ring_cnt);
+ bp->rx.iob_cnt++;
+ }
+
+ if (cons_id != bp->rx.cons_idx) {
+ dbg_rx_cid(bp->rx.cons_idx, cons_id);
+ bp->rx.cons_idx = cons_id;
+ bnxt_db_rx(bp, (u32)cons_id);
+ }
+
+ FLAG_SET(bp->flag_hwrm, VALID_RX_IOB);
+
+ return STATUS_SUCCESS;
+}
+
+u8 bnxt_rx_drop(struct bnxt *bp, u8 *rx_buf, struct rx_pkt_cmpl_hi *rx_cmp_hi)
+{
+ u8 chksum_err = 0;
+ u8 i;
+ u16 error_flags;
+
+ error_flags = (rx_cmp_hi->errors_v2 >>
+ RX_PKT_CMPL_ERRORS_BUFFER_ERROR_SFT);
+ if (rx_cmp_hi->errors_v2 == 0x20 || rx_cmp_hi->errors_v2 == 0x21)
+ chksum_err = 1;
+
+ if (error_flags && !chksum_err) {
+ bp->rx.err++;
+ return 1;
+ }
+
+ for (i = 0; i < 6; i++) {
+ if (rx_buf[6 + i] != bp->mac_set[i])
+ break;
+ }
+
+ if (i == 6) {
+ bp->rx.dropped++;
+ return 2; /* Drop the loopback packets */
+ }
+
+ return 0;
+}
+
+static void bnxt_adv_cq_index(struct bnxt *bp, u16 count)
+{
+ u16 cons_idx = bp->cq.cons_idx + count;
+
+ if (cons_idx >= MAX_CQ_DESC_CNT) {
+ /* Toggle completion bit when the ring wraps. */
+ bp->cq.completion_bit ^= 1;
+ cons_idx = cons_idx - MAX_CQ_DESC_CNT;
+ }
+
+ bp->cq.cons_idx = cons_idx;
+}
+
+void bnxt_adv_rx_index(struct bnxt *bp, u8 *iob, u32 iob_idx)
+{
+ u16 cons_id = (bp->rx.cons_idx % bp->rx.ring_cnt);
+
+ set_rx_desc((u8 *)bp->rx.bd_virt, (void *)iob, cons_id, iob_idx);
+ cons_id = NEXT_IDX(cons_id, bp->rx.ring_cnt);
+ if (cons_id != bp->rx.cons_idx) {
+ dbg_rx_cid(bp->rx.cons_idx, cons_id);
+ bp->rx.cons_idx = cons_id;
+ bnxt_db_rx(bp, (u32)cons_id);
+ }
+}
+
+void rx_process(struct bnxt *bp, struct rx_pkt_cmpl *rx_cmp,
+ struct rx_pkt_cmpl_hi *rx_cmp_hi)
+{
+ u32 desc_idx = rx_cmp->opaque;
+ u8 *iob = bp->rx.iob[desc_idx];
+
+ dump_rx_bd(rx_cmp, rx_cmp_hi, desc_idx);
+ bp->rx.iob_len = rx_cmp->len;
+ bp->rx.iob_rx = iob;
+ if (bnxt_rx_drop(bp, iob, rx_cmp_hi))
+ bp->rx.iob_recv = PKT_DROPPED;
+ else
+ bp->rx.iob_recv = PKT_RECEIVED;
+
+ bp->rx.rx_cnt++;
+
+ dbg_rxp(bp->rx.iob_rx, bp->rx.iob_len, bp->rx.iob_recv);
+ bnxt_adv_rx_index(bp, iob, desc_idx);
+ bnxt_adv_cq_index(bp, 2); /* Rx completion is 2 entries. */
+}
+
+static int bnxt_rx_complete(struct bnxt *bp, struct rx_pkt_cmpl *rx_cmp)
+{
+ struct rx_pkt_cmpl_hi *rx_cmp_hi;
+ u8 completion_bit = bp->cq.completion_bit;
+
+ if (bp->cq.cons_idx == (bp->cq.ring_cnt - 1)) {
+ rx_cmp_hi = (struct rx_pkt_cmpl_hi *)bp->cq.bd_virt;
+ completion_bit ^= 0x1; /* Ring has wrapped. */
+ } else {
+ rx_cmp_hi = (struct rx_pkt_cmpl_hi *)(rx_cmp + 1);
+ }
+
+ if (!((rx_cmp_hi->errors_v2 & RX_PKT_CMPL_V2) ^ completion_bit))
+ rx_process(bp, rx_cmp, rx_cmp_hi);
+
+ return NO_MORE_CQ_BD_TO_SERVICE;
+}
+
+static int bnxt_hwrm_ver_get(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_ver_get_input);
+ struct hwrm_ver_get_input *req;
+ struct hwrm_ver_get_output *resp;
+ int rc;
+
+ req = (struct hwrm_ver_get_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_ver_get_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_VER_GET, cmd_len);
+ req->hwrm_intf_maj = HWRM_VERSION_MAJOR;
+ req->hwrm_intf_min = HWRM_VERSION_MINOR;
+ req->hwrm_intf_upd = HWRM_VERSION_UPDATE;
+ rc = wait_resp(bp, HWRM_CMD_DEFAULT_TIMEOUT, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ bp->hwrm_spec_code =
+ resp->hwrm_intf_maj_8b << 16 |
+ resp->hwrm_intf_min_8b << 8 |
+ resp->hwrm_intf_upd_8b;
+ bp->hwrm_cmd_timeout = (u32)resp->def_req_timeout;
+ if (!bp->hwrm_cmd_timeout)
+ bp->hwrm_cmd_timeout = (u32)HWRM_CMD_DEFAULT_TIMEOUT;
+
+ if (resp->hwrm_intf_maj_8b >= 1)
+ bp->hwrm_max_req_len = resp->max_req_win_len;
+
+ bp->chip_id =
+ resp->chip_rev << 24 |
+ resp->chip_metal << 16 |
+ resp->chip_bond_id << 8 |
+ resp->chip_platform_type;
+ bp->chip_num = resp->chip_num;
+ if ((resp->dev_caps_cfg & SHORT_CMD_SUPPORTED) &&
+ (resp->dev_caps_cfg & SHORT_CMD_REQUIRED))
+ FLAG_SET(bp->flags, BNXT_FLAG_HWRM_SHORT_CMD_SUPP);
+
+ bp->hwrm_max_ext_req_len = resp->max_ext_req_len;
+ bp->fw_maj = resp->hwrm_fw_maj_8b;
+ bp->fw_min = resp->hwrm_fw_min_8b;
+ bp->fw_bld = resp->hwrm_fw_bld_8b;
+ bp->fw_rsvd = resp->hwrm_fw_rsvd_8b;
+ print_fw_ver(resp, bp->hwrm_cmd_timeout);
+
+ return STATUS_SUCCESS;
+}
+
+/* Broadcom ethernet driver Function HW cmds APIs. */
+static int bnxt_hwrm_func_resource_qcaps(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_resource_qcaps_input);
+ struct hwrm_func_resource_qcaps_input *req;
+ struct hwrm_func_resource_qcaps_output *resp;
+ int rc;
+
+ req = (struct hwrm_func_resource_qcaps_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_func_resource_qcaps_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_RESOURCE_QCAPS, cmd_len);
+ req->fid = (u16)HWRM_NA_SIGNATURE;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc != STATUS_SUCCESS)
+ return STATUS_SUCCESS;
+
+ FLAG_SET(bp->flags, BNXT_FLAG_RESOURCE_QCAPS_SUPPORT);
+ /* VFs */
+ bp->max_vfs = resp->max_vfs;
+ bp->vf_res_strategy = resp->vf_reservation_strategy;
+ /* vNICs */
+ bp->min_vnics = resp->min_vnics;
+ bp->max_vnics = resp->max_vnics;
+ /* MSI-X */
+ bp->max_msix = resp->max_msix;
+ /* Ring Groups */
+ bp->min_hw_ring_grps = resp->min_hw_ring_grps;
+ bp->max_hw_ring_grps = resp->max_hw_ring_grps;
+ /* TX Rings */
+ bp->min_tx_rings = resp->min_tx_rings;
+ bp->max_tx_rings = resp->max_tx_rings;
+ /* RX Rings */
+ bp->min_rx_rings = resp->min_rx_rings;
+ bp->max_rx_rings = resp->max_rx_rings;
+ /* Completion Rings */
+ bp->min_cp_rings = resp->min_cmpl_rings;
+ bp->max_cp_rings = resp->max_cmpl_rings;
+ /* RSS Contexts */
+ bp->min_rsscos_ctxs = resp->min_rsscos_ctx;
+ bp->max_rsscos_ctxs = resp->max_rsscos_ctx;
+ /* L2 Contexts */
+ bp->min_l2_ctxs = resp->min_l2_ctxs;
+ bp->max_l2_ctxs = resp->max_l2_ctxs;
+ /* Statistic Contexts */
+ bp->min_stat_ctxs = resp->min_stat_ctx;
+ bp->max_stat_ctxs = resp->max_stat_ctx;
+ dbg_func_resource_qcaps(bp);
+
+ return STATUS_SUCCESS;
+}
+
+static u32 set_ring_info(struct bnxt *bp)
+{
+ u32 enables = 0;
+
+ bp->num_cmpl_rings = DEFAULT_NUMBER_OF_CMPL_RINGS;
+ bp->num_tx_rings = DEFAULT_NUMBER_OF_TX_RINGS;
+ bp->num_rx_rings = DEFAULT_NUMBER_OF_RX_RINGS;
+ bp->num_hw_ring_grps = DEFAULT_NUMBER_OF_RING_GRPS;
+ bp->num_stat_ctxs = DEFAULT_NUMBER_OF_STAT_CTXS;
+ if (bp->min_cp_rings <= DEFAULT_NUMBER_OF_CMPL_RINGS)
+ bp->num_cmpl_rings = bp->min_cp_rings;
+
+ if (bp->min_tx_rings <= DEFAULT_NUMBER_OF_TX_RINGS)
+ bp->num_tx_rings = bp->min_tx_rings;
+
+ if (bp->min_rx_rings <= DEFAULT_NUMBER_OF_RX_RINGS)
+ bp->num_rx_rings = bp->min_rx_rings;
+
+ if (bp->min_hw_ring_grps <= DEFAULT_NUMBER_OF_RING_GRPS)
+ bp->num_hw_ring_grps = bp->min_hw_ring_grps;
+
+ if (bp->min_stat_ctxs <= DEFAULT_NUMBER_OF_STAT_CTXS)
+ bp->num_stat_ctxs = bp->min_stat_ctxs;
+
+ print_num_rings(bp);
+ enables = (FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+ FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS |
+ FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS |
+ FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
+ FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS);
+
+ return enables;
+}
+
+static void bnxt_hwrm_assign_resources(struct bnxt *bp)
+{
+ struct hwrm_func_cfg_input *req;
+ u32 enables = 0;
+
+ if (FLAG_TEST(bp->flags, BNXT_FLAG_RESOURCE_QCAPS_SUPPORT))
+ enables = set_ring_info(bp);
+
+ req = (struct hwrm_func_cfg_input *)bp->hwrm_addr_req;
+ req->num_cmpl_rings = bp->num_cmpl_rings;
+ req->num_tx_rings = bp->num_tx_rings;
+ req->num_rx_rings = bp->num_rx_rings;
+ req->num_stat_ctxs = bp->num_stat_ctxs;
+ req->num_hw_ring_grps = bp->num_hw_ring_grps;
+ req->enables = enables;
+}
+
+int bnxt_hwrm_nvm_flush(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_nvm_flush_input);
+ struct hwrm_nvm_flush_input *req;
+ int rc;
+
+ req = (struct hwrm_nvm_flush_input *)bp->hwrm_addr_req;
+
+ hwrm_init(bp, (void *)req, (u16)HWRM_NVM_FLUSH, cmd_len);
+
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_func_qcaps_req(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_qcaps_input);
+ struct hwrm_func_qcaps_input *req;
+ struct hwrm_func_qcaps_output *resp;
+ int rc;
+
+ req = (struct hwrm_func_qcaps_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_func_qcaps_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_QCAPS, cmd_len);
+ req->fid = (u16)HWRM_NA_SIGNATURE;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ bp->fid = resp->fid;
+ bp->port_idx = (u8)resp->port_id;
+
+ /* Get MAC address for this PF */
+ memcpy(&bp->mac_addr[0], &resp->mac_address[0], ETH_ALEN);
+
+ memcpy(&bp->mac_set[0], &bp->mac_addr[0], ETH_ALEN);
+
+ print_func_qcaps(bp);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_func_qcfg_req(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_qcfg_input);
+ struct hwrm_func_qcfg_input *req;
+ struct hwrm_func_qcfg_output *resp;
+ int rc;
+
+ req = (struct hwrm_func_qcfg_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_func_qcfg_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_QCFG, cmd_len);
+ req->fid = (u16)HWRM_NA_SIGNATURE;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ if (resp->flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)
+ FLAG_SET(bp->flags, BNXT_FLAG_MULTI_HOST);
+
+ if (resp->port_partition_type &
+ FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0)
+ FLAG_SET(bp->flags, BNXT_FLAG_NPAR_MODE);
+
+ bp->ordinal_value = (u8)resp->pci_id & 0x0F;
+ bp->stat_ctx_id = resp->stat_ctx_id;
+ memcpy(&bp->mac_addr[0], &resp->mac_address[0], ETH_ALEN);
+ print_func_qcfg(bp);
+ dbg_flags(__func__, bp->flags);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_func_reset_req(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_reset_input);
+ struct hwrm_func_reset_input *req;
+
+ req = (struct hwrm_func_reset_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_RESET, cmd_len);
+ req->func_reset_level = FUNC_RESET_REQ_FUNC_RESET_LEVEL_RESETME;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_hwrm_func_cfg_req(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_cfg_input);
+ struct hwrm_func_cfg_input *req;
+
+ req = (struct hwrm_func_cfg_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_CFG, cmd_len);
+ req->fid = (u16)HWRM_NA_SIGNATURE;
+ bnxt_hwrm_assign_resources(bp);
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_drv_rgtr_input);
+ struct hwrm_func_drv_rgtr_input *req;
+ int rc;
+
+ req = (struct hwrm_func_drv_rgtr_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_DRV_RGTR, cmd_len);
+ /* Register with HWRM */
+ req->enables = FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE |
+ FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD |
+ FUNC_DRV_RGTR_REQ_ENABLES_VER;
+ req->async_event_fwd[0] |= 0x01;
+ req->os_type = FUNC_DRV_RGTR_REQ_OS_TYPE_OTHER;
+ req->ver_maj = DRIVER_VERSION_MAJOR;
+ req->ver_min = DRIVER_VERSION_MINOR;
+ req->ver_upd = DRIVER_VERSION_UPDATE;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_SET(bp->flag_hwrm, VALID_DRIVER_REG);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_drv_unrgtr_input);
+ struct hwrm_func_drv_unrgtr_input *req;
+ int rc;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_DRIVER_REG)))
+ return STATUS_SUCCESS;
+
+ req = (struct hwrm_func_drv_unrgtr_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_DRV_UNRGTR, cmd_len);
+ req->flags = FUNC_DRV_UNRGTR_REQ_FLAGS_PREPARE_FOR_SHUTDOWN;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_RESET(bp->flag_hwrm, VALID_DRIVER_REG);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_cfa_l2_filter_alloc(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_cfa_l2_filter_alloc_input);
+ struct hwrm_cfa_l2_filter_alloc_input *req;
+ struct hwrm_cfa_l2_filter_alloc_output *resp;
+ int rc;
+ u32 flags = CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX;
+ u32 enables;
+
+ req = (struct hwrm_cfa_l2_filter_alloc_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_cfa_l2_filter_alloc_output *)bp->hwrm_addr_resp;
+ enables = CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK;
+
+ hwrm_init(bp, (void *)req, (u16)HWRM_CFA_L2_FILTER_ALLOC, cmd_len);
+ req->flags = flags;
+ req->enables = enables;
+ memcpy((char *)&req->l2_addr[0], (char *)&bp->mac_set[0], ETH_ALEN);
+ memset((char *)&req->l2_addr_mask[0], 0xff, ETH_ALEN);
+ memcpy((char *)&req->t_l2_addr[0], (char *)&bp->mac_set[0], ETH_ALEN);
+ memset((char *)&req->t_l2_addr_mask[0], 0xff, ETH_ALEN);
+ req->src_type = CFA_L2_FILTER_ALLOC_REQ_SRC_TYPE_NPORT;
+ req->src_id = (u32)bp->port_idx;
+ req->dst_id = bp->vnic_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_SET(bp->flag_hwrm, VALID_L2_FILTER);
+ bp->l2_filter_id = resp->l2_filter_id;
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_cfa_l2_filter_free(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_cfa_l2_filter_free_input);
+ struct hwrm_cfa_l2_filter_free_input *req;
+ int rc;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_L2_FILTER)))
+ return STATUS_SUCCESS;
+
+ req = (struct hwrm_cfa_l2_filter_free_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_CFA_L2_FILTER_FREE, cmd_len);
+ req->l2_filter_id = bp->l2_filter_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_RESET(bp->flag_hwrm, VALID_L2_FILTER);
+
+ return STATUS_SUCCESS;
+}
+
+u32 bnxt_set_rx_mask(u32 rx_mask)
+{
+ u32 mask = 0;
+
+ if (!rx_mask)
+ return mask;
+ mask = CFA_L2_SET_RX_MASK_REQ_MASK_BCAST;
+ if (rx_mask != RX_MASK_ACCEPT_NONE) {
+ if (rx_mask & RX_MASK_ACCEPT_MULTICAST)
+ mask |= CFA_L2_SET_RX_MASK_REQ_MASK_MCAST;
+
+ if (rx_mask & RX_MASK_ACCEPT_ALL_MULTICAST)
+ mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
+
+ if (rx_mask & RX_MASK_PROMISCUOUS_MODE)
+ mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
+ }
+
+ return mask;
+}
+
+static int bnxt_hwrm_set_rx_mask(struct bnxt *bp, u32 rx_mask)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_cfa_l2_set_rx_mask_input);
+ struct hwrm_cfa_l2_set_rx_mask_input *req;
+ u32 mask = bnxt_set_rx_mask(rx_mask);
+
+ req = (struct hwrm_cfa_l2_set_rx_mask_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_CFA_L2_SET_RX_MASK, cmd_len);
+ req->vnic_id = bp->vnic_id;
+ req->mask = mask;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_hwrm_port_mac_cfg(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_port_mac_cfg_input);
+ struct hwrm_port_mac_cfg_input *req;
+
+ req = (struct hwrm_port_mac_cfg_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_PORT_MAC_CFG, cmd_len);
+ req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_hwrm_port_phy_qcfg(struct bnxt *bp, u16 idx)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_port_phy_qcfg_input);
+ struct hwrm_port_phy_qcfg_input *req;
+ struct hwrm_port_phy_qcfg_output *resp;
+ int rc;
+
+ req = (struct hwrm_port_phy_qcfg_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_port_phy_qcfg_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_PORT_PHY_QCFG, cmd_len);
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ if (idx & SUPPORT_SPEEDS)
+ bp->support_speeds = resp->support_speeds;
+
+ if (idx & DETECT_MEDIA)
+ bp->media_detect = resp->module_status;
+
+ if (idx & PHY_SPEED)
+ bp->current_link_speed = resp->link_speed;
+
+ if (idx & PHY_STATUS) {
+ if (resp->link == PORT_PHY_QCFG_RESP_LINK_LINK)
+ bp->link_status = STATUS_LINK_ACTIVE;
+ else
+ bp->link_status = STATUS_LINK_DOWN;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+u16 set_link_speed_mask(u16 link_cap)
+{
+ u16 speed_mask = 0;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_100M)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100MB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_1G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_1GB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_10G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10GB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_25G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_25GB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_40G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_40GB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_50G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_50GB;
+
+ if (link_cap & SPEED_CAPABILITY_DRV_100G)
+ speed_mask |= PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100GB;
+
+ return speed_mask;
+}
+
+static int bnxt_hwrm_port_phy_cfg(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_port_phy_cfg_input);
+ struct hwrm_port_phy_cfg_input *req;
+ u32 flags;
+ u32 enables = 0;
+ u16 force_link_speed = 0;
+ u16 auto_link_speed_mask = 0;
+ u8 auto_mode = 0;
+ u8 auto_pause = 0;
+ u8 auto_duplex = 0;
+
+ /*
+ * If multi_host or NPAR is set to TRUE,
+ * do not issue hwrm_port_phy_cfg
+ */
+ if (FLAG_TEST(bp->flags, PORT_PHY_FLAGS)) {
+ dbg_flags(__func__, bp->flags);
+ return STATUS_SUCCESS;
+ }
+
+ req = (struct hwrm_port_phy_cfg_input *)bp->hwrm_addr_req;
+ flags = PORT_PHY_CFG_REQ_FLAGS_FORCE |
+ PORT_PHY_CFG_REQ_FLAGS_RESET_PHY;
+
+ switch (GET_MEDIUM_SPEED(bp->medium)) {
+ case MEDIUM_SPEED_1000MBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
+ break;
+ case MEDIUM_SPEED_10GBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
+ break;
+ case MEDIUM_SPEED_25GBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
+ break;
+ case MEDIUM_SPEED_40GBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
+ break;
+ case MEDIUM_SPEED_50GBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
+ break;
+ case MEDIUM_SPEED_100GBPS:
+ force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB;
+ break;
+ default:
+ /* Enable AUTONEG by default */
+ auto_mode = PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK;
+ flags &= ~PORT_PHY_CFG_REQ_FLAGS_FORCE;
+ enables |= PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE |
+ PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK |
+ PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX |
+ PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE;
+ auto_pause = PORT_PHY_CFG_REQ_AUTO_PAUSE_TX |
+ PORT_PHY_CFG_REQ_AUTO_PAUSE_RX;
+ auto_duplex = PORT_PHY_CFG_REQ_AUTO_DUPLEX_BOTH;
+ auto_link_speed_mask = bp->support_speeds;
+ break;
+ }
+
+ hwrm_init(bp, (void *)req, (u16)HWRM_PORT_PHY_CFG, cmd_len);
+ req->flags = flags;
+ req->enables = enables;
+ req->port_id = bp->port_idx;
+ req->force_link_speed = force_link_speed;
+ req->auto_mode = auto_mode;
+ req->auto_duplex = auto_duplex;
+ req->auto_pause = auto_pause;
+ req->auto_link_speed_mask = auto_link_speed_mask;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_qphy_link(struct bnxt *bp)
+{
+ u16 flag = QCFG_PHY_ALL;
+
+ /* Query Link Status */
+ if (bnxt_hwrm_port_phy_qcfg(bp, flag) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+
+ if (bp->link_status != STATUS_LINK_ACTIVE) {
+ /*
+ * Configure link if it is not up.
+ * try to bring link up, but don't return
+ * failure if port_phy_cfg() fails
+ */
+ bnxt_hwrm_port_phy_cfg(bp);
+ /* refresh link speed values after bringing link up */
+ if (bnxt_hwrm_port_phy_qcfg(bp, flag) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_stat_ctx_alloc(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_stat_ctx_alloc_input);
+ struct hwrm_stat_ctx_alloc_input *req;
+ struct hwrm_stat_ctx_alloc_output *resp;
+ int rc;
+
+ req = (struct hwrm_stat_ctx_alloc_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_stat_ctx_alloc_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_STAT_CTX_ALLOC, cmd_len);
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_SET(bp->flag_hwrm, VALID_STAT_CTX);
+ bp->stat_ctx_id = (u16)resp->stat_ctx_id;
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_stat_ctx_free(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_stat_ctx_free_input);
+ struct hwrm_stat_ctx_free_input *req;
+ int rc;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_STAT_CTX)))
+ return STATUS_SUCCESS;
+
+ req = (struct hwrm_stat_ctx_free_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_STAT_CTX_FREE, cmd_len);
+ req->stat_ctx_id = (u32)bp->stat_ctx_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_RESET(bp->flag_hwrm, VALID_STAT_CTX);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_ring_free_grp(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_ring_grp_free_input);
+ struct hwrm_ring_grp_free_input *req;
+ int rc;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_RING_GRP)))
+ return STATUS_SUCCESS;
+
+ req = (struct hwrm_ring_grp_free_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_RING_GRP_FREE, cmd_len);
+ req->ring_group_id = (u32)bp->ring_grp_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_RESET(bp->flag_hwrm, VALID_RING_GRP);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_ring_alloc_grp(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_ring_grp_alloc_input);
+ struct hwrm_ring_grp_alloc_input *req;
+ struct hwrm_ring_grp_alloc_output *resp;
+ int rc;
+
+ req = (struct hwrm_ring_grp_alloc_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_ring_grp_alloc_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_RING_GRP_ALLOC, cmd_len);
+ req->cr = bp->cq_ring_id;
+ req->rr = bp->rx_ring_id;
+ req->ar = (u16)HWRM_NA_SIGNATURE;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_SET(bp->flag_hwrm, VALID_RING_GRP);
+ bp->ring_grp_id = (u16)resp->ring_group_id;
+
+ return STATUS_SUCCESS;
+}
+
+int bnxt_hwrm_ring_free(struct bnxt *bp, u16 ring_id, u8 ring_type)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_ring_free_input);
+ struct hwrm_ring_free_input *req;
+
+ req = (struct hwrm_ring_free_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_RING_FREE, cmd_len);
+ req->ring_type = ring_type;
+ req->ring_id = ring_id;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int bnxt_hwrm_ring_alloc(struct bnxt *bp,
+ dma_addr_t ring_map,
+ u16 length,
+ u16 ring_id,
+ u8 ring_type,
+ u8 int_mode)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_ring_alloc_input);
+ struct hwrm_ring_alloc_input *req;
+ struct hwrm_ring_alloc_output *resp;
+ int rc;
+
+ req = (struct hwrm_ring_alloc_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_ring_alloc_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_RING_ALLOC, cmd_len);
+ req->ring_type = ring_type;
+ req->page_tbl_addr = ring_map;
+ req->page_size = LM_PAGE_SIZE;
+ req->length = (u32)length;
+ req->cmpl_ring_id = ring_id;
+ req->int_mode = int_mode;
+ if (ring_type == RING_ALLOC_REQ_RING_TYPE_TX) {
+ req->queue_id = TX_RING_QID;
+ } else if (ring_type == RING_ALLOC_REQ_RING_TYPE_RX) {
+ req->queue_id = RX_RING_QID;
+ req->enables = RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID;
+ req->rx_buf_size = MAX_ETHERNET_PACKET_BUFFER_SIZE;
+ }
+
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ if (ring_type == RING_ALLOC_REQ_RING_TYPE_L2_CMPL) {
+ FLAG_SET(bp->flag_hwrm, VALID_RING_CQ);
+ bp->cq_ring_id = resp->ring_id;
+ } else if (ring_type == RING_ALLOC_REQ_RING_TYPE_TX) {
+ FLAG_SET(bp->flag_hwrm, VALID_RING_TX);
+ bp->tx_ring_id = resp->ring_id;
+ } else if (ring_type == RING_ALLOC_REQ_RING_TYPE_RX) {
+ FLAG_SET(bp->flag_hwrm, VALID_RING_RX);
+ bp->rx_ring_id = resp->ring_id;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_ring_alloc_cq(struct bnxt *bp)
+{
+ return bnxt_hwrm_ring_alloc(bp,
+ virt_to_bus(bp->cq.bd_virt),
+ bp->cq.ring_cnt,
+ 0,
+ RING_ALLOC_REQ_RING_TYPE_L2_CMPL,
+ BNXT_CQ_INTR_MODE());
+}
+
+static int bnxt_hwrm_ring_alloc_tx(struct bnxt *bp)
+{
+ return bnxt_hwrm_ring_alloc(bp,
+ virt_to_bus(bp->tx.bd_virt),
+ bp->tx.ring_cnt, bp->cq_ring_id,
+ RING_ALLOC_REQ_RING_TYPE_TX,
+ BNXT_INTR_MODE());
+}
+
+static int bnxt_hwrm_ring_alloc_rx(struct bnxt *bp)
+{
+ return bnxt_hwrm_ring_alloc(bp,
+ virt_to_bus(bp->rx.bd_virt),
+ bp->rx.ring_cnt,
+ bp->cq_ring_id,
+ RING_ALLOC_REQ_RING_TYPE_RX,
+ BNXT_INTR_MODE());
+}
+
+static int bnxt_hwrm_ring_free_cq(struct bnxt *bp)
+{
+ int ret = STATUS_SUCCESS;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_RING_CQ)))
+ return ret;
+
+ ret = RING_FREE(bp, bp->cq_ring_id, RING_FREE_REQ_RING_TYPE_L2_CMPL);
+ if (ret == STATUS_SUCCESS)
+ FLAG_RESET(bp->flag_hwrm, VALID_RING_CQ);
+
+ return ret;
+}
+
+static int bnxt_hwrm_ring_free_tx(struct bnxt *bp)
+{
+ int ret = STATUS_SUCCESS;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_RING_TX)))
+ return ret;
+
+ ret = RING_FREE(bp, bp->tx_ring_id, RING_FREE_REQ_RING_TYPE_TX);
+ if (ret == STATUS_SUCCESS)
+ FLAG_RESET(bp->flag_hwrm, VALID_RING_TX);
+
+ return ret;
+}
+
+static int bnxt_hwrm_ring_free_rx(struct bnxt *bp)
+{
+ int ret = STATUS_SUCCESS;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_RING_RX)))
+ return ret;
+
+ ret = RING_FREE(bp, bp->rx_ring_id, RING_FREE_REQ_RING_TYPE_RX);
+ if (ret == STATUS_SUCCESS)
+ FLAG_RESET(bp->flag_hwrm, VALID_RING_RX);
+
+ return ret;
+}
+
+static int bnxt_hwrm_vnic_alloc(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_vnic_alloc_input);
+ struct hwrm_vnic_alloc_input *req;
+ struct hwrm_vnic_alloc_output *resp;
+ int rc;
+
+ req = (struct hwrm_vnic_alloc_input *)bp->hwrm_addr_req;
+ resp = (struct hwrm_vnic_alloc_output *)bp->hwrm_addr_resp;
+ hwrm_init(bp, (void *)req, (u16)HWRM_VNIC_ALLOC, cmd_len);
+ req->flags = VNIC_ALLOC_REQ_FLAGS_DEFAULT;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_SET(bp->flag_hwrm, VALID_VNIC_ID);
+ bp->vnic_id = resp->vnic_id;
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_vnic_free(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_vnic_free_input);
+ struct hwrm_vnic_free_input *req;
+ int rc;
+
+ if (!(FLAG_TEST(bp->flag_hwrm, VALID_VNIC_ID)))
+ return STATUS_SUCCESS;
+
+ req = (struct hwrm_vnic_free_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_VNIC_FREE, cmd_len);
+ req->vnic_id = bp->vnic_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+ if (rc)
+ return STATUS_FAILURE;
+
+ FLAG_RESET(bp->flag_hwrm, VALID_VNIC_ID);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_vnic_cfg(struct bnxt *bp)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_vnic_cfg_input);
+ struct hwrm_vnic_cfg_input *req;
+
+ req = (struct hwrm_vnic_cfg_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_VNIC_CFG, cmd_len);
+ req->enables = VNIC_CFG_REQ_ENABLES_MRU;
+ req->mru = bp->mtu;
+ req->enables |= VNIC_CFG_REQ_ENABLES_DFLT_RING_GRP;
+ req->dflt_ring_grp = bp->ring_grp_id;
+ req->vnic_id = bp->vnic_id;
+
+ return wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+}
+
+static int set_phy_speed(struct bnxt *bp)
+{
+ char name[20];
+ u16 flag = PHY_STATUS | PHY_SPEED | DETECT_MEDIA;
+
+ /* Query Link Status */
+ if (bnxt_hwrm_port_phy_qcfg(bp, flag) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+
+ switch (bp->current_link_speed) {
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_100GB:
+ sprintf(name, "%s %s", str_100, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_50GB:
+ sprintf(name, "%s %s", str_50, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_40GB:
+ sprintf(name, "%s %s", str_40, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_25GB:
+ sprintf(name, "%s %s", str_25, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_20GB:
+ sprintf(name, "%s %s", str_20, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_10GB:
+ sprintf(name, "%s %s", str_10, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_2_5GB:
+ sprintf(name, "%s %s", str_2_5, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_2GB:
+ sprintf(name, "%s %s", str_2, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_1GB:
+ sprintf(name, "%s %s", str_1, str_gbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_100MB:
+ sprintf(name, "%s %s", str_100, str_mbps);
+ break;
+ case PORT_PHY_QCFG_RESP_LINK_SPEED_10MB:
+ sprintf(name, "%s %s", str_10, str_mbps);
+ break;
+ default:
+ sprintf(name, "%s %x", str_unknown, bp->current_link_speed);
+ }
+
+ dbg_phy_speed(bp, name);
+
+ return STATUS_SUCCESS;
+}
+
+static int set_phy_link(struct bnxt *bp, u32 tmo)
+{
+ int ret;
+
+ set_phy_speed(bp);
+ dbg_link_status(bp);
+ ret = STATUS_FAILURE;
+ if (bp->link_status == STATUS_LINK_ACTIVE) {
+ dbg_link_state(bp, tmo);
+ ret = STATUS_SUCCESS;
+ }
+
+ return ret;
+}
+
+static int get_phy_link(struct bnxt *bp)
+{
+ u16 flag = PHY_STATUS | PHY_SPEED | DETECT_MEDIA;
+
+ dbg_chip_info(bp);
+ /* Query Link Status */
+ if (bnxt_hwrm_port_phy_qcfg(bp, flag) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+
+ set_phy_link(bp, 100);
+
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_hwrm_set_async_event(struct bnxt *bp)
+{
+ int rc;
+ u16 cmd_len = (u16)sizeof(struct hwrm_func_cfg_input);
+ struct hwrm_func_cfg_input *req;
+
+ req = (struct hwrm_func_cfg_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_FUNC_CFG, cmd_len);
+ req->fid = (u16)HWRM_NA_SIGNATURE;
+ req->enables = FUNC_CFG_REQ_ENABLES_ASYNC_EVENT_CR;
+ req->async_event_cr = bp->cq_ring_id;
+ rc = wait_resp(bp, bp->hwrm_cmd_timeout, cmd_len, __func__);
+
+ return rc;
+}
+
+int bnxt_hwrm_get_nvmem(struct bnxt *bp,
+ u16 data_len,
+ u16 option_num,
+ u16 dimensions,
+ u16 index_0)
+{
+ u16 cmd_len = (u16)sizeof(struct hwrm_nvm_get_variable_input);
+ struct hwrm_nvm_get_variable_input *req;
+
+ req = (struct hwrm_nvm_get_variable_input *)bp->hwrm_addr_req;
+ hwrm_init(bp, (void *)req, (u16)HWRM_NVM_GET_VARIABLE, cmd_len);
+ req->dest_data_addr = bp->data_addr_mapping;
+ req->data_len = data_len;
+ req->option_num = option_num;
+ req->dimensions = dimensions;
+ req->index_0 = index_0;
+
+ return wait_resp(bp,
+ HWRM_CMD_FLASH_MULTIPLAYER(bp->hwrm_cmd_timeout),
+ cmd_len,
+ __func__);
+}
+
+static void set_medium(struct bnxt *bp)
+{
+ switch (bp->link_set & LINK_SPEED_DRV_MASK) {
+ case LINK_SPEED_DRV_1G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_1000MBPS);
+ break;
+ case LINK_SPEED_DRV_2_5G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_2500MBPS);
+ break;
+ case LINK_SPEED_DRV_10G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_10GBPS);
+ break;
+ case LINK_SPEED_DRV_25G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_25GBPS);
+ break;
+ case LINK_SPEED_DRV_40G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_40GBPS);
+ break;
+ case LINK_SPEED_DRV_50G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_50GBPS);
+ break;
+ case LINK_SPEED_DRV_100G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_100GBPS);
+ break;
+ case LINK_SPEED_DRV_200G:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_200GBPS);
+ break;
+ case LINK_SPEED_DRV_AUTONEG:
+ bp->medium = SET_MEDIUM_SPEED(bp, MEDIUM_SPEED_AUTONEG);
+ break;
+ default:
+ bp->medium = SET_MEDIUM_DUPLEX(bp, MEDIUM_FULL_DUPLEX);
+ break;
+ }
+}
+
+static int bnxt_hwrm_get_link_speed(struct bnxt *bp)
+{
+ u32 *ptr32 = (u32 *)bp->hwrm_addr_data;
+
+ if (bnxt_hwrm_get_nvmem(bp,
+ 4,
+ (u16)LINK_SPEED_DRV_NUM,
+ 1,
+ (u16)bp->port_idx) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+
+ bp->link_set = *ptr32;
+ bp->link_set &= SPEED_DRV_MASK;
+ set_medium(bp);
+
+ return STATUS_SUCCESS;
+}
+
+typedef int (*hwrm_func_t)(struct bnxt *bp);
+
+hwrm_func_t down_chip[] = {
+ bnxt_hwrm_cfa_l2_filter_free, /* Free l2 filter */
+ bnxt_free_rx_iob, /* Free rx iob */
+ bnxt_hwrm_vnic_free, /* Free vnic */
+ bnxt_hwrm_ring_free_grp, /* Free ring group */
+ bnxt_hwrm_ring_free_rx, /* Free rx ring */
+ bnxt_hwrm_ring_free_tx, /* Free tx ring */
+ bnxt_hwrm_ring_free_cq, /* Free CQ ring */
+ bnxt_hwrm_stat_ctx_free, /* Free Stat ctx */
+ bnxt_hwrm_func_drv_unrgtr, /* unreg driver */
+ NULL,
+};
+
+hwrm_func_t bring_chip[] = {
+ bnxt_hwrm_ver_get, /* HWRM_VER_GET */
+ bnxt_hwrm_func_reset_req, /* HWRM_FUNC_RESET */
+ bnxt_hwrm_func_drv_rgtr, /* HWRM_FUNC_DRV_RGTR */
+ bnxt_hwrm_func_resource_qcaps, /* HWRM_FUNC_RESOURCE_QCAPS */
+ bnxt_hwrm_func_qcfg_req, /* HWRM_FUNC_QCFG */
+ bnxt_hwrm_func_qcaps_req, /* HWRM_FUNC_QCAPS */
+ bnxt_hwrm_get_link_speed, /* HWRM_NVM_GET_VARIABLE - 203 */
+ bnxt_hwrm_port_mac_cfg, /* HWRM_PORT_MAC_CFG */
+ bnxt_qphy_link, /* HWRM_PORT_PHY_QCFG */
+ bnxt_hwrm_func_cfg_req, /* HWRM_FUNC_CFG - ring resource*/
+ bnxt_hwrm_stat_ctx_alloc, /* Allocate Stat Ctx ID */
+ bnxt_hwrm_ring_alloc_cq, /* Allocate CQ Ring */
+ bnxt_hwrm_ring_alloc_tx, /* Allocate Tx ring */
+ bnxt_hwrm_ring_alloc_rx, /* Allocate Rx Ring */
+ bnxt_hwrm_ring_alloc_grp, /* Create Ring Group */
+ post_rx_buffers, /* Post RX buffers */
+ bnxt_hwrm_set_async_event, /* ENABLES_ASYNC_EVENT_CR */
+ bnxt_hwrm_vnic_alloc, /* Alloc VNIC */
+ bnxt_hwrm_vnic_cfg, /* Config VNIC */
+ bnxt_hwrm_cfa_l2_filter_alloc, /* Alloc L2 Filter */
+ get_phy_link, /* Get Physical Link */
+ NULL,
+};
+
+int bnxt_hwrm_run(hwrm_func_t cmds[], struct bnxt *bp, int flag)
+{
+ hwrm_func_t *ptr;
+ int ret;
+ int status = STATUS_SUCCESS;
+
+ for (ptr = cmds; *ptr; ++ptr) {
+ ret = (*ptr)(bp);
+ if (ret) {
+ status = STATUS_FAILURE;
+ /* Continue till all cleanup routines are called */
+ if (flag)
+ return STATUS_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/* Broadcom ethernet driver Network interface APIs. */
+static int bnxt_start(struct udevice *dev)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+
+ if (bnxt_hwrm_set_rx_mask(bp, RX_MASK) != STATUS_SUCCESS)
+ return STATUS_FAILURE;
+
+ bp->card_en = true;
+ return STATUS_SUCCESS;
+}
+
+static int bnxt_send(struct udevice *dev, void *packet, int length)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+ int len;
+ u16 entry;
+ dma_addr_t mapping;
+
+ if (bnxt_tx_avail(bp) < 1) {
+ dbg_no_tx_bd();
+ return -ENOBUFS;
+ }
+
+ entry = bp->tx.prod_id;
+ len = iob_pad(packet, length);
+ mapping = virt_to_bus(packet);
+ set_txq(bp, entry, mapping, len);
+ entry = NEXT_IDX(entry, bp->tx.ring_cnt);
+ dump_tx_pkt(packet, mapping, len);
+ bnxt_db_tx(bp, (u32)entry);
+ bp->tx.prod_id = entry;
+ bp->tx.cnt_req++;
+ bnxt_tx_complete(bp);
+
+ return 0;
+}
+
+static void bnxt_link_evt(struct bnxt *bp, struct cmpl_base *cmp)
+{
+ struct hwrm_async_event_cmpl *evt;
+
+ evt = (struct hwrm_async_event_cmpl *)cmp;
+ switch (evt->event_id) {
+ case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
+ if (evt->event_data1 & 0x01)
+ bp->link_status = STATUS_LINK_ACTIVE;
+ else
+ bp->link_status = STATUS_LINK_DOWN;
+
+ set_phy_link(bp, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static int bnxt_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+ struct cmpl_base *cmp;
+ u16 old_cons_idx = bp->cq.cons_idx;
+ int done = SERVICE_NEXT_CQ_BD;
+ u32 cq_type;
+
+ while (done == SERVICE_NEXT_CQ_BD) {
+ cmp = (struct cmpl_base *)BD_NOW(bp->cq.bd_virt,
+ bp->cq.cons_idx,
+ sizeof(struct cmpl_base));
+ if ((cmp->info3_v & CMPL_BASE_V) ^ bp->cq.completion_bit)
+ break;
+
+ cq_type = cmp->type & CMPL_BASE_TYPE_MASK;
+ dump_evt((u8 *)cmp, cq_type, bp->cq.cons_idx);
+ dump_CQ(cmp, bp->cq.cons_idx);
+ switch (cq_type) {
+ case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
+ bnxt_link_evt(bp, cmp);
+ fallthrough;
+ case CMPL_BASE_TYPE_TX_L2:
+ case CMPL_BASE_TYPE_STAT_EJECT:
+ bnxt_adv_cq_index(bp, 1);
+ break;
+ case CMPL_BASE_TYPE_RX_L2:
+ done = bnxt_rx_complete(bp, (struct rx_pkt_cmpl *)cmp);
+ break;
+ default:
+ done = NO_MORE_CQ_BD_TO_SERVICE;
+ break;
+ }
+ }
+
+ if (bp->cq.cons_idx != old_cons_idx)
+ bnxt_db_cq(bp);
+
+ if (bp->rx.iob_recv == PKT_RECEIVED) {
+ *packetp = bp->rx.iob_rx;
+ return bp->rx.iob_len;
+ }
+
+ return -EAGAIN;
+}
+
+static void bnxt_stop(struct udevice *dev)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+
+ if (bp->card_en) {
+ bnxt_hwrm_set_rx_mask(bp, 0);
+ bp->card_en = false;
+ }
+}
+
+static int bnxt_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+
+ dbg_rx_pkt(bp, __func__, packet, length);
+ bp->rx.iob_recv = PKT_DONE;
+ bp->rx.iob_len = 0;
+ bp->rx.iob_rx = NULL;
+
+ return 0;
+}
+
+static int bnxt_read_rom_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_plat(dev);
+ struct bnxt *bp = dev_get_priv(dev);
+
+ memcpy(plat->enetaddr, bp->mac_set, ETH_ALEN);
+
+ return 0;
+}
+
+static const struct eth_ops bnxt_eth_ops = {
+ .start = bnxt_start,
+ .send = bnxt_send,
+ .recv = bnxt_recv,
+ .stop = bnxt_stop,
+ .free_pkt = bnxt_free_pkt,
+ .read_rom_hwaddr = bnxt_read_rom_hwaddr,
+};
+
+static const struct udevice_id bnxt_eth_ids[] = {
+ { .compatible = "broadcom,nxe" },
+ { }
+};
+
+static int bnxt_eth_bind(struct udevice *dev)
+{
+ char name[20];
+
+ sprintf(name, "bnxt_eth%u", dev_seq(dev));
+
+ return device_set_name(dev, name);
+}
+
+static int bnxt_eth_probe(struct udevice *dev)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+ int ret;
+
+ ret = bnxt_alloc_mem(bp);
+ if (ret) {
+ printf("*** error: bnxt_alloc_mem failed! ***\n");
+ return ret;
+ }
+
+ bp->cardnum = dev_seq(dev);
+ bp->name = dev->name;
+ bp->pdev = (struct udevice *)dev;
+
+ bnxt_bring_pci(bp);
+
+ ret = bnxt_bring_chip(bp);
+ if (ret) {
+ printf("*** error: bnxt_bring_chip failed! ***\n");
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int bnxt_eth_remove(struct udevice *dev)
+{
+ struct bnxt *bp = dev_get_priv(dev);
+
+ bnxt_down_chip(bp);
+ bnxt_free_mem(bp);
+
+ return 0;
+}
+
+static struct pci_device_id bnxt_nics[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NXT_57320)},
+ {}
+};
+
+U_BOOT_DRIVER(eth_bnxt) = {
+ .name = "eth_bnxt",
+ .id = UCLASS_ETH,
+ .of_match = bnxt_eth_ids,
+ .bind = bnxt_eth_bind,
+ .probe = bnxt_eth_probe,
+ .remove = bnxt_eth_remove,
+ .ops = &bnxt_eth_ops,
+ .priv_auto = sizeof(struct bnxt),
+ .plat_auto = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ACTIVE_DMA,
+};
+
+U_BOOT_PCI_DEVICE(eth_bnxt, bnxt_nics);
diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h
new file mode 100644
index 00000000000..6c648272af1
--- /dev/null
+++ b/drivers/net/bnxt/bnxt.h
@@ -0,0 +1,390 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019-2021 Broadcom.
+ */
+
+#ifndef _BNXT_H_
+#define _BNXT_H_
+
+#include <pci.h>
+#include <linux/if_ether.h>
+
+#include "bnxt_hsi.h"
+
+union dma_addr64_t {
+ dma_addr_t addr;
+ u64 as_u64;
+};
+
+#define DRIVER_VERSION_MAJOR 1
+#define DRIVER_VERSION_MINOR 0
+#define DRIVER_VERSION_UPDATE 0
+
+/* Broadcom ethernet driver defines. */
+#define FLAG_SET(f, b) ((f) |= (b))
+#define FLAG_TEST(f, b) ((f) & (b))
+#define FLAG_RESET(f, b) ((f) &= ~(b))
+#define BNXT_FLAG_HWRM_SHORT_CMD_SUPP BIT(0)
+#define BNXT_FLAG_HWRM_SHORT_CMD_REQ BIT(1)
+#define BNXT_FLAG_RESOURCE_QCAPS_SUPPORT BIT(2)
+#define BNXT_FLAG_MULTI_HOST BIT(3)
+#define BNXT_FLAG_NPAR_MODE BIT(4)
+/*******************************************************************************
+ * Status codes.
+ ******************************************************************************/
+#define STATUS_SUCCESS 0
+#define STATUS_FAILURE 1
+#define STATUS_LINK_ACTIVE 4
+#define STATUS_LINK_DOWN 5
+#define STATUS_TIMEOUT 0xffff
+/*******************************************************************************
+ * Receive filter masks.
+ ******************************************************************************/
+#define RX_MASK_ACCEPT_NONE 0x0000
+#define RX_MASK_ACCEPT_MULTICAST 0x0002
+#define RX_MASK_ACCEPT_ALL_MULTICAST 0x0004
+#define RX_MASK_ACCEPT_BROADCAST 0x0008
+#define RX_MASK_PROMISCUOUS_MODE 0x10000
+/*******************************************************************************
+ * media speed.
+ ******************************************************************************/
+#define MEDIUM_SPEED_AUTONEG 0x0000L
+#define MEDIUM_SPEED_1000MBPS 0x0300L
+#define MEDIUM_SPEED_2500MBPS 0x0400L
+#define MEDIUM_SPEED_10GBPS 0x0600L
+#define MEDIUM_SPEED_25GBPS 0x0800L
+#define MEDIUM_SPEED_40GBPS 0x0900L
+#define MEDIUM_SPEED_50GBPS 0x0a00L
+#define MEDIUM_SPEED_100GBPS 0x0b00L
+#define MEDIUM_SPEED_200GBPS 0x0c00L
+#define MEDIUM_SPEED_MASK 0xff00L
+#define GET_MEDIUM_SPEED(m) ((m) & MEDIUM_SPEED_MASK)
+#define SET_MEDIUM_SPEED(bp, s) (((bp)->medium & ~MEDIUM_SPEED_MASK) | (s))
+#define MEDIUM_UNKNOWN_DUPLEX 0x00000L
+#define MEDIUM_FULL_DUPLEX 0x00000L
+#define MEDIUM_HALF_DUPLEX 0x10000L
+#define GET_MEDIUM_DUPLEX(m) ((m) & MEDIUM_HALF_DUPLEX)
+#define SET_MEDIUM_DUPLEX(bp, d) (((bp)->medium & ~MEDIUM_HALF_DUPLEX) | (d))
+#define MEDIUM_SELECTIVE_AUTONEG 0x01000000L
+#define GET_MEDIUM_AUTONEG_MODE(m) ((m) & 0xff000000L)
+#define GRC_COM_CHAN_BASE 0
+#define GRC_COM_CHAN_TRIG 0x100
+#define HWRM_CMD_DEFAULT_TIMEOUT 500 /* in Miliseconds */
+#define HWRM_CMD_POLL_WAIT_TIME 100 /* In MicroeSconds */
+#define HWRM_CMD_DEFAULT_MULTIPLAYER(a) ((a) * 10)
+#define HWRM_CMD_FLASH_MULTIPLAYER(a) ((a) * 100)
+#define HWRM_CMD_FLASH_ERASE_MULTIPLAYER(a) ((a) * 1000)
+#define MAX_ETHERNET_PACKET_BUFFER_SIZE 1536
+#define DEFAULT_NUMBER_OF_CMPL_RINGS 0x01
+#define DEFAULT_NUMBER_OF_TX_RINGS 0x01
+#define DEFAULT_NUMBER_OF_RX_RINGS 0x01
+#define DEFAULT_NUMBER_OF_RING_GRPS 0x01
+#define DEFAULT_NUMBER_OF_STAT_CTXS 0x01
+#define NUM_RX_BUFFERS 512
+#define MAX_RX_DESC_CNT 1024
+#define MAX_TX_DESC_CNT 512
+#define MAX_CQ_DESC_CNT 2048
+#define TX_RING_DMA_BUFFER_SIZE (MAX_TX_DESC_CNT * sizeof(struct tx_bd_short))
+#define RX_RING_DMA_BUFFER_SIZE \
+ (MAX_RX_DESC_CNT * sizeof(struct rx_prod_pkt_bd))
+#define CQ_RING_DMA_BUFFER_SIZE (MAX_CQ_DESC_CNT * sizeof(struct cmpl_base))
+#define BNXT_DMA_ALIGNMENT 256 //64
+#define REQ_BUFFER_SIZE 1024
+#define RESP_BUFFER_SIZE 1024
+#define DMA_BUFFER_SIZE 1024
+#define LM_PAGE_BITS 8
+#define BNXT_RX_STD_DMA_SZ 1536
+#define NEXT_IDX(N, S) (((N) + 1) & ((S) - 1))
+#define BD_NOW(bd, entry, len) (&((u8 *)(bd))[(entry) * (len)])
+#define BNXT_CQ_INTR_MODE() RING_ALLOC_REQ_INT_MODE_POLL
+#define BNXT_INTR_MODE() RING_ALLOC_REQ_INT_MODE_POLL
+/* Set default link timeout period to 500 millseconds */
+#define LINK_DEFAULT_TIMEOUT 500
+#define RX_MASK \
+ (RX_MASK_ACCEPT_BROADCAST | \
+ RX_MASK_ACCEPT_ALL_MULTICAST | \
+ RX_MASK_ACCEPT_MULTICAST)
+#define TX_RING_QID ((u16)bp->port_idx * 10)
+#define RX_RING_QID 0
+#define LM_PAGE_SIZE LM_PAGE_BITS
+#define virt_to_bus(a) ((dma_addr_t)(a))
+#define REQ_BUF_SIZE_ALIGNED ALIGN(REQ_BUFFER_SIZE, BNXT_DMA_ALIGNMENT)
+#define RESP_BUF_SIZE_ALIGNED ALIGN(RESP_BUFFER_SIZE, BNXT_DMA_ALIGNMENT)
+#define DMA_BUF_SIZE_ALIGNED ALIGN(DMA_BUFFER_SIZE, BNXT_DMA_ALIGNMENT)
+#define RX_STD_DMA_ALIGNED ALIGN(BNXT_RX_STD_DMA_SZ, BNXT_DMA_ALIGNMENT)
+#define PCI_COMMAND_INTX_DISABLE 0x0400 /* Interrupt disable */
+#define TX_AVAIL(r) ((r) - 1)
+#define NO_MORE_CQ_BD_TO_SERVICE 1
+#define SERVICE_NEXT_CQ_BD 0
+#define PHY_STATUS 0x0001
+#define PHY_SPEED 0x0002
+#define DETECT_MEDIA 0x0004
+#define SUPPORT_SPEEDS 0x0008
+#define str_1 "1"
+#define str_2 "2"
+#define str_2_5 "2.5"
+#define str_10 "10"
+#define str_20 "20"
+#define str_25 "25"
+#define str_40 "40"
+#define str_50 "50"
+#define str_100 "100"
+#define str_gbps "Gbps"
+#define str_mbps "Mbps"
+#define str_unknown "Unknown"
+/* Broadcom ethernet driver nvm defines. */
+/* nvm cfg 1 - MAC settings */
+#define FUNC_MAC_ADDR_NUM 1
+/* nvm cfg 203 - u32 link_settings */
+#define LINK_SPEED_DRV_NUM 203
+#define LINK_SPEED_DRV_MASK 0x0000000F
+#define LINK_SPEED_DRV_SHIFT 0
+#define LINK_SPEED_DRV_AUTONEG 0x0
+#define LINK_SPEED_DRV_1G 0x1
+#define LINK_SPEED_DRV_10G 0x2
+#define LINK_SPEED_DRV_25G 0x3
+#define LINK_SPEED_DRV_40G 0x4
+#define LINK_SPEED_DRV_50G 0x5
+#define LINK_SPEED_DRV_100G 0x6
+#define LINK_SPEED_DRV_200G 0x7
+#define LINK_SPEED_DRV_2_5G 0xE
+#define LINK_SPEED_DRV_100M 0xF
+/* nvm cfg 201 - u32 speed_cap_mask */
+#define SPEED_CAPABILITY_DRV_1G 0x1
+#define SPEED_CAPABILITY_DRV_10G 0x2
+#define SPEED_CAPABILITY_DRV_25G 0x4
+#define SPEED_CAPABILITY_DRV_40G 0x8
+#define SPEED_CAPABILITY_DRV_50G 0x10
+#define SPEED_CAPABILITY_DRV_100G 0x20
+#define SPEED_CAPABILITY_DRV_100M 0x8000
+/* nvm cfg 202 */
+/* nvm cfg 205 */
+#define LINK_SPEED_FW_NUM 205
+/* nvm cfg 210 */
+/* nvm cfg 211 */
+/* nvm cfg 213 */
+#define SPEED_DRV_MASK LINK_SPEED_DRV_MASK
+/******************************************************************************
+ * Doorbell info.
+ *****************************************************************************/
+#define RX_DOORBELL_KEY_RX (0x1UL << 28)
+#define TX_DOORBELL_KEY_TX (0x0UL << 28)
+
+#define CMPL_DOORBELL_IDX_VALID 0x4000000UL
+#define CMPL_DOORBELL_KEY_CMPL (0x2UL << 28)
+
+/******************************************************************************
+ * Transmit info.
+ *****************************************************************************/
+struct tx_bd_short {
+ u16 flags_type;
+#define TX_BD_SHORT_TYPE_TX_BD_SHORT 0x0UL
+#define TX_BD_SHORT_FLAGS_PACKET_END 0x40UL
+#define TX_BD_SHORT_FLAGS_NO_CMPL 0x80UL
+#define TX_BD_SHORT_FLAGS_BD_CNT_SFT 8
+#define TX_BD_SHORT_FLAGS_LHINT_LT512 (0x0UL << 13)
+#define TX_BD_SHORT_FLAGS_LHINT_LT1K (0x1UL << 13)
+#define TX_BD_SHORT_FLAGS_LHINT_LT2K (0x2UL << 13)
+#define TX_BD_SHORT_FLAGS_LHINT_GTE2K (0x3UL << 13)
+#define TX_BD_SHORT_FLAGS_COAL_NOW 0x8000UL
+ u16 len;
+ u32 opaque;
+ union dma_addr64_t dma;
+};
+
+struct lm_tx_info_t {
+ void *bd_virt;
+ u16 prod_id; /* Tx producer index. */
+ u16 cons_id;
+ u16 ring_cnt;
+ u32 cnt; /* Tx statistics. */
+ u32 cnt_req;
+};
+
+struct cmpl_base {
+ u16 type;
+#define CMPL_BASE_TYPE_MASK 0x3fUL
+#define CMPL_BASE_TYPE_TX_L2 0x0UL
+#define CMPL_BASE_TYPE_RX_L2 0x11UL
+#define CMPL_BASE_TYPE_STAT_EJECT 0x1aUL
+#define CMPL_BASE_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ u16 info1;
+ u32 info2;
+ u32 info3_v;
+#define CMPL_BASE_V 0x1UL
+ u32 info4;
+};
+
+struct lm_cmp_info_t {
+ void *bd_virt;
+ u16 cons_idx;
+ u16 ring_cnt;
+ u8 completion_bit;
+ u8 res[3];
+};
+
+struct rx_pkt_cmpl {
+ u16 flags_type;
+ u16 len;
+ u32 opaque;
+ u8 agg_bufs_v1;
+ u8 rss_hash_type;
+ u8 payload_offset;
+ u8 unused1;
+ u32 rss_hash;
+};
+
+struct rx_pkt_cmpl_hi {
+ u32 flags2;
+ u32 metadata;
+ u16 errors_v2;
+#define RX_PKT_CMPL_V2 0x1UL
+#define RX_PKT_CMPL_ERRORS_BUFFER_ERROR_SFT 1
+ u16 cfa_code;
+ u32 reorder;
+};
+
+struct rx_prod_pkt_bd {
+ u16 flags_type;
+#define RX_PROD_PKT_BD_TYPE_RX_PROD_PKT 0x4UL
+ u16 len;
+ u32 opaque;
+ union dma_addr64_t dma;
+};
+
+struct lm_rx_info_t {
+ void *bd_virt;
+ void *iob[NUM_RX_BUFFERS];
+ void *iob_rx;
+ u16 iob_len;
+ u16 iob_recv;
+ u16 iob_cnt;
+ u16 buf_cnt; /* Total Rx buffer descriptors. */
+ u16 ring_cnt;
+ u16 cons_idx; /* Last processed consumer index. */
+ u32 rx_cnt;
+ u32 rx_buf_cnt;
+ u32 err;
+ u32 crc;
+ u32 dropped;
+};
+
+#define VALID_DRIVER_REG 0x0001
+#define VALID_STAT_CTX 0x0002
+#define VALID_RING_CQ 0x0004
+#define VALID_RING_TX 0x0008
+#define VALID_RING_RX 0x0010
+#define VALID_RING_GRP 0x0020
+#define VALID_VNIC_ID 0x0040
+#define VALID_RX_IOB 0x0080
+#define VALID_L2_FILTER 0x0100
+
+enum RX_FLAGS {
+ PKT_DONE = 0,
+ PKT_RECEIVED = 1,
+ PKT_DROPPED = 2,
+};
+
+struct bnxt {
+ struct udevice *pdev;
+ const char *name;
+ unsigned int cardnum;
+ void *hwrm_addr_req;
+ void *hwrm_addr_resp;
+ void *hwrm_addr_data;
+ dma_addr_t data_addr_mapping;
+ dma_addr_t req_addr_mapping;
+ dma_addr_t resp_addr_mapping;
+ struct lm_tx_info_t tx; /* Tx info. */
+ struct lm_rx_info_t rx; /* Rx info. */
+ struct lm_cmp_info_t cq; /* completion info. */
+ u16 last_resp_code;
+ u16 seq_id;
+ u32 flag_hwrm;
+ u32 flags;
+ u16 vendor_id;
+ u16 device_id;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+ u16 cmd_reg;
+ u8 irq;
+ void __iomem *bar0;
+ void __iomem *bar1;
+ void __iomem *bar2;
+ u16 chip_num;
+ /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+ u32 chip_id;
+ u32 hwrm_cmd_timeout;
+ u16 hwrm_spec_code;
+ u16 hwrm_max_req_len;
+ u16 hwrm_max_ext_req_len;
+ u8 fw_maj;
+ u8 fw_min;
+ u8 fw_bld;
+ u8 fw_rsvd;
+ u8 mac_addr[ETH_ALEN]; /* HW MAC address */
+ u8 mac_set[ETH_ALEN]; /* NVM Configured MAC */
+ u16 fid;
+ u8 port_idx;
+ u8 ordinal_value;
+ u16 mtu;
+ u16 ring_grp_id;
+ u16 cq_ring_id;
+ u16 tx_ring_id;
+ u16 rx_ring_id;
+ u16 current_link_speed;
+ u16 link_status;
+ u16 wait_link_timeout;
+ u64 l2_filter_id;
+ u16 vnic_id;
+ u16 stat_ctx_id;
+ u32 medium;
+ u16 support_speeds;
+ u32 link_set;
+ u8 media_detect;
+ u8 media_change;
+ u16 max_vfs;
+ u16 vf_res_strategy;
+ u16 min_vnics;
+ u16 max_vnics;
+ u16 max_msix;
+ u16 min_hw_ring_grps;
+ u16 max_hw_ring_grps;
+ u16 min_tx_rings;
+ u16 max_tx_rings;
+ u16 min_rx_rings;
+ u16 max_rx_rings;
+ u16 min_cp_rings;
+ u16 max_cp_rings;
+ u16 min_rsscos_ctxs;
+ u16 max_rsscos_ctxs;
+ u16 min_l2_ctxs;
+ u16 max_l2_ctxs;
+ u16 min_stat_ctxs;
+ u16 max_stat_ctxs;
+ u16 num_cmpl_rings;
+ u16 num_tx_rings;
+ u16 num_rx_rings;
+ u16 num_stat_ctxs;
+ u16 num_hw_ring_grps;
+ bool card_en;
+};
+
+#define SHORT_CMD_SUPPORTED VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED
+#define SHORT_CMD_REQUIRED VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED
+#define CQ_DOORBELL_KEY_IDX(a) \
+ (CMPL_DOORBELL_KEY_CMPL | \
+ CMPL_DOORBELL_IDX_VALID | \
+ (u32)(a))
+#define TX_BD_FLAGS \
+ (TX_BD_SHORT_TYPE_TX_BD_SHORT | \
+ TX_BD_SHORT_FLAGS_NO_CMPL | \
+ TX_BD_SHORT_FLAGS_COAL_NOW | \
+ TX_BD_SHORT_FLAGS_PACKET_END | \
+ (1 << TX_BD_SHORT_FLAGS_BD_CNT_SFT))
+#define MEM_HWRM_RESP memalign(BNXT_DMA_ALIGNMENT, RESP_BUF_SIZE_ALIGNED)
+#define PORT_PHY_FLAGS (BNXT_FLAG_NPAR_MODE | BNXT_FLAG_MULTI_HOST)
+#define RING_FREE(bp, rid, flag) bnxt_hwrm_ring_free(bp, rid, flag)
+#define QCFG_PHY_ALL (SUPPORT_SPEEDS | DETECT_MEDIA | PHY_SPEED | PHY_STATUS)
+
+#endif /* _BNXT_H_ */
diff --git a/drivers/net/bnxt/bnxt_dbg.h b/drivers/net/bnxt/bnxt_dbg.h
new file mode 100644
index 00000000000..e9e9f6efefd
--- /dev/null
+++ b/drivers/net/bnxt/bnxt_dbg.h
@@ -0,0 +1,536 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019-2021 Broadcom.
+ */
+
+#ifndef _BXNT_DBG_H_
+#define _BXNT_DBG_H_
+
+/* Adjust commented out lines below to enable debug. */
+/* #define DEBUG_PCI */
+/* #define DEBUG_MEMORY */
+/* #define DEBUG_LINK */
+/* #define DEBUG_CHIP */
+/* #define DEBUG_FAIL */
+/* #define DEBUG_HWRM_CMDS */
+/* #define DEBUG_HWRM_DUMP */
+/* #define DEBUG_CQ */
+/* #define DEBUG_CQ_DUMP */
+/* #define DEBUG_TX */
+/* #define DEBUG_TX_DUMP */
+/* #define DEBUG_RX */
+/* #define DEBUG_RX_DUMP */
+
+#if \
+ defined(DEBUG_PCI) || \
+ defined(DEBUG_MEMORY) || \
+ defined(DEBUG_LINK) || \
+ defined(DEBUG_CHIP) || \
+ defined(DEBUG_FAIL) || \
+ defined(DEBUG_HWRM_CMDS) || \
+ defined(DEBUG_HWRM_DUMP) || \
+ defined(DEBUG_CQ) || \
+ defined(DEBUG_CQ_DUMP) || \
+ defined(DEBUG_TX) || \
+ defined(DEBUG_TX_DUMP) || \
+ defined(DEBUG_RX) || \
+ defined(DEBUG_RX_DUMP)
+#define DEBUG_DEFAULT
+#endif
+
+#if defined(DEBUG_DEFAULT)
+#define dbg_prn printf
+#define MAX_CHAR_SIZE(a) (u32)((1 << (a)) - 1)
+#define DISP_U8 0x00
+#define DISP_U16 0x01
+#define DISP_U32 0x02
+#define DISP_U64 0x03
+
+void dumpmemory1(u8 *buffer, u32 length, u8 flag)
+{
+ u32 jj = 0;
+ u8 i, c;
+
+ printf("\n %p:", buffer);
+ for (jj = 0; jj < 16; jj++) {
+ if (!(jj & MAX_CHAR_SIZE(flag)))
+ printf(" ");
+ if (jj < length)
+ printf("%02x", buffer[jj]);
+ else
+ printf(" ");
+ if ((jj & 0xF) == 0xF) {
+ printf(" ");
+ for (i = 0; i < 16; i++) {
+ if (i < length) {
+ c = buffer[jj + i - 15];
+ if (c >= 0x20 && c < 0x7F)
+ ;
+ else
+ c = '.';
+ printf("%c", c);
+ }
+ }
+ }
+ }
+}
+
+void dump_mem(u8 *buffer, u32 length, u8 flag)
+{
+ u32 length16, remlen, jj;
+
+ length16 = length & 0xFFFFFFF0;
+ remlen = length & 0xF;
+ for (jj = 0; jj < length16; jj += 16)
+ dumpmemory1((u8 *)&buffer[jj], 16, flag);
+ if (remlen)
+ dumpmemory1((u8 *)&buffer[length16], remlen, flag);
+ if (length16 || remlen)
+ printf("\n");
+}
+#endif
+
+#if defined(DEBUG_PCI)
+void dbg_pci(struct bnxt *bp, const char *func, u16 cmd_reg)
+{
+ printf("- %s()\n", func);
+ printf(" Vendor id : %04X\n", bp->vendor_id);
+ printf(" Device id : %04X\n", bp->device_id);
+ printf(" Irq : %d\n", bp->irq);
+ printf(" PCI Command Reg : %04X %04X\n", bp->cmd_reg, cmd_reg);
+ printf(" Sub Vendor id : %04X\n", bp->subsystem_vendor);
+ printf(" Sub Device id : %04X\n", bp->subsystem_device);
+ printf(" BAR (0) : %p\n", bp->bar0);
+ printf(" BAR (1) : %p\n", bp->bar1);
+ printf(" BAR (2) : %p\n", bp->bar2);
+}
+#else
+#define dbg_pci(bp, func, creg)
+#endif
+
+#if defined(DEBUG_MEMORY)
+void dbg_mem(struct bnxt *bp, const char *func)
+{
+ printf("- %s()\n", func);
+ printf(" bp Addr : %p", bp);
+ printf(" Len %4d", (u16)sizeof(struct bnxt));
+ printf(" phy %llx\n", virt_to_bus(bp));
+ printf(" bp->hwrm_req_addr : %p", bp->hwrm_addr_req);
+ printf(" Len %4d", (u16)REQ_BUFFER_SIZE);
+ printf(" phy %llx\n", bp->req_addr_mapping);
+ printf(" bp->hwrm_resp_addr : %p", bp->hwrm_addr_resp);
+ printf(" Len %4d", (u16)RESP_BUFFER_SIZE);
+ printf(" phy %llx\n", bp->resp_addr_mapping);
+ printf(" bp->tx.bd_virt : %p", bp->tx.bd_virt);
+ printf(" Len %4d", (u16)TX_RING_DMA_BUFFER_SIZE);
+ printf(" phy %llx\n", virt_to_bus(bp->tx.bd_virt));
+ printf(" bp->rx.bd_virt : %p", bp->rx.bd_virt);
+ printf(" Len %4d", (u16)RX_RING_DMA_BUFFER_SIZE);
+ printf(" phy %llx\n", virt_to_bus(bp->rx.bd_virt));
+ printf(" bp->cq.bd_virt : %p", bp->cq.bd_virt);
+ printf(" Len %4d", (u16)CQ_RING_DMA_BUFFER_SIZE);
+ printf(" phy %llx\n", virt_to_bus(bp->cq.bd_virt));
+}
+#else
+#define dbg_mem(bp, func)
+#endif
+
+#if defined(DEBUG_CHIP)
+void print_fw_ver(struct hwrm_ver_get_output *resp, u32 tmo)
+{
+ if (resp->hwrm_intf_maj_8b < 1) {
+ dbg_prn(" HWRM interface %d.%d.%d is older than 1.0.0.\n",
+ resp->hwrm_intf_maj_8b, resp->hwrm_intf_min_8b,
+ resp->hwrm_intf_upd_8b);
+ dbg_prn(" Update FW with HWRM interface 1.0.0 or newer.\n");
+ }
+ dbg_prn(" FW Version : %d.%d.%d.%d\n",
+ resp->hwrm_fw_maj_8b, resp->hwrm_fw_min_8b,
+ resp->hwrm_fw_bld_8b, resp->hwrm_fw_rsvd_8b);
+ printf(" cmd timeout : %d\n", tmo);
+}
+
+void dbg_func_resource_qcaps(struct bnxt *bp)
+{
+ /* Ring Groups */
+ printf(" min_hw_ring_grps : %d\n", bp->min_hw_ring_grps);
+ printf(" max_hw_ring_grps : %d\n", bp->max_hw_ring_grps);
+ /* TX Rings */
+ printf(" min_tx_rings : %d\n", bp->min_tx_rings);
+ printf(" max_tx_rings : %d\n", bp->max_tx_rings);
+ /* RX Rings */
+ printf(" min_rx_rings : %d\n", bp->min_rx_rings);
+ printf(" max_rx_rings : %d\n", bp->max_rx_rings);
+ /* Completion Rings */
+ printf(" min_cq_rings : %d\n", bp->min_cp_rings);
+ printf(" max_cq_rings : %d\n", bp->max_cp_rings);
+ /* Statistic Contexts */
+ printf(" min_stat_ctxs : %d\n", bp->min_stat_ctxs);
+ printf(" max_stat_ctxs : %d\n", bp->max_stat_ctxs);
+}
+
+void print_func_qcaps(struct bnxt *bp)
+{
+ printf(" Port Number : %d\n", bp->port_idx);
+ printf(" fid : 0x%04x\n", bp->fid);
+ dbg_prn(" PF MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp->mac_addr[0],
+ bp->mac_addr[1],
+ bp->mac_addr[2],
+ bp->mac_addr[3],
+ bp->mac_addr[4],
+ bp->mac_addr[5]);
+}
+
+void print_func_qcfg(struct bnxt *bp)
+{
+ printf(" ordinal_value : %d\n", bp->ordinal_value);
+ printf(" stat_ctx_id : %x\n", bp->stat_ctx_id);
+ dbg_prn(" FW MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp->mac_addr[0],
+ bp->mac_addr[1],
+ bp->mac_addr[2],
+ bp->mac_addr[3],
+ bp->mac_addr[4],
+ bp->mac_addr[5]);
+}
+
+void dbg_set_speed(u32 speed)
+{
+ u32 speed1 = ((speed & LINK_SPEED_DRV_MASK) >> LINK_SPEED_DRV_SHIFT);
+
+ printf(" Set Link Speed : ");
+ switch (speed & LINK_SPEED_DRV_MASK) {
+ case LINK_SPEED_DRV_1G:
+ printf("1 GBPS");
+ break;
+ case LINK_SPEED_DRV_10G:
+ printf("10 GBPS");
+ break;
+ case LINK_SPEED_DRV_25G:
+ printf("25 GBPS");
+ break;
+ case LINK_SPEED_DRV_40G:
+ printf("40 GBPS");
+ break;
+ case LINK_SPEED_DRV_50G:
+ printf("50 GBPS");
+ break;
+ case LINK_SPEED_DRV_100G:
+ printf("100 GBPS");
+ break;
+ case LINK_SPEED_DRV_AUTONEG:
+ printf("AUTONEG");
+ break;
+ default:
+ printf("%x", speed1);
+ break;
+ }
+ printf("\n");
+}
+
+void dbg_chip_info(struct bnxt *bp)
+{
+ printf(" Stat Ctx ID : %d\n", bp->stat_ctx_id);
+ printf(" Grp ID : %d\n", bp->ring_grp_id);
+ printf(" CQ Ring Id : %d\n", bp->cq_ring_id);
+ printf(" Tx Ring Id : %d\n", bp->tx_ring_id);
+ printf(" Rx ring Id : %d\n", bp->rx_ring_id);
+}
+
+void print_num_rings(struct bnxt *bp)
+{
+ printf(" num_cmpl_rings : %d\n", bp->num_cmpl_rings);
+ printf(" num_tx_rings : %d\n", bp->num_tx_rings);
+ printf(" num_rx_rings : %d\n", bp->num_rx_rings);
+ printf(" num_ring_grps : %d\n", bp->num_hw_ring_grps);
+ printf(" num_stat_ctxs : %d\n", bp->num_stat_ctxs);
+}
+
+void dbg_flags(const char *func, u32 flags)
+{
+ printf("- %s()\n", func);
+ printf(" bp->flags : 0x%04x\n", flags);
+}
+#else
+#define print_fw_ver(resp, tmo)
+#define dbg_func_resource_qcaps(bp)
+#define print_func_qcaps(bp)
+#define print_func_qcfg(bp)
+#define dbg_set_speed(speed)
+#define dbg_chip_info(bp)
+#define print_num_rings(bp)
+#define dbg_flags(func, flags)
+#endif
+
+#if defined(DEBUG_HWRM_CMDS) || defined(DEBUG_FAIL)
+void dump_hwrm_req(struct bnxt *bp, const char *func, u32 len, u32 tmo)
+{
+ dbg_prn("- %s(0x%04x) cmd_len %d cmd_tmo %d",
+ func, (u16)((struct input *)bp->hwrm_addr_req)->req_type,
+ len, tmo);
+#if defined(DEBUG_HWRM_DUMP)
+ dump_mem((u8 *)bp->hwrm_addr_req, len, DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+
+void debug_resp(struct bnxt *bp, const char *func, u32 resp_len, u16 err)
+{
+ dbg_prn("- %s(0x%04x) - ",
+ func, (u16)((struct input *)bp->hwrm_addr_req)->req_type);
+ if (err == STATUS_SUCCESS)
+ printf("Done");
+ else if (err != STATUS_TIMEOUT)
+ printf("Fail err 0x%04x", err);
+ else
+ printf("timedout");
+#if defined(DEBUG_HWRM_DUMP)
+ if (err != STATUS_TIMEOUT)
+ dump_mem((u8 *)bp->hwrm_addr_resp, resp_len, DISP_U8);
+ else
+ printf("\n");
+#else
+ printf("\n");
+#endif
+}
+
+void dbg_hw_cmd(struct bnxt *bp,
+ const char *func, u16 cmd_len,
+ u16 resp_len, u32 cmd_tmo, u16 err)
+{
+#if !defined(DEBUG_HWRM_CMDS)
+ if (err && err != STATUS_TIMEOUT)
+#endif
+ {
+ dump_hwrm_req(bp, func, cmd_len, cmd_tmo);
+ debug_resp(bp, func, resp_len, err);
+ }
+}
+#else
+#define dbg_hw_cmd(bp, func, cmd_len, resp_len, cmd_tmo, err)
+#endif
+
+#if defined(DEBUG_HWRM_CMDS)
+void dbg_short_cmd(u8 *req, const char *func, u32 len)
+{
+ struct hwrm_short_input *sreq;
+
+ sreq = (struct hwrm_short_input *)req;
+ dbg_prn("- %s(0x%04x) short_cmd_len %d",
+ func,
+ sreq->req_type,
+ (int)len);
+#if defined(DEBUG_HWRM_DUMP)
+ dump_mem((u8 *)sreq, len, DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+#else
+#define dbg_short_cmd(sreq, func, len)
+#endif
+
+#if defined(DEBUG_RX)
+void dump_rx_bd(struct rx_pkt_cmpl *rx_cmp,
+ struct rx_pkt_cmpl_hi *rx_cmp_hi,
+ u32 desc_idx)
+{
+ printf(" RX desc_idx %d\n", desc_idx);
+ printf("- rx_cmp %llx", virt_to_bus(rx_cmp));
+#if defined(DEBUG_RX_DUMP)
+ dump_mem((u8 *)rx_cmp, (u32)sizeof(struct rx_pkt_cmpl), DISP_U8);
+#else
+ printf("\n");
+#endif
+ printf("- rx_cmp_hi %llx", virt_to_bus(rx_cmp_hi));
+#if defined(DEBUG_RX_DUMP)
+ dump_mem((u8 *)rx_cmp_hi, (u32)sizeof(struct rx_pkt_cmpl_hi), DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+
+void dbg_rxp(u8 *iob, u16 rx_len, u16 flag)
+{
+ printf("- RX iob %llx Len %d ", virt_to_bus(iob), rx_len);
+ if (flag == PKT_RECEIVED)
+ printf(" PKT RECEIVED");
+ else if (flag == PKT_DROPPED)
+ printf(" PKT DROPPED");
+#if defined(DEBUG_RX_DUMP)
+ dump_mem(iob, (u32)rx_len, DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+
+void dbg_rx_cid(u16 idx, u16 cid)
+{
+ dbg_prn("- RX old cid %d new cid %d\n", idx, cid);
+}
+
+void dbg_rx_alloc_iob_fail(u16 idx, u16 cid)
+{
+ dbg_prn(" Rx alloc_iob (%d) failed", idx);
+ dbg_prn(" for cons_id %d\n", cid);
+}
+
+void dbg_rx_iob(void *iob, u16 idx, u16 cid)
+{
+ dbg_prn(" Rx alloc_iob (%d) %p bd_virt (%d)\n",
+ idx, iob, cid);
+}
+
+void dbg_rx_pkt(struct bnxt *bp, const char *func, uchar *pkt, int len)
+{
+ if (bp->rx.iob_recv == PKT_RECEIVED) {
+ dbg_prn("- %s: %llx %d\n", func,
+ virt_to_bus(pkt), len);
+ }
+}
+#else
+#define dump_rx_bd(rx_cmp, rx_cmp_hi, desc_idx)
+#define dbg_rxp(iob, rx_len, flag)
+#define dbg_rx_cid(idx, cid)
+#define dbg_rx_alloc_iob_fail(idx, cid)
+#define dbg_rx_iob(iob, idx, cid)
+#define dbg_rx_pkt(bp, func, pkt, len)
+#endif
+
+#if defined(DEBUG_CQ)
+void dump_CQ(struct cmpl_base *cmp, u16 cons_idx)
+{
+ printf("- CQ Type ");
+
+ switch (cmp->type & CMPL_BASE_TYPE_MASK) {
+ case CMPL_BASE_TYPE_STAT_EJECT:
+ printf("(se)");
+ break;
+ case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
+ printf("(ae)");
+ break;
+ case CMPL_BASE_TYPE_TX_L2:
+ printf("(tx)");
+ break;
+ case CMPL_BASE_TYPE_RX_L2:
+ printf("(rx)");
+ break;
+ default:
+ printf("%04x", (u16)(cmp->type & CMPL_BASE_TYPE_MASK));
+ break;
+ }
+ printf(" cid %d", cons_idx);
+#if defined(DEBUG_CQ_DUMP)
+ dump_mem((u8 *)cmp, (u32)sizeof(struct cmpl_base), DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+#else
+#define dump_CQ(cq, id)
+#endif
+
+#if defined(DEBUG_TX)
+void dump_tx_stat(struct bnxt *bp)
+{
+ printf(" TX stats cnt %d req_cnt %d", bp->tx.cnt, bp->tx.cnt_req);
+ printf(" prod_id %d cons_id %d\n", bp->tx.prod_id, bp->tx.cons_id);
+}
+
+void dump_tx_pkt(void *packet, dma_addr_t mapping, int len)
+{
+ printf(" TX Addr %llx Size %d", mapping, len);
+#if defined(DEBUG_TX_DUMP)
+ dump_mem((u8 *)packet, len, DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+
+void dump_tx_bd(struct tx_bd_short *tx_bd, u16 len)
+{
+ printf(" Tx BD Addr %llx Size %d", virt_to_bus(tx_bd), len);
+#if defined(DEBUG_TX_DUMP)
+ dump_mem((u8 *)tx_bd, (u32)len, DISP_U8);
+#else
+ printf("\n");
+#endif
+}
+
+void dbg_no_tx_bd(void)
+{
+ printf(" Tx ring full\n");
+}
+#else
+#define dump_tx_stat(bp)
+#define dump_tx_pkt(packet, mapping, len)
+#define dump_tx_bd(prod_bd, len)
+#define dbg_no_tx_bd()
+#endif
+
+#if defined(DEBUG_MEMORY)
+void dbg_mem_free_done(const char *func)
+{
+ printf("- %s - Done\n", func);
+}
+#else
+#define dbg_mem_free_done(func)
+#endif
+
+#if defined(DEBUG_FAIL)
+void dbg_mem_alloc_fail(const char *func)
+{
+ printf("- %s() Fail\n", func);
+}
+#else
+#define dbg_mem_alloc_fail(func)
+#endif
+
+#if defined(DEBUG_LINK)
+static void dump_evt(u8 *cmp, u32 type, u16 cid)
+{
+ u32 size = sizeof(struct cmpl_base);
+ u8 c = 'C';
+
+ switch (type) {
+ case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
+ break;
+ default:
+ return;
+ }
+ dbg_prn("- %cQ Type (ae) cid %d", c, cid);
+ dump_mem(cmp, size, DISP_U8);
+}
+
+void dbg_link_status(struct bnxt *bp)
+{
+ dbg_prn(" Port(%d) : Link", bp->port_idx);
+ if (bp->link_status == STATUS_LINK_ACTIVE) {
+ dbg_prn("Up");
+ } else {
+ dbg_prn("Down\n");
+ dbg_prn(" media_detect : %x", bp->media_detect);
+ }
+ dbg_prn("\n");
+}
+
+void dbg_link_state(struct bnxt *bp, u32 tmo)
+{
+ if (bp->link_status == STATUS_LINK_ACTIVE)
+ printf(" Link wait time : %d ms\n", tmo);
+}
+
+void dbg_phy_speed(struct bnxt *bp, char *name)
+{
+ printf(" Current Speed : %s\n", name);
+}
+#else
+#define dump_evt(cmp, ty, cid)
+#define dbg_link_status(bp)
+#define dbg_link_state(bp, tmo)
+#define dbg_phy_speed(bp, name)
+#endif
+
+#endif /* _BXNT_DBG_H_ */
diff --git a/drivers/net/bnxt/bnxt_hsi.h b/drivers/net/bnxt/bnxt_hsi.h
new file mode 100644
index 00000000000..81cc5da9e4d
--- /dev/null
+++ b/drivers/net/bnxt/bnxt_hsi.h
@@ -0,0 +1,889 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+ /*
+ * Copyright 2019-2021 Broadcom.
+ */
+
+#ifndef _BNXT_HSI_H_
+#define _BNXT_HSI_H_
+
+/* input (size:128b/16B) */
+struct input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+};
+
+/* output (size:64b/8B) */
+struct output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+};
+
+/* hwrm_short_input (size:128b/16B) */
+struct hwrm_short_input {
+ __le16 req_type;
+ __le16 signature;
+#define SHORT_REQ_SIGNATURE_SHORT_CMD 0x4321UL
+ __le16 unused_0;
+ __le16 size;
+ __le64 req_addr;
+};
+
+#define HWRM_VER_GET 0x0UL
+#define HWRM_FUNC_RESET 0x11UL
+#define HWRM_FUNC_QCAPS 0x15UL
+#define HWRM_FUNC_QCFG 0x16UL
+#define HWRM_FUNC_CFG 0x17UL
+#define HWRM_FUNC_DRV_UNRGTR 0x1aUL
+#define HWRM_FUNC_DRV_RGTR 0x1dUL
+#define HWRM_PORT_PHY_CFG 0x20UL
+#define HWRM_PORT_MAC_CFG 0x21UL
+#define HWRM_PORT_PHY_QCFG 0x27UL
+#define HWRM_VNIC_ALLOC 0x40UL
+#define HWRM_VNIC_FREE 0x41UL
+#define HWRM_VNIC_CFG 0x42UL
+#define HWRM_RING_ALLOC 0x50UL
+#define HWRM_RING_FREE 0x51UL
+#define HWRM_RING_GRP_ALLOC 0x60UL
+#define HWRM_RING_GRP_FREE 0x61UL
+#define HWRM_CFA_L2_FILTER_ALLOC 0x90UL
+#define HWRM_CFA_L2_FILTER_FREE 0x91UL
+#define HWRM_CFA_L2_SET_RX_MASK 0x93UL
+#define HWRM_STAT_CTX_ALLOC 0xb0UL
+#define HWRM_STAT_CTX_FREE 0xb1UL
+#define HWRM_FUNC_RESOURCE_QCAPS 0x190UL
+#define HWRM_NVM_FLUSH 0xfff0UL
+#define HWRM_NVM_GET_VARIABLE 0xfff1UL
+#define HWRM_NVM_SET_VARIABLE 0xfff2UL
+
+#define HWRM_NA_SIGNATURE ((__le32)(-1))
+#define HWRM_MAX_REQ_LEN 128
+#define HWRM_VERSION_MAJOR 1
+#define HWRM_VERSION_MINOR 10
+#define HWRM_VERSION_UPDATE 0
+
+/* hwrm_ver_get_input (size:192b/24B) */
+struct hwrm_ver_get_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ u8 hwrm_intf_maj;
+ u8 hwrm_intf_min;
+ u8 hwrm_intf_upd;
+ u8 unused_0[5];
+};
+
+/* hwrm_ver_get_output (size:1408b/176B) */
+struct hwrm_ver_get_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 hwrm_intf_maj_8b;
+ u8 hwrm_intf_min_8b;
+ u8 hwrm_intf_upd_8b;
+ u8 hwrm_intf_rsvd_8b;
+ u8 hwrm_fw_maj_8b;
+ u8 hwrm_fw_min_8b;
+ u8 hwrm_fw_bld_8b;
+ u8 hwrm_fw_rsvd_8b;
+ u8 mgmt_fw_maj_8b;
+ u8 mgmt_fw_min_8b;
+ u8 mgmt_fw_bld_8b;
+ u8 mgmt_fw_rsvd_8b;
+ u8 netctrl_fw_maj_8b;
+ u8 netctrl_fw_min_8b;
+ u8 netctrl_fw_bld_8b;
+ u8 netctrl_fw_rsvd_8b;
+ __le32 dev_caps_cfg;
+#define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED 0x4UL
+#define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED 0x8UL
+ u8 roce_fw_maj_8b;
+ u8 roce_fw_min_8b;
+ u8 roce_fw_bld_8b;
+ u8 roce_fw_rsvd_8b;
+ char hwrm_fw_name[16];
+ char mgmt_fw_name[16];
+ char netctrl_fw_name[16];
+ u8 reserved2[16];
+ char roce_fw_name[16];
+ __le16 chip_num;
+ u8 chip_rev;
+ u8 chip_metal;
+ u8 chip_bond_id;
+ u8 chip_platform_type;
+ __le16 max_req_win_len;
+ __le16 max_resp_len;
+ __le16 def_req_timeout;
+ u8 flags;
+ u8 unused_0[2];
+ u8 always_1;
+ __le16 hwrm_intf_major;
+ __le16 hwrm_intf_minor;
+ __le16 hwrm_intf_build;
+ __le16 hwrm_intf_patch;
+ __le16 hwrm_fw_major;
+ __le16 hwrm_fw_minor;
+ __le16 hwrm_fw_build;
+ __le16 hwrm_fw_patch;
+ __le16 mgmt_fw_major;
+ __le16 mgmt_fw_minor;
+ __le16 mgmt_fw_build;
+ __le16 mgmt_fw_patch;
+ __le16 netctrl_fw_major;
+ __le16 netctrl_fw_minor;
+ __le16 netctrl_fw_build;
+ __le16 netctrl_fw_patch;
+ __le16 roce_fw_major;
+ __le16 roce_fw_minor;
+ __le16 roce_fw_build;
+ __le16 roce_fw_patch;
+ __le16 max_ext_req_len;
+ u8 unused_1[5];
+ u8 valid;
+};
+
+/* hwrm_async_event_cmpl (size:128b/16B) */
+struct hwrm_async_event_cmpl {
+ __le16 type;
+ __le16 event_id;
+#define ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE 0x0UL
+ __le32 event_data2;
+ u8 opaque_v;
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+};
+
+/* hwrm_func_reset_input (size:192b/24B) */
+struct hwrm_func_reset_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 enables;
+ __le16 vf_id;
+ u8 func_reset_level;
+#define FUNC_RESET_REQ_FUNC_RESET_LEVEL_RESETME 0x1UL
+ u8 unused_0;
+};
+
+/* hwrm_func_qcaps_input (size:192b/24B) */
+struct hwrm_func_qcaps_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 fid;
+ u8 unused_0[6];
+};
+
+/* hwrm_func_qcaps_output (size:640b/80B) */
+struct hwrm_func_qcaps_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le16 fid;
+ __le16 port_id;
+ __le32 flags;
+ u8 mac_address[6];
+ __le16 max_rsscos_ctx;
+ __le16 max_cmpl_rings;
+ __le16 max_tx_rings;
+ __le16 max_rx_rings;
+ __le16 max_l2_ctxs;
+ __le16 max_vnics;
+ __le16 first_vf_id;
+ __le16 max_vfs;
+ __le16 max_stat_ctx;
+ __le32 max_encap_records;
+ __le32 max_decap_records;
+ __le32 max_tx_em_flows;
+ __le32 max_tx_wm_flows;
+ __le32 max_rx_em_flows;
+ __le32 max_rx_wm_flows;
+ __le32 max_mcast_filters;
+ __le32 max_flow_id;
+ __le32 max_hw_ring_grps;
+ __le16 max_sp_tx_rings;
+ u8 unused_0;
+ u8 valid;
+};
+
+/* hwrm_func_qcfg_input (size:192b/24B) */
+struct hwrm_func_qcfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 fid;
+ u8 unused_0[6];
+};
+
+/* hwrm_func_qcfg_output (size:704b/88B) */
+struct hwrm_func_qcfg_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le16 fid;
+ __le16 port_id;
+ __le16 vlan;
+ __le16 flags;
+#define FUNC_QCFG_RESP_FLAGS_MULTI_HOST 0x20UL
+ u8 mac_address[6];
+ __le16 pci_id;
+ __le16 alloc_rsscos_ctx;
+ __le16 alloc_cmpl_rings;
+ __le16 alloc_tx_rings;
+ __le16 alloc_rx_rings;
+ __le16 alloc_l2_ctx;
+ __le16 alloc_vnics;
+ __le16 mtu;
+ __le16 mru;
+ __le16 stat_ctx_id;
+ u8 port_partition_type;
+#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0 0x2UL
+ u8 port_pf_cnt;
+ __le16 dflt_vnic_id;
+ __le16 max_mtu_configured;
+ __le32 min_bw;
+ __le32 max_bw;
+ u8 evb_mode;
+ u8 options;
+ __le16 alloc_vfs;
+ __le32 alloc_mcast_filters;
+ __le32 alloc_hw_ring_grps;
+ __le16 alloc_sp_tx_rings;
+ __le16 alloc_stat_ctx;
+ __le16 alloc_msix;
+ __le16 registered_vfs;
+ u8 unused_1[3];
+ u8 always_1;
+ __le32 reset_addr_poll;
+ u8 unused_2[3];
+ u8 valid;
+};
+
+/* hwrm_func_cfg_input (size:704b/88B) */
+struct hwrm_func_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 fid;
+ __le16 num_msix;
+ __le32 flags;
+ __le32 enables;
+#define FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS 0x8UL
+#define FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS 0x10UL
+#define FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS 0x20UL
+#define FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS 0x100UL
+#define FUNC_CFG_REQ_ENABLES_ASYNC_EVENT_CR 0x4000UL
+#define FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS 0x80000UL
+ __le16 mtu;
+ __le16 mru;
+ __le16 num_rsscos_ctxs;
+ __le16 num_cmpl_rings;
+ __le16 num_tx_rings;
+ __le16 num_rx_rings;
+ __le16 num_l2_ctxs;
+ __le16 num_vnics;
+ __le16 num_stat_ctxs;
+ __le16 num_hw_ring_grps;
+ u8 dflt_mac_addr[6];
+ __le16 dflt_vlan;
+ __be32 dflt_ip_addr[4];
+ __le32 min_bw;
+ __le32 max_bw;
+ __le16 async_event_cr;
+ u8 vlan_antispoof_mode;
+ u8 allowed_vlan_pris;
+ u8 evb_mode;
+ u8 options;
+ __le16 num_mcast_filters;
+};
+
+/* hwrm_func_drv_rgtr_input (size:896b/112B) */
+struct hwrm_func_drv_rgtr_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+ __le32 enables;
+#define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL
+#define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL
+#define FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD 0x10UL
+ __le16 os_type;
+#define FUNC_DRV_RGTR_REQ_OS_TYPE_OTHER 0x1UL
+ u8 ver_maj_8b;
+ u8 ver_min_8b;
+ u8 ver_upd_8b;
+ u8 unused_0[3];
+ __le32 timestamp;
+ u8 unused_1[4];
+ __le32 vf_req_fwd[8];
+ __le32 async_event_fwd[8];
+ __le16 ver_maj;
+ __le16 ver_min;
+ __le16 ver_upd;
+ __le16 ver_patch;
+};
+
+/* hwrm_func_drv_unrgtr_input (size:192b/24B) */
+struct hwrm_func_drv_unrgtr_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+#define FUNC_DRV_UNRGTR_REQ_FLAGS_PREPARE_FOR_SHUTDOWN 0x1UL
+ u8 unused_0[4];
+};
+
+/* hwrm_func_resource_qcaps_input (size:192b/24B) */
+struct hwrm_func_resource_qcaps_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 fid;
+ u8 unused_0[6];
+};
+
+/* hwrm_func_resource_qcaps_output (size:448b/56B) */
+struct hwrm_func_resource_qcaps_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le16 max_vfs;
+ __le16 max_msix;
+ __le16 vf_reservation_strategy;
+ __le16 min_rsscos_ctx;
+ __le16 max_rsscos_ctx;
+ __le16 min_cmpl_rings;
+ __le16 max_cmpl_rings;
+ __le16 min_tx_rings;
+ __le16 max_tx_rings;
+ __le16 min_rx_rings;
+ __le16 max_rx_rings;
+ __le16 min_l2_ctxs;
+ __le16 max_l2_ctxs;
+ __le16 min_vnics;
+ __le16 max_vnics;
+ __le16 min_stat_ctx;
+ __le16 max_stat_ctx;
+ __le16 min_hw_ring_grps;
+ __le16 max_hw_ring_grps;
+ __le16 max_tx_scheduler_inputs;
+ __le16 flags;
+ u8 unused_0[5];
+ u8 valid;
+};
+
+/* hwrm_func_vlan_qcfg_input (size:192b/24B) */
+struct hwrm_func_vlan_qcfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 fid;
+ u8 unused_0[6];
+};
+
+/* hwrm_port_phy_cfg_input (size:448b/56B) */
+struct hwrm_port_phy_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+#define PORT_PHY_CFG_REQ_FLAGS_RESET_PHY 0x1UL
+#define PORT_PHY_CFG_REQ_FLAGS_FORCE 0x4UL
+ __le32 enables;
+#define PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE 0x1UL
+#define PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX 0x2UL
+#define PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE 0x4UL
+#define PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK 0x10UL
+ __le16 port_id;
+ __le16 force_link_speed;
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB 0xaUL
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB 0x64UL
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB 0xfaUL
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB 0x190UL
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB 0x1f4UL
+#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB 0x3e8UL
+ u8 auto_mode;
+#define PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK 0x4UL
+ u8 auto_duplex;
+#define PORT_PHY_CFG_REQ_AUTO_DUPLEX_BOTH 0x2UL
+ u8 auto_pause;
+#define PORT_PHY_CFG_REQ_AUTO_PAUSE_TX 0x1UL
+#define PORT_PHY_CFG_REQ_AUTO_PAUSE_RX 0x2UL
+ u8 unused_0;
+ __le16 auto_link_speed;
+ __le16 auto_link_speed_mask;
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100MB 0x2UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_1GB 0x8UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10GB 0x40UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_25GB 0x100UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_40GB 0x200UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_50GB 0x400UL
+#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100GB 0x800UL
+ u8 wirespeed;
+ u8 lpbk;
+ u8 force_pause;
+ u8 unused_1;
+ __le32 preemphasis;
+ __le16 eee_link_speed_mask;
+ u8 unused_2[2];
+ __le32 tx_lpi_timer;
+ __le32 unused_3;
+};
+
+/* hwrm_port_phy_qcfg_input (size:192b/24B) */
+struct hwrm_port_phy_qcfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 port_id;
+ u8 unused_0[6];
+};
+
+/* hwrm_port_phy_qcfg_output (size:768b/96B) */
+struct hwrm_port_phy_qcfg_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 link;
+#define PORT_PHY_QCFG_RESP_LINK_LINK 0x2UL
+ u8 unused_0;
+ __le16 link_speed;
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_100MB 0x1UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_1GB 0xaUL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_2GB 0x14UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_2_5GB 0x19UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_10GB 0x64UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_20GB 0xc8UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_25GB 0xfaUL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_40GB 0x190UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL
+#define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL
+ u8 duplex_cfg;
+ u8 pause;
+ __le16 support_speeds;
+#define PORT_QCFG_SUPPORT_SPEEDS_100MBHD 0x1UL
+#define PORT_QCFG_SUPPORT_SPEEDS_100MB 0x2UL
+#define PORT_QCFG_SUPPORT_SPEEDS_1GBHD 0x4UL
+#define PORT_QCFG_SUPPORT_SPEEDS_1GB 0x8UL
+#define PORT_QCFG_SUPPORT_SPEEDS_2GB 0x10UL
+#define PORT_QCFG_SUPPORT_SPEEDS_2_5GB 0x20UL
+#define PORT_QCFG_SUPPORT_SPEEDS_10GB 0x40UL
+#define PORT_QCFG_SUPPORT_SPEEDS_20GB 0x80UL
+#define PORT_QCFG_SUPPORT_SPEEDS_25GB 0x100UL
+#define PORT_QCFG_SUPPORT_SPEEDS_50GB 0x400UL
+#define PORT_QCFG_SUPPORT_SPEEDS_100GB 0x800UL
+#define PORT_QCFG_SUPPORT_SPEEDS_200GB 0x4000UL
+ __le16 force_link_speed;
+ u8 auto_mode;
+ u8 auto_pause;
+ __le16 auto_link_speed;
+ __le16 auto_link_speed_mask;
+ u8 wirespeed;
+ u8 lpbk;
+ u8 force_pause;
+ u8 module_status;
+ __le32 preemphasis;
+ u8 phy_maj;
+ u8 phy_min;
+ u8 phy_bld;
+ u8 phy_type;
+ u8 media_type;
+ u8 xcvr_pkg_type;
+ u8 eee_config_phy_addr;
+ u8 parallel_detect;
+ __le16 link_partner_adv_speeds;
+ u8 link_partner_adv_auto_mode;
+ u8 link_partner_adv_pause;
+ __le16 adv_eee_link_speed_mask;
+ __le16 link_partner_adv_eee_link_speed_mask;
+ __le32 xcvr_identifier_type_tx_lpi_timer;
+ __le16 fec_cfg;
+ u8 duplex_state;
+ u8 option_flags;
+ char phy_vendor_name[16];
+ char phy_vendor_partnumber[16];
+ u8 unused_2[7];
+ u8 valid;
+};
+
+/* hwrm_port_mac_cfg_input (size:320b/40B) */
+struct hwrm_port_mac_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+ __le32 enables;
+ __le16 port_id;
+ u8 ipg;
+ u8 lpbk;
+#define PORT_MAC_CFG_REQ_LPBK_NONE 0x0UL
+ u8 vlan_pri2cos_map_pri;
+ u8 reserved1;
+ u8 tunnel_pri2cos_map_pri;
+ u8 dscp2pri_map_pri;
+ __le16 rx_ts_capture_ptp_msg_type;
+ __le16 tx_ts_capture_ptp_msg_type;
+ u8 cos_field_cfg;
+ u8 unused_0[3];
+};
+
+/* hwrm_vnic_alloc_input (size:192b/24B) */
+struct hwrm_vnic_alloc_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+#define VNIC_ALLOC_REQ_FLAGS_DEFAULT 0x1UL
+ u8 unused_0[4];
+};
+
+/* hwrm_vnic_alloc_output (size:128b/16B) */
+struct hwrm_vnic_alloc_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le32 vnic_id;
+ u8 unused_0[3];
+ u8 valid;
+};
+
+/* hwrm_vnic_free_input (size:192b/24B) */
+struct hwrm_vnic_free_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 vnic_id;
+ u8 unused_0[4];
+};
+
+/* hwrm_vnic_cfg_input (size:320b/40B) */
+struct hwrm_vnic_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+ __le32 enables;
+#define VNIC_CFG_REQ_ENABLES_DFLT_RING_GRP 0x1UL
+#define VNIC_CFG_REQ_ENABLES_MRU 0x10UL
+ __le16 vnic_id;
+ __le16 dflt_ring_grp;
+ __le16 rss_rule;
+ __le16 cos_rule;
+ __le16 lb_rule;
+ __le16 mru;
+ __le16 default_rx_ring_id;
+ __le16 default_cmpl_ring_id;
+};
+
+/* hwrm_ring_alloc_input (size:704b/88B) */
+struct hwrm_ring_alloc_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 enables;
+#define RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID 0x100UL
+ u8 ring_type;
+#define RING_ALLOC_REQ_RING_TYPE_L2_CMPL 0x0UL
+#define RING_ALLOC_REQ_RING_TYPE_TX 0x1UL
+#define RING_ALLOC_REQ_RING_TYPE_RX 0x2UL
+ u8 unused_0;
+ __le16 flags;
+ __le64 page_tbl_addr;
+ __le32 fbo;
+ u8 page_size;
+ u8 page_tbl_depth;
+ u8 unused_1[2];
+ __le32 length;
+ __le16 logical_id;
+ __le16 cmpl_ring_id;
+ __le16 queue_id;
+ __le16 rx_buf_size;
+ __le16 rx_ring_id;
+ __le16 nq_ring_id;
+ __le16 ring_arb_cfg;
+ __le16 unused_3;
+ __le32 reserved3;
+ __le32 stat_ctx_id;
+ __le32 reserved4;
+ __le32 max_bw;
+ u8 int_mode;
+#define RING_ALLOC_REQ_INT_MODE_POLL 0x3UL
+ u8 unused_4[3];
+ __le64 cq_handle;
+};
+
+/* hwrm_ring_alloc_output (size:128b/16B) */
+struct hwrm_ring_alloc_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le16 ring_id;
+ __le16 logical_ring_id;
+ u8 unused_0[3];
+ u8 valid;
+};
+
+/* hwrm_ring_free_input (size:192b/24B) */
+struct hwrm_ring_free_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ u8 ring_type;
+#define RING_FREE_REQ_RING_TYPE_L2_CMPL 0x0UL
+#define RING_FREE_REQ_RING_TYPE_TX 0x1UL
+#define RING_FREE_REQ_RING_TYPE_RX 0x2UL
+ u8 unused_0;
+ __le16 ring_id;
+ u8 unused_1[4];
+};
+
+/* hwrm_ring_grp_alloc_input (size:192b/24B) */
+struct hwrm_ring_grp_alloc_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 cr;
+ __le16 rr;
+ __le16 ar;
+ __le16 sc;
+};
+
+/* hwrm_ring_grp_alloc_output (size:128b/16B) */
+struct hwrm_ring_grp_alloc_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le32 ring_group_id;
+ u8 unused_0[3];
+ u8 valid;
+};
+
+/* hwrm_ring_grp_free_input (size:192b/24B) */
+struct hwrm_ring_grp_free_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 ring_group_id;
+ u8 unused_0[4];
+};
+
+/* hwrm_cfa_l2_filter_alloc_input (size:768b/96B) */
+struct hwrm_cfa_l2_filter_alloc_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+#define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX 0x1UL
+ __le32 enables;
+#define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR 0x1UL
+#define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK 0x2UL
+#define CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID 0x8000UL
+ u8 l2_addr[6];
+ u8 unused_0[2];
+ u8 l2_addr_mask[6];
+ __le16 l2_ovlan;
+ __le16 l2_ovlan_mask;
+ __le16 l2_ivlan;
+ __le16 l2_ivlan_mask;
+ u8 unused_1[2];
+ u8 t_l2_addr[6];
+ u8 unused_2[2];
+ u8 t_l2_addr_mask[6];
+ __le16 t_l2_ovlan;
+ __le16 t_l2_ovlan_mask;
+ __le16 t_l2_ivlan;
+ __le16 t_l2_ivlan_mask;
+ u8 src_type;
+#define CFA_L2_FILTER_ALLOC_REQ_SRC_TYPE_NPORT 0x0UL
+ u8 unused_3;
+ __le32 src_id;
+ u8 tunnel_type;
+ u8 unused_4;
+ __le16 dst_id;
+ __le16 mirror_vnic_id;
+ u8 pri_hint;
+ u8 unused_5;
+ __le32 unused_6;
+ __le64 l2_filter_id_hint;
+};
+
+/* hwrm_cfa_l2_filter_alloc_output (size:192b/24B) */
+struct hwrm_cfa_l2_filter_alloc_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le64 l2_filter_id;
+ __le32 flow_id;
+ u8 unused_0[3];
+ u8 valid;
+};
+
+/* hwrm_cfa_l2_filter_free_input (size:192b/24B) */
+struct hwrm_cfa_l2_filter_free_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le64 l2_filter_id;
+};
+
+/* hwrm_cfa_l2_set_rx_mask_input (size:448b/56B) */
+struct hwrm_cfa_l2_set_rx_mask_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 vnic_id;
+ __le32 mask;
+#define CFA_L2_SET_RX_MASK_REQ_MASK_MCAST 0x2UL
+#define CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST 0x4UL
+#define CFA_L2_SET_RX_MASK_REQ_MASK_BCAST 0x8UL
+#define CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS 0x10UL
+ __le64 mc_tbl_addr;
+ __le32 num_mc_entries;
+ u8 unused_0[4];
+ __le64 vlan_tag_tbl_addr;
+ __le32 num_vlan_tags;
+ u8 unused_1[4];
+};
+
+/* hwrm_stat_ctx_alloc_input (size:256b/32B) */
+struct hwrm_stat_ctx_alloc_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le64 stats_dma_addr;
+ __le32 update_period_ms;
+ u8 stat_ctx_flags;
+ u8 unused_0[3];
+};
+
+/* hwrm_stat_ctx_alloc_output (size:128b/16B) */
+struct hwrm_stat_ctx_alloc_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le32 stat_ctx_id;
+ u8 unused_0[3];
+ u8 valid;
+};
+
+/* hwrm_stat_ctx_free_input (size:192b/24B) */
+struct hwrm_stat_ctx_free_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 stat_ctx_id;
+ u8 unused_0[4];
+};
+
+/* hwrm_nvm_flush_input (size:128b/16B) */
+struct hwrm_nvm_flush_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+};
+
+/* hwrm_nvm_get_variable_input (size:320b/40B) */
+struct hwrm_nvm_get_variable_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le64 dest_data_addr;
+ __le16 data_len;
+ __le16 option_num;
+ __le16 dimensions;
+ __le16 index_0;
+ __le16 index_1;
+ __le16 index_2;
+ __le16 index_3;
+ u8 flags;
+ u8 unused_0;
+};
+
+/* hwrm_nvm_set_variable_input (size:320b/40B) */
+struct hwrm_nvm_set_variable_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le64 src_data_addr;
+ __le16 data_len;
+ __le16 option_num;
+ __le16 dimensions;
+ __le16 index_0;
+ __le16 index_1;
+ __le16 index_2;
+ __le16 index_3;
+ u8 flags;
+ u8 unused_0;
+};
+
+#endif /* _BNXT_HSI_H_ */
diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h
index 1c0d0e5b8f8..48faa33d66e 100644
--- a/drivers/net/fec_mxc.h
+++ b/drivers/net/fec_mxc.h
@@ -272,7 +272,7 @@ struct fec_priv {
struct clk clk_ref;
struct clk clk_ptp;
u32 clk_rate;
- char promisc;
+ bool promisc;
};
/**
diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c
index 7d51be1f723..f8256126405 100644
--- a/drivers/net/fm/fm.c
+++ b/drivers/net/fm/fm.c
@@ -387,8 +387,8 @@ int fm_init_common(int index, struct ccsr_fman *reg)
struct udevice *new;
/* speed and mode will be read from DT */
- ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
- CONFIG_ENV_SPI_CS, 0, 0, &new);
+ ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS, 0, 0, &new);
ucode_flash = dev_get_uclass_priv(new);
#else
@@ -474,7 +474,7 @@ int fm_init_common(int index, struct ccsr_fman *reg)
struct udevice *new;
/* speed and mode will be read from DT */
- ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS,
0, 0, &new);
ucode_flash = dev_get_uclass_priv(new);
diff --git a/drivers/net/mscc_eswitch/felix_switch.c b/drivers/net/mscc_eswitch/felix_switch.c
index 551fc2c9f96..60b2e8f32d4 100644
--- a/drivers/net/mscc_eswitch/felix_switch.c
+++ b/drivers/net/mscc_eswitch/felix_switch.c
@@ -16,6 +16,7 @@
*/
#include <dm/device_compat.h>
+#include <dm/of_extra.h>
#include <linux/delay.h>
#include <net/dsa.h>
#include <asm/io.h>
@@ -39,7 +40,9 @@
#define FELIX_IS2 0x060000
#define FELIX_GMII(port) (0x100000 + (port) * 0x10000)
#define FELIX_QSYS 0x200000
-
+#define FELIX_DEVCPU_GCB 0x070000
+#define FELIX_DEVCPU_GCB_SOFT_RST (FELIX_DEVCPU_GCB + 0x00000004)
+#define SOFT_SWC_RST BIT(0)
#define FELIX_SYS_SYSTEM (FELIX_SYS + 0x00000E00)
#define FELIX_SYS_SYSTEM_EN BIT(0)
#define FELIX_SYS_RAM_CTRL (FELIX_SYS + 0x00000F24)
@@ -210,17 +213,14 @@ static int felix_init_sxgmii(struct mii_dev *imdio, int pidx)
static void felix_start_pcs(struct udevice *dev, int port,
struct phy_device *phy, struct mii_dev *imdio)
{
- bool autoneg = true;
-
- if (phy->phy_id == PHY_FIXED_ID ||
- phy->interface == PHY_INTERFACE_MODE_2500BASEX)
- autoneg = false;
+ ofnode node = dsa_port_get_ofnode(dev, port);
+ bool inband_an = ofnode_eth_uses_inband_aneg(node);
switch (phy->interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_QSGMII:
- felix_init_sgmii(imdio, port, autoneg);
+ felix_init_sgmii(imdio, port, inband_an);
break;
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_USXGMII:
@@ -239,6 +239,15 @@ static void felix_init(struct udevice *dev)
void *base = priv->regs_base;
int timeout = 100;
+ /* Switch core reset */
+ out_le32(base + FELIX_DEVCPU_GCB_SOFT_RST, SOFT_SWC_RST);
+ while (in_le32(base + FELIX_DEVCPU_GCB_SOFT_RST) & SOFT_SWC_RST &&
+ --timeout)
+ udelay(10);
+ if (in_le32(base + FELIX_DEVCPU_GCB_SOFT_RST) & SOFT_SWC_RST)
+ dev_err(dev, "Timeout waiting for switch core reset\n");
+ timeout = 100;
+
/* Init core memories */
out_le32(base + FELIX_SYS_RAM_CTRL, FELIX_SYS_RAM_CTRL_INIT);
while (in_le32(base + FELIX_SYS_RAM_CTRL) & FELIX_SYS_RAM_CTRL_INIT &&
diff --git a/drivers/net/pfe_eth/Kconfig b/drivers/net/pfe_eth/Kconfig
index a13b331a508..b2724ee3e84 100644
--- a/drivers/net/pfe_eth/Kconfig
+++ b/drivers/net/pfe_eth/Kconfig
@@ -9,4 +9,20 @@ config SYS_FSL_PFE_ADDR
hex "PFE base address"
default 0x04000000
+config SYS_FSL_PFE_SPI_BUS
+ int "Value of SPI flash bus for PFE firmware"
+ default SF_DEFAULT_BUS
+
+config SYS_FSL_PFE_SPI_CS
+ int "Value of SPI flash chip select for PFE firmware"
+ default SF_DEFAULT_CS
+
+config SYS_FSL_PFE_SPI_MAX_HZ
+ int "Value of SPI flash max frequency for PFE firmware"
+ default SF_DEFAULT_SPEED
+
+config SYS_FSL_PFE_SPI_MODE
+ hex "Value of SPI flash work mode for PFE firmware"
+ default SF_DEFAULT_MODE
+
endif
diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c
index ad5bc3c8624..93e5ea55c78 100644
--- a/drivers/net/pfe_eth/pfe_firmware.c
+++ b/drivers/net/pfe_eth/pfe_firmware.c
@@ -179,10 +179,10 @@ int pfe_spi_flash_init(void)
if (!addr)
return -ENOMEM;
- ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
- CONFIG_ENV_SPI_CS,
- CONFIG_ENV_SPI_MAX_HZ,
- CONFIG_ENV_SPI_MODE,
+ ret = spi_flash_probe_bus_cs(CONFIG_SYS_FSL_PFE_SPI_BUS,
+ CONFIG_SYS_FSL_PFE_SPI_CS,
+ CONFIG_SYS_FSL_PFE_SPI_MAX_HZ,
+ CONFIG_SYS_FSL_PFE_SPI_MODE,
&new);
if (ret) {
printf("SF: failed to probe spi\n");
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 68ee7d7a2dd..e69cd8a4b31 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -214,16 +214,6 @@ config PHY_NXP_C45_TJA11XX
config PHY_REALTEK
bool "Realtek Ethernet PHYs support"
-config RTL8211E_PINE64_GIGABIT_FIX
- bool "Fix gigabit throughput on some Pine64+ models"
- depends on PHY_REALTEK
- help
- Configure the Realtek RTL8211E found on some Pine64+ models differently to
- fix throughput on Gigabit links, turning off all internal delays in the
- process. The settings that this touches are not documented in the CONFREG
- section of the RTL8211E datasheet, but come from Realtek by way of the
- Pine64 engineering team.
-
config RTL8211X_PHY_FORCE_MASTER
bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode"
depends on PHY_REALTEK
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
index 2ac02952450..778d93e609c 100644
--- a/drivers/net/phy/cortina.c
+++ b/drivers/net/phy/cortina.c
@@ -159,8 +159,8 @@ void cs4340_upload_firmware(struct phy_device *phydev)
struct spi_flash *ucode_flash;
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
- ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
- CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ ucode_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE);
if (!ucode_flash) {
puts("SF: probe for Cortina ucode failed\n");
} else {
@@ -212,8 +212,8 @@ void cs4340_upload_firmware(struct phy_device *phydev)
struct spi_flash *ucode_flash;
addr = malloc(CONFIG_CORTINA_FW_LENGTH);
- ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
- CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ ucode_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE);
if (!ucode_flash) {
puts("SF: probe for Cortina ucode failed\n");
} else {
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index d1a643cf5a0..f9482b21a01 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -19,6 +19,7 @@
/* Microsemi PHY ID's */
#define PHY_ID_VSC8530 0x00070560
#define PHY_ID_VSC8531 0x00070570
+#define PHY_ID_VSC8502 0x00070630
#define PHY_ID_VSC8540 0x00070760
#define PHY_ID_VSC8541 0x00070770
#define PHY_ID_VSC8574 0x000704a0
@@ -1513,6 +1514,50 @@ static int vsc8584_config(struct phy_device *phydev)
return vsc8584_config_init(phydev);
}
+static int vsc8502_config(struct phy_device *phydev)
+{
+ bool rgmii_rx_delay = false, rgmii_tx_delay = false;
+ u16 reg = 0;
+ int ret;
+
+ /* Assume nothing needs to be done for the default GMII/MII mode */
+ if (!phy_interface_is_rgmii(phydev))
+ return 0;
+
+ /* Set Extended PHY Control 1 register to RGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG,
+ BIT(13) | BIT(12));
+
+ /* Soft reset required after changing PHY mode from the default
+ * of GMII/MII
+ */
+ ret = mscc_phy_soft_reset(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ rgmii_rx_delay = true;
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ rgmii_tx_delay = true;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXT2);
+
+ if (rgmii_rx_delay)
+ reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_RX_CLK_DELAY_POS;
+ if (rgmii_tx_delay)
+ reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_TX_CLK_DELAY_POS;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_STD);
+
+ return 0;
+}
+
static struct phy_driver VSC8530_driver = {
.name = "Microsemi VSC8530",
.uid = PHY_ID_VSC8530,
@@ -1533,6 +1578,16 @@ static struct phy_driver VSC8531_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver VSC8502_driver = {
+ .name = "Microsemi VSC8502",
+ .uid = PHY_ID_VSC8502,
+ .mask = 0x000ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8502_config,
+ .startup = &mscc_startup,
+ .shutdown = &genphy_shutdown,
+};
+
static struct phy_driver VSC8540_driver = {
.name = "Microsemi VSC8540",
.uid = PHY_ID_VSC8540,
@@ -1577,6 +1632,7 @@ int phy_mscc_init(void)
{
phy_register(&VSC8530_driver);
phy_register(&VSC8531_driver);
+ phy_register(&VSC8502_driver);
phy_register(&VSC8540_driver);
phy_register(&VSC8541_driver);
phy_register(&VSC8574_driver);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index b1b1fa50809..24c3ea59bbb 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#define PHY_RTL8211x_FORCE_MASTER BIT(1)
-#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
#define PHY_RTL8201F_S700_RMII_TIMINGS BIT(4)
@@ -49,10 +48,10 @@
#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
-#define MIIM_RTL8211E_CONFREG 0x1c
-#define MIIM_RTL8211E_CONFREG_TXD 0x0002
-#define MIIM_RTL8211E_CONFREG_RXD 0x0004
-#define MIIM_RTL8211E_CONFREG_MAGIC 0xb400 /* Undocumented */
+#define MIIM_RTL8211E_CONFREG 0x1c
+#define MIIM_RTL8211E_CTRL_DELAY BIT(13)
+#define MIIM_RTL8211E_TX_DELAY BIT(12)
+#define MIIM_RTL8211E_RX_DELAY BIT(11)
#define MIIM_RTL8211E_EXT_PAGE_SELECT 0x1e
@@ -108,10 +107,6 @@ static int rtl8211b_probe(struct phy_device *phydev)
static int rtl8211e_probe(struct phy_device *phydev)
{
-#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
- phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
-#endif
-
return 0;
}
@@ -154,22 +149,6 @@ static int rtl8211x_config(struct phy_device *phydev)
reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
}
- if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
- unsigned int reg;
-
- phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
- 7);
- phy_write(phydev, MDIO_DEVAD_NONE,
- MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
- reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
- /* Ensure both internal delays are turned off */
- reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
- /* Flip the magic undocumented bits */
- reg |= MIIM_RTL8211E_CONFREG_MAGIC;
- phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
- phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
- 0);
- }
/* read interrupt status just to clear it */
phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
@@ -201,6 +180,44 @@ static int rtl8201f_config(struct phy_device *phydev)
return 0;
}
+static int rtl8211e_config(struct phy_device *phydev)
+{
+ int reg, val;
+
+ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val = MIIM_RTL8211E_CTRL_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY |
+ MIIM_RTL8211E_RX_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_RX_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY;
+ break;
+ default: /* the rest of the modes imply leaving delays as is. */
+ goto default_delay;
+ }
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 7);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
+ reg &= ~(MIIM_RTL8211E_TX_DELAY | MIIM_RTL8211E_RX_DELAY);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg | val);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0);
+
+default_delay:
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
static int rtl8211f_config(struct phy_device *phydev)
{
u16 reg;
@@ -410,7 +427,7 @@ static struct phy_driver RTL8211E_driver = {
.mask = 0xffffff,
.features = PHY_GBIT_FEATURES,
.probe = &rtl8211e_probe,
- .config = &rtl8211x_config,
+ .config = &rtl8211e_config,
.startup = &rtl8211e_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c
new file mode 100644
index 00000000000..17bab33eddb
--- /dev/null
+++ b/drivers/net/sja1105.c
@@ -0,0 +1,3376 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2016-2018 NXP
+ * Copyright 2018, Sensor-Technik Wiedemann GmbH
+ * Copyright 2018-2019, Vladimir Oltean <olteanv@gmail.com>
+ * Copyright 2020-2021 NXP
+ *
+ * Ported from Linux (drivers/net/dsa/sja1105/).
+ */
+
+#include <common.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/bitrev.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/types.h>
+#include <net/dsa.h>
+#include <stdlib.h>
+#include <spi.h>
+#include <miiphy.h>
+#include <dm/of_extra.h>
+
+enum packing_op {
+ PACK,
+ UNPACK,
+};
+
+#define ETHER_CRC32_POLY 0x04C11DB7
+#define ETH_P_SJA1105 0xdadb
+#define SJA1105_NUM_PORTS 5
+#define SJA1110_NUM_PORTS 11
+#define SJA1105_MAX_NUM_PORTS SJA1110_NUM_PORTS
+#define SJA1105_NUM_TC 8
+#define SJA1105ET_FDB_BIN_SIZE 4
+#define SJA1105_SIZE_CGU_CMD 4
+#define SJA1105_SIZE_RESET_CMD 4
+#define SJA1105_SIZE_MDIO_CMD 4
+#define SJA1105_SIZE_SPI_MSG_HEADER 4
+#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4)
+#define SJA1105_SIZE_DEVICE_ID 4
+#define SJA1105_SIZE_TABLE_HEADER 12
+#define SJA1105_SIZE_L2_POLICING_ENTRY 8
+#define SJA1105_SIZE_VLAN_LOOKUP_ENTRY 8
+#define SJA1110_SIZE_VLAN_LOOKUP_ENTRY 12
+#define SJA1105_SIZE_L2_FORWARDING_ENTRY 8
+#define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY 12
+#define SJA1105_SIZE_XMII_PARAMS_ENTRY 4
+#define SJA1110_SIZE_XMII_PARAMS_ENTRY 8
+#define SJA1105ET_SIZE_MAC_CONFIG_ENTRY 28
+#define SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY 40
+#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY 32
+#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY 44
+#define SJA1110_SIZE_GENERAL_PARAMS_ENTRY 56
+
+#define SJA1105_MAX_L2_LOOKUP_COUNT 1024
+#define SJA1105_MAX_L2_POLICING_COUNT 45
+#define SJA1110_MAX_L2_POLICING_COUNT 110
+#define SJA1105_MAX_VLAN_LOOKUP_COUNT 4096
+#define SJA1105_MAX_L2_FORWARDING_COUNT 13
+#define SJA1110_MAX_L2_FORWARDING_COUNT 19
+#define SJA1105_MAX_MAC_CONFIG_COUNT 5
+#define SJA1110_MAX_MAC_CONFIG_COUNT 11
+#define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1
+#define SJA1105_MAX_GENERAL_PARAMS_COUNT 1
+#define SJA1105_MAX_XMII_PARAMS_COUNT 1
+
+#define SJA1105_MAX_FRAME_MEMORY 929
+
+#define SJA1105E_DEVICE_ID 0x9C00000Cull
+#define SJA1105T_DEVICE_ID 0x9E00030Eull
+#define SJA1105PR_DEVICE_ID 0xAF00030Eull
+#define SJA1105QS_DEVICE_ID 0xAE00030Eull
+#define SJA1110_DEVICE_ID 0xB700030Full
+
+#define SJA1105ET_PART_NO 0x9A83
+#define SJA1105P_PART_NO 0x9A84
+#define SJA1105Q_PART_NO 0x9A85
+#define SJA1105R_PART_NO 0x9A86
+#define SJA1105S_PART_NO 0x9A87
+#define SJA1110A_PART_NO 0x1110
+#define SJA1110B_PART_NO 0x1111
+#define SJA1110C_PART_NO 0x1112
+#define SJA1110D_PART_NO 0x1113
+
+#define SJA1110_ACU 0x1c4400
+#define SJA1110_RGU 0x1c6000
+#define SJA1110_CGU 0x1c6400
+
+#define SJA1110_SPI_ADDR(x) ((x) / 4)
+#define SJA1110_ACU_ADDR(x) (SJA1110_ACU + SJA1110_SPI_ADDR(x))
+#define SJA1110_CGU_ADDR(x) (SJA1110_CGU + SJA1110_SPI_ADDR(x))
+#define SJA1110_RGU_ADDR(x) (SJA1110_RGU + SJA1110_SPI_ADDR(x))
+
+#define SJA1105_RSV_ADDR 0xffffffffffffffffull
+
+#define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc)
+
+#define DSA_8021Q_DIR_TX BIT(11)
+#define DSA_8021Q_PORT_SHIFT 0
+#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
+#define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \
+ DSA_8021Q_PORT_MASK)
+
+#define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000)
+
+/* XPCS registers */
+
+/* VR MII MMD registers offsets */
+#define DW_VR_MII_DIG_CTRL1 0x8000
+#define DW_VR_MII_AN_CTRL 0x8001
+#define DW_VR_MII_DIG_CTRL2 0x80e1
+
+/* VR_MII_DIG_CTRL1 */
+#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
+
+/* VR_MII_DIG_CTRL2 */
+#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
+
+/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
+#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
+#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
+#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1
+#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
+#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
+
+/* PMA registers */
+
+/* LANE_DRIVER1_0 register */
+#define SJA1110_LANE_DRIVER1_0 0x8038
+#define SJA1110_TXDRV(x) (((x) << 12) & GENMASK(14, 12))
+
+/* LANE_DRIVER2_0 register */
+#define SJA1110_LANE_DRIVER2_0 0x803a
+#define SJA1110_TXDRVTRIM_LSB(x) ((x) & GENMASK_ULL(15, 0))
+
+/* LANE_DRIVER2_1 register */
+#define SJA1110_LANE_DRIVER2_1 0x803b
+#define SJA1110_LANE_DRIVER2_1_RSV BIT(9)
+#define SJA1110_TXDRVTRIM_MSB(x) (((x) & GENMASK_ULL(23, 16)) >> 16)
+
+/* LANE_TRIM register */
+#define SJA1110_LANE_TRIM 0x8040
+#define SJA1110_TXTEN BIT(11)
+#define SJA1110_TXRTRIM(x) (((x) << 8) & GENMASK(10, 8))
+#define SJA1110_TXPLL_BWSEL BIT(7)
+#define SJA1110_RXTEN BIT(6)
+#define SJA1110_RXRTRIM(x) (((x) << 3) & GENMASK(5, 3))
+#define SJA1110_CDR_GAIN BIT(2)
+#define SJA1110_ACCOUPLE_RXVCM_EN BIT(0)
+
+/* LANE_DATAPATH_1 register */
+#define SJA1110_LANE_DATAPATH_1 0x8037
+
+/* POWERDOWN_ENABLE register */
+#define SJA1110_POWERDOWN_ENABLE 0x8041
+#define SJA1110_TXPLL_PD BIT(12)
+#define SJA1110_TXPD BIT(11)
+#define SJA1110_RXPKDETEN BIT(10)
+#define SJA1110_RXCH_PD BIT(9)
+#define SJA1110_RXBIAS_PD BIT(8)
+#define SJA1110_RESET_SER_EN BIT(7)
+#define SJA1110_RESET_SER BIT(6)
+#define SJA1110_RESET_DES BIT(5)
+#define SJA1110_RCVEN BIT(4)
+
+/* RXPLL_CTRL0 register */
+#define SJA1110_RXPLL_CTRL0 0x8065
+#define SJA1110_RXPLL_FBDIV(x) (((x) << 2) & GENMASK(9, 2))
+
+/* RXPLL_CTRL1 register */
+#define SJA1110_RXPLL_CTRL1 0x8066
+#define SJA1110_RXPLL_REFDIV(x) ((x) & GENMASK(4, 0))
+
+/* TXPLL_CTRL0 register */
+#define SJA1110_TXPLL_CTRL0 0x806d
+#define SJA1110_TXPLL_FBDIV(x) ((x) & GENMASK(11, 0))
+
+/* TXPLL_CTRL1 register */
+#define SJA1110_TXPLL_CTRL1 0x806e
+#define SJA1110_TXPLL_REFDIV(x) ((x) & GENMASK(5, 0))
+
+/* RX_DATA_DETECT register */
+#define SJA1110_RX_DATA_DETECT 0x8045
+
+/* RX_CDR_CTLE register */
+#define SJA1110_RX_CDR_CTLE 0x8042
+
+/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
+enum {
+ BLKID_L2_POLICING = 0x06,
+ BLKID_VLAN_LOOKUP = 0x07,
+ BLKID_L2_FORWARDING = 0x08,
+ BLKID_MAC_CONFIG = 0x09,
+ BLKID_L2_FORWARDING_PARAMS = 0x0E,
+ BLKID_GENERAL_PARAMS = 0x11,
+ BLKID_XMII_PARAMS = 0x4E,
+};
+
+enum sja1105_blk_idx {
+ BLK_IDX_L2_POLICING = 0,
+ BLK_IDX_VLAN_LOOKUP,
+ BLK_IDX_L2_FORWARDING,
+ BLK_IDX_MAC_CONFIG,
+ BLK_IDX_L2_FORWARDING_PARAMS,
+ BLK_IDX_GENERAL_PARAMS,
+ BLK_IDX_XMII_PARAMS,
+ BLK_IDX_MAX,
+};
+
+struct sja1105_general_params_entry {
+ u64 mac_fltres1;
+ u64 mac_fltres0;
+ u64 mac_flt1;
+ u64 mac_flt0;
+ u64 casc_port;
+ u64 host_port;
+ u64 mirr_port;
+ u64 tpid;
+ u64 tpid2;
+};
+
+struct sja1105_vlan_lookup_entry {
+ u64 vmemb_port;
+ u64 vlan_bc;
+ u64 tag_port;
+ u64 vlanid;
+ u64 type_entry; /* SJA1110 only */
+};
+
+struct sja1105_l2_forwarding_entry {
+ u64 bc_domain;
+ u64 reach_port;
+ u64 fl_domain;
+};
+
+struct sja1105_l2_forwarding_params_entry {
+ u64 part_spc[SJA1105_NUM_TC];
+};
+
+struct sja1105_l2_policing_entry {
+ u64 sharindx;
+ u64 smax;
+ u64 rate;
+ u64 maxlen;
+ u64 partition;
+};
+
+struct sja1105_mac_config_entry {
+ u64 top[SJA1105_NUM_TC];
+ u64 base[SJA1105_NUM_TC];
+ u64 enabled[SJA1105_NUM_TC];
+ u64 speed;
+ u64 vlanid;
+ u64 egress;
+ u64 ingress;
+};
+
+struct sja1105_xmii_params_entry {
+ u64 phy_mac[SJA1105_MAX_NUM_PORTS];
+ u64 xmii_mode[SJA1105_MAX_NUM_PORTS];
+ u64 special[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1105_table_header {
+ u64 block_id;
+ u64 len;
+ u64 crc;
+};
+
+struct sja1105_table_ops {
+ size_t (*packing)(void *buf, void *entry_ptr, enum packing_op op);
+ size_t unpacked_entry_size;
+ size_t packed_entry_size;
+ size_t max_entry_count;
+};
+
+struct sja1105_table {
+ const struct sja1105_table_ops *ops;
+ size_t entry_count;
+ void *entries;
+};
+
+struct sja1105_static_config {
+ u64 device_id;
+ struct sja1105_table tables[BLK_IDX_MAX];
+};
+
+struct sja1105_xpcs_cfg {
+ bool inband_an;
+ int speed;
+};
+
+struct sja1105_private {
+ struct sja1105_static_config static_config;
+ bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
+ bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
+ u16 pvid[SJA1105_MAX_NUM_PORTS];
+ struct sja1105_xpcs_cfg xpcs_cfg[SJA1105_MAX_NUM_PORTS];
+ struct mii_dev *mdio_pcs;
+ const struct sja1105_info *info;
+ struct udevice *dev;
+};
+
+typedef enum {
+ SPI_READ = 0,
+ SPI_WRITE = 1,
+} sja1105_spi_rw_mode_t;
+
+typedef enum {
+ XMII_MAC = 0,
+ XMII_PHY = 1,
+} sja1105_mii_role_t;
+
+typedef enum {
+ XMII_MODE_MII = 0,
+ XMII_MODE_RMII = 1,
+ XMII_MODE_RGMII = 2,
+ XMII_MODE_SGMII = 3,
+} sja1105_phy_interface_t;
+
+enum {
+ SJA1105_SPEED_AUTO,
+ SJA1105_SPEED_10MBPS,
+ SJA1105_SPEED_100MBPS,
+ SJA1105_SPEED_1000MBPS,
+ SJA1105_SPEED_MAX,
+};
+
+enum sja1110_vlan_type {
+ SJA1110_VLAN_INVALID = 0,
+ SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
+ SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
+ SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
+};
+
+/* Keeps the different addresses between E/T and P/Q/R/S */
+struct sja1105_regs {
+ u64 device_id;
+ u64 prod_id;
+ u64 status;
+ u64 port_control;
+ u64 rgu;
+ u64 config;
+ u64 rmii_pll1;
+ u64 pad_mii_tx[SJA1105_MAX_NUM_PORTS];
+ u64 pad_mii_rx[SJA1105_MAX_NUM_PORTS];
+ u64 pad_mii_id[SJA1105_MAX_NUM_PORTS];
+ u64 cgu_idiv[SJA1105_MAX_NUM_PORTS];
+ u64 mii_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_rx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_ext_rx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rgmii_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 pcs_base[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1105_info {
+ u64 device_id;
+ u64 part_no;
+ const struct sja1105_table_ops *static_ops;
+ const struct sja1105_regs *regs;
+ int (*reset_cmd)(struct sja1105_private *priv);
+ int (*setup_rgmii_delay)(struct sja1105_private *priv, int port);
+ int (*pcs_mdio_read)(struct mii_dev *bus, int phy, int mmd, int reg);
+ int (*pcs_mdio_write)(struct mii_dev *bus, int phy, int mmd, int reg,
+ u16 val);
+ int (*pma_config)(struct sja1105_private *priv, int port);
+ const char *name;
+ bool supports_mii[SJA1105_MAX_NUM_PORTS];
+ bool supports_rmii[SJA1105_MAX_NUM_PORTS];
+ bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
+ bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
+ const u64 port_speed[SJA1105_SPEED_MAX];
+};
+
+struct sja1105_chunk {
+ u8 *buf;
+ size_t len;
+ u64 reg_addr;
+};
+
+struct sja1105_spi_message {
+ u64 access;
+ u64 read_count;
+ u64 address;
+};
+
+/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
+struct sja1105_cfg_pad_mii {
+ u64 d32_os;
+ u64 d32_ih;
+ u64 d32_ipud;
+ u64 d10_ih;
+ u64 d10_os;
+ u64 d10_ipud;
+ u64 ctrl_os;
+ u64 ctrl_ih;
+ u64 ctrl_ipud;
+ u64 clk_os;
+ u64 clk_ih;
+ u64 clk_ipud;
+};
+
+struct sja1105_cfg_pad_mii_id {
+ u64 rxc_stable_ovr;
+ u64 rxc_delay;
+ u64 rxc_bypass;
+ u64 rxc_pd;
+ u64 txc_stable_ovr;
+ u64 txc_delay;
+ u64 txc_bypass;
+ u64 txc_pd;
+};
+
+struct sja1105_cgu_idiv {
+ u64 clksrc;
+ u64 autoblock;
+ u64 idiv;
+ u64 pd;
+};
+
+struct sja1105_cgu_pll_ctrl {
+ u64 pllclksrc;
+ u64 msel;
+ u64 autoblock;
+ u64 psel;
+ u64 direct;
+ u64 fbsel;
+ u64 bypass;
+ u64 pd;
+};
+
+enum {
+ CLKSRC_MII0_TX_CLK = 0x00,
+ CLKSRC_MII0_RX_CLK = 0x01,
+ CLKSRC_MII1_TX_CLK = 0x02,
+ CLKSRC_MII1_RX_CLK = 0x03,
+ CLKSRC_MII2_TX_CLK = 0x04,
+ CLKSRC_MII2_RX_CLK = 0x05,
+ CLKSRC_MII3_TX_CLK = 0x06,
+ CLKSRC_MII3_RX_CLK = 0x07,
+ CLKSRC_MII4_TX_CLK = 0x08,
+ CLKSRC_MII4_RX_CLK = 0x09,
+ CLKSRC_PLL0 = 0x0B,
+ CLKSRC_PLL1 = 0x0E,
+ CLKSRC_IDIV0 = 0x11,
+ CLKSRC_IDIV1 = 0x12,
+ CLKSRC_IDIV2 = 0x13,
+ CLKSRC_IDIV3 = 0x14,
+ CLKSRC_IDIV4 = 0x15,
+};
+
+struct sja1105_cgu_mii_ctrl {
+ u64 clksrc;
+ u64 autoblock;
+ u64 pd;
+};
+
+static int get_reverse_lsw32_offset(int offset, size_t len)
+{
+ int closest_multiple_of_4;
+ int word_index;
+
+ word_index = offset / 4;
+ closest_multiple_of_4 = word_index * 4;
+ offset -= closest_multiple_of_4;
+ word_index = (len / 4) - word_index - 1;
+ return word_index * 4 + offset;
+}
+
+/* Simplified version of the "packing" function from Linux, adapted
+ * to support only sja1105's quirk: QUIRK_LSW32_IS_FIRST
+ */
+static void sja1105_packing(void *pbuf, u64 *uval, int startbit, int endbit,
+ size_t pbuflen, enum packing_op op)
+{
+ int plogical_first_u8, plogical_last_u8, box;
+
+ if (op == UNPACK)
+ *uval = 0;
+
+ plogical_first_u8 = startbit / 8;
+ plogical_last_u8 = endbit / 8;
+
+ for (box = plogical_first_u8; box >= plogical_last_u8; box--) {
+ int box_start_bit, box_end_bit, box_addr;
+ int proj_start_bit, proj_end_bit;
+ u64 proj_mask;
+ u8 box_mask;
+
+ if (box == plogical_first_u8)
+ box_start_bit = startbit % 8;
+ else
+ box_start_bit = 7;
+ if (box == plogical_last_u8)
+ box_end_bit = endbit % 8;
+ else
+ box_end_bit = 0;
+
+ proj_start_bit = ((box * 8) + box_start_bit) - endbit;
+ proj_end_bit = ((box * 8) + box_end_bit) - endbit;
+ proj_mask = GENMASK_ULL(proj_start_bit, proj_end_bit);
+ box_mask = GENMASK_ULL(box_start_bit, box_end_bit);
+
+ box_addr = pbuflen - box - 1;
+ box_addr = get_reverse_lsw32_offset(box_addr, pbuflen);
+
+ if (op == UNPACK) {
+ u64 pval;
+
+ /* Read from pbuf, write to uval */
+ pval = ((u8 *)pbuf)[box_addr] & box_mask;
+
+ pval >>= box_end_bit;
+ pval <<= proj_end_bit;
+ *uval &= ~proj_mask;
+ *uval |= pval;
+ } else {
+ u64 pval;
+
+ /* Write to pbuf, read from uval */
+ pval = (*uval) & proj_mask;
+ pval >>= proj_end_bit;
+
+ pval <<= box_end_bit;
+ ((u8 *)pbuf)[box_addr] &= ~box_mask;
+ ((u8 *)pbuf)[box_addr] |= pval;
+ }
+ }
+}
+
+static u32 crc32_add(u32 crc, u8 byte)
+{
+ u32 byte32 = bitrev32(byte);
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if ((crc ^ byte32) & BIT(31)) {
+ crc <<= 1;
+ crc ^= ETHER_CRC32_POLY;
+ } else {
+ crc <<= 1;
+ }
+ byte32 <<= 1;
+ }
+ return crc;
+}
+
+/* Little-endian Ethernet CRC32 of data packed as big-endian u32 words */
+static uint32_t sja1105_crc32(void *buf, size_t len)
+{
+ unsigned int i;
+ u64 chunk;
+ u32 crc;
+
+ /* seed */
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < len; i += 4) {
+ sja1105_packing(buf + i, &chunk, 31, 0, 4, UNPACK);
+ crc = crc32_add(crc, chunk & 0xFF);
+ crc = crc32_add(crc, (chunk >> 8) & 0xFF);
+ crc = crc32_add(crc, (chunk >> 16) & 0xFF);
+ crc = crc32_add(crc, (chunk >> 24) & 0xFF);
+ }
+ return bitrev32(~crc);
+}
+
+static void sja1105_spi_message_pack(void *buf, struct sja1105_spi_message *msg)
+{
+ const int size = SJA1105_SIZE_SPI_MSG_HEADER;
+
+ memset(buf, 0, size);
+
+ sja1105_packing(buf, &msg->access, 31, 31, size, PACK);
+ sja1105_packing(buf, &msg->read_count, 30, 25, size, PACK);
+ sja1105_packing(buf, &msg->address, 24, 4, size, PACK);
+}
+
+static int sja1105_xfer_buf(const struct sja1105_private *priv,
+ sja1105_spi_rw_mode_t rw, u64 reg_addr,
+ u8 *buf, size_t len)
+{
+ struct udevice *dev = priv->dev;
+ struct sja1105_chunk chunk = {
+ .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN),
+ .reg_addr = reg_addr,
+ .buf = buf,
+ };
+ int num_chunks;
+ int rc, i;
+
+ rc = dm_spi_claim_bus(dev);
+ if (rc)
+ return rc;
+
+ num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN);
+
+ for (i = 0; i < num_chunks; i++) {
+ u8 hdr_buf[SJA1105_SIZE_SPI_MSG_HEADER];
+ struct sja1105_spi_message msg;
+ u8 *rx_buf = NULL;
+ u8 *tx_buf = NULL;
+
+ /* Populate the transfer's header buffer */
+ msg.address = chunk.reg_addr;
+ msg.access = rw;
+ if (rw == SPI_READ)
+ msg.read_count = chunk.len / 4;
+ else
+ /* Ignored */
+ msg.read_count = 0;
+ sja1105_spi_message_pack(hdr_buf, &msg);
+ rc = dm_spi_xfer(dev, SJA1105_SIZE_SPI_MSG_HEADER * 8, hdr_buf,
+ NULL, SPI_XFER_BEGIN);
+ if (rc)
+ goto out;
+
+ /* Populate the transfer's data buffer */
+ if (rw == SPI_READ)
+ rx_buf = chunk.buf;
+ else
+ tx_buf = chunk.buf;
+ rc = dm_spi_xfer(dev, chunk.len * 8, tx_buf, rx_buf,
+ SPI_XFER_END);
+ if (rc)
+ goto out;
+
+ /* Calculate next chunk */
+ chunk.buf += chunk.len;
+ chunk.reg_addr += chunk.len / 4;
+ chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf),
+ SJA1105_SIZE_SPI_MSG_MAXLEN);
+ }
+
+out:
+ dm_spi_release_bus(dev);
+
+ return rc;
+}
+
+static int sja1105et_reset_cmd(struct sja1105_private *priv)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+ const int size = SJA1105_SIZE_RESET_CMD;
+ u64 cold_rst = 1;
+
+ sja1105_packing(packed_buf, &cold_rst, 3, 3, size, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+ SJA1105_SIZE_RESET_CMD);
+}
+
+static int sja1105pqrs_reset_cmd(struct sja1105_private *priv)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+ const int size = SJA1105_SIZE_RESET_CMD;
+ u64 cold_rst = 1;
+
+ sja1105_packing(packed_buf, &cold_rst, 2, 2, size, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+ SJA1105_SIZE_RESET_CMD);
+}
+
+static int sja1110_reset_cmd(struct sja1105_private *priv)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+ const int size = SJA1105_SIZE_RESET_CMD;
+ u64 switch_rst = 1;
+
+ /* Only reset the switch core.
+ * A full cold reset would re-enable the BASE_MCSS_CLOCK PLL which
+ * would turn on the microcontroller, potentially letting it execute
+ * code which could interfere with our configuration.
+ */
+ sja1105_packing(packed_buf, &switch_rst, 20, 20, size, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+ SJA1105_SIZE_RESET_CMD);
+}
+
+static size_t sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY;
+ struct sja1105_general_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->mac_fltres1, 311, 264, size, op);
+ sja1105_packing(buf, &entry->mac_fltres0, 263, 216, size, op);
+ sja1105_packing(buf, &entry->mac_flt1, 215, 168, size, op);
+ sja1105_packing(buf, &entry->mac_flt0, 167, 120, size, op);
+ sja1105_packing(buf, &entry->casc_port, 115, 113, size, op);
+ sja1105_packing(buf, &entry->host_port, 112, 110, size, op);
+ sja1105_packing(buf, &entry->mirr_port, 109, 107, size, op);
+ sja1105_packing(buf, &entry->tpid, 42, 27, size, op);
+ sja1105_packing(buf, &entry->tpid2, 25, 10, size, op);
+ return size;
+}
+
+static size_t sja1110_general_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_general_params_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
+
+ sja1105_packing(buf, &entry->mac_fltres1, 438, 391, size, op);
+ sja1105_packing(buf, &entry->mac_fltres0, 390, 343, size, op);
+ sja1105_packing(buf, &entry->mac_flt1, 342, 295, size, op);
+ sja1105_packing(buf, &entry->mac_flt0, 294, 247, size, op);
+ sja1105_packing(buf, &entry->casc_port, 242, 232, size, op);
+ sja1105_packing(buf, &entry->host_port, 231, 228, size, op);
+ sja1105_packing(buf, &entry->mirr_port, 227, 224, size, op);
+ sja1105_packing(buf, &entry->tpid2, 159, 144, size, op);
+ sja1105_packing(buf, &entry->tpid, 142, 127, size, op);
+ return size;
+}
+
+static size_t
+sja1105pqrs_general_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
+ struct sja1105_general_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->mac_fltres1, 343, 296, size, op);
+ sja1105_packing(buf, &entry->mac_fltres0, 295, 248, size, op);
+ sja1105_packing(buf, &entry->mac_flt1, 247, 200, size, op);
+ sja1105_packing(buf, &entry->mac_flt0, 199, 152, size, op);
+ sja1105_packing(buf, &entry->casc_port, 147, 145, size, op);
+ sja1105_packing(buf, &entry->host_port, 144, 142, size, op);
+ sja1105_packing(buf, &entry->mirr_port, 141, 139, size, op);
+ sja1105_packing(buf, &entry->tpid, 74, 59, size, op);
+ sja1105_packing(buf, &entry->tpid2, 57, 42, size, op);
+ return size;
+}
+
+static size_t
+sja1105_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY;
+ struct sja1105_l2_forwarding_params_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 13; i < SJA1105_NUM_TC; i++, offset += 10)
+ sja1105_packing(buf, &entry->part_spc[i],
+ offset + 9, offset + 0, size, op);
+ return size;
+}
+
+static size_t
+sja1110_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_forwarding_params_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY;
+ int offset, i;
+
+ for (i = 0, offset = 5; i < 8; i++, offset += 11)
+ sja1105_packing(buf, &entry->part_spc[i],
+ offset + 10, offset + 0, size, op);
+ return size;
+}
+
+static size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_ENTRY;
+ struct sja1105_l2_forwarding_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->bc_domain, 63, 59, size, op);
+ sja1105_packing(buf, &entry->reach_port, 58, 54, size, op);
+ sja1105_packing(buf, &entry->fl_domain, 53, 49, size, op);
+ return size;
+}
+
+static size_t sja1110_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_forwarding_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_ENTRY;
+
+ sja1105_packing(buf, &entry->bc_domain, 63, 53, size, op);
+ sja1105_packing(buf, &entry->reach_port, 52, 42, size, op);
+ sja1105_packing(buf, &entry->fl_domain, 41, 31, size, op);
+ return size;
+}
+
+static size_t sja1105_l2_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_policing_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_POLICING_ENTRY;
+
+ sja1105_packing(buf, &entry->sharindx, 63, 58, size, op);
+ sja1105_packing(buf, &entry->smax, 57, 42, size, op);
+ sja1105_packing(buf, &entry->rate, 41, 26, size, op);
+ sja1105_packing(buf, &entry->maxlen, 25, 15, size, op);
+ sja1105_packing(buf, &entry->partition, 14, 12, size, op);
+ return size;
+}
+
+static size_t sja1110_l2_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_policing_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_POLICING_ENTRY;
+
+ sja1105_packing(buf, &entry->sharindx, 63, 57, size, op);
+ sja1105_packing(buf, &entry->smax, 56, 39, size, op);
+ sja1105_packing(buf, &entry->rate, 38, 21, size, op);
+ sja1105_packing(buf, &entry->maxlen, 20, 10, size, op);
+ sja1105_packing(buf, &entry->partition, 9, 7, size, op);
+ return size;
+}
+
+static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY;
+ struct sja1105_mac_config_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 72; i < SJA1105_NUM_TC; i++, offset += 19) {
+ sja1105_packing(buf, &entry->enabled[i],
+ offset + 0, offset + 0, size, op);
+ sja1105_packing(buf, &entry->base[i],
+ offset + 9, offset + 1, size, op);
+ sja1105_packing(buf, &entry->top[i],
+ offset + 18, offset + 10, size, op);
+ }
+ sja1105_packing(buf, &entry->speed, 66, 65, size, op);
+ sja1105_packing(buf, &entry->vlanid, 21, 10, size, op);
+ sja1105_packing(buf, &entry->egress, 2, 2, size, op);
+ sja1105_packing(buf, &entry->ingress, 1, 1, size, op);
+ return size;
+}
+
+static size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+ struct sja1105_mac_config_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 104; i < SJA1105_NUM_TC; i++, offset += 19) {
+ sja1105_packing(buf, &entry->enabled[i],
+ offset + 0, offset + 0, size, op);
+ sja1105_packing(buf, &entry->base[i],
+ offset + 9, offset + 1, size, op);
+ sja1105_packing(buf, &entry->top[i],
+ offset + 18, offset + 10, size, op);
+ }
+ sja1105_packing(buf, &entry->speed, 98, 97, size, op);
+ sja1105_packing(buf, &entry->vlanid, 53, 42, size, op);
+ sja1105_packing(buf, &entry->egress, 32, 32, size, op);
+ sja1105_packing(buf, &entry->ingress, 31, 31, size, op);
+ return size;
+}
+
+static size_t sja1110_mac_config_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+ struct sja1105_mac_config_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 104; i < 8; i++, offset += 19) {
+ sja1105_packing(buf, &entry->enabled[i],
+ offset + 0, offset + 0, size, op);
+ sja1105_packing(buf, &entry->base[i],
+ offset + 9, offset + 1, size, op);
+ sja1105_packing(buf, &entry->top[i],
+ offset + 18, offset + 10, size, op);
+ }
+ sja1105_packing(buf, &entry->speed, 98, 96, size, op);
+ sja1105_packing(buf, &entry->vlanid, 52, 41, size, op);
+ sja1105_packing(buf, &entry->egress, 31, 31, size, op);
+ sja1105_packing(buf, &entry->ingress, 30, 30, size, op);
+ return size;
+}
+
+static size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY;
+ struct sja1105_vlan_lookup_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->vmemb_port, 53, 49, size, op);
+ sja1105_packing(buf, &entry->vlan_bc, 48, 44, size, op);
+ sja1105_packing(buf, &entry->tag_port, 43, 39, size, op);
+ sja1105_packing(buf, &entry->vlanid, 38, 27, size, op);
+ return size;
+}
+
+static size_t sja1110_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vlan_lookup_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
+
+ sja1105_packing(buf, &entry->vmemb_port, 73, 63, size, op);
+ sja1105_packing(buf, &entry->vlan_bc, 62, 52, size, op);
+ sja1105_packing(buf, &entry->tag_port, 51, 41, size, op);
+ sja1105_packing(buf, &entry->type_entry, 40, 39, size, op);
+ sja1105_packing(buf, &entry->vlanid, 38, 27, size, op);
+ return size;
+}
+
+static size_t sja1105_xmii_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105_SIZE_XMII_PARAMS_ENTRY;
+ struct sja1105_xmii_params_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 17; i < SJA1105_NUM_PORTS; i++, offset += 3) {
+ sja1105_packing(buf, &entry->xmii_mode[i],
+ offset + 1, offset + 0, size, op);
+ sja1105_packing(buf, &entry->phy_mac[i],
+ offset + 2, offset + 2, size, op);
+ }
+ return size;
+}
+
+static size_t sja1110_xmii_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1110_SIZE_XMII_PARAMS_ENTRY;
+ struct sja1105_xmii_params_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 20; i < SJA1110_NUM_PORTS; i++, offset += 4) {
+ sja1105_packing(buf, &entry->xmii_mode[i],
+ offset + 1, offset + 0, size, op);
+ sja1105_packing(buf, &entry->phy_mac[i],
+ offset + 2, offset + 2, size, op);
+ sja1105_packing(buf, &entry->special[i],
+ offset + 3, offset + 3, size, op);
+ }
+ return size;
+}
+
+static size_t sja1105_table_header_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105_SIZE_TABLE_HEADER;
+ struct sja1105_table_header *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->block_id, 31, 24, size, op);
+ sja1105_packing(buf, &entry->len, 55, 32, size, op);
+ sja1105_packing(buf, &entry->crc, 95, 64, size, op);
+ return size;
+}
+
+static void
+sja1105_table_header_pack_with_crc(void *buf, struct sja1105_table_header *hdr)
+{
+ /* First pack the table as-is, then calculate the CRC, and
+ * finally put the proper CRC into the packed buffer
+ */
+ memset(buf, 0, SJA1105_SIZE_TABLE_HEADER);
+ sja1105_table_header_packing(buf, hdr, PACK);
+ hdr->crc = sja1105_crc32(buf, SJA1105_SIZE_TABLE_HEADER - 4);
+ sja1105_packing(buf + SJA1105_SIZE_TABLE_HEADER - 4, &hdr->crc,
+ 31, 0, 4, PACK);
+}
+
+static void sja1105_table_write_crc(u8 *table_start, u8 *crc_ptr)
+{
+ u64 computed_crc;
+ int len_bytes;
+
+ len_bytes = (uintptr_t)(crc_ptr - table_start);
+ computed_crc = sja1105_crc32(table_start, len_bytes);
+ sja1105_packing(crc_ptr, &computed_crc, 31, 0, 4, PACK);
+}
+
+/* The block IDs that the switches support are unfortunately sparse, so keep a
+ * mapping table to "block indices" and translate back and forth.
+ */
+static const u64 blk_id_map[BLK_IDX_MAX] = {
+ [BLK_IDX_L2_POLICING] = BLKID_L2_POLICING,
+ [BLK_IDX_VLAN_LOOKUP] = BLKID_VLAN_LOOKUP,
+ [BLK_IDX_L2_FORWARDING] = BLKID_L2_FORWARDING,
+ [BLK_IDX_MAC_CONFIG] = BLKID_MAC_CONFIG,
+ [BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS,
+ [BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS,
+ [BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS,
+};
+
+static void
+sja1105_static_config_pack(void *buf, struct sja1105_static_config *config)
+{
+ struct sja1105_table_header header = {0};
+ enum sja1105_blk_idx i;
+ u8 *p = buf;
+ int j;
+
+ sja1105_packing(p, &config->device_id, 31, 0, 4, PACK);
+ p += SJA1105_SIZE_DEVICE_ID;
+
+ for (i = 0; i < BLK_IDX_MAX; i++) {
+ const struct sja1105_table *table;
+ u8 *table_start;
+
+ table = &config->tables[i];
+ if (!table->entry_count)
+ continue;
+
+ header.block_id = blk_id_map[i];
+ header.len = table->entry_count *
+ table->ops->packed_entry_size / 4;
+ sja1105_table_header_pack_with_crc(p, &header);
+ p += SJA1105_SIZE_TABLE_HEADER;
+ table_start = p;
+ for (j = 0; j < table->entry_count; j++) {
+ u8 *entry_ptr = table->entries;
+
+ entry_ptr += j * table->ops->unpacked_entry_size;
+ memset(p, 0, table->ops->packed_entry_size);
+ table->ops->packing(p, entry_ptr, PACK);
+ p += table->ops->packed_entry_size;
+ }
+ sja1105_table_write_crc(table_start, p);
+ p += 4;
+ }
+ /* Final header:
+ * Block ID does not matter
+ * Length of 0 marks that header is final
+ * CRC will be replaced on-the-fly
+ */
+ header.block_id = 0;
+ header.len = 0;
+ header.crc = 0xDEADBEEF;
+ memset(p, 0, SJA1105_SIZE_TABLE_HEADER);
+ sja1105_table_header_packing(p, &header, PACK);
+}
+
+static size_t
+sja1105_static_config_get_length(const struct sja1105_static_config *config)
+{
+ unsigned int header_count;
+ enum sja1105_blk_idx i;
+ unsigned int sum;
+
+ /* Ending header */
+ header_count = 1;
+ sum = SJA1105_SIZE_DEVICE_ID;
+
+ /* Tables (headers and entries) */
+ for (i = 0; i < BLK_IDX_MAX; i++) {
+ const struct sja1105_table *table;
+
+ table = &config->tables[i];
+ if (table->entry_count)
+ header_count++;
+
+ sum += table->ops->packed_entry_size * table->entry_count;
+ }
+ /* Headers have an additional CRC at the end */
+ sum += header_count * (SJA1105_SIZE_TABLE_HEADER + 4);
+ /* Last header does not have an extra CRC because there is no data */
+ sum -= 4;
+
+ return sum;
+}
+
+/* Compatibility matrices */
+static const struct sja1105_table_ops sja1105et_table_ops[BLK_IDX_MAX] = {
+ [BLK_IDX_L2_POLICING] = {
+ .packing = sja1105_l2_policing_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_POLICING_COUNT,
+ },
+ [BLK_IDX_VLAN_LOOKUP] = {
+ .packing = sja1105_vlan_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+ .packed_entry_size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY,
+ .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING] = {
+ .packing = sja1105_l2_forwarding_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
+ },
+ [BLK_IDX_MAC_CONFIG] = {
+ .packing = sja1105et_mac_config_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+ .packed_entry_size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY,
+ .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING_PARAMS] = {
+ .packing = sja1105_l2_forwarding_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ },
+ [BLK_IDX_GENERAL_PARAMS] = {
+ .packing = sja1105et_general_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+ .packed_entry_size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ },
+ [BLK_IDX_XMII_PARAMS] = {
+ .packing = sja1105_xmii_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+ .packed_entry_size = SJA1105_SIZE_XMII_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+ },
+};
+
+static const struct sja1105_table_ops sja1105pqrs_table_ops[BLK_IDX_MAX] = {
+ [BLK_IDX_L2_POLICING] = {
+ .packing = sja1105_l2_policing_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_POLICING_COUNT,
+ },
+ [BLK_IDX_VLAN_LOOKUP] = {
+ .packing = sja1105_vlan_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+ .packed_entry_size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY,
+ .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING] = {
+ .packing = sja1105_l2_forwarding_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
+ },
+ [BLK_IDX_MAC_CONFIG] = {
+ .packing = sja1105pqrs_mac_config_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY,
+ .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING_PARAMS] = {
+ .packing = sja1105_l2_forwarding_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ },
+ [BLK_IDX_GENERAL_PARAMS] = {
+ .packing = sja1105pqrs_general_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ },
+ [BLK_IDX_XMII_PARAMS] = {
+ .packing = sja1105_xmii_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+ .packed_entry_size = SJA1105_SIZE_XMII_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+ },
+};
+
+static const struct sja1105_table_ops sja1110_table_ops[BLK_IDX_MAX] = {
+ [BLK_IDX_L2_POLICING] = {
+ .packing = sja1110_l2_policing_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+ .max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
+ },
+ [BLK_IDX_VLAN_LOOKUP] = {
+ .packing = sja1110_vlan_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+ .packed_entry_size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY,
+ .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING] = {
+ .packing = sja1110_l2_forwarding_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+ .max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
+ },
+ [BLK_IDX_MAC_CONFIG] = {
+ .packing = sja1110_mac_config_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY,
+ .max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING_PARAMS] = {
+ .packing = sja1110_l2_forwarding_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ },
+ [BLK_IDX_GENERAL_PARAMS] = {
+ .packing = sja1110_general_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+ .packed_entry_size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ },
+ [BLK_IDX_XMII_PARAMS] = {
+ .packing = sja1110_xmii_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+ .packed_entry_size = SJA1110_SIZE_XMII_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+ },
+};
+
+static int sja1105_init_mii_settings(struct sja1105_private *priv)
+{
+ struct sja1105_table *table;
+
+ table = &priv->static_config.tables[BLK_IDX_XMII_PARAMS];
+
+ table->entries = calloc(SJA1105_MAX_XMII_PARAMS_COUNT,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ /* Table will be populated at runtime */
+ table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
+
+ return 0;
+}
+
+static void sja1105_setup_tagging(struct sja1105_private *priv, int port)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_vlan_lookup_entry *vlan;
+ int cpu = pdata->cpu_port;
+
+ /* The CPU port is implicitly configured by
+ * configuring the front-panel ports
+ */
+ if (port == cpu)
+ return;
+
+ vlan = priv->static_config.tables[BLK_IDX_VLAN_LOOKUP].entries;
+
+ priv->pvid[port] = DSA_8021Q_DIR_TX | DSA_8021Q_PORT(port);
+
+ vlan[port].vmemb_port = BIT(port) | BIT(cpu);
+ vlan[port].vlan_bc = BIT(port) | BIT(cpu);
+ vlan[port].tag_port = BIT(cpu);
+ vlan[port].vlanid = priv->pvid[port];
+ vlan[port].type_entry = SJA1110_VLAN_D_TAG;
+}
+
+static int sja1105_init_vlan(struct sja1105_private *priv)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_table *table;
+ int port;
+
+ table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];
+
+ table->entries = calloc(pdata->num_ports,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = pdata->num_ports;
+
+ for (port = 0; port < pdata->num_ports; port++)
+ sja1105_setup_tagging(priv, port);
+
+ return 0;
+}
+
+static void
+sja1105_port_allow_traffic(struct sja1105_l2_forwarding_entry *l2_fwd,
+ int from, int to)
+{
+ l2_fwd[from].bc_domain |= BIT(to);
+ l2_fwd[from].reach_port |= BIT(to);
+ l2_fwd[from].fl_domain |= BIT(to);
+}
+
+static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_l2_forwarding_entry *l2fwd;
+ struct sja1105_table *table;
+ int cpu = pdata->cpu_port;
+ int i;
+
+ table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING];
+
+ table->entries = calloc(SJA1105_MAX_L2_FORWARDING_COUNT,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_L2_FORWARDING_COUNT;
+
+ l2fwd = table->entries;
+
+ /* First 5 entries define the forwarding rules */
+ for (i = 0; i < pdata->num_ports; i++) {
+ if (i == cpu)
+ continue;
+
+ sja1105_port_allow_traffic(l2fwd, i, cpu);
+ sja1105_port_allow_traffic(l2fwd, cpu, i);
+ }
+ /* Next 8 entries define VLAN PCP mapping from ingress to egress.
+ * Leave them unpopulated (implicitly 0) but present.
+ */
+ return 0;
+}
+
+static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv)
+{
+ struct sja1105_l2_forwarding_params_entry default_l2fwd_params = {
+ /* Use a single memory partition for all ingress queues */
+ .part_spc = { SJA1105_MAX_FRAME_MEMORY, 0, 0, 0, 0, 0, 0, 0 },
+ };
+ struct sja1105_table *table;
+
+ table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING_PARAMS];
+
+ table->entries = calloc(SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT;
+
+ /* This table only has a single entry */
+ ((struct sja1105_l2_forwarding_params_entry *)table->entries)[0] =
+ default_l2fwd_params;
+
+ return 0;
+}
+
+static int sja1105_init_general_params(struct sja1105_private *priv)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_general_params_entry default_general_params = {
+ /* No frame trapping */
+ .mac_fltres1 = 0x0,
+ .mac_flt1 = 0xffffffffffff,
+ .mac_fltres0 = 0x0,
+ .mac_flt0 = 0xffffffffffff,
+ .host_port = pdata->num_ports,
+ /* No mirroring => specify an out-of-range port value */
+ .mirr_port = pdata->num_ports,
+ /* No link-local trapping => specify an out-of-range port value
+ */
+ .casc_port = pdata->num_ports,
+ /* Force the switch to see all traffic as untagged. */
+ .tpid = ETH_P_SJA1105,
+ .tpid2 = ETH_P_SJA1105,
+ };
+ struct sja1105_table *table;
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+
+ table->entries = calloc(SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT;
+
+ /* This table only has a single entry */
+ ((struct sja1105_general_params_entry *)table->entries)[0] =
+ default_general_params;
+
+ return 0;
+}
+
+static void sja1105_setup_policer(struct sja1105_l2_policing_entry *policing,
+ int index, int mtu)
+{
+ policing[index].sharindx = index;
+ policing[index].smax = 65535; /* Burst size in bytes */
+ policing[index].rate = SJA1105_RATE_MBPS(1000);
+ policing[index].maxlen = mtu;
+ policing[index].partition = 0;
+}
+
+static int sja1105_init_l2_policing(struct sja1105_private *priv)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_l2_policing_entry *policing;
+ struct sja1105_table *table;
+ int cpu = pdata->cpu_port;
+ int i, j, k;
+
+ table = &priv->static_config.tables[BLK_IDX_L2_POLICING];
+
+ table->entries = calloc(SJA1105_MAX_L2_POLICING_COUNT,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_L2_POLICING_COUNT;
+
+ policing = table->entries;
+
+ /* k sweeps through all unicast policers (0-39).
+ * bcast sweeps through policers 40-44.
+ */
+ for (i = 0, k = 0; i < pdata->num_ports; i++) {
+ int bcast = (pdata->num_ports * SJA1105_NUM_TC) + i;
+ int mtu = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
+
+ if (i == cpu)
+ mtu += VLAN_HLEN;
+
+ for (j = 0; j < SJA1105_NUM_TC; j++, k++)
+ sja1105_setup_policer(policing, k, mtu);
+
+ /* Set up this port's policer for broadcast traffic */
+ sja1105_setup_policer(policing, bcast, mtu);
+ }
+ return 0;
+}
+
+static int sja1105_init_mac_settings(struct sja1105_private *priv)
+{
+ struct sja1105_mac_config_entry default_mac = {
+ /* Enable 1 priority queue on egress. */
+ .top = {0x1FF, 0, 0, 0, 0, 0, 0},
+ .base = {0x0, 0, 0, 0, 0, 0, 0, 0},
+ .enabled = {1, 0, 0, 0, 0, 0, 0, 0},
+ /* Will be overridden in sja1105_port_enable. */
+ .speed = priv->info->port_speed[SJA1105_SPEED_AUTO],
+ .egress = true,
+ .ingress = true,
+ };
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ struct sja1105_mac_config_entry *mac;
+ struct sja1105_table *table;
+ int port;
+
+ table = &priv->static_config.tables[BLK_IDX_MAC_CONFIG];
+
+ table->entries = calloc(pdata->num_ports,
+ table->ops->unpacked_entry_size);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = pdata->num_ports;
+
+ mac = table->entries;
+
+ for (port = 0; port < pdata->num_ports; port++) {
+ mac[port] = default_mac;
+ /* Internal VLAN (pvid) to apply to untagged ingress */
+ mac[port].vlanid = priv->pvid[port];
+ }
+
+ return 0;
+}
+
+static int sja1105_static_config_init(struct sja1105_private *priv)
+{
+ struct sja1105_static_config *config = &priv->static_config;
+ const struct sja1105_table_ops *static_ops = priv->info->static_ops;
+ u64 device_id = priv->info->device_id;
+ enum sja1105_blk_idx i;
+ int rc;
+
+ *config = (struct sja1105_static_config) {0};
+
+ /* Transfer static_ops array from priv into per-table ops
+ * for handier access
+ */
+ for (i = 0; i < BLK_IDX_MAX; i++)
+ config->tables[i].ops = &static_ops[i];
+
+ config->device_id = device_id;
+
+ /* Build initial static configuration, to be fixed up during runtime */
+ rc = sja1105_init_vlan(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_mac_settings(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_mii_settings(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_l2_forwarding(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_l2_forwarding_params(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_l2_policing(priv);
+ if (rc < 0)
+ return rc;
+ rc = sja1105_init_general_params(priv);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static void sja1105_static_config_free(struct sja1105_static_config *config)
+{
+ enum sja1105_blk_idx i;
+
+ for (i = 0; i < BLK_IDX_MAX; i++) {
+ if (config->tables[i].entry_count) {
+ free(config->tables[i].entries);
+ config->tables[i].entry_count = 0;
+ }
+ }
+}
+
+static void sja1105_cgu_idiv_packing(void *buf, struct sja1105_cgu_idiv *idiv,
+ enum packing_op op)
+{
+ const int size = 4;
+
+ sja1105_packing(buf, &idiv->clksrc, 28, 24, size, op);
+ sja1105_packing(buf, &idiv->autoblock, 11, 11, size, op);
+ sja1105_packing(buf, &idiv->idiv, 5, 2, size, op);
+ sja1105_packing(buf, &idiv->pd, 0, 0, size, op);
+}
+
+static int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port,
+ bool enabled, int factor)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1105_cgu_idiv idiv;
+
+ if (regs->cgu_idiv[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ if (enabled && factor != 1 && factor != 10)
+ return -ERANGE;
+
+ /* Payload for packed_buf */
+ idiv.clksrc = 0x0A; /* 25MHz */
+ idiv.autoblock = 1; /* Block clk automatically */
+ idiv.idiv = factor - 1; /* Divide by 1 or 10 */
+ idiv.pd = enabled ? 0 : 1; /* Power down? */
+ sja1105_cgu_idiv_packing(packed_buf, &idiv, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->cgu_idiv[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static void
+sja1105_cgu_mii_control_packing(void *buf, struct sja1105_cgu_mii_ctrl *cmd,
+ enum packing_op op)
+{
+ const int size = 4;
+
+ sja1105_packing(buf, &cmd->clksrc, 28, 24, size, op);
+ sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
+ sja1105_packing(buf, &cmd->pd, 0, 0, size, op);
+}
+
+static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
+ int port, sja1105_mii_role_t role)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cgu_mii_ctrl mii_tx_clk;
+ const int mac_clk_sources[] = {
+ CLKSRC_MII0_TX_CLK,
+ CLKSRC_MII1_TX_CLK,
+ CLKSRC_MII2_TX_CLK,
+ CLKSRC_MII3_TX_CLK,
+ CLKSRC_MII4_TX_CLK,
+ };
+ const int phy_clk_sources[] = {
+ CLKSRC_IDIV0,
+ CLKSRC_IDIV1,
+ CLKSRC_IDIV2,
+ CLKSRC_IDIV3,
+ CLKSRC_IDIV4,
+ };
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ int clksrc;
+
+ if (regs->mii_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ if (role == XMII_MAC)
+ clksrc = mac_clk_sources[port];
+ else
+ clksrc = phy_clk_sources[port];
+
+ /* Payload for packed_buf */
+ mii_tx_clk.clksrc = clksrc;
+ mii_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ mii_tx_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &mii_tx_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_tx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1105_cgu_mii_ctrl mii_rx_clk;
+ const int clk_sources[] = {
+ CLKSRC_MII0_RX_CLK,
+ CLKSRC_MII1_RX_CLK,
+ CLKSRC_MII2_RX_CLK,
+ CLKSRC_MII3_RX_CLK,
+ CLKSRC_MII4_RX_CLK,
+ };
+
+ if (regs->mii_rx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload for packed_buf */
+ mii_rx_clk.clksrc = clk_sources[port];
+ mii_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ mii_rx_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &mii_rx_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_rx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cgu_mii_ctrl mii_ext_tx_clk;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ const int clk_sources[] = {
+ CLKSRC_IDIV0,
+ CLKSRC_IDIV1,
+ CLKSRC_IDIV2,
+ CLKSRC_IDIV3,
+ CLKSRC_IDIV4,
+ };
+
+ if (regs->mii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload for packed_buf */
+ mii_ext_tx_clk.clksrc = clk_sources[port];
+ mii_ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ mii_ext_tx_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_tx_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_tx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cgu_mii_ctrl mii_ext_rx_clk;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ const int clk_sources[] = {
+ CLKSRC_IDIV0,
+ CLKSRC_IDIV1,
+ CLKSRC_IDIV2,
+ CLKSRC_IDIV3,
+ CLKSRC_IDIV4,
+ };
+
+ if (regs->mii_ext_rx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload for packed_buf */
+ mii_ext_rx_clk.clksrc = clk_sources[port];
+ mii_ext_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ mii_ext_rx_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_rx_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_rx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_mii_clocking_setup(struct sja1105_private *priv, int port,
+ sja1105_mii_role_t role)
+{
+ int rc;
+
+ rc = sja1105_cgu_idiv_config(priv, port, (role == XMII_PHY), 1);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_cgu_mii_tx_clk_config(priv, port, role);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_cgu_mii_rx_clk_config(priv, port);
+ if (rc < 0)
+ return rc;
+
+ if (role == XMII_PHY) {
+ rc = sja1105_cgu_mii_ext_tx_clk_config(priv, port);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_cgu_mii_ext_rx_clk_config(priv, port);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static void
+sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
+ enum packing_op op)
+{
+ const int size = 4;
+
+ sja1105_packing(buf, &cmd->pllclksrc, 28, 24, size, op);
+ sja1105_packing(buf, &cmd->msel, 23, 16, size, op);
+ sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
+ sja1105_packing(buf, &cmd->psel, 9, 8, size, op);
+ sja1105_packing(buf, &cmd->direct, 7, 7, size, op);
+ sja1105_packing(buf, &cmd->fbsel, 6, 6, size, op);
+ sja1105_packing(buf, &cmd->bypass, 1, 1, size, op);
+ sja1105_packing(buf, &cmd->pd, 0, 0, size, op);
+}
+
+static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
+ int port, u64 speed)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cgu_mii_ctrl txc;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ int clksrc;
+
+ if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
+ clksrc = CLKSRC_PLL0;
+ } else {
+ int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
+ CLKSRC_IDIV3, CLKSRC_IDIV4};
+ clksrc = clk_sources[port];
+ }
+
+ /* RGMII: 125MHz for 1000, 25MHz for 100, 2.5MHz for 10 */
+ txc.clksrc = clksrc;
+ /* Autoblock clk while changing clksrc */
+ txc.autoblock = 1;
+ /* Power Down off => enabled */
+ txc.pd = 0;
+ sja1105_cgu_mii_control_packing(packed_buf, &txc, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgmii_tx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+/* AGU */
+static void
+sja1105_cfg_pad_mii_packing(void *buf, struct sja1105_cfg_pad_mii *cmd,
+ enum packing_op op)
+{
+ const int size = 4;
+
+ sja1105_packing(buf, &cmd->d32_os, 28, 27, size, op);
+ sja1105_packing(buf, &cmd->d32_ih, 26, 26, size, op);
+ sja1105_packing(buf, &cmd->d32_ipud, 25, 24, size, op);
+ sja1105_packing(buf, &cmd->d10_os, 20, 19, size, op);
+ sja1105_packing(buf, &cmd->d10_ih, 18, 18, size, op);
+ sja1105_packing(buf, &cmd->d10_ipud, 17, 16, size, op);
+ sja1105_packing(buf, &cmd->ctrl_os, 12, 11, size, op);
+ sja1105_packing(buf, &cmd->ctrl_ih, 10, 10, size, op);
+ sja1105_packing(buf, &cmd->ctrl_ipud, 9, 8, size, op);
+ sja1105_packing(buf, &cmd->clk_os, 4, 3, size, op);
+ sja1105_packing(buf, &cmd->clk_ih, 2, 2, size, op);
+ sja1105_packing(buf, &cmd->clk_ipud, 1, 0, size, op);
+}
+
+static void
+sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+ enum packing_op op)
+{
+ const int size = SJA1105_SIZE_CGU_CMD;
+ u64 range = 4;
+
+ /* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
+ * 0 = 2.5MHz
+ * 1 = 25MHz
+ * 2 = 50MHz
+ * 3 = 125MHz
+ * 4 = Automatically determined by port speed.
+ * There's no point in defining a structure different than the one for
+ * SJA1105, so just hardcode the frequency range to automatic, just as
+ * before.
+ */
+ sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
+ sja1105_packing(buf, &cmd->rxc_delay, 25, 21, size, op);
+ sja1105_packing(buf, &range, 20, 18, size, op);
+ sja1105_packing(buf, &cmd->rxc_bypass, 17, 17, size, op);
+ sja1105_packing(buf, &cmd->rxc_pd, 16, 16, size, op);
+ sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
+ sja1105_packing(buf, &cmd->txc_delay, 9, 5, size, op);
+ sja1105_packing(buf, &range, 4, 2, size, op);
+ sja1105_packing(buf, &cmd->txc_bypass, 1, 1, size, op);
+ sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
+}
+
+static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
+ int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii pad_mii_tx = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+ if (regs->pad_mii_tx[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload */
+ pad_mii_tx.d32_os = 3; /* TXD[3:2] output stage: */
+ /* high noise/high speed */
+ pad_mii_tx.d10_os = 3; /* TXD[1:0] output stage: */
+ /* high noise/high speed */
+ pad_mii_tx.d32_ipud = 2; /* TXD[3:2] input stage: */
+ /* plain input (default) */
+ pad_mii_tx.d10_ipud = 2; /* TXD[1:0] input stage: */
+ /* plain input (default) */
+ pad_mii_tx.ctrl_os = 3; /* TX_CTL / TX_ER output stage */
+ pad_mii_tx.ctrl_ipud = 2; /* TX_CTL / TX_ER input stage (default) */
+ pad_mii_tx.clk_os = 3; /* TX_CLK output stage */
+ pad_mii_tx.clk_ih = 0; /* TX_CLK input hysteresis (default) */
+ pad_mii_tx.clk_ipud = 2; /* TX_CLK input stage (default) */
+ sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_tx, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_cfg_pad_rx_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii pad_mii_rx = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+ if (regs->pad_mii_rx[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload */
+ pad_mii_rx.d32_ih = 0; /* RXD[3:2] input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.d32_ipud = 2; /* RXD[3:2] input weak pull-up/down */
+ /* plain input (default) */
+ pad_mii_rx.d10_ih = 0; /* RXD[1:0] input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.d10_ipud = 2; /* RXD[1:0] input weak pull-up/down */
+ /* plain input (default) */
+ pad_mii_rx.ctrl_ih = 0; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+ /* input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.ctrl_ipud = 3; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+ /* input stage weak pull-up/down: */
+ /* pull-down */
+ pad_mii_rx.clk_os = 2; /* RX_CLK/RXC output stage: */
+ /* medium noise/fast speed (default) */
+ pad_mii_rx.clk_ih = 0; /* RX_CLK/RXC input hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.clk_ipud = 2; /* RX_CLK/RXC input pull-up/down: */
+ /* plain input (default) */
+ sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_rx, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_rx[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static void
+sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+ enum packing_op op)
+{
+ const int size = SJA1105_SIZE_CGU_CMD;
+
+ sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
+ sja1105_packing(buf, &cmd->rxc_delay, 14, 10, size, op);
+ sja1105_packing(buf, &cmd->rxc_bypass, 9, 9, size, op);
+ sja1105_packing(buf, &cmd->rxc_pd, 8, 8, size, op);
+ sja1105_packing(buf, &cmd->txc_stable_ovr, 7, 7, size, op);
+ sja1105_packing(buf, &cmd->txc_delay, 6, 2, size, op);
+ sja1105_packing(buf, &cmd->txc_bypass, 1, 1, size, op);
+ sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
+}
+
+/* Valid range in degrees is an integer between 73.8 and 101.7 */
+static u64 sja1105_rgmii_delay(u64 phase)
+{
+ /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
+ * To avoid floating point operations we'll multiply by 10
+ * and get 1 decimal point precision.
+ */
+ phase *= 10;
+ return (phase - 738) / 9;
+}
+
+static int sja1105pqrs_setup_rgmii_delay(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ int rc;
+
+ if (priv->rgmii_rx_delay[port])
+ pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+ if (priv->rgmii_tx_delay[port])
+ pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+
+ /* Stage 1: Turn the RGMII delay lines off. */
+ pad_mii_id.rxc_bypass = 1;
+ pad_mii_id.rxc_pd = 1;
+ pad_mii_id.txc_bypass = 1;
+ pad_mii_id.txc_pd = 1;
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+ if (rc < 0)
+ return rc;
+
+ /* Stage 2: Turn the RGMII delay lines on. */
+ if (priv->rgmii_rx_delay[port]) {
+ pad_mii_id.rxc_bypass = 0;
+ pad_mii_id.rxc_pd = 0;
+ }
+ if (priv->rgmii_tx_delay[port]) {
+ pad_mii_id.txc_bypass = 0;
+ pad_mii_id.txc_pd = 0;
+ }
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1110_setup_rgmii_delay(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+ pad_mii_id.rxc_pd = 1;
+ pad_mii_id.txc_pd = 1;
+
+ if (priv->rgmii_rx_delay[port]) {
+ pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+ /* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
+ pad_mii_id.rxc_bypass = 1;
+ pad_mii_id.rxc_pd = 0;
+ }
+
+ if (priv->rgmii_tx_delay[port]) {
+ pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+ pad_mii_id.txc_bypass = 1;
+ pad_mii_id.txc_pd = 0;
+ }
+
+ sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
+ sja1105_mii_role_t role)
+{
+ struct sja1105_mac_config_entry *mac;
+ struct udevice *dev = priv->dev;
+ u64 speed;
+ int rc;
+
+ mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+ speed = mac[port].speed;
+
+ if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
+ /* 1000Mbps, IDIV disabled (125 MHz) */
+ rc = sja1105_cgu_idiv_config(priv, port, false, 1);
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
+ /* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
+ rc = sja1105_cgu_idiv_config(priv, port, true, 1);
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
+ /* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
+ rc = sja1105_cgu_idiv_config(priv, port, true, 10);
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
+ /* Skip CGU configuration if there is no speed available
+ * (e.g. link is not established yet)
+ */
+ dev_dbg(dev, "Speed not available, skipping CGU config\n");
+ return 0;
+ } else {
+ rc = -EINVAL;
+ }
+
+ if (rc < 0) {
+ dev_err(dev, "Failed to configure idiv\n");
+ return rc;
+ }
+ rc = sja1105_cgu_rgmii_tx_clk_config(priv, port, speed);
+ if (rc < 0) {
+ dev_err(dev, "Failed to configure RGMII Tx clock\n");
+ return rc;
+ }
+ rc = sja1105_rgmii_cfg_pad_tx_config(priv, port);
+ if (rc < 0) {
+ dev_err(dev, "Failed to configure Tx pad registers\n");
+ return rc;
+ }
+
+ if (!priv->info->setup_rgmii_delay)
+ return 0;
+
+ return priv->info->setup_rgmii_delay(priv, port);
+}
+
+static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
+ int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1105_cgu_mii_ctrl ref_clk;
+ const int clk_sources[] = {
+ CLKSRC_MII0_TX_CLK,
+ CLKSRC_MII1_TX_CLK,
+ CLKSRC_MII2_TX_CLK,
+ CLKSRC_MII3_TX_CLK,
+ CLKSRC_MII4_TX_CLK,
+ };
+
+ if (regs->rmii_ref_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload for packed_buf */
+ ref_clk.clksrc = clk_sources[port];
+ ref_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ ref_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &ref_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ref_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cgu_mii_ctrl ext_tx_clk;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+ if (regs->rmii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Payload for packed_buf */
+ ext_tx_clk.clksrc = CLKSRC_PLL1;
+ ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+ ext_tx_clk.pd = 0; /* Power Down off => enabled */
+ sja1105_cgu_mii_control_packing(packed_buf, &ext_tx_clk, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ext_tx_clk[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1105_cgu_pll_ctrl pll = {0};
+ int rc;
+
+ if (regs->rmii_pll1 == SJA1105_RSV_ADDR)
+ return 0;
+
+ /* Step 1: PLL1 setup for 50Mhz */
+ pll.pllclksrc = 0xA;
+ pll.msel = 0x1;
+ pll.autoblock = 0x1;
+ pll.psel = 0x1;
+ pll.direct = 0x0;
+ pll.fbsel = 0x1;
+ pll.bypass = 0x0;
+ pll.pd = 0x1;
+
+ sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
+ SJA1105_SIZE_CGU_CMD);
+ if (rc < 0)
+ return rc;
+
+ /* Step 2: Enable PLL1 */
+ pll.pd = 0x0;
+
+ sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
+ SJA1105_SIZE_CGU_CMD);
+ return rc;
+}
+
+static int sja1105_rmii_clocking_setup(struct sja1105_private *priv, int port,
+ sja1105_mii_role_t role)
+{
+ int rc;
+
+ /* AH1601.pdf chapter 2.5.1. Sources */
+ if (role == XMII_MAC) {
+ /* Configure and enable PLL1 for 50Mhz output */
+ rc = sja1105_cgu_rmii_pll_config(priv);
+ if (rc < 0)
+ return rc;
+ }
+ /* Disable IDIV for this port */
+ rc = sja1105_cgu_idiv_config(priv, port, false, 1);
+ if (rc < 0)
+ return rc;
+ /* Source to sink mappings */
+ rc = sja1105_cgu_rmii_ref_clk_config(priv, port);
+ if (rc < 0)
+ return rc;
+ if (role == XMII_MAC) {
+ rc = sja1105_cgu_rmii_ext_tx_clk_config(priv, port);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int sja1105_pcs_read(struct sja1105_private *priv, int addr,
+ int devad, int regnum)
+{
+ return priv->mdio_pcs->read(priv->mdio_pcs, addr, devad, regnum);
+}
+
+static int sja1105_pcs_write(struct sja1105_private *priv, int addr,
+ int devad, int regnum, u16 val)
+{
+ return priv->mdio_pcs->write(priv->mdio_pcs, addr, devad, regnum, val);
+}
+
+/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
+ * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
+ * normal non-inverted behavior, the TX lane polarity must be inverted in the
+ * PCS, via the DIGITAL_CONTROL_2 register.
+ */
+static int sja1105_pma_config(struct sja1105_private *priv, int port)
+{
+ return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ DW_VR_MII_DIG_CTRL2,
+ DW_VR_MII_DIG_CTRL2_TX_POL_INV);
+}
+
+static int sja1110_pma_config(struct sja1105_private *priv, int port)
+{
+ u16 txpll_fbdiv = 0x19, txpll_refdiv = 0x1;
+ u16 rxpll_fbdiv = 0x19, rxpll_refdiv = 0x1;
+ u16 rx_cdr_ctle = 0x212a;
+ u16 val;
+ int rc;
+
+ /* Program TX PLL feedback divider and reference divider settings for
+ * correct oscillation frequency.
+ */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
+ SJA1110_TXPLL_FBDIV(txpll_fbdiv));
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
+ SJA1110_TXPLL_REFDIV(txpll_refdiv));
+ if (rc < 0)
+ return rc;
+
+ /* Program transmitter amplitude and disable amplitude trimming */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_LANE_DRIVER1_0, SJA1110_TXDRV(0x5));
+ if (rc < 0)
+ return rc;
+
+ val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_LANE_DRIVER2_0, val);
+ if (rc < 0)
+ return rc;
+
+ val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_LANE_DRIVER2_1, val);
+ if (rc < 0)
+ return rc;
+
+ /* Enable input and output resistor terminations for low BER. */
+ val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
+ SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
+ SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_LANE_TRIM,
+ val);
+ if (rc < 0)
+ return rc;
+
+ /* Select PCS as transmitter data source. */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_LANE_DATAPATH_1, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Program RX PLL feedback divider and reference divider for correct
+ * oscillation frequency.
+ */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
+ SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
+ SJA1110_RXPLL_REFDIV(rxpll_refdiv));
+ if (rc < 0)
+ return rc;
+
+ /* Program threshold for receiver signal detector.
+ * Enable control of RXPLL by receiver signal detector to disable RXPLL
+ * when an input signal is not present.
+ */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_RX_DATA_DETECT, 0x0005);
+ if (rc < 0)
+ return rc;
+
+ /* Enable TX and RX PLLs and circuits.
+ * Release reset of PMA to enable data flow to/from PCS.
+ */
+ rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2,
+ SJA1110_POWERDOWN_ENABLE);
+ if (rc < 0)
+ return rc;
+
+ val = rc & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
+ SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
+ SJA1110_RESET_SER | SJA1110_RESET_DES);
+ val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+ SJA1110_POWERDOWN_ENABLE, val);
+ if (rc < 0)
+ return rc;
+
+ /* Program continuous-time linear equalizer (CTLE) settings. */
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
+ rx_cdr_ctle);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int sja1105_xpcs_config_aneg_c37_sgmii(struct sja1105_private *priv,
+ int port)
+{
+ int rc;
+
+ rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
+ if (rc < 0)
+ return rc;
+ rc &= ~MDIO_AN_CTRL1_ENABLE;
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
+ rc);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
+ if (rc < 0)
+ return rc;
+
+ rc &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
+ rc |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
+ DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
+ DW_VR_MII_PCS_MODE_MASK);
+ rc |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
+ DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
+ DW_VR_MII_TX_CONFIG_MASK);
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
+ rc);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+ if (rc < 0)
+ return rc;
+
+ if (priv->xpcs_cfg[port].inband_an)
+ rc |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ else
+ rc &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+
+ rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
+ rc);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
+ if (rc < 0)
+ return rc;
+
+ if (priv->xpcs_cfg[port].inband_an)
+ rc |= MDIO_AN_CTRL1_ENABLE;
+ else
+ rc &= ~MDIO_AN_CTRL1_ENABLE;
+
+ return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, rc);
+}
+
+static int sja1105_xpcs_link_up_sgmii(struct sja1105_private *priv, int port)
+{
+ int val = BMCR_FULLDPLX;
+
+ if (priv->xpcs_cfg[port].inband_an)
+ return 0;
+
+ switch (priv->xpcs_cfg[port].speed) {
+ case SPEED_1000:
+ val = BMCR_SPEED1000;
+ break;
+ case SPEED_100:
+ val = BMCR_SPEED100;
+ break;
+ case SPEED_10:
+ val = BMCR_SPEED10;
+ break;
+ default:
+ dev_err(priv->dev, "Invalid PCS speed %d\n",
+ priv->xpcs_cfg[port].speed);
+ return -EINVAL;
+ }
+
+ return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, val);
+}
+
+static int sja1105_sgmii_setup(struct sja1105_private *priv, int port)
+{
+ int rc;
+
+ rc = sja1105_xpcs_config_aneg_c37_sgmii(priv, port);
+ if (rc)
+ return rc;
+
+ rc = sja1105_xpcs_link_up_sgmii(priv, port);
+ if (rc)
+ return rc;
+
+ return priv->info->pma_config(priv, port);
+}
+
+static int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
+{
+ struct sja1105_xmii_params_entry *mii;
+ sja1105_phy_interface_t phy_mode;
+ sja1105_mii_role_t role;
+ int rc;
+
+ mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+
+ /* RGMII etc */
+ phy_mode = mii->xmii_mode[port];
+ /* MAC or PHY, for applicable types (not RGMII) */
+ role = mii->phy_mac[port];
+
+ switch (phy_mode) {
+ case XMII_MODE_MII:
+ rc = sja1105_mii_clocking_setup(priv, port, role);
+ break;
+ case XMII_MODE_RMII:
+ rc = sja1105_rmii_clocking_setup(priv, port, role);
+ break;
+ case XMII_MODE_RGMII:
+ rc = sja1105_rgmii_clocking_setup(priv, port, role);
+ break;
+ case XMII_MODE_SGMII:
+ rc = sja1105_sgmii_setup(priv, port);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (rc)
+ return rc;
+
+ /* Internally pull down the RX_DV/CRS_DV/RX_CTL and RX_ER inputs */
+ return sja1105_cfg_pad_rx_config(priv, port);
+}
+
+static int sja1105_clocking_setup(struct sja1105_private *priv)
+{
+ struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+ int port, rc;
+
+ for (port = 0; port < pdata->num_ports; port++) {
+ rc = sja1105_clocking_setup_port(priv, port);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int sja1105_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
+{
+ u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+ struct sja1105_private *priv = bus->priv;
+ const int size = SJA1105_SIZE_MDIO_CMD;
+ u64 addr, tmp;
+ int rc;
+
+ if (mmd == MDIO_DEVAD_NONE)
+ return -ENODEV;
+
+ if (!priv->info->supports_sgmii[phy])
+ return -ENODEV;
+
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+ return 0xffff;
+
+ rc = sja1105_xfer_buf(priv, SPI_READ, addr, packed_buf, size);
+ if (rc < 0)
+ return rc;
+
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
+
+ return tmp & 0xffff;
+}
+
+static int sja1105_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
+ int reg, u16 val)
+{
+ u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+ struct sja1105_private *priv = bus->priv;
+ const int size = SJA1105_SIZE_MDIO_CMD;
+ u64 addr, tmp;
+
+ if (mmd == MDIO_DEVAD_NONE)
+ return -ENODEV;
+
+ if (!priv->info->supports_sgmii[phy])
+ return -ENODEV;
+
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+ tmp = val;
+
+ if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+ return -ENODEV;
+
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, addr, packed_buf, size);
+}
+
+static int sja1110_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
+{
+ struct sja1105_private *priv = bus->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+ const int size = SJA1105_SIZE_MDIO_CMD;
+ int offset, bank;
+ u64 addr, tmp;
+ int rc;
+
+ if (mmd == MDIO_DEVAD_NONE)
+ return -ENODEV;
+
+ if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+ return -ENODEV;
+
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ bank = addr >> 8;
+ offset = addr & GENMASK(7, 0);
+
+ /* This addressing scheme reserves register 0xff for the bank address
+ * register, so that can never be addressed.
+ */
+ if (offset == 0xff)
+ return -ENODEV;
+
+ tmp = bank;
+
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+ rc = sja1105_xfer_buf(priv, SPI_WRITE,
+ regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+ packed_buf, size);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_xfer_buf(priv, SPI_READ, regs->pcs_base[phy] + offset,
+ packed_buf, size);
+ if (rc < 0)
+ return rc;
+
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
+
+ return tmp & 0xffff;
+}
+
+static int sja1110_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
+ int reg, u16 val)
+{
+ struct sja1105_private *priv = bus->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+ const int size = SJA1105_SIZE_MDIO_CMD;
+ int offset, bank;
+ u64 addr, tmp;
+ int rc;
+
+ if (mmd == MDIO_DEVAD_NONE)
+ return -ENODEV;
+
+ if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+ return -ENODEV;
+
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ bank = addr >> 8;
+ offset = addr & GENMASK(7, 0);
+
+ /* This addressing scheme reserves register 0xff for the bank address
+ * register, so that can never be addressed.
+ */
+ if (offset == 0xff)
+ return -ENODEV;
+
+ tmp = bank;
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+ rc = sja1105_xfer_buf(priv, SPI_WRITE,
+ regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+ packed_buf, size);
+ if (rc < 0)
+ return rc;
+
+ tmp = val;
+ sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
+ packed_buf, size);
+}
+
+static int sja1105_mdiobus_register(struct sja1105_private *priv)
+{
+ struct udevice *dev = priv->dev;
+ struct mii_dev *bus;
+ int rc;
+
+ if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write)
+ return 0;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return -ENOMEM;
+
+ snprintf(bus->name, MDIO_NAME_LEN, "%s-pcs", dev->name);
+ bus->read = priv->info->pcs_mdio_read;
+ bus->write = priv->info->pcs_mdio_write;
+ bus->priv = priv;
+
+ rc = mdio_register(bus);
+ if (rc) {
+ mdio_free(bus);
+ return rc;
+ }
+
+ priv->mdio_pcs = bus;
+
+ return 0;
+}
+
+static void sja1105_mdiobus_unregister(struct sja1105_private *priv)
+{
+ if (!priv->mdio_pcs)
+ return;
+
+ mdio_unregister(priv->mdio_pcs);
+ mdio_free(priv->mdio_pcs);
+}
+
+static const struct sja1105_regs sja1105et_regs = {
+ .device_id = 0x0,
+ .prod_id = 0x100BC3,
+ .status = 0x1,
+ .port_control = 0x11,
+ .config = 0x020000,
+ .rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
+ .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+ .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
+ .rmii_pll1 = 0x10000A,
+ .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
+ /* UM10944.pdf, Table 78, CGU Register overview */
+ .mii_tx_clk = {0x100013, 0x10001A, 0x100021, 0x100028, 0x10002F},
+ .mii_rx_clk = {0x100014, 0x10001B, 0x100022, 0x100029, 0x100030},
+ .mii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+ .mii_ext_rx_clk = {0x100019, 0x100020, 0x100027, 0x10002E, 0x100035},
+ .rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032},
+ .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031},
+ .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+};
+
+static const struct sja1105_regs sja1105pqrs_regs = {
+ .device_id = 0x0,
+ .prod_id = 0x100BC3,
+ .status = 0x1,
+ .port_control = 0x12,
+ .config = 0x020000,
+ .rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
+ .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+ .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
+ .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
+ .rmii_pll1 = 0x10000A,
+ .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
+ /* UM11040.pdf, Table 114 */
+ .mii_tx_clk = {0x100013, 0x100019, 0x10001F, 0x100025, 0x10002B},
+ .mii_rx_clk = {0x100014, 0x10001A, 0x100020, 0x100026, 0x10002C},
+ .mii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
+ .mii_ext_rx_clk = {0x100018, 0x10001E, 0x100024, 0x10002A, 0x100030},
+ .rgmii_tx_clk = {0x100016, 0x10001C, 0x100022, 0x100028, 0x10002E},
+ .rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D},
+ .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
+};
+
+static const struct sja1105_regs sja1110_regs = {
+ .device_id = SJA1110_SPI_ADDR(0x0),
+ .prod_id = SJA1110_ACU_ADDR(0xf00),
+ .status = SJA1110_SPI_ADDR(0x4),
+ .port_control = SJA1110_SPI_ADDR(0x50), /* actually INHIB_TX */
+ .config = 0x020000,
+ .rgu = SJA1110_RGU_ADDR(0x100), /* Reset Control Register 0 */
+ /* Ports 2 and 3 are capable of xMII, but there isn't anything to
+ * configure in the CGU/ACU for them.
+ */
+ .pad_mii_tx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .pad_mii_rx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .pad_mii_id = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1110_ACU_ADDR(0x18), SJA1110_ACU_ADDR(0x28),
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .rmii_pll1 = SJA1105_RSV_ADDR,
+ .cgu_idiv = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_ext_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rgmii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rmii_ref_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rmii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+};
+
+enum sja1105_switch_id {
+ SJA1105E = 0,
+ SJA1105T,
+ SJA1105P,
+ SJA1105Q,
+ SJA1105R,
+ SJA1105S,
+ SJA1110A,
+ SJA1110B,
+ SJA1110C,
+ SJA1110D,
+ SJA1105_MAX_SWITCH_ID,
+};
+
+static const struct sja1105_info sja1105_info[] = {
+ [SJA1105E] = {
+ .device_id = SJA1105E_DEVICE_ID,
+ .part_no = SJA1105ET_PART_NO,
+ .static_ops = sja1105et_table_ops,
+ .reset_cmd = sja1105et_reset_cmd,
+ .regs = &sja1105et_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .name = "SJA1105E",
+ },
+ [SJA1105T] = {
+ .device_id = SJA1105T_DEVICE_ID,
+ .part_no = SJA1105ET_PART_NO,
+ .static_ops = sja1105et_table_ops,
+ .reset_cmd = sja1105et_reset_cmd,
+ .regs = &sja1105et_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .name = "SJA1105T",
+ },
+ [SJA1105P] = {
+ .device_id = SJA1105PR_DEVICE_ID,
+ .part_no = SJA1105P_PART_NO,
+ .static_ops = sja1105pqrs_table_ops,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
+ .reset_cmd = sja1105pqrs_reset_cmd,
+ .regs = &sja1105pqrs_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .name = "SJA1105P",
+ },
+ [SJA1105Q] = {
+ .device_id = SJA1105QS_DEVICE_ID,
+ .part_no = SJA1105Q_PART_NO,
+ .static_ops = sja1105pqrs_table_ops,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
+ .reset_cmd = sja1105pqrs_reset_cmd,
+ .regs = &sja1105pqrs_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .name = "SJA1105Q",
+ },
+ [SJA1105R] = {
+ .device_id = SJA1105PR_DEVICE_ID,
+ .part_no = SJA1105R_PART_NO,
+ .static_ops = sja1105pqrs_table_ops,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
+ .reset_cmd = sja1105pqrs_reset_cmd,
+ .regs = &sja1105pqrs_regs,
+ .pcs_mdio_read = sja1105_pcs_mdio_read,
+ .pcs_mdio_write = sja1105_pcs_mdio_write,
+ .pma_config = sja1105_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .supports_sgmii = {false, false, false, false, true},
+ .name = "SJA1105R",
+ },
+ [SJA1105S] = {
+ .device_id = SJA1105QS_DEVICE_ID,
+ .part_no = SJA1105S_PART_NO,
+ .static_ops = sja1105pqrs_table_ops,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
+ .reset_cmd = sja1105pqrs_reset_cmd,
+ .regs = &sja1105pqrs_regs,
+ .pcs_mdio_read = sja1105_pcs_mdio_read,
+ .pcs_mdio_write = sja1105_pcs_mdio_write,
+ .pma_config = sja1105_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .supports_sgmii = {false, false, false, false, true},
+ .name = "SJA1105S",
+ },
+ [SJA1110A] = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110A_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .regs = &sja1110_regs,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .pma_config = sja1110_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, true, true, true},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, true, true, true, true,
+ false, false, false, false, false, false},
+ .name = "SJA1110A",
+ },
+ [SJA1110B] = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110B_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .regs = &sja1110_regs,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .pma_config = sja1110_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, true, true, false},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, false, false, true, true,
+ false, false, false, false, false, false},
+ .name = "SJA1110B",
+ },
+ [SJA1110C] = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110C_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .regs = &sja1110_regs,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .pma_config = sja1110_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, false, false, false},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, false, false, false, true,
+ false, false, false, false, false, false},
+ .name = "SJA1110C",
+ },
+ [SJA1110D] = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110D_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .regs = &sja1110_regs,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .pma_config = sja1110_pma_config,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ },
+ .supports_mii = {true, false, true, false, false,
+ true, true, true, false, false, false},
+ .supports_rmii = {false, false, true, false, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, false, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, true, true, true, true,
+ false, false, false, false, false, false},
+ .name = "SJA1110D",
+ },
+};
+
+struct sja1105_status {
+ u64 configs;
+ u64 crcchkl;
+ u64 ids;
+ u64 crcchkg;
+};
+
+static void sja1105_status_unpack(void *buf, struct sja1105_status *status)
+{
+ sja1105_packing(buf, &status->configs, 31, 31, 4, UNPACK);
+ sja1105_packing(buf, &status->crcchkl, 30, 30, 4, UNPACK);
+ sja1105_packing(buf, &status->ids, 29, 29, 4, UNPACK);
+ sja1105_packing(buf, &status->crcchkg, 28, 28, 4, UNPACK);
+}
+
+static int sja1105_status_get(struct sja1105_private *priv,
+ struct sja1105_status *status)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[4];
+ int rc;
+
+ rc = sja1105_xfer_buf(priv, SPI_READ, regs->status, packed_buf, 4);
+ if (rc < 0)
+ return rc;
+
+ sja1105_status_unpack(packed_buf, status);
+
+ return 0;
+}
+
+/* Not const because unpacking priv->static_config into buffers and preparing
+ * for upload requires the recalculation of table CRCs and updating the
+ * structures with these.
+ */
+static int
+static_config_buf_prepare_for_upload(struct sja1105_private *priv,
+ void *config_buf, int buf_len)
+{
+ struct sja1105_static_config *config = &priv->static_config;
+ struct sja1105_table_header final_header;
+ char *final_header_ptr;
+ int crc_len;
+
+ /* Write Device ID and config tables to config_buf */
+ sja1105_static_config_pack(config_buf, config);
+ /* Recalculate CRC of the last header (right now 0xDEADBEEF).
+ * Don't include the CRC field itself.
+ */
+ crc_len = buf_len - 4;
+ /* Read the whole table header */
+ final_header_ptr = config_buf + buf_len - SJA1105_SIZE_TABLE_HEADER;
+ sja1105_table_header_packing(final_header_ptr, &final_header, UNPACK);
+ /* Modify */
+ final_header.crc = sja1105_crc32(config_buf, crc_len);
+ /* Rewrite */
+ sja1105_table_header_packing(final_header_ptr, &final_header, PACK);
+
+ return 0;
+}
+
+static int sja1105_static_config_upload(struct sja1105_private *priv)
+{
+ struct sja1105_static_config *config = &priv->static_config;
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_status status;
+ u8 *config_buf;
+ int buf_len;
+ int rc;
+
+ buf_len = sja1105_static_config_get_length(config);
+ config_buf = calloc(buf_len, sizeof(char));
+ if (!config_buf)
+ return -ENOMEM;
+
+ rc = static_config_buf_prepare_for_upload(priv, config_buf, buf_len);
+ if (rc < 0) {
+ printf("Invalid config, cannot upload\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Put the SJA1105 in programming mode */
+ rc = priv->info->reset_cmd(priv);
+ if (rc < 0) {
+ printf("Failed to reset switch\n");
+ goto out;
+ }
+ /* Wait for the switch to come out of reset */
+ udelay(1000);
+ /* Upload the static config to the device */
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->config,
+ config_buf, buf_len);
+ if (rc < 0) {
+ printf("Failed to upload config\n");
+ goto out;
+ }
+ /* Check that SJA1105 responded well to the config upload */
+ rc = sja1105_status_get(priv, &status);
+ if (rc < 0)
+ goto out;
+
+ if (status.ids == 1) {
+ printf("Mismatch between hardware and static config device id. "
+ "Wrote 0x%llx, wants 0x%llx\n",
+ config->device_id, priv->info->device_id);
+ rc = -EIO;
+ goto out;
+ }
+ if (status.crcchkl == 1 || status.crcchkg == 1) {
+ printf("Switch reported invalid CRC on static config\n");
+ rc = -EIO;
+ goto out;
+ }
+ if (status.configs == 0) {
+ printf("Switch reported that config is invalid\n");
+ rc = -EIO;
+ goto out;
+ }
+
+out:
+ free(config_buf);
+ return rc;
+}
+
+static int sja1105_static_config_reload(struct sja1105_private *priv)
+{
+ int rc;
+
+ rc = sja1105_static_config_upload(priv);
+ if (rc < 0) {
+ printf("Failed to load static config: %d\n", rc);
+ return rc;
+ }
+
+ /* Configure the CGU (PHY link modes and speeds) */
+ rc = sja1105_clocking_setup(priv);
+ if (rc < 0) {
+ printf("Failed to configure MII clocking: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int sja1105_port_probe(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ struct sja1105_private *priv = dev_get_priv(dev);
+ ofnode node = dsa_port_get_ofnode(dev, port);
+ phy_interface_t phy_mode = phy->interface;
+
+ priv->xpcs_cfg[port].inband_an = ofnode_eth_uses_inband_aneg(node);
+
+ if (phy_mode == PHY_INTERFACE_MODE_MII ||
+ phy_mode == PHY_INTERFACE_MODE_RMII) {
+ phy->supported &= PHY_BASIC_FEATURES;
+ phy->advertising &= PHY_BASIC_FEATURES;
+ } else {
+ phy->supported &= PHY_GBIT_FEATURES;
+ phy->advertising &= PHY_GBIT_FEATURES;
+ }
+
+ return phy_config(phy);
+}
+
+static int sja1105_port_enable(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ struct sja1105_private *priv = dev_get_priv(dev);
+ phy_interface_t phy_mode = phy->interface;
+ struct sja1105_xmii_params_entry *mii;
+ struct sja1105_mac_config_entry *mac;
+ int rc;
+
+ rc = phy_startup(phy);
+ if (rc)
+ return rc;
+
+ mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+ mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+
+ switch (phy_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ if (!priv->info->supports_mii[port])
+ goto unsupported;
+
+ mii->xmii_mode[port] = XMII_MODE_MII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (!priv->info->supports_rmii[port])
+ goto unsupported;
+
+ mii->xmii_mode[port] = XMII_MODE_RMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!priv->info->supports_rgmii[port])
+ goto unsupported;
+
+ mii->xmii_mode[port] = XMII_MODE_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ if (!priv->info->supports_sgmii[port])
+ goto unsupported;
+
+ mii->xmii_mode[port] = XMII_MODE_SGMII;
+ mii->special[port] = true;
+ break;
+unsupported:
+ default:
+ dev_err(dev, "Unsupported PHY mode %d on port %d!\n",
+ phy_mode, port);
+ return -EINVAL;
+ }
+
+ /* RevMII, RevRMII not supported */
+ mii->phy_mac[port] = XMII_MAC;
+
+ /* Let the PHY handle the RGMII delays, if present. */
+ if (phy->phy_id == PHY_FIXED_ID) {
+ if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+ priv->rgmii_rx_delay[port] = true;
+
+ if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+ priv->rgmii_tx_delay[port] = true;
+
+ if ((priv->rgmii_rx_delay[port] ||
+ priv->rgmii_tx_delay[port]) &&
+ !priv->info->setup_rgmii_delay) {
+ printf("Chip does not support internal RGMII delays\n");
+ return -EINVAL;
+ }
+ }
+
+ if (mii->xmii_mode[port] == XMII_MODE_SGMII) {
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+ priv->xpcs_cfg[port].speed = phy->speed;
+ } else if (phy->speed == SPEED_1000) {
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+ } else if (phy->speed == SPEED_100) {
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
+ } else if (phy->speed == SPEED_10) {
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_10MBPS];
+ } else {
+ printf("Invalid PHY speed %d on port %d\n", phy->speed, port);
+ return -EINVAL;
+ }
+
+ return sja1105_static_config_reload(priv);
+}
+
+static void sja1105_port_disable(struct udevice *dev, int port,
+ struct phy_device *phy)
+{
+ phy_shutdown(phy);
+}
+
+static int sja1105_xmit(struct udevice *dev, int port, void *packet, int length)
+{
+ struct sja1105_private *priv = dev_get_priv(dev);
+ u8 *from = (u8 *)packet + VLAN_HLEN;
+ struct vlan_ethhdr *hdr = packet;
+ u8 *dest = (u8 *)packet;
+
+ memmove(dest, from, 2 * ETH_ALEN);
+ hdr->h_vlan_proto = htons(ETH_P_SJA1105);
+ hdr->h_vlan_TCI = htons(priv->pvid[port]);
+
+ return 0;
+}
+
+static int sja1105_rcv(struct udevice *dev, int *port, void *packet, int length)
+{
+ struct vlan_ethhdr *hdr = packet;
+ u8 *dest = packet + VLAN_HLEN;
+ u8 *from = packet;
+
+ if (ntohs(hdr->h_vlan_proto) != ETH_P_SJA1105)
+ return -EINVAL;
+
+ *port = ntohs(hdr->h_vlan_TCI) & DSA_8021Q_PORT_MASK;
+ memmove(dest, from, 2 * ETH_ALEN);
+
+ return 0;
+}
+
+static const struct dsa_ops sja1105_dsa_ops = {
+ .port_probe = sja1105_port_probe,
+ .port_enable = sja1105_port_enable,
+ .port_disable = sja1105_port_disable,
+ .xmit = sja1105_xmit,
+ .rcv = sja1105_rcv,
+};
+
+static int sja1105_init(struct sja1105_private *priv)
+{
+ int rc;
+
+ rc = sja1105_static_config_init(priv);
+ if (rc) {
+ printf("Failed to initialize static config: %d\n", rc);
+ return rc;
+ }
+
+ rc = sja1105_mdiobus_register(priv);
+ if (rc) {
+ printf("Failed to register MDIO bus: %d\n", rc);
+ goto err_mdiobus_register;
+ }
+
+ return 0;
+
+err_mdiobus_register:
+ sja1105_static_config_free(&priv->static_config);
+
+ return rc;
+}
+
+static int sja1105_check_device_id(struct sja1105_private *priv)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ u8 packed_buf[SJA1105_SIZE_DEVICE_ID] = {0};
+ enum sja1105_switch_id id;
+ u64 device_id;
+ u64 part_no;
+ int rc;
+
+ rc = sja1105_xfer_buf(priv, SPI_READ, regs->device_id, packed_buf,
+ SJA1105_SIZE_DEVICE_ID);
+ if (rc < 0)
+ return rc;
+
+ sja1105_packing(packed_buf, &device_id, 31, 0, SJA1105_SIZE_DEVICE_ID,
+ UNPACK);
+
+ if (device_id != priv->info->device_id) {
+ printf("Expected device ID 0x%llx but read 0x%llx\n",
+ priv->info->device_id, device_id);
+ return -ENODEV;
+ }
+
+ rc = sja1105_xfer_buf(priv, SPI_READ, regs->prod_id, packed_buf,
+ SJA1105_SIZE_DEVICE_ID);
+ if (rc < 0)
+ return rc;
+
+ sja1105_packing(packed_buf, &part_no, 19, 4, SJA1105_SIZE_DEVICE_ID,
+ UNPACK);
+
+ for (id = 0; id < SJA1105_MAX_SWITCH_ID; id++) {
+ const struct sja1105_info *info = &sja1105_info[id];
+
+ /* Is what's been probed in our match table at all? */
+ if (info->device_id != device_id || info->part_no != part_no)
+ continue;
+
+ /* But is it what's in the device tree? */
+ if (priv->info->device_id != device_id ||
+ priv->info->part_no != part_no) {
+ printf("Device tree specifies chip %s but found %s, please fix it!\n",
+ priv->info->name, info->name);
+ /* It isn't. No problem, pick that up. */
+ priv->info = info;
+ }
+
+ return 0;
+ }
+
+ printf("Unexpected {device ID, part number}: 0x%llx 0x%llx\n",
+ device_id, part_no);
+
+ return -ENODEV;
+}
+
+static int sja1105_probe(struct udevice *dev)
+{
+ enum sja1105_switch_id id = dev_get_driver_data(dev);
+ struct sja1105_private *priv = dev_get_priv(dev);
+ int rc;
+
+ if (ofnode_valid(dev_ofnode(dev)) &&
+ !ofnode_is_available(dev_ofnode(dev))) {
+ dev_dbg(dev, "switch disabled\n");
+ return -ENODEV;
+ }
+
+ priv->info = &sja1105_info[id];
+ priv->dev = dev;
+
+ rc = sja1105_check_device_id(priv);
+ if (rc < 0) {
+ dev_err(dev, "Device ID check failed: %d\n", rc);
+ return rc;
+ }
+
+ dsa_set_tagging(dev, VLAN_HLEN, 0);
+
+ return sja1105_init(priv);
+}
+
+static int sja1105_remove(struct udevice *dev)
+{
+ struct sja1105_private *priv = dev_get_priv(dev);
+
+ sja1105_mdiobus_unregister(priv);
+ sja1105_static_config_free(&priv->static_config);
+
+ return 0;
+}
+
+static const struct udevice_id sja1105_ids[] = {
+ { .compatible = "nxp,sja1105e", .data = SJA1105E },
+ { .compatible = "nxp,sja1105t", .data = SJA1105T },
+ { .compatible = "nxp,sja1105p", .data = SJA1105P },
+ { .compatible = "nxp,sja1105q", .data = SJA1105Q },
+ { .compatible = "nxp,sja1105r", .data = SJA1105R },
+ { .compatible = "nxp,sja1105s", .data = SJA1105S },
+ { .compatible = "nxp,sja1110a", .data = SJA1110A },
+ { .compatible = "nxp,sja1110b", .data = SJA1110B },
+ { .compatible = "nxp,sja1110c", .data = SJA1110C },
+ { .compatible = "nxp,sja1110d", .data = SJA1110D },
+ { }
+};
+
+U_BOOT_DRIVER(sja1105) = {
+ .name = "sja1105",
+ .id = UCLASS_DSA,
+ .of_match = sja1105_ids,
+ .probe = sja1105_probe,
+ .remove = sja1105_remove,
+ .ops = &sja1105_dsa_ops,
+ .priv_auto = sizeof(struct sja1105_private),
+};
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 0ce97656715..beca886b256 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -156,6 +156,19 @@ static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int join)
return 0;
}
+static int __maybe_unused tsec_set_promisc(struct udevice *dev, bool enable)
+{
+ struct tsec_private *priv = dev_get_priv(dev);
+ struct tsec __iomem *regs = priv->regs;
+
+ if (enable)
+ setbits_be32(&regs->rctrl, RCTRL_PROM);
+ else
+ clrbits_be32(&regs->rctrl, RCTRL_PROM);
+
+ return 0;
+}
+
/*
* Initialized required registers to appropriate values, zeroing
* those we don't care about (unless zero is bad, in which case,
@@ -186,8 +199,6 @@ static void init_registers(struct tsec __iomem *regs)
out_be32(&regs->hash.gaddr6, 0);
out_be32(&regs->hash.gaddr7, 0);
- out_be32(&regs->rctrl, 0x00000000);
-
/* Init RMON mib registers */
memset((void *)&regs->rmon, 0, sizeof(regs->rmon));
@@ -432,7 +443,7 @@ static void tsec_halt(struct udevice *dev)
* of the eTSEC port initialization sequence,
* the eTSEC Rx logic may not be properly initialized.
*/
-void redundant_init(struct tsec_private *priv)
+static void redundant_init(struct tsec_private *priv)
{
struct tsec __iomem *regs = priv->regs;
uint t, count = 0;
@@ -454,7 +465,7 @@ void redundant_init(struct tsec_private *priv)
0x71, 0x72};
/* Enable promiscuous mode */
- setbits_be32(&regs->rctrl, 0x8);
+ setbits_be32(&regs->rctrl, RCTRL_PROM);
/* Enable loopback mode */
setbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
/* Enable transmit and receive */
@@ -506,7 +517,7 @@ void redundant_init(struct tsec_private *priv)
if (fail)
panic("eTSEC init fail!\n");
/* Disable promiscuous mode */
- clrbits_be32(&regs->rctrl, 0x8);
+ clrbits_be32(&regs->rctrl, RCTRL_PROM);
/* Disable loopback mode */
clrbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
}
@@ -932,6 +943,7 @@ static const struct eth_ops tsec_ops = {
.free_pkt = tsec_free_pkt,
.stop = tsec_halt,
.mcast = tsec_mcast_addr,
+ .set_promisc = tsec_set_promisc,
};
static struct tsec_data etsec2_data = {
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index cc139af6cb5..42f8cb6be0d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -19,6 +19,12 @@ config DM_PCI_COMPAT
measure when porting a board to use driver model for PCI. Once the
board is fully supported, this option should be disabled.
+config SYS_PCI_64BIT
+ bool "Enable 64-bit PCI resources"
+ default y if PPC
+ help
+ Enable 64-bit PCI resource access.
+
config PCI_AARDVARK
bool "Enable Aardvark PCIe driver"
depends on DM_GPIO
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4a131bf5ca4..04f623652f0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o
obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o
obj-$(CONFIG_PCIE_ECAM_SYNQUACER) += pcie_ecam_synquacer.o
-obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
obj-$(CONFIG_PCI_MPC85XX) += pci_mpc85xx.o
obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
deleted file mode 100644
index c544af2a0b7..00000000000
--- a/drivers/pci/fsl_pci_init.c
+++ /dev/null
@@ -1,936 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2007-2012 Freescale Semiconductor, Inc.
- */
-
-#include <common.h>
-#include <env.h>
-#include <init.h>
-#include <log.h>
-#include <malloc.h>
-#include <asm/fsl_serdes.h>
-#include <asm/global_data.h>
-#include <linux/delay.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/*
- * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
- *
- * Initialize controller and call the common driver/pci pci_hose_scan to
- * scan for bridges and devices.
- *
- * Hose fields which need to be pre-initialized by board specific code:
- * regions[]
- * first_busno
- *
- * Fields updated:
- * last_busno
- */
-
-#include <pci.h>
-#include <asm/io.h>
-#include <asm/fsl_pci.h>
-
-#define MAX_PCI_REGIONS 7
-
-#ifndef CONFIG_SYS_PCI_MEMORY_BUS
-#define CONFIG_SYS_PCI_MEMORY_BUS 0
-#endif
-
-#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
-#define CONFIG_SYS_PCI_MEMORY_PHYS 0
-#endif
-
-#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
-#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
-#endif
-
-/* Setup one inbound ATMU window.
- *
- * We let the caller decide what the window size should be
- */
-static void set_inbound_window(volatile pit_t *pi,
- struct pci_region *r,
- u64 size)
-{
- u32 sz = (__ilog2_u64(size) - 1);
-#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
- u32 flag = 0;
-#else
- u32 flag = PIWAR_LOCAL;
-#endif
-
- flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
-
- out_be32(&pi->pitar, r->phys_start >> 12);
- out_be32(&pi->piwbar, r->bus_start >> 12);
-#ifdef CONFIG_SYS_PCI_64BIT
- out_be32(&pi->piwbear, r->bus_start >> 44);
-#else
- out_be32(&pi->piwbear, 0);
-#endif
- if (r->flags & PCI_REGION_PREFETCH)
- flag |= PIWAR_PF;
- out_be32(&pi->piwar, flag | sz);
-}
-
-int fsl_setup_hose(struct pci_controller *hose, unsigned long addr)
-{
- volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr;
-
- /* Reset hose to make sure its in a clean state */
- memset(hose, 0, sizeof(struct pci_controller));
-
- hose->regions = (struct pci_region *)
- calloc(1, MAX_PCI_REGIONS * sizeof(struct pci_region));
-
- pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);
-
- return fsl_is_pci_agent(hose);
-}
-
-static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
- u64 out_lo, u8 pcie_cap,
- volatile pit_t *pi)
-{
- struct pci_region *r = hose->regions + hose->region_count;
- u64 sz = min((u64)gd->ram_size, (1ull << 32));
-
- phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
- pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
- pci_size_t pci_sz;
-
- /* we have no space available for inbound memory mapping */
- if (bus_start > out_lo) {
- printf ("no space for inbound mapping of memory\n");
- return 0;
- }
-
- /* limit size */
- if ((bus_start + sz) > out_lo) {
- sz = out_lo - bus_start;
- debug ("limiting size to %llx\n", sz);
- }
-
- pci_sz = 1ull << __ilog2_u64(sz);
- /*
- * we can overlap inbound/outbound windows on PCI-E since RX & TX
- * links a separate
- */
- if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) {
- debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
- (u64)bus_start, (u64)phys_start, (u64)sz);
- pci_set_region(r, bus_start, phys_start, sz,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
- PCI_REGION_PREFETCH);
-
- /* if we aren't an exact power of two match, pci_sz is smaller
- * round it up to the next power of two. We report the actual
- * size to pci region tracking.
- */
- if (pci_sz != sz)
- sz = 2ull << __ilog2_u64(sz);
-
- set_inbound_window(pi--, r++, sz);
- sz = 0; /* make sure we dont set the R2 window */
- } else {
- debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
- (u64)bus_start, (u64)phys_start, (u64)pci_sz);
- pci_set_region(r, bus_start, phys_start, pci_sz,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
- PCI_REGION_PREFETCH);
- set_inbound_window(pi--, r++, pci_sz);
-
- sz -= pci_sz;
- bus_start += pci_sz;
- phys_start += pci_sz;
-
- pci_sz = 1ull << __ilog2_u64(sz);
- if (sz) {
- debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n",
- (u64)bus_start, (u64)phys_start, (u64)pci_sz);
- pci_set_region(r, bus_start, phys_start, pci_sz,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
- PCI_REGION_PREFETCH);
- set_inbound_window(pi--, r++, pci_sz);
- sz -= pci_sz;
- bus_start += pci_sz;
- phys_start += pci_sz;
- }
- }
-
-#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
- /*
- * On 64-bit capable systems, set up a mapping for all of DRAM
- * in high pci address space.
- */
- pci_sz = 1ull << __ilog2_u64(gd->ram_size);
- /* round up to the next largest power of two */
- if (gd->ram_size > pci_sz)
- pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
- debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n",
- (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
- (u64)CONFIG_SYS_PCI_MEMORY_PHYS,
- (u64)pci_sz);
- pci_set_region(r,
- CONFIG_SYS_PCI64_MEMORY_BUS,
- CONFIG_SYS_PCI_MEMORY_PHYS,
- pci_sz,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
- PCI_REGION_PREFETCH);
- set_inbound_window(pi--, r++, pci_sz);
-#else
- pci_sz = 1ull << __ilog2_u64(sz);
- if (sz) {
- debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n",
- (u64)bus_start, (u64)phys_start, (u64)pci_sz);
- pci_set_region(r, bus_start, phys_start, pci_sz,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
- PCI_REGION_PREFETCH);
- sz -= pci_sz;
- bus_start += pci_sz;
- phys_start += pci_sz;
- set_inbound_window(pi--, r++, pci_sz);
- }
-#endif
-
-#ifdef CONFIG_PHYS_64BIT
- if (sz && (((u64)gd->ram_size) < (1ull << 32)))
- printf("Was not able to map all of memory via "
- "inbound windows -- %lld remaining\n", sz);
-#endif
-
- hose->region_count = r - hose->regions;
-
- return 1;
-}
-
-#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
-static void fsl_pcie_boot_master(pit_t *pi)
-{
- /* configure inbound window for slave's u-boot image */
- debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
- "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
- (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
- (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
- struct pci_region r_inbound;
- u32 sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)
- - 1;
- pci_set_region(&r_inbound,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
- sz_inbound,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
- set_inbound_window(pi--, &r_inbound,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
-
- /* configure inbound window for slave's u-boot image */
- debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
- "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
- (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
- (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
- pci_set_region(&r_inbound,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
- sz_inbound,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
- set_inbound_window(pi--, &r_inbound,
- CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
-
- /* configure inbound window for slave's ucode and ENV */
- debug("PCIEBOOT - MASTER: Inbound window for slave's "
- "ucode and ENV; "
- "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
- (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
- (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
- CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
- sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE)
- - 1;
- pci_set_region(&r_inbound,
- CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
- CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
- sz_inbound,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
- set_inbound_window(pi--, &r_inbound,
- CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
-}
-
-static void fsl_pcie_boot_master_release_slave(int port)
-{
- unsigned long release_addr;
-
- /* now release slave's core 0 */
- switch (port) {
- case 1:
- release_addr = CONFIG_SYS_PCIE1_MEM_VIRT
- + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
- break;
-#ifdef CONFIG_SYS_PCIE2_MEM_VIRT
- case 2:
- release_addr = CONFIG_SYS_PCIE2_MEM_VIRT
- + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
- break;
-#endif
-#ifdef CONFIG_SYS_PCIE3_MEM_VIRT
- case 3:
- release_addr = CONFIG_SYS_PCIE3_MEM_VIRT
- + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
- break;
-#endif
- default:
- release_addr = 0;
- break;
- }
- if (release_addr != 0) {
- out_be32((void *)release_addr,
- CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
- debug("PCIEBOOT - MASTER: "
- "Release slave successfully! Now the slave should start up!\n");
- } else {
- debug("PCIEBOOT - MASTER: "
- "Release slave failed!\n");
- }
-}
-#endif
-
-void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
-{
- u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
- u32 cfg_data = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_data;
- u16 temp16;
- u32 temp32;
- u32 block_rev;
- int enabled, r, inbound = 0;
- u16 ltssm;
- u8 temp8, pcie_cap;
- int pcie_cap_pos;
- int pci_dcr;
- int pci_dsr;
- int pci_lsr;
-
-#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
- int pci_lcr;
-#endif
-
- volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
- struct pci_region *reg = hose->regions + hose->region_count;
- pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
-
- /* Initialize ATMU registers based on hose regions and flags */
- volatile pot_t *po = &pci->pot[1]; /* skip 0 */
- volatile pit_t *pi;
-
- u64 out_hi = 0, out_lo = -1ULL;
- u32 pcicsrbar, pcicsrbar_sz;
-
- pci_setup_indirect(hose, cfg_addr, cfg_data);
-
-#ifdef PEX_CCB_DIV
- /* Configure the PCIE controller core clock ratio */
- pci_hose_write_config_dword(hose, dev, 0x440,
- ((gd->bus_clk / 1000000) *
- (16 / PEX_CCB_DIV)) / 333);
-#endif
- block_rev = in_be32(&pci->block_rev1);
- if (PEX_IP_BLK_REV_2_2 <= block_rev) {
- pi = &pci->pit[2]; /* 0xDC0 */
- } else {
- pi = &pci->pit[3]; /* 0xDE0 */
- }
-
- /* Handle setup of outbound windows first */
- for (r = 0; r < hose->region_count; r++) {
- unsigned long flags = hose->regions[r].flags;
- u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);
-
- flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE;
- if (flags != PCI_REGION_SYS_MEMORY) {
- u64 start = hose->regions[r].bus_start;
- u64 end = start + hose->regions[r].size;
-
- out_be32(&po->powbar, hose->regions[r].phys_start >> 12);
- out_be32(&po->potar, start >> 12);
-#ifdef CONFIG_SYS_PCI_64BIT
- out_be32(&po->potear, start >> 44);
-#else
- out_be32(&po->potear, 0);
-#endif
- if (hose->regions[r].flags & PCI_REGION_IO) {
- out_be32(&po->powar, POWAR_EN | sz |
- POWAR_IO_READ | POWAR_IO_WRITE);
- } else {
- out_be32(&po->powar, POWAR_EN | sz |
- POWAR_MEM_READ | POWAR_MEM_WRITE);
- out_lo = min(start, out_lo);
- out_hi = max(end, out_hi);
- }
- po++;
- }
- }
- debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi);
-
- /* setup PCSRBAR/PEXCSRBAR */
- pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff);
- pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
- pcicsrbar_sz = ~pcicsrbar_sz + 1;
-
- if (out_hi < (0x100000000ull - pcicsrbar_sz) ||
- (out_lo > 0x100000000ull))
- pcicsrbar = 0x100000000ull - pcicsrbar_sz;
- else
- pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz;
- pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar);
-
- out_lo = min(out_lo, (u64)pcicsrbar);
-
- debug("PCICSRBAR @ 0x%x\n", pcicsrbar);
-
- pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS,
- pcicsrbar_sz, PCI_REGION_SYS_MEMORY);
- hose->region_count++;
-
- /* see if we are a PCIe or PCI controller */
- pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
- pci_dcr = pcie_cap_pos + 0x08;
- pci_dsr = pcie_cap_pos + 0x0a;
- pci_lsr = pcie_cap_pos + 0x12;
-
- pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
-
-#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
- /* boot from PCIE --master */
- char *s = env_get("bootmaster");
- char pcie[6];
- sprintf(pcie, "PCIE%d", pci_info->pci_num);
-
- if (s && (strcmp(s, pcie) == 0)) {
- debug("PCIEBOOT - MASTER: Master port [ %d ] for pcie boot.\n",
- pci_info->pci_num);
- fsl_pcie_boot_master((pit_t *)pi);
- } else {
- /* inbound */
- inbound = fsl_pci_setup_inbound_windows(hose,
- out_lo, pcie_cap, pi);
- }
-#else
- /* inbound */
- inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);
-#endif
-
- for (r = 0; r < hose->region_count; r++)
- debug("PCI reg:%d %016llx:%016llx %016llx %08lx\n", r,
- (u64)hose->regions[r].phys_start,
- (u64)hose->regions[r].bus_start,
- (u64)hose->regions[r].size,
- hose->regions[r].flags);
-
- pci_register_hose(hose);
- pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */
- hose->current_busno = hose->first_busno;
-
- out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */
- out_be32(&pci->peer, ~0x20140); /* Enable All Error Interrupts except
- * - Master abort (pci)
- * - Master PERR (pci)
- * - ICCA (PCIe)
- */
- pci_hose_read_config_dword(hose, dev, pci_dcr, &temp32);
- temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */
- pci_hose_write_config_dword(hose, dev, pci_dcr, temp32);
-
-#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
- pci_lcr = pcie_cap_pos + 0x10;
- temp32 = 0;
- pci_hose_read_config_dword(hose, dev, pci_lcr, &temp32);
- temp32 &= ~0x03; /* Disable ASPM */
- pci_hose_write_config_dword(hose, dev, pci_lcr, temp32);
- udelay(1);
-#endif
- if (pcie_cap == PCI_CAP_ID_EXP) {
- if (block_rev >= PEX_IP_BLK_REV_3_0) {
-#define PEX_CSR0_LTSSM_MASK 0xFC
-#define PEX_CSR0_LTSSM_SHIFT 2
- ltssm = (in_be32(&pci->pex_csr0)
- & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
- enabled = (ltssm == 0x11) ? 1 : 0;
-#ifdef CONFIG_FSL_PCIE_RESET
- int i;
- /* assert PCIe reset */
- setbits_be32(&pci->pdb_stat, 0x08000000);
- (void) in_be32(&pci->pdb_stat);
- udelay(1000);
- /* clear PCIe reset */
- clrbits_be32(&pci->pdb_stat, 0x08000000);
- asm("sync;isync");
- for (i = 0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
- pci_hose_read_config_word(hose, dev, PCI_LTSSM,
- &ltssm);
- udelay(1000);
- }
-#endif
- } else {
- /* pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm); */
- /* enabled = ltssm >= PCI_LTSSM_L0; */
- pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
- enabled = ltssm >= PCI_LTSSM_L0;
-
-#ifdef CONFIG_FSL_PCIE_RESET
- if (ltssm == 1) {
- int i;
- debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
- /* assert PCIe reset */
- setbits_be32(&pci->pdb_stat, 0x08000000);
- (void) in_be32(&pci->pdb_stat);
- udelay(100);
- debug(" Asserting PCIe reset @%p = %x\n",
- &pci->pdb_stat, in_be32(&pci->pdb_stat));
- /* clear PCIe reset */
- clrbits_be32(&pci->pdb_stat, 0x08000000);
- asm("sync;isync");
- for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
- pci_hose_read_config_word(hose, dev, PCI_LTSSM,
- &ltssm);
- udelay(1000);
- debug("....PCIe link error. "
- "LTSSM=0x%02x.\n", ltssm);
- }
- enabled = ltssm >= PCI_LTSSM_L0;
-
- /* we need to re-write the bar0 since a reset will
- * clear it
- */
- pci_hose_write_config_dword(hose, dev,
- PCI_BASE_ADDRESS_0, pcicsrbar);
- }
-#endif
- }
-
-#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
- if (enabled == 0) {
- serdes_corenet_t *srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
- temp32 = in_be32(&srds_regs->srdspccr0);
-
- if ((temp32 >> 28) == 3) {
- int i;
-
- out_be32(&srds_regs->srdspccr0, 2 << 28);
- setbits_be32(&pci->pdb_stat, 0x08000000);
- in_be32(&pci->pdb_stat);
- udelay(100);
- clrbits_be32(&pci->pdb_stat, 0x08000000);
- asm("sync;isync");
- for (i=0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
- pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
- udelay(1000);
- }
- enabled = ltssm >= PCI_LTSSM_L0;
- }
- }
-#endif
- if (!enabled) {
- /* Let the user know there's no PCIe link for root
- * complex. for endpoint, the link may not setup, so
- * print undetermined.
- */
- if (fsl_is_pci_agent(hose))
- printf("undetermined, regs @ 0x%lx\n", pci_info->regs);
- else
- printf("no link, regs @ 0x%lx\n", pci_info->regs);
- hose->last_busno = hose->first_busno;
- return;
- }
-
- out_be32(&pci->pme_msg_det, 0xffffffff);
- out_be32(&pci->pme_msg_int_en, 0xffffffff);
-
- /* Print the negotiated PCIe link width */
- pci_hose_read_config_word(hose, dev, pci_lsr, &temp16);
- printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4,
- (temp16 & 0xf), pci_info->regs);
-
- hose->current_busno++; /* Start scan with secondary */
- pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
- }
-
-#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
- /* The Read-Only Write Enable bit defaults to 1 instead of 0.
- * Set to 0 to protect the read-only registers.
- */
- clrbits_be32(&pci->dbi_ro_wr_en, 0x01);
-#endif
-
- /* Use generic setup_device to initialize standard pci regs,
- * but do not allocate any windows since any BAR found (such
- * as PCSRBAR) is not in this cpu's memory space.
- */
- pciauto_setup_device(hose, dev, 0, hose->pci_mem,
- hose->pci_prefetch, hose->pci_io);
-
- if (inbound) {
- pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
- pci_hose_write_config_word(hose, dev, PCI_COMMAND,
- temp16 | PCI_COMMAND_MEMORY);
- }
-
-#ifndef CONFIG_PCI_NOSCAN
- if (!fsl_is_pci_agent(hose)) {
- debug(" Scanning PCI bus %02x\n",
- hose->current_busno);
- hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
- } else {
- debug(" Not scanning PCI bus %02x. PI=%x\n",
- hose->current_busno, temp8);
- hose->last_busno = hose->current_busno;
- }
-
- /* if we are PCIe - update limit regs and subordinate busno
- * for the virtual P2P bridge
- */
- if (pcie_cap == PCI_CAP_ID_EXP) {
- pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
- }
-#else
- hose->last_busno = hose->current_busno;
-#endif
-
- /* Clear all error indications */
- if (pcie_cap == PCI_CAP_ID_EXP)
- out_be32(&pci->pme_msg_det, 0xffffffff);
- out_be32(&pci->pedr, 0xffffffff);
-
- pci_hose_read_config_word(hose, dev, pci_dsr, &temp16);
- if (temp16) {
- pci_hose_write_config_word(hose, dev, pci_dsr, 0xffff);
- }
-
- pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
- if (temp16) {
- pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
- }
-}
-
-int fsl_is_pci_agent(struct pci_controller *hose)
-{
- int pcie_cap_pos;
- u8 pcie_cap;
- pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
-
- pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
- pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
- if (pcie_cap == PCI_CAP_ID_EXP) {
- u8 header_type;
-
- pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE,
- &header_type);
- return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
- } else {
- u8 prog_if;
-
- pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if);
- /* Programming Interface (PCI_CLASS_PROG)
- * 0 == pci host or pcie root-complex,
- * 1 == pci agent or pcie end-point
- */
- return (prog_if == FSL_PROG_IF_AGENT);
- }
-}
-
-int fsl_pci_init_port(struct fsl_pci_info *pci_info,
- struct pci_controller *hose, int busno)
-{
- volatile ccsr_fsl_pci_t *pci;
- struct pci_region *r;
- pci_dev_t dev = PCI_BDF(busno,0,0);
- int pcie_cap_pos;
- u8 pcie_cap;
-
- pci = (ccsr_fsl_pci_t *) pci_info->regs;
-
- /* on non-PCIe controllers we don't have pme_msg_det so this code
- * should do nothing since the read will return 0
- */
- if (in_be32(&pci->pme_msg_det)) {
- out_be32(&pci->pme_msg_det, 0xffffffff);
- debug (" with errors. Clearing. Now 0x%08x",
- pci->pme_msg_det);
- }
-
- r = hose->regions + hose->region_count;
-
- /* outbound memory */
- pci_set_region(r++,
- pci_info->mem_bus,
- pci_info->mem_phys,
- pci_info->mem_size,
- PCI_REGION_MEM);
-
- /* outbound io */
- pci_set_region(r++,
- pci_info->io_bus,
- pci_info->io_phys,
- pci_info->io_size,
- PCI_REGION_IO);
-
- hose->region_count = r - hose->regions;
- hose->first_busno = busno;
-
- fsl_pci_init(hose, pci_info);
-
- if (fsl_is_pci_agent(hose)) {
- fsl_pci_config_unlock(hose);
- hose->last_busno = hose->first_busno;
-#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
- } else {
- /* boot from PCIE --master releases slave's core 0 */
- char *s = env_get("bootmaster");
- char pcie[6];
- sprintf(pcie, "PCIE%d", pci_info->pci_num);
-
- if (s && (strcmp(s, pcie) == 0))
- fsl_pcie_boot_master_release_slave(pci_info->pci_num);
-#endif
- }
-
- pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
- pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
- printf("PCI%s%x: Bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ?
- "e" : "", pci_info->pci_num,
- hose->first_busno, hose->last_busno);
- return(hose->last_busno + 1);
-}
-
-/* Enable inbound PCI config cycles for agent/endpoint interface */
-void fsl_pci_config_unlock(struct pci_controller *hose)
-{
- pci_dev_t dev = PCI_BDF(hose->first_busno,0,0);
- int pcie_cap_pos;
- u8 pcie_cap;
- u16 pbfr;
-
- if (!fsl_is_pci_agent(hose))
- return;
-
- pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
- pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
- if (pcie_cap != 0x0) {
- ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)hose->cfg_addr;
- u32 block_rev = in_be32(&pci->block_rev1);
- /* PCIe - set CFG_READY bit of Configuration Ready Register */
- if (block_rev >= PEX_IP_BLK_REV_3_0)
- setbits_be32(&pci->config, FSL_PCIE_V3_CFG_RDY);
- else
- pci_hose_write_config_byte(hose, dev,
- FSL_PCIE_CFG_RDY, 0x1);
- } else {
- /* PCI - clear ACL bit of PBFR */
- pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr);
- pbfr &= ~0x20;
- pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr);
- }
-}
-
-#if defined(CONFIG_PCIE1) || defined(CONFIG_PCIE2) || \
- defined(CONFIG_PCIE3) || defined(CONFIG_PCIE4)
-int fsl_configure_pcie(struct fsl_pci_info *info,
- struct pci_controller *hose,
- const char *connected, int busno)
-{
- int is_endpoint;
-
- set_next_law(info->mem_phys, law_size_bits(info->mem_size), info->law);
- set_next_law(info->io_phys, law_size_bits(info->io_size), info->law);
-
- is_endpoint = fsl_setup_hose(hose, info->regs);
- printf("PCIe%u: %s", info->pci_num,
- is_endpoint ? "Endpoint" : "Root Complex");
- if (connected)
- printf(" of %s", connected);
- puts(", ");
-
- return fsl_pci_init_port(info, hose, busno);
-}
-
-#if defined(CONFIG_FSL_CORENET)
-#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
- #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR3_PCIE1
- #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR3_PCIE2
- #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR3_PCIE3
- #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR3_PCIE4
-#else
- #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR_PCIE1
- #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR_PCIE2
- #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR_PCIE3
- #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR_PCIE4
-#endif
- #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
-#elif defined(CONFIG_MPC85xx)
- #define _DEVDISR_PCIE1 MPC85xx_DEVDISR_PCIE
- #define _DEVDISR_PCIE2 MPC85xx_DEVDISR_PCIE2
- #define _DEVDISR_PCIE3 MPC85xx_DEVDISR_PCIE3
- #define _DEVDISR_PCIE4 0
- #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
-#elif defined(CONFIG_MPC86xx)
- #define _DEVDISR_PCIE1 MPC86xx_DEVDISR_PCIE1
- #define _DEVDISR_PCIE2 MPC86xx_DEVDISR_PCIE2
- #define _DEVDISR_PCIE3 0
- #define _DEVDISR_PCIE4 0
- #define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
- (&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
-#else
-#error "No defines for DEVDISR_PCIE"
-#endif
-
-/* Implement a dummy function for those platforms w/o SERDES */
-static const char *__board_serdes_name(enum srds_prtcl device)
-{
- switch (device) {
-#ifdef CONFIG_SYS_PCIE1_NAME
- case PCIE1:
- return CONFIG_SYS_PCIE1_NAME;
-#endif
-#ifdef CONFIG_SYS_PCIE2_NAME
- case PCIE2:
- return CONFIG_SYS_PCIE2_NAME;
-#endif
-#ifdef CONFIG_SYS_PCIE3_NAME
- case PCIE3:
- return CONFIG_SYS_PCIE3_NAME;
-#endif
-#ifdef CONFIG_SYS_PCIE4_NAME
- case PCIE4:
- return CONFIG_SYS_PCIE4_NAME;
-#endif
- default:
- return NULL;
- }
-
- return NULL;
-}
-
-__attribute__((weak, alias("__board_serdes_name"))) const char *
-board_serdes_name(enum srds_prtcl device);
-
-static u32 devdisr_mask[] = {
- _DEVDISR_PCIE1,
- _DEVDISR_PCIE2,
- _DEVDISR_PCIE3,
- _DEVDISR_PCIE4,
-};
-
-int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
- struct fsl_pci_info *pci_info)
-{
- struct pci_controller *hose;
- int num = dev - PCIE1;
-
- hose = calloc(1, sizeof(struct pci_controller));
- if (!hose)
- return busno;
-
- if (is_serdes_configured(dev) && !(devdisr & devdisr_mask[num])) {
- busno = fsl_configure_pcie(pci_info, hose,
- board_serdes_name(dev), busno);
- } else {
- printf("PCIe%d: disabled\n", num + 1);
- }
-
- return busno;
-}
-
-int fsl_pcie_init_board(int busno)
-{
- struct fsl_pci_info pci_info;
- ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
- u32 devdisr;
- u32 *addr;
-
-#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
- addr = &gur->devdisr3;
-#else
- addr = &gur->devdisr;
-#endif
- devdisr = in_be32(addr);
-
-#ifdef CONFIG_PCIE1
- SET_STD_PCIE_INFO(pci_info, 1);
- busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE1, &pci_info);
-#else
- setbits_be32(addr, _DEVDISR_PCIE1); /* disable */
-#endif
-
-#ifdef CONFIG_PCIE2
- SET_STD_PCIE_INFO(pci_info, 2);
- busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE2, &pci_info);
-#else
- setbits_be32(addr, _DEVDISR_PCIE2); /* disable */
-#endif
-
-#ifdef CONFIG_PCIE3
- SET_STD_PCIE_INFO(pci_info, 3);
- busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE3, &pci_info);
-#else
- setbits_be32(addr, _DEVDISR_PCIE3); /* disable */
-#endif
-
-#ifdef CONFIG_PCIE4
- SET_STD_PCIE_INFO(pci_info, 4);
- busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE4, &pci_info);
-#else
- setbits_be32(addr, _DEVDISR_PCIE4); /* disable */
-#endif
-
- return busno;
-}
-#else
-int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
- struct fsl_pci_info *pci_info)
-{
- return busno;
-}
-
-int fsl_pcie_init_board(int busno)
-{
- return busno;
-}
-#endif
-
-#ifdef CONFIG_OF_BOARD_SETUP
-#include <linux/libfdt.h>
-#include <fdt_support.h>
-
-void ft_fsl_pci_setup(void *blob, const char *pci_compat,
- unsigned long ctrl_addr)
-{
- int off;
- u32 bus_range[2];
- phys_addr_t p_ctrl_addr = (phys_addr_t)ctrl_addr;
- struct pci_controller *hose;
-
- hose = find_hose_by_cfg_addr((void *)(ctrl_addr));
-
- /* convert ctrl_addr to true physical address */
- p_ctrl_addr = (phys_addr_t)ctrl_addr - CONFIG_SYS_CCSRBAR;
- p_ctrl_addr += CONFIG_SYS_CCSRBAR_PHYS;
-
- off = fdt_node_offset_by_compat_reg(blob, pci_compat, p_ctrl_addr);
-
- if (off < 0)
- return;
-
- /* We assume a cfg_addr not being set means we didn't setup the controller */
- if ((hose == NULL) || (hose->cfg_addr == NULL)) {
- fdt_del_node(blob, off);
- } else {
- bus_range[0] = 0;
- bus_range[1] = hose->last_busno - hose->first_busno;
- fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4);
- fdt_pci_dma_ranges(blob, off, hose);
- }
-}
-#endif
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index a92f00d0af5..22b6d8b6286 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -21,6 +21,7 @@
*
* Author: Victor Gu <xigu@marvell.com>
* Hezi Shahmoon <hezi.shahmoon@marvell.com>
+ * Pali Rohár <pali@kernel.org>
*
*/
@@ -165,16 +166,6 @@
#define PCIE_CONFIG_WR_TYPE0 0xa
#define PCIE_CONFIG_WR_TYPE1 0xb
-/* PCI_BDF shifts 8bit, so we need extra 4bit shift */
-#define PCIE_BDF(b, d, f) (PCI_BDF(b, d, f) << 4)
-#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
-#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
-#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
-#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
-#define PCIE_CONF_ADDR(bus, devfn, where) \
- (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
- PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
-
/* PCIe Retries & Timeout definitions */
#define PIO_MAX_RETRIES 1500
#define PIO_WAIT_TIMEOUT 1000
@@ -467,7 +458,7 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf,
advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */
- reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset);
+ reg = PCIE_ECAM_OFFSET(busno, PCI_DEV(bdf), PCI_FUNC(bdf), (offset & ~0x3));
advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS);
@@ -626,7 +617,7 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf,
advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */
- reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset);
+ reg = PCIE_ECAM_OFFSET(busno, PCI_DEV(bdf), PCI_FUNC(bdf), (offset & ~0x3));
advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS);
dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg);
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 62a4df37a02..9248cbc294c 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -7,13 +7,13 @@
* Ported to U-Boot by:
* Anton Schubert <anton.schubert@gmx.de>
* Stefan Roese <sr@denx.de>
+ * Pali Rohár <pali@kernel.org>
*/
#include <common.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
-#include <asm/global_data.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/of_access.h>
@@ -26,8 +26,6 @@
#include <linux/ioport.h>
#include <linux/mbus.h>
-DECLARE_GLOBAL_DATA_PTR;
-
/* PCIe unit register offsets */
#define SELECT(x, n) ((x >> n) & 1UL)
@@ -313,7 +311,9 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
/*
* Setup PCIE BARs and Address Decode Wins:
- * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
+ * BAR[0] -> internal registers
+ * BAR[1] -> covers all DRAM banks
+ * BAR[2] -> disabled
* WIN[0-3] -> DRAM bank[0-3]
*/
static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
@@ -364,6 +364,10 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
writel(((size - 1) & 0xffff0000) | 0x1,
pcie->base + PCIE_BAR_CTRL_OFF(1));
+
+ /* Setup BAR[0] to internal registers. */
+ writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
}
static int mvebu_pcie_probe(struct udevice *dev)
@@ -444,9 +448,9 @@ static int mvebu_pcie_probe(struct udevice *dev)
if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
(phys_addr_t)pcie->mem.start,
- MBUS_PCI_MEM_SIZE)) {
+ resource_size(&pcie->mem))) {
printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
- (u32)pcie->mem.start, MBUS_PCI_MEM_SIZE);
+ (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem));
}
pcie->io.start = (u32)mvebu_pcie_iobase;
@@ -455,9 +459,9 @@ static int mvebu_pcie_probe(struct udevice *dev)
if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
(phys_addr_t)pcie->io.start,
- MBUS_PCI_IO_SIZE)) {
+ resource_size(&pcie->io))) {
printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
- (u32)pcie->io.start, MBUS_PCI_IO_SIZE);
+ (u32)pcie->io.start, (unsigned)resource_size(&pcie->io));
}
/* Setup windows and configure host bridge */
@@ -465,19 +469,15 @@ static int mvebu_pcie_probe(struct udevice *dev)
/* PCI memory space */
pci_set_region(hose->regions + 0, pcie->mem.start,
- pcie->mem.start, MBUS_PCI_MEM_SIZE, PCI_REGION_MEM);
+ pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM);
pci_set_region(hose->regions + 1,
0, 0,
gd->ram_size,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
pci_set_region(hose->regions + 2, pcie->io.start,
- pcie->io.start, MBUS_PCI_IO_SIZE, PCI_REGION_IO);
+ pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO);
hose->region_count = 3;
- /* Set BAR0 to internal registers */
- writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
- writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
-
/* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */
pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] =
PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8);
diff --git a/drivers/pci/pcie_ecam_generic.c b/drivers/pci/pcie_ecam_generic.c
index e83e5aff206..1a9f9aec2ee 100644
--- a/drivers/pci/pcie_ecam_generic.c
+++ b/drivers/pci/pcie_ecam_generic.c
@@ -14,6 +14,8 @@
#include <asm/io.h>
+#define TYPE_PCI 0x1
+
/**
* struct generic_ecam_pcie - generic_ecam PCIe controller state
* @cfg_base: The base address of memory mapped configuration space
@@ -46,10 +48,14 @@ static int pci_generic_ecam_conf_address(const struct udevice *bus,
void *addr;
addr = pcie->cfg_base;
- addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
- addr += PCI_DEV(bdf) << 15;
- addr += PCI_FUNC(bdf) << 12;
- addr += offset;
+
+ if (dev_get_driver_data(bus) == TYPE_PCI) {
+ addr += ((PCI_BUS(bdf) - pcie->first_busno) << 16) |
+ (PCI_DEV(bdf) << 11) | (PCI_FUNC(bdf) << 8) | offset;
+ } else {
+ addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - pcie->first_busno,
+ PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+ }
*paddress = addr;
return 0;
@@ -158,7 +164,8 @@ static const struct dm_pci_ops pci_generic_ecam_ops = {
};
static const struct udevice_id pci_generic_ecam_ids[] = {
- { .compatible = "pci-host-ecam-generic" },
+ { .compatible = "pci-host-ecam-generic" /* PCI-E */ },
+ { .compatible = "pci-host-cam-generic", .data = TYPE_PCI },
{ }
};
diff --git a/drivers/pci/pcie_ecam_synquacer.c b/drivers/pci/pcie_ecam_synquacer.c
index c6e7c59f8a6..e3e22891088 100644
--- a/drivers/pci/pcie_ecam_synquacer.c
+++ b/drivers/pci/pcie_ecam_synquacer.c
@@ -235,10 +235,8 @@ static int pci_synquacer_ecam_conf_address(const struct udevice *bus,
void *addr;
addr = pcie->cfg_base;
- addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
- addr += PCI_DEV(bdf) << 15;
- addr += PCI_FUNC(bdf) << 12;
- addr += offset;
+ addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - pcie->first_busno,
+ PCI_DEV(bdf), PCI_FUNC(bdf), offset);
*paddress = addr;
return 0;
diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c
index 8a2a0e1f4a9..a47c9ef7c2f 100644
--- a/drivers/pci/pcie_layerscape_fixup.c
+++ b/drivers/pci/pcie_layerscape_fixup.c
@@ -584,9 +584,9 @@ static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc)
return;
if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
- fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
else
- fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
}
static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc)
@@ -600,9 +600,9 @@ static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc)
return;
if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
- fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
else
- fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
}
static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc)
diff --git a/drivers/pci/pcie_layerscape_gen4_fixup.c b/drivers/pci/pcie_layerscape_gen4_fixup.c
index 7d112341061..b2a45bf105c 100644
--- a/drivers/pci/pcie_layerscape_gen4_fixup.c
+++ b/drivers/pci/pcie_layerscape_gen4_fixup.c
@@ -193,9 +193,9 @@ static void ft_pcie_ep_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
}
if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
- fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
else
- fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
}
static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
@@ -214,9 +214,9 @@ static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
}
if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
- fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY);
else
- fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED);
}
static void ft_pcie_layerscape_gen4_setup(void *blob, struct ls_pcie_g4 *pcie)
diff --git a/drivers/pci/pcie_phytium.c b/drivers/pci/pcie_phytium.c
index 752e1703215..a8072762542 100644
--- a/drivers/pci/pcie_phytium.c
+++ b/drivers/pci/pcie_phytium.c
@@ -36,9 +36,7 @@ static int phytium_pci_skip_dev(pci_dev_t parent)
unsigned short capreg;
unsigned char port_type;
- addr += PCI_BUS(parent) << 20;
- addr += PCI_DEV(parent) << 15;
- addr += PCI_FUNC(parent) << 12;
+ addr += PCIE_ECAM_OFFSET(PCI_BUS(parent), PCI_DEV(parent), PCI_FUNC(parent), 0);
pos = 0x34;
while (1) {
@@ -89,9 +87,7 @@ static int pci_phytium_conf_address(const struct udevice *bus, pci_dev_t bdf,
bdf_parent = PCI_BDF((bus_no - 1), 0, 0);
addr = pcie->cfg_base;
- addr += PCI_BUS(bdf) << 20;
- addr += PCI_DEV(bdf) << 15;
- addr += PCI_FUNC(bdf) << 12;
+ addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), 0);
if (bus_no > 0 && dev_no > 0) {
if ((readb(addr + PCI_HEADER_TYPE) & 0x7f) !=
diff --git a/drivers/pci/pcie_rockchip.c b/drivers/pci/pcie_rockchip.c
index b0c91c0f430..67039d2a29f 100644
--- a/drivers/pci/pcie_rockchip.c
+++ b/drivers/pci/pcie_rockchip.c
@@ -101,15 +101,6 @@ struct rockchip_pcie {
struct phy pcie_phy;
};
-static int rockchip_pcie_off_conf(pci_dev_t bdf, uint offset)
-{
- unsigned int bus = PCI_BUS(bdf);
- unsigned int dev = PCI_DEV(bdf);
- unsigned int func = PCI_FUNC(bdf);
-
- return (bus << 20) | (dev << 15) | (func << 12) | (offset & ~0x3);
-}
-
static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
@@ -117,7 +108,7 @@ static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf,
struct rockchip_pcie *priv = dev_get_priv(udev);
unsigned int bus = PCI_BUS(bdf);
unsigned int dev = PCI_DEV(bdf);
- int where = rockchip_pcie_off_conf(bdf, offset);
+ int where = PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset & ~0x3);
ulong value;
if (bus == priv->first_busno && dev == 0) {
@@ -144,7 +135,7 @@ static int rockchip_pcie_wr_conf(struct udevice *udev, pci_dev_t bdf,
struct rockchip_pcie *priv = dev_get_priv(udev);
unsigned int bus = PCI_BUS(bdf);
unsigned int dev = PCI_DEV(bdf);
- int where = rockchip_pcie_off_conf(bdf, offset);
+ int where = PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset & ~0x3);
ulong old;
if (bus == priv->first_busno && dev == 0) {
diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c
index ae9a65b0a9e..eb9ec97b74f 100644
--- a/drivers/pci/pcie_xilinx.c
+++ b/drivers/pci/pcie_xilinx.c
@@ -76,10 +76,7 @@ static int pcie_xilinx_config_address(const struct udevice *udev, pci_dev_t bdf,
return -ENODEV;
addr = pcie->cfg_base;
- addr += bus << 20;
- addr += dev << 15;
- addr += func << 12;
- addr += offset;
+ addr += PCIE_ECAM_OFFSET(bus, dev, func, offset);
*paddress = addr;
return 0;
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 141ece479fe..ef924e7af50 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -616,8 +616,8 @@ static int cdns_torrent_phy_probe(struct udevice *dev)
/* Going through all the available subnodes or children*/
ofnode_for_each_subnode(child, dev_ofnode(dev)) {
- /* PHY subnode name must be a 'link' */
- if (!ofnode_name_eq(child, "link"))
+ /* PHY subnode name must be a 'phy' */
+ if (!ofnode_name_eq(child, "phy"))
continue;
cdns_phy->phys[node].lnk_rst =
devm_reset_bulk_get_by_node(dev, child);
diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c
index 047c8bb0452..41043535554 100644
--- a/drivers/phy/marvell/comphy_a3700.c
+++ b/drivers/phy/marvell/comphy_a3700.c
@@ -11,6 +11,7 @@
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <linux/delay.h>
+#include <phy.h>
#include "comphy_a3700.h"
@@ -982,6 +983,138 @@ void comphy_dedicated_phys_init(void)
debug_exit();
}
+static int find_available_node_by_compatible(int offset, const char *compatible)
+{
+ do {
+ offset = fdt_node_offset_by_compatible(gd->fdt_blob, offset,
+ compatible);
+ } while (offset > 0 && !fdtdec_get_is_enabled(gd->fdt_blob, offset));
+
+ return offset;
+}
+
+static bool comphy_a3700_find_lane(const int nodes[3], int node,
+ int port, int *lane, int *invert)
+{
+ int res, i, j;
+
+ for (i = 0; ; i++) {
+ struct fdtdec_phandle_args args;
+
+ res = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "phys",
+ "#phy-cells", 0, i, &args);
+ if (res)
+ return false;
+
+ for (j = 0; j < 3; j++) {
+ if (nodes[j] >= 0 && args.node == nodes[j] &&
+ (args.args_count >= 1 ? args.args[0] : 0) == port) {
+ *lane = j;
+ *invert = args.args_count >= 2 ? args.args[1]
+ : 0;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void comphy_a3700_fill_cfg(struct chip_serdes_phy_config *cfg,
+ const int nodes[3], const char *compatible,
+ int type)
+{
+ int node, lane, port, speed, invert;
+
+ port = (type == COMPHY_TYPE_SGMII1) ? 1 : 0;
+
+ node = -1;
+ while (1) {
+ node = find_available_node_by_compatible(node, compatible);
+ if (node < 0)
+ return;
+
+ if (comphy_a3700_find_lane(nodes, node, port, &lane, &invert))
+ break;
+ }
+
+ if (cfg->comphy_map_data[lane].type != COMPHY_TYPE_UNCONNECTED) {
+ printf("Error: More PHYs defined for lane %d, skipping\n",
+ lane);
+ return;
+ }
+
+ if (type == COMPHY_TYPE_SGMII0 || type == COMPHY_TYPE_SGMII1) {
+ const char *phy_mode;
+
+ phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
+ if (phy_mode &&
+ !strcmp(phy_mode,
+ phy_string_for_interface(PHY_INTERFACE_MODE_2500BASEX)))
+ speed = COMPHY_SPEED_3_125G;
+ else
+ speed = COMPHY_SPEED_1_25G;
+ } else if (type == COMPHY_TYPE_SATA0) {
+ speed = COMPHY_SPEED_6G;
+ } else {
+ speed = COMPHY_SPEED_5G;
+ }
+
+ cfg->comphy_map_data[lane].type = type;
+ cfg->comphy_map_data[lane].speed = speed;
+ cfg->comphy_map_data[lane].invert = invert;
+}
+
+static const fdt32_t comphy_a3700_mux_lane_order[3] = {
+ __constant_cpu_to_be32(1),
+ __constant_cpu_to_be32(0),
+ __constant_cpu_to_be32(2),
+};
+
+int comphy_a3700_init_serdes_map(int node, struct chip_serdes_phy_config *cfg)
+{
+ int comphy_nodes[3];
+ int child, i;
+
+ for (i = 0; i < ARRAY_SIZE(comphy_nodes); i++)
+ comphy_nodes[i] = -FDT_ERR_NOTFOUND;
+
+ fdt_for_each_subnode(child, gd->fdt_blob, node) {
+ if (!fdtdec_get_is_enabled(gd->fdt_blob, child))
+ continue;
+
+ i = fdtdec_get_int(gd->fdt_blob, child, "reg", -1);
+ if (i < 0 || i >= ARRAY_SIZE(comphy_nodes))
+ continue;
+
+ comphy_nodes[i] = child;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(comphy_nodes); i++) {
+ cfg->comphy_map_data[i].type = COMPHY_TYPE_UNCONNECTED;
+ cfg->comphy_map_data[i].speed = COMPHY_SPEED_INVALID;
+ }
+
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada3700-u3d",
+ COMPHY_TYPE_USB3_DEVICE);
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada3700-xhci",
+ COMPHY_TYPE_USB3_HOST0);
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada-3700-pcie",
+ COMPHY_TYPE_PEX0);
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada-3700-ahci",
+ COMPHY_TYPE_SATA0);
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada-3700-neta",
+ COMPHY_TYPE_SGMII0);
+ comphy_a3700_fill_cfg(cfg, comphy_nodes, "marvell,armada-3700-neta",
+ COMPHY_TYPE_SGMII1);
+
+ cfg->comphy_lanes_count = 3;
+ cfg->comphy_mux_bitcount = 4;
+ cfg->comphy_mux_lane_order = comphy_a3700_mux_lane_order;
+
+ return 0;
+}
+
int comphy_a3700_init(struct chip_serdes_phy_config *chip_cfg,
struct comphy_map *serdes_map)
{
diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c
index 2c9d7b2288d..233a973035b 100644
--- a/drivers/phy/marvell/comphy_core.c
+++ b/drivers/phy/marvell/comphy_core.c
@@ -86,11 +86,8 @@ __weak int comphy_update_map(struct comphy_map *serdes_map, int count)
static int comphy_probe(struct udevice *dev)
{
- const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
struct chip_serdes_phy_config *chip_cfg = dev_get_priv(dev);
- int subnode;
- int lane;
int last_idx = 0;
static int current_idx;
int res;
@@ -104,30 +101,14 @@ static int comphy_probe(struct udevice *dev)
if (IS_ERR(chip_cfg->hpipe3_base_addr))
return PTR_ERR(chip_cfg->hpipe3_base_addr);
- chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node,
- "max-lanes", 0);
- if (chip_cfg->comphy_lanes_count <= 0) {
- dev_err(dev, "comphy max lanes is wrong\n");
- return -EINVAL;
- }
-
- chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node,
- "mux-bitcount", 0);
- if (chip_cfg->comphy_mux_bitcount <= 0) {
- dev_err(dev, "comphy mux bit count is wrong\n");
- return -EINVAL;
- }
-
- chip_cfg->comphy_mux_lane_order =
- fdtdec_locate_array(blob, node, "mux-lane-order",
- chip_cfg->comphy_lanes_count);
-
if (device_is_compatible(dev, "marvell,comphy-armada-3700")) {
+ chip_cfg->comphy_init_map = comphy_a3700_init_serdes_map;
chip_cfg->ptr_comphy_chip_init = comphy_a3700_init;
chip_cfg->rx_training = NULL;
}
if (device_is_compatible(dev, "marvell,comphy-cp110")) {
+ chip_cfg->comphy_init_map = comphy_cp110_init_serdes_map;
chip_cfg->ptr_comphy_chip_init = comphy_cp110_init;
chip_cfg->rx_training = comphy_cp110_sfi_rx_training;
}
@@ -141,39 +122,9 @@ static int comphy_probe(struct udevice *dev)
return -ENODEV;
}
- lane = 0;
- fdt_for_each_subnode(subnode, blob, node) {
- /* Skip disabled ports */
- if (!fdtdec_get_is_enabled(blob, subnode))
- continue;
-
- chip_cfg->comphy_map_data[lane].type =
- fdtdec_get_int(blob, subnode, "phy-type",
- COMPHY_TYPE_INVALID);
-
- if (chip_cfg->comphy_map_data[lane].type ==
- COMPHY_TYPE_INVALID) {
- printf("no phy type for lane %d, setting lane as unconnected\n",
- lane + 1);
- continue;
- }
-
- chip_cfg->comphy_map_data[lane].speed =
- fdtdec_get_int(blob, subnode, "phy-speed",
- COMPHY_SPEED_INVALID);
-
- chip_cfg->comphy_map_data[lane].invert =
- fdtdec_get_int(blob, subnode, "phy-invert",
- COMPHY_POLARITY_NO_INVERT);
-
- chip_cfg->comphy_map_data[lane].clk_src =
- fdtdec_get_bool(blob, subnode, "clk-src");
-
- chip_cfg->comphy_map_data[lane].end_point =
- fdtdec_get_bool(blob, subnode, "end_point");
-
- lane++;
- }
+ res = chip_cfg->comphy_init_map(node, chip_cfg);
+ if (res < 0)
+ return res;
res = comphy_update_map(chip_cfg->comphy_map_data, chip_cfg->comphy_lanes_count);
if (res < 0)
diff --git a/drivers/phy/marvell/comphy_core.h b/drivers/phy/marvell/comphy_core.h
index 9bbd7f8f35d..d573776c05a 100644
--- a/drivers/phy/marvell/comphy_core.h
+++ b/drivers/phy/marvell/comphy_core.h
@@ -32,6 +32,7 @@ struct comphy_mux_data {
struct chip_serdes_phy_config {
struct comphy_mux_data *mux_data;
+ int (*comphy_init_map)(int, struct chip_serdes_phy_config *);
int (*ptr_comphy_chip_init)(struct chip_serdes_phy_config *,
struct comphy_map *);
int (*rx_training)(struct chip_serdes_phy_config *, u32);
@@ -85,9 +86,20 @@ static inline void reg_set16(void __iomem *addr, u16 data, u16 mask)
/* SoC specific init functions */
#ifdef CONFIG_ARMADA_3700
+int comphy_a3700_init_serdes_map(int node, struct chip_serdes_phy_config *cfg);
int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg,
struct comphy_map *serdes_map);
#else
+static inline int
+comphy_a3700_init_serdes_map(int node, struct chip_serdes_phy_config *cfg)
+{
+ /*
+ * This function should never be called in this configuration, so
+ * lets return an error here.
+ */
+ return -1;
+}
+
static inline int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg,
struct comphy_map *serdes_map)
{
@@ -100,11 +112,22 @@ static inline int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg,
#endif
#ifdef CONFIG_ARMADA_8K
+int comphy_cp110_init_serdes_map(int node, struct chip_serdes_phy_config *cfg);
int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
struct comphy_map *serdes_map);
int comphy_cp110_sfi_rx_training(struct chip_serdes_phy_config *ptr_chip_cfg,
u32 lane);
#else
+static inline int
+comphy_cp110_init_serdes_map(int node, struct chip_serdes_phy_config *cfg)
+{
+ /*
+ * This function should never be called in this configuration, so
+ * lets return an error here.
+ */
+ return -1;
+}
+
static inline int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
struct comphy_map *serdes_map)
{
diff --git a/drivers/phy/marvell/comphy_cp110.c b/drivers/phy/marvell/comphy_cp110.c
index 4fe2dfcdd17..e063b51c6dd 100644
--- a/drivers/phy/marvell/comphy_cp110.c
+++ b/drivers/phy/marvell/comphy_cp110.c
@@ -554,6 +554,64 @@ void comphy_dedicated_phys_init(void)
debug_exit();
}
+int comphy_cp110_init_serdes_map(int node, struct chip_serdes_phy_config *cfg)
+{
+ int lane, subnode;
+
+ cfg->comphy_lanes_count = fdtdec_get_int(gd->fdt_blob, node,
+ "max-lanes", 0);
+ if (cfg->comphy_lanes_count <= 0) {
+ printf("comphy max lanes is wrong\n");
+ return -EINVAL;
+ }
+
+ cfg->comphy_mux_bitcount = fdtdec_get_int(gd->fdt_blob, node,
+ "mux-bitcount", 0);
+ if (cfg->comphy_mux_bitcount <= 0) {
+ printf("comphy mux bit count is wrong\n");
+ return -EINVAL;
+ }
+
+ cfg->comphy_mux_lane_order = fdtdec_locate_array(gd->fdt_blob, node,
+ "mux-lane-order",
+ cfg->comphy_lanes_count);
+
+ lane = 0;
+ fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
+ /* Skip disabled ports */
+ if (!fdtdec_get_is_enabled(gd->fdt_blob, subnode))
+ continue;
+
+ cfg->comphy_map_data[lane].type =
+ fdtdec_get_int(gd->fdt_blob, subnode, "phy-type",
+ COMPHY_TYPE_INVALID);
+
+ if (cfg->comphy_map_data[lane].type == COMPHY_TYPE_INVALID) {
+ printf("no phy type for lane %d, setting lane as unconnected\n",
+ lane + 1);
+ continue;
+ }
+
+ cfg->comphy_map_data[lane].speed =
+ fdtdec_get_int(gd->fdt_blob, subnode, "phy-speed",
+ COMPHY_SPEED_INVALID);
+
+ cfg->comphy_map_data[lane].invert =
+ fdtdec_get_int(gd->fdt_blob, subnode, "phy-invert",
+ COMPHY_POLARITY_NO_INVERT);
+
+ cfg->comphy_map_data[lane].clk_src =
+ fdtdec_get_bool(gd->fdt_blob, subnode, "clk-src");
+
+ cfg->comphy_map_data[lane].end_point =
+ fdtdec_get_bool(gd->fdt_blob, subnode, "end_point");
+
+ lane++;
+ }
+
+ return 0;
+}
+
int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
struct comphy_map *serdes_map)
{
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 30eaa376c8e..03946245c7d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -145,6 +145,17 @@ config SPL_PINCONF_RECURSIVE
if PINCTRL || SPL_PINCTRL
+config PINCTRL_APPLE
+ bool "Apple pinctrl driver"
+ depends on DM && PINCTRL_GENERIC && ARCH_APPLE
+ default y
+ help
+ Support pin multiplexing on Apple SoCs.
+
+ The driver is controlled by a device tree node which contains
+ both the GPIO definitions and pin control functions for each
+ available multiplex function.
+
config PINCTRL_AR933X
bool "QCA/Athores ar933x pin control driver"
depends on DM && SOC_AR933X
@@ -291,6 +302,15 @@ config ASPEED_AST2500_PINCTRL
uses Generic Pinctrl framework and is compatible with the Linux
driver, i.e. it uses the same device tree configuration.
+config ASPEED_AST2600_PINCTRL
+ bool "Aspeed AST2600 pin control driver"
+ depends on DM && PINCTRL_GENERIC && ASPEED_AST2600
+ default y
+ help
+ Support pin multiplexing control on Aspeed ast2600 SoC. The driver
+ uses Generic Pinctrl framework and is compatible with the Linux
+ driver, i.e. it uses the same device tree configuration.
+
config PINCTRL_K210
bool "Kendryte K210 Fully-Programmable Input/Output Array driver"
depends on DM && PINCTRL_GENERIC
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 05b71f2f134..fd736a7f640 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -3,6 +3,7 @@
obj-y += pinctrl-uclass.o
obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
+obj-$(CONFIG_PINCTRL_APPLE) += pinctrl-apple.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
obj-y += nxp/
diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile
index 2e6ed604c8f..a3e01ed1ca9 100644
--- a/drivers/pinctrl/aspeed/Makefile
+++ b/drivers/pinctrl/aspeed/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o
+obj-$(CONFIG_ASPEED_AST2600_PINCTRL) += pinctrl_ast2600.o
diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2600.c b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
new file mode 100644
index 00000000000..12cba83f6c0
--- /dev/null
+++ b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) ASPEED Technology Inc.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/pinctrl.h>
+#include <asm/arch/scu_ast2600.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+/*
+ * This driver works with very simple configuration that has the same name
+ * for group and function. This way it is compatible with the Linux Kernel
+ * driver.
+ */
+struct aspeed_sig_desc {
+ u32 offset;
+ u32 reg_set;
+ int clr;
+};
+
+struct aspeed_group_config {
+ char *group_name;
+ int ndescs;
+ struct aspeed_sig_desc *descs;
+};
+
+struct ast2600_pinctrl_priv {
+ struct ast2600_scu *scu;
+};
+
+static int ast2600_pinctrl_probe(struct udevice *dev)
+{
+ struct ast2600_pinctrl_priv *priv = dev_get_priv(dev);
+ struct udevice *clk_dev;
+ int ret = 0;
+
+ /* find SCU base address from clock device */
+ uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(aspeed_ast2600_scu), &clk_dev);
+
+ if (ret)
+ return ret;
+
+ priv->scu = dev_read_addr_ptr(clk_dev);
+ if (IS_ERR(priv->scu))
+ return PTR_ERR(priv->scu);
+
+ return 0;
+}
+
+static struct aspeed_sig_desc i2c1_link[] = {
+ { 0x418, GENMASK(9, 8), 1 },
+ { 0x4B8, GENMASK(9, 8), 0 },
+};
+
+static struct aspeed_sig_desc i2c2_link[] = {
+ { 0x418, GENMASK(11, 10), 1 },
+ { 0x4B8, GENMASK(11, 10), 0 },
+};
+
+static struct aspeed_sig_desc i2c3_link[] = {
+ { 0x418, GENMASK(13, 12), 1 },
+ { 0x4B8, GENMASK(13, 12), 0 },
+};
+
+static struct aspeed_sig_desc i2c4_link[] = {
+ { 0x418, GENMASK(15, 14), 1 },
+ { 0x4B8, GENMASK(15, 14), 0 },
+};
+
+static struct aspeed_sig_desc i2c5_link[] = {
+ { 0x418, GENMASK(17, 16), 0 },
+};
+
+static struct aspeed_sig_desc i2c6_link[] = {
+ { 0x418, GENMASK(19, 18), 0 },
+};
+
+static struct aspeed_sig_desc i2c7_link[] = {
+ { 0x418, GENMASK(21, 20), 0 },
+};
+
+static struct aspeed_sig_desc i2c8_link[] = {
+ { 0x418, GENMASK(23, 22), 0 },
+};
+
+static struct aspeed_sig_desc i2c9_link[] = {
+ { 0x418, GENMASK(25, 24), 0 },
+};
+
+static struct aspeed_sig_desc i2c10_link[] = {
+ { 0x418, GENMASK(27, 26), 0 },
+};
+
+static struct aspeed_sig_desc i2c11_link[] = {
+ { 0x410, GENMASK(1, 0), 1 },
+ { 0x4B0, GENMASK(1, 0), 0 },
+};
+
+static struct aspeed_sig_desc i2c12_link[] = {
+ { 0x410, GENMASK(3, 2), 1 },
+ { 0x4B0, GENMASK(3, 2), 0 },
+};
+
+static struct aspeed_sig_desc i2c13_link[] = {
+ { 0x410, GENMASK(5, 4), 1 },
+ { 0x4B0, GENMASK(5, 4), 0 },
+};
+
+static struct aspeed_sig_desc i2c14_link[] = {
+ { 0x410, GENMASK(7, 6), 1 },
+ { 0x4B0, GENMASK(7, 6), 0 },
+};
+
+static struct aspeed_sig_desc i2c15_link[] = {
+ { 0x414, GENMASK(29, 28), 1 },
+ { 0x4B4, GENMASK(29, 28), 0 },
+};
+
+static struct aspeed_sig_desc i2c16_link[] = {
+ { 0x414, GENMASK(31, 30), 1 },
+ { 0x4B4, GENMASK(31, 30), 0 },
+};
+
+static struct aspeed_sig_desc mac1_link[] = {
+ { 0x410, BIT(4), 0 },
+ { 0x470, BIT(4), 1 },
+};
+
+static struct aspeed_sig_desc mac2_link[] = {
+ { 0x410, BIT(5), 0 },
+ { 0x470, BIT(5), 1 },
+};
+
+static struct aspeed_sig_desc mac3_link[] = {
+ { 0x410, BIT(6), 0 },
+ { 0x470, BIT(6), 1 },
+};
+
+static struct aspeed_sig_desc mac4_link[] = {
+ { 0x410, BIT(7), 0 },
+ { 0x470, BIT(7), 1 },
+};
+
+static struct aspeed_sig_desc rgmii1[] = {
+ { 0x500, BIT(6), 0 },
+ { 0x400, GENMASK(11, 0), 0 },
+};
+
+static struct aspeed_sig_desc rgmii2[] = {
+ { 0x500, BIT(7), 0 },
+ { 0x400, GENMASK(23, 12), 0 },
+};
+
+static struct aspeed_sig_desc rgmii3[] = {
+ { 0x510, BIT(0), 0 },
+ { 0x410, GENMASK(27, 16), 0 },
+};
+
+static struct aspeed_sig_desc rgmii4[] = {
+ { 0x510, BIT(1), 0 },
+ { 0x410, GENMASK(31, 28), 1 },
+ { 0x4b0, GENMASK(31, 28), 0 },
+ { 0x474, GENMASK(7, 0), 1 },
+ { 0x414, GENMASK(7, 0), 1 },
+ { 0x4b4, GENMASK(7, 0), 0 },
+};
+
+static struct aspeed_sig_desc rmii1[] = {
+ { 0x504, BIT(6), 0 },
+ { 0x400, GENMASK(3, 0), 0 },
+ { 0x400, GENMASK(11, 6), 0 },
+};
+
+static struct aspeed_sig_desc rmii2[] = {
+ { 0x504, BIT(7), 0 },
+ { 0x400, GENMASK(15, 12), 0 },
+ { 0x400, GENMASK(23, 18), 0 },
+};
+
+static struct aspeed_sig_desc rmii3[] = {
+ { 0x514, BIT(0), 0 },
+ { 0x410, GENMASK(27, 22), 0 },
+ { 0x410, GENMASK(19, 16), 0 },
+};
+
+static struct aspeed_sig_desc rmii4[] = {
+ { 0x514, BIT(1), 0 },
+ { 0x410, GENMASK(7, 2), 1 },
+ { 0x410, GENMASK(31, 28), 1 },
+ { 0x414, GENMASK(7, 2), 1 },
+ { 0x4B0, GENMASK(31, 28), 0 },
+ { 0x4B4, GENMASK(7, 2), 0 },
+};
+
+static struct aspeed_sig_desc rmii1_rclk_oe[] = {
+ { 0x340, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc rmii2_rclk_oe[] = {
+ { 0x340, BIT(30), 0 },
+};
+
+static struct aspeed_sig_desc rmii3_rclk_oe[] = {
+ { 0x350, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc rmii4_rclk_oe[] = {
+ { 0x350, BIT(30), 0 },
+};
+
+static struct aspeed_sig_desc mdio1_link[] = {
+ { 0x430, BIT(17) | BIT(16), 0 },
+};
+
+static struct aspeed_sig_desc mdio2_link[] = {
+ { 0x470, BIT(13) | BIT(12), 1 },
+ { 0x410, BIT(13) | BIT(12), 0 },
+};
+
+static struct aspeed_sig_desc mdio3_link[] = {
+ { 0x470, BIT(1) | BIT(0), 1 },
+ { 0x410, BIT(1) | BIT(0), 0 },
+};
+
+static struct aspeed_sig_desc mdio4_link[] = {
+ { 0x470, BIT(3) | BIT(2), 1 },
+ { 0x410, BIT(3) | BIT(2), 0 },
+};
+
+static struct aspeed_sig_desc sdio2_link[] = {
+ { 0x414, GENMASK(23, 16), 1 },
+ { 0x4B4, GENMASK(23, 16), 0 },
+ { 0x450, BIT(1), 0 },
+};
+
+static struct aspeed_sig_desc sdio1_link[] = {
+ { 0x414, GENMASK(15, 8), 0 },
+};
+
+/* when sdio1 8bits, sdio2 can't use */
+static struct aspeed_sig_desc sdio1_8bit_link[] = {
+ { 0x414, GENMASK(15, 8), 0 },
+ { 0x4b4, GENMASK(21, 18), 0 },
+ { 0x450, BIT(3), 0 },
+ { 0x450, BIT(1), 1 },
+};
+
+static struct aspeed_sig_desc emmc_link[] = {
+ { 0x400, GENMASK(31, 24), 0 },
+};
+
+static struct aspeed_sig_desc emmcg8_link[] = {
+ { 0x400, GENMASK(31, 24), 0 },
+ { 0x404, GENMASK(3, 0), 0 },
+/* set SCU504 to clear the strap bits in SCU500 */
+ { 0x504, BIT(3), 0 },
+ { 0x504, BIT(5), 0 },
+};
+
+static struct aspeed_sig_desc fmcquad_link[] = {
+ { 0x438, GENMASK(5, 4), 0 },
+};
+
+static struct aspeed_sig_desc spi1_link[] = {
+ { 0x438, GENMASK(13, 11), 0 },
+};
+
+static struct aspeed_sig_desc spi1abr_link[] = {
+ { 0x438, BIT(9), 0 },
+};
+
+static struct aspeed_sig_desc spi1cs1_link[] = {
+ { 0x438, BIT(8), 0 },
+};
+
+static struct aspeed_sig_desc spi1wp_link[] = {
+ { 0x438, BIT(10), 0 },
+};
+
+static struct aspeed_sig_desc spi1quad_link[] = {
+ { 0x438, GENMASK(15, 14), 0 },
+};
+
+static struct aspeed_sig_desc spi2_link[] = {
+ { 0x434, GENMASK(29, 27) | BIT(24), 0 },
+};
+
+static struct aspeed_sig_desc spi2cs1_link[] = {
+ { 0x434, BIT(25), 0 },
+};
+
+static struct aspeed_sig_desc spi2cs2_link[] = {
+ { 0x434, BIT(26), 0 },
+};
+
+static struct aspeed_sig_desc spi2quad_link[] = {
+ { 0x434, GENMASK(31, 30), 0 },
+};
+
+static struct aspeed_sig_desc fsi1[] = {
+ { 0xd48, GENMASK(21, 20), 0 },
+};
+
+static struct aspeed_sig_desc fsi2[] = {
+ { 0xd48, GENMASK(23, 22), 0 },
+};
+
+static struct aspeed_sig_desc usb2ad_link[] = {
+ { 0x440, BIT(24), 0 },
+ { 0x440, BIT(25), 1 },
+};
+
+static struct aspeed_sig_desc usb2ah_link[] = {
+ { 0x440, BIT(24), 1 },
+ { 0x440, BIT(25), 0 },
+};
+
+static struct aspeed_sig_desc usb2bh_link[] = {
+ { 0x440, BIT(28), 1 },
+ { 0x440, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc pcie0rc_link[] = {
+ { 0x40, BIT(21), 0 },
+};
+
+static struct aspeed_sig_desc pcie1rc_link[] = {
+ { 0x40, BIT(19), 0 }, /* SSPRST# output enable */
+ { 0x500, BIT(24), 0 }, /* dedicate rc reset */
+};
+
+static const struct aspeed_group_config ast2600_groups[] = {
+ { "MAC1LINK", ARRAY_SIZE(mac1_link), mac1_link },
+ { "MAC2LINK", ARRAY_SIZE(mac2_link), mac2_link },
+ { "MAC3LINK", ARRAY_SIZE(mac3_link), mac3_link },
+ { "MAC4LINK", ARRAY_SIZE(mac4_link), mac4_link },
+ { "RGMII1", ARRAY_SIZE(rgmii1), rgmii1 },
+ { "RGMII2", ARRAY_SIZE(rgmii2), rgmii2 },
+ { "RGMII3", ARRAY_SIZE(rgmii3), rgmii3 },
+ { "RGMII4", ARRAY_SIZE(rgmii4), rgmii4 },
+ { "RMII1", ARRAY_SIZE(rmii1), rmii1 },
+ { "RMII2", ARRAY_SIZE(rmii2), rmii2 },
+ { "RMII3", ARRAY_SIZE(rmii3), rmii3 },
+ { "RMII4", ARRAY_SIZE(rmii4), rmii4 },
+ { "RMII1RCLK", ARRAY_SIZE(rmii1_rclk_oe), rmii1_rclk_oe },
+ { "RMII2RCLK", ARRAY_SIZE(rmii2_rclk_oe), rmii2_rclk_oe },
+ { "RMII3RCLK", ARRAY_SIZE(rmii3_rclk_oe), rmii3_rclk_oe },
+ { "RMII4RCLK", ARRAY_SIZE(rmii4_rclk_oe), rmii4_rclk_oe },
+ { "MDIO1", ARRAY_SIZE(mdio1_link), mdio1_link },
+ { "MDIO2", ARRAY_SIZE(mdio2_link), mdio2_link },
+ { "MDIO3", ARRAY_SIZE(mdio3_link), mdio3_link },
+ { "MDIO4", ARRAY_SIZE(mdio4_link), mdio4_link },
+ { "SD1", ARRAY_SIZE(sdio1_link), sdio1_link },
+ { "SD1_8bits", ARRAY_SIZE(sdio1_8bit_link), sdio1_8bit_link },
+ { "SD2", ARRAY_SIZE(sdio2_link), sdio2_link },
+ { "EMMC", ARRAY_SIZE(emmc_link), emmc_link },
+ { "EMMCG8", ARRAY_SIZE(emmcg8_link), emmcg8_link },
+ { "FMCQUAD", ARRAY_SIZE(fmcquad_link), fmcquad_link },
+ { "SPI1", ARRAY_SIZE(spi1_link), spi1_link },
+ { "SPI1ABR", ARRAY_SIZE(spi1abr_link), spi1abr_link },
+ { "SPI1CS1", ARRAY_SIZE(spi1cs1_link), spi1cs1_link },
+ { "SPI1WP", ARRAY_SIZE(spi1wp_link), spi1wp_link },
+ { "SPI1QUAD", ARRAY_SIZE(spi1quad_link), spi1quad_link },
+ { "SPI2", ARRAY_SIZE(spi2_link), spi2_link },
+ { "SPI2CS1", ARRAY_SIZE(spi2cs1_link), spi2cs1_link },
+ { "SPI2CS2", ARRAY_SIZE(spi2cs2_link), spi2cs2_link },
+ { "SPI2QUAD", ARRAY_SIZE(spi2quad_link), spi2quad_link },
+ { "I2C1", ARRAY_SIZE(i2c1_link), i2c1_link },
+ { "I2C2", ARRAY_SIZE(i2c2_link), i2c2_link },
+ { "I2C3", ARRAY_SIZE(i2c3_link), i2c3_link },
+ { "I2C4", ARRAY_SIZE(i2c4_link), i2c4_link },
+ { "I2C5", ARRAY_SIZE(i2c5_link), i2c5_link },
+ { "I2C6", ARRAY_SIZE(i2c6_link), i2c6_link },
+ { "I2C7", ARRAY_SIZE(i2c7_link), i2c7_link },
+ { "I2C8", ARRAY_SIZE(i2c8_link), i2c8_link },
+ { "I2C9", ARRAY_SIZE(i2c9_link), i2c9_link },
+ { "I2C10", ARRAY_SIZE(i2c10_link), i2c10_link },
+ { "I2C11", ARRAY_SIZE(i2c11_link), i2c11_link },
+ { "I2C12", ARRAY_SIZE(i2c12_link), i2c12_link },
+ { "I2C13", ARRAY_SIZE(i2c13_link), i2c13_link },
+ { "I2C14", ARRAY_SIZE(i2c14_link), i2c14_link },
+ { "I2C15", ARRAY_SIZE(i2c15_link), i2c15_link },
+ { "I2C16", ARRAY_SIZE(i2c16_link), i2c16_link },
+ { "FSI1", ARRAY_SIZE(fsi1), fsi1 },
+ { "FSI2", ARRAY_SIZE(fsi2), fsi2 },
+ { "USB2AD", ARRAY_SIZE(usb2ad_link), usb2ad_link },
+ { "USB2AH", ARRAY_SIZE(usb2ah_link), usb2ah_link },
+ { "USB2BH", ARRAY_SIZE(usb2bh_link), usb2bh_link },
+ { "PCIE0RC", ARRAY_SIZE(pcie0rc_link), pcie0rc_link },
+ { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link },
+};
+
+static int ast2600_pinctrl_get_groups_count(struct udevice *dev)
+{
+ debug("PINCTRL: get_(functions/groups)_count\n");
+
+ return ARRAY_SIZE(ast2600_groups);
+}
+
+static const char *ast2600_pinctrl_get_group_name(struct udevice *dev,
+ unsigned selector)
+{
+ debug("PINCTRL: get_(function/group)_name %u\n", selector);
+
+ return ast2600_groups[selector].group_name;
+}
+
+static int ast2600_pinctrl_group_set(struct udevice *dev, unsigned selector, unsigned func_selector)
+{
+ struct ast2600_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct aspeed_group_config *config;
+ const struct aspeed_sig_desc *descs;
+ u32 ctrl_reg = (u32)priv->scu;
+ u32 i;
+
+ debug("PINCTRL: group_set <%u, %u>\n", selector, func_selector);
+ if (selector >= ARRAY_SIZE(ast2600_groups))
+ return -EINVAL;
+
+ config = &ast2600_groups[selector];
+ for (i = 0; i < config->ndescs; i++) {
+ descs = &config->descs[i];
+ if (descs->clr)
+ clrbits_le32((u32)ctrl_reg + descs->offset, descs->reg_set);
+ else
+ setbits_le32((u32)ctrl_reg + descs->offset, descs->reg_set);
+ }
+
+ return 0;
+}
+
+static struct pinctrl_ops ast2600_pinctrl_ops = {
+ .set_state = pinctrl_generic_set_state,
+ .get_groups_count = ast2600_pinctrl_get_groups_count,
+ .get_group_name = ast2600_pinctrl_get_group_name,
+ .get_functions_count = ast2600_pinctrl_get_groups_count,
+ .get_function_name = ast2600_pinctrl_get_group_name,
+ .pinmux_group_set = ast2600_pinctrl_group_set,
+};
+
+static const struct udevice_id ast2600_pinctrl_ids[] = {
+ { .compatible = "aspeed,g6-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_aspeed) = {
+ .name = "aspeed_ast2600_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = ast2600_pinctrl_ids,
+ .priv_auto = sizeof(struct ast2600_pinctrl_priv),
+ .ops = &ast2600_pinctrl_ops,
+ .probe = ast2600_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/pinctrl-apple.c b/drivers/pinctrl/pinctrl-apple.c
new file mode 100644
index 00000000000..62476358c34
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-apple.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/apple.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <linux/bitfield.h>
+
+struct apple_pinctrl_priv {
+ void *base;
+ int pin_count;
+};
+
+#define REG_GPIO(x) (4 * (x))
+#define REG_GPIO_DATA BIT(0)
+#define REG_GPIO_MODE GENMASK(3, 1)
+#define REG_GPIO_OUT 1
+#define REG_GPIO_PERIPH GENMASK(6, 5)
+#define REG_GPIO_INPUT_ENABLE BIT(9)
+
+static void apple_pinctrl_config_pin(struct apple_pinctrl_priv *priv,
+ unsigned pin, u32 clr, u32 set)
+{
+ unsigned reg = REG_GPIO(pin);
+ u32 old, new;
+
+ old = readl(priv->base + REG_GPIO(pin));
+ new = (old & ~clr) | set;
+ writel(new, priv->base + reg);
+}
+
+static int apple_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+ return !!(readl(priv->base + REG_GPIO(offset)) & REG_GPIO_DATA);
+}
+
+static int apple_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+ apple_pinctrl_config_pin(priv, offset, REG_GPIO_DATA,
+ value ? REG_GPIO_DATA : 0);
+ return 0;
+}
+
+static int apple_gpio_get_direction(struct udevice *dev, unsigned offset)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+ u32 reg = readl(priv->base + REG_GPIO(offset));
+
+ if (FIELD_GET(REG_GPIO_MODE, reg) == REG_GPIO_OUT)
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int apple_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+ apple_pinctrl_config_pin(priv, offset,
+ REG_GPIO_PERIPH | REG_GPIO_MODE,
+ REG_GPIO_INPUT_ENABLE);
+ return 0;
+}
+
+static int apple_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+ u32 set = (value ? REG_GPIO_DATA : 0);
+
+ apple_pinctrl_config_pin(priv, offset, REG_GPIO_DATA |
+ REG_GPIO_PERIPH | REG_GPIO_MODE,
+ set | FIELD_PREP(REG_GPIO_MODE, REG_GPIO_OUT));
+ return 0;
+}
+
+static int apple_gpio_probe(struct udevice *dev)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+ struct gpio_dev_priv *uc_priv;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ uc_priv->bank_name = "gpio";
+ uc_priv->gpio_count = priv->pin_count;
+
+ return 0;
+}
+
+static struct dm_gpio_ops apple_gpio_ops = {
+ .get_value = apple_gpio_get_value,
+ .set_value = apple_gpio_set_value,
+ .get_function = apple_gpio_get_direction,
+ .direction_input = apple_gpio_direction_input,
+ .direction_output = apple_gpio_direction_output,
+};
+
+static struct driver apple_gpio_driver = {
+ .name = "apple_gpio",
+ .id = UCLASS_GPIO,
+ .probe = apple_gpio_probe,
+ .ops = &apple_gpio_ops,
+};
+
+static int apple_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->pin_count;
+}
+
+static const char *apple_pinctrl_get_pin_name(struct udevice *dev,
+ unsigned selector)
+{
+ static char pin_name[PINNAME_SIZE];
+
+ snprintf(pin_name, PINNAME_SIZE, "pin%d", selector);
+ return pin_name;
+}
+
+static int apple_pinctrl_get_pin_muxing(struct udevice *dev, unsigned selector,
+ char *buf, int size)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+ if (readl(priv->base + REG_GPIO(selector)) & REG_GPIO_PERIPH)
+ strncpy(buf, "periph", size);
+ else
+ strncpy(buf, "gpio", size);
+ return 0;
+}
+
+static int apple_pinctrl_pinmux_set(struct udevice *dev, unsigned pin_selector,
+ unsigned func_selector)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+ apple_pinctrl_config_pin(priv, pin_selector,
+ REG_GPIO_DATA | REG_GPIO_MODE,
+ FIELD_PREP(REG_GPIO_PERIPH, func_selector) |
+ REG_GPIO_INPUT_ENABLE);
+ return 0;
+}
+
+static int apple_pinctrl_pinmux_property_set(struct udevice *dev,
+ u32 pinmux_group)
+{
+ unsigned pin_selector = APPLE_PIN(pinmux_group);
+ unsigned func_selector = APPLE_FUNC(pinmux_group);
+ int ret;
+
+ ret = apple_pinctrl_pinmux_set(dev, pin_selector, func_selector);
+ return ret ? ret : pin_selector;
+}
+
+static int apple_pinctrl_probe(struct udevice *dev)
+{
+ struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
+ struct udevice *child;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -EINVAL;
+
+ if (!dev_read_phandle_with_args(dev, "gpio-ranges",
+ NULL, 3, 0, &args))
+ priv->pin_count = args.args[2];
+
+ device_bind(dev, &apple_gpio_driver, "apple_gpio", NULL,
+ dev_ofnode(dev), &child);
+
+ return 0;
+}
+
+static struct pinctrl_ops apple_pinctrl_ops = {
+ .set_state = pinctrl_generic_set_state,
+ .get_pins_count = apple_pinctrl_get_pins_count,
+ .get_pin_name = apple_pinctrl_get_pin_name,
+ .pinmux_set = apple_pinctrl_pinmux_set,
+ .pinmux_property_set = apple_pinctrl_pinmux_property_set,
+ .get_pin_muxing = apple_pinctrl_get_pin_muxing,
+};
+
+static const struct udevice_id apple_pinctrl_ids[] = {
+ { .compatible = "apple,pinctrl" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_apple) = {
+ .name = "apple_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = apple_pinctrl_ids,
+ .priv_auto = sizeof(struct apple_pinctrl_priv),
+ .ops = &apple_pinctrl_ops,
+ .probe = apple_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index fe7a59d4313..509e2a80e9a 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -5,8 +5,12 @@
* Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander
* based on Linux driver : pinctrl/pinctrl-stmfx.c
*/
+
+#define LOG_CATEGORY UCLASS_PINCTRL
+
#include <common.h>
#include <dm.h>
+#include <log.h>
#include <i2c.h>
#include <asm/gpio.h>
#include <dm/device.h>
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
index b3142bf4e1f..3ddeaf4adcb 100644
--- a/drivers/power/regulator/scmi_regulator.c
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2020-2021 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
#include <common.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/ram/stm32mp1/Makefile b/drivers/ram/stm32mp1/Makefile
index e1e9135603a..71ded6bed40 100644
--- a/drivers/ram/stm32mp1/Makefile
+++ b/drivers/ram/stm32mp1/Makefile
@@ -8,7 +8,6 @@ obj-y += stm32mp1_ddr.o
obj-$(CONFIG_STM32MP1_DDR_INTERACTIVE) += stm32mp1_interactive.o
obj-$(CONFIG_STM32MP1_DDR_TESTS) += stm32mp1_tests.o
-obj-$(CONFIG_STM32MP1_DDR_TUNING) += stm32mp1_tuning.o
ifneq ($(DDR_INTERACTIVE),)
CFLAGS_stm32mp1_interactive.o += -DCONFIG_STM32MP1_DDR_INTERACTIVE_FORCE=y
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
index 0457166b127..4d78aa5cb13 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -68,7 +68,6 @@ struct reg_desc {
#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
-#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
@@ -178,22 +177,6 @@ static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
DDRPHY_REG_TIMING(mr3),
};
-#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
-static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = {
- DDRPHY_REG_CAL(dx0dllcr),
- DDRPHY_REG_CAL(dx0dqtr),
- DDRPHY_REG_CAL(dx0dqstr),
- DDRPHY_REG_CAL(dx1dllcr),
- DDRPHY_REG_CAL(dx1dqtr),
- DDRPHY_REG_CAL(dx1dqstr),
- DDRPHY_REG_CAL(dx2dllcr),
- DDRPHY_REG_CAL(dx2dqtr),
- DDRPHY_REG_CAL(dx2dqstr),
- DDRPHY_REG_CAL(dx3dllcr),
- DDRPHY_REG_CAL(dx3dqtr),
- DDRPHY_REG_CAL(dx3dqstr),
-};
-
/**************************************************************
* DYNAMIC REGISTERS: only used for debug purpose (read/modify)
**************************************************************/
@@ -218,12 +201,24 @@ static const struct reg_desc ddrphy_dyn[] = {
DDRPHY_REG_DYN(zq0sr1),
DDRPHY_REG_DYN(dx0gsr0),
DDRPHY_REG_DYN(dx0gsr1),
+ DDRPHY_REG_DYN(dx0dllcr),
+ DDRPHY_REG_DYN(dx0dqtr),
+ DDRPHY_REG_DYN(dx0dqstr),
DDRPHY_REG_DYN(dx1gsr0),
DDRPHY_REG_DYN(dx1gsr1),
+ DDRPHY_REG_DYN(dx1dllcr),
+ DDRPHY_REG_DYN(dx1dqtr),
+ DDRPHY_REG_DYN(dx1dqstr),
DDRPHY_REG_DYN(dx2gsr0),
DDRPHY_REG_DYN(dx2gsr1),
+ DDRPHY_REG_DYN(dx2dllcr),
+ DDRPHY_REG_DYN(dx2dqtr),
+ DDRPHY_REG_DYN(dx2dqstr),
DDRPHY_REG_DYN(dx3gsr0),
DDRPHY_REG_DYN(dx3gsr1),
+ DDRPHY_REG_DYN(dx3dllcr),
+ DDRPHY_REG_DYN(dx3dqtr),
+ DDRPHY_REG_DYN(dx3dqstr),
};
#define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn)
@@ -240,7 +235,6 @@ enum reg_type {
REG_MAP,
REGPHY_REG,
REGPHY_TIMING,
- REGPHY_CAL,
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
/* dynamic registers => managed in driver or not changed,
* can be dumped in interactive mode
@@ -264,8 +258,6 @@ struct ddr_reg_info {
enum base_type base;
};
-#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
-
const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
"static", ddr_reg, DDRCTL_REG_REG_SIZE, DDR_BASE},
@@ -279,8 +271,6 @@ const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
"static", ddrphy_reg, DDRPHY_REG_REG_SIZE, DDRPHY_BASE},
[REGPHY_TIMING] = {
"timing", ddrphy_timing, DDRPHY_REG_TIMING_SIZE, DDRPHY_BASE},
-[REGPHY_CAL] = {
- "cal", ddrphy_cal, DDRPHY_REG_CAL_SIZE, DDRPHY_BASE},
#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
[REG_DYN] = {
"dyn", ddr_dyn, DDR_REG_DYN_SIZE, DDR_BASE},
@@ -456,9 +446,6 @@ static u32 get_par_addr(const struct stm32mp1_ddr_config *config,
case REGPHY_TIMING:
par_addr = (u32)&config->p_timing;
break;
- case REGPHY_CAL:
- par_addr = (u32)&config->p_cal;
- break;
case REG_DYN:
case REGPHY_DYN:
case REG_TYPE_NB:
@@ -570,7 +557,7 @@ static void ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
(u32)&phy->pgsr, pgsr, ret);
}
-void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
+static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir)
{
pir |= DDRPHYC_PIR_INIT;
writel(pir, &phy->pir);
@@ -639,7 +626,7 @@ static void wait_operating_mode(struct ddr_info *priv, int mode)
log_debug("[0x%08x] stat = 0x%08x\n", (u32)&priv->ctl->stat, stat);
}
-void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
+static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
{
start_sw_done(ctl);
/* quasi-dynamic register update*/
@@ -650,8 +637,8 @@ void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
wait_sw_done_ack(ctl);
}
-void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
- u32 rfshctl3, u32 pwrctl)
+static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
+ u32 rfshctl3, u32 pwrctl)
{
start_sw_done(ctl);
if (!(rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH))
@@ -774,8 +761,6 @@ start:
*/
set_reg(priv, REGPHY_REG, &config->p_reg);
set_reg(priv, REGPHY_TIMING, &config->p_timing);
- if (config->p_cal_present)
- set_reg(priv, REGPHY_CAL, &config->p_cal);
if (INTERACTIVE(STEP_PHY_INIT))
goto start;
@@ -810,32 +795,32 @@ start:
wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
- if (config->p_cal_present) {
- log_debug("DDR DQS training skipped.\n");
- } else {
- log_debug("DDR DQS training : ");
+ log_debug("DDR DQS training : ");
/* 8. Disable Auto refresh and power down by setting
* - RFSHCTL3.dis_au_refresh = 1
* - PWRCTL.powerdown_en = 0
* - DFIMISC.dfiinit_complete_en = 0
*/
- stm32mp1_refresh_disable(priv->ctl);
+ stm32mp1_refresh_disable(priv->ctl);
/* 9. Program PUBL PGCR to enable refresh during training and rank to train
* not done => keep the programed value in PGCR
*/
/* 10. configure PUBL PIR register to specify which training step to run */
- /* warning : RVTRN is not supported by this PUBL */
- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+ /* RVTRN is excuted only on LPDDR2/LPDDR3 */
+ if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
+ pir = DDRPHYC_PIR_QSTRN;
+ else
+ pir = DDRPHYC_PIR_QSTRN | DDRPHYC_PIR_RVTRN;
+ stm32mp1_ddrphy_init(priv->phy, pir);
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
- ddrphy_idone_wait(priv->phy);
+ ddrphy_idone_wait(priv->phy);
/* 12. set back registers in step 8 to the orginal values if desidered */
- stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
- config->c_reg.pwrctl);
- } /* if (config->p_cal_present) */
+ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+ config->c_reg.pwrctl);
/* enable uMCTL2 AXI port 0 and 1 */
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
index 4998f044394..861efff92be 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -140,21 +140,6 @@ struct stm32mp1_ddrphy_timing {
u32 mr3;
};
-struct stm32mp1_ddrphy_cal {
- u32 dx0dllcr;
- u32 dx0dqtr;
- u32 dx0dqstr;
- u32 dx1dllcr;
- u32 dx1dqtr;
- u32 dx1dqstr;
- u32 dx2dllcr;
- u32 dx2dqtr;
- u32 dx2dqstr;
- u32 dx3dllcr;
- u32 dx3dqtr;
- u32 dx3dqstr;
-};
-
struct stm32mp1_ddr_info {
const char *name;
u32 speed; /* in kHZ */
@@ -169,16 +154,9 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrctrl_perf c_perf;
struct stm32mp1_ddrphy_reg p_reg;
struct stm32mp1_ddrphy_timing p_timing;
- struct stm32mp1_ddrphy_cal p_cal;
- bool p_cal_present;
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
-void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, u32 pir);
-void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl);
-void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
- u32 rfshctl3,
- u32 pwrctl);
void stm32mp1_ddr_init(
struct ddr_info *priv,
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
index 3c8885a9657..f1a26e31f6c 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
@@ -6,8 +6,9 @@
#ifndef _RAM_STM32MP1_DDR_REGS_H
#define _RAM_STM32MP1_DDR_REGS_H
-/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
#include <linux/bitops.h>
+
+/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
struct stm32mp1_ddrctl {
u32 mstr ; /* 0x0 Master*/
u32 stat; /* 0x4 Operating Mode Status*/
@@ -238,6 +239,7 @@ struct stm32mp1_ddrphy {
#define DDRCTRL_MSTR_LPDDR2 BIT(2)
#define DDRCTRL_MSTR_LPDDR3 BIT(3)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT 12
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL (0 << 12)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF (1 << 12)
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER (2 << 12)
@@ -275,25 +277,6 @@ struct stm32mp1_ddrphy {
#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
-#define DDRCTRL_DBG1_DIS_HIF BIT(1)
-
-#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)
-#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28)
-#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26)
-#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK(12, 8)
-#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK(4, 0)
-#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \
- (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \
- DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY)
-#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \
- (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \
- DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \
- DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH)
-
-#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0)
-
-#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0)
-
#define DDRCTRL_SWCTL_SW_DONE BIT(0)
#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0)
@@ -309,13 +292,9 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_PIR_DRAMRST BIT(5)
#define DDRPHYC_PIR_DRAMINIT BIT(6)
#define DDRPHYC_PIR_QSTRN BIT(7)
+#define DDRPHYC_PIR_RVTRN BIT(8)
#define DDRPHYC_PIR_ICPC BIT(16)
#define DDRPHYC_PIR_ZCALBYP BIT(30)
-#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7)
-
-#define DDRPHYC_PGCR_DFTCMP BIT(2)
-#define DDRPHYC_PGCR_PDDISDX BIT(24)
-#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK(28, 25)
#define DDRPHYC_PGSR_IDONE BIT(0)
#define DDRPHYC_PGSR_DTERR BIT(5)
@@ -324,43 +303,6 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_PGSR_RVERR BIT(8)
#define DDRPHYC_PGSR_RVEIRR BIT(9)
-#define DDRPHYC_DLLGCR_BPS200 BIT(23)
-
-#define DDRPHYC_ACDLLCR_DLLDIS BIT(31)
-
-#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0)
-#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0
-#define DDRPHYC_ZQ0CRN_ZDEN BIT(28)
-
-#define DDRPHYC_DXNGCR_DXEN BIT(0)
-
-#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30)
-#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31)
-#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
-#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
-
-#define DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit) (4 * (bit))
-#define DDRPHYC_DXNDQTR_DQDLY_MASK GENMASK(3, 0)
-#define DDRPHYC_DXNDQTR_DQDLY_LOW_MASK GENMASK(1, 0)
-#define DDRPHYC_DXNDQTR_DQDLY_HIGH_MASK GENMASK(3, 2)
-
-#define DDRPHYC_DXNDQSTR_DQSDLY_MASK GENMASK(22, 20)
-#define DDRPHYC_DXNDQSTR_DQSDLY_SHIFT 20
-#define DDRPHYC_DXNDQSTR_DQSNDLY_MASK GENMASK(25, 23)
-#define DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT 23
-#define DDRPHYC_DXNDQSTR_R0DGSL_MASK GENMASK(2, 0)
-#define DDRPHYC_DXNDQSTR_R0DGSL_SHIFT 0
-#define DDRPHYC_DXNDQSTR_R0DGPS_MASK GENMASK(13, 12)
-#define DDRPHYC_DXNDQSTR_R0DGPS_SHIFT 12
-
-#define DDRPHYC_BISTRR_BDXSEL_MASK GENMASK(22, 19)
-#define DDRPHYC_BISTRR_BDXSEL_SHIFT 19
-
-#define DDRPHYC_BISTGSR_BDDONE BIT(0)
-#define DDRPHYC_BISTGSR_BDXERR BIT(2)
-
-#define DDRPHYC_BISTWCSR_DXWCNT_SHIFT 16
-
/* PWR registers */
#define PWR_CR3 0x00C
#define PWR_CR3_DDRSRDIS BIT(11)
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
index 8c2310ac906..f0fe7e61e33 100644
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -32,7 +32,6 @@ enum ddr_command {
DDR_CMD_NEXT,
DDR_CMD_GO,
DDR_CMD_TEST,
- DDR_CMD_TUNING,
DDR_CMD_UNKNOWN,
};
@@ -60,9 +59,6 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc)
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = "test",
#endif
-#ifdef CONFIG_STM32MP1_DDR_TUNING
- [DDR_CMD_TUNING] = "tuning",
-#endif
};
/* min and max number of argument */
const char cmd_arg[DDR_CMD_UNKNOWN][2] = {
@@ -79,9 +75,6 @@ enum ddr_command stm32mp1_get_command(char *cmd, int argc)
#ifdef CONFIG_STM32MP1_DDR_TESTS
[DDR_CMD_TEST] = { 0, 255 },
#endif
-#ifdef CONFIG_STM32MP1_DDR_TUNING
- [DDR_CMD_TUNING] = { 0, 255 },
-#endif
};
int i;
@@ -111,7 +104,7 @@ static void stm32mp1_do_usage(void)
"help displays help\n"
"info displays DDR information\n"
"info <param> <val> changes DDR information\n"
- " with <param> = step, name, size, speed or cal\n"
+ " with <param> = step, name, size or speed\n"
"freq displays the DDR PHY frequency in kHz\n"
"freq <freq> changes the DDR PHY frequency\n"
"param [type|reg] prints input parameters\n"
@@ -126,13 +119,10 @@ static void stm32mp1_do_usage(void)
#ifdef CONFIG_STM32MP1_DDR_TESTS
"test [help] | <n> [...] lists (with help) or executes test <n>\n"
#endif
-#ifdef CONFIG_STM32MP1_DDR_TUNING
- "tuning [help] | <n> [...] lists (with help) or execute tuning <n>\n"
-#endif
"\nwith for [type|reg]:\n"
" all registers if absent\n"
" <type> = ctl, phy\n"
- " or one category (static, timing, map, perf, cal, dyn)\n"
+ " or one category (static, timing, map, perf, dyn)\n"
" <reg> = name of the register\n"
};
@@ -165,7 +155,6 @@ static void stm32mp1_do_info(struct ddr_info *priv,
printf("name = %s\n", config->info.name);
printf("size = 0x%x\n", config->info.size);
printf("speed = %d kHz\n", config->info.speed);
- printf("cal = %d\n", config->p_cal_present);
return;
}
@@ -214,16 +203,6 @@ static void stm32mp1_do_info(struct ddr_info *priv,
}
return;
}
- if (!strcmp(argv[1], "cal")) {
- if (strict_strtoul(argv[2], 10, &value) < 0 ||
- (value != 0 && value != 1)) {
- printf("invalid value %s\n", argv[2]);
- } else {
- config->p_cal_present = value;
- printf("cal = %d\n", config->p_cal_present);
- }
- return;
- }
printf("argument %s invalid\n", argv[1]);
}
@@ -322,7 +301,7 @@ end:
return step;
}
-#if defined(CONFIG_STM32MP1_DDR_TESTS) || defined(CONFIG_STM32MP1_DDR_TUNING)
+#if defined(CONFIG_STM32MP1_DDR_TESTS)
static const char * const s_result[] = {
[TEST_PASSED] = "Pass",
[TEST_FAILED] = "Failed",
@@ -479,16 +458,6 @@ bool stm32mp1_ddr_interactive(void *priv,
stm32mp1_ddr_subcmd(priv, argc, argv, test, test_nb);
break;
#endif
-
-#ifdef CONFIG_STM32MP1_DDR_TUNING
- case DDR_CMD_TUNING:
- if (!stm32mp1_check_step(step, STEP_DDR_READY))
- continue;
- stm32mp1_ddr_subcmd(priv, argc, argv,
- tuning, tuning_nb);
- break;
-#endif
-
default:
break;
}
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index 98fa1f4f118..49b1262461b 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -16,6 +16,12 @@
#include <asm/io.h>
#include <dm/device_compat.h>
#include "stm32mp1_ddr.h"
+#include "stm32mp1_ddr_regs.h"
+
+/* DDR subsystem configuration */
+struct stm32mp1_ddr_cfg {
+ u8 nb_bytes; /* MEMC_DRAM_DATA_WIDTH */
+};
static const char *const clkname[] = {
"ddrc1",
@@ -82,7 +88,7 @@ static ofnode stm32mp1_ddr_get_ofnode(struct udevice *dev)
return dev_ofnode(dev);
}
-static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
+static int stm32mp1_ddr_setup(struct udevice *dev)
{
struct ddr_info *priv = dev_get_priv(dev);
int ret;
@@ -95,26 +101,22 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
{ .name = x, \
.offset = offsetof(struct stm32mp1_ddr_config, y), \
.size = sizeof(config.y) / sizeof(u32), \
- .present = z, \
}
#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
-#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
const struct {
const char *name; /* name in DT */
const u32 offset; /* offset in config struct */
const u32 size; /* size of parameters */
- bool * const present; /* presence indication for opt */
} param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
CTL_PARAM(map),
CTL_PARAM(perf),
PHY_PARAM(reg),
- PHY_PARAM(timing),
- PHY_PARAM_OPT(cal)
+ PHY_PARAM(timing)
};
config.info.speed = ofnode_read_u32_default(node, "st,mem-speed", 0);
@@ -133,25 +135,11 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
param[idx].size);
dev_dbg(dev, "%s: %s[0x%x] = %d\n", __func__,
param[idx].name, param[idx].size, ret);
- if (ret &&
- (ret != -FDT_ERR_NOTFOUND || !param[idx].present)) {
+ if (ret) {
dev_err(dev, "Cannot read %s, error=%d\n",
param[idx].name, ret);
return -EINVAL;
}
- if (param[idx].present) {
- /* save presence of optional parameters */
- *param[idx].present = true;
- if (ret == -FDT_ERR_NOTFOUND) {
- *param[idx].present = false;
-#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
- /* reset values if used later */
- memset((void *)((u32)&config +
- param[idx].offset),
- 0, param[idx].size * sizeof(u32));
-#endif
- }
- }
}
ret = clk_get_by_name(dev, "axidcg", &axidcg);
@@ -183,6 +171,183 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
return 0;
}
+static u8 get_data_bus_width(struct stm32mp1_ddrctl *ctl)
+{
+ u32 reg = readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK;
+ u8 data_bus_width = reg >> DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT;
+
+ return data_bus_width;
+}
+
+static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count bank address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap1);
+ /* addrmap1.addrmap_bank_b1 */
+ val = (reg & GENMASK(5, 0)) >> 0;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b2 */
+ val = (reg & GENMASK(13, 8)) >> 8;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b3 */
+ val = (reg & GENMASK(21, 16)) >> 16;
+ if (val <= 31)
+ bits++;
+
+ return bits;
+}
+
+static u8 get_nb_col(struct stm32mp1_ddrctl *ctl, u8 data_bus_width)
+{
+ u8 bits;
+ u32 reg, val;
+
+ /* Count column address bits, start at 2 for b0 and b1 (fixed) */
+ bits = 2;
+
+ reg = readl(&ctl->addrmap2);
+ /* addrmap2.addrmap_col_b2 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b3 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b4 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b5 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap3);
+ /* addrmap3.addrmap_col_b6 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b7 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b8 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b9 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap4);
+ /* addrmap4.addrmap_col_b10 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap4.addrmap_col_b11 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+
+ /*
+ * column bits shift up:
+ * 1 when half the data bus is used (data_bus_width = 1)
+ * 2 when a quarter the data bus is used (data_bus_width = 2)
+ * nothing to do for full data bus (data_bus_width = 0)
+ */
+ bits += data_bus_width;
+
+ return bits;
+}
+
+static u8 get_nb_row(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count row address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap5);
+ /* addrmap5.addrmap_row_b0 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b1 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b2_10 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 11)
+ bits += 9;
+ else
+ printf("warning: addrmap5.addrmap_row_b2_10 not supported\n");
+ /* addrmap5.addrmap_row_b11 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 11)
+ bits++;
+
+ reg = readl(&ctl->addrmap6);
+ /* addrmap6.addrmap_row_b12 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b13 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b14 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b15 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ return bits;
+}
+
+/*
+ * stm32mp1_ddr_size
+ *
+ * Get the current DRAM size from the DDR CTL registers
+ *
+ * @return: DRAM size
+ */
+u32 stm32mp1_ddr_size(struct udevice *dev)
+{
+ u8 nb_bit;
+ u32 ddr_size;
+ u8 data_bus_width;
+ struct ddr_info *priv = dev_get_priv(dev);
+ struct stm32mp1_ddrctl *ctl = priv->ctl;
+ struct stm32mp1_ddr_cfg *cfg = (struct stm32mp1_ddr_cfg *)dev_get_driver_data(dev);
+ const u8 nb_bytes = cfg->nb_bytes;
+
+ data_bus_width = get_data_bus_width(ctl);
+ nb_bit = get_nb_bank(ctl) + get_nb_col(ctl, data_bus_width) +
+ get_nb_row(ctl);
+ if (nb_bit > 32) {
+ nb_bit = 32;
+ debug("invalid DDR configuration: %d bits\n", nb_bit);
+ }
+
+ ddr_size = (nb_bytes >> data_bus_width) << nb_bit;
+ if (ddr_size > STM32_DDR_SIZE) {
+ ddr_size = STM32_DDR_SIZE;
+ debug("invalid DDR configuration: size = %x\n", ddr_size);
+ }
+
+ return ddr_size;
+}
+
static int stm32mp1_ddr_probe(struct udevice *dev)
{
struct ddr_info *priv = dev_get_priv(dev);
@@ -209,8 +374,8 @@ static int stm32mp1_ddr_probe(struct udevice *dev)
return log_ret(ret);
}
- ofnode node = stm32mp1_ddr_get_ofnode(dev);
- priv->info.size = ofnode_read_u32_default(node, "st,mem-size", 0);
+ priv->info.size = stm32mp1_ddr_size(dev);
+
return 0;
}
@@ -227,8 +392,12 @@ static struct ram_ops stm32mp1_ddr_ops = {
.get_info = stm32mp1_ddr_get_info,
};
+static const struct stm32mp1_ddr_cfg stm32mp15x_ddr_cfg = {
+ .nb_bytes = 4,
+};
+
static const struct udevice_id stm32mp1_ddr_ids[] = {
- { .compatible = "st,stm32mp1-ddr" },
+ { .compatible = "st,stm32mp1-ddr", .data = (ulong)&stm32mp15x_ddr_cfg},
{ }
};
diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.h b/drivers/ram/stm32mp1/stm32mp1_tests.h
index 55f5d6d93bc..8436780790f 100644
--- a/drivers/ram/stm32mp1/stm32mp1_tests.h
+++ b/drivers/ram/stm32mp1/stm32mp1_tests.h
@@ -28,7 +28,4 @@ struct test_desc {
extern const struct test_desc test[];
extern const int test_nb;
-extern const struct test_desc tuning[];
-extern const int tuning_nb;
-
#endif
diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c
deleted file mode 100644
index c8cd7c3ceaf..00000000000
--- a/drivers/ram/stm32mp1/stm32mp1_tuning.c
+++ /dev/null
@@ -1,1540 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- */
-
-#define LOG_CATEGORY UCLASS_RAM
-
-#include <common.h>
-#include <console.h>
-#include <clk.h>
-#include <log.h>
-#include <ram.h>
-#include <rand.h>
-#include <reset.h>
-#include <asm/io.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/iopoll.h>
-
-#include "stm32mp1_ddr_regs.h"
-#include "stm32mp1_ddr.h"
-#include "stm32mp1_tests.h"
-
-#define MAX_DQS_PHASE_IDX _144deg
-#define MAX_DQS_UNIT_IDX 7
-#define MAX_GSL_IDX 5
-#define MAX_GPS_IDX 3
-
-/* Number of bytes used in this SW. ( min 1--> max 4). */
-#define NUM_BYTES 4
-
-enum dqs_phase_enum {
- _36deg = 0,
- _54deg = 1,
- _72deg = 2,
- _90deg = 3,
- _108deg = 4,
- _126deg = 5,
- _144deg = 6
-};
-
-/* BIST Result struct */
-struct BIST_result {
- /* Overall test result:
- * 0 Fail (any bit failed) ,
- * 1 Success (All bits success)
- */
- bool test_result;
- /* 1: true, all fail / 0: False, not all bits fail */
- bool all_bits_fail;
- bool bit_i_test_result[8]; /* 0 fail / 1 success */
-};
-
-/* a struct that defines tuning parameters of a byte. */
-struct tuning_position {
- u8 phase; /* DQS phase */
- u8 unit; /* DQS unit delay */
- u32 bits_delay; /* Bits deskew in this byte */
-};
-
-/* 36deg, 54deg, 72deg, 90deg, 108deg, 126deg, 144deg */
-const u8 dx_dll_phase[7] = {3, 2, 1, 0, 14, 13, 12};
-
-static u8 BIST_error_max = 1;
-static u32 BIST_seed = 0x1234ABCD;
-
-static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl)
-{
- u32 data_bus = readl(&ctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK;
- u8 nb_bytes = NUM_BYTES;
-
- switch (data_bus) {
- case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
- nb_bytes /= 2;
- break;
- case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
- nb_bytes /= 4;
- break;
- default:
- break;
- }
-
- return nb_bytes;
-}
-
-static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl)
-{
- /* Count bank address bits */
- u8 bits = 0;
- u32 reg, val;
-
- reg = readl(&ctl->addrmap1);
- /* addrmap1.addrmap_bank_b1 */
- val = (reg & GENMASK(5, 0)) >> 0;
- if (val <= 31)
- bits++;
- /* addrmap1.addrmap_bank_b2 */
- val = (reg & GENMASK(13, 8)) >> 8;
- if (val <= 31)
- bits++;
- /* addrmap1.addrmap_bank_b3 */
- val = (reg & GENMASK(21, 16)) >> 16;
- if (val <= 31)
- bits++;
-
- return bits;
-}
-
-static u8 get_nb_col(struct stm32mp1_ddrctl *ctl)
-{
- u8 bits;
- u32 reg, val;
-
- /* Count column address bits, start at 2 for b0 and b1 (fixed) */
- bits = 2;
-
- reg = readl(&ctl->addrmap2);
- /* addrmap2.addrmap_col_b2 */
- val = (reg & GENMASK(3, 0)) >> 0;
- if (val <= 7)
- bits++;
- /* addrmap2.addrmap_col_b3 */
- val = (reg & GENMASK(11, 8)) >> 8;
- if (val <= 7)
- bits++;
- /* addrmap2.addrmap_col_b4 */
- val = (reg & GENMASK(19, 16)) >> 16;
- if (val <= 7)
- bits++;
- /* addrmap2.addrmap_col_b5 */
- val = (reg & GENMASK(27, 24)) >> 24;
- if (val <= 7)
- bits++;
-
- reg = readl(&ctl->addrmap3);
- /* addrmap3.addrmap_col_b6 */
- val = (reg & GENMASK(3, 0)) >> 0;
- if (val <= 7)
- bits++;
- /* addrmap3.addrmap_col_b7 */
- val = (reg & GENMASK(11, 8)) >> 8;
- if (val <= 7)
- bits++;
- /* addrmap3.addrmap_col_b8 */
- val = (reg & GENMASK(19, 16)) >> 16;
- if (val <= 7)
- bits++;
- /* addrmap3.addrmap_col_b9 */
- val = (reg & GENMASK(27, 24)) >> 24;
- if (val <= 7)
- bits++;
-
- reg = readl(&ctl->addrmap4);
- /* addrmap4.addrmap_col_b10 */
- val = (reg & GENMASK(3, 0)) >> 0;
- if (val <= 7)
- bits++;
- /* addrmap4.addrmap_col_b11 */
- val = (reg & GENMASK(11, 8)) >> 8;
- if (val <= 7)
- bits++;
-
- return bits;
-}
-
-static u8 get_nb_row(struct stm32mp1_ddrctl *ctl)
-{
- /* Count row address bits */
- u8 bits = 0;
- u32 reg, val;
-
- reg = readl(&ctl->addrmap5);
- /* addrmap5.addrmap_row_b0 */
- val = (reg & GENMASK(3, 0)) >> 0;
- if (val <= 11)
- bits++;
- /* addrmap5.addrmap_row_b1 */
- val = (reg & GENMASK(11, 8)) >> 8;
- if (val <= 11)
- bits++;
- /* addrmap5.addrmap_row_b2_10 */
- val = (reg & GENMASK(19, 16)) >> 16;
- if (val <= 11)
- bits += 9;
- else
- printf("warning: addrmap5.addrmap_row_b2_10 not supported\n");
- /* addrmap5.addrmap_row_b11 */
- val = (reg & GENMASK(27, 24)) >> 24;
- if (val <= 11)
- bits++;
-
- reg = readl(&ctl->addrmap6);
- /* addrmap6.addrmap_row_b12 */
- val = (reg & GENMASK(3, 0)) >> 0;
- if (val <= 7)
- bits++;
- /* addrmap6.addrmap_row_b13 */
- val = (reg & GENMASK(11, 8)) >> 8;
- if (val <= 7)
- bits++;
- /* addrmap6.addrmap_row_b14 */
- val = (reg & GENMASK(19, 16)) >> 16;
- if (val <= 7)
- bits++;
- /* addrmap6.addrmap_row_b15 */
- val = (reg & GENMASK(27, 24)) >> 24;
- if (val <= 7)
- bits++;
-
- return bits;
-}
-
-static void itm_soft_reset(struct stm32mp1_ddrphy *phy)
-{
- stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
-}
-
-/* Read DQ unit delay register and provides the retrieved value for DQS
- * We are assuming that we have the same delay when clocking
- * by DQS and when clocking by DQSN
- */
-static u8 DQ_unit_index(struct stm32mp1_ddrphy *phy, u8 byte, u8 bit)
-{
- u32 index;
- u32 addr = DXNDQTR(phy, byte);
-
- /* We are assuming that we have the same delay when clocking by DQS
- * and when clocking by DQSN : use only the low bits
- */
- index = (readl(addr) >> DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit))
- & DDRPHYC_DXNDQTR_DQDLY_LOW_MASK;
-
- log_debug("[%x]: %x => DQ unit index = %x\n", addr, readl(addr), index);
-
- return index;
-}
-
-/* Sets the DQS phase delay for a byte lane.
- *phase delay is specified by giving the index of the desired delay
- * in the dx_dll_phase array.
- */
-static void DQS_phase_delay(struct stm32mp1_ddrphy *phy, u8 byte, u8 phase_idx)
-{
- u8 sdphase_val = 0;
-
- /* Write DXNDLLCR.SDPHASE = dx_dll_phase(phase_index); */
- sdphase_val = dx_dll_phase[phase_idx];
- clrsetbits_le32(DXNDLLCR(phy, byte),
- DDRPHYC_DXNDLLCR_SDPHASE_MASK,
- sdphase_val << DDRPHYC_DXNDLLCR_SDPHASE_SHIFT);
-}
-
-/* Sets the DQS unit delay for a byte lane.
- * unit delay is specified by giving the index of the desired delay
- * for dgsdly and dqsndly (same value).
- */
-static void DQS_unit_delay(struct stm32mp1_ddrphy *phy,
- u8 byte, u8 unit_dly_idx)
-{
- /* Write the same value in DXNDQSTR.DQSDLY and DXNDQSTR.DQSNDLY */
- clrsetbits_le32(DXNDQSTR(phy, byte),
- DDRPHYC_DXNDQSTR_DQSDLY_MASK |
- DDRPHYC_DXNDQSTR_DQSNDLY_MASK,
- (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSDLY_SHIFT) |
- (unit_dly_idx << DDRPHYC_DXNDQSTR_DQSNDLY_SHIFT));
-
- /* After changing this value, an ITM soft reset (PIR.ITMSRST=1,
- * plus PIR.INIT=1) must be issued.
- */
- stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
-}
-
-/* Sets the DQ unit delay for a bit line in particular byte lane.
- * unit delay is specified by giving the desired delay
- */
-static void set_DQ_unit_delay(struct stm32mp1_ddrphy *phy,
- u8 byte, u8 bit,
- u8 dq_delay_index)
-{
- u8 dq_bit_delay_val = dq_delay_index | (dq_delay_index << 2);
-
- /* same value on delay for clock DQ an DQS_b */
- clrsetbits_le32(DXNDQTR(phy, byte),
- DDRPHYC_DXNDQTR_DQDLY_MASK
- << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit),
- dq_bit_delay_val << DDRPHYC_DXNDQTR_DQDLY_SHIFT(bit));
-}
-
-static void set_r0dgsl_delay(struct stm32mp1_ddrphy *phy,
- u8 byte, u8 r0dgsl_idx)
-{
- clrsetbits_le32(DXNDQSTR(phy, byte),
- DDRPHYC_DXNDQSTR_R0DGSL_MASK,
- r0dgsl_idx << DDRPHYC_DXNDQSTR_R0DGSL_SHIFT);
-}
-
-static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy,
- u8 byte, u8 r0dgps_idx)
-{
- clrsetbits_le32(DXNDQSTR(phy, byte),
- DDRPHYC_DXNDQSTR_R0DGPS_MASK,
- r0dgps_idx << DDRPHYC_DXNDQSTR_R0DGPS_SHIFT);
-}
-
-/* Basic BIST configuration for data lane tests. */
-static void config_BIST(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy)
-{
- u8 nb_bank = get_nb_bank(ctl);
- u8 nb_row = get_nb_row(ctl);
- u8 nb_col = get_nb_col(ctl);
-
- /* Selects the SDRAM bank address to be used during BIST. */
- u32 bbank = 0;
- /* Selects the SDRAM row address to be used during BIST. */
- u32 brow = 0;
- /* Selects the SDRAM column address to be used during BIST. */
- u32 bcol = 0;
- /* Selects the value by which the SDRAM address is incremented
- * for each write/read access.
- */
- u32 bainc = 0x00000008;
- /* Specifies the maximum SDRAM rank to be used during BIST.
- * The default value is set to maximum ranks minus 1.
- * must be 0 with single rank
- */
- u32 bmrank = 0;
- /* Selects the SDRAM rank to be used during BIST.
- * must be 0 with single rank
- */
- u32 brank = 0;
-
- /* Specifies the maximum SDRAM bank address to be used during
- * BIST before the address & increments to the next rank.
- */
- u32 bmbank = (1 << nb_bank) - 1;
- /* Specifies the maximum SDRAM row address to be used during
- * BIST before the address & increments to the next bank.
- */
- u32 bmrow = (1 << nb_row) - 1;
- /* Specifies the maximum SDRAM column address to be used during
- * BIST before the address & increments to the next row.
- */
- u32 bmcol = (1 << nb_col) - 1;
-
- u32 bmode_conf = 0x00000001; /* DRam mode */
- u32 bdxen_conf = 0x00000001; /* BIST on Data byte */
- u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */
-
- /*Setup BIST for DRAM mode, and LFSR-random data pattern.*/
- /*Write BISTRR.BMODE = 1?b1;*/
- /*Write BISTRR.BDXEN = 1?b1;*/
- /*Write BISTRR.BDPAT = 2?b10;*/
-
- /* reset BIST */
- writel(0x3, &phy->bistrr);
-
- writel((bmode_conf << 3) | (bdxen_conf << 14) | (bdpat_conf << 17),
- &phy->bistrr);
-
- /*Setup BIST Word Count*/
- /*Write BISTWCR.BWCNT = 16?b0008;*/
- writel(0x00000200, &phy->bistwcr); /* A multiple of BL/2 */
-
- writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0);
- writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1);
- writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2);
-}
-
-/* Select the Byte lane to be tested by BIST. */
-static void BIST_datx8_sel(struct stm32mp1_ddrphy *phy, u8 datx8)
-{
- clrsetbits_le32(&phy->bistrr,
- DDRPHYC_BISTRR_BDXSEL_MASK,
- datx8 << DDRPHYC_BISTRR_BDXSEL_SHIFT);
-
- /*(For example, selecting Byte Lane 3, BISTRR.BDXSEL = 4?b0011)*/
- /* Write BISTRR.BDXSEL = datx8; */
-}
-
-/* Perform BIST Write_Read test on a byte lane and return test result. */
-static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte,
- struct BIST_result *bist)
-{
- bool result = true; /* BIST_SUCCESS */
- u32 cnt = 0;
- u32 error = 0;
- u32 val;
- int ret;
-
- bist->test_result = true;
-
-run:
- itm_soft_reset(phy);
-
- /*Perform BIST Reset*/
- /* Write BISTRR.BINST = 3?b011; */
- clrsetbits_le32(&phy->bistrr,
- 0x00000007,
- 0x00000003);
-
- /*Re-seed LFSR*/
- /* Write BISTLSR.SEED = 32'h1234ABCD; */
- if (BIST_seed)
- writel(BIST_seed, &phy->bistlsr);
- else
- writel(rand(), &phy->bistlsr);
-
- /* some delay to reset BIST */
- udelay(10);
-
- /*Perform BIST Run*/
- clrsetbits_le32(&phy->bistrr,
- 0x00000007,
- 0x00000001);
- /* Write BISTRR.BINST = 3?b001; */
-
- /* poll on BISTGSR.BDONE and wait max 1000 us */
- ret = readl_poll_timeout(&phy->bistgsr, val,
- val & DDRPHYC_BISTGSR_BDDONE, 1000);
-
- if (ret < 0) {
- printf("warning: BIST timeout\n");
- result = false; /* BIST_FAIL; */
- /*Perform BIST Stop */
- clrsetbits_le32(&phy->bistrr, 0x00000007, 0x00000002);
- } else {
- /*Check if received correct number of words*/
- /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
- if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT)
- == readl(&phy->bistwcr)) {
- /*Determine if there is a data comparison error*/
- /* if (Read BISTGSR.BDXERR = 1?b0) */
- if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
- result = false; /* BIST_FAIL; */
- else
- result = true; /* BIST_SUCCESS; */
- } else {
- result = false; /* BIST_FAIL; */
- }
- }
-
- /* loop while success */
- cnt++;
- if (result && cnt != 1000)
- goto run;
-
- if (!result)
- error++;
-
- if (error < BIST_error_max) {
- if (cnt != 1000)
- goto run;
- bist->test_result = true;
- } else {
- bist->test_result = false;
- }
-}
-
-/* After running the deskew algo, this function applies the new DQ delays
- * by reading them from the array "deskew_delay"and writing in PHY registers.
- * The bits that are not deskewed parfectly (too much skew on them,
- * or data eye very wide) are marked in the array deskew_non_converge.
- */
-static void apply_deskew_results(struct stm32mp1_ddrphy *phy, u8 byte,
- u8 deskew_delay[NUM_BYTES][8],
- u8 deskew_non_converge[NUM_BYTES][8])
-{
- u8 bit_i;
- u8 index;
-
- for (bit_i = 0; bit_i < 8; bit_i++) {
- set_DQ_unit_delay(phy, byte, bit_i, deskew_delay[byte][bit_i]);
- index = DQ_unit_index(phy, byte, bit_i);
- log_debug("Byte %d ; bit %d : The new DQ delay (%d) index=%d [delta=%d, 3 is the default]",
- byte, bit_i, deskew_delay[byte][bit_i],
- index, index - 3);
- printf("Byte %d, bit %d, DQ delay = %d",
- byte, bit_i, deskew_delay[byte][bit_i]);
- if (deskew_non_converge[byte][bit_i] == 1)
- log_debug(" - not converged : still more skew");
- printf("\n");
- }
-}
-
-/* DQ Bit de-skew algorithm.
- * Deskews data lines as much as possible.
- * 1. Add delay to DQS line until finding the failure
- * (normally a hold time violation)
- * 2. Reduce DQS line by small steps until finding the very first time
- * we go back to "Pass" condition.
- * 3. For each DQ line, Reduce DQ delay until finding the very first failure
- * (normally a hold time fail)
- * 4. When all bits are at their first failure delay, we can consider them
- * aligned.
- * Handle conrer situation (Can't find Pass-fail, or fail-pass transitions
- * at any step)
- * TODO Provide a return Status. Improve doc
- */
-static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy, char *string)
-{
- /* New DQ delay value (index), set during Deskew algo */
- u8 deskew_delay[NUM_BYTES][8];
- /*If there is still skew on a bit, mark this bit. */
- u8 deskew_non_converge[NUM_BYTES][8];
- struct BIST_result result;
- s8 dqs_unit_delay_index = 0;
- u8 datx8 = 0;
- u8 bit_i = 0;
- s8 phase_idx = 0;
- s8 bit_i_delay_index = 0;
- u8 success = 0;
- struct tuning_position last_right_ok;
- u8 force_stop = 0;
- u8 fail_found;
- u8 error = 0;
- u8 nb_bytes = get_nb_bytes(ctl);
- /* u8 last_pass_dqs_unit = 0; */
-
- memset(deskew_delay, 0, sizeof(deskew_delay));
- memset(deskew_non_converge, 0, sizeof(deskew_non_converge));
-
- /*Disable DQS Drift Compensation*/
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
- /*Disable all bytes*/
- /* Disable automatic power down of DLL and IOs when disabling
- * a byte (To avoid having to add programming and delay
- * for a DLL re-lock when later re-enabling a disabled Byte Lane)
- */
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
-
- /* Disable all data bytes */
- clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
-
- /* Config the BIST block */
- config_BIST(ctl, phy);
- log_debug("BIST Config done.\n");
-
- /* Train each byte */
- for (datx8 = 0; datx8 < nb_bytes; datx8++) {
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- datx8 + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- log_debug("\n======================\n");
- log_debug("Start deskew byte %d .\n", datx8);
- log_debug("======================\n");
- /* Enable Byte (DXNGCR, bit DXEN) */
- setbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN);
-
- /* Select the byte lane for comparison of read data */
- BIST_datx8_sel(phy, datx8);
-
- /* Set all DQDLYn to maximum value. All bits within the byte
- * will be delayed with DQSTR = 2 instead of max = 3
- * to avoid inter bits fail influence
- */
- writel(0xAAAAAAAA, DXNDQTR(phy, datx8));
-
- /* Set the DQS phase delay to 90 DEG (default).
- * What is defined here is the index of the desired config
- * in the PHASE array.
- */
- phase_idx = _90deg;
-
- /* Set DQS unit delay to the max value. */
- dqs_unit_delay_index = MAX_DQS_UNIT_IDX;
- DQS_unit_delay(phy, datx8, dqs_unit_delay_index);
- DQS_phase_delay(phy, datx8, phase_idx);
-
- /* Issue a DLL soft reset */
- clrbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST);
- setbits_le32(DXNDLLCR(phy, datx8), DDRPHYC_DXNDLLCR_DLLSRST);
-
- /* Test this typical init condition */
- BIST_test(phy, datx8, &result);
- success = result.test_result;
-
- /* If the test pass in this typical condition,
- * start the algo with it.
- * Else, look for Pass init condition
- */
- if (!success) {
- log_debug("Fail at init condtion. Let's look for a good init condition.\n");
- success = 0; /* init */
- /* Make sure we start with a PASS condition before
- * looking for a fail condition.
- * Find the first PASS PHASE condition
- */
-
- /* escape if we find a PASS */
- log_debug("increase Phase idx\n");
- while (!success && (phase_idx <= MAX_DQS_PHASE_IDX)) {
- DQS_phase_delay(phy, datx8, phase_idx);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- phase_idx++;
- }
- /* if ended with success
- * ==>> Restore the fist success condition
- */
- if (success)
- phase_idx--; /* because it ended with ++ */
- }
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- datx8 + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- /* We couldn't find a successful condition, its seems
- * we have hold violation, lets try reduce DQS_unit Delay
- */
- if (!success) {
- /* We couldn't find a successful condition, its seems
- * we have hold violation, lets try reduce DQS_unit
- * Delay
- */
- log_debug("Still fail. Try decrease DQS Unit delay\n");
-
- phase_idx = 0;
- dqs_unit_delay_index = 0;
- DQS_phase_delay(phy, datx8, phase_idx);
-
- /* escape if we find a PASS */
- while (!success &&
- (dqs_unit_delay_index <=
- MAX_DQS_UNIT_IDX)) {
- DQS_unit_delay(phy, datx8,
- dqs_unit_delay_index);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- dqs_unit_delay_index++;
- }
- if (success) {
- /* Restore the first success condition*/
- dqs_unit_delay_index--;
- /* last_pass_dqs_unit = dqs_unit_delay_index;*/
- DQS_unit_delay(phy, datx8,
- dqs_unit_delay_index);
- } else {
- /* No need to continue,
- * there is no pass region.
- */
- force_stop = 1;
- }
- }
-
- /* There is an initial PASS condition
- * Look for the first failing condition by PHASE stepping.
- * This part of the algo can finish without converging.
- */
- if (force_stop) {
- printf("Result: Failed ");
- printf("[Cannot Deskew lines, ");
- printf("there is no PASS region]\n");
- error++;
- continue;
- }
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- datx8 + 1, nb_bytes, error);
- return TEST_FAILED;
- }
-
- log_debug("there is a pass region for phase idx %d\n",
- phase_idx);
- log_debug("Step1: Find the first failing condition\n");
- /* Look for the first failing condition by PHASE stepping.
- * This part of the algo can finish without converging.
- */
-
- /* escape if we find a fail (hold time violation)
- * condition at any bit or if out of delay range.
- */
- while (success && (phase_idx <= MAX_DQS_PHASE_IDX)) {
- DQS_phase_delay(phy, datx8, phase_idx);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- phase_idx++;
- }
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- datx8 + 1, nb_bytes, error);
- return TEST_FAILED;
- }
-
- /* if the loop ended with a failing condition at any bit,
- * lets look for the first previous success condition by unit
- * stepping (minimal delay)
- */
- if (!success) {
- log_debug("Fail region (PHASE) found phase idx %d\n",
- phase_idx);
- log_debug("Let's look for first success by DQS Unit steps\n");
- /* This part, the algo always converge */
- phase_idx--;
-
- /* escape if we find a success condition
- * or if out of delay range.
- */
- while (!success && dqs_unit_delay_index >= 0) {
- DQS_unit_delay(phy, datx8,
- dqs_unit_delay_index);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- dqs_unit_delay_index--;
- }
- /* if the loop ended with a success condition,
- * the last delay Right OK (before hold violation)
- * condition is then defined as following:
- */
- if (success) {
- /* Hold the dely parameters of the the last
- * delay Right OK condition.
- * -1 to get back to current condition
- */
- last_right_ok.phase = phase_idx;
- /*+1 to get back to current condition */
- last_right_ok.unit = dqs_unit_delay_index + 1;
- last_right_ok.bits_delay = 0xFFFFFFFF;
- log_debug("Found %d\n", dqs_unit_delay_index);
- } else {
- /* the last OK condition is then with the
- * previous phase_idx.
- * -2 instead of -1 because at the last
- * iteration of the while(),
- * we incremented phase_idx
- */
- last_right_ok.phase = phase_idx - 1;
- /* Nominal+1. Because we want the previous
- * delay after reducing the phase delay.
- */
- last_right_ok.unit = 1;
- last_right_ok.bits_delay = 0xFFFFFFFF;
- log_debug("Not Found : try previous phase %d\n",
- phase_idx - 1);
-
- DQS_phase_delay(phy, datx8, phase_idx - 1);
- dqs_unit_delay_index = 0;
- success = true;
- while (success &&
- (dqs_unit_delay_index <
- MAX_DQS_UNIT_IDX)) {
- DQS_unit_delay(phy, datx8,
- dqs_unit_delay_index);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- dqs_unit_delay_index++;
- log_debug("dqs_unit_delay_index = %d, result = %d\n",
- dqs_unit_delay_index, success);
- }
-
- if (!success) {
- last_right_ok.unit =
- dqs_unit_delay_index - 1;
- } else {
- last_right_ok.unit = 0;
- log_debug("ERROR: failed region not FOUND");
- }
- }
- } else {
- /* we can't find a failing condition at all bits
- * ==> Just hold the last test condition
- * (the max DQS delay)
- * which is the most likely,
- * the closest to a hold violation
- * If we can't find a Fail condition after
- * the Pass region, stick at this position
- * In order to have max chances to find a fail
- * when reducing DQ delays.
- */
- last_right_ok.phase = MAX_DQS_PHASE_IDX;
- last_right_ok.unit = MAX_DQS_UNIT_IDX;
- last_right_ok.bits_delay = 0xFFFFFFFF;
- log_debug("Can't find the a fail condition\n");
- }
-
- /* step 2:
- * if we arrive at this stage, it means that we found the last
- * Right OK condition (by tweeking the DQS delay). Or we simply
- * pushed DQS delay to the max
- * This means that by reducing the delay on some DQ bits,
- * we should find a failing condition.
- */
- printf("Byte %d, DQS unit = %d, phase = %d\n",
- datx8, last_right_ok.unit, last_right_ok.phase);
- log_debug("Step2, unit = %d, phase = %d, bits delay=%x\n",
- last_right_ok.unit, last_right_ok.phase,
- last_right_ok.bits_delay);
-
- /* Restore the last_right_ok condtion. */
- DQS_unit_delay(phy, datx8, last_right_ok.unit);
- DQS_phase_delay(phy, datx8, last_right_ok.phase);
- writel(last_right_ok.bits_delay, DXNDQTR(phy, datx8));
-
- /* train each bit
- * reduce delay on each bit, and perform a write/read test
- * and stop at the very first time it fails.
- * the goal is the find the first failing condition
- * for each bit.
- * When we achieve this condition< for all the bits,
- * we are sure they are aligned (+/- step resolution)
- */
- fail_found = 0;
- for (bit_i = 0; bit_i < 8; bit_i++) {
- if (ctrlc()) {
- sprintf(string,
- "interrupted at byte %d/%d, error=%d",
- datx8 + 1, nb_bytes, error);
- return error;
- }
- log_debug("deskewing bit %d:\n", bit_i);
- success = 1; /* init */
- /* Set all DQDLYn to maximum value.
- * Only bit_i will be down-delayed
- * ==> if we have a fail, it will be definitely
- * from bit_i
- */
- writel(0xFFFFFFFF, DXNDQTR(phy, datx8));
- /* Arriving at this stage,
- * we have a success condition with delay = 3;
- */
- bit_i_delay_index = 3;
-
- /* escape if bit delay is out of range or
- * if a fatil occurs
- */
- while ((bit_i_delay_index >= 0) && success) {
- set_DQ_unit_delay(phy, datx8,
- bit_i,
- bit_i_delay_index);
- BIST_test(phy, datx8, &result);
- success = result.test_result;
- bit_i_delay_index--;
- }
-
- /* if escape with a fail condition
- * ==> save this position for bit_i
- */
- if (!success) {
- /* save the delay position.
- * Add 1 because the while loop ended with a --,
- * and that we need to hold the last success
- * delay
- */
- deskew_delay[datx8][bit_i] =
- bit_i_delay_index + 2;
- if (deskew_delay[datx8][bit_i] > 3)
- deskew_delay[datx8][bit_i] = 3;
-
- /* A flag that states we found at least a fail
- * at one bit.
- */
- fail_found = 1;
- log_debug("Fail found on bit %d, for delay = %d => deskew[%d][%d] = %d\n",
- bit_i, bit_i_delay_index + 1,
- datx8, bit_i,
- deskew_delay[datx8][bit_i]);
- } else {
- /* if we can find a success condition by
- * back-delaying this bit, just set the delay
- * to 0 (the best deskew
- * possible) and mark the bit.
- */
- deskew_delay[datx8][bit_i] = 0;
- /* set a flag that will be used later
- * in the report.
- */
- deskew_non_converge[datx8][bit_i] = 1;
- log_debug("Fail not found on bit %d => deskew[%d][%d] = %d\n",
- bit_i, datx8, bit_i,
- deskew_delay[datx8][bit_i]);
- }
- }
- log_debug("**********byte %d tuning complete************\n",
- datx8);
- /* If we can't find any failure by back delaying DQ lines,
- * hold the default values
- */
- if (!fail_found) {
- for (bit_i = 0; bit_i < 8; bit_i++)
- deskew_delay[datx8][bit_i] = 0;
- log_debug("The Deskew algorithm can't converge, there is too much margin in your design. Good job!\n");
- }
-
- apply_deskew_results(phy, datx8, deskew_delay,
- deskew_non_converge);
- /* Restore nominal value for DQS delay */
- DQS_phase_delay(phy, datx8, 3);
- DQS_unit_delay(phy, datx8, 3);
- /* disable byte after byte bits deskew */
- clrbits_le32(DXNGCR(phy, datx8), DDRPHYC_DXNGCR_DXEN);
- } /* end of byte deskew */
-
- /* re-enable all data bytes */
- setbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
- setbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
- setbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
- setbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
-
- if (error) {
- sprintf(string, "error = %d", error);
- return TEST_FAILED;
- }
-
- return TEST_PASSED;
-} /* end function */
-
-/* Trim DQS timings and set it in the centre of data eye.
- * Look for a PPPPF region, then look for a FPPP region and finally select
- * the mid of the FPPPPPF region
- */
-static enum test_result eye_training(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy, char *string)
-{
- /*Stores the DQS trim values (PHASE index, unit index) */
- u8 eye_training_val[NUM_BYTES][2];
- u8 byte = 0;
- struct BIST_result result;
- s8 dqs_unit_delay_index = 0;
- s8 phase_idx = 0;
- s8 dqs_unit_delay_index_pass = 0;
- s8 phase_idx_pass = 0;
- u8 success = 0;
- u8 left_phase_bound_found, right_phase_bound_found;
- u8 left_unit_bound_found, right_unit_bound_found;
- u8 left_bound_found, right_bound_found;
- struct tuning_position left_bound, right_bound;
- u8 error = 0;
- u8 nb_bytes = get_nb_bytes(ctl);
-
- /*Disable DQS Drift Compensation*/
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
- /*Disable all bytes*/
- /* Disable automatic power down of DLL and IOs when disabling a byte
- * (To avoid having to add programming and delay
- * for a DLL re-lock when later re-enabling a disabled Byte Lane)
- */
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
-
- /*Disable all data bytes */
- clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
-
- /* Config the BIST block */
- config_BIST(ctl, phy);
-
- for (byte = 0; byte < nb_bytes; byte++) {
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- byte + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- right_bound.phase = 0;
- right_bound.unit = 0;
-
- left_bound.phase = 0;
- left_bound.unit = 0;
-
- left_phase_bound_found = 0;
- right_phase_bound_found = 0;
-
- left_unit_bound_found = 0;
- right_unit_bound_found = 0;
-
- left_bound_found = 0;
- right_bound_found = 0;
-
- /* Enable Byte (DXNGCR, bit DXEN) */
- setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN);
-
- /* Select the byte lane for comparison of read data */
- BIST_datx8_sel(phy, byte);
-
- /* Set DQS phase delay to the nominal value. */
- phase_idx = _90deg;
- phase_idx_pass = phase_idx;
-
- /* Set DQS unit delay to the nominal value. */
- dqs_unit_delay_index = 3;
- dqs_unit_delay_index_pass = dqs_unit_delay_index;
- success = 0;
-
- log_debug("STEP0: Find Init delay\n");
- /* STEP0: Find Init delay: a delay that put the system
- * in a "Pass" condition then (TODO) update
- * dqs_unit_delay_index_pass & phase_idx_pass
- */
- DQS_unit_delay(phy, byte, dqs_unit_delay_index);
- DQS_phase_delay(phy, byte, phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- /* If we have a fail in the nominal condition */
- if (!success) {
- /* Look at the left */
- while (phase_idx >= 0 && !success) {
- phase_idx--;
- DQS_phase_delay(phy, byte, phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- }
- }
- if (!success) {
- /* if we can't find pass condition,
- * then look at the right
- */
- phase_idx = _90deg;
- while (phase_idx <= MAX_DQS_PHASE_IDX &&
- !success) {
- phase_idx++;
- DQS_phase_delay(phy, byte,
- phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- }
- }
- /* save the pass condition */
- if (success) {
- phase_idx_pass = phase_idx;
- } else {
- printf("Result: Failed ");
- printf("[Cannot DQS timings, ");
- printf("there is no PASS region]\n");
- error++;
- continue;
- }
-
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- byte + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- log_debug("STEP1: Find LEFT PHASE DQS Bound\n");
- /* STEP1: Find LEFT PHASE DQS Bound */
- while ((phase_idx >= 0) &&
- (phase_idx <= MAX_DQS_PHASE_IDX) &&
- !left_phase_bound_found) {
- DQS_unit_delay(phy, byte,
- dqs_unit_delay_index);
- DQS_phase_delay(phy, byte,
- phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
-
- /*TODO: Manage the case were at the beginning
- * there is already a fail
- */
- if (!success) {
- /* the last pass condition */
- left_bound.phase = ++phase_idx;
- left_phase_bound_found = 1;
- } else if (success) {
- phase_idx--;
- }
- }
- if (!left_phase_bound_found) {
- left_bound.phase = 0;
- phase_idx = 0;
- }
- /* If not found, lets take 0 */
-
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- byte + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- log_debug("STEP2: Find UNIT left bound\n");
- /* STEP2: Find UNIT left bound */
- while ((dqs_unit_delay_index >= 0) &&
- !left_unit_bound_found) {
- DQS_unit_delay(phy, byte,
- dqs_unit_delay_index);
- DQS_phase_delay(phy, byte, phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- if (!success) {
- left_bound.unit =
- ++dqs_unit_delay_index;
- left_unit_bound_found = 1;
- left_bound_found = 1;
- } else if (success) {
- dqs_unit_delay_index--;
- }
- }
-
- /* If not found, lets take 0 */
- if (!left_unit_bound_found)
- left_bound.unit = 0;
-
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- byte + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- log_debug("STEP3: Find PHase right bound\n");
- /* STEP3: Find PHase right bound, start with "pass"
- * condition
- */
-
- /* Set DQS phase delay to the pass value. */
- phase_idx = phase_idx_pass;
-
- /* Set DQS unit delay to the pass value. */
- dqs_unit_delay_index = dqs_unit_delay_index_pass;
-
- while ((phase_idx <= MAX_DQS_PHASE_IDX) &&
- !right_phase_bound_found) {
- DQS_unit_delay(phy, byte,
- dqs_unit_delay_index);
- DQS_phase_delay(phy, byte, phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- if (!success) {
- /* the last pass condition */
- right_bound.phase = --phase_idx;
- right_phase_bound_found = 1;
- } else if (success) {
- phase_idx++;
- }
- }
-
- /* If not found, lets take the max value */
- if (!right_phase_bound_found) {
- right_bound.phase = MAX_DQS_PHASE_IDX;
- phase_idx = MAX_DQS_PHASE_IDX;
- }
-
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d, error=%d",
- byte + 1, nb_bytes, error);
- return TEST_FAILED;
- }
- log_debug("STEP4: Find UNIT right bound\n");
- /* STEP4: Find UNIT right bound */
- while ((dqs_unit_delay_index <= MAX_DQS_UNIT_IDX) &&
- !right_unit_bound_found) {
- DQS_unit_delay(phy, byte,
- dqs_unit_delay_index);
- DQS_phase_delay(phy, byte, phase_idx);
- BIST_test(phy, byte, &result);
- success = result.test_result;
- if (!success) {
- right_bound.unit =
- --dqs_unit_delay_index;
- right_unit_bound_found = 1;
- right_bound_found = 1;
- } else if (success) {
- dqs_unit_delay_index++;
- }
- }
- /* If not found, lets take the max value */
- if (!right_unit_bound_found)
- right_bound.unit = MAX_DQS_UNIT_IDX;
-
- /* If we found a regular FAil Pass FAil pattern
- * FFPPPPPPFF
- * OR PPPPPFF Or FFPPPPP
- */
-
- if (left_bound_found || right_bound_found) {
- eye_training_val[byte][0] = (right_bound.phase +
- left_bound.phase) / 2;
- eye_training_val[byte][1] = (right_bound.unit +
- left_bound.unit) / 2;
-
- /* If we already lost 1/2PHASE Tuning,
- * let's try to recover by ++ on unit
- */
- if (((right_bound.phase + left_bound.phase) % 2 == 1) &&
- eye_training_val[byte][1] != MAX_DQS_UNIT_IDX)
- eye_training_val[byte][1]++;
- log_debug("** found phase : %d - %d & unit %d - %d\n",
- right_bound.phase, left_bound.phase,
- right_bound.unit, left_bound.unit);
- log_debug("** calculating mid region: phase: %d unit: %d (nominal is 3)\n",
- eye_training_val[byte][0],
- eye_training_val[byte][1]);
- } else {
- /* PPPPPPPPPP, we're already good.
- * Set nominal values.
- */
- eye_training_val[byte][0] = 3;
- eye_training_val[byte][1] = 3;
- }
- DQS_phase_delay(phy, byte, eye_training_val[byte][0]);
- DQS_unit_delay(phy, byte, eye_training_val[byte][1]);
-
- printf("Byte %d, DQS unit = %d, phase = %d\n",
- byte,
- eye_training_val[byte][1],
- eye_training_val[byte][0]);
- }
-
- if (error) {
- sprintf(string, "error = %d", error);
- return TEST_FAILED;
- }
-
- return TEST_PASSED;
-}
-
-static void display_reg_results(struct stm32mp1_ddrphy *phy, u8 byte)
-{
- u8 i = 0;
-
- printf("Byte %d Dekew result, bit0 delay, bit1 delay...bit8 delay\n ",
- byte);
-
- for (i = 0; i < 8; i++)
- printf("%d ", DQ_unit_index(phy, byte, i));
- printf("\n");
-
- printf("dxndllcr: [%08x] val:%08x\n",
- DXNDLLCR(phy, byte),
- readl(DXNDLLCR(phy, byte)));
- printf("dxnqdstr: [%08x] val:%08x\n",
- DXNDQSTR(phy, byte),
- readl(DXNDQSTR(phy, byte)));
- printf("dxndqtr: [%08x] val:%08x\n",
- DXNDQTR(phy, byte),
- readl(DXNDQTR(phy, byte)));
-}
-
-/* analyse the dgs gating log table, and determine the midpoint.*/
-static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte,
- u8 dqs_gating[NUM_BYTES]
- [MAX_GSL_IDX + 1]
- [MAX_GPS_IDX + 1])
-{
- /* stores the dqs gate values (gsl index, gps index) */
- u8 dqs_gate_values[NUM_BYTES][2];
- u8 gsl_idx, gps_idx = 0;
- u8 left_bound_idx[2] = {0, 0};
- u8 right_bound_idx[2] = {0, 0};
- u8 left_bound_found = 0;
- u8 right_bound_found = 0;
- u8 intermittent = 0;
- u8 value;
-
- for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) {
- for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) {
- value = dqs_gating[byte][gsl_idx][gps_idx];
- if (value == 1 && left_bound_found == 0) {
- left_bound_idx[0] = gsl_idx;
- left_bound_idx[1] = gps_idx;
- left_bound_found = 1;
- } else if (value == 0 &&
- left_bound_found == 1 &&
- !right_bound_found) {
- if (gps_idx == 0) {
- right_bound_idx[0] = gsl_idx - 1;
- right_bound_idx[1] = MAX_GPS_IDX;
- } else {
- right_bound_idx[0] = gsl_idx;
- right_bound_idx[1] = gps_idx - 1;
- }
- right_bound_found = 1;
- } else if (value == 1 &&
- right_bound_found == 1) {
- intermittent = 1;
- }
- }
- }
-
- /* if only ppppppp is found, there is no mid region. */
- if (left_bound_idx[0] == 0 && left_bound_idx[1] == 0 &&
- right_bound_idx[0] == 0 && right_bound_idx[1] == 0)
- intermittent = 1;
-
- /*if we found a regular fail pass fail pattern ffppppppff
- * or pppppff or ffppppp
- */
- if (!intermittent) {
- /*if we found a regular fail pass fail pattern ffppppppff
- * or pppppff or ffppppp
- */
- if (left_bound_found || right_bound_found) {
- log_debug("idx0(%d): %d %d idx1(%d) : %d %d\n",
- left_bound_found,
- right_bound_idx[0], left_bound_idx[0],
- right_bound_found,
- right_bound_idx[1], left_bound_idx[1]);
- dqs_gate_values[byte][0] =
- (right_bound_idx[0] + left_bound_idx[0]) / 2;
- dqs_gate_values[byte][1] =
- (right_bound_idx[1] + left_bound_idx[1]) / 2;
- /* if we already lost 1/2gsl tuning,
- * let's try to recover by ++ on gps
- */
- if (((right_bound_idx[0] +
- left_bound_idx[0]) % 2 == 1) &&
- dqs_gate_values[byte][1] != MAX_GPS_IDX)
- dqs_gate_values[byte][1]++;
- /* if we already lost 1/2gsl tuning and gps is on max*/
- else if (((right_bound_idx[0] +
- left_bound_idx[0]) % 2 == 1) &&
- dqs_gate_values[byte][1] == MAX_GPS_IDX) {
- dqs_gate_values[byte][1] = 0;
- dqs_gate_values[byte][0]++;
- }
- /* if we have gsl left and write limit too close
- * (difference=1)
- */
- if (((right_bound_idx[0] - left_bound_idx[0]) == 1)) {
- dqs_gate_values[byte][1] = (left_bound_idx[1] +
- right_bound_idx[1] +
- 4) / 2;
- if (dqs_gate_values[byte][1] >= 4) {
- dqs_gate_values[byte][0] =
- right_bound_idx[0];
- dqs_gate_values[byte][1] -= 4;
- } else {
- dqs_gate_values[byte][0] =
- left_bound_idx[0];
- }
- }
- log_debug("*******calculating mid region: system latency: %d phase: %d********\n",
- dqs_gate_values[byte][0],
- dqs_gate_values[byte][1]);
- log_debug("*******the nominal values were system latency: 0 phase: 2*******\n");
- }
- } else {
- /* if intermitant, restore defaut values */
- log_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n");
- dqs_gate_values[byte][0] = 0;
- dqs_gate_values[byte][1] = 2;
- }
- set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
- set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
- printf("Byte %d, R0DGSL = %d, R0DGPS = %d\n",
- byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]);
-
- /* return 0 if intermittent or if both left_bound
- * and right_bound are not found
- */
- return !(intermittent || (left_bound_found && right_bound_found));
-}
-
-static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string)
-{
- /* stores the log of pass/fail */
- u8 dqs_gating[NUM_BYTES][MAX_GSL_IDX + 1][MAX_GPS_IDX + 1];
- u8 byte, gsl_idx, gps_idx = 0;
- struct BIST_result result;
- u8 success = 0;
- u8 nb_bytes = get_nb_bytes(ctl);
-
- memset(dqs_gating, 0x0, sizeof(dqs_gating));
-
- /*disable dqs drift compensation*/
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP);
- /*disable all bytes*/
- /* disable automatic power down of dll and ios when disabling a byte
- * (to avoid having to add programming and delay
- * for a dll re-lock when later re-enabling a disabled byte lane)
- */
- clrbits_le32(&phy->pgcr, DDRPHYC_PGCR_PDDISDX);
-
- /* disable all data bytes */
- clrbits_le32(&phy->dx0gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx1gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx2gcr, DDRPHYC_DXNGCR_DXEN);
- clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
-
- /* config the bist block */
- config_BIST(ctl, phy);
-
- for (byte = 0; byte < nb_bytes; byte++) {
- if (ctrlc()) {
- sprintf(string, "interrupted at byte %d/%d",
- byte + 1, nb_bytes);
- return TEST_FAILED;
- }
- /* enable byte x (dxngcr, bit dxen) */
- setbits_le32(DXNGCR(phy, byte), DDRPHYC_DXNGCR_DXEN);
-
- /* select the byte lane for comparison of read data */
- BIST_datx8_sel(phy, byte);
- for (gsl_idx = 0; gsl_idx <= MAX_GSL_IDX; gsl_idx++) {
- for (gps_idx = 0; gps_idx <= MAX_GPS_IDX; gps_idx++) {
- if (ctrlc()) {
- sprintf(string,
- "interrupted at byte %d/%d",
- byte + 1, nb_bytes);
- return TEST_FAILED;
- }
- /* write cfg to dxndqstr */
- set_r0dgsl_delay(phy, byte, gsl_idx);
- set_r0dgps_delay(phy, byte, gps_idx);
-
- BIST_test(phy, byte, &result);
- success = result.test_result;
- if (success)
- dqs_gating[byte][gsl_idx][gps_idx] = 1;
- itm_soft_reset(phy);
- }
- }
- set_midpoint_read_dqs_gating(phy, byte, dqs_gating);
- /* dummy reads */
- readl(0xc0000000);
- readl(0xc0000000);
- }
-
- /* re-enable drift compensation */
- /* setbits_le32(&phy->pgcr, DDRPHYC_PGCR_DFTCMP); */
- return TEST_PASSED;
-}
-
-/****************************************************************
- * TEST
- ****************************************************************
- */
-static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string, int argc,
- char *argv[])
-{
- u32 rfshctl3 = readl(&ctl->rfshctl3);
- u32 pwrctl = readl(&ctl->pwrctl);
- u32 derateen = readl(&ctl->derateen);
- enum test_result res;
-
- writel(0x0, &ctl->derateen);
- stm32mp1_refresh_disable(ctl);
-
- res = read_dqs_gating(ctl, phy, string);
-
- stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
- writel(derateen, &ctl->derateen);
-
- return res;
-}
-
-static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string, int argc, char *argv[])
-{
- u32 rfshctl3 = readl(&ctl->rfshctl3);
- u32 pwrctl = readl(&ctl->pwrctl);
- u32 derateen = readl(&ctl->derateen);
- enum test_result res;
-
- writel(0x0, &ctl->derateen);
- stm32mp1_refresh_disable(ctl);
-
- res = bit_deskew(ctl, phy, string);
-
- stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
- writel(derateen, &ctl->derateen);
-
- return res;
-}
-
-static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string, int argc, char *argv[])
-{
- u32 rfshctl3 = readl(&ctl->rfshctl3);
- u32 pwrctl = readl(&ctl->pwrctl);
- u32 derateen = readl(&ctl->derateen);
- enum test_result res;
-
- writel(0x0, &ctl->derateen);
- stm32mp1_refresh_disable(ctl);
-
- res = eye_training(ctl, phy, string);
-
- stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
- writel(derateen, &ctl->derateen);
-
- return res;
-}
-
-static enum test_result do_display(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string, int argc, char *argv[])
-{
- int byte;
- u8 nb_bytes = get_nb_bytes(ctl);
-
- for (byte = 0; byte < nb_bytes; byte++)
- display_reg_results(phy, byte);
-
- return TEST_PASSED;
-}
-
-static enum test_result do_bist_config(struct stm32mp1_ddrctl *ctl,
- struct stm32mp1_ddrphy *phy,
- char *string, int argc, char *argv[])
-{
- unsigned long value;
-
- if (argc > 0) {
- if (strict_strtoul(argv[0], 0, &value) < 0) {
- sprintf(string, "invalid nbErr %s", argv[0]);
- return TEST_FAILED;
- }
- BIST_error_max = value;
- }
- if (argc > 1) {
- if (strict_strtoul(argv[1], 0, &value) < 0) {
- sprintf(string, "invalid Seed %s", argv[1]);
- return TEST_FAILED;
- }
- BIST_seed = value;
- }
- printf("Bist.nbErr = %d\n", BIST_error_max);
- if (BIST_seed)
- printf("Bist.Seed = 0x%x\n", BIST_seed);
- else
- printf("Bist.Seed = random\n");
-
- return TEST_PASSED;
-}
-
-/****************************************************************
- * TEST Description
- ****************************************************************
- */
-
-const struct test_desc tuning[] = {
- {do_read_dqs_gating, "Read DQS gating",
- "software read DQS Gating", "", 0 },
- {do_bit_deskew, "Bit de-skew", "", "", 0 },
- {do_eye_training, "Eye Training", "or DQS training", "", 0 },
- {do_display, "Display registers", "", "", 0 },
- {do_bist_config, "Bist config", "[nbErr] [seed]",
- "configure Bist test", 2},
-};
-
-const int tuning_nb = ARRAY_SIZE(tuning);
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
index 1bff8075ee3..ca0135a4203 100644
--- a/drivers/reset/reset-scmi.c
+++ b/drivers/reset/reset-scmi.c
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_RESET
+
#include <common.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c
index dfcb6fd6981..a402a123b6d 100644
--- a/drivers/serial/arm_dcc.c
+++ b/drivers/serial/arm_dcc.c
@@ -51,7 +51,7 @@
#define status_dcc(x) \
__asm__ volatile ("mrc p14, 0, %0, c14, c0, 0\n" : "=r" (x))
-#elif defined(CONFIG_CPU_ARMV8)
+#elif defined(CONFIG_ARM64)
/*
* ARMV8
*/
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 33ddbd6080c..0067576389d 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -24,6 +24,9 @@ struct serial_efi_priv {
bool have_key;
};
+/* Convert a lower-case character to its ctrl-char equivalent */
+#define CTL_CH(c) ((c) - 'a' + 1)
+
int serial_efi_setbrg(struct udevice *dev, int baudrate)
{
return 0;
@@ -49,6 +52,7 @@ static int serial_efi_get_key(struct serial_efi_priv *priv)
static int serial_efi_getc(struct udevice *dev)
{
struct serial_efi_priv *priv = dev_get_priv(dev);
+ char conv_scan[10] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8};
int ret, ch;
ret = serial_efi_get_key(priv);
@@ -63,8 +67,11 @@ static int serial_efi_getc(struct udevice *dev)
* key scan code of 8. Handle this so that backspace works correctly
* in the U-Boot command line.
*/
- if (!ch && priv->key.scan_code == 8)
- ch = 8;
+ if (!ch && priv->key.scan_code < sizeof(conv_scan)) {
+ ch = conv_scan[priv->key.scan_code];
+ if (ch >= 'a')
+ ch -= 'a' - 1;
+ }
debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
return ch;
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 3c9a69598ad..ca49ef73723 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -5,6 +5,7 @@
*/
#include <common.h>
+#include <clock_legacy.h>
#include <clk.h>
#include <dm.h>
#include <fsl_lpuart.h>
@@ -102,13 +103,9 @@ static void lpuart_write32(u32 flags, u32 *addr, u32 val)
}
-#ifndef CONFIG_SYS_CLK_FREQ
-#define CONFIG_SYS_CLK_FREQ 0
-#endif
-
u32 __weak get_lpuart_clk(void)
{
- return CONFIG_SYS_CLK_FREQ;
+ return get_board_sys_clk();
}
#if CONFIG_IS_ENABLED(CLK)
diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index 93e4d38d34c..3e673bde57b 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ * Copyright (C) 2021 Pali Rohár <pali@kernel.org>
*/
#include <common.h>
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index b1a3aa9a297..098298336da 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -17,6 +17,7 @@
#include <errno.h>
#include <fdtdec.h>
#include <dm/device_compat.h>
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -32,6 +33,7 @@
#define QSPI_RD 0x0008 /* Receive Data Register */
#define QSPI_TD 0x000c /* Transmit Data Register */
#define QSPI_SR 0x0010 /* Status Register */
+#define QSPI_SR2 0x0024 /* SAMA7G5 Status Register */
#define QSPI_IER 0x0014 /* Interrupt Enable Register */
#define QSPI_IDR 0x0018 /* Interrupt Disable Register */
#define QSPI_IMR 0x001c /* Interrupt Mask Register */
@@ -46,6 +48,13 @@
#define QSPI_SMR 0x0040 /* Scrambling Mode Register */
#define QSPI_SKR 0x0044 /* Scrambling Key Register */
+#define QSPI_REFRESH 0x0050 /* Refresh Register */
+#define QSPI_WRACNT 0x0054 /* Write Access Counter Register */
+#define QSPI_DLLCFG 0x0058 /* DLL Configuration Register */
+#define QSPI_PCALCFG 0x005C /* Pad Calibration Configuration Register */
+#define QSPI_PCALBP 0x0060 /* Pad Calibration Bypass Register */
+#define QSPI_TOUT 0x0064 /* Timeout Register */
+
#define QSPI_WPMR 0x00E4 /* Write Protection Mode Register */
#define QSPI_WPSR 0x00E8 /* Write Protection Status Register */
@@ -54,7 +63,14 @@
/* Bitfields in QSPI_CR (Control Register) */
#define QSPI_CR_QSPIEN BIT(0)
#define QSPI_CR_QSPIDIS BIT(1)
+#define QSPI_CR_DLLON BIT(2)
+#define QSPI_CR_DLLOFF BIT(3)
+#define QSPI_CR_STPCAL BIT(4)
+#define QSPI_CR_SRFRSH BIT(5)
#define QSPI_CR_SWRST BIT(7)
+#define QSPI_CR_UPDCFG BIT(8)
+#define QSPI_CR_STTFR BIT(9)
+#define QSPI_CR_RTOUT BIT(10)
#define QSPI_CR_LASTXFER BIT(24)
/* Bitfields in QSPI_MR (Mode Register) */
@@ -62,12 +78,15 @@
#define QSPI_MR_LLB BIT(1)
#define QSPI_MR_WDRBT BIT(2)
#define QSPI_MR_SMRM BIT(3)
+#define QSPI_MR_DQSDLYEN BIT(3)
+
#define QSPI_MR_CSMODE_MASK GENMASK(5, 4)
#define QSPI_MR_CSMODE_NOT_RELOADED (0 << 4)
#define QSPI_MR_CSMODE_LASTXFER (1 << 4)
#define QSPI_MR_CSMODE_SYSTEMATICALLY (2 << 4)
#define QSPI_MR_NBBITS_MASK GENMASK(11, 8)
#define QSPI_MR_NBBITS(n) ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
+#define QSPI_MR_OENSD BIT(15)
#define QSPI_MR_DLYBCT_MASK GENMASK(23, 16)
#define QSPI_MR_DLYBCT(n) (((n) << 16) & QSPI_MR_DLYBCT_MASK)
#define QSPI_MR_DLYCS_MASK GENMASK(31, 24)
@@ -81,6 +100,13 @@
#define QSPI_SR_CSR BIT(8)
#define QSPI_SR_CSS BIT(9)
#define QSPI_SR_INSTRE BIT(10)
+#define QSPI_SR_LWRA BIT(11)
+#define QSPI_SR_QITF BIT(12)
+#define QSPI_SR_QITR BIT(13)
+#define QSPI_SR_CSFA BIT(14)
+#define QSPI_SR_CSRA BIT(15)
+#define QSPI_SR_RFRSHD BIT(16)
+#define QSPI_SR_TOUT BIT(17)
#define QSPI_SR_QSPIENS BIT(24)
#define QSPI_SR_CMD_COMPLETED (QSPI_SR_INSTRE | QSPI_SR_CSR)
@@ -93,9 +119,22 @@
#define QSPI_SCR_DLYBS_MASK GENMASK(23, 16)
#define QSPI_SCR_DLYBS(n) (((n) << 16) & QSPI_SCR_DLYBS_MASK)
+/* Bitfields in QSPI_SR2 (SAMA7G5 Status Register) */
+#define QSPI_SR2_SYNCBSY BIT(0)
+#define QSPI_SR2_QSPIENS BIT(1)
+#define QSPI_SR2_CSS BIT(2)
+#define QSPI_SR2_RBUSY BIT(3)
+#define QSPI_SR2_HIDLE BIT(4)
+#define QSPI_SR2_DLOCK BIT(5)
+#define QSPI_SR2_CALBSY BIT(6)
+
+/* Bitfields in QSPI_IAR (Instruction Address Register) */
+#define QSPI_IAR_ADDR GENMASK(31, 0)
+
/* Bitfields in QSPI_ICR (Read/Write Instruction Code Register) */
#define QSPI_ICR_INST_MASK GENMASK(7, 0)
#define QSPI_ICR_INST(inst) (((inst) << 0) & QSPI_ICR_INST_MASK)
+#define QSPI_ICR_INST_MASK_SAMA7G5 GENMASK(15, 0)
#define QSPI_ICR_OPT_MASK GENMASK(23, 16)
#define QSPI_ICR_OPT(opt) (((opt) << 16) & QSPI_ICR_OPT_MASK)
@@ -108,6 +147,9 @@
#define QSPI_IFR_WIDTH_QUAD_IO (4 << 0)
#define QSPI_IFR_WIDTH_DUAL_CMD (5 << 0)
#define QSPI_IFR_WIDTH_QUAD_CMD (6 << 0)
+#define QSPI_IFR_WIDTH_OCT_OUTPUT (7 << 0)
+#define QSPI_IFR_WIDTH_OCT_IO (8 << 0)
+#define QSPI_IFR_WIDTH_OCT_CMD (9 << 0)
#define QSPI_IFR_INSTEN BIT(4)
#define QSPI_IFR_ADDREN BIT(5)
#define QSPI_IFR_OPTEN BIT(6)
@@ -118,19 +160,60 @@
#define QSPI_IFR_OPTL_4BIT (2 << 8)
#define QSPI_IFR_OPTL_8BIT (3 << 8)
#define QSPI_IFR_ADDRL BIT(10)
+#define QSPI_IFR_ADDRL_SAMA7G5 GENMASK(11, 10)
#define QSPI_IFR_TFRTYP_MEM BIT(12)
#define QSPI_IFR_SAMA5D2_WRITE_TRSFR BIT(13)
#define QSPI_IFR_CRM BIT(14)
+#define QSPI_IFR_DDREN BIT(15)
#define QSPI_IFR_NBDUM_MASK GENMASK(20, 16)
#define QSPI_IFR_NBDUM(n) (((n) << 16) & QSPI_IFR_NBDUM_MASK)
+#define QSPI_IFR_END BIT(22)
+#define QSPI_IFR_SMRM BIT(23)
#define QSPI_IFR_APBTFRTYP_READ BIT(24) /* Defined in SAM9X60 */
+#define QSPI_IFR_DQSEN BIT(25)
+#define QSPI_IFR_DDRCMDEN BIT(26)
+#define QSPI_IFR_HFWBEN BIT(27)
+#define QSPI_IFR_PROTTYP GENMASK(29, 28)
+#define QSPI_IFR_PROTTYP_STD_SPI 0
+#define QSPI_IFR_PROTTYP_TWIN_QUAD 1
+#define QSPI_IFR_PROTTYP_OCTAFLASH 2
+#define QSPI_IFR_PROTTYP_HYPERFLASH 3
/* Bitfields in QSPI_SMR (Scrambling Mode Register) */
#define QSPI_SMR_SCREN BIT(0)
#define QSPI_SMR_RVDIS BIT(1)
+#define QSPI_SMR_SCRKL BIT(2)
+
+/* Bitfields in QSPI_REFRESH (Refresh Register) */
+#define QSPI_REFRESH_DELAY_COUNTER GENMASK(31, 0)
+
+/* Bitfields in QSPI_WRACNT (Write Access Counter Register) */
+#define QSPI_WRACNT_NBWRA GENMASK(31, 0)
+
+/* Bitfields in QSPI_DLLCFG (DLL Configuration Register) */
+#define QSPI_DLLCFG_RANGE BIT(0)
+
+/* Bitfields in QSPI_PCALCFG (DLL Pad Calibration Configuration Register) */
+#define QSPI_PCALCFG_AAON BIT(0)
+#define QSPI_PCALCFG_DAPCAL BIT(1)
+#define QSPI_PCALCFG_DIFFPM BIT(2)
+#define QSPI_PCALCFG_CLKDIV GENMASK(6, 4)
+#define QSPI_PCALCFG_CALCNT GENMASK(16, 8)
+#define QSPI_PCALCFG_CALP GENMASK(27, 24)
+#define QSPI_PCALCFG_CALN GENMASK(31, 28)
+
+/* Bitfields in QSPI_PCALBP (DLL Pad Calibration Bypass Register) */
+#define QSPI_PCALBP_BPEN BIT(0)
+#define QSPI_PCALBP_CALPBP GENMASK(11, 8)
+#define QSPI_PCALBP_CALNBP GENMASK(19, 16)
+
+/* Bitfields in QSPI_TOUT (Timeout Register) */
+#define QSPI_TOUT_TCNTM GENMASK(15, 0)
/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
#define QSPI_WPMR_WPEN BIT(0)
+#define QSPI_WPMR_WPITEN BIT(1)
+#define QSPI_WPMR_WPCREN BIT(2)
#define QSPI_WPMR_WPKEY_MASK GENMASK(31, 8)
#define QSPI_WPMR_WPKEY(wpkey) (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
@@ -139,21 +222,61 @@
#define QSPI_WPSR_WPVSRC_MASK GENMASK(15, 8)
#define QSPI_WPSR_WPVSRC(src) (((src) << 8) & QSPI_WPSR_WPVSRC)
+#define ATMEL_QSPI_TIMEOUT 1000000 /* us */
+#define ATMEL_QSPI_SYNC_TIMEOUT 300000 /* us */
+#define QSPI_DLLCFG_THRESHOLD_FREQ 90000000U
+#define QSPI_TOUT_MAX 0xffff
+
+/**
+ * struct atmel_qspi_pcal - Pad Calibration Clock Division
+ * @pclk_rate: peripheral clock rate.
+ * @pclkdiv: calibration clock division. The clock applied to the calibration
+ * cell is divided by pclkdiv + 1.
+ */
+struct atmel_qspi_pcal {
+ u32 pclk_rate;
+ u8 pclk_div;
+};
+
+#define ATMEL_QSPI_PCAL_ARRAY_SIZE 8
+static const struct atmel_qspi_pcal pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE] = {
+ {25000000, 0},
+ {50000000, 1},
+ {75000000, 2},
+ {100000000, 3},
+ {125000000, 4},
+ {150000000, 5},
+ {175000000, 6},
+ {200000000, 7},
+};
+
struct atmel_qspi_caps {
bool has_qspick;
+ bool has_gclk;
bool has_ricr;
+ bool octal;
};
+struct atmel_qspi_priv_ops;
+
struct atmel_qspi {
void __iomem *regs;
void __iomem *mem;
resource_size_t mmap_size;
const struct atmel_qspi_caps *caps;
+ const struct atmel_qspi_priv_ops *ops;
struct udevice *dev;
ulong bus_clk_rate;
u32 mr;
};
+struct atmel_qspi_priv_ops {
+ int (*set_cfg)(struct atmel_qspi *aq, const struct spi_mem_op *op,
+ u32 *offset);
+ int (*transfer)(struct atmel_qspi *aq, const struct spi_mem_op *op,
+ u32 offset);
+};
+
struct atmel_qspi_mode {
u8 cmd_buswidth;
u8 addr_buswidth;
@@ -171,6 +294,19 @@ static const struct atmel_qspi_mode atmel_qspi_modes[] = {
{ 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
};
+static const struct atmel_qspi_mode atmel_qspi_sama7g5_modes[] = {
+ { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI },
+ { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT },
+ { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT },
+ { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO },
+ { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO },
+ { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD },
+ { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
+ { 1, 1, 8, QSPI_IFR_WIDTH_OCT_OUTPUT },
+ { 1, 8, 8, QSPI_IFR_WIDTH_OCT_IO },
+ { 8, 8, 8, QSPI_IFR_WIDTH_OCT_CMD },
+};
+
#ifdef VERBOSE_DEBUG
static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
{
@@ -180,7 +316,7 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
case QSPI_MR:
return "MR";
case QSPI_RD:
- return "MR";
+ return "RD";
case QSPI_TD:
return "TD";
case QSPI_SR:
@@ -193,6 +329,8 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
return "IMR";
case QSPI_SCR:
return "SCR";
+ case QSPI_SR2:
+ return "SR2";
case QSPI_IAR:
return "IAR";
case QSPI_ICR:
@@ -205,6 +343,18 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
return "SMR";
case QSPI_SKR:
return "SKR";
+ case QSPI_REFRESH:
+ return "REFRESH";
+ case QSPI_WRACNT:
+ return "WRACNT";
+ case QSPI_DLLCFG:
+ return "DLLCFG";
+ case QSPI_PCALCFG:
+ return "PCALCFG";
+ case QSPI_PCALBP:
+ return "PCALBP";
+ case QSPI_TOUT:
+ return "TOUT";
case QSPI_WPMR:
return "WPMR";
case QSPI_WPSR:
@@ -272,9 +422,29 @@ static int atmel_qspi_find_mode(const struct spi_mem_op *op)
return -ENOTSUPP;
}
+static int atmel_qspi_sama7g5_find_mode(const struct spi_mem_op *op)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(atmel_qspi_sama7g5_modes); i++)
+ if (atmel_qspi_is_compatible(op, &atmel_qspi_sama7g5_modes[i]))
+ return i;
+
+ return -EOPNOTSUPP;
+}
+
static bool atmel_qspi_supports_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
+ struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
+
+ if (aq->caps->octal) {
+ if (atmel_qspi_sama7g5_find_mode(op) < 0)
+ return false;
+ else
+ return true;
+ }
+
if (atmel_qspi_find_mode(op) < 0)
return false;
@@ -397,24 +567,10 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
return 0;
}
-static int atmel_qspi_exec_op(struct spi_slave *slave,
- const struct spi_mem_op *op)
+static int atmel_qspi_transfer(struct atmel_qspi *aq,
+ const struct spi_mem_op *op, u32 offset)
{
- struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
- u32 sr, imr, offset;
- int err;
-
- /*
- * Check if the address exceeds the MMIO window size. An improvement
- * would be to add support for regular SPI mode and fall back to it
- * when the flash memories overrun the controller's memory space.
- */
- if (op->addr.val + op->data.nbytes > aq->mmap_size)
- return -ENOTSUPP;
-
- err = atmel_qspi_set_cfg(aq, op, &offset);
- if (err)
- return err;
+ u32 sr, imr;
/* Skip to the final steps if there is no data */
if (op->data.nbytes) {
@@ -436,7 +592,341 @@ static int atmel_qspi_exec_op(struct spi_slave *slave,
/* Poll INSTruction End and Chip Select Rise flags. */
imr = QSPI_SR_INSTRE | QSPI_SR_CSR;
return readl_poll_timeout(aq->regs + QSPI_SR, sr, (sr & imr) == imr,
- 1000000);
+ ATMEL_QSPI_TIMEOUT);
+}
+
+static int atmel_qspi_reg_sync(struct atmel_qspi *aq)
+{
+ u32 val;
+
+ return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_SYNCBSY),
+ ATMEL_QSPI_SYNC_TIMEOUT);
+}
+
+static int atmel_qspi_update_config(struct atmel_qspi *aq)
+{
+ int ret;
+
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR);
+ return atmel_qspi_reg_sync(aq);
+}
+
+static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq,
+ const struct spi_mem_op *op, u32 *offset)
+{
+ u32 iar, icr, ifr;
+ int mode, ret;
+
+ iar = 0;
+ icr = FIELD_PREP(QSPI_ICR_INST_MASK_SAMA7G5, op->cmd.opcode);
+ ifr = QSPI_IFR_INSTEN;
+
+ mode = atmel_qspi_sama7g5_find_mode(op);
+ if (mode < 0)
+ return mode;
+ ifr |= atmel_qspi_sama7g5_modes[mode].config;
+
+ if (op->dummy.buswidth && op->dummy.nbytes) {
+ if (op->addr.dtr && op->dummy.dtr && op->data.dtr)
+ ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+ (2 * op->dummy.buswidth));
+ else
+ ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+ op->dummy.buswidth);
+ }
+
+ if (op->addr.buswidth && op->addr.nbytes) {
+ ifr |= FIELD_PREP(QSPI_IFR_ADDRL_SAMA7G5, op->addr.nbytes - 1) |
+ QSPI_IFR_ADDREN;
+ iar = FIELD_PREP(QSPI_IAR_ADDR, op->addr.val);
+ }
+
+ if (op->addr.dtr && op->dummy.dtr && op->data.dtr) {
+ ifr |= QSPI_IFR_DDREN;
+ if (op->cmd.dtr)
+ ifr |= QSPI_IFR_DDRCMDEN;
+ ifr |= QSPI_IFR_DQSEN;
+ }
+
+ if (op->cmd.buswidth == 8 || op->addr.buswidth == 8 ||
+ op->data.buswidth == 8)
+ ifr |= FIELD_PREP(QSPI_IFR_PROTTYP, QSPI_IFR_PROTTYP_OCTAFLASH);
+
+ /* offset of the data access in the QSPI memory space */
+ *offset = iar;
+
+ /* Set data enable */
+ if (op->data.nbytes) {
+ ifr |= QSPI_IFR_DATAEN;
+ if (op->addr.nbytes)
+ ifr |= QSPI_IFR_TFRTYP_MEM;
+ }
+
+ /*
+ * If the QSPI controller is set in regular SPI mode, set it in
+ * Serial Memory Mode (SMM).
+ */
+ if (aq->mr != QSPI_MR_SMM) {
+ atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
+ ret = atmel_qspi_update_config(aq);
+ if (ret)
+ return ret;
+ aq->mr = QSPI_MR_SMM;
+ }
+
+ /* Clear pending interrupts */
+ (void)atmel_qspi_read(aq, QSPI_SR);
+
+ /* Set QSPI Instruction Frame registers */
+ if (op->addr.nbytes && !op->data.nbytes)
+ atmel_qspi_write(iar, aq, QSPI_IAR);
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ atmel_qspi_write(icr, aq, QSPI_RICR);
+ } else {
+ atmel_qspi_write(icr, aq, QSPI_WICR);
+ if (op->data.nbytes)
+ atmel_qspi_write(FIELD_PREP(QSPI_WRACNT_NBWRA,
+ op->data.nbytes),
+ aq, QSPI_WRACNT);
+ }
+
+ atmel_qspi_write(ifr, aq, QSPI_IFR);
+
+ return atmel_qspi_update_config(aq);
+}
+
+static int atmel_qspi_sama7g5_transfer(struct atmel_qspi *aq,
+ const struct spi_mem_op *op, u32 offset)
+{
+ int err;
+ u32 val;
+
+ if (!op->data.nbytes) {
+ /* Start the transfer. */
+ err = atmel_qspi_reg_sync(aq);
+ if (err)
+ return err;
+ atmel_qspi_write(QSPI_CR_STTFR, aq, QSPI_CR);
+
+ return readl_poll_timeout(aq->regs + QSPI_SR, val,
+ val & QSPI_SR_CSRA,
+ ATMEL_QSPI_TIMEOUT);
+ }
+
+ /* Send/Receive data. */
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ memcpy_fromio(op->data.buf.in, aq->mem + offset,
+ op->data.nbytes);
+
+ if (op->addr.nbytes) {
+ err = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_RBUSY),
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (err)
+ return err;
+ }
+ } else {
+ memcpy_toio(aq->mem + offset, op->data.buf.out,
+ op->data.nbytes);
+
+ err = readl_poll_timeout(aq->regs + QSPI_SR, val,
+ val & QSPI_SR_LWRA,
+ ATMEL_QSPI_TIMEOUT);
+ if (err)
+ return err;
+ }
+
+ /* Release the chip-select. */
+ err = atmel_qspi_reg_sync(aq);
+ if (err)
+ return err;
+ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
+
+ return readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_CSRA,
+ ATMEL_QSPI_TIMEOUT);
+}
+
+static int atmel_qspi_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
+ u32 offset;
+ int err;
+
+ /*
+ * Check if the address exceeds the MMIO window size. An improvement
+ * would be to add support for regular SPI mode and fall back to it
+ * when the flash memories overrun the controller's memory space.
+ */
+ if (op->addr.val + op->data.nbytes > aq->mmap_size)
+ return -ENOTSUPP;
+
+ if (op->addr.nbytes > 4)
+ return -EOPNOTSUPP;
+
+ err = aq->ops->set_cfg(aq, op, &offset);
+ if (err)
+ return err;
+
+ return aq->ops->transfer(aq, op, offset);
+}
+
+static int atmel_qspi_set_pad_calibration(struct udevice *bus, uint hz)
+{
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ u32 status, val;
+ int i, ret;
+ u8 pclk_div = 0;
+
+ for (i = 0; i < ATMEL_QSPI_PCAL_ARRAY_SIZE; i++) {
+ if (aq->bus_clk_rate <= pcal[i].pclk_rate) {
+ pclk_div = pcal[i].pclk_div;
+ break;
+ }
+ }
+
+ /*
+ * Use the biggest divider in case the peripheral clock exceeds
+ * 200MHZ.
+ */
+ if (aq->bus_clk_rate > pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_rate)
+ pclk_div = pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_div;
+
+ /* Disable QSPI while configuring the pad calibration. */
+ status = atmel_qspi_read(aq, QSPI_SR2);
+ if (status & QSPI_SR2_QSPIENS) {
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+ }
+
+ /*
+ * The analog circuitry is not shut down at the end of the calibration
+ * and the start-up time is only required for the first calibration
+ * sequence, thus increasing performance. Set the delay between the Pad
+ * calibration analog circuitry and the calibration request to 2us.
+ */
+ atmel_qspi_write(QSPI_PCALCFG_AAON |
+ FIELD_PREP(QSPI_PCALCFG_CLKDIV, pclk_div) |
+ FIELD_PREP(QSPI_PCALCFG_CALCNT,
+ 2 * (aq->bus_clk_rate / 1000000)),
+ aq, QSPI_PCALCFG);
+
+ /* DLL On + start calibration. */
+ atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_DLOCK) &&
+ !(val & QSPI_SR2_CALBSY),
+ ATMEL_QSPI_TIMEOUT);
+
+ /* Refresh analogic blocks every 1 ms.*/
+ atmel_qspi_write(FIELD_PREP(QSPI_REFRESH_DELAY_COUNTER, hz / 1000),
+ aq, QSPI_REFRESH);
+
+ return ret;
+}
+
+static int atmel_qspi_set_gclk(struct udevice *bus, uint hz)
+{
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ struct clk gclk;
+ u32 status, val;
+ int ret;
+
+ /* Disable DLL before setting GCLK */
+ status = atmel_qspi_read(aq, QSPI_SR2);
+ if (status & QSPI_SR2_DLOCK) {
+ atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_DLOCK),
+ ATMEL_QSPI_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+
+ if (hz > QSPI_DLLCFG_THRESHOLD_FREQ)
+ atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG);
+ else
+ atmel_qspi_write(0, aq, QSPI_DLLCFG);
+
+ ret = clk_get_by_name(bus, "gclk", &gclk);
+ if (ret) {
+ dev_err(bus, "Missing QSPI generic clock\n");
+ return ret;
+ }
+
+ ret = clk_disable(&gclk);
+ if (ret)
+ dev_err(bus, "Failed to disable QSPI generic clock\n");
+
+ ret = clk_set_rate(&gclk, hz);
+ if (ret < 0) {
+ dev_err(bus, "Failed to set generic clock rate.\n");
+ return ret;
+ }
+
+ ret = clk_enable(&gclk);
+ if (ret)
+ dev_err(bus, "Failed to enable QSPI generic clock\n");
+ clk_free(&gclk);
+
+ return ret;
+}
+
+static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz)
+{
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ u32 val;
+ int ret;
+
+ ret = atmel_qspi_set_gclk(bus, hz);
+ if (ret)
+ return ret;
+
+ if (aq->caps->octal) {
+ ret = atmel_qspi_set_pad_calibration(bus, hz);
+ if (ret)
+ return ret;
+ } else {
+ atmel_qspi_write(QSPI_CR_DLLON, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ val & QSPI_SR2_DLOCK,
+ ATMEL_QSPI_TIMEOUT);
+ }
+
+ /* Set the QSPI controller by default in Serial Memory Mode */
+ atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
+ ret = atmel_qspi_update_config(aq);
+ if (ret)
+ return ret;
+ aq->mr = QSPI_MR_SMM;
+
+ /* Enable the QSPI controller. */
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ val & QSPI_SR2_QSPIENS,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (aq->caps->octal)
+ ret = readl_poll_timeout(aq->regs + QSPI_SR, val,
+ val & QSPI_SR_RFRSHD,
+ ATMEL_QSPI_TIMEOUT);
+
+ atmel_qspi_write(FIELD_PREP(QSPI_TOUT_TCNTM, QSPI_TOUT_MAX),
+ aq, QSPI_TOUT);
+
+ return ret;
}
static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
@@ -444,6 +934,9 @@ static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
struct atmel_qspi *aq = dev_get_priv(bus);
u32 scr, scbr, mask, new_value;
+ if (aq->caps->has_gclk)
+ return atmel_qspi_sama7g5_set_speed(bus, hz);
+
/* Compute the QSPI baudrate */
scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz);
if (scbr > 0)
@@ -480,6 +973,8 @@ static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
scr = (scr & ~mask) | new_value;
atmel_qspi_write(scr, aq, QSPI_SCR);
+ if (aq->caps->has_gclk)
+ return atmel_qspi_update_config(aq);
return 0;
}
@@ -487,7 +982,7 @@ static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
static int atmel_qspi_enable_clk(struct udevice *dev)
{
struct atmel_qspi *aq = dev_get_priv(dev);
- struct clk pclk, qspick;
+ struct clk pclk, qspick, gclk;
int ret;
ret = clk_get_by_name(dev, "pclk", &pclk);
@@ -517,6 +1012,17 @@ static int atmel_qspi_enable_clk(struct udevice *dev)
if (ret)
dev_err(dev, "Failed to enable QSPI system clock\n");
clk_free(&qspick);
+ } else if (aq->caps->has_gclk) {
+ ret = clk_get_by_name(dev, "gclk", &gclk);
+ if (ret) {
+ dev_err(dev, "Missing QSPI generic clock\n");
+ goto free_pclk;
+ }
+
+ ret = clk_enable(&gclk);
+ if (ret)
+ dev_err(dev, "Failed to enable QSPI system clock\n");
+ clk_free(&gclk);
}
aq->bus_clk_rate = clk_get_rate(&pclk);
@@ -529,8 +1035,18 @@ free_pclk:
return ret;
}
-static void atmel_qspi_init(struct atmel_qspi *aq)
+static int atmel_qspi_init(struct atmel_qspi *aq)
{
+ int ret;
+
+ if (aq->caps->has_gclk) {
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
+ return 0;
+ }
+
/* Reset the QSPI controller */
atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
@@ -540,8 +1056,20 @@ static void atmel_qspi_init(struct atmel_qspi *aq)
/* Enable the QSPI controller */
atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+
+ return 0;
}
+static const struct atmel_qspi_priv_ops atmel_qspi_priv_ops = {
+ .set_cfg = atmel_qspi_set_cfg,
+ .transfer = atmel_qspi_transfer,
+};
+
+static const struct atmel_qspi_priv_ops atmel_qspi_sama7g5_priv_ops = {
+ .set_cfg = atmel_qspi_sama7g5_set_cfg,
+ .transfer = atmel_qspi_sama7g5_transfer,
+};
+
static int atmel_qspi_probe(struct udevice *dev)
{
struct atmel_qspi *aq = dev_get_priv(dev);
@@ -554,6 +1082,11 @@ static int atmel_qspi_probe(struct udevice *dev)
return -EINVAL;
};
+ if (aq->caps->has_gclk)
+ aq->ops = &atmel_qspi_sama7g5_priv_ops;
+ else
+ aq->ops = &atmel_qspi_priv_ops;
+
/* Map the registers */
ret = dev_read_resource_byname(dev, "qspi_base", &res);
if (ret) {
@@ -583,10 +1116,7 @@ static int atmel_qspi_probe(struct udevice *dev)
return ret;
aq->dev = dev;
-
- atmel_qspi_init(aq);
-
- return 0;
+ return atmel_qspi_init(aq);
}
static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
@@ -607,6 +1137,15 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = {
.has_ricr = true,
};
+static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = {
+ .has_gclk = true,
+ .octal = true,
+};
+
+static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = {
+ .has_gclk = true,
+};
+
static const struct udevice_id atmel_qspi_ids[] = {
{
.compatible = "atmel,sama5d2-qspi",
@@ -616,6 +1155,14 @@ static const struct udevice_id atmel_qspi_ids[] = {
.compatible = "microchip,sam9x60-qspi",
.data = (ulong)&atmel_sam9x60_qspi_caps,
},
+ {
+ .compatible = "microchip,sama7g5-ospi",
+ .data = (ulong)&atmel_sama7g5_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7g5-qspi",
+ .data = (ulong)&atmel_sama7g5_qspi_caps,
+ },
{ /* sentinel */ }
};
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 8d40ce60c2b..a8ef926a480 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -87,16 +87,6 @@
#define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0
/*
- * Same values as TEE_LOGIN_* from TEE Internal API
- */
-#define OPTEE_MSG_LOGIN_PUBLIC 0x00000000
-#define OPTEE_MSG_LOGIN_USER 0x00000001
-#define OPTEE_MSG_LOGIN_GROUP 0x00000002
-#define OPTEE_MSG_LOGIN_APPLICATION 0x00000004
-#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005
-#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006
-
-/*
* Page size used in non-contiguous buffer entries
*/
#define OPTEE_MSG_NONCONTIG_PAGE_SIZE 4096
@@ -279,7 +269,7 @@ struct optee_msg_arg {
* parameters to pass the following information:
* param[0].u.value.a-b uuid of Trusted Application
* param[1].u.value.a-b uuid of Client
- * param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_*
+ * param[1].u.value.c Login class of client TEE_LOGIN_*
*
* OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened
* session to a Trusted Application. struct optee_msg_arg::func is Trusted
diff --git a/drivers/timer/ostm_timer.c b/drivers/timer/ostm_timer.c
index 24813de2653..3ec729d2c43 100644
--- a/drivers/timer/ostm_timer.c
+++ b/drivers/timer/ostm_timer.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <clock_legacy.h>
#include <malloc.h>
#include <asm/global_data.h>
#include <asm/io.h>
@@ -51,7 +52,7 @@ static int ostm_probe(struct udevice *dev)
clk_free(&clk);
#else
- uc_priv->clock_rate = CONFIG_SYS_CLK_FREQ / 2;
+ uc_priv->clock_rate = get_board_sys_clk() / 2;
#endif
readb(priv->regs + OSTM_CTL);
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index 43171678ee1..8958f0166bd 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -180,6 +180,7 @@ static int cdns_ti_remove(struct udevice *dev)
static const struct udevice_id cdns_ti_of_match[] = {
{ .compatible = "ti,j721e-usb", },
+ { .compatible = "ti,am64-usb", },
{},
};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a58f87f479b..cfa08b501ba 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -14,6 +14,17 @@ config DM_VIDEO
option compiles in the video uclass and routes all LCD/video access
through this.
+config VIDEO_LOGO
+ bool "Show the U-Boot logo on the display"
+ depends on DM_VIDEO
+ default y if !SPLASH_SCREEN
+ select VIDEO_BMP_RLE8
+ help
+ This enables showing the U-Boot logo on the display when a video
+ device is probed. It appears at the top right. The logo itself is at
+ tools/logos/u-boot_logo.bmp and looks best when the display has a
+ black background.
+
config BACKLIGHT
bool "Enable panel backlight uclass support"
depends on DM_VIDEO
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8956b5f9b00..4038395b128 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -17,6 +17,9 @@ obj-$(CONFIG_DM_VIDEO) += video_bmp.o
obj-$(CONFIG_PANEL) += panel-uclass.o
obj-$(CONFIG_DM_PANEL_HX8238D) += hx8238d.o
obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o
+
+obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
+
endif
obj-${CONFIG_EXYNOS_FB} += exynos/
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 7df7d57e6ec..52b109f1551 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -42,11 +42,6 @@
* VIDEO_TSTC_FCT - keyboard_tstc function
* VIDEO_GETC_FCT - keyboard_getc function
*
- * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner.
- * Use CONFIG_SPLASH_SCREEN_ALIGN with
- * environment variable "splashpos" to place
- * the logo on other position. In this case
- * no CONSOLE_EXTRA_INFO is possible.
* CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo
* CONFIG_CONSOLE_EXTRA_INFO - display additional board information
* strings that normaly goes to serial
@@ -127,34 +122,6 @@ void console_cursor(int state);
#define CURSOR_SET video_set_cursor()
#endif /* CONFIG_VIDEO_SW_CURSOR */
-#ifdef CONFIG_VIDEO_LOGO
-#ifdef CONFIG_VIDEO_BMP_LOGO
-#include <bmp_logo.h>
-#include <bmp_logo_data.h>
-#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
-#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
-#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
-#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
-
-#else /* CONFIG_VIDEO_BMP_LOGO */
-#define LINUX_LOGO_WIDTH 80
-#define LINUX_LOGO_HEIGHT 80
-#define LINUX_LOGO_COLORS 214
-#define LINUX_LOGO_LUT_OFFSET 0x20
-#define __initdata
-#include <linux_logo.h>
-#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
-#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
-#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
-#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
-#endif /* CONFIG_VIDEO_BMP_LOGO */
-#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
-#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
-#else /* CONFIG_VIDEO_LOGO */
-#define VIDEO_LOGO_WIDTH 0
-#define VIDEO_LOGO_HEIGHT 0
-#endif /* CONFIG_VIDEO_LOGO */
-
#define VIDEO_COLS VIDEO_VISIBLE_COLS
#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
#ifndef VIDEO_LINE_LEN
@@ -163,11 +130,7 @@ void console_cursor(int state);
#define VIDEO_SIZE (VIDEO_ROWS * VIDEO_LINE_LEN)
#define VIDEO_BURST_LEN (VIDEO_COLS/8)
-#ifdef CONFIG_VIDEO_LOGO
-#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
-#else
#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
-#endif
#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
@@ -214,7 +177,7 @@ static GraphicDevice *pGD; /* Pointer to Graphic array */
static void *video_fb_address; /* frame buffer address */
static void *video_console_address; /* console buffer start address */
-static int video_logo_height = VIDEO_LOGO_HEIGHT;
+static int video_logo_height; /* not supported anymore */
static int __maybe_unused cursor_state;
static int __maybe_unused old_col;
@@ -1670,292 +1633,6 @@ int video_display_bitmap(ulong bmp_image, int x, int y)
}
#endif
-
-#ifdef CONFIG_VIDEO_LOGO
-static int video_logo_xpos;
-static int video_logo_ypos;
-
-static void plot_logo_or_black(void *screen, int x, int y, int black);
-
-static void logo_plot(void *screen, int x, int y)
-{
- plot_logo_or_black(screen, x, y, 0);
-}
-
-static void logo_black(void)
-{
- plot_logo_or_black(video_fb_address, video_logo_xpos, video_logo_ypos,
- 1);
-}
-
-static int do_clrlogo(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
-{
- if (argc != 1)
- return cmd_usage(cmdtp);
-
- logo_black();
- return 0;
-}
-
-U_BOOT_CMD(
- clrlogo, 1, 0, do_clrlogo,
- "fill the boot logo area with black",
- " "
- );
-
-static void plot_logo_or_black(void *screen, int x, int y, int black)
-{
-
- int xcount, i;
- int skip = VIDEO_LINE_LEN - VIDEO_LOGO_WIDTH * VIDEO_PIXEL_SIZE;
- int ycount = video_logo_height;
- unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
- unsigned char *source;
- unsigned char *dest;
-
-#ifdef CONFIG_SPLASH_SCREEN_ALIGN
- if (x == BMP_ALIGN_CENTER)
- x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
- else if (x < 0)
- x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
-
- if (y == BMP_ALIGN_CENTER)
- y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
- else if (y < 0)
- y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
-#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
-
- dest = (unsigned char *)screen + y * VIDEO_LINE_LEN + x * VIDEO_PIXEL_SIZE;
-
-#ifdef CONFIG_VIDEO_BMP_LOGO
- source = bmp_logo_bitmap;
-
- /* Allocate temporary space for computing colormap */
- logo_red = malloc(BMP_LOGO_COLORS);
- logo_green = malloc(BMP_LOGO_COLORS);
- logo_blue = malloc(BMP_LOGO_COLORS);
- /* Compute color map */
- for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
- logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
- logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
- logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
- }
-#else
- source = linux_logo;
- logo_red = linux_logo_red;
- logo_green = linux_logo_green;
- logo_blue = linux_logo_blue;
-#endif
-
- if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
- for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
- video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
- logo_red[i], logo_green[i],
- logo_blue[i]);
- }
- }
-
- while (ycount--) {
-#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
- int xpos = x;
-#endif
- xcount = VIDEO_LOGO_WIDTH;
- while (xcount--) {
- if (black) {
- r = 0x00;
- g = 0x00;
- b = 0x00;
- } else {
- r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
- g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
- b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
- }
-
- switch (VIDEO_DATA_FORMAT) {
- case GDF__8BIT_INDEX:
- *dest = *source;
- break;
- case GDF__8BIT_332RGB:
- *dest = ((r >> 5) << 5) |
- ((g >> 5) << 2) |
- (b >> 6);
- break;
- case GDF_15BIT_555RGB:
-#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
- fill_555rgb_pswap(dest, xpos++, r, g, b);
-#else
- *(unsigned short *) dest =
- SWAP16((unsigned short) (
- ((r >> 3) << 10) |
- ((g >> 3) << 5) |
- (b >> 3)));
-#endif
- break;
- case GDF_16BIT_565RGB:
- *(unsigned short *) dest =
- SWAP16((unsigned short) (
- ((r >> 3) << 11) |
- ((g >> 2) << 5) |
- (b >> 3)));
- break;
- case GDF_32BIT_X888RGB:
- *(u32 *) dest =
- SWAP32((u32) (
- (r << 16) |
- (g << 8) |
- b));
- break;
- case GDF_24BIT_888RGB:
-#ifdef VIDEO_FB_LITTLE_ENDIAN
- dest[0] = b;
- dest[1] = g;
- dest[2] = r;
-#else
- dest[0] = r;
- dest[1] = g;
- dest[2] = b;
-#endif
- break;
- }
- source++;
- dest += VIDEO_PIXEL_SIZE;
- }
- dest += skip;
- }
-#ifdef CONFIG_VIDEO_BMP_LOGO
- free(logo_red);
- free(logo_green);
- free(logo_blue);
-#endif
-}
-
-static void *video_logo(void)
-{
- char info[128];
- __maybe_unused int y_off = 0;
- __maybe_unused ulong addr;
- __maybe_unused char *s;
- __maybe_unused int len, ret, space;
-
- splash_get_pos(&video_logo_xpos, &video_logo_ypos);
-
-#ifdef CONFIG_SPLASH_SCREEN
- s = env_get("splashimage");
- if (s != NULL) {
- ret = splash_screen_prepare();
- if (ret < 0)
- return video_fb_address;
- addr = hextoul(s, NULL);
-
- if (video_display_bitmap(addr,
- video_logo_xpos,
- video_logo_ypos) == 0) {
- video_logo_height = 0;
- return ((void *) (video_fb_address));
- }
- }
-#endif /* CONFIG_SPLASH_SCREEN */
-
- logo_plot(video_fb_address, video_logo_xpos, video_logo_ypos);
-
-#ifdef CONFIG_SPLASH_SCREEN_ALIGN
- /*
- * when using splashpos for video_logo, skip any info
- * output on video console if the logo is not at 0,0
- */
- if (video_logo_xpos || video_logo_ypos) {
- /*
- * video_logo_height is used in text and cursor offset
- * calculations. Since the console is below the logo,
- * we need to adjust the logo height
- */
- if (video_logo_ypos == BMP_ALIGN_CENTER)
- video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
- VIDEO_LOGO_HEIGHT) / 2);
- else if (video_logo_ypos > 0)
- video_logo_height += video_logo_ypos;
-
- return video_fb_address + video_logo_height * VIDEO_LINE_LEN;
- }
-#endif
- if (board_cfb_skip())
- return 0;
-
- sprintf(info, " %s", version_string);
-
-#ifndef CONFIG_HIDE_LOGO_VERSION
- space = (VIDEO_COLS - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
- len = strlen(info);
-
- if (len > space) {
- int xx = VIDEO_INFO_X, yy = VIDEO_INFO_Y;
- uchar *p = (uchar *) info;
-
- while (len) {
- if (len > space) {
- video_drawchars(xx, yy, p, space);
- len -= space;
-
- p = (uchar *)p + space;
-
- if (!y_off) {
- xx += VIDEO_FONT_WIDTH;
- space--;
- }
- yy += VIDEO_FONT_HEIGHT;
-
- y_off++;
- } else {
- video_drawchars(xx, yy, p, len);
- len = 0;
- }
- }
- } else
- video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
-
-#ifdef CONFIG_CONSOLE_EXTRA_INFO
- {
- int i, n =
- ((video_logo_height -
- VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
-
- for (i = 1; i < n; i++) {
- video_get_info_str(i, info);
- if (!*info)
- continue;
-
- len = strlen(info);
- if (len > space) {
- video_drawchars(VIDEO_INFO_X,
- VIDEO_INFO_Y +
- (i + y_off) *
- VIDEO_FONT_HEIGHT,
- (uchar *) info, space);
- y_off++;
- video_drawchars(VIDEO_INFO_X +
- VIDEO_FONT_WIDTH,
- VIDEO_INFO_Y +
- (i + y_off) *
- VIDEO_FONT_HEIGHT,
- (uchar *) info + space,
- len - space);
- } else {
- video_drawstring(VIDEO_INFO_X,
- VIDEO_INFO_Y +
- (i + y_off) *
- VIDEO_FONT_HEIGHT,
- (uchar *) info);
- }
- }
- }
-#endif
-#endif
-
- return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
-}
-#endif
-
static int cfb_fb_is_in_dram(void)
{
struct bd_info *bd = gd->bd;
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 98427f4c618..de8b86bbacc 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -274,6 +274,27 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
*/
for (row = 0; row < height; row++) {
switch (vid_priv->bpix) {
+ case VIDEO_BPP8:
+ if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
+ u8 *dst = line + xoff;
+ int i;
+
+ for (i = 0; i < width; i++) {
+ int val = *bits;
+ int out;
+
+ if (vid_priv->colour_bg)
+ val = 255 - val;
+ out = val;
+ if (vid_priv->colour_fg)
+ *dst++ |= out;
+ else
+ *dst++ &= out;
+ bits++;
+ }
+ end = dst;
+ }
+ break;
#ifdef CONFIG_VIDEO_BPP16
case VIDEO_BPP16: {
uint16_t *dst = (uint16_t *)line + xoff;
diff --git a/drivers/video/sandbox_sdl.c b/drivers/video/sandbox_sdl.c
index 5956b59ce49..9081c7da62e 100644
--- a/drivers/video/sandbox_sdl.c
+++ b/drivers/video/sandbox_sdl.c
@@ -12,6 +12,7 @@
#include <asm/sdl.h>
#include <asm/state.h>
#include <asm/u-boot-sandbox.h>
+#include <dm/device-internal.h>
#include <dm/test.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -43,27 +44,86 @@ static int sandbox_sdl_probe(struct udevice *dev)
uc_priv->vidconsole_drv_name = plat->vidconsole_drv_name;
uc_priv->font_size = plat->font_size;
if (IS_ENABLED(CONFIG_VIDEO_COPY))
- uc_plat->copy_base = uc_plat->base - uc_plat->size / 2;
+ uc_plat->copy_base = uc_plat->base + uc_plat->size / 2;
return 0;
}
-static int sandbox_sdl_bind(struct udevice *dev)
+static void set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp)
{
struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
struct sandbox_sdl_plat *plat = dev_get_plat(dev);
- int ret = 0;
- plat->xres = dev_read_u32_default(dev, "xres", LCD_MAX_WIDTH);
- plat->yres = dev_read_u32_default(dev, "yres", LCD_MAX_HEIGHT);
- plat->bpix = dev_read_u32_default(dev, "log2-depth", VIDEO_BPP16);
- plat->rot = dev_read_u32_default(dev, "rotate", 0);
- uc_plat->size = plat->xres * plat->yres * (1 << plat->bpix) / 8;
+ plat->bpix = l2bpp;
+
+ uc_plat->size = plat->xres * plat->yres * VNBYTES(plat->bpix);
+
+ /*
+ * Set up to the maximum size we'll ever need. This is a strange case.
+ * The video memory is allocated by video_post_bind() called from
+ * board_init_r(). If a test changes the reoslution so it needs more
+ * memory later (with sandbox_sdl_set_bpp()), it is too late to make
+ * the frame buffer larger.
+ *
+ * So use a maximum size here.
+ */
+ uc_plat->size = max(uc_plat->size, 1920U * 1080 * VNBYTES(VIDEO_BPP32));
/* Allow space for two buffers, the lower one being the copy buffer */
log_debug("Frame buffer size %x\n", uc_plat->size);
+
+ /*
+ * If a copy framebuffer is used, double the size and use the last half
+ * as the copy, with the first half as the normal frame buffer.
+ */
if (IS_ENABLED(CONFIG_VIDEO_COPY))
uc_plat->size *= 2;
+}
+
+int sandbox_sdl_set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp)
+{
+ struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+ int ret;
+
+ if (device_active(dev))
+ return -EINVAL;
+ sandbox_sdl_remove_display();
+
+ uc_plat->hide_logo = true;
+ set_bpp(dev, l2bpp);
+
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_sdl_remove(struct udevice *dev)
+{
+ /*
+ * Removing the display it a bit annoying when running unit tests, since
+ * they remove all devices. It is nice to be able to see what the test
+ * wrote onto the display. So this comment is just here to show how to
+ * do it, if we want to make it optional one day.
+ *
+ * sandbox_sdl_remove_display();
+ */
+ return 0;
+}
+
+static int sandbox_sdl_bind(struct udevice *dev)
+{
+ struct sandbox_sdl_plat *plat = dev_get_plat(dev);
+ enum video_log2_bpp l2bpp;
+ int ret = 0;
+
+ plat->xres = dev_read_u32_default(dev, "xres", LCD_MAX_WIDTH);
+ plat->yres = dev_read_u32_default(dev, "yres", LCD_MAX_HEIGHT);
+ l2bpp = dev_read_u32_default(dev, "log2-depth", VIDEO_BPP16);
+ plat->rot = dev_read_u32_default(dev, "rotate", 0);
+
+ set_bpp(dev, l2bpp);
return ret;
}
@@ -79,5 +139,6 @@ U_BOOT_DRIVER(sandbox_lcd_sdl) = {
.of_match = sandbox_sdl_ids,
.bind = sandbox_sdl_bind,
.probe = sandbox_sdl_probe,
+ .remove = sandbox_sdl_remove,
.plat_auto = sizeof(struct sandbox_sdl_plat),
};
diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
index 65c882d9f12..87e5fd54d9a 100644
--- a/drivers/video/stm32/stm32_ltdc.c
+++ b/drivers/video/stm32/stm32_ltdc.c
@@ -459,7 +459,10 @@ static int stm32_ltdc_bind(struct udevice *dev)
uc_plat->size = CONFIG_VIDEO_STM32_MAX_XRES *
CONFIG_VIDEO_STM32_MAX_YRES *
(CONFIG_VIDEO_STM32_MAX_BPP >> 3);
- dev_dbg(dev, "frame buffer max size %d bytes\n", uc_plat->size);
+ /* align framebuffer on kernel MMU_SECTION_SIZE = max 2MB for LPAE */
+ uc_plat->align = SZ_2M;
+ dev_dbg(dev, "frame buffer max size %d bytes align %x\n",
+ uc_plat->size, uc_plat->align);
return 0;
}
diff --git a/drivers/video/u_boot_logo.bmp b/drivers/video/u_boot_logo.bmp
new file mode 100644
index 00000000000..47f1e9b9978
--- /dev/null
+++ b/drivers/video/u_boot_logo.bmp
Binary files differ
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index 9f8cf6ef2a9..7d499bcec51 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -228,6 +228,20 @@ void video_sync_all(void)
}
}
+bool video_is_active(void)
+{
+ struct udevice *dev;
+
+ for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ if (device_active(dev))
+ return true;
+ }
+
+ return false;
+}
+
int video_get_xsize(struct udevice *dev)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
@@ -265,10 +279,10 @@ int video_sync_copy(struct udevice *dev, void *from, void *to)
*/
if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
#ifdef DEBUG
- char str[80];
+ char str[120];
snprintf(str, sizeof(str),
- "[sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
+ "[** FAULT sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
priv->fb, from, to, offset);
console_puts_select_stderr(true, str);
#endif
@@ -305,23 +319,20 @@ int video_sync_copy_all(struct udevice *dev)
#endif
-/* Set up the colour map */
-static int video_pre_probe(struct udevice *dev)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
+#define SPLASH_DECL(_name) \
+ extern u8 __splash_ ## _name ## _begin[]; \
+ extern u8 __splash_ ## _name ## _end[]
- priv->cmap = calloc(256, sizeof(ushort));
- if (!priv->cmap)
- return -ENOMEM;
+#define SPLASH_START(_name) __splash_ ## _name ## _begin
- return 0;
-}
+SPLASH_DECL(u_boot_logo);
-static int video_pre_remove(struct udevice *dev)
+static int show_splash(struct udevice *dev)
{
- struct video_priv *priv = dev_get_uclass_priv(dev);
+ u8 *data = SPLASH_START(u_boot_logo);
+ int ret;
- free(priv->cmap);
+ ret = video_bmp_display(dev, map_to_sysmem(data), -4, 4, true);
return 0;
}
@@ -391,6 +402,14 @@ static int video_post_probe(struct udevice *dev)
return ret;
}
+ if (IS_ENABLED(CONFIG_VIDEO_LOGO) && !plat->hide_logo) {
+ ret = show_splash(dev);
+ if (ret) {
+ log_debug("Cannot show splash screen\n");
+ return ret;
+ }
+ }
+
return 0;
};
@@ -433,9 +452,7 @@ UCLASS_DRIVER(video) = {
.name = "video",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = video_post_bind,
- .pre_probe = video_pre_probe,
.post_probe = video_post_probe,
- .pre_remove = video_pre_remove,
.priv_auto = sizeof(struct video_uc_priv),
.per_device_auto = sizeof(struct video_priv),
.per_device_plat_auto = sizeof(struct video_uc_plat),
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 1e6f07ff4b0..e8600b2def3 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -13,34 +13,90 @@
#include <watchdog.h>
#include <asm/unaligned.h>
-#ifdef CONFIG_VIDEO_BMP_RLE8
#define BMP_RLE8_ESCAPE 0
#define BMP_RLE8_EOL 0
#define BMP_RLE8_EOBMP 1
#define BMP_RLE8_DELTA 2
-static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
+/**
+ * get_bmp_col_16bpp() - Convert a colour-table entry into a 16bpp pixel value
+ *
+ * @return value to write to the 16bpp frame buffer for this palette entry
+ */
+static uint get_bmp_col_16bpp(struct bmp_color_table_entry cte)
+{
+ return ((cte.red << 8) & 0xf800) |
+ ((cte.green << 3) & 0x07e0) |
+ ((cte.blue >> 3) & 0x001f);
+}
+
+/**
+ * write_pix8() - Write a pixel from a BMP image into the framebuffer
+ *
+ * This handles frame buffers with 8, 16, 24 or 32 bits per pixel
+ *
+ * @fb: Place in frame buffer to update
+ * @bpix: Frame buffer bits-per-pixel, which controls how many bytes are written
+ * @palette: BMP palette table
+ * @bmap: Pointer to BMP bitmap position to write. This contains a single byte
+ * which is either written directly (bpix == 8) or used to look up the
+ * palette to get a colour to write
+ */
+static void write_pix8(u8 *fb, uint bpix, struct bmp_color_table_entry *palette,
+ u8 *bmap)
+{
+ if (bpix == 8) {
+ *fb++ = *bmap;
+ } else if (bpix == 16) {
+ *(u16 *)fb = get_bmp_col_16bpp(palette[*bmap]);
+ } else {
+ /* Only support big endian */
+ struct bmp_color_table_entry *cte = &palette[*bmap];
+
+ if (bpix == 24) {
+ *fb++ = cte->red;
+ *fb++ = cte->green;
+ *fb++ = cte->blue;
+ } else {
+ *fb++ = cte->blue;
+ *fb++ = cte->green;
+ *fb++ = cte->red;
+ *fb++ = 0;
+ }
+ }
+}
+
+static void draw_unencoded_bitmap(u8 **fbp, uint bpix, uchar *bmap,
+ struct bmp_color_table_entry *palette,
int cnt)
{
+ u8 *fb = *fbp;
+
while (cnt > 0) {
- *(*fbp)++ = cmap[*bmap++];
+ write_pix8(fb, bpix, palette, bmap++);
+ fb += bpix / 8;
cnt--;
}
+ *fbp = fb;
}
-static void draw_encoded_bitmap(ushort **fbp, ushort col, int cnt)
+static void draw_encoded_bitmap(u8 **fbp, uint bpix,
+ struct bmp_color_table_entry *palette, u8 *bmap,
+ int cnt)
{
- ushort *fb = *fbp;
+ u8 *fb = *fbp;
while (cnt > 0) {
- *fb++ = col;
+ write_pix8(fb, bpix, palette, bmap);
+ fb += bpix / 8;
cnt--;
}
*fbp = fb;
}
static void video_display_rle8_bitmap(struct udevice *dev,
- struct bmp_image *bmp, ushort *cmap,
+ struct bmp_image *bmp, uint bpix,
+ struct bmp_color_table_entry *palette,
uchar *fb, int x_off, int y_off,
ulong width, ulong height)
{
@@ -49,6 +105,7 @@ static void video_display_rle8_bitmap(struct udevice *dev,
ulong cnt, runlen;
int x, y;
int decode = 1;
+ uint bytes_per_pixel = bpix / 8;
debug("%s\n", __func__);
bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
@@ -64,8 +121,8 @@ static void video_display_rle8_bitmap(struct udevice *dev,
bmap += 2;
x = 0;
y--;
- /* 16bpix, 2-byte per pixel, width should *2 */
- fb -= (width * 2 + priv->line_length);
+ fb -= width * bytes_per_pixel +
+ priv->line_length;
break;
case BMP_RLE8_EOBMP:
/* end of bitmap */
@@ -75,9 +132,9 @@ static void video_display_rle8_bitmap(struct udevice *dev,
/* delta run */
x += bmap[2];
y -= bmap[3];
- /* 16bpix, 2-byte per pixel, x should *2 */
- fb = (uchar *)(priv->fb + (y + y_off - 1)
- * priv->line_length + (x + x_off) * 2);
+ fb = (uchar *)(priv->fb +
+ (y + y_off - 1) * priv->line_length +
+ (x + x_off) * bytes_per_pixel);
bmap += 4;
break;
default:
@@ -91,8 +148,8 @@ static void video_display_rle8_bitmap(struct udevice *dev,
else
cnt = runlen;
draw_unencoded_bitmap(
- (ushort **)&fb,
- bmap, cmap, cnt);
+ &fb, bpix,
+ bmap, palette, cnt);
}
x += runlen;
}
@@ -116,8 +173,8 @@ static void video_display_rle8_bitmap(struct udevice *dev,
cnt = width - x;
else
cnt = runlen;
- draw_encoded_bitmap((ushort **)&fb,
- cmap[bmap[1]], cnt);
+ draw_encoded_bitmap(&fb, bpix, palette,
+ &bmap[1], cnt);
}
x += runlen;
}
@@ -125,20 +182,6 @@ static void video_display_rle8_bitmap(struct udevice *dev,
}
}
}
-#endif
-
-__weak void fb_put_byte(uchar **fb, uchar **from)
-{
- *(*fb)++ = *(*from)++;
-}
-
-#if defined(CONFIG_BMP_16BPP)
-__weak void fb_put_word(uchar **fb, uchar **from)
-{
- *(*fb)++ = *(*from)++;
- *(*fb)++ = *(*from)++;
-}
-#endif /* CONFIG_BMP_16BPP */
/**
* video_splash_align_axis() - Align a single coordinate
@@ -169,28 +212,10 @@ static void video_splash_align_axis(int *axis, unsigned long panel_size,
*axis = max(0, (int)axis_alignment);
}
-static void video_set_cmap(struct udevice *dev,
- struct bmp_color_table_entry *cte, unsigned colours)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
- int i;
- ushort *cmap = priv->cmap;
-
- debug("%s: colours=%d\n", __func__, colours);
- for (i = 0; i < colours; ++i) {
- *cmap = ((cte->red << 8) & 0xf800) |
- ((cte->green << 3) & 0x07e0) |
- ((cte->blue >> 3) & 0x001f);
- cmap++;
- cte++;
- }
-}
-
int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
bool align)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
- ushort *cmap_base = NULL;
int i, j;
uchar *start, *fb;
struct bmp_image *bmp = map_sysmem(bmp_image, 0);
@@ -246,9 +271,6 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
debug("Display-bmp: %d x %d with %d colours, display %d\n",
(int)width, (int)height, (int)colours, 1 << bpix);
- if (bmp_bpix == 8)
- video_set_cmap(dev, palette, colours);
-
padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
if (align) {
@@ -270,23 +292,19 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
switch (bmp_bpix) {
case 1:
- case 8: {
- struct bmp_color_table_entry *cte;
- cmap_base = priv->cmap;
-#ifdef CONFIG_VIDEO_BMP_RLE8
- u32 compression = get_unaligned_le32(&bmp->header.compression);
- debug("compressed %d %d\n", compression, BMP_BI_RLE8);
- if (compression == BMP_BI_RLE8) {
- if (bpix != 16) {
- /* TODO implement render code for bpix != 16 */
- printf("Error: only support 16 bpix");
- return -EPROTONOSUPPORT;
+ case 8:
+ if (IS_ENABLED(CONFIG_VIDEO_BMP_RLE8)) {
+ u32 compression = get_unaligned_le32(
+ &bmp->header.compression);
+ debug("compressed %d %d\n", compression, BMP_BI_RLE8);
+ if (compression == BMP_BI_RLE8) {
+ video_display_rle8_bitmap(dev, bmp, bpix, palette, fb,
+ x, y, width, height);
+ break;
}
- video_display_rle8_bitmap(dev, bmp, cmap_base, fb, x,
- y, width, height);
- break;
}
-#endif
+
+ /* Not compressed */
byte_width = width * (bpix / 8);
if (!byte_width)
byte_width = width;
@@ -294,81 +312,64 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
for (i = 0; i < height; ++i) {
WATCHDOG_RESET();
for (j = 0; j < width; j++) {
- if (bpix == 8) {
- fb_put_byte(&fb, &bmap);
- } else if (bpix == 16) {
- *(uint16_t *)fb = cmap_base[*bmap];
- bmap++;
- fb += sizeof(uint16_t) / sizeof(*fb);
- } else {
- /* Only support big endian */
- cte = &palette[*bmap];
- bmap++;
- if (bpix == 24) {
- *(fb++) = cte->red;
- *(fb++) = cte->green;
- *(fb++) = cte->blue;
- } else {
- *(fb++) = cte->blue;
- *(fb++) = cte->green;
- *(fb++) = cte->red;
- *(fb++) = 0;
- }
- }
+ write_pix8(fb, bpix, palette, bmap);
+ bmap++;
+ fb += bpix / 8;
}
bmap += (padded_width - width);
fb -= byte_width + priv->line_length;
}
break;
- }
-#if defined(CONFIG_BMP_16BPP)
case 16:
- for (i = 0; i < height; ++i) {
- WATCHDOG_RESET();
- for (j = 0; j < width; j++)
- fb_put_word(&fb, &bmap);
-
- bmap += (padded_width - width);
- fb -= width * 2 + priv->line_length;
+ if (IS_ENABLED(CONFIG_BMP_16BPP)) {
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ }
+ bmap += (padded_width - width);
+ fb -= width * 2 + priv->line_length;
+ }
}
break;
-#endif /* CONFIG_BMP_16BPP */
-#if defined(CONFIG_BMP_24BPP)
case 24:
- for (i = 0; i < height; ++i) {
- for (j = 0; j < width; j++) {
- if (bpix == 16) {
- /* 16bit 555RGB format */
- *(u16 *)fb = ((bmap[2] >> 3) << 10) |
- ((bmap[1] >> 3) << 5) |
- (bmap[0] >> 3);
- bmap += 3;
- fb += 2;
- } else {
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
- *(fb++) = 0;
+ if (IS_ENABLED(CONFIG_BMP_24BPP)) {
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ if (bpix == 16) {
+ /* 16bit 565RGB format */
+ *(u16 *)fb = ((bmap[2] >> 3)
+ << 11) |
+ ((bmap[1] >> 2) << 5) |
+ (bmap[0] >> 3);
+ bmap += 3;
+ fb += 2;
+ } else {
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ *fb++ = 0;
+ }
}
+ fb -= priv->line_length + width * (bpix / 8);
+ bmap += (padded_width - width);
}
- fb -= priv->line_length + width * (bpix / 8);
- bmap += (padded_width - width);
}
break;
-#endif /* CONFIG_BMP_24BPP */
-#if defined(CONFIG_BMP_32BPP)
case 32:
- for (i = 0; i < height; ++i) {
- for (j = 0; j < width; j++) {
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
+ if (IS_ENABLED(CONFIG_BMP_32BPP)) {
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; j++) {
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ *fb++ = *bmap++;
+ }
+ fb -= priv->line_length + width * (bpix / 8);
}
- fb -= priv->line_length + width * (bpix / 8);
}
break;
-#endif /* CONFIG_BMP_32BPP */
default:
break;
};