summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/altera/clk-arria10.c3
-rw-r--r--drivers/clk/at91/pmc.c2
-rw-r--r--drivers/core/ofnode.c21
-rw-r--r--drivers/core/syscon-uclass.c83
-rw-r--r--drivers/core/util.c40
-rw-r--r--drivers/dma/bcm6348-iudma.c6
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/bcm6345_gpio.c12
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/nand/spi/gigadevice.c79
-rw-r--r--drivers/mtd/spi/Kconfig6
-rw-r--r--drivers/mtd/spi/sf_probe.c1
-rw-r--r--drivers/mtd/spi/spi-nor-core.c14
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c7
-rw-r--r--drivers/net/ag7xxx.c328
-rw-r--r--drivers/net/mscc_eswitch/Kconfig14
-rw-r--r--drivers/net/mscc_eswitch/Makefile2
-rw-r--r--drivers/net/mscc_eswitch/jr2_switch.c1075
-rw-r--r--drivers/net/mscc_eswitch/ocelot_switch.c27
-rw-r--r--drivers/net/mscc_eswitch/servalt_switch.c622
-rw-r--r--drivers/phy/Kconfig8
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/mt76x8-usb-phy.c161
-rw-r--r--drivers/pinctrl/ath79/Makefile2
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c36
-rw-r--r--drivers/spi/cadence_qspi.c2
-rw-r--r--drivers/spi/cadence_qspi.h2
-rw-r--r--drivers/spi/cadence_qspi_apb.c7
-rw-r--r--drivers/spi/fsl_dspi.c30
-rw-r--r--drivers/spi/spi-mem.c2
-rw-r--r--drivers/spi/spi-uclass.c4
-rw-r--r--drivers/sysreset/sysreset_syscon.c15
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/console_normal.c3
-rw-r--r--drivers/video/console_rotate.c7
-rw-r--r--drivers/video/pwm_backlight.c11
-rw-r--r--drivers/video/vidconsole-uclass.c111
-rw-r--r--drivers/video/video-uclass.c1
38 files changed, 2521 insertions, 234 deletions
diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
index 612a1718dcb..179869df45f 100644
--- a/drivers/clk/altera/clk-arria10.c
+++ b/drivers/clk/altera/clk-arria10.c
@@ -254,7 +254,8 @@ static int socfpga_a10_clk_bind(struct udevice *dev)
fdt_node_check_compatible(fdt, offset, "fixed-clock"))
continue;
- if (pre_reloc_only && !dm_fdt_pre_reloc(fdt, offset))
+ if (pre_reloc_only &&
+ !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
continue;
ret = device_bind_driver_to_node(dev, "clk-a10", name,
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 7cfbabc96d3..6b55ec59d6d 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -61,7 +61,7 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
offset > 0;
offset = fdt_next_subnode(fdt, offset)) {
if (pre_reloc_only &&
- !dm_fdt_pre_reloc(fdt, offset))
+ !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
continue;
/*
* If this node has "compatible" property, this is not
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 0e584c12dc8..785f5c3acf7 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -254,14 +254,13 @@ int ofnode_read_size(ofnode node, const char *propname)
fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
{
int na, ns;
- fdt_size_t size;
if (ofnode_is_np(node)) {
const __be32 *prop_val;
uint flags;
prop_val = of_get_address(ofnode_to_np(node), index,
- (u64 *)&size, &flags);
+ NULL, &flags);
if (!prop_val)
return FDT_ADDR_T_NONE;
@@ -278,7 +277,7 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
return fdtdec_get_addr_size_fixed(gd->fdt_blob,
ofnode_to_offset(node), "reg",
- index, na, ns, &size, true);
+ index, na, ns, NULL, true);
}
return FDT_ADDR_T_NONE;
@@ -700,18 +699,18 @@ int ofnode_read_simple_size_cells(ofnode node)
bool ofnode_pre_reloc(ofnode node)
{
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
+ /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
+ * had property dm-pre-reloc or u-boot,dm-spl/tpl.
+ * They are removed in final dtb (fdtgrep 2nd pass)
+ */
+ return true;
+#else
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
return true;
if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
return true;
-#ifdef CONFIG_TPL_BUILD
- if (ofnode_read_bool(node, "u-boot,dm-tpl"))
- return true;
-#elif defined(CONFIG_SPL_BUILD)
- if (ofnode_read_bool(node, "u-boot,dm-spl"))
- return true;
-#else
/*
* In regular builds individual spl and tpl handling both
* count as handled pre-relocation for later second init.
@@ -719,9 +718,9 @@ bool ofnode_pre_reloc(ofnode node)
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
ofnode_read_bool(node, "u-boot,dm-tpl"))
return true;
-#endif
return false;
+#endif
}
int ofnode_read_resource(ofnode node, uint index, struct resource *res)
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index afac6d6e37e..5bb38e329cb 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -57,18 +57,64 @@ static int syscon_pre_probe(struct udevice *dev)
#endif
}
+static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
+{
+ struct udevice *dev, *parent;
+ int ret;
+
+ /* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
+ if (!ofnode_device_is_compatible(node, "syscon")) {
+ dev_dbg(dev, "invalid compatible for syscon device\n");
+ return -EINVAL;
+ }
+
+ /* bound to driver with same ofnode or to root if not found */
+ if (device_find_global_by_ofnode(node, &parent))
+ parent = dm_root();
+
+ /* force bound to syscon class */
+ ret = device_bind_driver_to_node(parent, "syscon",
+ ofnode_get_name(node),
+ node, &dev);
+ if (ret) {
+ dev_dbg(dev, "unable to bound syscon device\n");
+ return ret;
+ }
+ ret = device_probe(dev);
+ if (ret) {
+ dev_dbg(dev, "unable to probe syscon device\n");
+ return ret;
+ }
+
+ *devp = dev;
+ return 0;
+}
+
struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
const char *name)
{
struct udevice *syscon;
struct regmap *r;
+ u32 phandle;
+ ofnode node;
int err;
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
name, &syscon);
if (err) {
- dev_dbg(dev, "unable to find syscon device\n");
- return ERR_PTR(err);
+ /* found node with "syscon" compatible, not bounded to SYSCON */
+ err = ofnode_read_u32(dev_ofnode(dev), name, &phandle);
+ if (err)
+ return ERR_PTR(err);
+
+ node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(node)) {
+ dev_dbg(dev, "unable to find syscon device\n");
+ return ERR_PTR(-EINVAL);
+ }
+ err = syscon_probe_by_ofnode(node, &syscon);
+ if (err)
+ return ERR_PTR(-ENODEV);
}
r = syscon_get_regmap(syscon);
@@ -152,29 +198,18 @@ U_BOOT_DRIVER(generic_syscon) = {
*/
struct regmap *syscon_node_to_regmap(ofnode node)
{
- struct udevice *dev, *parent;
- int ret;
-
- if (!uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
- return syscon_get_regmap(dev);
-
- if (!ofnode_device_is_compatible(node, "syscon"))
- return ERR_PTR(-EINVAL);
+ struct udevice *dev;
+ struct regmap *r;
- /* bound to driver with same ofnode or to root if not found */
- if (device_find_global_by_ofnode(node, &parent))
- parent = dm_root();
+ if (uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
+ if (syscon_probe_by_ofnode(node, &dev))
+ return ERR_PTR(-ENODEV);
- /* force bound to syscon class */
- ret = device_bind_driver_to_node(parent, "syscon",
- ofnode_get_name(node),
- node, &dev);
- if (ret)
- return ERR_PTR(ret);
-
- ret = device_probe(dev);
- if (ret)
- return ERR_PTR(ret);
+ r = syscon_get_regmap(dev);
+ if (!r) {
+ dev_dbg(dev, "unable to find regmap\n");
+ return ERR_PTR(-ENODEV);
+ }
- return syscon_get_regmap(dev);
+ return r;
}
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 27a68487034..96e47dc7070 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -31,42 +31,18 @@ int list_count_items(struct list_head *head)
return count;
}
-bool dm_fdt_pre_reloc(const void *blob, int offset)
-{
- if (fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
- return true;
-
-#ifdef CONFIG_TPL_BUILD
- if (fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL))
- return true;
-#elif defined(CONFIG_SPL_BUILD)
- if (fdt_getprop(blob, offset, "u-boot,dm-spl", NULL))
- return true;
-#else
- /*
- * In regular builds individual spl and tpl handling both
- * count as handled pre-relocation for later second init.
- */
- if (fdt_getprop(blob, offset, "u-boot,dm-spl", NULL) ||
- fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL))
- return true;
-#endif
-
- return false;
-}
-
bool dm_ofnode_pre_reloc(ofnode node)
{
+#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
+ /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
+ * had property dm-pre-reloc or u-boot,dm-spl/tpl.
+ * They are removed in final dtb (fdtgrep 2nd pass)
+ */
+ return true;
+#else
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
return true;
-#ifdef CONFIG_TPL_BUILD
- if (ofnode_read_bool(node, "u-boot,dm-tpl"))
- return true;
-#elif defined(CONFIG_SPL_BUILD)
- if (ofnode_read_bool(node, "u-boot,dm-spl"))
- return true;
-#else
/*
* In regular builds individual spl and tpl handling both
* count as handled pre-relocation for later second init.
@@ -74,7 +50,7 @@ bool dm_ofnode_pre_reloc(ofnode node)
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
ofnode_read_bool(node, "u-boot,dm-tpl"))
return true;
-#endif
return false;
+#endif
}
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
index 1d3c192cfe5..e7bd1b2350f 100644
--- a/drivers/dma/bcm6348-iudma.c
+++ b/drivers/dma/bcm6348-iudma.c
@@ -324,6 +324,9 @@ static int bcm6348_iudma_receive(struct dma *dma, void **dst, void *metadata)
struct bcm6348_dma_desc *dma_desc = dma_desc = ch_priv->dma_ring;
int ret;
+ if (!ch_priv->running)
+ return -EINVAL;
+
/* get dma ring descriptor address */
dma_desc += ch_priv->desc_id;
@@ -369,6 +372,9 @@ static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len,
struct bcm6348_dma_desc *dma_desc;
uint16_t status;
+ if (!ch_priv->running)
+ return -EINVAL;
+
/* flush cache */
bcm6348_iudma_fdc(src, len);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b103180cf37..b3e4ecc50e1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -23,7 +23,7 @@ config ALTERA_PIO
config BCM6345_GPIO
bool "BCM6345 GPIO driver"
- depends on DM_GPIO && ARCH_BMIPS
+ depends on DM_GPIO && (ARCH_BMIPS || ARCH_BCM6858 || ARCH_BCM63158)
help
This driver supports the GPIO banks on BCM6345 SoCs.
diff --git a/drivers/gpio/bcm6345_gpio.c b/drivers/gpio/bcm6345_gpio.c
index d1f6cfa8405..71a978cf407 100644
--- a/drivers/gpio/bcm6345_gpio.c
+++ b/drivers/gpio/bcm6345_gpio.c
@@ -22,7 +22,7 @@ static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
{
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
- return !!(readl_be(priv->reg_data) & BIT(offset));
+ return !!(readl(priv->reg_data) & BIT(offset));
}
static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
@@ -31,9 +31,9 @@ static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
if (value)
- setbits_be32(priv->reg_data, BIT(offset));
+ setbits_32(priv->reg_data, BIT(offset));
else
- clrbits_be32(priv->reg_data, BIT(offset));
+ clrbits_32(priv->reg_data, BIT(offset));
return 0;
}
@@ -42,9 +42,9 @@ static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
bool input)
{
if (input)
- clrbits_be32(dirout, BIT(offset));
+ clrbits_32(dirout, BIT(offset));
else
- setbits_be32(dirout, BIT(offset));
+ setbits_32(dirout, BIT(offset));
return 0;
}
@@ -70,7 +70,7 @@ static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
{
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
- if (readl_be(priv->reg_dirout) & BIT(offset))
+ if (readl(priv->reg_dirout) & BIT(offset))
return GPIOF_OUTPUT;
else
return GPIOF_INPUT;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index cb7ca38d074..89ac8229f58 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1051,13 +1051,13 @@ static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
return -EINVAL;
if (ops->ooblen) {
- u64 maxooblen;
+ size_t maxooblen;
if (ops->ooboffs >= mtd_oobavail(mtd, ops))
return -EINVAL;
- maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
- mtd_div_by_ws(offs, mtd)) *
+ maxooblen = ((size_t)(mtd_div_by_ws(mtd->size, mtd) -
+ mtd_div_by_ws(offs, mtd)) *
mtd_oobavail(mtd, ops)) - ops->ooboffs;
if (ops->ooblen > maxooblen)
return -EINVAL;
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index 0bade208084..3681c5eed9a 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -12,12 +12,11 @@
#endif
#include <linux/mtd/spinand.h>
-#define SPINAND_MFR_GIGADEVICE 0xc8
+#define SPINAND_MFR_GIGADEVICE 0xC8
+#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
+#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
-#define GIGADEVICE_STATUS_ECC_MASK GENMASK(5, 4)
-#define GIGADEVICE_STATUS_ECC_NO_BITFLIPS (0 << 4)
-#define GIGADEVICE_STATUS_ECC_1TO7_BITFLIPS (1 << 4)
-#define GIGADEVICE_STATUS_ECC_8_BITFLIPS (3 << 4)
+#define GD5FXGQ4XEXXG_REG_STATUS2 0xf0
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
@@ -35,8 +34,8 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-static int gd5f1gq4u_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+static int gd5fxgq4xexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
@@ -47,38 +46,49 @@ static int gd5f1gq4u_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5f1gq4u_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+static int gd5fxgq4xexxg_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
- /* Reserve 2 bytes for the BBM. */
- region->offset = 2;
- region->length = 62;
+ /* Reserve 1 bytes for the BBM. */
+ region->offset = 1;
+ region->length = 63;
return 0;
}
-static const struct mtd_ooblayout_ops gd5f1gq4u_ooblayout = {
- .ecc = gd5f1gq4u_ooblayout_ecc,
- .free = gd5f1gq4u_ooblayout_free,
-};
-
-static int gd5f1gq4u_ecc_get_status(struct spinand_device *spinand,
- u8 status)
+static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
{
- if (status)
- debug("%s (%d): status=%02x\n", __func__, __LINE__, status);
+ u8 status2;
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4XEXXG_REG_STATUS2,
+ &status2);
+ int ret;
- switch (status & GIGADEVICE_STATUS_ECC_MASK) {
+ switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
- case GIGADEVICE_STATUS_ECC_1TO7_BITFLIPS:
- return 7;
-
- case GIGADEVICE_STATUS_ECC_8_BITFLIPS:
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+ /*
+ * Read status2 register to determine a more fine grained
+ * bit error status
+ */
+ ret = spi_mem_exec_op(spinand->slave, &op);
+ if (ret)
+ return ret;
+
+ /*
+ * 4 ... 7 bits are flipped (1..4 can't be detected, so
+ * report the maximum of 4 in this case
+ */
+ /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
+ return ((status & STATUS_ECC_MASK) >> 2) |
+ ((status2 & STATUS_ECC_MASK) >> 4);
+
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
return 8;
case STATUS_ECC_UNCOR_ERROR:
@@ -91,16 +101,21 @@ static int gd5f1gq4u_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
+static const struct mtd_ooblayout_ops gd5fxgq4xexxg_ooblayout = {
+ .ecc = gd5fxgq4xexxg_ooblayout_ecc,
+ .free = gd5fxgq4xexxg_ooblayout_free,
+};
+
static const struct spinand_info gigadevice_spinand_table[] = {
- SPINAND_INFO("GD5F1GQ4UC", 0xd1,
+ SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
- NAND_ECCREQ(8, 2048),
+ NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&gd5f1gq4u_ooblayout,
- gd5f1gq4u_ecc_get_status)),
+ SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout,
+ gd5fxgq4xexxg_ecc_get_status)),
};
static int gigadevice_spinand_detect(struct spinand_device *spinand)
@@ -109,8 +124,8 @@ static int gigadevice_spinand_detect(struct spinand_device *spinand)
int ret;
/*
- * Gigadevice SPI NAND read ID need a dummy byte,
- * so the first byte in raw_id is dummy.
+ * For GD NANDs, There is an address byte needed to shift in before IDs
+ * are read out, so the first byte in raw_id is dummy.
*/
if (id[1] != SPINAND_MFR_GIGADEVICE)
return 0;
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 5671bca24a0..d3b007a731d 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -62,6 +62,9 @@ config SF_DEFAULT_MODE
The default mode may be provided by the platform
to handle the common case when only a single serial
flash is present on the system.
+ Not used for boot with device tree; the SPI driver reads
+ speed and mode from platdata values computed from
+ available node.
config SF_DEFAULT_SPEED
int "SPI Flash default speed in Hz"
@@ -71,6 +74,9 @@ config SF_DEFAULT_SPEED
The default speed may be provided by the platform
to handle the common case when only a single serial
flash is present on the system.
+ Not used for boot with device tree; the SPI driver reads
+ speed and mode from platdata values computed from
+ available node.
if SPI_FLASH
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 7f1378f4946..73297e1a0a5 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -166,7 +166,6 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = {
};
static const struct udevice_id spi_flash_std_ids[] = {
- { .compatible = "spi-flash" },
{ .compatible = "jedec,spi-nor" },
{ }
};
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index b7f07338779..c4e2f6a08fa 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -524,8 +524,11 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info)
*/
static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
{
- u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
- int i;
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
+ SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_DATA);
if (nor->erase)
return nor->erase(nor, addr);
@@ -534,12 +537,7 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
* Default implementation, if driver doesn't have a specialized HW
* control
*/
- for (i = nor->addr_width - 1; i >= 0; i--) {
- buf[i] = addr & 0xff;
- addr >>= 8;
- }
-
- return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
+ return spi_mem_exec_op(nor->spi, &op);
}
/*
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 3215e2431dc..ec929760eee 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -106,6 +106,11 @@ const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
+ {
+ INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256,
+ SECT_4K | SPI_NOR_DUAL_READ |
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+ },
#endif
#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */
/* ISSI */
@@ -142,6 +147,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) },
{ INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { INFO("mx66u2g45g", 0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) },
#endif
@@ -187,6 +193,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("s25fl116k", 0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("s25fl164k", 0x014017, 0, 64 * 1024, 128, SECT_4K) },
{ INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) },
+ { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_SST /* SST */
diff --git a/drivers/net/ag7xxx.c b/drivers/net/ag7xxx.c
index 8146c3170e1..7f1dee4b3e4 100644
--- a/drivers/net/ag7xxx.c
+++ b/drivers/net/ag7xxx.c
@@ -3,6 +3,7 @@
* Atheros AR71xx / AR9xxx GMAC driver
*
* Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
*/
#include <common.h>
@@ -23,6 +24,8 @@ DECLARE_GLOBAL_DATA_PTR;
enum ag7xxx_model {
AG7XXX_MODEL_AG933X,
AG7XXX_MODEL_AG934X,
+ AG7XXX_MODEL_AG953X,
+ AG7XXX_MODEL_AG956X
};
/* MAC Configuration 1 */
@@ -99,8 +102,29 @@ enum ag7xxx_model {
/* Rx Status */
#define AG7XXX_ETH_DMA_RX_STATUS 0x194
+/* Custom register at 0x1805002C */
+#define AG7XXX_ETH_XMII 0x2C
+#define AG7XXX_ETH_XMII_TX_INVERT BIT(31)
+#define AG7XXX_ETH_XMII_RX_DELAY_LSB 28
+#define AG7XXX_ETH_XMII_RX_DELAY_MASK 0x30000000
+#define AG7XXX_ETH_XMII_RX_DELAY_SET(x) \
+ (((x) << AG7XXX_ETH_XMII_RX_DELAY_LSB) & AG7XXX_ETH_XMII_RX_DELAY_MASK)
+#define AG7XXX_ETH_XMII_TX_DELAY_LSB 26
+#define AG7XXX_ETH_XMII_TX_DELAY_MASK 0x0c000000
+#define AG7XXX_ETH_XMII_TX_DELAY_SET(x) \
+ (((x) << AG7XXX_ETH_XMII_TX_DELAY_LSB) & AG7XXX_ETH_XMII_TX_DELAY_MASK)
+#define AG7XXX_ETH_XMII_GIGE BIT(25)
+
/* Custom register at 0x18070000 */
#define AG7XXX_GMAC_ETH_CFG 0x00
+#define AG7XXX_ETH_CFG_RXDV_DELAY_LSB 16
+#define AG7XXX_ETH_CFG_RXDV_DELAY_MASK 0x00030000
+#define AG7XXX_ETH_CFG_RXDV_DELAY_SET(x) \
+ (((x) << AG7XXX_ETH_CFG_RXDV_DELAY_LSB) & AG7XXX_ETH_CFG_RXDV_DELAY_MASK)
+#define AG7XXX_ETH_CFG_RXD_DELAY_LSB 14
+#define AG7XXX_ETH_CFG_RXD_DELAY_MASK 0x0000c000
+#define AG7XXX_ETH_CFG_RXD_DELAY_SET(x) \
+ (((x) << AG7XXX_ETH_CFG_RXD_DELAY_LSB) & AG7XXX_ETH_CFG_RXD_DELAY_MASK)
#define AG7XXX_ETH_CFG_SW_PHY_ADDR_SWAP BIT(8)
#define AG7XXX_ETH_CFG_SW_PHY_SWAP BIT(7)
#define AG7XXX_ETH_CFG_SW_ONLY_MODE BIT(6)
@@ -197,24 +221,33 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
u32 reg_addr;
u32 phy_temp;
u32 reg_temp;
+ u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
u16 rv = 0;
int ret;
- if (priv->model == AG7XXX_MODEL_AG933X) {
+ if (priv->model == AG7XXX_MODEL_AG933X ||
+ priv->model == AG7XXX_MODEL_AG953X) {
phy_addr = 0x1f;
reg_addr = 0x10;
- } else if (priv->model == AG7XXX_MODEL_AG934X) {
+ } else if (priv->model == AG7XXX_MODEL_AG934X ||
+ priv->model == AG7XXX_MODEL_AG956X) {
phy_addr = 0x18;
reg_addr = 0x00;
} else
return -EINVAL;
- ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
+ if (priv->model == AG7XXX_MODEL_AG956X)
+ ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
+ else
+ ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
if (ret)
return ret;
phy_temp = ((reg >> 6) & 0x7) | 0x10;
- reg_temp = (reg >> 1) & 0x1e;
+ if (priv->model == AG7XXX_MODEL_AG956X)
+ reg_temp = reg_temp_w & 0x1f;
+ else
+ reg_temp = (reg >> 1) & 0x1e;
*val = 0;
ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 0, &rv);
@@ -222,7 +255,13 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
return ret;
*val |= rv;
- ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
+ if (priv->model == AG7XXX_MODEL_AG956X) {
+ phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
+ reg_temp = (reg_temp_w + 1) & 0x1f;
+ ret = ag7xxx_switch_read(bus, phy_temp, reg_temp, &rv);
+ } else {
+ ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
+ }
if (ret < 0)
return ret;
*val |= (rv << 16);
@@ -237,23 +276,34 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
u32 reg_addr;
u32 phy_temp;
u32 reg_temp;
+ u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
int ret;
- if (priv->model == AG7XXX_MODEL_AG933X) {
+ if (priv->model == AG7XXX_MODEL_AG933X ||
+ priv->model == AG7XXX_MODEL_AG953X) {
phy_addr = 0x1f;
reg_addr = 0x10;
- } else if (priv->model == AG7XXX_MODEL_AG934X) {
+ } else if (priv->model == AG7XXX_MODEL_AG934X ||
+ priv->model == AG7XXX_MODEL_AG956X) {
phy_addr = 0x18;
reg_addr = 0x00;
} else
return -EINVAL;
- ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
+ if (priv->model == AG7XXX_MODEL_AG956X)
+ ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
+ else
+ ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
if (ret)
return ret;
- phy_temp = ((reg >> 6) & 0x7) | 0x10;
- reg_temp = (reg >> 1) & 0x1e;
+ if (priv->model == AG7XXX_MODEL_AG956X) {
+ reg_temp = (reg_temp_w + 1) & 0x1f;
+ phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
+ } else {
+ phy_temp = ((reg >> 6) & 0x7) | 0x10;
+ reg_temp = (reg >> 1) & 0x1e;
+ }
/*
* The switch on AR933x has some special register behavior, which
@@ -272,10 +322,18 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
if (ret < 0)
return ret;
} else {
- ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
+ if (priv->model == AG7XXX_MODEL_AG956X)
+ ret = ag7xxx_switch_write(bus, phy_temp, reg_temp, val >> 16);
+ else
+ ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
if (ret < 0)
return ret;
+ if (priv->model == AG7XXX_MODEL_AG956X) {
+ phy_temp = ((reg_temp_w >> 5) & 0x7) | 0x10;
+ reg_temp = reg_temp_w & 0x1f;
+ }
+
ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
if (ret < 0)
return ret;
@@ -598,10 +656,19 @@ static int ag7xxx_mii_setup(struct udevice *dev)
return 0;
}
- if (priv->model == AG7XXX_MODEL_AG934X) {
- writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | 0x4,
+ if (priv->model == AG7XXX_MODEL_AG934X)
+ reg = 0x4;
+ else if (priv->model == AG7XXX_MODEL_AG953X)
+ reg = 0x2;
+ else if (priv->model == AG7XXX_MODEL_AG956X)
+ reg = 0x7;
+
+ if (priv->model == AG7XXX_MODEL_AG934X ||
+ priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X) {
+ writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | reg,
priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
- writel(0x4, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
+ writel(reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
return 0;
}
@@ -698,14 +765,126 @@ static int ag933x_phy_setup_lan(struct udevice *dev)
return 0;
}
+static int ag953x_phy_setup_wan(struct udevice *dev)
+{
+ int ret;
+ u32 reg = 0;
+ struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+
+ /* Set wan port connect to GE0 */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0x8, &reg);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x8, reg | BIT(28));
+ if (ret)
+ return ret;
+
+ /* Configure switch port 4 (GMAC0) */
+ ret = ag7xxx_switch_write(priv->bus, 4, MII_BMCR, 0x9000);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ag953x_phy_setup_lan(struct udevice *dev)
+{
+ struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+ int i, ret;
+ u32 reg = 0;
+
+ /* Reset the switch */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0, reg | BIT(31));
+ if (ret)
+ return ret;
+
+ do {
+ ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+ if (ret)
+ return ret;
+ } while (reg & BIT(31));
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x100, 0x4e);
+ if (ret)
+ return ret;
+
+ /* Set GMII mode */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0x4, &reg);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x4, reg | BIT(6));
+ if (ret)
+ return ret;
+
+ /* Configure switch ports 0...4 (GMAC1) */
+ for (i = 0; i < 5; i++) {
+ ret = ag7xxx_switch_write(priv->bus, i, MII_BMCR, 0x9000);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < 5; i++) {
+ ret = ag7xxx_switch_reg_write(priv->bus, (i + 2) * 0x100, BIT(9));
+ if (ret)
+ return ret;
+ }
+
+ /* QM Control */
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
+ if (ret)
+ return ret;
+
+ /* Disable Atheros header */
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
+ if (ret)
+ return ret;
+
+ /* Tag priority mapping */
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
+ if (ret)
+ return ret;
+
+ /* Enable ARP packets to the CPU */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg | 0x100000);
+ if (ret)
+ return ret;
+
+ /* Enable broadcast packets to the CPU */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0x2c, &reg);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x2c, reg | BIT(25) | BIT(26));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
{
struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
int ret;
- ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
- ADVERTISE_PAUSE_ASYM);
+ if (priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X) {
+ ret = ag7xxx_switch_write(priv->bus, port, MII_ADVERTISE,
+ ADVERTISE_ALL);
+ } else {
+ ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ }
if (ret)
return ret;
@@ -714,8 +893,18 @@ static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
ADVERTISE_1000FULL);
if (ret)
return ret;
+ } else if (priv->model == AG7XXX_MODEL_AG956X) {
+ ret = ag7xxx_switch_write(priv->bus, port, MII_CTRL1000,
+ ADVERTISE_1000FULL);
+ if (ret)
+ return ret;
}
+ if (priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X)
+ return ag7xxx_switch_write(priv->bus, port, MII_BMCR,
+ BMCR_ANENABLE | BMCR_RESET);
+
return ag7xxx_mdio_write(priv->bus, port, 0, MII_BMCR,
BMCR_ANENABLE | BMCR_RESET);
}
@@ -724,13 +913,24 @@ static int ag933x_phy_setup_reset_fin(struct udevice *dev, int port)
{
struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
int ret;
+ u16 reg;
- do {
- ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
- if (ret < 0)
- return ret;
- mdelay(10);
- } while (ret & BMCR_RESET);
+ if (priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X) {
+ do {
+ ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, &reg);
+ if (ret < 0)
+ return ret;
+ mdelay(10);
+ } while (reg & BMCR_RESET);
+ } else {
+ do {
+ ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
+ if (ret < 0)
+ return ret;
+ mdelay(10);
+ } while (ret & BMCR_RESET);
+ }
return 0;
}
@@ -739,10 +939,13 @@ static int ag933x_phy_setup_common(struct udevice *dev)
{
struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
int i, ret, phymax;
+ u16 reg;
if (priv->model == AG7XXX_MODEL_AG933X)
phymax = 4;
- else if (priv->model == AG7XXX_MODEL_AG934X)
+ else if (priv->model == AG7XXX_MODEL_AG934X ||
+ priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X)
phymax = 5;
else
return -EINVAL;
@@ -757,7 +960,10 @@ static int ag933x_phy_setup_common(struct udevice *dev)
return ret;
/* Read out link status */
- ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
+ if (priv->model == AG7XXX_MODEL_AG953X)
+ ret = ag7xxx_switch_read(priv->bus, phymax, MII_MIPSCR, &reg);
+ else
+ ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
if (ret < 0)
return ret;
@@ -779,7 +985,11 @@ static int ag933x_phy_setup_common(struct udevice *dev)
for (i = 0; i < phymax; i++) {
/* Read out link status */
- ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
+ if (priv->model == AG7XXX_MODEL_AG953X ||
+ priv->model == AG7XXX_MODEL_AG956X)
+ ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, &reg);
+ else
+ ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
if (ret < 0)
return ret;
}
@@ -841,6 +1051,63 @@ static int ag934x_phy_setup(struct udevice *dev)
return 0;
}
+static int ag956x_phy_setup(struct udevice *dev)
+{
+ struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+ int i, ret;
+ u32 reg, ctrl;
+
+ ret = ag7xxx_switch_reg_read(priv->bus, 0x0, &reg);
+ if (ret)
+ return ret;
+ if ((reg & 0xffff) >= 0x1301)
+ ctrl = 0xc74164de;
+ else
+ ctrl = 0xc74164d0;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x4, BIT(7));
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0xe0, ctrl);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
+ if (ret)
+ return ret;
+
+ /*
+ * Values suggested by the switch team when s17 in sgmii
+ * configuration. 0x10(S17_PWS_REG) = 0x602613a0
+ */
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x602613a0);
+ if (ret)
+ return ret;
+
+ ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
+ if (ret)
+ return ret;
+
+ /* AR8337/AR8334 v1.0 fixup */
+ ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+ if (ret)
+ return ret;
+ if ((reg & 0xffff) == 0x1301) {
+ for (i = 0; i < 5; i++) {
+ /* Turn on Gigabit clock */
+ ret = ag7xxx_switch_write(priv->bus, i, 0x1d, 0x3d);
+ if (ret)
+ return ret;
+ ret = ag7xxx_switch_write(priv->bus, i, 0x1e, 0x6820);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ag7xxx_mac_probe(struct udevice *dev)
{
struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
@@ -858,8 +1125,15 @@ static int ag7xxx_mac_probe(struct udevice *dev)
ret = ag933x_phy_setup_wan(dev);
else
ret = ag933x_phy_setup_lan(dev);
+ } else if (priv->model == AG7XXX_MODEL_AG953X) {
+ if (priv->interface == PHY_INTERFACE_MODE_RMII)
+ ret = ag953x_phy_setup_wan(dev);
+ else
+ ret = ag953x_phy_setup_lan(dev);
} else if (priv->model == AG7XXX_MODEL_AG934X) {
ret = ag934x_phy_setup(dev);
+ } else if (priv->model == AG7XXX_MODEL_AG956X) {
+ ret = ag956x_phy_setup(dev);
} else {
return -EINVAL;
}
@@ -997,6 +1271,8 @@ static int ag7xxx_eth_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id ag7xxx_eth_ids[] = {
{ .compatible = "qca,ag933x-mac", .data = AG7XXX_MODEL_AG933X },
{ .compatible = "qca,ag934x-mac", .data = AG7XXX_MODEL_AG934X },
+ { .compatible = "qca,ag953x-mac", .data = AG7XXX_MODEL_AG953X },
+ { .compatible = "qca,ag956x-mac", .data = AG7XXX_MODEL_AG956X },
{ }
};
diff --git a/drivers/net/mscc_eswitch/Kconfig b/drivers/net/mscc_eswitch/Kconfig
index 88e5a97c4bf..6359d0b6101 100644
--- a/drivers/net/mscc_eswitch/Kconfig
+++ b/drivers/net/mscc_eswitch/Kconfig
@@ -15,3 +15,17 @@ config MSCC_LUTON_SWITCH
select PHYLIB
help
This driver supports the Luton network switch device.
+
+config MSCC_JR2_SWITCH
+ bool "Jaguar2 switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Jaguar2 network switch device.
+
+config MSCC_SERVALT_SWITCH
+ bool "Servalt switch driver"
+ depends on DM_ETH && ARCH_MSCC
+ select PHYLIB
+ help
+ This driver supports the Servalt network switch device.
diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile
index 751a839a5f0..bffd8ec77b0 100644
--- a/drivers/net/mscc_eswitch/Makefile
+++ b/drivers/net/mscc_eswitch/Makefile
@@ -1,3 +1,5 @@
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
+obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o
+obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o
diff --git a/drivers/net/mscc_eswitch/jr2_switch.c b/drivers/net/mscc_eswitch/jr2_switch.c
new file mode 100644
index 00000000000..60d408f1c75
--- /dev/null
+++ b/drivers/net/mscc_eswitch/jr2_switch.c
@@ -0,0 +1,1075 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include <dt-bindings/mscc/jr2_data.h>
+#include "mscc_xfer.h"
+
+#define GCB_MIIM_MII_STATUS 0x0
+#define GCB_MIIM_STAT_BUSY BIT(3)
+#define GCB_MIIM_MII_CMD 0x8
+#define GCB_MIIM_MII_CMD_SCAN BIT(0)
+#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
+#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
+#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3)
+#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
+#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
+#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
+#define GCB_MIIM_MII_CMD_VLD BIT(31)
+#define GCB_MIIM_DATA 0xC
+#define GCB_MIIM_DATA_ERROR (0x3 << 16)
+
+#define ANA_AC_RAM_CTRL_RAM_INIT 0x94358
+#define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x94370
+
+#define ANA_CL_PORT_VLAN_CFG(x) (0x24018 + 0xc8 * (x))
+#define ANA_CL_PORT_VLAN_CFG_AWARE_ENA BIT(19)
+#define ANA_CL_PORT_VLAN_CFG_POP_CNT(x) ((x) << 17)
+
+#define ANA_L2_COMMON_FWD_CFG 0x8a2a8
+#define ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA BIT(6)
+
+#define ASM_CFG_STAT_CFG 0x3508
+#define ASM_CFG_PORT(x) (0x36c4 + 0x4 * (x))
+#define ASM_CFG_PORT_NO_PREAMBLE_ENA BIT(8)
+#define ASM_CFG_PORT_INJ_FORMAT_CFG(x) ((x) << 1)
+#define ASM_RAM_CTRL_RAM_INIT 0x39b8
+
+#define DEV_DEV_CFG_DEV_RST_CTRL 0x0
+#define DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(x) ((x) << 20)
+#define DEV_MAC_CFG_MAC_ENA 0x1c
+#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+#define DEV_MAC_CFG_MAC_IFG 0x34
+#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
+#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
+#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
+#define DEV_PCS1G_CFG_PCS1G_SD 0x48
+#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
+#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
+
+#define DSM_RAM_CTRL_RAM_INIT 0x8
+
+#define HSIO_ANA_SERDES1G_DES_CFG 0xac
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
+#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
+#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG 0xb0
+#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
+#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
+#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19)
+#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG 0xb4
+#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
+#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG 0xb8
+#define HSIO_ANA_SERDES1G_COMMON_CFG 0xbc
+#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
+#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG 0xc0
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
+#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
+#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0 0xc8
+#define HSIO_DIG_SERDES1G_TP_CFG 0xd4
+#define HSIO_DIG_SERDES1G_MISC_CFG 0xdc
+#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES1G_CFG 0xe8
+#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
+
+#define HSIO_ANA_SERDES6G_DES_CFG 0x11c
+#define HSIO_ANA_SERDES6G_DES_CFG_SWAP_ANA BIT(0)
+#define HSIO_ANA_SERDES6G_DES_CFG_BW_ANA(x) ((x) << 1)
+#define HSIO_ANA_SERDES6G_DES_CFG_SWAP_HYST BIT(4)
+#define HSIO_ANA_SERDES6G_DES_CFG_BW_HYST(x) ((x) << 5)
+#define HSIO_ANA_SERDES6G_DES_CFG_CPMD_SEL(x) ((x) << 8)
+#define HSIO_ANA_SERDES6G_DES_CFG_MBTR_CTRL(x) ((x) << 10)
+#define HSIO_ANA_SERDES6G_DES_CFG_PHS_CTRL(x) ((x) << 13)
+#define HSIO_ANA_SERDES6G_IB_CFG 0x120
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_ENA BIT(0)
+#define HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA BIT(1)
+#define HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA BIT(2)
+#define HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(x) ((x) << 3)
+#define HSIO_ANA_SERDES6G_IB_CFG_CONCUR BIT(4)
+#define HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA BIT(5)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(x) ((x) << 7)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(x) ((x) << 9)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(x) ((x) << 11)
+#define HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(x) ((x) << 13)
+#define HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(x) ((x) << 15)
+#define HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(x) ((x) << 20)
+#define HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(x) ((x) << 24)
+#define HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL BIT(28)
+#define HSIO_ANA_SERDES6G_IB_CFG_SOFSI(x) ((x) << 29)
+#define HSIO_ANA_SERDES6G_IB_CFG1 0x124
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET BIT(4)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP BIT(5)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID BIT(6)
+#define HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP BIT(7)
+#define HSIO_ANA_SERDES6G_IB_CFG1_SCALY(x) ((x) << 8)
+#define HSIO_ANA_SERDES6G_IB_CFG1_TSDET(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(x) ((x) << 17)
+#define HSIO_ANA_SERDES6G_IB_CFG2 0x128
+#define HSIO_ANA_SERDES6G_IB_CFG2_UREG(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG2_UMAX(x) ((x) << 3)
+#define HSIO_ANA_SERDES6G_IB_CFG2_TCALV(x) ((x) << 5)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OCALS(x) ((x) << 10)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OINFS(x) ((x) << 16)
+#define HSIO_ANA_SERDES6G_IB_CFG2_OINFI(x) ((x) << 22)
+#define HSIO_ANA_SERDES6G_IB_CFG2_TINFV(x) ((x) << 27)
+#define HSIO_ANA_SERDES6G_IB_CFG3 0x12c
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG3_INI_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG4 0x130
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MAX_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_IB_CFG5 0x134
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_OFFSET(x) (x)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_LP(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_MID(x) ((x) << 12)
+#define HSIO_ANA_SERDES6G_IB_CFG4_MIN_HP(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_OB_CFG 0x138
+#define HSIO_ANA_SERDES6G_OB_CFG_RESISTOR_CTRL(x) (x)
+#define HSIO_ANA_SERDES6G_OB_CFG_SR(x) ((x) << 4)
+#define HSIO_ANA_SERDES6G_OB_CFG_SR_H BIT(8)
+#define HSIO_ANA_SERDES6G_OB_CFG_SEL_RCTRL BIT(9)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_COR BIT(10)
+#define HSIO_ANA_SERDES6G_OB_CFG_POST1(x) ((x) << 11)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_ADJ_PDR BIT(16)
+#define HSIO_ANA_SERDES6G_OB_CFG_R_ADJ_MUX BIT(17)
+#define HSIO_ANA_SERDES6G_OB_CFG_PREC(x) ((x) << 18)
+#define HSIO_ANA_SERDES6G_OB_CFG_POST0(x) ((x) << 23)
+#define HSIO_ANA_SERDES6G_OB_CFG_POL BIT(29)
+#define HSIO_ANA_SERDES6G_OB_CFG_ENA1V_MODE(x) ((x) << 30)
+#define HSIO_ANA_SERDES6G_OB_CFG_IDLE BIT(31)
+#define HSIO_ANA_SERDES6G_OB_CFG1 0x13c
+#define HSIO_ANA_SERDES6G_OB_CFG1_LEV(x) (x)
+#define HSIO_ANA_SERDES6G_OB_CFG1_ENA_CAS(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_SER_CFG 0x140
+#define HSIO_ANA_SERDES6G_COMMON_CFG 0x144
+#define HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(x) (x)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_QRATE(x) (x << 2)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_ENA_LANE BIT(14)
+#define HSIO_ANA_SERDES6G_COMMON_CFG_SYS_RST BIT(16)
+#define HSIO_ANA_SERDES6G_PLL_CFG 0x148
+#define HSIO_ANA_SERDES6G_PLL_CFG_ROT_FRQ BIT(0)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ROT_DIR BIT(1)
+#define HSIO_ANA_SERDES6G_PLL_CFG_RB_DATA_SEL BIT(2)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_OOR_RECAL_ENA BIT(3)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_FORCE_SET_ENA BIT(4)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_ENA BIT(5)
+#define HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 6)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ENA_ROT BIT(14)
+#define HSIO_ANA_SERDES6G_PLL_CFG_DIV4 BIT(15)
+#define HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(x) ((x) << 16)
+#define HSIO_DIG_SERDES6G_MISC_CFG 0x108
+#define HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST BIT(0)
+#define HSIO_MCB_SERDES6G_CFG 0x168
+#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
+#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
+#define HSIO_HW_CFGSTAT_HW_CFG 0x16c
+
+#define LRN_COMMON_ACCESS_CTRL 0x0
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT BIT(0)
+#define LRN_COMMON_MAC_ACCESS_CFG0 0x4
+#define LRN_COMMON_MAC_ACCESS_CFG1 0x8
+#define LRN_COMMON_MAC_ACCESS_CFG2 0xc
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(x) (x)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(x) ((x) << 12)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD BIT(15)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED BIT(16)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY BIT(23)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(x) ((x) << 24)
+
+#define QFWD_SYSTEM_SWITCH_PORT_MODE(x) (0x4 * (x))
+#define QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA BIT(17)
+
+#define QS_XTR_GRP_CFG(x) (0x0 + 4 * (x))
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+
+#define QSYS_SYSTEM_RESET_CFG 0xf0
+#define QSYS_CALCFG_CAL_AUTO(x) (0x3d4 + 4 * (x))
+#define QSYS_CALCFG_CAL_CTRL 0x3e8
+#define QSYS_CALCFG_CAL_CTRL_CAL_MODE(x) ((x) << 11)
+#define QSYS_RAM_CTRL_RAM_INIT 0x3ec
+
+#define REW_RAM_CTRL_RAM_INIT 0x53528
+
+#define VOP_RAM_CTRL_RAM_INIT 0x43638
+
+#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
+#define MAC_VID 0
+#define CPU_PORT 53
+#define IFH_LEN 7
+#define JR2_BUF_CELL_SZ 60
+#define ETH_ALEN 6
+#define PGID_BROADCAST 510
+#define PGID_UNICAST 511
+
+static const char * const regs_names[] = {
+ "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+ "port8", "port9", "port10", "port11", "port12", "port13", "port14",
+ "port15", "port16", "port17", "port18", "port19", "port20", "port21",
+ "port22", "port23", "port24", "port25", "port26", "port27", "port28",
+ "port29", "port30", "port31", "port32", "port33", "port34", "port35",
+ "port36", "port37", "port38", "port39", "port40", "port41", "port42",
+ "port43", "port44", "port45", "port46", "port47",
+ "ana_ac", "ana_cl", "ana_l2", "asm", "hsio", "lrn",
+ "qfwd", "qs", "qsys", "rew",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 48
+
+enum jr2_ctrl_regs {
+ ANA_AC = MAX_PORT,
+ ANA_CL,
+ ANA_L2,
+ ASM,
+ HSIO,
+ LRN,
+ QFWD,
+ QS,
+ QSYS,
+ REW,
+};
+
+#define JR2_MIIM_BUS_COUNT 3
+
+struct jr2_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+ u8 serdes_index;
+ u8 phy_mode;
+};
+
+struct jr2_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[JR2_MIIM_BUS_COUNT];
+ struct jr2_phy_port_t ports[MAX_PORT];
+};
+
+struct jr2_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
+};
+
+static const unsigned long jr2_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static struct jr2_miim_dev miim[JR2_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static int mscc_miim_wait_ready(struct jr2_miim_dev *miim)
+{
+ unsigned long deadline;
+ u32 val;
+
+ deadline = timer_get_us() + 250000;
+
+ do {
+ val = readl(miim->regs + GCB_MIIM_MII_STATUS);
+ } while (timer_get_us() <= deadline && (val & GCB_MIIM_STAT_BUSY));
+
+ if (val & GCB_MIIM_STAT_BUSY)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+ miim->regs + GCB_MIIM_MII_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + GCB_MIIM_DATA);
+ if (val & GCB_MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+ out:
+ return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+ GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+
+ out:
+ return ret;
+}
+
+static struct mii_dev *jr2_mdiobus_init(phys_addr_t miim_base,
+ unsigned long miim_size)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return NULL;
+
+ ++miim_count;
+ sprintf(bus->name, "miim-bus%d", miim_count);
+
+ miim[miim_count].regs = ioremap(miim_base, miim_size);
+ miim[miim_count].miim_base = miim_base;
+ miim[miim_count].miim_size = miim_size;
+ bus->priv = &miim[miim_count];
+ bus->read = mscc_miim_read;
+ bus->write = mscc_miim_write;
+
+ if (mdio_register(bus))
+ return NULL;
+
+ miim[miim_count].bus = bus;
+ return bus;
+}
+
+static void jr2_cpu_capture_setup(struct jr2_private *priv)
+{
+ /* ASM: No preamble and IFH prefix on CPU injected frames */
+ writel(ASM_CFG_PORT_NO_PREAMBLE_ENA |
+ ASM_CFG_PORT_INJ_FORMAT_CFG(1),
+ priv->regs[ASM] + ASM_CFG_PORT(CPU_PORT));
+
+ /* Set Manual injection via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x5, priv->regs[QS] + QS_INJ_GRP_CFG(0));
+
+ /* Set Manual extraction via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x7, priv->regs[QS] + QS_XTR_GRP_CFG(0));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(CPU_PORT),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* Send a copy to CPU when found as forwarding entry */
+ setbits_le32(priv->regs[ANA_L2] + ANA_L2_COMMON_FWD_CFG,
+ ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA);
+}
+
+static void jr2_port_init(struct jr2_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+ regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+ regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(4) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG1(5) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG2(1),
+ regs + DEV_MAC_CFG_MAC_IFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(2),
+ regs + DEV_DEV_CFG_DEV_RST_CTRL);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_CL_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_CL_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA_CL] + ANA_CL_PORT_VLAN_CFG(port));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(port),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes6g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES6G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES6G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES6G_CFG);
+ } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes6g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ u32 ib_if_mode = 0;
+ u32 ib_qrate = 0;
+ u32 ib_cal_ena = 0;
+ u32 ib1_tsdet = 0;
+ u32 ob_lev = 0;
+ u32 ob_ena_cas = 0;
+ u32 ob_ena1v_mode = 0;
+ u32 des_bw_ana = 0;
+ u32 pll_fsm_ctrl_data = 0;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ib_if_mode = 1;
+ ib_qrate = 1;
+ ib_cal_ena = 1;
+ ib1_tsdet = 3;
+ ob_lev = 48;
+ ob_ena_cas = 2;
+ ob_ena1v_mode = 1;
+ des_bw_ana = 3;
+ pll_fsm_ctrl_data = 60;
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+ ib_if_mode = 3;
+ ib1_tsdet = 16;
+ ob_lev = 24;
+ des_bw_ana = 5;
+ pll_fsm_ctrl_data = 120;
+ break;
+ default:
+ pr_err("Interface not supported\n");
+ return;
+ }
+
+ if (interface == PHY_INTERFACE_MODE_QSGMII)
+ writel(0xfff, base + HSIO_HW_CFGSTAT_HW_CFG);
+
+ writel(HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(3),
+ base + HSIO_ANA_SERDES6G_COMMON_CFG);
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(120) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(7) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(3) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+ writel(HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ serdes6g_write(base, addr);
+
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(16) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+
+ writel(0x0, base + HSIO_ANA_SERDES6G_SER_CFG);
+ writel(HSIO_ANA_SERDES6G_COMMON_CFG_IF_MODE(ib_if_mode) |
+ HSIO_ANA_SERDES6G_COMMON_CFG_QRATE(ib_qrate) |
+ HSIO_ANA_SERDES6G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES6G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES6G_COMMON_CFG);
+ writel(HSIO_DIG_SERDES6G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ writel(HSIO_ANA_SERDES6G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR(7) |
+ HSIO_ANA_SERDES6G_OB_CFG_SR_H |
+ HSIO_ANA_SERDES6G_OB_CFG_ENA1V_MODE(ob_ena1v_mode) |
+ HSIO_ANA_SERDES6G_OB_CFG_POL, base + HSIO_ANA_SERDES6G_OB_CFG);
+ writel(HSIO_ANA_SERDES6G_OB_CFG1_LEV(ob_lev) |
+ HSIO_ANA_SERDES6G_OB_CFG1_ENA_CAS(ob_ena_cas),
+ base + HSIO_ANA_SERDES6G_OB_CFG1);
+
+ writel(HSIO_ANA_SERDES6G_DES_CFG_BW_ANA(des_bw_ana) |
+ HSIO_ANA_SERDES6G_DES_CFG_BW_HYST(5) |
+ HSIO_ANA_SERDES6G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES6G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES6G_DES_CFG);
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(pll_fsm_ctrl_data) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* set pll_fsm_ena = 1 */
+ writel(HSIO_ANA_SERDES6G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES6G_PLL_CFG_FSM_CTRL_DATA(pll_fsm_ctrl_data) |
+ HSIO_ANA_SERDES6G_PLL_CFG_ENA_OFFS(3),
+ base + HSIO_ANA_SERDES6G_PLL_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* wait 20ms for pll bringup */
+ mdelay(20);
+
+ /* start IB calibration by setting ib_cal_ena and clearing lane_rst */
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(ib_cal_ena) |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES6G_MISC_CFG);
+
+ serdes6g_write(base, addr);
+
+ /* wait 60 for calibration */
+ mdelay(60);
+
+ /* set ib_tsdet and ib_reg_pat_sel_offset back to correct values */
+ writel(HSIO_ANA_SERDES6G_IB_CFG_REG_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_EQZ_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_SAM_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_CAL_ENA(ib_cal_ena) |
+ HSIO_ANA_SERDES6G_IB_CFG_CONCUR |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_ENA |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_OFF(0) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_LP(2) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_MID(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_REG_PAT_SEL_HP(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_SIG_DET_CLK_SEL(7) |
+ HSIO_ANA_SERDES6G_IB_CFG_TERM_MODE_SEL(1) |
+ HSIO_ANA_SERDES6G_IB_CFG_ICML_ADJ(5) |
+ HSIO_ANA_SERDES6G_IB_CFG_RTRM_ADJ(13) |
+ HSIO_ANA_SERDES6G_IB_CFG_VBULK_SEL |
+ HSIO_ANA_SERDES6G_IB_CFG_SOFSI(1),
+ base + HSIO_ANA_SERDES6G_IB_CFG);
+ writel(HSIO_ANA_SERDES6G_IB_CFG1_FILT_OFFSET |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_LP |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_MID |
+ HSIO_ANA_SERDES6G_IB_CFG1_FILT_HP |
+ HSIO_ANA_SERDES6G_IB_CFG1_SCALY(15) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TSDET(ib1_tsdet) |
+ HSIO_ANA_SERDES6G_IB_CFG1_TJTAG(8),
+ base + HSIO_ANA_SERDES6G_IB_CFG1);
+
+ serdes6g_write(base, addr);
+}
+
+static void serdes1g_write(void __iomem *base, u32 addr)
+{
+ u32 data;
+
+ writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+ HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+ base + HSIO_MCB_SERDES1G_CFG);
+
+ do {
+ data = readl(base + HSIO_MCB_SERDES1G_CFG);
+ } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+ phy_interface_t interface)
+{
+ writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_TP_CFG);
+ writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+ writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+ HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+ HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+ HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+ HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+ base + HSIO_ANA_SERDES1G_OB_CFG);
+ writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(13) |
+ HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(2) |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV |
+ HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+ HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(3) |
+ HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+ base + HSIO_ANA_SERDES1G_IB_CFG);
+ writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+ HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+ HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+ HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+ base + HSIO_ANA_SERDES1G_DES_CFG);
+ writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+ base + HSIO_DIG_SERDES1G_MISC_CFG);
+ writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+ HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(0xc8) |
+ HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+ base + HSIO_ANA_SERDES1G_PLL_CFG);
+ writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+ base + HSIO_ANA_SERDES1G_COMMON_CFG);
+
+ serdes1g_write(base, addr);
+
+ setbits_le32(base + HSIO_ANA_SERDES1G_COMMON_CFG,
+ HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST);
+
+ serdes1g_write(base, addr);
+
+ clrbits_le32(base + HSIO_DIG_SERDES1G_MISC_CFG,
+ HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST);
+
+ serdes1g_write(base, addr);
+}
+
+static int ram_init(u32 val, void __iomem *addr)
+{
+ writel(val, addr);
+
+ if (wait_for_bit_le32(addr, BIT(1), false, 2000, false)) {
+ printf("Timeout in memory reset, reg = 0x%08x\n", val);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int jr2_switch_init(struct jr2_private *priv)
+{
+ /* Initialize memories */
+ ram_init(0x3, priv->regs[QSYS] + QSYS_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ASM] + ASM_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ANA_AC] + ANA_AC_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[REW] + REW_RAM_CTRL_RAM_INIT);
+
+ /* Reset counters */
+ writel(0x1, priv->regs[ANA_AC] + ANA_AC_STAT_GLOBAL_CFG_PORT_RESET);
+ writel(0x1, priv->regs[ASM] + ASM_CFG_STAT_CFG);
+
+ /* Enable switch-core and queue system */
+ writel(0x1, priv->regs[QSYS] + QSYS_SYSTEM_RESET_CFG);
+
+ return 0;
+}
+
+static void jr2_switch_config(struct jr2_private *priv)
+{
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(0));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(1));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(2));
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO(3));
+
+ writel(readl(priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL) |
+ QSYS_CALCFG_CAL_CTRL_CAL_MODE(8),
+ priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL);
+}
+
+static int jr2_initialize(struct jr2_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = jr2_switch_init(priv);
+ if (ret)
+ return ret;
+
+ jr2_switch_config(priv);
+
+ for (i = 0; i < MAX_PORT; i++)
+ jr2_port_init(priv, i);
+
+ jr2_cpu_capture_setup(priv);
+
+ return 0;
+}
+
+static inline int jr2_vlant_wait_for_completion(struct jr2_private *priv)
+{
+ if (wait_for_bit_le32(priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL,
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ false, 2000, false))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int jr2_mac_table_add(struct jr2_private *priv,
+ const unsigned char mac[ETH_ALEN], int pgid)
+{
+ u32 macl = 0, mach = 0;
+
+ /*
+ * Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= MAC_VID << 16;
+ mach |= ((u32)mac[0]) << 8;
+ mach |= ((u32)mac[1]) << 0;
+ macl |= ((u32)mac[2]) << 24;
+ macl |= ((u32)mac[3]) << 16;
+ macl |= ((u32)mac[4]) << 8;
+ macl |= ((u32)mac[5]) << 0;
+
+ writel(mach, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG0);
+ writel(macl, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG1);
+
+ writel(LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(pgid) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(0x3) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(0) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED,
+ priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG2);
+
+ writel(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL);
+
+ return jr2_vlant_wait_for_completion(priv);
+}
+
+static int jr2_write_hwaddr(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ return jr2_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+}
+
+static void serdes_setup(struct jr2_private *priv)
+{
+ size_t mask;
+ int i = 0;
+
+ for (i = 0; i < MAX_PORT; ++i) {
+ if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+ continue;
+
+ mask = BIT(priv->ports[i].serdes_index);
+ if (priv->ports[i].serdes_index < SERDES1G_MAX) {
+ serdes1g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ } else {
+ mask >>= SERDES6G(0);
+ serdes6g_setup(priv->regs[HSIO], mask,
+ priv->ports[i].phy_mode);
+ }
+ }
+}
+
+static int jr2_start(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const unsigned char mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = jr2_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ ret = jr2_mac_table_add(priv, mac, PGID_BROADCAST);
+ if (ret)
+ return ret;
+
+ ret = jr2_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+ if (ret)
+ return ret;
+
+ serdes_setup(priv);
+
+ return 0;
+}
+
+static void jr2_stop(struct udevice *dev)
+{
+}
+
+static int jr2_send(struct udevice *dev, void *packet, int length)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ memset(ifh, '\0', IFH_LEN);
+
+ /* Set DST PORT_MASK */
+ ifh[0] = htonl(0);
+ ifh[1] = htonl(0x1FFFFF);
+ ifh[2] = htonl(~0);
+ /* Set DST_MODE to INJECT and UPDATE_FCS */
+ ifh[5] = htonl(0x4c0);
+
+ return mscc_send(priv->regs[QS], jr2_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int jr2_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], jr2_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < JR2_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct jr2_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus,
+ u8 serdes_index, u8 phy_mode)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+ priv->ports[index].serdes_index = serdes_index;
+ priv->ports[index].phy_mode = phy_mode;
+}
+
+static int jr2_probe(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ int i;
+ int ret;
+ struct resource res;
+ fdt32_t faddr;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+ struct phy_device *phy;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct jr2_miim_dev) * JR2_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+ 0, 0, &phandle);
+ if (ret)
+ continue;
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ faddr = cpu_to_fdt32(res.start);
+
+ addr_base = ofnode_translate_address(mdio_node, &faddr);
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ jr2_mdiobus_init(addr_base, addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+
+ /* Get serdes info */
+ ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+ 3, 0, &phandle);
+ if (ret)
+ return -ENOMEM;
+
+ add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+ phandle.args[2]);
+ }
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy = phy_connect(priv->ports[i].bus,
+ priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ if (phy)
+ board_phy_config(phy);
+ }
+
+ return 0;
+}
+
+static int jr2_remove(struct udevice *dev)
+{
+ struct jr2_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < JR2_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops jr2_ops = {
+ .start = jr2_start,
+ .stop = jr2_stop,
+ .send = jr2_send,
+ .recv = jr2_recv,
+ .write_hwaddr = jr2_write_hwaddr,
+};
+
+static const struct udevice_id mscc_jr2_ids[] = {
+ {.compatible = "mscc,vsc7454-switch" },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(jr2) = {
+ .name = "jr2-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_jr2_ids,
+ .probe = jr2_probe,
+ .remove = jr2_remove,
+ .ops = &jr2_ops,
+ .priv_auto_alloc_size = sizeof(struct jr2_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c
index bf08c35ba04..815c2da2646 100644
--- a/drivers/net/mscc_eswitch/ocelot_switch.c
+++ b/drivers/net/mscc_eswitch/ocelot_switch.c
@@ -142,18 +142,16 @@ static const unsigned long ocelot_regs_ana_table[] = {
static struct mscc_miim_dev miim[NUM_PHY];
-static int mscc_miim_reset(struct mii_dev *bus)
+static void mscc_phy_reset(void)
{
- struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
-
- if (miim->phy_regs) {
- writel(0, miim->phy_regs + PHY_CFG);
- writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
- | PHY_CFG_ENA, miim->phy_regs + PHY_CFG);
- mdelay(500);
+ writel(0, miim[INTERNAL].phy_regs + PHY_CFG);
+ writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
+ | PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG);
+ if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT,
+ PHY_STAT_SUPERVISOR_COMPLETE,
+ true, 2000, false)) {
+ pr_err("Timeout in phy reset\n");
}
-
- return 0;
}
/* For now only setup the internal mdio bus */
@@ -194,7 +192,6 @@ static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
bus->priv = &miim[INTERNAL];
- bus->reset = mscc_miim_reset;
bus->read = mscc_miim_read;
bus->write = mscc_miim_write;
@@ -210,13 +207,8 @@ __weak void mscc_switch_reset(void)
static void ocelot_stop(struct udevice *dev)
{
- struct ocelot_private *priv = dev_get_priv(dev);
- int i;
-
mscc_switch_reset();
- for (i = 0; i < NUM_PHY; i++)
- if (priv->bus[i])
- mscc_miim_reset(priv->bus[i]);
+ mscc_phy_reset();
}
static void ocelot_cpu_capture_setup(struct ocelot_private *priv)
@@ -473,6 +465,7 @@ static int ocelot_probe(struct udevice *dev)
}
priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
+ mscc_phy_reset();
for (i = 0; i < 4; i++) {
phy_connect(priv->bus[INTERNAL], i, dev,
diff --git a/drivers/net/mscc_eswitch/servalt_switch.c b/drivers/net/mscc_eswitch/servalt_switch.c
new file mode 100644
index 00000000000..995c62309d2
--- /dev/null
+++ b/drivers/net/mscc_eswitch/servalt_switch.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+
+#define GCB_MIIM_MII_STATUS 0x0
+#define GCB_MIIM_STAT_BUSY BIT(3)
+#define GCB_MIIM_MII_CMD 0x8
+#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
+#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
+#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
+#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
+#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
+#define GCB_MIIM_MII_CMD_VLD BIT(31)
+#define GCB_MIIM_DATA 0xC
+#define GCB_MIIM_DATA_ERROR (0x3 << 16)
+
+#define PHY_CFG 0x0
+#define PHY_CFG_ENA 0x3
+#define PHY_CFG_COMMON_RST BIT(2)
+#define PHY_CFG_RST (0x3 << 3)
+#define PHY_STAT 0x4
+#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
+
+#define ANA_AC_RAM_CTRL_RAM_INIT 0x14fdc
+#define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x15474
+
+#define ANA_CL_PORT_VLAN_CFG(x) (0xa018 + 0xc8 * (x))
+#define ANA_CL_PORT_VLAN_CFG_AWARE_ENA BIT(19)
+#define ANA_CL_PORT_VLAN_CFG_POP_CNT(x) ((x) << 17)
+
+#define ANA_L2_COMMON_FWD_CFG 0x18498
+#define ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA BIT(6)
+
+#define ASM_CFG_STAT_CFG 0xb08
+#define ASM_CFG_PORT(x) (0xb74 + 0x4 * (x))
+#define ASM_CFG_PORT_NO_PREAMBLE_ENA BIT(8)
+#define ASM_CFG_PORT_INJ_FORMAT_CFG(x) ((x) << 1)
+#define ASM_RAM_CTRL_RAM_INIT 0xbfc
+
+#define DEV_DEV_CFG_DEV_RST_CTRL 0x0
+#define DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(x) ((x) << 20)
+#define DEV_MAC_CFG_MAC_ENA 0x24
+#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
+#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
+#define DEV_MAC_CFG_MAC_IFG 0x3c
+#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
+#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
+#define DEV_PCS1G_CFG_PCS1G_CFG 0x48
+#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV_PCS1G_CFG_PCS1G_MODE 0x4c
+#define DEV_PCS1G_CFG_PCS1G_SD 0x50
+#define DEV_PCS1G_CFG_PCS1G_ANEG 0x54
+#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
+
+#define LRN_COMMON_ACCESS_CTRL 0x0
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT BIT(0)
+#define LRN_COMMON_MAC_ACCESS_CFG0 0x4
+#define LRN_COMMON_MAC_ACCESS_CFG1 0x8
+#define LRN_COMMON_MAC_ACCESS_CFG2 0xc
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(x) (x)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(x) ((x) << 12)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD BIT(15)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED BIT(16)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY BIT(23)
+#define LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(x) ((x) << 24)
+
+#define QFWD_SYSTEM_SWITCH_PORT_MODE(x) (0x4400 + 0x4 * (x))
+#define QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA BIT(17)
+
+#define QS_XTR_GRP_CFG(x) (4 * (x))
+#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
+
+#define QSYS_SYSTEM_RESET_CFG 0x1048
+#define QSYS_CALCFG_CAL_AUTO 0x1134
+#define QSYS_CALCFG_CAL_CTRL 0x113c
+#define QSYS_CALCFG_CAL_CTRL_CAL_MODE(x) ((x) << 11)
+#define QSYS_RAM_CTRL_RAM_INIT 0x1140
+
+#define REW_RAM_CTRL_RAM_INIT 0xFFF4
+
+#define MAC_VID 0
+#define CPU_PORT 11
+#define IFH_LEN 7
+#define ETH_ALEN 6
+#define PGID_BROADCAST 50
+#define PGID_UNICAST 51
+
+static const char * const regs_names[] = {
+ "port0", "port1",
+ "ana_ac", "ana_cl", "ana_l2", "asm", "lrn", "qfwd", "qs", "qsys", "rew",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 2
+
+enum servalt_ctrl_regs {
+ ANA_AC = MAX_PORT,
+ ANA_CL,
+ ANA_L2,
+ ASM,
+ LRN,
+ QFWD,
+ QS,
+ QSYS,
+ REW,
+};
+
+#define SERVALT_MIIM_BUS_COUNT 2
+
+struct servalt_phy_port_t {
+ size_t phy_addr;
+ struct mii_dev *bus;
+};
+
+struct servalt_private {
+ void __iomem *regs[REGS_NAMES_COUNT];
+ struct mii_dev *bus[SERVALT_MIIM_BUS_COUNT];
+ struct servalt_phy_port_t ports[MAX_PORT];
+};
+
+struct mscc_miim_dev {
+ void __iomem *regs;
+ phys_addr_t miim_base;
+ unsigned long miim_size;
+ struct mii_dev *bus;
+};
+
+static const unsigned long servalt_regs_qs[] = {
+ [MSCC_QS_XTR_RD] = 0x8,
+ [MSCC_QS_XTR_FLUSH] = 0x18,
+ [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+ [MSCC_QS_INJ_WR] = 0x2c,
+ [MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static struct mscc_miim_dev miim[SERVALT_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+ return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+ GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ u32 val;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+ miim->regs + GCB_MIIM_MII_CMD);
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret)
+ goto out;
+
+ val = readl(miim->regs + GCB_MIIM_DATA);
+ if (val & GCB_MIIM_DATA_ERROR) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = val & 0xFFFF;
+out:
+ return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+ int ret;
+
+ ret = mscc_miim_wait_ready(miim);
+ if (ret < 0)
+ goto out;
+
+ writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+ GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+ GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+
+out:
+ return ret;
+}
+
+static struct mii_dev *servalt_mdiobus_init(phys_addr_t miim_base,
+ unsigned long miim_size)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+ if (!bus)
+ return NULL;
+
+ ++miim_count;
+ sprintf(bus->name, "miim-bus%d", miim_count);
+
+ miim[miim_count].regs = ioremap(miim_base, miim_size);
+ miim[miim_count].miim_base = miim_base;
+ miim[miim_count].miim_size = miim_size;
+ bus->priv = &miim[miim_count];
+ bus->read = mscc_miim_read;
+ bus->write = mscc_miim_write;
+
+ if (mdio_register(bus))
+ return NULL;
+
+ miim[miim_count].bus = bus;
+ return bus;
+}
+
+static void mscc_phy_reset(void)
+{
+ writel(0, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG);
+ writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
+ | PHY_CFG_ENA, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG);
+ if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + GCB_PHY_CFG) +
+ PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
+ true, 2000, false)) {
+ pr_err("Timeout in phy reset\n");
+ }
+}
+
+static void servalt_cpu_capture_setup(struct servalt_private *priv)
+{
+ /* ASM: No preamble and IFH prefix on CPU injected frames */
+ writel(ASM_CFG_PORT_NO_PREAMBLE_ENA |
+ ASM_CFG_PORT_INJ_FORMAT_CFG(1),
+ priv->regs[ASM] + ASM_CFG_PORT(CPU_PORT));
+
+ /* Set Manual injection via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x5, priv->regs[QS] + QS_INJ_GRP_CFG(0));
+
+ /* Set Manual extraction via DEVCPU_QS registers for CPU queue 0 */
+ writel(0x7, priv->regs[QS] + QS_XTR_GRP_CFG(0));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(CPU_PORT),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+
+ /* Send a copy to CPU when found as forwarding entry */
+ setbits_le32(priv->regs[ANA_L2] + ANA_L2_COMMON_FWD_CFG,
+ ANA_L2_COMMON_FWD_CFG_CPU_DMAC_COPY_ENA);
+}
+
+static void servalt_port_init(struct servalt_private *priv, int port)
+{
+ void __iomem *regs = priv->regs[port];
+
+ /* Enable PCS */
+ writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
+ regs + DEV_PCS1G_CFG_PCS1G_CFG);
+
+ /* Disable Signal Detect */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
+
+ /* Enable MAC RX and TX */
+ writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
+ DEV_MAC_CFG_MAC_ENA_TX_ENA,
+ regs + DEV_MAC_CFG_MAC_ENA);
+
+ /* Clear sgmii_mode_ena */
+ writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
+
+ /*
+ * Clear sw_resolve_ena(bit 0) and set adv_ability to
+ * something meaningful just in case
+ */
+ writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
+ regs + DEV_PCS1G_CFG_PCS1G_ANEG);
+
+ /* Set MAC IFG Gaps */
+ writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(4) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG1(5) |
+ DEV_MAC_CFG_MAC_IFG_RX_IFG2(1),
+ regs + DEV_MAC_CFG_MAC_IFG);
+
+ /* Set link speed and release all resets */
+ writel(DEV_DEV_CFG_DEV_RST_CTRL_SPEED_SEL(2),
+ regs + DEV_DEV_CFG_DEV_RST_CTRL);
+
+ /* Make VLAN aware for CPU traffic */
+ writel(ANA_CL_PORT_VLAN_CFG_AWARE_ENA |
+ ANA_CL_PORT_VLAN_CFG_POP_CNT(1) |
+ MAC_VID,
+ priv->regs[ANA_CL] + ANA_CL_PORT_VLAN_CFG(port));
+
+ /* Enable CPU port for any frame transfer */
+ setbits_le32(priv->regs[QFWD] + QFWD_SYSTEM_SWITCH_PORT_MODE(port),
+ QFWD_SYSTEM_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static int ram_init(u32 val, void __iomem *addr)
+{
+ writel(val, addr);
+
+ if (wait_for_bit_le32(addr, BIT(1), false, 2000, false)) {
+ printf("Timeout in memory reset, reg = 0x%08x\n", val);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int servalt_switch_init(struct servalt_private *priv)
+{
+ /* Initialize memories */
+ ram_init(0x3, priv->regs[QSYS] + QSYS_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ASM] + ASM_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[ANA_AC] + ANA_AC_RAM_CTRL_RAM_INIT);
+ ram_init(0x3, priv->regs[REW] + REW_RAM_CTRL_RAM_INIT);
+
+ /* Reset counters */
+ writel(0x1, priv->regs[ANA_AC] + ANA_AC_STAT_GLOBAL_CFG_PORT_RESET);
+ writel(0x1, priv->regs[ASM] + ASM_CFG_STAT_CFG);
+
+ /* Enable switch-core and queue system */
+ writel(0x1, priv->regs[QSYS] + QSYS_SYSTEM_RESET_CFG);
+
+ return 0;
+}
+
+static void servalt_switch_config(struct servalt_private *priv)
+{
+ writel(0x55555555, priv->regs[QSYS] + QSYS_CALCFG_CAL_AUTO);
+
+ writel(readl(priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL) |
+ QSYS_CALCFG_CAL_CTRL_CAL_MODE(8),
+ priv->regs[QSYS] + QSYS_CALCFG_CAL_CTRL);
+}
+
+static int servalt_initialize(struct servalt_private *priv)
+{
+ int ret, i;
+
+ /* Initialize switch memories, enable core */
+ ret = servalt_switch_init(priv);
+ if (ret)
+ return ret;
+
+ servalt_switch_config(priv);
+
+ for (i = 0; i < MAX_PORT; i++)
+ servalt_port_init(priv, i);
+
+ servalt_cpu_capture_setup(priv);
+
+ return 0;
+}
+
+static inline
+int servalt_vlant_wait_for_completion(struct servalt_private *priv)
+{
+ if (wait_for_bit_le32(priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL,
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ false, 2000, false))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int servalt_mac_table_add(struct servalt_private *priv,
+ const unsigned char mac[ETH_ALEN], int pgid)
+{
+ u32 macl = 0, mach = 0;
+
+ /*
+ * Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= MAC_VID << 16;
+ mach |= ((u32)mac[0]) << 8;
+ mach |= ((u32)mac[1]) << 0;
+ macl |= ((u32)mac[2]) << 24;
+ macl |= ((u32)mac[3]) << 16;
+ macl |= ((u32)mac[4]) << 8;
+ macl |= ((u32)mac[5]) << 0;
+
+ writel(mach, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG0);
+ writel(macl, priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG1);
+
+ writel(LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_ADDR(pgid) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_TYPE(0x3) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_COPY |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_CPU_QU(0) |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_VLD |
+ LRN_COMMON_MAC_ACCESS_CFG2_MAC_ENTRY_LOCKED,
+ priv->regs[LRN] + LRN_COMMON_MAC_ACCESS_CFG2);
+
+ writel(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT,
+ priv->regs[LRN] + LRN_COMMON_ACCESS_CTRL);
+
+ return servalt_vlant_wait_for_completion(priv);
+}
+
+static int servalt_write_hwaddr(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ return servalt_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+}
+
+static int servalt_start(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const unsigned char mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ int ret;
+
+ ret = servalt_initialize(priv);
+ if (ret)
+ return ret;
+
+ /* Set MAC address tables entries for CPU redirection */
+ ret = servalt_mac_table_add(priv, mac, PGID_BROADCAST);
+ if (ret)
+ return ret;
+
+ ret = servalt_mac_table_add(priv, pdata->enetaddr, PGID_UNICAST);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void servalt_stop(struct udevice *dev)
+{
+}
+
+static int servalt_send(struct udevice *dev, void *packet, int length)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ u32 ifh[IFH_LEN];
+ u32 *buf = packet;
+
+ memset(ifh, '\0', IFH_LEN * 4);
+
+ /* Set DST PORT_MASK */
+ ifh[0] = htonl(0);
+ ifh[1] = htonl(0x1FFFFF);
+ ifh[2] = htonl(~0);
+ /* Set DST_MODE to INJECT and UPDATE_FCS */
+ ifh[5] = htonl(0x4c0);
+
+ return mscc_send(priv->regs[QS], servalt_regs_qs,
+ ifh, IFH_LEN, buf, length);
+}
+
+static int servalt_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ u32 *rxbuf = (u32 *)net_rx_packets[0];
+ int byte_cnt = 0;
+
+ byte_cnt = mscc_recv(priv->regs[QS], servalt_regs_qs, rxbuf, IFH_LEN,
+ false);
+
+ *packetp = net_rx_packets[0];
+
+ return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+ int i = 0;
+
+ for (i = 0; i < SERVALT_MIIM_BUS_COUNT; ++i)
+ if (miim[i].miim_base == base && miim[i].miim_size == size)
+ return miim[i].bus;
+
+ return NULL;
+}
+
+static void add_port_entry(struct servalt_private *priv, size_t index,
+ size_t phy_addr, struct mii_dev *bus)
+{
+ priv->ports[index].phy_addr = phy_addr;
+ priv->ports[index].bus = bus;
+}
+
+static int servalt_probe(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ int i;
+ struct resource res;
+ fdt32_t faddr;
+ phys_addr_t addr_base;
+ unsigned long addr_size;
+ ofnode eth_node, node, mdio_node;
+ size_t phy_addr;
+ struct mii_dev *bus;
+ struct ofnode_phandle_args phandle;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Get registers and map them to the private structure */
+ for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+ priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+ if (!priv->regs[i]) {
+ debug
+ ("Error can't get regs base addresses for %s\n",
+ regs_names[i]);
+ return -ENOMEM;
+ }
+ }
+
+ /* Initialize miim buses */
+ memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
+ SERVALT_MIIM_BUS_COUNT);
+
+ /* iterate all the ports and find out on which bus they are */
+ i = 0;
+ eth_node = dev_read_first_subnode(dev);
+ for (node = ofnode_first_subnode(eth_node);
+ ofnode_valid(node);
+ node = ofnode_next_subnode(node)) {
+ if (ofnode_read_resource(node, 0, &res))
+ return -ENOMEM;
+ i = res.start;
+
+ ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+ &phandle);
+
+ /* Get phy address on mdio bus */
+ if (ofnode_read_resource(phandle.node, 0, &res))
+ return -ENOMEM;
+ phy_addr = res.start;
+
+ /* Get mdio node */
+ mdio_node = ofnode_get_parent(phandle.node);
+
+ if (ofnode_read_resource(mdio_node, 0, &res))
+ return -ENOMEM;
+ faddr = cpu_to_fdt32(res.start);
+
+ addr_base = ofnode_translate_address(mdio_node, &faddr);
+ addr_size = res.end - res.start;
+
+ /* If the bus is new then create a new bus */
+ if (!get_mdiobus(addr_base, addr_size))
+ priv->bus[miim_count] =
+ servalt_mdiobus_init(addr_base, addr_size);
+
+ /* Connect mdio bus with the port */
+ bus = get_mdiobus(addr_base, addr_size);
+ add_port_entry(priv, i, phy_addr, bus);
+ }
+
+ mscc_phy_reset();
+
+ for (i = 0; i < MAX_PORT; i++) {
+ if (!priv->ports[i].bus)
+ continue;
+
+ phy_connect(priv->ports[i].bus, priv->ports[i].phy_addr, dev,
+ PHY_INTERFACE_MODE_NONE);
+ }
+
+ return 0;
+}
+
+static int servalt_remove(struct udevice *dev)
+{
+ struct servalt_private *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < SERVALT_MIIM_BUS_COUNT; i++) {
+ mdio_unregister(priv->bus[i]);
+ mdio_free(priv->bus[i]);
+ }
+
+ return 0;
+}
+
+static const struct eth_ops servalt_ops = {
+ .start = servalt_start,
+ .stop = servalt_stop,
+ .send = servalt_send,
+ .recv = servalt_recv,
+ .write_hwaddr = servalt_write_hwaddr,
+};
+
+static const struct udevice_id mscc_servalt_ids[] = {
+ {.compatible = "mscc,vsc7437-switch" },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(servalt) = {
+ .name = "servalt-switch",
+ .id = UCLASS_ETH,
+ .of_match = mscc_servalt_ids,
+ .probe = servalt_probe,
+ .remove = servalt_remove,
+ .ops = &servalt_ops,
+ .priv_auto_alloc_size = sizeof(struct servalt_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 32bbf41dd1f..102fb91fffd 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -174,4 +174,12 @@ config KEYSTONE_USB_PHY
This PHY is found on some Keystone (K2) devices supporting USB.
+config MT76X8_USB_PHY
+ bool "MediaTek MT76x8 (7628/88) USB PHY support"
+ depends on PHY
+ help
+ Support the USB PHY in MT76x8 SoCs
+
+ This PHY is found on MT76x8 devices supporting USB.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 099551d6930..b55917bce1a 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o
obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
+obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
diff --git a/drivers/phy/mt76x8-usb-phy.c b/drivers/phy/mt76x8-usb-phy.c
new file mode 100644
index 00000000000..268da8ef6c9
--- /dev/null
+++ b/drivers/phy/mt76x8-usb-phy.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stefan Roese <sr@denx.de>
+ *
+ * Derived from linux/drivers/phy/ralink/phy-ralink-usb.c
+ * Copyright (C) 2017 John Crispin <john@phrozen.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <syscon.h>
+#include <asm/io.h>
+
+#define RT_SYSC_REG_SYSCFG1 0x014
+#define RT_SYSC_REG_CLKCFG1 0x030
+#define RT_SYSC_REG_USB_PHY_CFG 0x05c
+
+#define OFS_U2_PHY_AC0 0x800
+#define OFS_U2_PHY_AC1 0x804
+#define OFS_U2_PHY_AC2 0x808
+#define OFS_U2_PHY_ACR0 0x810
+#define OFS_U2_PHY_ACR1 0x814
+#define OFS_U2_PHY_ACR2 0x818
+#define OFS_U2_PHY_ACR3 0x81C
+#define OFS_U2_PHY_ACR4 0x820
+#define OFS_U2_PHY_AMON0 0x824
+#define OFS_U2_PHY_DCR0 0x860
+#define OFS_U2_PHY_DCR1 0x864
+#define OFS_U2_PHY_DTM0 0x868
+#define OFS_U2_PHY_DTM1 0x86C
+
+#define RT_RSTCTRL_UDEV BIT(25)
+#define RT_RSTCTRL_UHST BIT(22)
+#define RT_SYSCFG1_USB0_HOST_MODE BIT(10)
+
+#define MT7620_CLKCFG1_UPHY0_CLK_EN BIT(25)
+#define MT7620_CLKCFG1_UPHY1_CLK_EN BIT(22)
+#define RT_CLKCFG1_UPHY1_CLK_EN BIT(20)
+#define RT_CLKCFG1_UPHY0_CLK_EN BIT(18)
+
+#define USB_PHY_UTMI_8B60M BIT(1)
+#define UDEV_WAKEUP BIT(0)
+
+struct mt76x8_usb_phy {
+ u32 clk;
+ void __iomem *base;
+ struct regmap *sysctl;
+};
+
+static void u2_phy_w32(struct mt76x8_usb_phy *phy, u32 val, u32 reg)
+{
+ writel(val, phy->base + reg);
+}
+
+static u32 u2_phy_r32(struct mt76x8_usb_phy *phy, u32 reg)
+{
+ return readl(phy->base + reg);
+}
+
+static void mt76x8_usb_phy_init(struct mt76x8_usb_phy *phy)
+{
+ u2_phy_r32(phy, OFS_U2_PHY_AC2);
+ u2_phy_r32(phy, OFS_U2_PHY_ACR0);
+ u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+
+ u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0);
+ u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+ u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0);
+ u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+ u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0);
+ u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+ u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0);
+ u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+ u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0);
+ u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1);
+ u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3);
+ u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0);
+}
+
+static int mt76x8_usb_phy_power_on(struct phy *_phy)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+ u32 t;
+
+ /* enable the phy */
+ regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
+ phy->clk, phy->clk);
+
+ /* setup host mode */
+ regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1,
+ RT_SYSCFG1_USB0_HOST_MODE,
+ RT_SYSCFG1_USB0_HOST_MODE);
+
+ /*
+ * The SDK kernel had a delay of 100ms. however on device
+ * testing showed that 10ms is enough
+ */
+ mdelay(10);
+
+ if (phy->base)
+ mt76x8_usb_phy_init(phy);
+
+ /* print some status info */
+ regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t);
+ printf("remote usb device wakeup %s\n",
+ (t & UDEV_WAKEUP) ? "enabled" : "disabled");
+ if (t & USB_PHY_UTMI_8B60M)
+ printf("UTMI 8bit 60MHz\n");
+ else
+ printf("UTMI 16bit 30MHz\n");
+
+ return 0;
+}
+
+static int mt76x8_usb_phy_power_off(struct phy *_phy)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ /* disable the phy */
+ regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
+ phy->clk, 0);
+
+ return 0;
+}
+
+static int mt76x8_usb_phy_probe(struct udevice *dev)
+{
+ struct mt76x8_usb_phy *phy = dev_get_priv(dev);
+
+ phy->sysctl = syscon_regmap_lookup_by_phandle(dev, "ralink,sysctl");
+ if (IS_ERR(phy->sysctl))
+ return PTR_ERR(phy->sysctl);
+
+ phy->base = dev_read_addr_ptr(dev);
+ if (!phy->base)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct phy_ops mt76x8_usb_phy_ops = {
+ .power_on = mt76x8_usb_phy_power_on,
+ .power_off = mt76x8_usb_phy_power_off,
+};
+
+static const struct udevice_id mt76x8_usb_phy_ids[] = {
+ { .compatible = "mediatek,mt7628-usbphy" },
+ { }
+};
+
+U_BOOT_DRIVER(mt76x8_usb_phy) = {
+ .name = "mt76x8_usb_phy",
+ .id = UCLASS_PHY,
+ .of_match = mt76x8_usb_phy_ids,
+ .ops = &mt76x8_usb_phy_ops,
+ .probe = mt76x8_usb_phy_probe,
+ .priv_auto_alloc_size = sizeof(struct mt76x8_usb_phy),
+};
diff --git a/drivers/pinctrl/ath79/Makefile b/drivers/pinctrl/ath79/Makefile
index 1daa2123a14..c7d1e44882e 100644
--- a/drivers/pinctrl/ath79/Makefile
+++ b/drivers/pinctrl/ath79/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_PINCTRL_AR933X) += pinctrl_ar933x.o
-obj-$(CONFIG_PINCTRL_QCA953x) += pinctrl_qca953x.o
+obj-$(CONFIG_PINCTRL_QCA953X) += pinctrl_qca953x.o
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 0e3260afd1e..0e6c559d5ef 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -27,28 +27,6 @@ int pinctrl_decode_pin_config(const void *blob, int node)
return flags;
}
-/*
- * TODO: this function is temporary for v2019.01.
- * It should be renamed to pinctrl_decode_pin_config(),
- * the original pinctrl_decode_pin_config() function should
- * be removed and all callers of the original function should
- * be migrated to use the new one.
- */
-int pinctrl_decode_pin_config_dm(struct udevice *dev)
-{
- int pinconfig = 0;
-
- if (dev->uclass->uc_drv->id != UCLASS_PINCONFIG)
- return -EINVAL;
-
- if (dev_read_bool(dev, "bias-pull-up"))
- pinconfig |= 1 << PIN_CONFIG_BIAS_PULL_UP;
- else if (dev_read_bool(dev, "bias-pull-down"))
- pinconfig |= 1 << PIN_CONFIG_BIAS_PULL_DOWN;
-
- return pinconfig;
-}
-
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
/**
* pinctrl_config_one() - apply pinctrl settings for a single node
@@ -149,6 +127,9 @@ static int pinconfig_post_bind(struct udevice *dev)
ofnode_get_property(node, "compatible", &ret);
if (ret >= 0)
continue;
+ /* If this node has "gpio-controller" property, skip */
+ if (ofnode_read_bool(node, "gpio-controller"))
+ continue;
if (ret != -FDT_ERR_NOTFOUND)
return ret;
@@ -201,11 +182,14 @@ static int pinctrl_select_state_simple(struct udevice *dev)
int ret;
/*
- * For simplicity, assume the first device of PINCTRL uclass
- * is the correct one. This is most likely OK as there is
- * usually only one pinctrl device on the system.
+ * For most system, there is only one pincontroller device. But in
+ * case of multiple pincontroller devices, probe the one with sequence
+ * number 0 (defined by alias) to avoid race condition.
*/
- ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
+ ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev);
+ if (ret)
+ /* if not found, get the first one */
+ ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
if (ret)
return ret;
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 11fce9c4fe5..efdb178450e 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -256,7 +256,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
break;
case CQSPI_INDIRECT_WRITE:
err = cadence_qspi_apb_indirect_write_setup
- (plat, priv->cmd_len, cmd_buf);
+ (plat, priv->cmd_len, dm_plat->mode, cmd_buf);
if (!err) {
err = cadence_qspi_apb_indirect_write_execute
(plat, data_bytes, dout);
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 055900def00..b4914071308 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -60,7 +60,7 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
unsigned int rxlen, u8 *rxbuf);
int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
- unsigned int cmdlen, const u8 *cmdbuf);
+ unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf);
int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
unsigned int txlen, const u8 *txbuf);
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index a8af3520303..55a7501913a 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -77,6 +77,7 @@
#define CQSPI_REG_WR_INSTR 0x08
#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
#define CQSPI_REG_DELAY 0x0C
#define CQSPI_REG_DELAY_TSLCH_LSB 0
@@ -686,7 +687,7 @@ failrd:
/* Opcode + Address (3/4 bytes) */
int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
- unsigned int cmdlen, const u8 *cmdbuf)
+ unsigned int cmdlen, unsigned int tx_width, const u8 *cmdbuf)
{
unsigned int reg;
unsigned int addr_bytes = cmdlen > 4 ? 4 : 3;
@@ -702,6 +703,10 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
/* Configure the opcode */
reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+
+ if (tx_width & SPI_TX_QUAD)
+ reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
+
writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
/* Setup write address. */
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index 764c94215e7..a68a51945e4 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -273,7 +273,18 @@ static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
if (len > 1) {
int tmp_len = len - 1;
while (tmp_len--) {
- if (dout != NULL) {
+ if ((dout != NULL) && (din != NULL)) {
+ if (priv->charbit == 16) {
+ dspi_tx(priv, ctrl, *spi_wr16++);
+ *spi_rd16++ = dspi_rx(priv);
+ }
+ else {
+ dspi_tx(priv, ctrl, *spi_wr++);
+ *spi_rd++ = dspi_rx(priv);
+ }
+ }
+
+ else if (dout != NULL) {
if (priv->charbit == 16)
dspi_tx(priv, ctrl, *spi_wr16++);
else
@@ -281,7 +292,7 @@ static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
dspi_rx(priv);
}
- if (din != NULL) {
+ else if (din != NULL) {
dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
if (priv->charbit == 16)
*spi_rd16++ = dspi_rx(priv);
@@ -297,7 +308,18 @@ static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
ctrl &= ~DSPI_TFR_CONT;
if (len) {
- if (dout != NULL) {
+ if ((dout != NULL) && (din != NULL)) {
+ if (priv->charbit == 16) {
+ dspi_tx(priv, ctrl, *spi_wr16++);
+ *spi_rd16++ = dspi_rx(priv);
+ }
+ else {
+ dspi_tx(priv, ctrl, *spi_wr++);
+ *spi_rd++ = dspi_rx(priv);
+ }
+ }
+
+ else if (dout != NULL) {
if (priv->charbit == 16)
dspi_tx(priv, ctrl, *spi_wr16);
else
@@ -305,7 +327,7 @@ static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
dspi_rx(priv);
}
- if (din != NULL) {
+ else if (din != NULL) {
dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
if (priv->charbit == 16)
*spi_rd16 = dspi_rx(priv);
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 1bb0987edb7..b86eee75bcb 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -214,7 +214,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
if (ret < 0)
return ret;
- if (ops->mem_ops) {
+ if (ops->mem_ops && ops->mem_ops->exec_op) {
#ifndef __UBOOT__
/*
* Flush the message queue before executing our SPI memory
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 2bc289a74cc..88cb2a12622 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -328,7 +328,9 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
}
plat = dev_get_parent_platdata(dev);
- if (!speed) {
+
+ /* get speed and mode from platdata when available */
+ if (plat->max_hz) {
speed = plat->max_hz;
mode = plat->mode;
}
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c
index 34506402ac3..3fb39b9952e 100644
--- a/drivers/sysreset/sysreset_syscon.c
+++ b/drivers/sysreset/sysreset_syscon.c
@@ -36,20 +36,9 @@ static struct sysreset_ops syscon_reboot_ops = {
int syscon_reboot_probe(struct udevice *dev)
{
struct syscon_reboot_priv *priv = dev_get_priv(dev);
- int err;
- u32 phandle;
- ofnode node;
- err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle);
- if (err)
- return err;
-
- node = ofnode_get_by_phandle(phandle);
- if (!ofnode_valid(node))
- return -EINVAL;
-
- priv->regmap = syscon_node_to_regmap(node);
- if (!priv->regmap) {
+ priv->regmap = syscon_regmap_lookup_by_phandle(dev, "regmap");
+ if (IS_ERR(priv->regmap)) {
pr_err("unable to find regmap\n");
return -ENODEV;
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 53871f864f5..c3781b160d9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -120,7 +120,7 @@ config CONSOLE_TRUETYPE_SIZE
config SYS_WHITE_ON_BLACK
bool "Display console as white on a black background"
- default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || TEGRA || X86
+ default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || TEGRA || X86 || ARCH_SUNXI
help
Normally the display is black on a white background, Enable this
option to invert this, i.e. white on a black background. This can be
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c
index 2cfa510d5f7..7f01ee94242 100644
--- a/drivers/video/console_normal.c
+++ b/drivers/video/console_normal.c
@@ -84,7 +84,8 @@ static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y,
return -EAGAIN;
for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
- uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row];
+ unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row;
+ uchar bits = video_fontdata[idx];
switch (vid_priv->bpix) {
#ifdef CONFIG_VIDEO_BPP8
diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c
index f076570335b..71a5c5efba3 100644
--- a/drivers/video/console_rotate.c
+++ b/drivers/video/console_rotate.c
@@ -90,7 +90,7 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch)
int i, col;
int mask = 0x80;
void *line;
- uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
+ uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT;
line = vid_priv->fb + (VID_TO_PIXEL(x_frac) + 1) *
vid_priv->line_length - (y + 1) * pbytes;
@@ -222,7 +222,8 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch)
VIDEO_FONT_WIDTH - 1) * VNBYTES(vid_priv->bpix);
for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
- uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row];
+ unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row;
+ uchar bits = video_fontdata[idx];
switch (vid_priv->bpix) {
#ifdef CONFIG_VIDEO_BPP8
@@ -348,7 +349,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch)
void *line = vid_priv->fb +
(vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1) *
vid_priv->line_length + y * pbytes;
- uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT;
+ uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT;
if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac)
return -EAGAIN;
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index bd733f5f1ca..a587977c225 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -39,6 +39,12 @@ struct pwm_backlight_priv {
struct udevice *pwm;
uint channel;
uint period_ns;
+ /*
+ * the polarity of one PWM
+ * 0: normal polarity
+ * 1: inverted polarity
+ */
+ bool polarity;
u32 *levels;
int num_levels;
uint default_level;
@@ -57,7 +63,10 @@ static int set_pwm(struct pwm_backlight_priv *priv)
(priv->max_level - priv->min_level + 1);
ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
duty_cycle);
+ if (ret)
+ return log_ret(ret);
+ ret = pwm_set_invert(priv->pwm, priv->channel, priv->polarity);
return log_ret(ret);
}
@@ -202,6 +211,8 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev)
return log_msg_ret("Not enough arguments to pwm\n", -EINVAL);
priv->channel = args.args[0];
priv->period_ns = args.args[1];
+ if (args.args_count > 2)
+ priv->polarity = args.args[2];
index = dev_read_u32_default(dev, "default-brightness-level", 255);
cell = dev_read_prop(dev, "brightness-levels", &len);
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index 2ca19d40491..c31303b56ed 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -259,6 +259,43 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
priv->escape = 0;
switch (ch) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F': {
+ int row, col, num;
+ char *s = priv->escape_buf;
+
+ /*
+ * Cursor up/down: [%dA, [%dB, [%dE, [%dF
+ * Cursor left/right: [%dD, [%dC
+ */
+ s++; /* [ */
+ s = parsenum(s, &num);
+ if (num == 0) /* No digit in sequence ... */
+ num = 1; /* ... means "move by 1". */
+
+ get_cursor_position(priv, &row, &col);
+ if (ch == 'A' || ch == 'F')
+ row -= num;
+ if (ch == 'C')
+ col += num;
+ if (ch == 'D')
+ col -= num;
+ if (ch == 'B' || ch == 'E')
+ row += num;
+ if (ch == 'E' || ch == 'F')
+ col = 0;
+ if (col < 0)
+ col = 0;
+ if (row < 0)
+ row = 0;
+ /* Right and bottom overflows are handled in the callee. */
+ set_cursor_position(priv, row, col);
+ break;
+ }
case 'H':
case 'f': {
int row, col;
@@ -309,6 +346,25 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
}
break;
}
+ case 'K': {
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ int mode;
+
+ /*
+ * Clear (parts of) current line
+ * [0K - clear line to end
+ * [2K - clear entire line
+ */
+ parsenum(priv->escape_buf + 1, &mode);
+
+ if (mode == 2) {
+ int row, col;
+
+ get_cursor_position(priv, &row, &col);
+ vidconsole_set_row(dev, row, vid_priv->colour_bg);
+ }
+ break;
+ }
case 'm': {
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
char *s = priv->escape_buf;
@@ -360,6 +416,13 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
vid_priv->colour_fg = vid_console_color(
vid_priv, vid_priv->fg_col_idx);
break;
+ case 7:
+ /* reverse video */
+ vid_priv->colour_fg = vid_console_color(
+ vid_priv, vid_priv->bg_col_idx);
+ vid_priv->colour_bg = vid_console_color(
+ vid_priv, vid_priv->fg_col_idx);
+ break;
case 30 ... 37:
/* foreground color */
vid_priv->fg_col_idx &= ~7;
@@ -368,9 +431,11 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
vid_priv, vid_priv->fg_col_idx);
break;
case 40 ... 47:
- /* background color */
+ /* background color, also mask the bold bit */
+ vid_priv->bg_col_idx &= ~0xf;
+ vid_priv->bg_col_idx |= val - 40;
vid_priv->colour_bg = vid_console_color(
- vid_priv, val - 40);
+ vid_priv, vid_priv->bg_col_idx);
break;
default:
/* ignore unsupported SGR parameter */
@@ -392,6 +457,32 @@ error:
priv->escape = 0;
}
+/* Put that actual character on the screen (using the CP437 code page). */
+static int vidconsole_output_glyph(struct udevice *dev, char ch)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ /*
+ * Failure of this function normally indicates an unsupported
+ * colour depth. Check this and return an error to help with
+ * diagnosis.
+ */
+ ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
+ if (ret == -EAGAIN) {
+ vidconsole_newline(dev);
+ ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
+ }
+ if (ret < 0)
+ return ret;
+ priv->xcur_frac += ret;
+ priv->last_ch = ch;
+ if (priv->xcur_frac >= priv->xsize_frac)
+ vidconsole_newline(dev);
+
+ return 0;
+}
+
int vidconsole_put_char(struct udevice *dev, char ch)
{
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
@@ -429,23 +520,9 @@ int vidconsole_put_char(struct udevice *dev, char ch)
priv->last_ch = 0;
break;
default:
- /*
- * Failure of this function normally indicates an unsupported
- * colour depth. Check this and return an error to help with
- * diagnosis.
- */
- ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
- if (ret == -EAGAIN) {
- vidconsole_newline(dev);
- ret = vidconsole_putc_xy(dev, priv->xcur_frac,
- priv->ycur, ch);
- }
+ ret = vidconsole_output_glyph(dev, ch);
if (ret < 0)
return ret;
- priv->xcur_frac += ret;
- priv->last_ch = ch;
- if (priv->xcur_frac >= priv->xsize_frac)
- vidconsole_newline(dev);
break;
}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index f307cf243bd..14aac88d6d2 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -136,6 +136,7 @@ void video_set_default_colors(struct udevice *dev, bool invert)
back = temp;
}
priv->fg_col_idx = fore;
+ priv->bg_col_idx = back;
priv->colour_fg = vid_console_color(priv, fore);
priv->colour_bg = vid_console_color(priv, back);
}