diff options
Diffstat (limited to 'drivers')
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(®s->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(®s->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 = ðoc_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(®s->mrdd); + data = (u16) readl(®s->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(ð->mii_data); + retVal = (u16) in_be32(ð->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 */ |