diff options
Diffstat (limited to 'drivers')
70 files changed, 2142 insertions, 623 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index e6702eced46..96ff4f566ab 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -14,6 +14,8 @@ source "drivers/block/Kconfig" source "drivers/bootcount/Kconfig" +source "drivers/cache/Kconfig" + source "drivers/clk/Kconfig" source "drivers/cpu/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index a7bba3ed564..0a00096332b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ obj-y += board/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ +obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig new file mode 100644 index 00000000000..24def7ac0fe --- /dev/null +++ b/drivers/cache/Kconfig @@ -0,0 +1,25 @@ +# +# Cache controllers +# + +menu "Cache Controller drivers" + +config CACHE + bool "Enable Driver Model for Cache controllers" + depends on DM + help + Enable driver model for cache controllers that are found on + most CPU's. Cache is memory that the CPU can access directly and + is usually located on the same chip. This uclass can be used for + configuring settings that be found from a device tree file. + +config L2X0_CACHE + tristate "PL310 cache driver" + select CACHE + depends on ARM + help + This driver is for the PL310 cache controller commonly found on + ARMv7(32-bit) devices. The driver configures the cache settings + found in the device tree. + +endmenu diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile new file mode 100644 index 00000000000..9deb961d91f --- /dev/null +++ b/drivers/cache/Makefile @@ -0,0 +1,4 @@ + +obj-$(CONFIG_CACHE) += cache-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox_cache.o +obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o diff --git a/drivers/cache/cache-l2x0.c b/drivers/cache/cache-l2x0.c new file mode 100644 index 00000000000..67c752d076f --- /dev/null +++ b/drivers/cache/cache-l2x0.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + */ +#include <common.h> +#include <command.h> +#include <dm.h> + +#include <asm/io.h> +#include <asm/pl310.h> + +static void l2c310_of_parse_and_init(struct udevice *dev) +{ + u32 tag[3] = { 0, 0, 0 }; + u32 saved_reg, prefetch; + struct pl310_regs *regs = (struct pl310_regs *)dev_read_addr(dev); + + /* Disable the L2 Cache */ + clrbits_le32(®s->pl310_ctrl, L2X0_CTRL_EN); + + saved_reg = readl(®s->pl310_aux_ctrl); + if (!dev_read_u32(dev, "prefetch-data", &prefetch)) { + if (prefetch) + saved_reg |= L310_AUX_CTRL_DATA_PREFETCH_MASK; + else + saved_reg &= ~L310_AUX_CTRL_DATA_PREFETCH_MASK; + } + + if (!dev_read_u32(dev, "prefetch-instr", &prefetch)) { + if (prefetch) + saved_reg |= L310_AUX_CTRL_INST_PREFETCH_MASK; + else + saved_reg &= ~L310_AUX_CTRL_INST_PREFETCH_MASK; + } + + saved_reg |= dev_read_bool(dev, "arm,shared-override"); + writel(saved_reg, ®s->pl310_aux_ctrl); + + saved_reg = readl(®s->pl310_tag_latency_ctrl); + if (!dev_read_u32_array(dev, "arm,tag-latency", tag, 3)) + saved_reg |= L310_LATENCY_CTRL_RD(tag[0] - 1) | + L310_LATENCY_CTRL_WR(tag[1] - 1) | + L310_LATENCY_CTRL_SETUP(tag[2] - 1); + writel(saved_reg, ®s->pl310_tag_latency_ctrl); + + saved_reg = readl(®s->pl310_data_latency_ctrl); + if (!dev_read_u32_array(dev, "arm,data-latency", tag, 3)) + saved_reg |= L310_LATENCY_CTRL_RD(tag[0] - 1) | + L310_LATENCY_CTRL_WR(tag[1] - 1) | + L310_LATENCY_CTRL_SETUP(tag[2] - 1); + writel(saved_reg, ®s->pl310_data_latency_ctrl); + + /* Enable the L2 cache */ + setbits_le32(®s->pl310_ctrl, L2X0_CTRL_EN); +} + +static int l2x0_probe(struct udevice *dev) +{ + l2c310_of_parse_and_init(dev); + + return 0; +} + + +static const struct udevice_id l2x0_ids[] = { + { .compatible = "arm,pl310-cache" }, + {} +}; + +U_BOOT_DRIVER(pl310_cache) = { + .name = "pl310_cache", + .id = UCLASS_CACHE, + .of_match = l2x0_ids, + .probe = l2x0_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/cache/cache-uclass.c b/drivers/cache/cache-uclass.c new file mode 100644 index 00000000000..97ce0249a4a --- /dev/null +++ b/drivers/cache/cache-uclass.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + */ + +#include <common.h> +#include <cache.h> +#include <dm.h> + +int cache_get_info(struct udevice *dev, struct cache_info *info) +{ + struct cache_ops *ops = cache_get_ops(dev); + + if (!ops->get_info) + return -ENOSYS; + + return ops->get_info(dev, info); +} + +UCLASS_DRIVER(cache) = { + .id = UCLASS_CACHE, + .name = "cache", + .post_bind = dm_scan_fdt_dev, +}; diff --git a/drivers/cache/sandbox_cache.c b/drivers/cache/sandbox_cache.c new file mode 100644 index 00000000000..14cc6b0c0ac --- /dev/null +++ b/drivers/cache/sandbox_cache.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + */ + +#include <common.h> +#include <cache.h> +#include <dm.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_get_info(struct udevice *dev, struct cache_info *info) +{ + info->base = 0x11223344; + + return 0; +} + +static const struct cache_ops sandbox_cache_ops = { + .get_info = sandbox_get_info, +}; + +static const struct udevice_id sandbox_cache_ids[] = { + { .compatible = "sandbox,cache" }, + { } +}; + +U_BOOT_DRIVER(cache_sandbox) = { + .name = "cache_sandbox", + .id = UCLASS_CACHE, + .of_match = sandbox_cache_ids, + .ops = &sandbox_cache_ops, +}; diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c index 9c4e8901e80..9bf9cedaf8c 100644 --- a/drivers/clk/rockchip/clk_rk3036.c +++ b/drivers/clk/rockchip/clk_rk3036.c @@ -9,9 +9,9 @@ #include <errno.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3036.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3036.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3036-cru.h> #include <linux/log2.h> diff --git a/drivers/clk/rockchip/clk_rk3128.c b/drivers/clk/rockchip/clk_rk3128.c index 7da785abc67..efda8c830b0 100644 --- a/drivers/clk/rockchip/clk_rk3128.c +++ b/drivers/clk/rockchip/clk_rk3128.c @@ -9,9 +9,9 @@ #include <errno.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3128.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3128.h> +#include <asm/arch-rockchip/hardware.h> #include <bitfield.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3128-cru.h> diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c index db7479a2375..9bb9959c9d3 100644 --- a/drivers/clk/rockchip/clk_rk3188.c +++ b/drivers/clk/rockchip/clk_rk3188.c @@ -12,10 +12,10 @@ #include <mapmem.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3188.h> -#include <asm/arch/grf_rk3188.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3188.h> +#include <asm/arch-rockchip/grf_rk3188.h> +#include <asm/arch-rockchip/hardware.h> #include <dt-bindings/clock/rk3188-cru.h> #include <dm/device-internal.h> #include <dm/lists.h> diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c index 46a569c9ecd..48ed14b2aff 100644 --- a/drivers/clk/rockchip/clk_rk322x.c +++ b/drivers/clk/rockchip/clk_rk322x.c @@ -9,9 +9,9 @@ #include <errno.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk322x.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk322x.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3228-cru.h> #include <linux/log2.h> diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c index 930c99f4d9f..375d7f8acbb 100644 --- a/drivers/clk/rockchip/clk_rk3288.c +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -13,10 +13,10 @@ #include <mapmem.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/grf_rk3288.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3288.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/hardware.h> #include <dt-bindings/clock/rk3288-cru.h> #include <dm/device-internal.h> #include <dm/lists.h> diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index 106621fe7cf..a89e2ecc4ad 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -9,10 +9,10 @@ #include <dm.h> #include <errno.h> #include <syscon.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3328.h> -#include <asm/arch/hardware.h> -#include <asm/arch/grf_rk3328.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3328.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/grf_rk3328.h> #include <asm/io.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3328-cru.h> diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c index 9492cc2a36e..89cbae59c5e 100644 --- a/drivers/clk/rockchip/clk_rk3368.c +++ b/drivers/clk/rockchip/clk_rk3368.c @@ -13,9 +13,9 @@ #include <mapmem.h> #include <syscon.h> #include <bitfield.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3368.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3368.h> +#include <asm/arch-rockchip/hardware.h> #include <asm/io.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3368-cru.h> diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index cab2bd99433..93a652e5ff4 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -13,9 +13,9 @@ #include <syscon.h> #include <bitfield.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3399.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3399.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> #include <dt-bindings/clock/rk3399-cru.h> diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c index 914e2f4b214..3ebb007fab3 100644 --- a/drivers/clk/rockchip/clk_rv1108.c +++ b/drivers/clk/rockchip/clk_rv1108.c @@ -11,9 +11,9 @@ #include <errno.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rv1108.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rv1108.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> #include <dt-bindings/clock/rv1108-cru.h> diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index f78a01aa8f8..a5fc7809bc4 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -575,14 +575,6 @@ static int udma_get_tchan(struct udma_chan *uc) pr_debug("chan%d: got tchan%d\n", uc->id, uc->tchan->id); - if (udma_is_chan_running(uc)) { - dev_warn(ud->dev, "chan%d: tchan%d is running!\n", uc->id, - uc->tchan->id); - udma_stop(uc); - if (udma_is_chan_running(uc)) - dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); - } - return 0; } @@ -602,14 +594,6 @@ static int udma_get_rchan(struct udma_chan *uc) pr_debug("chan%d: got rchan%d\n", uc->id, uc->rchan->id); - if (udma_is_chan_running(uc)) { - dev_warn(ud->dev, "chan%d: rchan%d is running!\n", uc->id, - uc->rchan->id); - udma_stop(uc); - if (udma_is_chan_running(uc)) - dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); - } - return 0; } @@ -652,14 +636,6 @@ static int udma_get_chan_pair(struct udma_chan *uc) pr_debug("chan%d: got t/rchan%d pair\n", uc->id, chan_id); - if (udma_is_chan_running(uc)) { - dev_warn(ud->dev, "chan%d: t/rchan%d pair is running!\n", - uc->id, chan_id); - udma_stop(uc); - if (udma_is_chan_running(uc)) - dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); - } - return 0; } @@ -1071,6 +1047,15 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) } } + if (udma_is_chan_running(uc)) { + dev_warn(ud->dev, "chan%d: is running!\n", uc->id); + udma_stop(uc); + if (udma_is_chan_running(uc)) { + dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); + goto err_free_res; + } + } + /* PSI-L pairing */ ret = udma_navss_psil_pair(ud, uc->src_thread, uc->dst_thread); if (ret) { @@ -1492,7 +1477,7 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata) u32 tc_ring_id; int ret; - if (!metadata) + if (metadata) packet_data = *((struct ti_udma_drv_packet_data *)metadata); if (dma->id >= (ud->rchan_cnt + ud->tchan_cnt)) { diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 1196ce07123..303aa6a6311 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -158,7 +158,7 @@ static inline int ti_sci_get_response(struct ti_sci_info *info, int ret; /* Receive the response */ - ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_ms); + ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_ms * 1000); if (ret) { dev_err(info->dev, "%s: Message receive failed. ret = %d\n", __func__, ret); @@ -257,7 +257,8 @@ static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle) info = handle_to_ti_sci_info(handle); - xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0, + xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr), sizeof(*rev_info)); if (IS_ERR(xfer)) { @@ -499,8 +500,8 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle, info = handle_to_ti_sci_info(handle); - /* Response is expected, so need of any flags */ - xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, 0, + xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, (u32 *)&req, sizeof(req), sizeof(*resp)); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); @@ -2574,8 +2575,8 @@ static int ti_sci_cmd_change_fwl_owner(const struct ti_sci_handle *handle, info = handle_to_ti_sci_info(handle); - xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_GET, - TISCI_MSG_FWL_CHANGE_OWNER, + xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_FWL_CHANGE_OWNER, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, (u32 *)&req, sizeof(req), sizeof(*resp)); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b3e4ecc50e1..684ca9d868f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -351,7 +351,7 @@ config MPC8XXX_GPIO config MT7621_GPIO bool "MediaTek MT7621 GPIO driver" - depends on DM_GPIO && ARCH_MT7620 + depends on DM_GPIO && SOC_MT7628 default y help Say yes here to support MediaTek MT7621 compatible GPIOs. diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index 21df2277176..3d96678a45a 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -12,7 +12,8 @@ #include <linux/errno.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clock.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/gpio.h> #include <dm/pinctrl.h> #include <dt-bindings/clock/rk3288-cru.h> diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 74ac0a4aa78..0a2dafcec6c 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -271,6 +271,17 @@ static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status, do { control = readl(&twsi->control); if (control & MVTWSI_CONTROL_IFLG) { + /* + * On Armada 38x it seems that the controller works as + * if it first set the MVTWSI_CONTROL_IFLAG in the + * control register and only after that it changed the + * status register. + * This sometimes caused weird bugs which only appeared + * on selected I2C speeds and even then only sometimes. + * We therefore add here a simple ndealy(100), which + * seems to fix this weird bug. + */ + ndelay(100); status = readl(&twsi->status); if (status == expected_status) return 0; diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index f9a5796b96b..cdd94bb05a9 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -12,9 +12,9 @@ #include <errno.h> #include <i2c.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/i2c.h> -#include <asm/arch/periph.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/i2c.h> +#include <asm/arch-rockchip/periph.h> #include <dm/pinctrl.h> #include <linux/sizes.h> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index c34dd5d1879..c23299ea962 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -78,6 +78,12 @@ config SUPPORT_EMMC_RPMB Enable support for reading, writing and programming the key for the Replay Protection Memory Block partition in eMMC. +config SUPPORT_EMMC_BOOT + bool "Support some additional features of the eMMC boot partitions" + help + Enable support for eMMC boot partitions. This also enables + extensions within the mmc command. + config MMC_IO_VOLTAGE bool "Support IO voltage configuration" help @@ -385,6 +391,20 @@ config MMC_SDHCI_SDMA This enables support for the SDMA (Single Operation DMA) defined in the SD Host Controller Standard Specification Version 1.00 . +config MMC_SDHCI_ADMA + bool "Support SDHCI ADMA2" + depends on MMC_SDHCI + help + This enables support for the ADMA (Advanced DMA) defined + in the SD Host Controller Standard Specification Version 3.00 + +config SPL_MMC_SDHCI_ADMA + bool "Support SDHCI ADMA2 in SPL" + depends on MMC_SDHCI + help + This enables support for the ADMA (Advanced DMA) defined + in the SD Host Controller Standard Specification Version 3.00 in SPL. + config MMC_SDHCI_ATMEL bool "Atmel SDHCI controller support" depends on ARCH_AT91 diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 93a836eac36..1992d611821 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -74,15 +74,15 @@ static void dwmci_prepare_data(struct dwmci_host *host, dwmci_set_idma_desc(cur_idmac, flags, cnt, (ulong)bounce_buffer + (i * PAGE_SIZE)); + cur_idmac++; if (blk_cnt <= 8) break; blk_cnt -= 8; - cur_idmac++; i++; } while(1); data_end = (ulong)cur_idmac; - flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); + flush_dcache_range(data_start, roundup(data_end, ARCH_DMA_MINALIGN)); ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; @@ -114,22 +114,40 @@ static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len) return 0; } +static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) +{ + unsigned int timeout; + + timeout = size * 8 * 1000; /* counting in bits and msec */ + timeout *= 2; /* wait twice as long */ + timeout /= mmc->clock; + timeout /= mmc->bus_width; + timeout /= mmc->ddr_mode ? 2 : 1; + timeout = (timeout < 1000) ? 1000 : timeout; + + return timeout; +} + static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) { + struct mmc *mmc = host->mmc; int ret = 0; - u32 timeout = 240000; - u32 mask, size, i, len = 0; + u32 timeout, mask, size, i, len = 0; u32 *buf = NULL; ulong start = get_timer(0); u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1) * 2; - size = data->blocksize * data->blocks / 4; + size = data->blocksize * data->blocks; if (data->flags == MMC_DATA_READ) buf = (unsigned int *)data->dest; else buf = (unsigned int *)data->src; + timeout = dwmci_get_timeout(mmc, size); + + size /= 4; + for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); /* Error during data transfer. */ @@ -252,14 +270,20 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); } else { if (data->flags == MMC_DATA_READ) { - bounce_buffer_start(&bbstate, (void*)data->dest, + ret = bounce_buffer_start(&bbstate, + (void*)data->dest, data->blocksize * data->blocks, GEN_BB_WRITE); } else { - bounce_buffer_start(&bbstate, (void*)data->src, + ret = bounce_buffer_start(&bbstate, + (void*)data->src, data->blocksize * data->blocks, GEN_BB_READ); } + + if (ret) + return ret; + dwmci_prepare_data(host, data, cur_idmac, bbstate.bounce_buffer); } diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 9e34557d165..1b7de74a72d 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -297,6 +297,13 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); return -ETIMEDOUT; } + } else { +#ifdef CONFIG_DM_GPIO + if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) { + printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); + return -ETIMEDOUT; + } +#endif } esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, @@ -614,18 +621,31 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) #else int pre_div = 2; #endif - int ddr_pre_div = mmc->ddr_mode ? 2 : 1; int sdhc_clk = priv->sdhc_clk; uint clk; + /* + * For ddr mode, usdhc need to enable DDR mode first, after select + * this DDR mode, usdhc will automatically divide the usdhc clock + */ + if (mmc->ddr_mode) { + writel(readl(®s->mixctrl) | MIX_CTRL_DDREN, ®s->mixctrl); + sdhc_clk >>= 1; + } + if (clock < mmc->cfg->f_min) clock = mmc->cfg->f_min; - while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256) - pre_div *= 2; + if (sdhc_clk / 16 > clock) { + for (; pre_div < 256; pre_div *= 2) + if ((sdhc_clk / pre_div) <= (clock * 16)) + break; + } else + pre_div = 1; - while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16) - div++; + for (div = 1; div <= 16; div++) + if ((sdhc_clk / (div * pre_div)) <= clock) + break; pre_div >>= 1; div -= 1; @@ -1489,14 +1509,15 @@ static int fsl_esdhc_probe(struct udevice *dev) #endif } - priv->wp_enable = 1; - + if (dev_read_prop(dev, "fsl,wp-controller", NULL)) { + priv->wp_enable = 1; + } else { + priv->wp_enable = 0; #ifdef CONFIG_DM_GPIO - ret = gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, + gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN); - if (ret) - priv->wp_enable = 0; #endif + } priv->vs18_enable = 0; diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index bf2d83a52c5..b2a1201631a 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -13,8 +13,8 @@ #include <pwrseq.h> #include <syscon.h> #include <asm/gpio.h> -#include <asm/arch/clock.h> -#include <asm/arch/periph.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/periph.h> #include <linux/err.h> struct rockchip_mmc_plat { diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index cdeba914f95..e2bb90abbdf 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -67,17 +67,123 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) } } -static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, - unsigned int start_addr) +#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) +static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len, + bool end) +{ + struct sdhci_adma_desc *desc; + u8 attr; + + desc = &host->adma_desc_table[host->desc_slot]; + + attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + if (!end) + host->desc_slot++; + else + attr |= ADMA_DESC_ATTR_END; + + desc->attr = attr; + desc->len = len; + desc->reserved = 0; + desc->addr_lo = (dma_addr_t)buf; +#ifdef CONFIG_DMA_ADDR_T_64BIT + desc->addr_hi = (u64)buf >> 32; +#endif +} + +static void sdhci_prepare_adma_table(struct sdhci_host *host, + struct mmc_data *data) +{ + uint trans_bytes = data->blocksize * data->blocks; + uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); + int i = desc_count; + char *buf; + + host->desc_slot = 0; + + if (data->flags & MMC_DATA_READ) + buf = data->dest; + else + buf = (char *)data->src; + + while (--i) { + sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false); + buf += ADMA_MAX_LEN; + trans_bytes -= ADMA_MAX_LEN; + } + + sdhci_adma_desc(host, buf, trans_bytes, true); + + flush_cache((dma_addr_t)host->adma_desc_table, + ROUND(desc_count * sizeof(struct sdhci_adma_desc), + ARCH_DMA_MINALIGN)); +} +#elif defined(CONFIG_MMC_SDHCI_SDMA) +static void sdhci_prepare_adma_table(struct sdhci_host *host, + struct mmc_data *data) +{} +#endif +#if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)) +static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, + int *is_aligned, int trans_bytes) { - unsigned int stat, rdy, mask, timeout, block = 0; - bool transfer_done = false; -#ifdef CONFIG_MMC_SDHCI_SDMA unsigned char ctrl; + + if (data->flags == MMC_DATA_READ) + host->start_addr = (dma_addr_t)data->dest; + else + host->start_addr = (dma_addr_t)data->src; + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; + if (host->flags & USE_ADMA64) + ctrl |= SDHCI_CTRL_ADMA64; + else if (host->flags & USE_ADMA) + ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + if (host->flags & USE_SDMA) { + if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && + (host->start_addr & 0x7) != 0x0) { + *is_aligned = 0; + host->start_addr = (unsigned long)aligned_buffer; + if (data->flags != MMC_DATA_READ) + memcpy(aligned_buffer, data->src, trans_bytes); + } + +#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) + /* + * Always use this bounce-buffer when + * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined + */ + *is_aligned = 0; + host->start_addr = (unsigned long)aligned_buffer; + if (data->flags != MMC_DATA_READ) + memcpy(aligned_buffer, data->src, trans_bytes); +#endif + sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS); + + } else if (host->flags & (USE_ADMA | USE_ADMA64)) { + sdhci_prepare_adma_table(host, data); + + sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS); + if (host->flags & USE_ADMA64) + sdhci_writel(host, (u64)host->adma_addr >> 32, + SDHCI_ADMA_ADDRESS_HI); + } + + flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN)); +} +#else +static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, + int *is_aligned, int trans_bytes) +{} #endif +static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data) +{ + dma_addr_t start_addr = host->start_addr; + unsigned int stat, rdy, mask, timeout, block = 0; + bool transfer_done = false; timeout = 1000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; @@ -104,14 +210,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, continue; } } -#ifdef CONFIG_MMC_SDHCI_SDMA - if (!transfer_done && (stat & SDHCI_INT_DMA_END)) { + if ((host->flags & USE_DMA) && !transfer_done && + (stat & SDHCI_INT_DMA_END)) { sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS); - start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); - start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; - sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); + if (host->flags & USE_SDMA) { + start_addr &= + ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); + start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; + sdhci_writel(host, start_addr, + SDHCI_DMA_ADDRESS); + } } -#endif if (timeout-- > 0) udelay(10); else { @@ -149,10 +258,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, int ret = 0; int trans_bytes = 0, is_aligned = 1; u32 mask, flags, mode; - unsigned int time = 0, start_addr = 0; + unsigned int time = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; ulong start = get_timer(0); + host->start_addr = 0; /* Timeout unit - ms */ static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; @@ -218,33 +328,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (data->flags == MMC_DATA_READ) mode |= SDHCI_TRNS_READ; -#ifdef CONFIG_MMC_SDHCI_SDMA - if (data->flags == MMC_DATA_READ) - start_addr = (unsigned long)data->dest; - else - start_addr = (unsigned long)data->src; - if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && - (start_addr & 0x7) != 0x0) { - is_aligned = 0; - start_addr = (unsigned long)aligned_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); + if (host->flags & USE_DMA) { + mode |= SDHCI_TRNS_DMA; + sdhci_prepare_dma(host, data, &is_aligned, trans_bytes); } -#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) - /* - * Always use this bounce-buffer when - * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined - */ - is_aligned = 0; - start_addr = (unsigned long)aligned_buffer; - if (data->flags != MMC_DATA_READ) - memcpy(aligned_buffer, data->src, trans_bytes); -#endif - - sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); - mode |= SDHCI_TRNS_DMA; -#endif sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize), SDHCI_BLOCK_SIZE); @@ -255,12 +343,6 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, } sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); -#ifdef CONFIG_MMC_SDHCI_SDMA - if (data) { - trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE); - flush_cache(start_addr, trans_bytes); - } -#endif sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); start = get_timer(0); do { @@ -286,7 +368,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, ret = -1; if (!ret && data) - ret = sdhci_transfer_data(host, data, start_addr); + ret = sdhci_transfer_data(host, data); if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) udelay(1000); @@ -570,6 +652,24 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, __func__); return -EINVAL; } + + host->flags |= USE_SDMA; +#endif +#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) + if (!(caps & SDHCI_CAN_DO_ADMA2)) { + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); + return -EINVAL; + } + host->adma_desc_table = (struct sdhci_adma_desc *) + memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); + + host->adma_addr = (dma_addr_t)host->adma_desc_table; +#ifdef CONFIG_DMA_ADDR_T_64BIT + host->flags |= USE_ADMA64; +#else + host->flags |= USE_ADMA; +#endif #endif if (host->quirks & SDHCI_QUIRK_REG32_RW) host->version = diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index e6a84a52b42..cfa9b535c8a 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -730,43 +730,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd) return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1; } -static void nand_flash_init(void) -{ - /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS! - * Instead, have your board_init() set EMIF timings, based on its - * knowledge of the clocks and what devices are hooked up ... and - * don't even do that unless no UBL handled it. - */ -#ifdef CONFIG_SOC_DM644X - u_int32_t acfg1 = 0x3ffffffc; - - /*------------------------------------------------------------------* - * NAND FLASH CHIP TIMEOUT @ 459 MHz * - * * - * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * - * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * - * * - *------------------------------------------------------------------*/ - acfg1 = 0 - | (0 << 31) /* selectStrobe */ - | (0 << 30) /* extWait */ - | (1 << 26) /* writeSetup 10 ns */ - | (3 << 20) /* writeStrobe 40 ns */ - | (1 << 17) /* writeHold 10 ns */ - | (1 << 13) /* readSetup 10 ns */ - | (5 << 7) /* readStrobe 60 ns */ - | (1 << 4) /* readHold 10 ns */ - | (3 << 2) /* turnAround ?? ns */ - | (0 << 0) /* asyncSize 8-bit bus */ - ; - - __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */ - - /* NAND flash on CS2 */ - __raw_writel(0x00000101, &davinci_emif_regs->nandfcr); -#endif -} - void davinci_nand_init(struct nand_chip *nand) { #if defined CONFIG_KEYSTONE_RBL_NAND @@ -820,8 +783,6 @@ void davinci_nand_init(struct nand_chip *nand) nand->write_buf = nand_davinci_write_buf; nand->dev_ready = nand_davinci_dev_ready; - - nand_flash_init(); } int board_nand_init(struct nand_chip *chip) __attribute__((weak)); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6e436b56abf..64cdc58f92c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -269,7 +269,7 @@ config MACB_ZYNQ config MT7628_ETH bool "MediaTek MT7628 Ethernet Interface" - depends on ARCH_MT7620 + depends on SOC_MT7628 help The MediaTek MT7628 ethernet interface is used on MT7628 and MT7688 based boards. diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c index c01ae758c76..26a61211750 100644 --- a/drivers/net/gmac_rockchip.c +++ b/drivers/net/gmac_rockchip.c @@ -11,15 +11,15 @@ #include <phy.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/periph.h> -#include <asm/arch/clock.h> -#include <asm/arch/hardware.h> -#include <asm/arch/grf_rk322x.h> -#include <asm/arch/grf_rk3288.h> -#include <asm/arch/grf_rk3328.h> -#include <asm/arch/grf_rk3368.h> -#include <asm/arch/grf_rk3399.h> -#include <asm/arch/grf_rv1108.h> +#include <asm/arch-rockchip/periph.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/grf_rk322x.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/grf_rk3328.h> +#include <asm/arch-rockchip/grf_rk3368.h> +#include <asm/arch-rockchip/grf_rk3399.h> +#include <asm/arch-rockchip/grf_rv1108.h> #include <dm/pinctrl.h> #include <dt-bindings/clock/rk3288-cru.h> #include "designware.h" diff --git a/drivers/net/mscc_eswitch/Kconfig b/drivers/net/mscc_eswitch/Kconfig index 6359d0b6101..80dd22f98b7 100644 --- a/drivers/net/mscc_eswitch/Kconfig +++ b/drivers/net/mscc_eswitch/Kconfig @@ -29,3 +29,10 @@ config MSCC_SERVALT_SWITCH select PHYLIB help This driver supports the Servalt network switch device. + +config MSCC_SERVAL_SWITCH + bool "Serval switch driver" + depends on DM_ETH && ARCH_MSCC + select PHYLIB + help + This driver supports the Serval network switch device. diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile index bffd8ec77b0..02f39a76bb0 100644 --- a/drivers/net/mscc_eswitch/Makefile +++ b/drivers/net/mscc_eswitch/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o -obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o +obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o +obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o +obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c index 6667614966d..94852b06e74 100644 --- a/drivers/net/mscc_eswitch/luton_switch.c +++ b/drivers/net/mscc_eswitch/luton_switch.c @@ -15,10 +15,21 @@ #include <net.h> #include <wait_bit.h> -#include "mscc_miim.h" #include "mscc_xfer.h" #include "mscc_mac_table.h" +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x2 << 16) + #define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) @@ -136,61 +147,53 @@ #define PGID_UNICAST 29 #define PGID_SRC 80 -enum luton_target { - PORT0, - PORT1, - PORT2, - PORT3, - PORT4, - PORT5, - PORT6, - PORT7, - PORT8, - PORT9, - PORT10, - PORT11, - PORT12, - PORT13, - PORT14, - PORT15, - PORT16, - PORT17, - PORT18, - PORT19, - PORT20, - PORT21, - PORT22, - PORT23, - SYS, +static const char * const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7", + "port8", "port9", "port10", "port11", "port12", "port13", "port14", + "port15", "port16", "port17", "port18", "port19", "port20", "port21", + "port22", "port23", + "sys", "ana", "rew", "gcb", "qs", "hsio", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 24 + +enum luton_ctrl_regs { + SYS = MAX_PORT, ANA, REW, GCB, QS, - HSIO, - TARGET_MAX, + HSIO }; -#define MAX_PORT (PORT23 - PORT0 + 1) +#define MIN_INT_PORT 0 +#define PORT10 10 +#define PORT11 11 +#define MAX_INT_PORT 12 +#define MIN_EXT_PORT MAX_INT_PORT +#define MAX_EXT_PORT MAX_PORT -#define MIN_INT_PORT PORT0 -#define MAX_INT_PORT (PORT11 - PORT0 + 1) -#define MIN_EXT_PORT PORT12 -#define MAX_EXT_PORT MAX_PORT +#define LUTON_MIIM_BUS_COUNT 2 -enum luton_mdio_target { - MIIM, - TARGET_MDIO_MAX, +struct luton_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; }; -enum luton_phy_id { - INTERNAL, - EXTERNAL, - NUM_PHY, +struct luton_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[LUTON_MIIM_BUS_COUNT]; + struct luton_phy_port_t ports[MAX_PORT]; }; -struct luton_private { - void __iomem *regs[TARGET_MAX]; - struct mii_dev *bus[NUM_PHY]; +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; }; static const unsigned long luton_regs_qs[] = { @@ -207,53 +210,85 @@ static const unsigned long luton_regs_ana_table[] = { [MSCC_ANA_TABLES_MACACCESS] = 0x11b8, }; -static struct mscc_miim_dev miim[NUM_PHY]; +static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT]; +static int miim_count = -1; -static struct mii_dev *luton_mdiobus_init(struct udevice *dev, - int mdiobus_id) +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) { - unsigned long phy_size[NUM_PHY]; - phys_addr_t phy_base[NUM_PHY]; - struct ofnode_phandle_args phandle; - ofnode eth_node, node, mdio_node; - struct resource res; struct mii_dev *bus; - fdt32_t faddr; - int i; bus = mdio_alloc(); if (!bus) return NULL; - /* gather only the first mdio bus */ - eth_node = dev_read_first_subnode(dev); - node = ofnode_first_subnode(eth_node); - ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, - &phandle); - mdio_node = ofnode_get_parent(phandle.node); - - for (i = 0; i < TARGET_MDIO_MAX; i++) { - if (ofnode_read_resource(mdio_node, i, &res)) { - pr_err("%s: get OF resource failed\n", __func__); - return NULL; - } - - faddr = cpu_to_fdt32(res.start); - phy_base[i] = ofnode_translate_address(mdio_node, &faddr); - phy_size[i] = res.end - res.start; - } + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); - strcpy(bus->name, "miim-internal"); - miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id], - phy_size[mdiobus_id]); - bus->priv = &miim[mdiobus_id]; + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; bus->read = mscc_miim_read; bus->write = mscc_miim_write; if (mdio_register(bus)) return NULL; - else - return bus; + + miim[miim_count].bus = bus; + return bus; } static void luton_stop(struct udevice *dev) @@ -324,10 +359,10 @@ static void luton_gmii_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } @@ -346,10 +381,10 @@ static void luton_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } @@ -393,35 +428,34 @@ static void luton_ext_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } -static void serdes6g_write(struct luton_private *priv, u32 addr) +static void serdes6g_write(void __iomem *base, u32 addr) { u32 data; writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT | HSIO_MCB_SERDES6G_CFG_ADDR(addr), - priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); + base + HSIO_MCB_SERDES6G_CFG); do { - data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); + data = readl(base + HSIO_MCB_SERDES6G_CFG); } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT); - - mdelay(100); } -static void serdes6g_cfg(struct luton_private *priv) +static void serdes6g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) { writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) | HSIO_RCOMP_CFG_CFG0_RUN_CAL, - priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0); + base + HSIO_RCOMP_CFG_CFG0); - while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) & + while (readl(base + HSIO_RCOMP_STATUS) & HSIO_RCOMP_STATUS_BUSY) ; @@ -430,50 +464,64 @@ static void serdes6g_cfg(struct luton_private *priv) HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) | HSIO_SERDES6G_ANA_CFG_OB_CFG_POL | HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG); + base + HSIO_SERDES6G_ANA_CFG_OB_CFG); writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) | HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1); + base + HSIO_SERDES6G_ANA_CFG_OB_CFG1); writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) | HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) | HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG); + base + HSIO_SERDES6G_ANA_CFG_IB_CFG); writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE | HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF | HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1); + base + HSIO_SERDES6G_ANA_CFG_IB_CFG1); writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) | HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) | HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) | HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG); + base + HSIO_SERDES6G_ANA_CFG_DES_CFG); writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA | HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG); + base + HSIO_SERDES6G_ANA_CFG_PLL_CFG); writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); + base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); /* * There are 4 serdes6g, configure all except serdes6g0, therefore * the address is b1110 */ - serdes6g_write(priv, 0xe); + serdes6g_write(base, addr); - writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | + writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); - serdes6g_write(priv, 0xe); + base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); + serdes6g_write(base, addr); - clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1, + clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1, HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST); writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST, - priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG); - serdes6g_write(priv, 0xe); + base + HSIO_SERDES6G_DIG_CFG_MISC_CFG); + serdes6g_write(base, addr); +} + +static void serdes_setup(struct luton_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode); + } } static int luton_switch_init(struct luton_private *priv) @@ -495,8 +543,8 @@ static int luton_switch_init(struct luton_private *priv) setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, SYS_SYSTEM_RST_CORE_ENA); - /* Setup the Serdes6g macros */ - serdes6g_cfg(priv); + /* Setup the Serdes macros */ + serdes_setup(priv); return 0; } @@ -525,7 +573,7 @@ static int luton_initialize(struct luton_private *priv) writel(2000000000 / 4, priv->regs[SYS] + SYS_FRM_AGING); - for (i = PORT0; i < MAX_PORT; i++) { + for (i = 0; i < MAX_PORT; i++) { if (i < PORT10) luton_gmii_port_init(priv, i); else @@ -608,56 +656,51 @@ static int luton_recv(struct udevice *dev, int flags, uchar **packetp) return byte_cnt; } +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct luton_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + static int luton_probe(struct udevice *dev) { struct luton_private *priv = dev_get_priv(dev); - int i; - - struct { - enum luton_target id; - char *name; - } reg[] = { - { PORT0, "port0" }, - { PORT1, "port1" }, - { PORT2, "port2" }, - { PORT3, "port3" }, - { PORT4, "port4" }, - { PORT5, "port5" }, - { PORT6, "port6" }, - { PORT7, "port7" }, - { PORT8, "port8" }, - { PORT9, "port9" }, - { PORT10, "port10" }, - { PORT11, "port11" }, - { PORT12, "port12" }, - { PORT13, "port13" }, - { PORT14, "port14" }, - { PORT15, "port15" }, - { PORT16, "port16" }, - { PORT17, "port17" }, - { PORT18, "port18" }, - { PORT19, "port19" }, - { PORT20, "port20" }, - { PORT21, "port21" }, - { PORT22, "port22" }, - { PORT23, "port23" }, - { SYS, "sys" }, - { ANA, "ana" }, - { REW, "rew" }, - { GCB, "gcb" }, - { QS, "qs" }, - { HSIO, "hsio" }, - }; + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; if (!priv) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(reg); i++) { - priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); - if (!priv->regs[reg[i].id]) { + /* Get registers and map them to the private structure */ + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { debug ("Error can't get regs base addresses for %s\n", - reg[i].name); + regs_names[i]); return -ENOMEM; } } @@ -666,7 +709,7 @@ static int luton_probe(struct udevice *dev) writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST); /* Ports with ext phy don't need to reset clk */ - for (i = PORT0; i < MAX_INT_PORT; i++) { + for (i = 0; i < MAX_INT_PORT; i++) { if (i < PORT10) clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK, DEV_GMII_PORT_MODE_CLK_PHY_RST); @@ -680,20 +723,76 @@ static int luton_probe(struct udevice *dev) GCB_MISC_STAT_PHY_READY, true, 500, false)) return -EACCES; - priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL); - for (i = 0; i < MAX_INT_PORT; i++) { - phy_connect(priv->bus[INTERNAL], i, dev, - PHY_INTERFACE_MODE_NONE); + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL, + 0, 0, &phandle); + if (ret) + continue; + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + serval_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff); + else + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy && i >= MAX_INT_PORT) + board_phy_config(phy); } /* * coma_mode is need on only one phy, because all the other phys * will be affected. */ - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10); - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800); - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0); + mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10); + mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800); + mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0); return 0; } @@ -703,7 +802,7 @@ static int luton_remove(struct udevice *dev) struct luton_private *priv = dev_get_priv(dev); int i; - for (i = 0; i < NUM_PHY; i++) { + for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) { mdio_unregister(priv->bus[i]); mdio_free(priv->bus[i]); } diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c index 815c2da2646..5c7e6961be4 100644 --- a/drivers/net/mscc_eswitch/ocelot_switch.c +++ b/drivers/net/mscc_eswitch/ocelot_switch.c @@ -15,7 +15,6 @@ #include <net.h> #include <wait_bit.h> -#include "mscc_miim.h" #include "mscc_xfer.h" #include "mscc_mac_table.h" @@ -26,6 +25,20 @@ #define PHY_STAT 0x4 #define PHY_STAT_SUPERVISOR_COMPLETE BIT(0) +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_SCAN BIT(0) +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x3 << 16) + #define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) @@ -33,6 +46,41 @@ #define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) #define ANA_PGID(x) (0x8c00 + 4 * (x)) +#define HSIO_ANA_SERDES1G_DES_CFG 0x4c +#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1) +#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5) +#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_IB_CFG 0x50 +#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13) +#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24) +#define HSIO_ANA_SERDES1G_OB_CFG 0x54 +#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4) +#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10) +#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17) +#define HSIO_ANA_SERDES1G_SER_CFG 0x58 +#define HSIO_ANA_SERDES1G_COMMON_CFG 0x5c +#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0) +#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18) +#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31) +#define HSIO_ANA_SERDES1G_PLL_CFG 0x60 +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7) +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21) +#define HSIO_DIG_SERDES1G_DFT_CFG0 0x68 +#define HSIO_DIG_SERDES1G_MISC_CFG 0x7c +#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0) +#define HSIO_MCB_SERDES1G_CFG 0x88 +#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31) +#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x) +#define HSIO_HW_CFGSTAT_HW_CFG 0x10c + #define SYS_FRM_AGING 0x574 #define SYS_FRM_AGING_ENA BIT(20) @@ -83,49 +131,58 @@ #define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) #define IFH_INJ_BYPASS BIT(31) -#define IFH_TAG_TYPE_C 0 -#define MAC_VID 1 +#define IFH_TAG_TYPE_C 0 +#define MAC_VID 1 #define CPU_PORT 11 -#define INTERNAL_PORT_MSK 0xF +#define INTERNAL_PORT_MSK 0x2FF #define IFH_LEN 4 #define ETH_ALEN 6 -#define PGID_BROADCAST 13 -#define PGID_UNICAST 14 -#define PGID_SRC 80 +#define PGID_BROADCAST 13 +#define PGID_UNICAST 14 +#define PGID_SRC 80 -enum ocelot_target { - ANA, - QS, - QSYS, +static const char * const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7", + "port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 11 + +enum ocelot_ctrl_regs { + SYS = MAX_PORT, REW, - SYS, + QS, HSIO, - PORT0, - PORT1, - PORT2, - PORT3, - TARGET_MAX, + QSYS, + ANA, }; -#define MAX_PORT (PORT3 - PORT0) +#define OCELOT_MIIM_BUS_COUNT 2 -enum ocelot_mdio_target { - MIIM, - PHY, - TARGET_MDIO_MAX, +struct ocelot_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; }; -enum ocelot_phy_id { - INTERNAL, - EXTERNAL, - NUM_PHY, +struct ocelot_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT]; + struct ocelot_phy_port_t ports[MAX_PORT]; }; -struct ocelot_private { - void __iomem *regs[TARGET_MAX]; - struct mii_dev *bus[NUM_PHY]; +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; }; +static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT]; +static int miim_count = -1; + static const unsigned long ocelot_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_FLUSH] = 0x18, @@ -140,65 +197,95 @@ static const unsigned long ocelot_regs_ana_table[] = { [MSCC_ANA_TABLES_MACACCESS] = 0x8b3c, }; -static struct mscc_miim_dev miim[NUM_PHY]; - static void mscc_phy_reset(void) { - writel(0, miim[INTERNAL].phy_regs + PHY_CFG); + writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG); writel(PHY_CFG_RST | PHY_CFG_COMMON_RST - | PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG); - if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT, - PHY_STAT_SUPERVISOR_COMPLETE, + | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG); + if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) + + PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE, true, 2000, false)) { pr_err("Timeout in phy reset\n"); } } -/* For now only setup the internal mdio bus */ -static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev) +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) { - unsigned long phy_size[TARGET_MAX]; - phys_addr_t phy_base[TARGET_MAX]; - struct ofnode_phandle_args phandle; - ofnode eth_node, node, mdio_node; - struct resource res; struct mii_dev *bus; - fdt32_t faddr; - int i; bus = mdio_alloc(); if (!bus) return NULL; - /* gathered only the first mdio bus */ - eth_node = dev_read_first_subnode(dev); - node = ofnode_first_subnode(eth_node); - ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, - &phandle); - mdio_node = ofnode_get_parent(phandle.node); - - for (i = 0; i < TARGET_MDIO_MAX; i++) { - if (ofnode_read_resource(mdio_node, i, &res)) { - pr_err("%s: get OF resource failed\n", __func__); - return NULL; - } - faddr = cpu_to_fdt32(res.start); - phy_base[i] = ofnode_translate_address(mdio_node, &faddr); - phy_size[i] = res.end - res.start; - } + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); - strcpy(bus->name, "miim-internal"); - miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]); - miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]); - bus->priv = &miim[INTERNAL]; + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; bus->read = mscc_miim_read; bus->write = mscc_miim_write; if (mdio_register(bus)) return NULL; - else - return bus; + + miim[miim_count].bus = bus; + return bus; } __weak void mscc_switch_reset(void) @@ -291,13 +378,87 @@ static void ocelot_port_init(struct ocelot_private *priv, int port) /* Make VLAN aware for CPU traffic */ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | - MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable the port in the core */ - setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port), QSYS_SWITCH_PORT_MODE_PORT_ENA); } +static void serdes1g_write(void __iomem *base, u32 addr) +{ + u32 data; + + writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT | + HSIO_MCB_SERDES1G_CFG_ADDR(addr), + base + HSIO_MCB_SERDES1G_CFG); + + do { + data = readl(base + HSIO_MCB_SERDES1G_CFG); + } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT); +} + +static void serdes1g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) +{ + writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG); + + writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG); + writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0); + writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) | + HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) | + HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP | + HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM | + HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1), + base + HSIO_ANA_SERDES1G_IB_CFG); + writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) | + HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) | + HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) | + HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6), + base + HSIO_ANA_SERDES1G_DES_CFG); + writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) | + HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) | + HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) | + HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) | + HSIO_ANA_SERDES1G_OB_CFG_SLP(3), + base + HSIO_ANA_SERDES1G_OB_CFG); + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA | + HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) | + HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2, + base + HSIO_ANA_SERDES1G_PLL_CFG); + writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST, + base + HSIO_DIG_SERDES1G_MISC_CFG); + + serdes1g_write(base, addr); + + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE | + HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + serdes1g_write(base, addr); + + writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes1g_write(base, addr); +} + +static void serdes_setup(struct ocelot_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes1g_setup(priv->regs[HSIO], mask, + priv->ports[i].phy_mode); + } +} + static int ocelot_switch_init(struct ocelot_private *priv) { /* Reset switch & memories */ @@ -315,6 +476,7 @@ static int ocelot_switch_init(struct ocelot_private *priv) setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, SYS_SYSTEM_RST_CORE_ENA); + serdes_setup(priv); return 0; } @@ -331,7 +493,7 @@ static int ocelot_initialize(struct ocelot_private *priv) * Put fron ports in "port isolation modes" - i.e. they cant send * to other ports - via the PGID sorce masks. */ - for (i = 0; i <= MAX_PORT; i++) + for (i = 0; i < MAX_PORT; i++) writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i)); /* Flush queues */ @@ -341,7 +503,7 @@ static int ocelot_initialize(struct ocelot_private *priv) writel(SYS_FRM_AGING_ENA | (20000000 / 65), priv->regs[SYS] + SYS_FRM_AGING); - for (i = PORT0; i <= PORT3; i++) + for (i = 0; i < MAX_PORT; i++) ocelot_port_init(priv, i); ocelot_cpu_capture_setup(priv); @@ -433,43 +595,119 @@ static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp) return byte_cnt; } +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct ocelot_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + +static int external_bus(struct ocelot_private *priv, size_t port_index) +{ + return priv->ports[port_index].serdes_index != 0xff; +} + static int ocelot_probe(struct udevice *dev) { struct ocelot_private *priv = dev_get_priv(dev); - int ret, i; + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; + + if (!priv) + return -EINVAL; - struct { - enum ocelot_target id; - char *name; - } reg[] = { - { SYS, "sys" }, - { REW, "rew" }, - { QSYS, "qsys" }, - { ANA, "ana" }, - { QS, "qs" }, - { HSIO, "hsio" }, - { PORT0, "port0" }, - { PORT1, "port1" }, - { PORT2, "port2" }, - { PORT3, "port3" }, - }; - - for (i = 0; i < ARRAY_SIZE(reg); i++) { - priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); - if (!priv->regs[reg[i].id]) { - pr_err - ("Error %d: can't get regs base addresses for %s\n", - ret, reg[i].name); + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { + debug + ("Error can't get regs base addresses for %s\n", + regs_names[i]); return -ENOMEM; } } - priv->bus[INTERNAL] = ocelot_mdiobus_init(dev); + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(struct mscc_miim_dev) * + OCELOT_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, + &phandle); + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + ocelot_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff); + else + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + mscc_phy_reset(); - for (i = 0; i < 4; i++) { - phy_connect(priv->bus[INTERNAL], i, dev, - PHY_INTERFACE_MODE_NONE); + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy && external_bus(priv, i)) + board_phy_config(phy); } return 0; @@ -480,7 +718,7 @@ static int ocelot_remove(struct udevice *dev) struct ocelot_private *priv = dev_get_priv(dev); int i; - for (i = 0; i < NUM_PHY; i++) { + for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) { mdio_unregister(priv->bus[i]); mdio_free(priv->bus[i]); } diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c new file mode 100644 index 00000000000..2559f5d0cd1 --- /dev/null +++ b/drivers/net/mscc_eswitch/serval_switch.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Microsemi Corporation + */ + +#include <common.h> +#include <config.h> +#include <dm.h> +#include <dm/of_access.h> +#include <dm/of_addr.h> +#include <fdt_support.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <miiphy.h> +#include <net.h> +#include <wait_bit.h> + +#include "mscc_xfer.h" +#include "mscc_mac_table.h" + +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x2 << 16) + +#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x)) +#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) +#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) +#define ANA_PORT_PORT_CFG(x) (0xc070 + 0x100 * (x)) +#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) +#define ANA_PGID(x) (0x9c00 + 4 * (x)) + +#define HSIO_ANA_SERDES1G_DES_CFG 0x3c +#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1) +#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5) +#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_IB_CFG 0x40 +#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13) +#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19) +#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24) +#define HSIO_ANA_SERDES1G_OB_CFG 0x44 +#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4) +#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10) +#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17) +#define HSIO_ANA_SERDES1G_SER_CFG 0x48 +#define HSIO_ANA_SERDES1G_COMMON_CFG 0x4c +#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0) +#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18) +#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31) +#define HSIO_ANA_SERDES1G_PLL_CFG 0x50 +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7) +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21) +#define HSIO_DIG_SERDES1G_DFT_CFG0 0x58 +#define HSIO_DIG_SERDES1G_MISC_CFG 0x6c +#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0) +#define HSIO_MCB_SERDES1G_CFG 0x74 +#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31) +#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x) + +#define SYS_FRM_AGING 0x584 +#define SYS_FRM_AGING_ENA BIT(20) +#define SYS_SYSTEM_RST_CFG 0x518 +#define SYS_SYSTEM_RST_MEM_INIT BIT(5) +#define SYS_SYSTEM_RST_MEM_ENA BIT(6) +#define SYS_SYSTEM_RST_CORE_ENA BIT(7) +#define SYS_PORT_MODE(x) (0x524 + 0x4 * (x)) +#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 4) +#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 2) +#define SYS_PAUSE_CFG(x) (0x65c + 0x4 * (x)) +#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0) + +#define QSYS_SWITCH_PORT_MODE(x) (0x15a34 + 0x4 * (x)) +#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(13) +#define QSYS_EGR_NO_SHARING 0x15a9c +#define QSYS_QMAP 0x15adc + +/* Port registers */ +#define DEV_CLOCK_CFG 0x0 +#define DEV_CLOCK_CFG_LINK_SPEED_1000 1 +#define DEV_MAC_ENA_CFG 0x10 +#define DEV_MAC_ENA_CFG_RX_ENA BIT(4) +#define DEV_MAC_ENA_CFG_TX_ENA BIT(0) +#define DEV_MAC_IFG_CFG 0x24 +#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8) +#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4) +#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x) +#define PCS1G_CFG 0x3c +#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0) +#define PCS1G_MODE_CFG 0x40 +#define PCS1G_SD_CFG 0x44 +#define PCS1G_ANEG_CFG 0x48 +#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16) + +#define QS_XTR_GRP_CFG(x) (4 * (x)) +#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2) +#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0) +#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4) +#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2) +#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) + +#define IFH_INJ_BYPASS BIT(31) +#define IFH_TAG_TYPE_C 0 +#define MAC_VID 1 +#define CPU_PORT 11 +#define INTERNAL_PORT_MSK 0xFF +#define IFH_LEN 4 +#define ETH_ALEN 6 +#define PGID_BROADCAST 13 +#define PGID_UNICAST 14 + +static const char *const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", + "port7", "port8", "port9", "port10", + "ana", "qs", "qsys", "rew", "sys", "hsio", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 11 + +enum serval_ctrl_regs { + ANA = MAX_PORT, + QS, + QSYS, + REW, + SYS, + HSIO, +}; + +#define SERVAL_MIIM_BUS_COUNT 2 + +struct serval_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; +}; + +struct serval_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT]; + struct serval_phy_port_t ports[MAX_PORT]; +}; + +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; +}; + +static const unsigned long serval_regs_qs[] = { + [MSCC_QS_XTR_RD] = 0x8, + [MSCC_QS_XTR_FLUSH] = 0x18, + [MSCC_QS_XTR_DATA_PRESENT] = 0x1c, + [MSCC_QS_INJ_WR] = 0x2c, + [MSCC_QS_INJ_CTRL] = 0x34, +}; + +static const unsigned long serval_regs_ana_table[] = { + [MSCC_ANA_TABLES_MACHDATA] = 0x9b34, + [MSCC_ANA_TABLES_MACLDATA] = 0x9b38, + [MSCC_ANA_TABLES_MACACCESS] = 0x9b3c, +}; + +static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT]; +static int miim_count = -1; + +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) +{ + struct mii_dev *bus; + + bus = mdio_alloc(); + if (!bus) + return NULL; + + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); + + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; + bus->read = mscc_miim_read; + bus->write = mscc_miim_write; + + if (mdio_register(bus)) + return NULL; + + miim[miim_count].bus = bus; + return bus; +} + +static void serval_cpu_capture_setup(struct serval_private *priv) +{ + int i; + + /* map the 8 CPU extraction queues to CPU port 11 */ + writel(0, priv->regs[QSYS] + QSYS_QMAP); + + for (i = 0; i <= 1; i++) { + /* + * Do byte-swap and expect status after last data word + * Extraction: Mode: manual extraction) | Byte_swap + */ + writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP, + priv->regs[QS] + QS_XTR_GRP_CFG(i)); + /* + * Injection: Mode: manual extraction | Byte_swap + */ + writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP, + priv->regs[QS] + QS_INJ_GRP_CFG(i)); + } + + for (i = 0; i <= 1; i++) + /* Enable IFH insertion/parsing on CPU ports */ + writel(SYS_PORT_MODE_INCL_INJ_HDR(1) | + SYS_PORT_MODE_INCL_XTR_HDR(1), + priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i)); + /* + * Setup the CPU port as VLAN aware to support switching frames + * based on tags + */ + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT)); + + /* Disable learning (only RECV_ENA must be set) */ + writel(ANA_PORT_PORT_CFG_RECV_ENA, + priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT)); + + /* Enable switching to/from cpu port */ + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT), + QSYS_SWITCH_PORT_MODE_PORT_ENA); + + /* No pause on CPU port - not needed (off by default) */ + clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT), + SYS_PAUSE_CFG_PAUSE_ENA); + + setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT)); +} + +static void serval_port_init(struct serval_private *priv, int port) +{ + void __iomem *regs = priv->regs[port]; + + /* Enable PCS */ + writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG); + + /* Disable Signal Detect */ + writel(0, regs + PCS1G_SD_CFG); + + /* Enable MAC RX and TX */ + writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, + regs + DEV_MAC_ENA_CFG); + + /* Clear sgmii_mode_ena */ + writel(0, regs + PCS1G_MODE_CFG); + + /* + * Clear sw_resolve_ena(bit 0) and set adv_ability to + * something meaningful just in case + */ + writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG); + + /* Set MAC IFG Gaps */ + writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) | + DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG); + + /* Set link speed and release all resets */ + writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG); + + /* Make VLAN aware for CPU traffic */ + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); + + /* Enable the port in the core */ + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port), + QSYS_SWITCH_PORT_MODE_PORT_ENA); +} + +static void serdes_write(void __iomem *base, u32 addr) +{ + u32 data; + + writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT | + HSIO_MCB_SERDES1G_CFG_ADDR(addr), + base + HSIO_MCB_SERDES1G_CFG); + + do { + data = readl(base + HSIO_MCB_SERDES1G_CFG); + } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT); + + mdelay(100); +} + +static void serdes1g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) +{ + writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG); + writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0); + writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) | + HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) | + HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP | + HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM | + HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1), + base + HSIO_ANA_SERDES1G_IB_CFG); + writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) | + HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) | + HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) | + HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6), + base + HSIO_ANA_SERDES1G_DES_CFG); + writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) | + HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) | + HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) | + HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) | + HSIO_ANA_SERDES1G_OB_CFG_SLP(3), + base + HSIO_ANA_SERDES1G_OB_CFG); + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA | + HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) | + HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2, + base + HSIO_ANA_SERDES1G_PLL_CFG); + writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST, + base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes_write(base, addr); + + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE | + HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + serdes_write(base, addr); + + writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes_write(base, addr); +} + +static void serdes_setup(struct serval_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes1g_setup(priv->regs[HSIO], mask, + priv->ports[i].phy_mode); + } +} + +static int serval_switch_init(struct serval_private *priv) +{ + /* Reset switch & memories */ + writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT, + priv->regs[SYS] + SYS_SYSTEM_RST_CFG); + + if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, + SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) { + pr_err("Timeout in memory reset\n"); + return -EIO; + } + + /* Enable switch core */ + setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, + SYS_SYSTEM_RST_CORE_ENA); + + serdes_setup(priv); + + return 0; +} + +static int serval_initialize(struct serval_private *priv) +{ + int ret, i; + + /* Initialize switch memories, enable core */ + ret = serval_switch_init(priv); + if (ret) + return ret; + + /* Flush queues */ + mscc_flush(priv->regs[QS], serval_regs_qs); + + /* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */ + writel(SYS_FRM_AGING_ENA | (20000000 / 65), + priv->regs[SYS] + SYS_FRM_AGING); + + for (i = 0; i < MAX_PORT; i++) + serval_port_init(priv, i); + + serval_cpu_capture_setup(priv); + + debug("Ports enabled\n"); + + return 0; +} + +static int serval_write_hwaddr(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, + pdata->enetaddr, PGID_UNICAST); + + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); + + return 0; +} + +static int serval_start(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff }; + int ret; + + ret = serval_initialize(priv); + if (ret) + return ret; + + /* Set MAC address tables entries for CPU redirection */ + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac, + PGID_BROADCAST); + + writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK, + priv->regs[ANA] + ANA_PGID(PGID_BROADCAST)); + + /* It should be setup latter in serval_write_hwaddr */ + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, + pdata->enetaddr, PGID_UNICAST); + + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); + return 0; +} + +static void serval_stop(struct udevice *dev) +{ + writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET); + writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST); +} + +static int serval_send(struct udevice *dev, void *packet, int length) +{ + struct serval_private *priv = dev_get_priv(dev); + u32 ifh[IFH_LEN]; + u32 *buf = packet; + + /* + * Generate the IFH for frame injection + * + * The IFH is a 128bit-value + * bit 127: bypass the analyzer processing + * bit 57-67: destination mask + * bit 28-29: pop_cnt: 3 disables all rewriting of the frame + * bit 20-27: cpu extraction queue mask + * bit 16: tag type 0: C-tag, 1: S-tag + * bit 0-11: VID + */ + ifh[0] = IFH_INJ_BYPASS; + ifh[1] = (0x07); + ifh[2] = (0x7f) << 25; + ifh[3] = (IFH_TAG_TYPE_C << 16); + + return mscc_send(priv->regs[QS], serval_regs_qs, + ifh, IFH_LEN, buf, length); +} + +static int serval_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct serval_private *priv = dev_get_priv(dev); + u32 *rxbuf = (u32 *)net_rx_packets[0]; + int byte_cnt = 0; + + byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN, + false); + + *packetp = net_rx_packets[0]; + + return byte_cnt; +} + +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct serval_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + +static int serval_probe(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; + + if (!priv) + return -EINVAL; + + /* Get registers and map them to the private structure */ + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { + debug + ("Error can't get regs base addresses for %s\n", + regs_names[i]); + return -ENOMEM; + } + } + + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL, + 0, 0, &phandle); + if (ret) + continue; + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + serval_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + return -ENOMEM; + + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy) + board_phy_config(phy); + } + + return 0; +} + +static int serval_remove(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) { + mdio_unregister(priv->bus[i]); + mdio_free(priv->bus[i]); + } + + return 0; +} + +static const struct eth_ops serval_ops = { + .start = serval_start, + .stop = serval_stop, + .send = serval_send, + .recv = serval_recv, + .write_hwaddr = serval_write_hwaddr, +}; + +static const struct udevice_id mscc_serval_ids[] = { + {.compatible = "mscc,vsc7418-switch"}, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(serval) = { + .name = "serval-switch", + .id = UCLASS_ETH, + .of_match = mscc_serval_ids, + .probe = serval_probe, + .remove = serval_remove, + .ops = &serval_ops, + .priv_auto_alloc_size = sizeof(struct serval_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c index bb879d8d4fe..9d539849739 100644 --- a/drivers/net/ti/davinci_emac.c +++ b/drivers/net/ti/davinci_emac.c @@ -816,55 +816,12 @@ int davinci_emac_initialize(void) phy_id |= tmp & 0x0000ffff; - switch (phy_id) { -#ifdef PHY_KSZ8873 - case PHY_KSZ8873: - sprintf(phy[i].name, "KSZ8873 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = ksz8873_init_phy; - phy[i].is_phy_connected = ksz8873_is_phy_connected; - phy[i].get_link_speed = ksz8873_get_link_speed; - phy[i].auto_negotiate = ksz8873_auto_negotiate; - break; -#endif -#ifdef PHY_LXT972 - case PHY_LXT972: - sprintf(phy[i].name, "LXT972 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = lxt972_init_phy; - phy[i].is_phy_connected = lxt972_is_phy_connected; - phy[i].get_link_speed = lxt972_get_link_speed; - phy[i].auto_negotiate = lxt972_auto_negotiate; - break; -#endif -#ifdef PHY_DP83848 - case PHY_DP83848: - sprintf(phy[i].name, "DP83848 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = dp83848_init_phy; - phy[i].is_phy_connected = dp83848_is_phy_connected; - phy[i].get_link_speed = dp83848_get_link_speed; - phy[i].auto_negotiate = dp83848_auto_negotiate; - break; -#endif -#ifdef PHY_ET1011C - case PHY_ET1011C: - sprintf(phy[i].name, "ET1011C @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = et1011c_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - break; -#endif - default: - sprintf(phy[i].name, "GENERIC @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = gen_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - } + sprintf(phy[i].name, "GENERIC @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = gen_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; debug("Ethernet PHY: %s\n", phy[i].name); diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 0e6c559d5ef..f01bc77a576 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -116,6 +116,9 @@ static int pinconfig_post_bind(struct udevice *dev) ofnode node; int ret; + if (!dev_of_valid(dev)) + return 0; + dev_for_each_subnode(node, dev) { if (pre_reloc_only && !ofnode_pre_reloc(node)) diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c index 9994cbafbff..88db294cf14 100644 --- a/drivers/pwm/rk_pwm.c +++ b/drivers/pwm/rk_pwm.c @@ -12,7 +12,7 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/pwm.h> +#include <asm/arch-rockchip/pwm.h> #include <power/regulator.h> struct rk_pwm_priv { diff --git a/drivers/ram/rockchip/dmc-rk3368.c b/drivers/ram/rockchip/dmc-rk3368.c index 8d1b9faacc0..92f584fadcb 100644 --- a/drivers/ram/rockchip/dmc-rk3368.c +++ b/drivers/ram/rockchip/dmc-rk3368.c @@ -12,12 +12,12 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3368.h> -#include <asm/arch/grf_rk3368.h> -#include <asm/arch/ddr_rk3368.h> -#include <asm/arch/sdram.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3368.h> +#include <asm/arch-rockchip/grf_rk3368.h> +#include <asm/arch-rockchip/ddr_rk3368.h> +#include <asm/arch-rockchip/sdram.h> +#include <asm/arch-rockchip/sdram_common.h> struct dram_info { struct ram_info info; diff --git a/drivers/ram/rockchip/sdram_rk3128.c b/drivers/ram/rockchip/sdram_rk3128.c index df7b9887033..bfabc22a7d8 100644 --- a/drivers/ram/rockchip/sdram_rk3128.c +++ b/drivers/ram/rockchip/sdram_rk3128.c @@ -7,9 +7,9 @@ #include <dm.h> #include <ram.h> #include <syscon.h> -#include <asm/arch/clock.h> -#include <asm/arch/grf_rk3128.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/grf_rk3128.h> +#include <asm/arch-rockchip/sdram_common.h> struct dram_info { struct ram_info info; diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c index fdd500aa472..00e52ec949e 100644 --- a/drivers/ram/rockchip/sdram_rk3188.c +++ b/drivers/ram/rockchip/sdram_rk3188.c @@ -15,13 +15,13 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3188.h> -#include <asm/arch/ddr_rk3188.h> -#include <asm/arch/grf_rk3188.h> -#include <asm/arch/pmu_rk3188.h> -#include <asm/arch/sdram.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3188.h> +#include <asm/arch-rockchip/ddr_rk3188.h> +#include <asm/arch-rockchip/grf_rk3188.h> +#include <asm/arch-rockchip/pmu_rk3188.h> +#include <asm/arch-rockchip/sdram.h> +#include <asm/arch-rockchip/sdram_common.h> #include <linux/err.h> struct chan_info { diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c index 53835a9cd08..c596523d4ff 100644 --- a/drivers/ram/rockchip/sdram_rk322x.c +++ b/drivers/ram/rockchip/sdram_rk322x.c @@ -11,14 +11,14 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk322x.h> -#include <asm/arch/grf_rk322x.h> -#include <asm/arch/hardware.h> -#include <asm/arch/sdram_rk322x.h> -#include <asm/arch/timer.h> -#include <asm/arch/uart.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk322x.h> +#include <asm/arch-rockchip/grf_rk322x.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/sdram_rk322x.h> +#include <asm/arch-rockchip/timer.h> +#include <asm/arch-rockchip/uart.h> +#include <asm/arch-rockchip/sdram_common.h> #include <asm/types.h> #include <linux/err.h> diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c index d1e52d84e7a..6bb025a851a 100644 --- a/drivers/ram/rockchip/sdram_rk3288.c +++ b/drivers/ram/rockchip/sdram_rk3288.c @@ -15,13 +15,13 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/ddr_rk3288.h> -#include <asm/arch/grf_rk3288.h> -#include <asm/arch/pmu_rk3288.h> -#include <asm/arch/sdram.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3288.h> +#include <asm/arch-rockchip/ddr_rk3288.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/pmu_rk3288.h> +#include <asm/arch-rockchip/sdram.h> +#include <asm/arch-rockchip/sdram_common.h> #include <linux/err.h> #include <power/regulator.h> #include <power/rk8xx_pmic.h> diff --git a/drivers/ram/rockchip/sdram_rk3328.c b/drivers/ram/rockchip/sdram_rk3328.c index e8b234d8665..f4e0b184470 100644 --- a/drivers/ram/rockchip/sdram_rk3328.c +++ b/drivers/ram/rockchip/sdram_rk3328.c @@ -7,9 +7,9 @@ #include <dm.h> #include <ram.h> #include <syscon.h> -#include <asm/arch/clock.h> -#include <asm/arch/grf_rk3328.h> -#include <asm/arch/sdram_common.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/grf_rk3328.h> +#include <asm/arch-rockchip/sdram_common.h> struct dram_info { struct ram_info info; diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 94dd01156a7..05ec5fc28d7 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -13,12 +13,12 @@ #include <regmap.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/sdram_common.h> -#include <asm/arch/sdram_rk3399.h> -#include <asm/arch/cru_rk3399.h> -#include <asm/arch/grf_rk3399.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/sdram_common.h> +#include <asm/arch-rockchip/sdram_rk3399.h> +#include <asm/arch-rockchip/cru_rk3399.h> +#include <asm/arch-rockchip/grf_rk3399.h> +#include <asm/arch-rockchip/hardware.h> #include <linux/err.h> #include <time.h> diff --git a/drivers/reset/reset-rockchip.c b/drivers/reset/reset-rockchip.c index af071340495..3871fc00d07 100644 --- a/drivers/reset/reset-rockchip.c +++ b/drivers/reset/reset-rockchip.c @@ -7,7 +7,7 @@ #include <dm.h> #include <reset-uclass.h> #include <linux/io.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> /* * Each reg has 16 bits reset signal for devices diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c index 35fefd74c69..b1718f72d1b 100644 --- a/drivers/serial/serial_rockchip.c +++ b/drivers/serial/serial_rockchip.c @@ -9,7 +9,7 @@ #include <dt-structs.h> #include <ns16550.h> #include <serial.h> -#include <asm/arch/clock.h> +#include <asm/arch-rockchip/clock.h> #if defined(CONFIG_ROCKCHIP_RK3188) struct rockchip_uart_platdata { diff --git a/drivers/sound/rockchip_sound.c b/drivers/sound/rockchip_sound.c index e7fb9fb1646..a092dbc4458 100644 --- a/drivers/sound/rockchip_sound.c +++ b/drivers/sound/rockchip_sound.c @@ -13,7 +13,7 @@ #include <i2s.h> #include <misc.h> #include <sound.h> -#include <asm/arch/periph.h> +#include <asm/arch-rockchip/periph.h> #include <dm/pinctrl.h> static int rockchip_sound_setup(struct udevice *dev) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index fb794adae72..2830f765877 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -133,7 +133,7 @@ config MPC8XX_SPI config MT7621_SPI bool "MediaTek MT7621 SPI driver" - depends on ARCH_MT7620 + depends on SOC_MT7628 help Enable the MT7621 SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Ralink / MediaTek diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 14437c0a9af..a68553b75bf 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -2,6 +2,8 @@ /* * spi driver for rockchip * + * (C) 2019 Theobroma Systems Design und Consulting GmbH + * * (C) Copyright 2015 Google, Inc * * (C) Copyright 2008-2013 Rockchip Electronics @@ -16,14 +18,19 @@ #include <spi.h> #include <linux/errno.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/periph.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/periph.h> #include <dm/pinctrl.h> #include "rk_spi.h" /* Change to 1 to output registers at the start of each transaction */ #define DEBUG_RK_SPI 0 +struct rockchip_spi_params { + /* RXFIFO overruns and TXFIFO underruns stop the master clock */ + bool master_manages_fifo; +}; + struct rockchip_spi_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) struct dtd_rockchip_rk3288_spi of_plat; @@ -40,11 +47,8 @@ struct rockchip_spi_priv { unsigned int max_freq; unsigned int mode; ulong last_transaction_us; /* Time of last transaction end */ - u8 bits_per_word; /* max 16 bits per word */ - u8 n_bytes; unsigned int speed_hz; unsigned int last_speed_hz; - unsigned int tmode; uint input_rate; }; @@ -130,8 +134,13 @@ static void spi_cs_activate(struct udevice *dev, uint cs) if (plat->deactivate_delay_us && priv->last_transaction_us) { ulong delay_us; /* The delay completed so far */ delay_us = timer_get_us() - priv->last_transaction_us; - if (delay_us < plat->deactivate_delay_us) - udelay(plat->deactivate_delay_us - delay_us); + if (delay_us < plat->deactivate_delay_us) { + ulong additional_delay_us = + plat->deactivate_delay_us - delay_us; + debug("%s: delaying by %ld us\n", + __func__, additional_delay_us); + udelay(additional_delay_us); + } } debug("activate cs%u\n", cs); @@ -263,8 +272,6 @@ static int rockchip_spi_probe(struct udevice *bus) } priv->input_rate = ret; debug("%s: rate = %u\n", __func__, priv->input_rate); - priv->bits_per_word = 8; - priv->tmode = TMOD_TR; /* Tx & Rx */ return 0; } @@ -274,28 +281,10 @@ static int rockchip_spi_claim_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct rockchip_spi_priv *priv = dev_get_priv(bus); struct rockchip_spi *regs = priv->regs; - u8 spi_dfs, spi_tf; uint ctrlr0; /* Disable the SPI hardware */ - rkspi_enable_chip(regs, 0); - - switch (priv->bits_per_word) { - case 8: - priv->n_bytes = 1; - spi_dfs = DFS_8BIT; - spi_tf = HALF_WORD_OFF; - break; - case 16: - priv->n_bytes = 2; - spi_dfs = DFS_16BIT; - spi_tf = HALF_WORD_ON; - break; - default: - debug("%s: unsupported bits: %dbits\n", __func__, - priv->bits_per_word); - return -EPROTONOSUPPORT; - } + rkspi_enable_chip(regs, false); if (priv->speed_hz != priv->last_speed_hz) rkspi_set_clk(priv, priv->speed_hz); @@ -304,7 +293,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 = OMOD_MASTER << OMOD_SHIFT; /* Data Frame Size */ - ctrlr0 |= spi_dfs << DFS_SHIFT; + ctrlr0 |= DFS_8BIT << DFS_SHIFT; /* set SPI mode 0..3 */ if (priv->mode & SPI_CPOL) @@ -325,7 +314,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 |= FBM_MSB << FBM_SHIFT; /* Byte and Halfword Transform */ - ctrlr0 |= spi_tf << HALF_WORD_TX_SHIFT; + ctrlr0 |= HALF_WORD_OFF << HALF_WORD_TX_SHIFT; /* Rxd Sample Delay */ ctrlr0 |= 0 << RXDSD_SHIFT; @@ -334,7 +323,7 @@ static int rockchip_spi_claim_bus(struct udevice *dev) ctrlr0 |= FRF_SPI << FRF_SHIFT; /* Tx and Rx mode */ - ctrlr0 |= (priv->tmode & TMOD_MASK) << TMOD_SHIFT; + ctrlr0 |= TMOD_TR << TMOD_SHIFT; writel(ctrlr0, ®s->ctrlr0); @@ -351,6 +340,83 @@ static int rockchip_spi_release_bus(struct udevice *dev) return 0; } +static inline int rockchip_spi_16bit_reader(struct udevice *dev, + u8 **din, int *len) +{ + struct udevice *bus = dev->parent; + const struct rockchip_spi_params * const data = + (void *)dev_get_driver_data(bus); + struct rockchip_spi_priv *priv = dev_get_priv(bus); + struct rockchip_spi *regs = priv->regs; + const u32 saved_ctrlr0 = readl(®s->ctrlr0); +#if defined(DEBUG) + u32 statistics_rxlevels[33] = { }; +#endif + u32 frames = *len / 2; + u8 *in = (u8 *)(*din); + u32 max_chunk_size = SPI_FIFO_DEPTH; + + if (!frames) + return 0; + + /* + * If we know that the hardware will manage RXFIFO overruns + * (i.e. stop the SPI clock until there's space in the FIFO), + * we the allow largest possible chunk size that can be + * represented in CTRLR1. + */ + if (data && data->master_manages_fifo) + max_chunk_size = 0x10000; + + // rockchip_spi_configure(dev, mode, size) + rkspi_enable_chip(regs, false); + clrsetbits_le32(®s->ctrlr0, + TMOD_MASK << TMOD_SHIFT, + TMOD_RO << TMOD_SHIFT); + /* 16bit data frame size */ + clrsetbits_le32(®s->ctrlr0, DFS_MASK, DFS_16BIT); + + /* Update caller's context */ + const u32 bytes_to_process = 2 * frames; + *din += bytes_to_process; + *len -= bytes_to_process; + + /* Process our frames */ + while (frames) { + u32 chunk_size = min(frames, max_chunk_size); + + frames -= chunk_size; + + writew(chunk_size - 1, ®s->ctrlr1); + rkspi_enable_chip(regs, true); + + do { + u32 rx_level = readw(®s->rxflr); +#if defined(DEBUG) + statistics_rxlevels[rx_level]++; +#endif + chunk_size -= rx_level; + while (rx_level--) { + u16 val = readw(regs->rxdr); + *in++ = val & 0xff; + *in++ = val >> 8; + } + } while (chunk_size); + + rkspi_enable_chip(regs, false); + } + +#if defined(DEBUG) + debug("%s: observed rx_level during processing:\n", __func__); + for (int i = 0; i <= 32; ++i) + if (statistics_rxlevels[i]) + debug("\t%2d: %d\n", i, statistics_rxlevels[i]); +#endif + /* Restore the original transfer setup and return error-free. */ + writel(saved_ctrlr0, ®s->ctrlr0); + return 0; +} + static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -362,7 +428,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, const u8 *out = dout; u8 *in = din; int toread, towrite; - int ret; + int ret = 0; debug("%s: dout=%p, din=%p, len=%x, flags=%lx\n", __func__, dout, din, len, flags); @@ -373,8 +439,18 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) spi_cs_activate(dev, slave_plat->cs); + /* + * To ensure fast loading of firmware images (e.g. full U-Boot + * stage, ATF, Linux kernel) from SPI flash, we optimise the + * case of read-only transfers by using the full 16bits of each + * FIFO element. + */ + if (!out) + ret = rockchip_spi_16bit_reader(dev, &in, &len); + + /* This is the original 8bit reader/writer code */ while (len > 0) { - int todo = min(len, 0xffff); + int todo = min(len, 0x10000); rkspi_enable_chip(regs, false); writel(todo - 1, ®s->ctrlr1); @@ -397,9 +473,18 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, toread--; } } - ret = rkspi_wait_till_not_busy(regs); - if (ret) - break; + + /* + * In case that there's a transmit-component, we need to wait + * until the control goes idle before we can disable the SPI + * control logic (as this will implictly flush the FIFOs). + */ + if (out) { + ret = rkspi_wait_till_not_busy(regs); + if (ret) + break; + } + len -= todo; } @@ -446,10 +531,16 @@ static const struct dm_spi_ops rockchip_spi_ops = { */ }; +const struct rockchip_spi_params rk3399_spi_params = { + .master_manages_fifo = true, +}; + static const struct udevice_id rockchip_spi_ids[] = { { .compatible = "rockchip,rk3288-spi" }, - { .compatible = "rockchip,rk3368-spi" }, - { .compatible = "rockchip,rk3399-spi" }, + { .compatible = "rockchip,rk3368-spi", + .data = (ulong)&rk3399_spi_params }, + { .compatible = "rockchip,rk3399-spi", + .data = (ulong)&rk3399_spi_params }, { } }; diff --git a/drivers/sysreset/sysreset_rockchip.c b/drivers/sysreset/sysreset_rockchip.c index 93d7cfe463a..0fc6b683f2b 100644 --- a/drivers/sysreset/sysreset_rockchip.c +++ b/drivers/sysreset/sysreset_rockchip.c @@ -8,9 +8,9 @@ #include <errno.h> #include <sysreset.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3328.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3328.h> +#include <asm/arch-rockchip/hardware.h> #include <linux/err.h> int rockchip_sysreset_request(struct udevice *dev, enum sysreset_t type) diff --git a/drivers/timer/rockchip_timer.c b/drivers/timer/rockchip_timer.c index 69019740b0d..54956e557a1 100644 --- a/drivers/timer/rockchip_timer.c +++ b/drivers/timer/rockchip_timer.c @@ -7,7 +7,7 @@ #include <dm.h> #include <dm/ofnode.h> #include <mapmem.h> -#include <asm/arch/timer.h> +#include <asm/arch-rockchip/timer.h> #include <dt-structs.h> #include <timer.h> #include <asm/io.h> diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index e81eb164b0d..f3d24772cde 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -15,7 +15,7 @@ #include <linux/compiler.h> #include <version.h> #include <g_dnl.h> -#include <asm/arch/f_rockusb.h> +#include <asm/arch-rockchip/f_rockusb.h> static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) { diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1c2212f547b..b1188bcbf52 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -246,6 +246,11 @@ config USB_OHCI_GENERIC ---help--- Enables support for generic OHCI controller. +config USB_OHCI_DA8XX + bool "Support for da850 OHCI USB controller" + help + Enable support for the da850 USB controller. + endif # USB_OHCI_HCD config USB_UHCI_HCD diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 47ad3f34d5a..e8a495fde59 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -4,9 +4,54 @@ */ #include <common.h> - +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/ofnode.h> +#include <generic-phy.h> +#include <reset.h> +#include "ohci.h" #include <asm/arch/da8xx-usb.h> +struct da8xx_ohci { + ohci_t ohci; + struct clk *clocks; /* clock list */ + struct phy phy; + int clock_count; /* number of clock in clock list */ +}; + +static int usb_phy_on(void) +{ + unsigned long timeout; + + clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, + (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | + CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE | + CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX), + (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | + CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ | + CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM)); + + /* wait until the usb phy pll locks */ + timeout = get_timer(0); + while (get_timer(timeout) < 10) { + if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) + return 1; + } + + /* USB phy was not turned on */ + return 0; +} + +static void usb_phy_off(void) +{ + /* Power down the on-chip PHY. */ + clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, + CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM, + CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | + CFGCHIP2_RESET); +} + int usb_cpu_init(void) { /* enable psc for usb2.0 */ @@ -37,3 +82,94 @@ int usb_cpu_init_fail(void) { return usb_cpu_stop(); } + +#if CONFIG_IS_ENABLED(DM_USB) +static int ohci_da8xx_probe(struct udevice *dev) +{ + struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); + struct da8xx_ohci *priv = dev_get_priv(dev); + int i, err, ret, clock_nb; + + err = 0; + priv->clock_count = 0; + clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + if (err < 0) + break; + + err = clk_enable(&priv->clocks[i]); + if (err) { + dev_err(dev, "failed to enable clock %d\n", i); + clk_free(&priv->clocks[i]); + goto clk_err; + } + priv->clock_count++; + } + } else if (clock_nb != -ENOENT) { + dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb); + return clock_nb; + } + + err = usb_cpu_init(); + + if (err) + goto clk_err; + + err = ohci_register(dev, regs); + if (err) + goto phy_err; + + return 0; + +phy_err: + ret = usb_cpu_stop(); + if (ret) + dev_err(dev, "failed to shutdown usb phy\n"); + +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + dev_err(dev, "failed to disable all clocks\n"); + + return err; +} + +static int ohci_da8xx_remove(struct udevice *dev) +{ + struct da8xx_ohci *priv = dev_get_priv(dev); + int ret; + + ret = ohci_deregister(dev); + if (ret) + return ret; + + ret = usb_cpu_stop(); + if (ret) + return ret; + + return clk_release_all(priv->clocks, priv->clock_count); +} + +static const struct udevice_id da8xx_ohci_ids[] = { + { .compatible = "ti,da830-ohci" }, + { } +}; + +U_BOOT_DRIVER(ohci_generic) = { + .name = "ohci-da8xx", + .id = UCLASS_USB, + .of_match = da8xx_ohci_ids, + .probe = ohci_da8xx_probe, + .remove = ohci_da8xx_remove, + .ops = &ohci_usb_ops, + .priv_auto_alloc_size = sizeof(struct da8xx_ohci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 3b6f889f7b7..2b0df88f49e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1545,10 +1545,8 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, return -1; } -#if 0 mdelay(10); /* ohci_dump_status(ohci); */ -#endif timeout = USB_TIMEOUT_MS(pipe); diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 2ee0f23b7ed..1f2805270aa 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -327,9 +327,7 @@ static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) csr = readw(&musbr->txcsr); csr |= MUSB_CSR0_TXPKTRDY; -#if !defined(CONFIG_SOC_DM365) csr |= MUSB_CSR0_H_DIS_PING; -#endif writew(csr, &musbr->txcsr); result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); if (result < 0) @@ -352,9 +350,7 @@ static int ctrlreq_out_status_phase(struct usb_device *dev) /* Set the StatusPkt bit */ csr = readw(&musbr->txcsr); csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT); -#if !defined(CONFIG_SOC_DM365) csr |= MUSB_CSR0_H_DIS_PING; -#endif writew(csr, &musbr->txcsr); /* Wait until TXPKTRDY bit is cleared */ @@ -372,9 +368,7 @@ static int ctrlreq_in_status_phase(struct usb_device *dev) /* Set the StatusPkt bit and ReqPkt bit */ csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT; -#if !defined(CONFIG_SOC_DM365) csr |= MUSB_CSR0_H_DIS_PING; -#endif writew(csr, &musbr->txcsr); result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT); diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c index eb3692c3871..315d3adf275 100644 --- a/drivers/video/rockchip/rk3288_hdmi.c +++ b/drivers/video/rockchip/rk3288_hdmi.c @@ -13,9 +13,9 @@ #include <syscon.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/hardware.h> -#include <asm/arch/grf_rk3288.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/grf_rk3288.h> #include <power/regulator.h> #include "rk_hdmi.h" diff --git a/drivers/video/rockchip/rk3288_mipi.c b/drivers/video/rockchip/rk3288_mipi.c index d268b465148..7c4a4cc53b0 100644 --- a/drivers/video/rockchip/rk3288_mipi.c +++ b/drivers/video/rockchip/rk3288_mipi.c @@ -14,14 +14,14 @@ #include "rk_mipi.h" #include <syscon.h> #include <asm/gpio.h> -#include <asm/hardware.h> #include <asm/io.h> #include <dm/uclass-internal.h> #include <linux/kernel.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3288.h> -#include <asm/arch/grf_rk3288.h> -#include <asm/arch/rockchip_mipi_dsi.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3288.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/rockchip_mipi_dsi.h> #define MHz 1000000 diff --git a/drivers/video/rockchip/rk3288_vop.c b/drivers/video/rockchip/rk3288_vop.c index 7e953a628c1..0f91dab1f25 100644 --- a/drivers/video/rockchip/rk3288_vop.c +++ b/drivers/video/rockchip/rk3288_vop.c @@ -11,10 +11,10 @@ #include <regmap.h> #include <syscon.h> #include <video.h> -#include <asm/hardware.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/grf_rk3288.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/hardware.h> #include "rk_vop.h" DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/video/rockchip/rk3399_hdmi.c b/drivers/video/rockchip/rk3399_hdmi.c index b75efe6fc32..a62be983275 100644 --- a/drivers/video/rockchip/rk3399_hdmi.c +++ b/drivers/video/rockchip/rk3399_hdmi.c @@ -13,9 +13,9 @@ #include <syscon.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/hardware.h> -#include <asm/arch/grf_rk3399.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/grf_rk3399.h> #include <power/regulator.h> #include "rk_hdmi.h" diff --git a/drivers/video/rockchip/rk3399_mipi.c b/drivers/video/rockchip/rk3399_mipi.c index bb9007bf363..a93b73400be 100644 --- a/drivers/video/rockchip/rk3399_mipi.c +++ b/drivers/video/rockchip/rk3399_mipi.c @@ -14,14 +14,14 @@ #include "rk_mipi.h" #include <syscon.h> #include <asm/gpio.h> -#include <asm/hardware.h> #include <asm/io.h> #include <dm/uclass-internal.h> #include <linux/kernel.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3399.h> -#include <asm/arch/grf_rk3399.h> -#include <asm/arch/rockchip_mipi_dsi.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3399.h> +#include <asm/arch-rockchip/grf_rk3399.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/rockchip_mipi_dsi.h> /* Select mipi dsi source, big or little vop */ static int rk_mipi_dsi_source_select(struct udevice *dev) diff --git a/drivers/video/rockchip/rk3399_vop.c b/drivers/video/rockchip/rk3399_vop.c index 7a02221ae0b..81c122d7a9e 100644 --- a/drivers/video/rockchip/rk3399_vop.c +++ b/drivers/video/rockchip/rk3399_vop.c @@ -10,7 +10,7 @@ #include <dm.h> #include <regmap.h> #include <video.h> -#include <asm/hardware.h> +#include <asm/arch-rockchip/hardware.h> #include <asm/io.h> #include "rk_vop.h" diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c index e0741076324..4330725a251 100644 --- a/drivers/video/rockchip/rk_edp.c +++ b/drivers/video/rockchip/rk_edp.c @@ -14,9 +14,9 @@ #include <syscon.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/edp_rk3288.h> -#include <asm/arch/grf_rk3288.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/edp_rk3288.h> +#include <asm/arch-rockchip/grf_rk3288.h> #include <dt-bindings/clock/rk3288-cru.h> #define MAX_CR_LOOP 5 diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index 13d07ee3048..51931ceefae 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -14,10 +14,9 @@ #include <regmap.h> #include <syscon.h> #include <asm/gpio.h> -#include <asm/hardware.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> #include "rk_hdmi.h" #include "rk_vop.h" /* for rk_vop_probe_regulators */ diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c index f0a528c0d6d..cf5c0439b1a 100644 --- a/drivers/video/rockchip/rk_lvds.c +++ b/drivers/video/rockchip/rk_lvds.c @@ -12,9 +12,9 @@ #include <syscon.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/lvds_rk3288.h> -#include <asm/arch/grf_rk3288.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/lvds_rk3288.h> +#include <asm/arch-rockchip/grf_rk3288.h> #include <dt-bindings/clock/rk3288-cru.h> #include <dt-bindings/video/rk3288.h> diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c index 4f1a0f3a5f7..bcd039b7bc6 100644 --- a/drivers/video/rockchip/rk_mipi.c +++ b/drivers/video/rockchip/rk_mipi.c @@ -14,14 +14,13 @@ #include "rk_mipi.h" #include <syscon.h> #include <asm/gpio.h> -#include <asm/hardware.h> #include <asm/io.h> #include <dm/uclass-internal.h> #include <linux/kernel.h> -#include <asm/arch/clock.h> -#include <asm/arch/cru_rk3399.h> -#include <asm/arch/grf_rk3399.h> -#include <asm/arch/rockchip_mipi_dsi.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3399.h> +#include <asm/arch-rockchip/grf_rk3399.h> +#include <asm/arch-rockchip/rockchip_mipi_dsi.h> DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index faf4f24db04..b56c3f336c9 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -13,11 +13,10 @@ #include <syscon.h> #include <video.h> #include <asm/gpio.h> -#include <asm/hardware.h> #include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/edp_rk3288.h> -#include <asm/arch/vop_rk3288.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/edp_rk3288.h> +#include <asm/arch-rockchip/vop_rk3288.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> #include <power/regulator.h> diff --git a/drivers/video/rockchip/rk_vop.h b/drivers/video/rockchip/rk_vop.h index 828974d394f..8fa2f389390 100644 --- a/drivers/video/rockchip/rk_vop.h +++ b/drivers/video/rockchip/rk_vop.h @@ -6,7 +6,7 @@ #ifndef __RK_VOP_H__ #define __RK_VOP_H__ -#include <asm/arch/vop_rk3288.h> +#include <asm/arch-rockchip/vop_rk3288.h> struct rk_vop_priv { void *grf; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3bce0aa0b87..f909d40f455 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -55,7 +55,7 @@ config WDT help Enable driver model for watchdog timer. At the moment the API is very simple and only supports four operations: - start, restart, stop and reset (expire immediately). + start, stop, reset and expire_now (expire immediately). What exactly happens when the timer expires is up to a particular device/driver. @@ -143,7 +143,7 @@ config WDT_AT91 config WDT_MT7621 bool "MediaTek MT7621 watchdog timer support" - depends on WDT && ARCH_MT7620 + depends on WDT && SOC_MT7628 help Select this to enable Ralink / Mediatek watchdog timer, which can be found on some MediaTek chips. |