summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/tegra/Kconfig6
-rw-r--r--drivers/clk/tegra/Makefile5
-rw-r--r--drivers/clk/tegra/tegra186-clk.c104
-rw-r--r--drivers/i2c/Kconfig10
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/tegra186_bpmp_i2c.c129
-rw-r--r--drivers/i2c/tegra_i2c.c89
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/tegra186_bpmp.c257
-rw-r--r--drivers/mmc/tegra_mmc.c64
-rw-r--r--drivers/net/4xx_enet.c20
-rw-r--r--drivers/net/Kconfig5
-rw-r--r--drivers/net/armada100_fec.c33
-rw-r--r--drivers/net/at91_emac.c28
-rw-r--r--drivers/net/bcm-sf2-eth-gmac.c18
-rw-r--r--drivers/net/bcm-sf2-eth.c13
-rw-r--r--drivers/net/bcm-sf2-eth.h8
-rw-r--r--drivers/net/bfin_mac.c43
-rw-r--r--drivers/net/davinci_emac.c34
-rw-r--r--drivers/net/e1000.c6
-rw-r--r--drivers/net/e1000_spi.c59
-rw-r--r--drivers/net/eepro100.c34
-rw-r--r--drivers/net/enc28j60.c26
-rw-r--r--drivers/net/ep93xx_eth.c40
-rw-r--r--drivers/net/ethoc.c526
-rw-r--r--drivers/net/fsl_mcdmafec.c13
-rw-r--r--drivers/net/ftmac110.c35
-rw-r--r--drivers/net/lpc32xx_eth.c52
-rw-r--r--drivers/net/macb.c123
-rw-r--r--drivers/net/mcffec.c13
-rw-r--r--drivers/net/mcfmii.c19
-rw-r--r--drivers/net/mpc512x_fec.c30
-rw-r--r--drivers/net/mpc5xxx_fec.c30
-rw-r--r--drivers/net/mvgbe.c33
-rw-r--r--drivers/net/phy/miiphybb.c25
-rw-r--r--drivers/net/sh_eth.c12
-rw-r--r--drivers/net/smc911x.c35
-rw-r--r--drivers/pci/Kconfig1
-rw-r--r--drivers/pci/pci_tegra.c163
-rw-r--r--drivers/power/domain/Kconfig7
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/tegra186-power-domain.c92
-rw-r--r--drivers/qe/uec.c32
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/tegra186-reset.c81
-rw-r--r--drivers/usb/eth/smsc95xx.c4
50 files changed, 1996 insertions, 387 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3da63c0..8f3b96a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -20,6 +20,7 @@ config SPL_CLK
setting up clocks within SPL, and allows the same drivers to be
used as U-Boot proper.
+source "drivers/clk/tegra/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/exynos/Kconfig"
source "drivers/clk/at91/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 65de008..778d748 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
+
+obj-y += tegra/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_EXYNOS) += exynos/
obj-$(CONFIG_CLK_AT91) += at91/
diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig
new file mode 100644
index 0000000..659fe02
--- /dev/null
+++ b/drivers/clk/tegra/Kconfig
@@ -0,0 +1,6 @@
+config TEGRA186_CLOCK
+ bool "Enable Tegra186 BPMP-based clock driver"
+ depends on TEGRA186_BPMP
+ help
+ Enable support for manipulating Tegra's on-SoC clocks via IPC
+ requests to the BPMP (Boot and Power Management Processor).
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
new file mode 100644
index 0000000..f32998c
--- /dev/null
+++ b/drivers/clk/tegra/Makefile
@@ -0,0 +1,5 @@
+# Copyright (c) 2016, NVIDIA CORPORATION.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_TEGRA186_CLOCK) += tegra186-clk.o
diff --git a/drivers/clk/tegra/tegra186-clk.c b/drivers/clk/tegra/tegra186-clk.c
new file mode 100644
index 0000000..075cb46
--- /dev/null
+++ b/drivers/clk/tegra/tegra186-clk.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <misc.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+
+static ulong tegra186_clk_get_rate(struct clk *clk)
+{
+ struct mrq_clk_request req;
+ struct mrq_clk_response resp;
+ int ret;
+
+ debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+ clk->id);
+
+ req.cmd_and_id = (CMD_CLK_GET_RATE << 24) | clk->id;
+
+ ret = misc_call(clk->dev->parent, MRQ_CLK, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ return resp.clk_get_rate.rate;
+}
+
+static ulong tegra186_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct mrq_clk_request req;
+ struct mrq_clk_response resp;
+ int ret;
+
+ debug("%s(clk=%p, rate=%lu) (dev=%p, id=%lu)\n", __func__, clk, rate,
+ clk->dev, clk->id);
+
+ req.cmd_and_id = (CMD_CLK_SET_RATE << 24) | clk->id;
+ req.clk_set_rate.rate = rate;
+
+ ret = misc_call(clk->dev->parent, MRQ_CLK, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ return resp.clk_set_rate.rate;
+}
+
+static int tegra186_clk_en_dis(struct clk *clk,
+ enum mrq_reset_commands cmd)
+{
+ struct mrq_clk_request req;
+ struct mrq_clk_response resp;
+ int ret;
+
+ req.cmd_and_id = (cmd << 24) | clk->id;
+
+ ret = misc_call(clk->dev->parent, MRQ_CLK, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tegra186_clk_enable(struct clk *clk)
+{
+ debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+ clk->id);
+
+ return tegra186_clk_en_dis(clk, CMD_CLK_ENABLE);
+}
+
+static int tegra186_clk_disable(struct clk *clk)
+{
+ debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+ clk->id);
+
+ return tegra186_clk_en_dis(clk, CMD_CLK_DISABLE);
+}
+
+static struct clk_ops tegra186_clk_ops = {
+ .get_rate = tegra186_clk_get_rate,
+ .set_rate = tegra186_clk_set_rate,
+ .enable = tegra186_clk_enable,
+ .disable = tegra186_clk_disable,
+};
+
+static int tegra186_clk_probe(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(tegra186_clk) = {
+ .name = "tegra186_clk",
+ .id = UCLASS_CLK,
+ .probe = tegra186_clk_probe,
+ .ops = &tegra186_clk_ops,
+};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 8575a23..1537b67 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -171,6 +171,16 @@ config SYS_I2C_MVTWSI
Support for Marvell I2C controllers as used on the orion5x and
kirkwood SoC families.
+config TEGRA186_BPMP_I2C
+ bool "Enable Tegra186 BPMP-based I2C driver"
+ depends on TEGRA186_BPMP
+ help
+ Support for Tegra I2C controllers managed by the BPMP (Boot and
+ Power Management Processor). On Tegra186, some I2C controllers are
+ directly controlled by the main CPU, whereas others are controlled
+ by the BPMP, and can only be accessed by the main CPU via IPC
+ requests to the BPMP. This driver covers the latter case.
+
source "drivers/i2c/muxes/Kconfig"
endmenu
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c5362a5..2987081 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -42,5 +42,6 @@ obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
+obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o
obj-$(CONFIG_I2C_MUX) += muxes/
diff --git a/drivers/i2c/tegra186_bpmp_i2c.c b/drivers/i2c/tegra186_bpmp_i2c.c
new file mode 100644
index 0000000..88e8413
--- /dev/null
+++ b/drivers/i2c/tegra186_bpmp_i2c.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <misc.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct tegra186_bpmp_i2c {
+ uint32_t bpmp_bus_id;
+};
+
+static inline void serialize_u16(uint8_t **p, uint16_t val)
+{
+ (*p)[0] = val & 0xff;
+ (*p)[1] = val >> 8;
+ (*p) += 2;
+}
+
+/* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
+#define SUPPORTED_FLAGS \
+ (I2C_M_TEN | \
+ I2C_M_RD | \
+ I2C_M_STOP | \
+ I2C_M_NOSTART | \
+ I2C_M_REV_DIR_ADDR | \
+ I2C_M_IGNORE_NAK | \
+ I2C_M_NO_RD_ACK | \
+ I2C_M_RECV_LEN)
+
+static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
+ struct mrq_i2c_request req;
+ struct mrq_i2c_response resp;
+ uint8_t *p;
+ int left, i, ret;
+
+ req.cmd = CMD_I2C_XFER;
+ req.xfer.bus_id = priv->bpmp_bus_id;
+ p = &req.xfer.data_buf[0];
+ left = ARRAY_SIZE(req.xfer.data_buf);
+ for (i = 0; i < nmsgs; i++) {
+ int len = 6;
+ if (!(msg[i].flags & I2C_M_RD))
+ len += msg[i].len;
+ if ((len >= BIT(16)) || (len > left))
+ return -ENOSPC;
+
+ if (msg[i].flags & ~SUPPORTED_FLAGS)
+ return -EINVAL;
+
+ serialize_u16(&p, msg[i].addr);
+ serialize_u16(&p, msg[i].flags);
+ serialize_u16(&p, msg[i].len);
+ if (!(msg[i].flags & I2C_M_RD)) {
+ memcpy(p, msg[i].buf, msg[i].len);
+ p += msg[i].len;
+ }
+ }
+ req.xfer.data_size = p - &req.xfer.data_buf[0];
+
+ ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (ret < 0)
+ return ret;
+
+ p = &resp.xfer.data_buf[0];
+ left = resp.xfer.data_size;
+ if (left > ARRAY_SIZE(resp.xfer.data_buf))
+ return -EINVAL;
+ for (i = 0; i < nmsgs; i++) {
+ if (msg[i].flags & I2C_M_RD) {
+ memcpy(msg[i].buf, p, msg[i].len);
+ p += msg[i].len;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra186_bpmp_i2c_probe(struct udevice *dev)
+{
+ struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
+ int ret;
+ struct fdtdec_phandle_args args;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+ "nvidia,bpmp", NULL, 0, 0, &args);
+ if (ret < 0) {
+ debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
+ "nvidia,bpmp-bus-id", U32_MAX);
+ if (priv->bpmp_bus_id == U32_MAX) {
+ debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
+ .xfer = tegra186_bpmp_i2c_xfer,
+};
+
+static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
+ { .compatible = "nvidia,tegra186-bpmp-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+ .name = "tegra186_bpmp_i2c",
+ .id = UCLASS_I2C,
+ .of_match = tegra186_bpmp_i2c_ids,
+ .probe = tegra186_bpmp_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct tegra186_bpmp_i2c),
+ .ops = &tegra186_bpmp_i2c_ops,
+};
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 2fa07f9..31ba263 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -12,13 +12,27 @@
#include <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
+#ifdef CONFIG_TEGRA186
+#include <clk.h>
+#include <reset.h>
+#else
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch-tegra/clk_rst.h>
+#endif
+#include <asm/arch/gpio.h>
#include <asm/arch-tegra/tegra_i2c.h>
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
+
DECLARE_GLOBAL_DATA_PTR;
enum i2c_type {
@@ -30,7 +44,12 @@ enum i2c_type {
/* Information about i2c controller */
struct i2c_bus {
int id;
+#ifdef CONFIG_TEGRA186
+ struct reset_ctl reset_ctl;
+ struct clk clk;
+#else
enum periph_id periph_id;
+#endif
int speed;
int pinmux_config;
struct i2c_control *control;
@@ -62,12 +81,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus)
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
+#ifdef CONFIG_TEGRA186
+ reset_assert(&i2c_bus->reset_ctl);
+ udelay(1);
+ reset_deassert(&i2c_bus->reset_ctl);
+ udelay(1);
+#else
reset_periph(i2c_bus->periph_id, 1);
+#endif
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
+#ifdef CONFIG_TEGRA186
+static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate)
+{
+ int ret;
+
+ ret = reset_assert(&i2c_bus->reset_ctl);
+ if (ret)
+ return ret;
+ ret = clk_enable(&i2c_bus->clk);
+ if (ret)
+ return ret;
+ ret = clk_set_rate(&i2c_bus->clk, rate);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ ret = reset_deassert(&i2c_bus->reset_ctl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
+
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
if (!i2c_bus->speed)
@@ -78,8 +126,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
* here, in section 23.3.1, but in fact we seem to need a factor of
* 16 to get the right frequency.
*/
+#ifdef CONFIG_TEGRA186
+ i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
+#else
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
i2c_bus->speed * 2 * 8);
+#endif
if (i2c_bus->type == TYPE_114) {
/*
@@ -94,12 +146,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
* is running, we hang, and we need it for the new calc.
*/
int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
+ unsigned rate = CLK_MULT_STD_FAST_MODE *
+ (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2;
debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
clk_div_stdfst_mode);
+#ifdef CONFIG_TEGRA186
+ i2c_init_clock(i2c_bus, rate);
+#else
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
- CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) *
- i2c_bus->speed * 2);
+ rate);
+#endif
}
/* Reset I2C controller. */
@@ -112,7 +169,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
+#ifndef CONFIG_TEGRA186
funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
+#endif
}
static void send_packet_headers(
@@ -333,8 +392,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
static int tegra_i2c_probe(struct udevice *dev)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
+#ifdef CONFIG_TEGRA186
+ int ret;
+#else
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
+#endif
bool is_dvc;
i2c_bus->id = dev->seq;
@@ -345,6 +408,18 @@ static int tegra_i2c_probe(struct udevice *dev)
* We don't have a binding for pinmux yet. Leave it out for now. So
* far no one needs anything other than the default.
*/
+#ifdef CONFIG_TEGRA186
+ ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
+ if (ret) {
+ error("reset_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+ ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk);
+ if (ret) {
+ error("clk_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+#else
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
i2c_bus->periph_id = clock_decode_periph_id(blob, node);
@@ -359,6 +434,7 @@ static int tegra_i2c_probe(struct udevice *dev)
*/
if (i2c_bus->periph_id == -1)
return -EINVAL;
+#endif
is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
if (is_dvc) {
@@ -370,7 +446,12 @@ static int tegra_i2c_probe(struct udevice *dev)
i2c_init_controller(i2c_bus);
debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
- i2c_bus->periph_id, i2c_bus->speed);
+#ifndef CONFIG_TEGRA186
+ i2c_bus->periph_id,
+#else
+ -1,
+#endif
+ i2c_bus->speed);
return 0;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 80c1558..4af1cbf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -121,6 +121,18 @@ config PCA9551_I2C_ADDR
help
The I2C address of the PCA9551 LED controller.
+config TEGRA186_BPMP
+ bool "Enable support for the Tegra186 BPMP driver"
+ depends on TEGRA186
+ help
+ The Tegra BPMP (Boot and Power Management Processor) is a separate
+ auxiliary CPU embedded into Tegra to perform power management work,
+ and controls related features such as clocks, resets, power domains,
+ PMIC I2C bus, etc. This driver provides the core low-level
+ communication path by which feature-specific drivers (such as clock)
+ can make requests to the BPMP. This driver is similar to an MFD
+ driver in the Linux kernel.
+
config WINBOND_W83627
bool "Enable Winbond Super I/O driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af541c6..dac9d10 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
endif
endif
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
+obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
diff --git a/drivers/misc/tegra186_bpmp.c b/drivers/misc/tegra186_bpmp.c
new file mode 100644
index 0000000..f4ddbea3
--- /dev/null
+++ b/drivers/misc/tegra186_bpmp.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <mailbox.h>
+#include <misc.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+#include <asm/arch-tegra/ivc.h>
+
+#define BPMP_IVC_FRAME_COUNT 1
+#define BPMP_IVC_FRAME_SIZE 128
+
+#define BPMP_FLAG_DO_ACK BIT(0)
+#define BPMP_FLAG_RING_DOORBELL BIT(1)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct tegra186_bpmp {
+ struct mbox_chan mbox;
+ struct tegra_ivc ivc;
+};
+
+static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg,
+ int tx_size, void *rx_msg, int rx_size)
+{
+ struct tegra186_bpmp *priv = dev_get_priv(dev);
+ int ret, err;
+ void *ivc_frame;
+ struct mrq_request *req;
+ struct mrq_response *resp;
+ ulong start_time;
+
+ debug("%s(dev=%p, mrq=%u, tx_msg=%p, tx_size=%d, rx_msg=%p, rx_size=%d) (priv=%p)\n",
+ __func__, dev, mrq, tx_msg, tx_size, rx_msg, rx_size, priv);
+
+ if ((tx_size > BPMP_IVC_FRAME_SIZE) || (rx_size > BPMP_IVC_FRAME_SIZE))
+ return -EINVAL;
+
+ ret = tegra_ivc_write_get_next_frame(&priv->ivc, &ivc_frame);
+ if (ret) {
+ error("tegra_ivc_write_get_next_frame() failed: %d\n", ret);
+ return ret;
+ }
+
+ req = ivc_frame;
+ req->mrq = mrq;
+ req->flags = BPMP_FLAG_DO_ACK | BPMP_FLAG_RING_DOORBELL;
+ memcpy(req + 1, tx_msg, tx_size);
+
+ ret = tegra_ivc_write_advance(&priv->ivc);
+ if (ret) {
+ error("tegra_ivc_write_advance() failed: %d\n", ret);
+ return ret;
+ }
+
+ start_time = timer_get_us();
+ for (;;) {
+ ret = tegra_ivc_channel_notified(&priv->ivc);
+ if (ret) {
+ error("tegra_ivc_channel_notified() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = tegra_ivc_read_get_next_frame(&priv->ivc, &ivc_frame);
+ if (!ret)
+ break;
+
+ /* Timeout 20ms; roughly 10x current max observed duration */
+ if ((timer_get_us() - start_time) > 20 * 1000) {
+ error("tegra_ivc_read_get_next_frame() timed out (%d)\n",
+ ret);
+ return -ETIMEDOUT;
+ }
+ }
+
+ resp = ivc_frame;
+ err = resp->err;
+ if (!err && rx_msg && rx_size)
+ memcpy(rx_msg, resp + 1, rx_size);
+
+ ret = tegra_ivc_read_advance(&priv->ivc);
+ if (ret) {
+ error("tegra_ivc_write_advance() failed: %d\n", ret);
+ return ret;
+ }
+
+ if (err) {
+ error("BPMP responded with error %d\n", err);
+ /* err isn't a U-Boot error code, so don't that */
+ return -EIO;
+ }
+
+ return rx_size;
+}
+
+/**
+ * The BPMP exposes multiple different services. We create a sub-device for
+ * each separate type of service, since each device must be of the appropriate
+ * UCLASS.
+ */
+static int tegra186_bpmp_bind(struct udevice *dev)
+{
+ int ret;
+ struct udevice *child;
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ ret = device_bind_driver_to_node(dev, "tegra186_clk", "tegra186_clk",
+ dev->of_offset, &child);
+ if (ret)
+ return ret;
+
+ ret = device_bind_driver_to_node(dev, "tegra186_reset",
+ "tegra186_reset", dev->of_offset,
+ &child);
+ if (ret)
+ return ret;
+
+ ret = device_bind_driver_to_node(dev, "tegra186_power_domain",
+ "tegra186_power_domain",
+ dev->of_offset, &child);
+ if (ret)
+ return ret;
+
+ ret = dm_scan_fdt_dev(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static ulong tegra186_bpmp_get_shmem(struct udevice *dev, int index)
+{
+ int ret;
+ struct fdtdec_phandle_args args;
+ fdt_addr_t reg;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+ "shmem", NULL, 0, index, &args);
+ if (ret < 0) {
+ error("fdtdec_parse_phandle_with_args() failed: %d\n", ret);
+ return ret;
+ }
+
+ reg = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, args.node,
+ "reg", 0, NULL, true);
+ if (reg == FDT_ADDR_T_NONE) {
+ error("fdtdec_get_addr_size_auto_noparent() failed\n");
+ return -ENODEV;
+ }
+
+ return reg;
+}
+
+static void tegra186_bpmp_ivc_notify(struct tegra_ivc *ivc)
+{
+ struct tegra186_bpmp *priv =
+ container_of(ivc, struct tegra186_bpmp, ivc);
+ int ret;
+
+ ret = mbox_send(&priv->mbox, NULL);
+ if (ret)
+ error("mbox_send() failed: %d\n", ret);
+}
+
+static int tegra186_bpmp_probe(struct udevice *dev)
+{
+ struct tegra186_bpmp *priv = dev_get_priv(dev);
+ int ret;
+ ulong tx_base, rx_base, start_time;
+
+ debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv);
+
+ ret = mbox_get_by_index(dev, 0, &priv->mbox);
+ if (ret) {
+ error("mbox_get_by_index() failed: %d\n", ret);
+ return ret;
+ }
+
+ tx_base = tegra186_bpmp_get_shmem(dev, 0);
+ if (IS_ERR_VALUE(tx_base)) {
+ error("tegra186_bpmp_get_shmem failed for tx_base\n");
+ return tx_base;
+ }
+ rx_base = tegra186_bpmp_get_shmem(dev, 1);
+ if (IS_ERR_VALUE(rx_base)) {
+ error("tegra186_bpmp_get_shmem failed for rx_base\n");
+ return rx_base;
+ }
+ debug("shmem: rx=%lx, tx=%lx\n", rx_base, tx_base);
+
+ ret = tegra_ivc_init(&priv->ivc, rx_base, tx_base, BPMP_IVC_FRAME_COUNT,
+ BPMP_IVC_FRAME_SIZE, tegra186_bpmp_ivc_notify);
+ if (ret) {
+ error("tegra_ivc_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ tegra_ivc_channel_reset(&priv->ivc);
+ start_time = timer_get_us();
+ for (;;) {
+ ret = tegra_ivc_channel_notified(&priv->ivc);
+ if (!ret)
+ break;
+
+ /* Timeout 100ms */
+ if ((timer_get_us() - start_time) > 100 * 1000) {
+ error("Initial IVC reset timed out (%d)\n", ret);
+ ret = -ETIMEDOUT;
+ goto err_free_mbox;
+ }
+ }
+
+ return 0;
+
+err_free_mbox:
+ mbox_free(&priv->mbox);
+
+ return ret;
+}
+
+static int tegra186_bpmp_remove(struct udevice *dev)
+{
+ struct tegra186_bpmp *priv = dev_get_priv(dev);
+
+ debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv);
+
+ mbox_free(&priv->mbox);
+
+ return 0;
+}
+
+static struct misc_ops tegra186_bpmp_ops = {
+ .call = tegra186_bpmp_call,
+};
+
+static const struct udevice_id tegra186_bpmp_ids[] = {
+ { .compatible = "nvidia,tegra186-bpmp" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra186_bpmp) = {
+ .name = "tegra186_bpmp",
+ .id = UCLASS_MISC,
+ .of_match = tegra186_bpmp_ids,
+ .bind = tegra186_bpmp_bind,
+ .probe = tegra186_bpmp_probe,
+ .remove = tegra186_bpmp_remove,
+ .ops = &tegra186_bpmp_ops,
+ .priv_auto_alloc_size = sizeof(struct tegra186_bpmp),
+};
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index 023ba3c..f0a39a6 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -9,6 +9,7 @@
#include <bouncebuf.h>
#include <common.h>
+#include <dm/device.h>
#include <errno.h>
#include <asm/gpio.h>
#include <asm/io.h>
@@ -20,6 +21,15 @@
#include <asm/arch-tegra/tegra_mmc.h>
#include <mmc.h>
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
+
DECLARE_GLOBAL_DATA_PTR;
struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE];
@@ -360,11 +370,14 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)
*/
if (clock == 0)
goto out;
-#ifndef CONFIG_TEGRA186
+#ifdef CONFIG_TEGRA186
+ {
+ ulong rate = clk_set_rate(&host->clk, clock);
+ div = (rate + clock - 1) / clock;
+ }
+#else
clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock,
&div);
-#else
- div = (20000000 + clock - 1) / clock;
#endif
debug("div = %d\n", div);
@@ -539,6 +552,9 @@ static int do_mmc_init(int dev_index, bool removable)
{
struct mmc_host *host;
struct mmc *mmc;
+#ifdef CONFIG_TEGRA186
+ int ret;
+#endif
/* DT should have been read & host config filled in */
host = &mmc_host[dev_index];
@@ -550,7 +566,21 @@ static int do_mmc_init(int dev_index, bool removable)
gpio_get_number(&host->cd_gpio));
host->clock = 0;
-#ifndef CONFIG_TEGRA186
+
+#ifdef CONFIG_TEGRA186
+ ret = reset_assert(&host->reset_ctl);
+ if (ret)
+ return ret;
+ ret = clk_enable(&host->clk);
+ if (ret)
+ return ret;
+ ret = clk_set_rate(&host->clk, 20000000);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ ret = reset_deassert(&host->reset_ctl);
+ if (ret)
+ return ret;
+#else
clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
#endif
@@ -577,11 +607,7 @@ static int do_mmc_init(int dev_index, bool removable)
* (actually 52MHz)
*/
host->cfg.f_min = 375000;
-#ifndef CONFIG_TEGRA186
host->cfg.f_max = 48000000;
-#else
- host->cfg.f_max = 375000;
-#endif
host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
@@ -613,7 +639,27 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host,
return -FDT_ERR_NOTFOUND;
}
-#ifndef CONFIG_TEGRA186
+#ifdef CONFIG_TEGRA186
+ {
+ /*
+ * FIXME: This variable should go away when the MMC device
+ * actually is a udevice.
+ */
+ struct udevice dev;
+ int ret;
+ dev.of_offset = node;
+ ret = reset_get_by_name(&dev, "sdmmc", &host->reset_ctl);
+ if (ret) {
+ debug("reset_get_by_index() failed: %d\n", ret);
+ return ret;
+ }
+ ret = clk_get_by_name(&dev, "sdmmc", &host->clk);
+ if (ret) {
+ debug("clk_get_by_index() failed: %d\n", ret);
+ return ret;
+ }
+ }
+#else
host->mmc_id = clock_decode_periph_id(blob, node);
if (host->mmc_id == PERIPH_ID_NONE) {
debug("%s: could not decode periph id\n", __func__);
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index bc52ed3..b718481 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -283,10 +283,9 @@ static void mal_err (struct eth_device *dev, unsigned long isr,
static void emac_err (struct eth_device *dev, unsigned long isr);
extern int phy_setup_aneg (char *devname, unsigned char addr);
-extern int emac4xx_miiphy_read (const char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value);
-extern int emac4xx_miiphy_write (const char *devname, unsigned char addr,
- unsigned char reg, unsigned short value);
+int emac4xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg);
+int emac4xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 value);
int board_emac_count(void);
@@ -2015,8 +2014,17 @@ int ppc_4xx_eth_initialize (bd_t * bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name,
- emac4xx_miiphy_read, emac4xx_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = emac4xx_miiphy_read;
+ mdiodev->write = emac4xx_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
if (0 == virgin) {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 88d8e83..be3ed73 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -124,6 +124,11 @@ config ETH_DESIGNWARE
100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
provide the PHY (physical media interface).
+config ETHOC
+ bool "OpenCores 10/100 Mbps Ethernet MAC"
+ help
+ This MAC is present in OpenRISC and Xtensa XTFPGA boards.
+
config MVPP2
bool "Marvell Armada 375 network interface support"
depends on ARMADA_375
diff --git a/drivers/net/armada100_fec.c b/drivers/net/armada100_fec.c
index e6a6252..ba2cb1a 100644
--- a/drivers/net/armada100_fec.c
+++ b/drivers/net/armada100_fec.c
@@ -57,18 +57,19 @@ static int armdfec_phy_timeout(u32 *reg, u32 flag, int cond)
return !timeout;
}
-static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
- u16 *value)
+static int smi_reg_read(struct mii_dev *bus, int phy_addr, int devad,
+ int phy_reg)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ u16 value = 0;
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct armdfec_device *darmdfec = to_darmdfec(dev);
struct armdfec_reg *regs = darmdfec->regs;
u32 val;
if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
val = readl(&regs->phyadr);
- *value = val & 0x1f;
- return 0;
+ value = val & 0x1f;
+ return value;
}
/* check parameters */
@@ -99,15 +100,15 @@ static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
return -1;
}
val = readl(&regs->smi);
- *value = val & 0xffff;
+ value = val & 0xffff;
- return 0;
+ return value;
}
-static int smi_reg_write(const char *devname,
- u8 phy_addr, u8 phy_reg, u16 value)
+static int smi_reg_write(struct mii_dev *bus, int phy_addr, int devad,
+ int phy_reg, u16 value)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct armdfec_device *darmdfec = to_darmdfec(dev);
struct armdfec_reg *regs = darmdfec->regs;
@@ -711,7 +712,17 @@ int armada100_fec_register(unsigned long base_addr)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = smi_reg_read;
+ mdiodev->write = smi_reg_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 0;
diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c
index 9151600..be3d82e 100644
--- a/drivers/net/at91_emac.c
+++ b/drivers/net/at91_emac.c
@@ -159,23 +159,23 @@ at91_emac_t *get_emacbase_by_name(const char *devname)
return (at91_emac_t *) netdev->iobase;
}
-int at91emac_mii_read(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value)
+int at91emac_mii_read(struct mii_dev *bus, int addr, int devad, int reg)
{
+ unsigned short value = 0;
at91_emac_t *emac;
- emac = get_emacbase_by_name(devname);
- at91emac_read(emac , addr, reg, value);
- return 0;
+ emac = get_emacbase_by_name(bus->name);
+ at91emac_read(emac , addr, reg, &value);
+ return value;
}
-int at91emac_mii_write(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short value)
+int at91emac_mii_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 value)
{
at91_emac_t *emac;
- emac = get_emacbase_by_name(devname);
+ emac = get_emacbase_by_name(bus->name);
at91emac_write(emac, addr, reg, value);
return 0;
}
@@ -502,7 +502,17 @@ int at91emac_register(bd_t *bis, unsigned long iobase)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, at91emac_mii_read, at91emac_mii_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = at91emac_mii_read;
+ mdiodev->write = at91emac_mii_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 1;
}
diff --git a/drivers/net/bcm-sf2-eth-gmac.c b/drivers/net/bcm-sf2-eth-gmac.c
index 977feec..f2853cf 100644
--- a/drivers/net/bcm-sf2-eth-gmac.c
+++ b/drivers/net/bcm-sf2-eth-gmac.c
@@ -596,12 +596,10 @@ bool gmac_mii_busywait(unsigned int timeout)
return tmp & (1 << GMAC_MII_BUSY_SHIFT);
}
-int gmac_miiphy_read(const char *devname, unsigned char phyaddr,
- unsigned char reg, unsigned short *value)
+int gmac_miiphy_read(struct mii_dev *bus, int phyaddr, int devad, int reg)
{
uint32_t tmp = 0;
-
- (void)devname;
+ u16 value = 0;
/* Busy wait timeout is 1ms */
if (gmac_mii_busywait(1000)) {
@@ -621,18 +619,16 @@ int gmac_miiphy_read(const char *devname, unsigned char phyaddr,
return -1;
}
- *value = readl(GMAC_MII_DATA_ADDR) & 0xffff;
- debug("MII read data 0x%x\n", *value);
- return 0;
+ value = readl(GMAC_MII_DATA_ADDR) & 0xffff;
+ debug("MII read data 0x%x\n", value);
+ return value;
}
-int gmac_miiphy_write(const char *devname, unsigned char phyaddr,
- unsigned char reg, unsigned short value)
+int gmac_miiphy_write(struct mii_dev *bus, int phyaddr, int devad, int reg,
+ u16 value)
{
uint32_t tmp = 0;
- (void)devname;
-
/* Busy wait timeout is 1ms */
if (gmac_mii_busywait(1000)) {
error("%s: Prepare MII write: MII/MDIO busy\n", __func__);
diff --git a/drivers/net/bcm-sf2-eth.c b/drivers/net/bcm-sf2-eth.c
index eab4c1f..e274736 100644
--- a/drivers/net/bcm-sf2-eth.c
+++ b/drivers/net/bcm-sf2-eth.c
@@ -244,7 +244,18 @@ int bcm_sf2_eth_register(bd_t *bis, u8 dev_num)
eth_register(dev);
#ifdef CONFIG_CMD_MII
- miiphy_register(dev->name, eth->miiphy_read, eth->miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = eth->miiphy_read;
+ mdiodev->write = eth->miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
/* Initialization */
diff --git a/drivers/net/bcm-sf2-eth.h b/drivers/net/bcm-sf2-eth.h
index 49a5836..6104aff 100644
--- a/drivers/net/bcm-sf2-eth.h
+++ b/drivers/net/bcm-sf2-eth.h
@@ -54,10 +54,10 @@ struct eth_info {
struct phy_device *port[BCM_ETH_MAX_PORT_NUM];
int port_num;
- int (*miiphy_read)(const char *devname, unsigned char phyaddr,
- unsigned char reg, unsigned short *value);
- int (*miiphy_write)(const char *devname, unsigned char phyaddr,
- unsigned char reg, unsigned short value);
+ int (*miiphy_read)(struct mii_dev *bus, int phyaddr, int devad,
+ int reg);
+ int (*miiphy_write)(struct mii_dev *bus, int phyaddr, int devad,
+ int reg, u16 value);
int (*mac_init)(struct eth_device *dev);
int (*enable_mac)(void);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 61cb1b0..26a626b 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -13,6 +13,7 @@
#include <command.h>
#include <malloc.h>
#include <miiphy.h>
+#include <linux/mdio.h>
#include <linux/mii.h>
#include <asm/blackfin.h>
@@ -72,18 +73,20 @@ static int bfin_miiphy_wait(void)
return 0;
}
-static int bfin_miiphy_read(const char *devname, uchar addr, uchar reg, ushort *val)
+static int bfin_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
{
+ ushort val = 0;
if (bfin_miiphy_wait())
return 1;
bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY);
if (bfin_miiphy_wait())
return 1;
- *val = bfin_read_EMAC_STADAT();
- return 0;
+ val = bfin_read_EMAC_STADAT();
+ return val;
}
-static int bfin_miiphy_write(const char *devname, uchar addr, uchar reg, ushort val)
+static int bfin_miiphy_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 val)
{
if (bfin_miiphy_wait())
return 1;
@@ -113,7 +116,19 @@ int bfin_EMAC_initialize(bd_t *bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = bfin_miiphy_read;
+ mdiodev->write = bfin_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
+
+ dev->priv = mdiodev;
#endif
return 0;
@@ -222,8 +237,9 @@ static int bfin_EMAC_recv(struct eth_device *dev)
static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
{
const unsigned short pins[] = CONFIG_BFIN_MAC_PINS;
- u16 phydat;
+ int phydat;
size_t count;
+ struct mii_dev *mdiodev = dev->priv;
/* Enable PHY output */
bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
@@ -236,12 +252,15 @@ static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ)));
/* turn on auto-negotiation and wait for link to come up */
- bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE);
+ bfin_miiphy_write(mdiodev, CONFIG_PHY_ADDR, MDIO_DEVAD_NONE, MII_BMCR,
+ BMCR_ANENABLE);
count = 0;
while (1) {
++count;
- if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat))
- return -1;
+ phydat = bfin_miiphy_read(mdiodev, CONFIG_PHY_ADDR,
+ MDIO_DEVAD_NONE, MII_BMSR);
+ if (phydat < 0)
+ return phydat;
if (phydat & BMSR_LSTATUS)
break;
if (count > 30000) {
@@ -252,8 +271,10 @@ static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
}
/* see what kind of link we have */
- if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat))
- return -1;
+ phydat = bfin_miiphy_read(mdiodev, CONFIG_PHY_ADDR, MDIO_DEVAD_NONE,
+ MII_LPA);
+ if (phydat < 0)
+ return phydat;
if (phydat & LPA_DUPLEX)
*opmode = FDMODE;
else
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index b030498..ca457b8 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -243,11 +243,10 @@ int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
if (tmp & MDIO_USERACCESS0_ACK) {
*data = tmp & 0xffff;
- return(1);
+ return 0;
}
- *data = -1;
- return(0);
+ return -EIO;
}
/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
@@ -268,7 +267,7 @@ int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
;
- return(1);
+ return 0;
}
/* PHY functions for a generic PHY */
@@ -390,14 +389,20 @@ static int gen_auto_negotiate(int phy_addr)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-static int davinci_mii_phy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
+static int davinci_mii_phy_read(struct mii_dev *bus, int addr, int devad,
+ int reg)
{
- return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1);
+ unsigned short value = 0;
+ int retval = davinci_eth_phy_read(addr, reg, &value);
+ if (retval < 0)
+ return retval;
+ return value;
}
-static int davinci_mii_phy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)
+static int davinci_mii_phy_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
{
- return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1);
+ return davinci_eth_phy_write(addr, reg, value);
}
#endif
@@ -883,8 +888,17 @@ int davinci_emac_initialize(void)
debug("Ethernet PHY: %s\n", phy[i].name);
- miiphy_register(phy[i].name, davinci_mii_phy_read,
- davinci_mii_phy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, phy[i].name, MDIO_NAME_LEN);
+ mdiodev->read = davinci_mii_phy_read;
+ mdiodev->write = davinci_mii_phy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
}
#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 196989b..3332ad9 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5513,7 +5513,8 @@ static int do_e1000(cmd_tbl_t *cmdtp, int flag,
struct udevice *dev;
char name[30];
int ret;
-#else
+#endif
+#if !defined(CONFIG_DM_ETH) || defined(CONFIG_E1000_SPI)
struct e1000_hw *hw;
#endif
int cardnum;
@@ -5549,6 +5550,9 @@ static int do_e1000(cmd_tbl_t *cmdtp, int flag,
}
#ifdef CONFIG_E1000_SPI
+#ifdef CONFIG_DM_ETH
+ hw = dev_get_priv(dev);
+#endif
/* Handle the "SPI" subcommand */
if (!strcmp(argv[2], "spi"))
return do_e1000_spi(cmdtp, hw, argc - 3, argv + 3);
diff --git a/drivers/net/e1000_spi.c b/drivers/net/e1000_spi.c
index 576ddb8..cb5f93d 100644
--- a/drivers/net/e1000_spi.c
+++ b/drivers/net/e1000_spi.c
@@ -94,17 +94,17 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
/* Make sure it has an SPI chip */
if (hw->eeprom.type != e1000_eeprom_spi) {
- E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
+ E1000_ERR(hw, "No attached SPI EEPROM found!\n");
return NULL;
}
/* Argument sanity checks */
if (cs != 0) {
- E1000_ERR(hw->nic, "No such SPI chip: %u\n", cs);
+ E1000_ERR(hw, "No such SPI chip: %u\n", cs);
return NULL;
}
if (mode != SPI_MODE_0) {
- E1000_ERR(hw->nic, "Only SPI MODE-0 is supported!\n");
+ E1000_ERR(hw, "Only SPI MODE-0 is supported!\n");
return NULL;
}
@@ -124,7 +124,7 @@ int spi_claim_bus(struct spi_slave *spi)
struct e1000_hw *hw = e1000_hw_from_spi(spi);
if (e1000_acquire_eeprom(hw)) {
- E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
return -1;
}
@@ -342,41 +342,41 @@ static int do_e1000_spi_show(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
/* Extra sanity checks */
if (!length) {
- E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
+ E1000_ERR(hw, "Requested zero-sized dump!\n");
return 1;
}
if ((0x10000 < length) || (0x10000 - length < offset)) {
- E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
+ E1000_ERR(hw, "Can't dump past 0xFFFF!\n");
return 1;
}
/* Allocate a buffer to hold stuff */
buffer = malloc(length);
if (!buffer) {
- E1000_ERR(hw->nic, "Out of Memory!\n");
+ E1000_ERR(hw, "Out of Memory!\n");
return 1;
}
/* Acquire the EEPROM and perform the dump */
if (e1000_acquire_eeprom(hw)) {
- E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
free(buffer);
return 1;
}
err = e1000_spi_eeprom_dump(hw, buffer, offset, length, true);
e1000_release_eeprom(hw);
if (err) {
- E1000_ERR(hw->nic, "Interrupted!\n");
+ E1000_ERR(hw, "Interrupted!\n");
free(buffer);
return 1;
}
/* Now hexdump the result */
printf("%s: ===== Intel e1000 EEPROM (0x%04hX - 0x%04hX) =====",
- hw->nic->name, offset, offset + length - 1);
+ hw->name, offset, offset + length - 1);
for (i = 0; i < length; i++) {
if ((i & 0xF) == 0)
- printf("\n%s: %04hX: ", hw->nic->name, offset + i);
+ printf("\n%s: %04hX: ", hw->name, offset + i);
else if ((i & 0xF) == 0x8)
printf(" ");
printf(" %02hx", buffer[i]);
@@ -407,29 +407,29 @@ static int do_e1000_spi_dump(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
/* Extra sanity checks */
if (!length) {
- E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
+ E1000_ERR(hw, "Requested zero-sized dump!\n");
return 1;
}
if ((0x10000 < length) || (0x10000 - length < offset)) {
- E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
+ E1000_ERR(hw, "Can't dump past 0xFFFF!\n");
return 1;
}
/* Acquire the EEPROM */
if (e1000_acquire_eeprom(hw)) {
- E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
return 1;
}
/* Perform the programming operation */
if (e1000_spi_eeprom_dump(hw, dest, offset, length, true) < 0) {
- E1000_ERR(hw->nic, "Interrupted!\n");
+ E1000_ERR(hw, "Interrupted!\n");
e1000_release_eeprom(hw);
return 1;
}
e1000_release_eeprom(hw);
- printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->nic->name);
+ printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->name);
return 0;
}
@@ -452,19 +452,19 @@ static int do_e1000_spi_program(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
/* Acquire the EEPROM */
if (e1000_acquire_eeprom(hw)) {
- E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
return 1;
}
/* Perform the programming operation */
if (e1000_spi_eeprom_program(hw, source, offset, length, true) < 0) {
- E1000_ERR(hw->nic, "Interrupted!\n");
+ E1000_ERR(hw, "Interrupted!\n");
e1000_release_eeprom(hw);
return 1;
}
e1000_release_eeprom(hw);
- printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->nic->name);
+ printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->name);
return 0;
}
@@ -488,19 +488,19 @@ static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
length = sizeof(uint16_t) * (EEPROM_CHECKSUM_REG + 1);
buffer = malloc(length);
if (!buffer) {
- E1000_ERR(hw->nic, "Unable to allocate EEPROM buffer!\n");
+ E1000_ERR(hw, "Unable to allocate EEPROM buffer!\n");
return 1;
}
/* Acquire the EEPROM */
if (e1000_acquire_eeprom(hw)) {
- E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
+ E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n");
return 1;
}
/* Read the EEPROM */
if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) {
- E1000_ERR(hw->nic, "Interrupted!\n");
+ E1000_ERR(hw, "Interrupted!\n");
e1000_release_eeprom(hw);
return 1;
}
@@ -514,15 +514,15 @@ static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
/* Verify it! */
if (checksum_reg == checksum) {
printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n",
- hw->nic->name, checksum);
+ hw->name, checksum);
e1000_release_eeprom(hw);
return 0;
}
/* Hrm, verification failed, print an error */
- E1000_ERR(hw->nic, "EEPROM checksum is incorrect!\n");
- E1000_ERR(hw->nic, " ...register was 0x%04hx, calculated 0x%04hx\n",
- checksum_reg, checksum);
+ E1000_ERR(hw, "EEPROM checksum is incorrect!\n");
+ E1000_ERR(hw, " ...register was 0x%04hx, calculated 0x%04hx\n",
+ checksum_reg, checksum);
/* If they didn't ask us to update it, just return an error */
if (!upd) {
@@ -531,11 +531,11 @@ static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
}
/* Ok, correct it! */
- printf("%s: Reprogramming the EEPROM checksum...\n", hw->nic->name);
+ printf("%s: Reprogramming the EEPROM checksum...\n", hw->name);
buffer[i] = cpu_to_le16(checksum);
if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t),
sizeof(uint16_t), true)) {
- E1000_ERR(hw->nic, "Interrupted!\n");
+ E1000_ERR(hw, "Interrupted!\n");
e1000_release_eeprom(hw);
return 1;
}
@@ -554,7 +554,8 @@ int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
/* Make sure it has an SPI chip */
if (hw->eeprom.type != e1000_eeprom_spi) {
- E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
+ E1000_ERR(hw, "No attached SPI EEPROM found (%d)!\n",
+ hw->eeprom.type);
return 1;
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index d4a6386..0f350cb 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -334,34 +334,35 @@ static struct eth_device* verify_phyaddr (const char *devname,
return dev;
}
-static int eepro100_miiphy_read(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value)
+static int eepro100_miiphy_read(struct mii_dev *bus, int addr, int devad,
+ int reg)
{
+ unsigned short value = 0;
struct eth_device *dev;
- dev = verify_phyaddr(devname, addr);
+ dev = verify_phyaddr(bus->name, addr);
if (dev == NULL)
return -1;
- if (get_phyreg(dev, addr, reg, value) != 0) {
- printf("%s: mii read timeout!\n", devname);
+ if (get_phyreg(dev, addr, reg, &value) != 0) {
+ printf("%s: mii read timeout!\n", bus->name);
return -1;
}
- return 0;
+ return value;
}
-static int eepro100_miiphy_write(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short value)
+static int eepro100_miiphy_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
{
struct eth_device *dev;
- dev = verify_phyaddr(devname, addr);
+ dev = verify_phyaddr(bus->name, addr);
if (dev == NULL)
return -1;
if (set_phyreg(dev, addr, reg, value) != 0) {
- printf("%s: mii write timeout!\n", devname);
+ printf("%s: mii write timeout!\n", bus->name);
return -1;
}
@@ -451,8 +452,17 @@ int eepro100_initialize (bd_t * bis)
#if defined (CONFIG_MII) || defined(CONFIG_CMD_MII)
/* register mii command access routines */
- miiphy_register(dev->name,
- eepro100_miiphy_read, eepro100_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = eepro100_miiphy_read;
+ mdiodev->write = eepro100_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
card_number++;
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 611eabb..2fe323a 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -742,9 +742,10 @@ static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate)
*
* This function is registered with miiphy_register().
*/
-int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+int enc_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ u16 value = 0;
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
enc_dev_t *enc;
if (!dev || phy_adr != 0)
@@ -757,9 +758,9 @@ int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
enc_release_bus(enc);
return -1;
}
- *value = enc_phy_read(enc, reg);
+ value = enc_phy_read(enc, reg);
enc_release_bus(enc);
- return 0;
+ return value;
}
/*
@@ -767,9 +768,10 @@ int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
*
* This function is registered with miiphy_register().
*/
-int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+int enc_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
+ u16 value)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
enc_dev_t *enc;
if (!dev || phy_adr != 0)
@@ -958,7 +960,17 @@ int enc28j60_initialize(unsigned int bus, unsigned int cs,
sprintf(dev->name, "enc%i.%i", bus, cs);
eth_register(dev);
#if defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, enc_miiphy_read, enc_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = enc_miiphy_read;
+ mdiodev->write = enc_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 0;
}
diff --git a/drivers/net/ep93xx_eth.c b/drivers/net/ep93xx_eth.c
index a3721c5..a94191b 100644
--- a/drivers/net/ep93xx_eth.c
+++ b/drivers/net/ep93xx_eth.c
@@ -30,10 +30,10 @@
#define GET_REGS(eth_dev) (GET_PRIV(eth_dev)->regs)
/* ep93xx_miiphy ops forward declarations */
-static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
- unsigned char const reg, unsigned short * const value);
-static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
- unsigned char const reg, unsigned short const value);
+static int ep93xx_miiphy_read(struct mii_dev *bus, int addr, int devad,
+ int reg);
+static int ep93xx_miiphy_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value);
#if defined(EP93XX_MAC_DEBUG)
/**
@@ -421,7 +421,17 @@ eth_send_out:
#if defined(CONFIG_MII)
int ep93xx_miiphy_initialize(bd_t * const bd)
{
- miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, "ep93xx_eth0", MDIO_NAME_LEN);
+ mdiodev->read = ep93xx_miiphy_read;
+ mdiodev->write = ep93xx_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
return 0;
}
#endif
@@ -542,9 +552,10 @@ eth_init_done:
/**
* Read a 16-bit value from an MII register.
*/
-static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
- unsigned char const reg, unsigned short * const value)
+static int ep93xx_miiphy_read(struct mii_dev *bus, int addr, int devad,
+ int reg)
{
+ unsigned short value = 0;
struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
int ret = -1;
uint32_t self_ctl;
@@ -552,10 +563,9 @@ static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
debug("+ep93xx_miiphy_read");
/* Parameter checks */
- BUG_ON(dev == NULL);
+ BUG_ON(bus->name == NULL);
BUG_ON(addr > MII_ADDRESS_MAX);
BUG_ON(reg > MII_REGISTER_MAX);
- BUG_ON(value == NULL);
/*
* Save the current SelfCTL register value. Set MAC to suppress
@@ -579,7 +589,7 @@ static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
while (readl(&mac->miists) & MIISTS_BUSY)
; /* noop */
- *value = (unsigned short)readl(&mac->miidata);
+ value = (unsigned short)readl(&mac->miidata);
/* Restore the saved SelfCTL value and return. */
writel(self_ctl, &mac->selfctl);
@@ -588,14 +598,16 @@ static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
/* Fall through */
debug("-ep93xx_miiphy_read");
- return ret;
+ if (ret < 0)
+ return ret;
+ return value;
}
/**
* Write a 16-bit value to an MII register.
*/
-static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
- unsigned char const reg, unsigned short const value)
+static int ep93xx_miiphy_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
{
struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
int ret = -1;
@@ -604,7 +616,7 @@ static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
debug("+ep93xx_miiphy_write");
/* Parameter checks */
- BUG_ON(dev == NULL);
+ BUG_ON(bus->name == NULL);
BUG_ON(addr > MII_ADDRESS_MAX);
BUG_ON(reg > MII_REGISTER_MAX);
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index edb3c80..ad8c462 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -5,19 +5,20 @@
* Copyright (C) 2008-2009 Avionic Design GmbH
* Thierry Reding <thierry.reding@avionic-design.de>
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2016 Cadence Design Systems Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
-#include <command.h>
+#include <dm/device.h>
+#include <dm/platform_data/net_ethoc.h>
+#include <linux/io.h>
#include <malloc.h>
#include <net.h>
#include <miiphy.h>
-#include <asm/io.h>
#include <asm/cache.h>
+#include <wait_bit.h>
/* register offsets */
#define MODER 0x00
@@ -162,6 +163,7 @@
#define ETHOC_BD_BASE 0x400
#define ETHOC_TIMEOUT (HZ / 2)
#define ETHOC_MII_TIMEOUT (1 + (HZ / 5))
+#define ETHOC_IOSIZE 0x54
/**
* struct ethoc - driver-private device structure
@@ -177,6 +179,14 @@ struct ethoc {
u32 dty_tx;
u32 num_rx;
u32 cur_rx;
+ void __iomem *iobase;
+ void __iomem *packet;
+ phys_addr_t packet_phys;
+
+#ifdef CONFIG_PHYLIB
+ struct mii_dev *bus;
+ struct phy_device *phydev;
+#endif
};
/**
@@ -189,65 +199,68 @@ struct ethoc_bd {
u32 addr;
};
-static inline u32 ethoc_read(struct eth_device *dev, size_t offset)
+static inline u32 *ethoc_reg(struct ethoc *priv, size_t offset)
{
- return readl(dev->iobase + offset);
+ return priv->iobase + offset;
}
-static inline void ethoc_write(struct eth_device *dev, size_t offset, u32 data)
+static inline u32 ethoc_read(struct ethoc *priv, size_t offset)
{
- writel(data, dev->iobase + offset);
+ return readl(ethoc_reg(priv, offset));
}
-static inline void ethoc_read_bd(struct eth_device *dev, int index,
+static inline void ethoc_write(struct ethoc *priv, size_t offset, u32 data)
+{
+ writel(data, ethoc_reg(priv, offset));
+}
+
+static inline void ethoc_read_bd(struct ethoc *priv, int index,
struct ethoc_bd *bd)
{
size_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
- bd->stat = ethoc_read(dev, offset + 0);
- bd->addr = ethoc_read(dev, offset + 4);
+ bd->stat = ethoc_read(priv, offset + 0);
+ bd->addr = ethoc_read(priv, offset + 4);
}
-static inline void ethoc_write_bd(struct eth_device *dev, int index,
+static inline void ethoc_write_bd(struct ethoc *priv, int index,
const struct ethoc_bd *bd)
{
size_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
- ethoc_write(dev, offset + 0, bd->stat);
- ethoc_write(dev, offset + 4, bd->addr);
+ ethoc_write(priv, offset + 0, bd->stat);
+ ethoc_write(priv, offset + 4, bd->addr);
}
-static int ethoc_set_mac_address(struct eth_device *dev)
+static int ethoc_write_hwaddr_common(struct ethoc *priv, u8 *mac)
{
- u8 *mac = dev->enetaddr;
-
- ethoc_write(dev, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
+ ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
(mac[4] << 8) | (mac[5] << 0));
- ethoc_write(dev, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0));
+ ethoc_write(priv, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0));
return 0;
}
-static inline void ethoc_ack_irq(struct eth_device *dev, u32 mask)
+static inline void ethoc_ack_irq(struct ethoc *priv, u32 mask)
{
- ethoc_write(dev, INT_SOURCE, mask);
+ ethoc_write(priv, INT_SOURCE, mask);
}
-static inline void ethoc_enable_rx_and_tx(struct eth_device *dev)
+static inline void ethoc_enable_rx_and_tx(struct ethoc *priv)
{
- u32 mode = ethoc_read(dev, MODER);
+ u32 mode = ethoc_read(priv, MODER);
mode |= MODER_RXEN | MODER_TXEN;
- ethoc_write(dev, MODER, mode);
+ ethoc_write(priv, MODER, mode);
}
-static inline void ethoc_disable_rx_and_tx(struct eth_device *dev)
+static inline void ethoc_disable_rx_and_tx(struct ethoc *priv)
{
- u32 mode = ethoc_read(dev, MODER);
+ u32 mode = ethoc_read(priv, MODER);
mode &= ~(MODER_RXEN | MODER_TXEN);
- ethoc_write(dev, MODER, mode);
+ ethoc_write(priv, MODER, mode);
}
-static int ethoc_init_ring(struct eth_device *dev)
+static int ethoc_init_ring(struct ethoc *priv)
{
- struct ethoc *priv = (struct ethoc *)dev->priv;
struct ethoc_bd bd;
+ phys_addr_t addr = priv->packet_phys;
int i;
priv->cur_tx = 0;
@@ -256,66 +269,92 @@ static int ethoc_init_ring(struct eth_device *dev)
/* setup transmission buffers */
bd.stat = TX_BD_IRQ | TX_BD_CRC;
+ bd.addr = 0;
for (i = 0; i < priv->num_tx; i++) {
+ if (addr) {
+ bd.addr = addr;
+ addr += PKTSIZE_ALIGN;
+ }
if (i == priv->num_tx - 1)
bd.stat |= TX_BD_WRAP;
- ethoc_write_bd(dev, i, &bd);
+ ethoc_write_bd(priv, i, &bd);
}
bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
for (i = 0; i < priv->num_rx; i++) {
- bd.addr = (u32)net_rx_packets[i];
+ if (addr) {
+ bd.addr = addr;
+ addr += PKTSIZE_ALIGN;
+ } else {
+ bd.addr = virt_to_phys(net_rx_packets[i]);
+ }
if (i == priv->num_rx - 1)
bd.stat |= RX_BD_WRAP;
- flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
- ethoc_write_bd(dev, priv->num_tx + i, &bd);
+ flush_dcache_range((ulong)net_rx_packets[i],
+ (ulong)net_rx_packets[i] + PKTSIZE_ALIGN);
+ ethoc_write_bd(priv, priv->num_tx + i, &bd);
}
return 0;
}
-static int ethoc_reset(struct eth_device *dev)
+static int ethoc_reset(struct ethoc *priv)
{
u32 mode;
/* TODO: reset controller? */
- ethoc_disable_rx_and_tx(dev);
+ ethoc_disable_rx_and_tx(priv);
/* TODO: setup registers */
/* enable FCS generation and automatic padding */
- mode = ethoc_read(dev, MODER);
+ mode = ethoc_read(priv, MODER);
mode |= MODER_CRC | MODER_PAD;
- ethoc_write(dev, MODER, mode);
+ ethoc_write(priv, MODER, mode);
/* set full-duplex mode */
- mode = ethoc_read(dev, MODER);
+ mode = ethoc_read(priv, MODER);
mode |= MODER_FULLD;
- ethoc_write(dev, MODER, mode);
- ethoc_write(dev, IPGT, 0x15);
+ ethoc_write(priv, MODER, mode);
+ ethoc_write(priv, IPGT, 0x15);
- ethoc_ack_irq(dev, INT_MASK_ALL);
- ethoc_enable_rx_and_tx(dev);
+ ethoc_ack_irq(priv, INT_MASK_ALL);
+ ethoc_enable_rx_and_tx(priv);
return 0;
}
-static int ethoc_init(struct eth_device *dev, bd_t * bd)
+static int ethoc_init_common(struct ethoc *priv)
{
- struct ethoc *priv = (struct ethoc *)dev->priv;
- printf("ethoc\n");
+ int ret = 0;
priv->num_tx = 1;
priv->num_rx = PKTBUFSRX;
- ethoc_write(dev, TX_BD_NUM, priv->num_tx);
- ethoc_init_ring(dev);
- ethoc_reset(dev);
+ ethoc_write(priv, TX_BD_NUM, priv->num_tx);
+ ethoc_init_ring(priv);
+ ethoc_reset(priv);
+
+#ifdef CONFIG_PHYLIB
+ ret = phy_startup(priv->phydev);
+ if (ret) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return ret;
+ }
+#endif
+ return ret;
+}
- return 0;
+static void ethoc_stop_common(struct ethoc *priv)
+{
+ ethoc_disable_rx_and_tx(priv);
+#ifdef CONFIG_PHYLIB
+ phy_shutdown(priv->phydev);
+#endif
}
static int ethoc_update_rx_stats(struct ethoc_bd *bd)
@@ -353,37 +392,46 @@ static int ethoc_update_rx_stats(struct ethoc_bd *bd)
return ret;
}
-static int ethoc_rx(struct eth_device *dev, int limit)
+static int ethoc_rx_common(struct ethoc *priv, uchar **packetp)
{
- struct ethoc *priv = (struct ethoc *)dev->priv;
- int count;
-
- for (count = 0; count < limit; ++count) {
- u32 entry;
- struct ethoc_bd bd;
-
- entry = priv->num_tx + (priv->cur_rx % priv->num_rx);
- ethoc_read_bd(dev, entry, &bd);
- if (bd.stat & RX_BD_EMPTY)
- break;
+ struct ethoc_bd bd;
+ u32 i = priv->cur_rx % priv->num_rx;
+ u32 entry = priv->num_tx + i;
+
+ ethoc_read_bd(priv, entry, &bd);
+ if (bd.stat & RX_BD_EMPTY)
+ return -EAGAIN;
+
+ debug("%s(): RX buffer %d, %x received\n",
+ __func__, priv->cur_rx, bd.stat);
+ if (ethoc_update_rx_stats(&bd) == 0) {
+ int size = bd.stat >> 16;
+
+ size -= 4; /* strip the CRC */
+ if (priv->packet)
+ *packetp = priv->packet + entry * PKTSIZE_ALIGN;
+ else
+ *packetp = net_rx_packets[i];
+ return size;
+ } else {
+ return 0;
+ }
+}
- debug("%s(): RX buffer %d, %x received\n",
- __func__, priv->cur_rx, bd.stat);
- if (ethoc_update_rx_stats(&bd) == 0) {
- int size = bd.stat >> 16;
- size -= 4; /* strip the CRC */
- net_process_received_packet((void *)bd.addr, size);
- }
+static int ethoc_is_new_packet_received(struct ethoc *priv)
+{
+ u32 pending;
- /* clear the buffer descriptor so it can be reused */
- flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
- bd.stat &= ~RX_BD_STATS;
- bd.stat |= RX_BD_EMPTY;
- ethoc_write_bd(dev, entry, &bd);
- priv->cur_rx++;
+ pending = ethoc_read(priv, INT_SOURCE);
+ ethoc_ack_irq(priv, pending);
+ if (pending & INT_MASK_BUSY)
+ debug("%s(): packet dropped\n", __func__);
+ if (pending & INT_MASK_RX) {
+ debug("%s(): rx irq\n", __func__);
+ return 1;
}
- return count;
+ return 0;
}
static int ethoc_update_tx_stats(struct ethoc_bd *bd)
@@ -403,52 +451,57 @@ static int ethoc_update_tx_stats(struct ethoc_bd *bd)
return 0;
}
-static void ethoc_tx(struct eth_device *dev)
+static void ethoc_tx(struct ethoc *priv)
{
- struct ethoc *priv = (struct ethoc *)dev->priv;
u32 entry = priv->dty_tx % priv->num_tx;
struct ethoc_bd bd;
- ethoc_read_bd(dev, entry, &bd);
+ ethoc_read_bd(priv, entry, &bd);
if ((bd.stat & TX_BD_READY) == 0)
(void)ethoc_update_tx_stats(&bd);
}
-static int ethoc_send(struct eth_device *dev, void *packet, int length)
+static int ethoc_send_common(struct ethoc *priv, void *packet, int length)
{
- struct ethoc *priv = (struct ethoc *)dev->priv;
struct ethoc_bd bd;
u32 entry;
u32 pending;
int tmo;
entry = priv->cur_tx % priv->num_tx;
- ethoc_read_bd(dev, entry, &bd);
+ ethoc_read_bd(priv, entry, &bd);
if (unlikely(length < ETHOC_ZLEN))
bd.stat |= TX_BD_PAD;
else
bd.stat &= ~TX_BD_PAD;
- bd.addr = (u32)packet;
- flush_dcache_range(bd.addr, bd.addr + length);
+ if (priv->packet) {
+ void *p = priv->packet + entry * PKTSIZE_ALIGN;
+
+ memcpy(p, packet, length);
+ packet = p;
+ } else {
+ bd.addr = virt_to_phys(packet);
+ }
+ flush_dcache_range((ulong)packet, (ulong)packet + length);
bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
bd.stat |= TX_BD_LEN(length);
- ethoc_write_bd(dev, entry, &bd);
+ ethoc_write_bd(priv, entry, &bd);
/* start transmit */
bd.stat |= TX_BD_READY;
- ethoc_write_bd(dev, entry, &bd);
+ ethoc_write_bd(priv, entry, &bd);
/* wait for transfer to succeed */
tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
while (1) {
- pending = ethoc_read(dev, INT_SOURCE);
- ethoc_ack_irq(dev, pending & ~INT_MASK_RX);
+ pending = ethoc_read(priv, INT_SOURCE);
+ ethoc_ack_irq(priv, pending & ~INT_MASK_RX);
if (pending & INT_MASK_BUSY)
debug("%s(): packet dropped\n", __func__);
if (pending & INT_MASK_TX) {
- ethoc_tx(dev);
+ ethoc_tx(priv);
break;
}
if (get_timer(0) >= tmo) {
@@ -461,24 +514,290 @@ static int ethoc_send(struct eth_device *dev, void *packet, int length)
return 0;
}
+static int ethoc_free_pkt_common(struct ethoc *priv)
+{
+ struct ethoc_bd bd;
+ u32 i = priv->cur_rx % priv->num_rx;
+ u32 entry = priv->num_tx + i;
+ void *src;
+
+ ethoc_read_bd(priv, entry, &bd);
+
+ if (priv->packet)
+ src = priv->packet + entry * PKTSIZE_ALIGN;
+ else
+ src = net_rx_packets[i];
+ /* clear the buffer descriptor so it can be reused */
+ flush_dcache_range((ulong)src,
+ (ulong)src + PKTSIZE_ALIGN);
+ bd.stat &= ~RX_BD_STATS;
+ bd.stat |= RX_BD_EMPTY;
+ ethoc_write_bd(priv, entry, &bd);
+ priv->cur_rx++;
+
+ return 0;
+}
+
+#ifdef CONFIG_PHYLIB
+
+static int ethoc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct ethoc *priv = bus->priv;
+ int rc;
+
+ ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg));
+ ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
+
+ rc = wait_for_bit(__func__, ethoc_reg(priv, MIISTATUS),
+ MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false);
+
+ if (rc == 0) {
+ u32 data = ethoc_read(priv, MIIRX_DATA);
+
+ /* reset MII command register */
+ ethoc_write(priv, MIICOMMAND, 0);
+ return data;
+ }
+ return rc;
+}
+
+static int ethoc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct ethoc *priv = bus->priv;
+ int rc;
+
+ ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg));
+ ethoc_write(priv, MIITX_DATA, val);
+ ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
+
+ rc = wait_for_bit(__func__, ethoc_reg(priv, MIISTATUS),
+ MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false);
+
+ if (rc == 0) {
+ /* reset MII command register */
+ ethoc_write(priv, MIICOMMAND, 0);
+ }
+ return rc;
+}
+
+static int ethoc_mdio_init(const char *name, struct ethoc *priv)
+{
+ struct mii_dev *bus = mdio_alloc();
+ int ret;
+
+ if (!bus) {
+ printf("Failed to allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->read = ethoc_mdio_read;
+ bus->write = ethoc_mdio_write;
+ snprintf(bus->name, sizeof(bus->name), "%s", name);
+ bus->priv = priv;
+
+ ret = mdio_register(bus);
+ if (ret < 0)
+ return ret;
+
+ priv->bus = miiphy_get_dev_by_name(name);
+ return 0;
+}
+
+static int ethoc_phy_init(struct ethoc *priv, void *dev)
+{
+ struct phy_device *phydev;
+ int mask = 0xffffffff;
+
+#ifdef CONFIG_PHY_ADDR
+ mask = 1 << CONFIG_PHY_ADDR;
+#endif
+
+ phydev = phy_find_by_mask(priv->bus, mask, PHY_INTERFACE_MODE_MII);
+ if (!phydev)
+ return -ENODEV;
+
+ phy_connect_dev(phydev, dev);
+
+ phydev->supported &= PHY_BASIC_FEATURES;
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+ phy_config(phydev);
+
+ return 0;
+}
+
+#else
+
+static inline int ethoc_mdio_init(const char *name, struct ethoc *priv)
+{
+ return 0;
+}
+
+static inline int ethoc_phy_init(struct ethoc *priv, void *dev)
+{
+ return 0;
+}
+
+#endif
+
+#ifdef CONFIG_DM_ETH
+
+static int ethoc_write_hwaddr(struct udevice *dev)
+{
+ struct ethoc_eth_pdata *pdata = dev_get_platdata(dev);
+ struct ethoc *priv = dev_get_priv(dev);
+ u8 *mac = pdata->eth_pdata.enetaddr;
+
+ return ethoc_write_hwaddr_common(priv, mac);
+}
+
+static int ethoc_send(struct udevice *dev, void *packet, int length)
+{
+ return ethoc_send_common(dev_get_priv(dev), packet, length);
+}
+
+static int ethoc_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ return ethoc_free_pkt_common(dev_get_priv(dev));
+}
+
+static int ethoc_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct ethoc *priv = dev_get_priv(dev);
+
+ if (flags & ETH_RECV_CHECK_DEVICE)
+ if (!ethoc_is_new_packet_received(priv))
+ return -EAGAIN;
+
+ return ethoc_rx_common(priv, packetp);
+}
+
+static int ethoc_start(struct udevice *dev)
+{
+ return ethoc_init_common(dev_get_priv(dev));
+}
+
+static void ethoc_stop(struct udevice *dev)
+{
+ ethoc_stop_common(dev_get_priv(dev));
+}
+
+static int ethoc_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ethoc_eth_pdata *pdata = dev_get_platdata(dev);
+ fdt_addr_t addr;
+
+ pdata->eth_pdata.iobase = dev_get_addr(dev);
+ addr = dev_get_addr_index(dev, 1);
+ if (addr != FDT_ADDR_T_NONE)
+ pdata->packet_base = addr;
+ return 0;
+}
+
+static int ethoc_probe(struct udevice *dev)
+{
+ struct ethoc_eth_pdata *pdata = dev_get_platdata(dev);
+ struct ethoc *priv = dev_get_priv(dev);
+
+ priv->iobase = ioremap(pdata->eth_pdata.iobase, ETHOC_IOSIZE);
+ if (pdata->packet_base) {
+ priv->packet_phys = pdata->packet_base;
+ priv->packet = ioremap(pdata->packet_base,
+ (1 + PKTBUFSRX) * PKTSIZE_ALIGN);
+ }
+
+ ethoc_mdio_init(dev->name, priv);
+ ethoc_phy_init(priv, dev);
+
+ return 0;
+}
+
+static int ethoc_remove(struct udevice *dev)
+{
+ struct ethoc *priv = dev_get_priv(dev);
+
+#ifdef CONFIG_PHYLIB
+ free(priv->phydev);
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+#endif
+ iounmap(priv->iobase);
+ return 0;
+}
+
+static const struct eth_ops ethoc_ops = {
+ .start = ethoc_start,
+ .stop = ethoc_stop,
+ .send = ethoc_send,
+ .recv = ethoc_recv,
+ .free_pkt = ethoc_free_pkt,
+ .write_hwaddr = ethoc_write_hwaddr,
+};
+
+static const struct udevice_id ethoc_ids[] = {
+ { .compatible = "opencores,ethoc" },
+ { }
+};
+
+U_BOOT_DRIVER(ethoc) = {
+ .name = "ethoc",
+ .id = UCLASS_ETH,
+ .of_match = ethoc_ids,
+ .ofdata_to_platdata = ethoc_ofdata_to_platdata,
+ .probe = ethoc_probe,
+ .remove = ethoc_remove,
+ .ops = &ethoc_ops,
+ .priv_auto_alloc_size = sizeof(struct ethoc),
+ .platdata_auto_alloc_size = sizeof(struct ethoc_eth_pdata),
+};
+
+#else
+
+static int ethoc_init(struct eth_device *dev, bd_t *bd)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+
+ return ethoc_init_common(priv);
+}
+
+static int ethoc_write_hwaddr(struct eth_device *dev)
+{
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ u8 *mac = dev->enetaddr;
+
+ return ethoc_write_hwaddr_common(priv, mac);
+}
+
+static int ethoc_send(struct eth_device *dev, void *packet, int length)
+{
+ return ethoc_send_common(dev->priv, packet, length);
+}
+
static void ethoc_halt(struct eth_device *dev)
{
- ethoc_disable_rx_and_tx(dev);
+ ethoc_disable_rx_and_tx(dev->priv);
}
static int ethoc_recv(struct eth_device *dev)
{
- u32 pending;
+ struct ethoc *priv = (struct ethoc *)dev->priv;
+ int count;
- pending = ethoc_read(dev, INT_SOURCE);
- ethoc_ack_irq(dev, pending);
- if (pending & INT_MASK_BUSY)
- debug("%s(): packet dropped\n", __func__);
- if (pending & INT_MASK_RX) {
- debug("%s(): rx irq\n", __func__);
- ethoc_rx(dev, PKTBUFSRX);
- }
+ if (!ethoc_is_new_packet_received(priv))
+ return 0;
+
+ for (count = 0; count < PKTBUFSRX; ++count) {
+ uchar *packetp;
+ int size = ethoc_rx_common(priv, &packetp);
+ if (size < 0)
+ break;
+ if (size > 0)
+ net_process_received_packet(packetp, size);
+ ethoc_free_pkt_common(priv);
+ }
return 0;
}
@@ -503,9 +822,16 @@ int ethoc_initialize(u8 dev_num, int base_addr)
dev->halt = ethoc_halt;
dev->send = ethoc_send;
dev->recv = ethoc_recv;
- dev->write_hwaddr = ethoc_set_mac_address;
+ dev->write_hwaddr = ethoc_write_hwaddr;
sprintf(dev->name, "%s-%hu", "ETHOC", dev_num);
+ priv->iobase = ioremap(dev->iobase, ETHOC_IOSIZE);
eth_register(dev);
+
+ ethoc_mdio_init(dev->name, priv);
+ ethoc_phy_init(priv, dev);
+
return 1;
}
+
+#endif
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index 792534b..15a3ce0 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -556,8 +556,17 @@ int mcdmafec_initialize(bd_t * bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name,
- mcffec_miiphy_read, mcffec_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = mcffec_miiphy_read;
+ mdiodev->write = mcffec_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
if (i > 0)
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
index 4f17015..8fa767a 100644
--- a/drivers/net/ftmac110.c
+++ b/drivers/net/ftmac110.c
@@ -364,32 +364,35 @@ static int ftmac110_recv(struct eth_device *dev)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-static int ftmac110_mdio_read(
- const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+static int ftmac110_mdio_read(struct mii_dev *bus, int addr, int devad,
+ int reg)
{
+ uint16_t value = 0;
int ret = 0;
struct eth_device *dev;
- dev = eth_get_dev_by_name(devname);
+ dev = eth_get_dev_by_name(bus->name);
if (dev == NULL) {
- printf("%s: no such device\n", devname);
+ printf("%s: no such device\n", bus->name);
ret = -1;
} else {
- *value = mdio_read(dev, addr, reg);
+ value = mdio_read(dev, addr, reg);
}
- return ret;
+ if (ret < 0)
+ return ret;
+ return value;
}
-static int ftmac110_mdio_write(
- const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+static int ftmac110_mdio_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
{
int ret = 0;
struct eth_device *dev;
- dev = eth_get_dev_by_name(devname);
+ dev = eth_get_dev_by_name(bus->name);
if (dev == NULL) {
- printf("%s: no such device\n", devname);
+ printf("%s: no such device\n", bus->name);
ret = -1;
} else {
mdio_write(dev, addr, reg, value);
@@ -468,7 +471,17 @@ int ftmac110_initialize(bd_t *bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = ftmac110_mdio_read;
+ mdiodev->write = ftmac110_mdio_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
card_nr++;
diff --git a/drivers/net/lpc32xx_eth.c b/drivers/net/lpc32xx_eth.c
index 6cc273c..2dd69f3 100644
--- a/drivers/net/lpc32xx_eth.c
+++ b/drivers/net/lpc32xx_eth.c
@@ -226,9 +226,11 @@ DECLARE_GLOBAL_DATA_PTR;
*
* Returns 16bit phy register value, or 0xffff on error
*/
-static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
+static int mii_reg_read(struct mii_dev *bus, int phy_adr, int devad,
+ int reg_ofs)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ u16 data = 0;
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
u32 mind_reg;
@@ -270,12 +272,12 @@ static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
return -EFAULT;
}
- *data = (u16) readl(&regs->mrdd);
+ data = (u16) readl(&regs->mrdd);
debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr,
- reg_ofs, *data);
+ reg_ofs, data);
- return 0;
+ return data;
}
/*
@@ -284,9 +286,10 @@ static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
* Returns 0 if write succeed, -EINVAL on bad parameters
* -ETIME on timeout
*/
-static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+static int mii_reg_write(struct mii_dev *bus, int phy_adr, int devad,
+ int reg_ofs, u16 data)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
u32 mind_reg;
@@ -333,25 +336,6 @@ static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
}
#endif
-#if defined(CONFIG_PHYLIB)
-int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
- int reg_addr)
-{
- u16 data;
- int ret;
- ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data);
- if (ret)
- return ret;
- return data;
-}
-
-int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
- int reg_addr, u16 data)
-{
- return mii_reg_write(bus->name, phy_addr, reg_addr, data);
-}
-#endif
-
/*
* Provide default Ethernet buffers base address if target did not.
* Locate buffers in SRAM at 0x00001000 to avoid cache issues and
@@ -580,8 +564,8 @@ int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid)
printf("mdio_alloc failed\n");
return -ENOMEM;
}
- bus->read = lpc32xx_eth_phy_read;
- bus->write = lpc32xx_eth_phy_write;
+ bus->read = mii_reg_read;
+ bus->write = mii_reg_write;
strcpy(bus->name, dev->name);
ret = mdio_register(bus);
@@ -645,7 +629,17 @@ int lpc32xx_eth_initialize(bd_t *bis)
#if defined(CONFIG_PHYLIB)
lpc32xx_eth_phylib_init(dev, CONFIG_PHY_ADDR);
#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, mii_reg_read, mii_reg_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = mii_reg_read;
+ mdiodev->write = mii_reg_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 0;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 0835fdc..921537f 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -43,6 +43,8 @@
#include "macb.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#define MACB_RX_BUFFER_SIZE 4096
#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128)
#define MACB_TX_RING_SIZE 16
@@ -108,6 +110,10 @@ struct macb_device {
#endif
unsigned short phy_addr;
struct mii_dev *bus;
+
+#ifdef CONFIG_DM_ETH
+ phy_interface_t phy_interface;
+#endif
};
#ifndef CONFIG_DM_ETH
#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
@@ -199,39 +205,41 @@ void __weak arch_get_mdio_control(const char *name)
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
-int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
{
+ u16 value = 0;
#ifdef CONFIG_DM_ETH
- struct udevice *dev = eth_get_dev_by_name(devname);
+ struct udevice *dev = eth_get_dev_by_name(bus->name);
struct macb_device *macb = dev_get_priv(dev);
#else
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct macb_device *macb = to_macb(dev);
#endif
if (macb->phy_addr != phy_adr)
return -1;
- arch_get_mdio_control(devname);
- *value = macb_mdio_read(macb, reg);
+ arch_get_mdio_control(bus->name);
+ value = macb_mdio_read(macb, reg);
- return 0;
+ return value;
}
-int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
+ u16 value)
{
#ifdef CONFIG_DM_ETH
- struct udevice *dev = eth_get_dev_by_name(devname);
+ struct udevice *dev = eth_get_dev_by_name(bus->name);
struct macb_device *macb = dev_get_priv(dev);
#else
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct macb_device *macb = to_macb(dev);
#endif
if (macb->phy_addr != phy_adr)
return -1;
- arch_get_mdio_control(devname);
+ arch_get_mdio_control(bus->name);
macb_mdio_write(macb, reg, value);
return 0;
@@ -434,7 +442,7 @@ static void macb_phy_reset(struct macb_device *macb, const char *name)
}
#ifdef CONFIG_MACB_SEARCH_PHY
-static int macb_phy_find(struct macb_device *macb)
+static int macb_phy_find(struct macb_device *macb, const char *name)
{
int i;
u16 phy_id;
@@ -444,21 +452,27 @@ static int macb_phy_find(struct macb_device *macb)
macb->phy_addr = i;
phy_id = macb_mdio_read(macb, MII_PHYSID1);
if (phy_id != 0xffff) {
- printf("%s: PHY present at %d\n", macb->netdev.name, i);
+ printf("%s: PHY present at %d\n", name, i);
return 1;
}
}
/* PHY isn't up to snuff */
- printf("%s: PHY not found\n", macb->netdev.name);
+ printf("%s: PHY not found\n", name);
return 0;
}
#endif /* CONFIG_MACB_SEARCH_PHY */
-
+#ifdef CONFIG_DM_ETH
+static int macb_phy_init(struct udevice *dev, const char *name)
+#else
static int macb_phy_init(struct macb_device *macb, const char *name)
+#endif
{
+#ifdef CONFIG_DM_ETH
+ struct macb_device *macb = dev_get_priv(dev);
+#endif
#ifdef CONFIG_PHYLIB
struct phy_device *phydev;
#endif
@@ -470,7 +484,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
arch_get_mdio_control(name);
#ifdef CONFIG_MACB_SEARCH_PHY
/* Auto-detect phy_addr */
- if (!macb_phy_find(macb))
+ if (!macb_phy_find(macb, name))
return 0;
#endif /* CONFIG_MACB_SEARCH_PHY */
@@ -482,9 +496,14 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
}
#ifdef CONFIG_PHYLIB
+#ifdef CONFIG_DM_ETH
+ phydev = phy_connect(macb->bus, macb->phy_addr, dev,
+ macb->phy_interface);
+#else
/* need to consider other phy interface mode */
phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev,
PHY_INTERFACE_MODE_RGMII);
+#endif
if (!phydev) {
printf("phy_connect failed\n");
return -ENODEV;
@@ -585,8 +604,15 @@ static int gmac_init_multi_queues(struct macb_device *macb)
return 0;
}
+#ifdef CONFIG_DM_ETH
+static int _macb_init(struct udevice *dev, const char *name)
+#else
static int _macb_init(struct macb_device *macb, const char *name)
+#endif
{
+#ifdef CONFIG_DM_ETH
+ struct macb_device *macb = dev_get_priv(dev);
+#endif
unsigned long paddr;
int i;
@@ -634,13 +660,35 @@ static int _macb_init(struct macb_device *macb, const char *name)
* When the GMAC IP without GE feature, this bit is used
* to select interface between RMII and MII.
*/
+#ifdef CONFIG_DM_ETH
+ if (macb->phy_interface == PHY_INTERFACE_MODE_RMII)
+ gem_writel(macb, UR, GEM_BIT(RGMII));
+ else
+ gem_writel(macb, UR, 0);
+#else
#if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
gem_writel(macb, UR, GEM_BIT(RGMII));
#else
gem_writel(macb, UR, 0);
#endif
+#endif
} else {
/* choose RMII or MII mode. This depends on the board */
+#ifdef CONFIG_DM_ETH
+#ifdef CONFIG_AT91FAMILY
+ if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) {
+ macb_writel(macb, USRIO,
+ MACB_BIT(RMII) | MACB_BIT(CLKEN));
+ } else {
+ macb_writel(macb, USRIO, MACB_BIT(CLKEN));
+ }
+#else
+ if (macb->phy_interface == PHY_INTERFACE_MODE_RMII)
+ macb_writel(macb, USRIO, 0);
+ else
+ macb_writel(macb, USRIO, MACB_BIT(MII));
+#endif
+#else
#ifdef CONFIG_RMII
#ifdef CONFIG_AT91FAMILY
macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
@@ -654,9 +702,14 @@ static int _macb_init(struct macb_device *macb, const char *name)
macb_writel(macb, USRIO, MACB_BIT(MII));
#endif
#endif /* CONFIG_RMII */
+#endif
}
+#ifdef CONFIG_DM_ETH
+ if (!macb_phy_init(dev, name))
+#else
if (!macb_phy_init(macb, name))
+#endif
return -1;
/* Enable TX and RX */
@@ -862,7 +915,17 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
eth_register(netdev);
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
- miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, netdev->name, MDIO_NAME_LEN);
+ mdiodev->read = macb_miiphy_read;
+ mdiodev->write = macb_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
macb->bus = miiphy_get_dev_by_name(netdev->name);
#endif
return 0;
@@ -873,9 +936,7 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
static int macb_start(struct udevice *dev)
{
- struct macb_device *macb = dev_get_priv(dev);
-
- return _macb_init(macb, dev->name);
+ return _macb_init(dev, dev->name);
}
static int macb_send(struct udevice *dev, void *packet, int length)
@@ -933,11 +994,33 @@ static int macb_eth_probe(struct udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev);
struct macb_device *macb = dev_get_priv(dev);
+#ifdef CONFIG_DM_ETH
+ const char *phy_mode;
+
+ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+ if (phy_mode)
+ macb->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (macb->phy_interface == -1) {
+ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+ return -EINVAL;
+ }
+#endif
+
macb->regs = (void *)pdata->iobase;
_macb_eth_initialize(macb);
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
- miiphy_register(dev->name, macb_miiphy_read, macb_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = macb_miiphy_read;
+ mdiodev->write = macb_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
macb->bus = miiphy_get_dev_by_name(dev->name);
#endif
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index fd73099..e1b06b2 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -595,8 +595,17 @@ int mcffec_initialize(bd_t * bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name,
- mcffec_miiphy_read, mcffec_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = mcffec_miiphy_read;
+ mdiodev->write = mcffec_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
if (i > 0)
fec_info[i - 1].next = &fec_info[i];
diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c
index 17a780c..103e365 100644
--- a/drivers/net/mcfmii.c
+++ b/drivers/net/mcfmii.c
@@ -277,8 +277,7 @@ void __mii_init(void)
* Otherwise they hang in mii_send() !!! Sorry!
*/
-int mcffec_miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
- unsigned short *value)
+int mcffec_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
{
short rdreg; /* register working value */
@@ -287,28 +286,22 @@ int mcffec_miiphy_read(const char *devname, unsigned char addr, unsigned char re
#endif
rdreg = mii_send(mk_mii_read(addr, reg));
- *value = rdreg;
-
#ifdef MII_DEBUG
- printf("0x%04x\n", *value);
+ printf("0x%04x\n", rdreg);
#endif
- return 0;
+ return rdreg;
}
-int mcffec_miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
- unsigned short value)
+int mcffec_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 value)
{
#ifdef MII_DEBUG
- printf("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+ printf("miiphy_write(0x%x) @ 0x%x = 0x%04x\n", reg, addr, value);
#endif
mii_send(mk_mii_write(addr, reg, value));
-#ifdef MII_DEBUG
- printf("0x%04x\n", value);
-#endif
-
return 0;
}
diff --git a/drivers/net/mpc512x_fec.c b/drivers/net/mpc512x_fec.c
index e850672..b3746fb 100644
--- a/drivers/net/mpc512x_fec.c
+++ b/drivers/net/mpc512x_fec.c
@@ -22,8 +22,10 @@ DECLARE_GLOBAL_DATA_PTR;
#error "CONFIG_MII has to be defined!"
#endif
-int fec512x_miiphy_read(const char *devname, u8 phyAddr, u8 regAddr, u16 * retVal);
-int fec512x_miiphy_write(const char *devname, u8 phyAddr, u8 regAddr, u16 data);
+int fec512x_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr);
+int fec512x_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr, u16 data);
int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis);
static uchar rx_buff[FEC_BUFFER_SIZE];
@@ -639,8 +641,17 @@ int mpc512x_fec_initialize (bd_t * bis)
eth_register (dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register (dev->name,
- fec512x_miiphy_read, fec512x_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = fec512x_miiphy_read;
+ mdiodev->write = fec512x_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
/* Clean up space FEC's MIB and FIFO RAM ...*/
@@ -670,8 +681,10 @@ int mpc512x_fec_initialize (bd_t * bis)
/* MII-interface related functions */
/********************************************************************/
-int fec512x_miiphy_read(const char *devname, u8 phyAddr, u8 regAddr, u16 *retVal)
+int fec512x_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr)
{
+ u16 retVal = 0;
volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
volatile fec512x_t *eth = &im->fec;
u32 reg; /* convenient holder for the PHY register */
@@ -711,13 +724,14 @@ int fec512x_miiphy_read(const char *devname, u8 phyAddr, u8 regAddr, u16 *retVal
/*
* it's now safe to read the PHY's register
*/
- *retVal = (u16) in_be32(&eth->mii_data);
+ retVal = (u16) in_be32(&eth->mii_data);
- return 0;
+ return retVal;
}
/********************************************************************/
-int fec512x_miiphy_write(const char *devname, u8 phyAddr, u8 regAddr, u16 data)
+int fec512x_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr, u16 data)
{
volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
volatile fec512x_t *eth = &im->fec;
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index e13b4cf..d75e858 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -35,8 +35,10 @@ typedef struct {
uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
} NBUF;
-int fec5xxx_miiphy_read(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 *retVal);
-int fec5xxx_miiphy_write(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
+int fec5xxx_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr);
+int fec5xxx_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr, u16 data);
static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis);
@@ -917,8 +919,17 @@ int mpc5xxx_fec_initialize(bd_t * bis)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register (dev->name,
- fec5xxx_miiphy_read, fec5xxx_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = fec5xxx_miiphy_read;
+ mdiodev->write = fec5xxx_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
/*
@@ -941,8 +952,10 @@ int mpc5xxx_fec_initialize(bd_t * bis)
/* MII-interface related functions */
/********************************************************************/
-int fec5xxx_miiphy_read(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
+int fec5xxx_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr)
{
+ uint16 retVal = 0;
ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
uint32 reg; /* convenient holder for the PHY register */
uint32 phy; /* convenient holder for the PHY */
@@ -977,13 +990,14 @@ int fec5xxx_miiphy_read(const char *devname, uint8 phyAddr, uint8 regAddr, uint1
/*
* it's now safe to read the PHY's register
*/
- *retVal = (uint16) eth->mii_data;
+ retVal = (uint16) eth->mii_data;
- return 0;
+ return retVal;
}
/********************************************************************/
-int fec5xxx_miiphy_write(const char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
+int fec5xxx_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
+ int regAddr, u16 data)
{
ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
uint32 reg; /* convenient holder for the PHY register */
diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c
index b16be92..a1c7ea0 100644
--- a/drivers/net/mvgbe.c
+++ b/drivers/net/mvgbe.c
@@ -48,9 +48,11 @@ DECLARE_GLOBAL_DATA_PTR;
*
* Returns 16bit phy register value, or 0xffff on error
*/
-static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
+static int smi_reg_read(struct mii_dev *bus, int phy_adr, int devad,
+ int reg_ofs)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ u16 data = 0;
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct mvgbe_device *dmvgbe = to_mvgbe(dev);
struct mvgbe_registers *regs = dmvgbe->regs;
u32 smi_reg;
@@ -60,8 +62,8 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
if (phy_adr == MV_PHY_ADR_REQUEST &&
reg_ofs == MV_PHY_ADR_REQUEST) {
/* */
- *data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK);
- return 0;
+ data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK);
+ return data;
}
/* check parameters */
if (phy_adr > PHYADR_MASK) {
@@ -111,12 +113,12 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
for (timeout = 0; timeout < MVGBE_PHY_SMI_TIMEOUT; timeout++)
;
- *data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
+ data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
debug("%s:(adr %d, off %d) value= %04x\n", __func__, phy_adr, reg_ofs,
- *data);
+ data);
- return 0;
+ return data;
}
/*
@@ -125,9 +127,10 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
* Returns 0 if write succeed, -EINVAL on bad parameters
* -ETIME on timeout
*/
-static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+static int smi_reg_write(struct mii_dev *bus, int phy_adr, int devad,
+ int reg_ofs, u16 data)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
struct mvgbe_device *dmvgbe = to_mvgbe(dev);
struct mvgbe_registers *regs = dmvgbe->regs;
u32 smi_reg;
@@ -785,7 +788,17 @@ error1:
#if defined(CONFIG_PHYLIB)
mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = smi_reg_read;
+ mdiodev->write = smi_reg_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
/* Set phy address of the port */
miiphy_write(dev->name, MV_PHY_ADR_REQUEST,
MV_PHY_ADR_REQUEST, PHY_BASE_ADR + devnum);
diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c
index 5cda0b8..af676b9 100644
--- a/drivers/net/phy/miiphybb.c
+++ b/drivers/net/phy/miiphybb.c
@@ -230,24 +230,18 @@ static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
* Returns:
* 0 on success
*/
-int bb_miiphy_read(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value)
+int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg)
{
short rdreg; /* register working value */
int v;
int j; /* counter */
struct bb_miiphy_bus *bus;
- bus = bb_miiphy_getbus(devname);
+ bus = bb_miiphy_getbus(miidev->name);
if (bus == NULL) {
return -1;
}
- if (value == NULL) {
- puts("NULL value pointer\n");
- return -1;
- }
-
miiphy_pre (bus, 1, addr, reg);
/* tri-state our MDIO I/O pin so we can read */
@@ -267,8 +261,7 @@ int bb_miiphy_read(const char *devname, unsigned char addr,
bus->set_mdc(bus, 1);
bus->delay(bus);
}
- /* There is no PHY, set value to 0xFFFF and return */
- *value = 0xFFFF;
+ /* There is no PHY, return */
return -1;
}
@@ -294,13 +287,11 @@ int bb_miiphy_read(const char *devname, unsigned char addr,
bus->set_mdc(bus, 1);
bus->delay(bus);
- *value = rdreg;
-
#ifdef DEBUG
- printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
+ printf("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, rdreg);
#endif
- return 0;
+ return rdreg;
}
@@ -311,13 +302,13 @@ int bb_miiphy_read(const char *devname, unsigned char addr,
* Returns:
* 0 on success
*/
-int bb_miiphy_write (const char *devname, unsigned char addr,
- unsigned char reg, unsigned short value)
+int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg,
+ u16 value)
{
struct bb_miiphy_bus *bus;
int j; /* counter */
- bus = bb_miiphy_getbus(devname);
+ bus = bb_miiphy_getbus(miidev->name);
if (bus == NULL) {
/* Bus not found! */
return -1;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 2fa2016..79c1db2 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -566,7 +566,17 @@ int sh_eth_initialize(bd_t *bd)
eth_register(dev);
bb_miiphy_buses[0].priv = eth;
- miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = bb_miiphy_read;
+ mdiodev->write = bb_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr))
puts("Please set MAC address\n");
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index c85a178..feae8c0 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -219,20 +219,27 @@ static int smc911x_rx(struct eth_device *dev)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
/* wrapper for smc911x_eth_phy_read */
-static int smc911x_miiphy_read(const char *devname, u8 phy, u8 reg, u16 *val)
+static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad,
+ int reg)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
- if (dev)
- return smc911x_eth_phy_read(dev, phy, reg, val);
- return -1;
+ u16 val = 0;
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
+ if (dev) {
+ int retval = smc911x_eth_phy_read(dev, phy, reg, &val);
+ if (retval < 0)
+ return retval;
+ return val;
+ }
+ return -ENODEV;
}
/* wrapper for smc911x_eth_phy_write */
-static int smc911x_miiphy_write(const char *devname, u8 phy, u8 reg, u16 val)
+static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad,
+ int reg, u16 val)
{
- struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct eth_device *dev = eth_get_dev_by_name(bus->name);
if (dev)
return smc911x_eth_phy_write(dev, phy, reg, val);
- return -1;
+ return -ENODEV;
}
#endif
@@ -276,7 +283,17 @@ int smc911x_initialize(u8 dev_num, int base_addr)
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, smc911x_miiphy_read, smc911x_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = smc911x_miiphy_read;
+ mdiodev->write = smc911x_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 1;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 26aa2b0..669e37b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -31,6 +31,7 @@ config PCI_SANDBOX
config PCI_TEGRA
bool "Tegra PCI support"
depends on TEGRA
+ depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
help
Enable support for the PCIe controller found on some generations of
Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 352cdef..ea8adb98 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -13,22 +13,35 @@
#define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h>
+#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
#include <asm/io.h>
#include <asm/gpio.h>
+#include <linux/list.h>
+
+#ifndef CONFIG_TEGRA186
#include <asm/arch/clock.h>
#include <asm/arch/powergate.h>
#include <asm/arch-tegra/xusb-padctl.h>
-
-#include <linux/list.h>
-
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+#endif
+
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +116,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104
#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
@@ -110,6 +126,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define AFI_PEX0_CTRL 0x110
#define AFI_PEX1_CTRL 0x118
#define AFI_PEX2_CTRL 0x128
+#define AFI_PEX2_CTRL_T186 0x19c
#define AFI_PEX_CTRL_RST (1 << 0)
#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
@@ -173,6 +190,7 @@ enum tegra_pci_id {
TEGRA30_PCIE,
TEGRA124_PCIE,
TEGRA210_PCIE,
+ TEGRA186_PCIE,
};
struct tegra_pcie_port {
@@ -189,6 +207,7 @@ struct tegra_pcie_soc {
unsigned int num_ports;
unsigned long pads_pll_ctl;
unsigned long tx_ref_sel;
+ unsigned long afi_pex2_ctrl;
u32 pads_refclk_cfg0;
u32 pads_refclk_cfg1;
bool has_pex_clkreq_en;
@@ -209,7 +228,17 @@ struct tegra_pcie {
unsigned long xbar;
const struct tegra_pcie_soc *soc;
+
+#ifdef CONFIG_TEGRA186
+ struct clk clk_afi;
+ struct clk clk_pex;
+ struct reset_ctl reset_afi;
+ struct reset_ctl reset_pex;
+ struct reset_ctl reset_pcie_x;
+ struct power_domain pwrdom;
+#else
struct tegra_xusb_phy *phy;
+#endif
};
static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
@@ -229,10 +258,12 @@ static void pads_writel(struct tegra_pcie *pcie, unsigned long value,
writel(value, pcie->pads.start + offset);
}
+#ifndef CONFIG_TEGRA186
static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset)
{
return readl(pcie->pads.start + offset);
}
+#endif
static unsigned long rp_readl(struct tegra_pcie_port *port,
unsigned long offset)
@@ -400,6 +431,24 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return 0;
}
break;
+ case TEGRA186_PCIE:
+ switch (lanes) {
+ case 0x0010004:
+ debug("x4 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401;
+ return 0;
+
+ case 0x0010102:
+ debug("x2 x1 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211;
+ return 0;
+
+ case 0x0010101:
+ debug("x1 x1 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111;
+ return 0;
+ }
+ break;
default:
break;
}
@@ -471,6 +520,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return err;
}
+#ifndef CONFIG_TEGRA186
pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
if (pcie->phy) {
err = tegra_xusb_phy_prepare(pcie->phy);
@@ -479,6 +529,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return err;
}
}
+#endif
fdt_for_each_subnode(fdt, subnode, node) {
unsigned int index = 0, num_lanes = 0;
@@ -523,6 +574,44 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return 0;
}
+#ifdef CONFIG_TEGRA186
+static int tegra_pcie_power_on(struct tegra_pcie *pcie)
+{
+ int ret;
+
+ ret = power_domain_on(&pcie->pwrdom);
+ if (ret) {
+ error("power_domain_on() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&pcie->clk_afi);
+ if (ret) {
+ error("clk_enable(afi) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&pcie->clk_pex);
+ if (ret) {
+ error("clk_enable(pex) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&pcie->reset_afi);
+ if (ret) {
+ error("reset_deassert(afi) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&pcie->reset_pex);
+ if (ret) {
+ error("reset_deassert(pex) failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#else
static int tegra_pcie_power_on(struct tegra_pcie *pcie)
{
const struct tegra_pcie_soc *soc = pcie->soc;
@@ -639,6 +728,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
return 0;
}
+#endif
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
{
@@ -647,7 +737,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
u32 value;
int err;
+#ifdef CONFIG_TEGRA186
+ {
+#else
if (pcie->phy) {
+#endif
value = afi_readl(pcie, AFI_PLLE_CONTROL);
value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
@@ -675,6 +769,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_FUSE);
+#ifndef CONFIG_TEGRA186
if (pcie->phy)
err = tegra_xusb_phy_enable(pcie->phy);
else
@@ -684,9 +779,18 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
error("failed to power on PHY: %d\n", err);
return err;
}
+#endif
/* take the PCIEXCLK logic out of reset */
+#ifdef CONFIG_TEGRA186
+ err = reset_deassert(&pcie->reset_pcie_x);
+ if (err) {
+ error("reset_deassert(pcie_x) failed: %d\n", err);
+ return err;
+ }
+#else
reset_set_enable(PERIPH_ID_PCIEXCLK, 0);
+#endif
/* finally enable PCIe */
value = afi_readl(pcie, AFI_CONFIGURATION);
@@ -787,7 +891,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
break;
case 2:
- ret = AFI_PEX2_CTRL;
+ ret = port->pcie->soc->afi_pex2_ctrl;
break;
}
@@ -945,6 +1049,7 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = {
.num_ports = 3,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .afi_pex2_ctrl = AFI_PEX2_CTRL,
.pads_refclk_cfg0 = 0xfa5cfa5c,
.pads_refclk_cfg1 = 0xfa5cfa5c,
.has_pex_clkreq_en = true,
@@ -972,7 +1077,16 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = {
.has_cml_clk = true,
.has_gen2 = true,
.force_pca_enable = true,
- }
+ },
+ [TEGRA186_PCIE] = {
+ .num_ports = 3,
+ .afi_pex2_ctrl = AFI_PEX2_CTRL_T186,
+ .pads_refclk_cfg0 = 0x80b880b8,
+ .pads_refclk_cfg1 = 0x000480b8,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_gen2 = true,
+ },
};
static int pci_tegra_ofdata_to_platdata(struct udevice *dev)
@@ -996,6 +1110,44 @@ static int pci_tegra_probe(struct udevice *dev)
struct tegra_pcie *pcie = dev_get_priv(dev);
int err;
+#ifdef CONFIG_TEGRA186
+ err = clk_get_by_name(dev, "afi", &pcie->clk_afi);
+ if (err) {
+ debug("clk_get_by_name(afi) failed: %d\n", err);
+ return err;
+ }
+
+ err = clk_get_by_name(dev, "pex", &pcie->clk_pex);
+ if (err) {
+ debug("clk_get_by_name(pex) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "afi", &pcie->reset_afi);
+ if (err) {
+ debug("reset_get_by_name(afi) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "pex", &pcie->reset_pex);
+ if (err) {
+ debug("reset_get_by_name(pex) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x);
+ if (err) {
+ debug("reset_get_by_name(pcie_x) failed: %d\n", err);
+ return err;
+ }
+
+ err = power_domain_get(dev, &pcie->pwrdom);
+ if (err) {
+ debug("power_domain_get() failed: %d\n", err);
+ return err;
+ }
+#endif
+
err = tegra_pcie_power_on(pcie);
if (err < 0) {
error("failed to power on");
@@ -1033,6 +1185,7 @@ static const struct udevice_id pci_tegra_ids[] = {
{ .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
{ .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
{ .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
+ { .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE },
{ }
};
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index b904097..132e332 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -17,4 +17,11 @@ config SANDBOX_POWER_DOMAIN
simply accepts requests to power on/off various HW modules without
actually doing anything beyond a little error checking.
+config TEGRA186_POWER_DOMAIN
+ bool "Enable Tegra186 BPMP-based power domain driver"
+ depends on TEGRA186_BPMP
+ help
+ Enable support for manipulating Tegra's on-SoC power domains via IPC
+ requests to the BPMP (Boot and Power Management Processor).
+
endmenu
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index c18292f..2c3d926 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
+obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
diff --git a/drivers/power/domain/tegra186-power-domain.c b/drivers/power/domain/tegra186-power-domain.c
new file mode 100644
index 0000000..41d84de
--- /dev/null
+++ b/drivers/power/domain/tegra186-power-domain.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <power-domain-uclass.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+
+#define UPDATE BIT(0)
+#define ON BIT(1)
+
+static int tegra186_power_domain_request(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return 0;
+}
+
+static int tegra186_power_domain_free(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return 0;
+}
+
+static int tegra186_power_domain_common(struct power_domain *power_domain,
+ bool on)
+{
+ struct mrq_pg_update_state_request req;
+ int on_state = on ? ON : 0;
+ int ret;
+
+ req.partition_id = power_domain->id;
+ req.logic_state = UPDATE | on_state;
+ req.sram_state = UPDATE | on_state;
+ /*
+ * Drivers manage their own clocks so they don't get out of sync, and
+ * since some power domains have many clocks, only a subset of which
+ * are actually needed depending on use-case.
+ */
+ req.clock_state = UPDATE;
+
+ ret = misc_call(power_domain->dev->parent, MRQ_PG_UPDATE_STATE, &req,
+ sizeof(req), NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tegra186_power_domain_on(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return tegra186_power_domain_common(power_domain, true);
+}
+
+static int tegra186_power_domain_off(struct power_domain *power_domain)
+{
+ debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__,
+ power_domain, power_domain->dev, power_domain->id);
+
+ return tegra186_power_domain_common(power_domain, false);
+}
+
+struct power_domain_ops tegra186_power_domain_ops = {
+ .request = tegra186_power_domain_request,
+ .free = tegra186_power_domain_free,
+ .on = tegra186_power_domain_on,
+ .off = tegra186_power_domain_off,
+};
+
+static int tegra186_power_domain_probe(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(tegra186_power_domain) = {
+ .name = "tegra186_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .probe = tegra186_power_domain_probe,
+ .ops = &tegra186_power_domain_ops,
+};
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 40cccc2..468c92e 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -623,20 +623,20 @@ static int uec_miiphy_find_dev_by_name(const char *devname)
* Returns:
* 0 on success
*/
-static int uec_miiphy_read(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value)
+static int uec_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
{
+ unsigned short value = 0;
int devindex = 0;
- if (devname == NULL || value == NULL) {
+ if (bus->name == NULL) {
debug("%s: NULL pointer given\n", __FUNCTION__);
} else {
- devindex = uec_miiphy_find_dev_by_name(devname);
+ devindex = uec_miiphy_find_dev_by_name(bus->name);
if (devindex >= 0) {
- *value = uec_read_phy_reg(devlist[devindex], addr, reg);
+ value = uec_read_phy_reg(devlist[devindex], addr, reg);
}
}
- return 0;
+ return value;
}
/*
@@ -645,15 +645,15 @@ static int uec_miiphy_read(const char *devname, unsigned char addr,
* Returns:
* 0 on success
*/
-static int uec_miiphy_write(const char *devname, unsigned char addr,
- unsigned char reg, unsigned short value)
+static int uec_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 value)
{
int devindex = 0;
- if (devname == NULL) {
+ if (bus->name == NULL) {
debug("%s: NULL pointer given\n", __FUNCTION__);
} else {
- devindex = uec_miiphy_find_dev_by_name(devname);
+ devindex = uec_miiphy_find_dev_by_name(bus->name);
if (devindex >= 0) {
uec_write_phy_reg(devlist[devindex], addr, reg, value);
}
@@ -1399,7 +1399,17 @@ int uec_initialize(bd_t *bis, uec_info_t *uec_info)
}
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_register(dev->name, uec_miiphy_read, uec_miiphy_write);
+ int retval;
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev)
+ return -ENOMEM;
+ strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+ mdiodev->read = uec_miiphy_read;
+ mdiodev->write = uec_miiphy_write;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0)
+ return retval;
#endif
return 1;
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 0fe8cc3..5b84f21 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -20,4 +20,11 @@ config SANDBOX_RESET
simply accepts requests to reset various HW modules without actually
doing anything beyond a little error checking.
+config TEGRA186_RESET
+ bool "Enable Tegra186 BPMP-based reset driver"
+ depends on TEGRA186_BPMP
+ help
+ Enable support for manipulating Tegra's on-SoC reset signals via IPC
+ requests to the BPMP (Boot and Power Management Processor).
+
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 71f3b21..ff0e090 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_DM_RESET) += reset-uclass.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o
+obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
diff --git a/drivers/reset/tegra186-reset.c b/drivers/reset/tegra186-reset.c
new file mode 100644
index 0000000..228adda
--- /dev/null
+++ b/drivers/reset/tegra186-reset.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <reset-uclass.h>
+#include <asm/arch-tegra/bpmp_abi.h>
+
+static int tegra186_reset_request(struct reset_ctl *reset_ctl)
+{
+ debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+ reset_ctl->dev, reset_ctl->id);
+
+ return 0;
+}
+
+static int tegra186_reset_free(struct reset_ctl *reset_ctl)
+{
+ debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+ reset_ctl->dev, reset_ctl->id);
+
+ return 0;
+}
+
+static int tegra186_reset_common(struct reset_ctl *reset_ctl,
+ enum mrq_reset_commands cmd)
+{
+ struct mrq_reset_request req;
+ int ret;
+
+ req.cmd = cmd;
+ req.reset_id = reset_ctl->id;
+
+ ret = misc_call(reset_ctl->dev->parent, MRQ_RESET, &req, sizeof(req),
+ NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tegra186_reset_assert(struct reset_ctl *reset_ctl)
+{
+ debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+ reset_ctl->dev, reset_ctl->id);
+
+ return tegra186_reset_common(reset_ctl, CMD_RESET_ASSERT);
+}
+
+static int tegra186_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+ reset_ctl->dev, reset_ctl->id);
+
+ return tegra186_reset_common(reset_ctl, CMD_RESET_DEASSERT);
+}
+
+struct reset_ops tegra186_reset_ops = {
+ .request = tegra186_reset_request,
+ .free = tegra186_reset_free,
+ .rst_assert = tegra186_reset_assert,
+ .rst_deassert = tegra186_reset_deassert,
+};
+
+static int tegra186_reset_probe(struct udevice *dev)
+{
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(tegra186_reset) = {
+ .name = "tegra186_reset",
+ .id = UCLASS_RESET,
+ .probe = tegra186_reset_probe,
+ .ops = &tegra186_reset_ops,
+};
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index 08eaed5..7d9abfd 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -391,8 +391,8 @@ static int smsc95xx_write_hwaddr_common(struct usb_device *udev,
struct smsc95xx_private *priv,
unsigned char *enetaddr)
{
- u32 addr_lo = __get_unaligned_le32(&enetaddr[0]);
- u32 addr_hi = __get_unaligned_le16(&enetaddr[4]);
+ u32 addr_lo = get_unaligned_le32(&enetaddr[0]);
+ u32 addr_hi = get_unaligned_le16(&enetaddr[4]);
int ret;
/* set hardware address */