diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/Kconfig | 33 | ||||
-rw-r--r-- | drivers/block/Makefile | 4 | ||||
-rw-r--r-- | drivers/block/blk-uclass.c | 6 | ||||
-rw-r--r-- | drivers/block/efi-media-uclass.c | 15 | ||||
-rw-r--r-- | drivers/block/efi_blk.c | 115 | ||||
-rw-r--r-- | drivers/block/sb_efi_media.c | 20 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 6 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/i2c-microchip.c | 482 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 22 | ||||
-rw-r--r-- | drivers/net/eth-phy-uclass.c | 2 | ||||
-rw-r--r-- | drivers/net/macb.c | 18 | ||||
-rw-r--r-- | drivers/net/ravb.c | 10 | ||||
-rw-r--r-- | drivers/pci/pci-aardvark.c | 54 | ||||
-rw-r--r-- | drivers/pci/pci_mvebu.c | 55 | ||||
-rw-r--r-- | drivers/serial/serial_mvebu_a3700.c | 13 | ||||
-rw-r--r-- | drivers/tpm/tpm2_tis_core.c | 6 | ||||
-rw-r--r-- | drivers/tpm/tpm2_tis_mmio.c | 5 |
18 files changed, 787 insertions, 80 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 56a4eec05a..8235430497 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -61,6 +61,39 @@ config TPL_BLOCK_CACHE help This option enables the disk-block cache in TPL +config EFI_MEDIA + bool "Support EFI media drivers" + default y if EFI || SANDBOX + help + Enable this to support media devices on top of UEFI. This enables + just the uclass so you also need a specific driver to make this do + anything. + + For sandbox there is a test driver. + +if EFI_MEDIA + +config EFI_MEDIA_SANDBOX + bool "Sandbox EFI media driver" + depends on SANDBOX + default y + help + Enables a simple sandbox media driver, used for testing just the + EFI_MEDIA uclass. It does not do anything useful, since sandbox does + not actually support running on top of UEFI. + +config EFI_MEDIA_BLK + bool "EFI media block driver" + depends on EFI_APP + default y + help + Enables a block driver for providing access to UEFI devices. This + allows use of block devices detected by the underlying UEFI + implementation. With this it is possible to use filesystems on these + devices, for example. + +endif # EFI_MEDIA + config IDE bool "Support IDE controllers" select HAVE_BLOCK_DEVICE diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 94ab5c6f90..b221a7c6ee 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -14,3 +14,7 @@ obj-$(CONFIG_IDE) += ide.o endif obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o + +obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o +obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o +obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 83682dcc18..4ae8af6d60 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -28,7 +28,8 @@ static const char *if_typename_str[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = "sata", [IF_TYPE_HOST] = "host", [IF_TYPE_NVME] = "nvme", - [IF_TYPE_EFI] = "efi", + [IF_TYPE_EFI_MEDIA] = "efi", + [IF_TYPE_EFI_LOADER] = "efiloader", [IF_TYPE_VIRTIO] = "virtio", [IF_TYPE_PVBLOCK] = "pvblock", }; @@ -44,7 +45,8 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_SATA] = UCLASS_AHCI, [IF_TYPE_HOST] = UCLASS_ROOT, [IF_TYPE_NVME] = UCLASS_NVME, - [IF_TYPE_EFI] = UCLASS_EFI, + [IF_TYPE_EFI_MEDIA] = UCLASS_EFI_MEDIA, + [IF_TYPE_EFI_LOADER] = UCLASS_EFI_LOADER, [IF_TYPE_VIRTIO] = UCLASS_VIRTIO, [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK, }; diff --git a/drivers/block/efi-media-uclass.c b/drivers/block/efi-media-uclass.c new file mode 100644 index 0000000000..e012f6f2f4 --- /dev/null +++ b/drivers/block/efi-media-uclass.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass for EFI media devices + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +UCLASS_DRIVER(efi_media) = { + .id = UCLASS_EFI_MEDIA, + .name = "efi_media", + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c new file mode 100644 index 0000000000..9d25ecbf37 --- /dev/null +++ b/drivers/block/efi_blk.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Block driver for EFI devices + * This supports a media driver of UCLASS_EFI with a child UCLASS_BLK + * It allows block-level access to EFI devices made available via EFI boot + * services + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <efi.h> +#include <efi_api.h> + +struct efi_block_plat { + struct efi_block_io *blkio; +}; + +/** + * Read from block device + * + * @dev: device + * @blknr: first block to be read + * @blkcnt: number of blocks to read + * @buffer: output buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->read_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/** + * Write to block device + * + * @dev: device + * @blknr: first block to be write + * @blkcnt: number of blocks to write + * @buffer: input buffer + * Return: number of blocks transferred + */ +static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer) +{ + struct efi_block_plat *plat = dev_get_plat(dev); + struct efi_block_io *io = plat->blkio; + efi_status_t ret; + + log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, + (ulong)blkcnt); + ret = io->write_blocks(io, io->media->media_id, blknr, + blkcnt * io->media->block_size, (void *)buffer); + log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, + ret & ~EFI_ERROR_MASK); + if (ret) + return 0; + + return blkcnt; +} + +/* Block device driver operators */ +static const struct blk_ops efi_blk_ops = { + .read = efi_bl_read, + .write = efi_bl_write, +}; + +U_BOOT_DRIVER(efi_block) = { + .name = "efi_block", + .id = UCLASS_BLK, + .ops = &efi_blk_ops, + .plat_auto = sizeof(struct efi_block_plat), +}; + +static int efi_media_bind(struct udevice *dev) +{ + struct efi_media_plat *plat = dev_get_plat(dev); + struct efi_block_plat *blk_plat; + struct udevice *blk; + int ret; + + ret = blk_create_devicef(dev, "efi_block", "blk", IF_TYPE_EFI_MEDIA, + dev_seq(dev), plat->blkio->media->block_size, + plat->blkio->media->last_block, &blk); + if (ret) { + debug("Cannot create block device\n"); + return ret; + } + blk_plat = dev_get_plat(blk); + blk_plat->blkio = plat->blkio; + + return 0; +} + +U_BOOT_DRIVER(efi_media) = { + .name = "efi_media", + .id = UCLASS_EFI_MEDIA, + .bind = efi_media_bind, + .plat_auto = sizeof(struct efi_media_plat), +}; diff --git a/drivers/block/sb_efi_media.c b/drivers/block/sb_efi_media.c new file mode 100644 index 0000000000..52af155a60 --- /dev/null +++ b/drivers/block/sb_efi_media.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI_MEDIA driver for sandbox + * + * Copyright 2021 Google LLC + */ + +#include <common.h> +#include <dm.h> + +static const struct udevice_id sandbox_efi_media_ids[] = { + { .compatible = "sandbox,efi-media" }, + { } +}; + +U_BOOT_DRIVER(sandbox_efi_media) = { + .name = "sandbox_efi_media", + .id = UCLASS_EFI_MEDIA, + .of_match = sandbox_efi_media_ids, +}; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 7c447a8aa0..5482a4a470 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -250,6 +250,12 @@ config SYS_I2C_MESON internal buffer holding up to 8 bytes for transfers and supports both 7-bit and 10-bit addresses. +config SYS_I2C_MICROCHIP + bool "Microchip I2C driver" + help + Add support for the Microchip I2C driver. This is operating on + standard mode up to 100 kbits/s and fast mode up to 400 kbits/s. + config SYS_I2C_MXC bool "NXP MXC I2C driver" help diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index fca6b157f8..9d41f379bb 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SYS_I2C_IPROC) += iproc_i2c.o obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o +obj-$(CONFIG_SYS_I2C_MICROCHIP) += i2c-microchip.o obj-$(CONFIG_SYS_I2C_MV) += mv_i2c.o obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o diff --git a/drivers/i2c/i2c-microchip.c b/drivers/i2c/i2c-microchip.c new file mode 100644 index 0000000000..12f65d0af7 --- /dev/null +++ b/drivers/i2c/i2c-microchip.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Microchip I2C controller driver + * + * Copyright (C) 2021 Microchip Technology Inc. + * Padmarao Begari <padmarao.begari@microchip.com> + */ +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <i2c.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> + +#define MICROCHIP_I2C_TIMEOUT (1000 * 60) + +#define MPFS_I2C_CTRL (0x00) +#define CTRL_CR0 (0x00) +#define CTRL_CR1 (0x01) +#define CTRL_AA BIT(2) +#define CTRL_SI BIT(3) +#define CTRL_STO BIT(4) +#define CTRL_STA BIT(5) +#define CTRL_ENS1 BIT(6) +#define CTRL_CR2 (0x07) +#define MPFS_I2C_STATUS (0x04) +#define STATUS_BUS_ERROR (0x00) +#define STATUS_M_START_SENT (0x08) +#define STATUS_M_REPEATED_START_SENT (0x10) +#define STATUS_M_SLAW_ACK (0x18) +#define STATUS_M_SLAW_NACK (0x20) +#define STATUS_M_TX_DATA_ACK (0x28) +#define STATUS_M_TX_DATA_NACK (0x30) +#define STATUS_M_ARB_LOST (0x38) +#define STATUS_M_SLAR_ACK (0x40) +#define STATUS_M_SLAR_NACK (0x48) +#define STATUS_M_RX_DATA_ACKED (0x50) +#define STATUS_M_RX_DATA_NACKED (0x58) +#define STATUS_S_SLAW_ACKED (0x60) +#define STATUS_S_ARB_LOST_SLAW_ACKED (0x68) +#define STATUS_S_GENERAL_CALL_ACKED (0x70) +#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED (0x78) +#define STATUS_S_RX_DATA_ACKED (0x80) +#define STATUS_S_RX_DATA_NACKED (0x88) +#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED (0x90) +#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED (0x98) +#define STATUS_S_RX_STOP (0xA0) +#define STATUS_S_SLAR_ACKED (0xA8) +#define STATUS_S_ARB_LOST_SLAR_ACKED (0xB0) +#define STATUS_S_TX_DATA_ACK (0xb8) +#define STATUS_S_TX_DATA_NACK (0xC0) +#define STATUS_LAST_DATA_ACK (0xC8) +#define STATUS_M_SMB_MASTER_RESET (0xD0) +#define STATUS_S_SCL_LOW_TIMEOUT (0xD8) +#define STATUS_NO_STATE_INFO (0xF8) +#define MPFS_I2C_DATA (0x08) +#define MPFS_I2C_SLAVE0_ADDR (0x0c) +#define MPFS_I2C_SMBUS (0x10) +#define MPFS_I2C_FREQ (0x14) +#define MPFS_I2C_GLITCHREG (0x18) +#define MPFS_I2C_SLAVE1_ADDR (0x1c) + +#define PCLK_DIV_256 ((0 << CTRL_CR0) | (0 << CTRL_CR1) | (0 << CTRL_CR2)) +#define PCLK_DIV_224 ((1 << CTRL_CR0) | (0 << CTRL_CR1) | (0 << CTRL_CR2)) +#define PCLK_DIV_192 ((0 << CTRL_CR0) | (1 << CTRL_CR1) | (0 << CTRL_CR2)) +#define PCLK_DIV_160 ((1 << CTRL_CR0) | (1 << CTRL_CR1) | (0 << CTRL_CR2)) +#define PCLK_DIV_960 ((0 << CTRL_CR0) | (0 << CTRL_CR1) | (1 << CTRL_CR2)) +#define PCLK_DIV_120 ((1 << CTRL_CR0) | (0 << CTRL_CR1) | (1 << CTRL_CR2)) +#define PCLK_DIV_60 ((0 << CTRL_CR0) | (1 << CTRL_CR1) | (1 << CTRL_CR2)) +#define BCLK_DIV_8 ((1 << CTRL_CR0) | (1 << CTRL_CR1) | (1 << CTRL_CR2)) +#define CLK_MASK ((1 << CTRL_CR0) | (1 << CTRL_CR1) | (1 << CTRL_CR2)) + +/* + * mpfs_i2c_bus - I2C bus context + * @base: pointer to register struct + * @msg_len: number of bytes transferred in msg + * @msg_err: error code for completed message + * @i2c_clk: clock reference for i2c input clock + * @clk_rate: current i2c bus clock rate + * @buf: ptr to msg buffer for easier use. + * @addr: i2c address. + * @isr_status: cached copy of local ISR status. + */ +struct mpfs_i2c_bus { + void __iomem *base; + size_t msg_len; + int msg_err; + struct clk i2c_clk; + u32 clk_rate; + u8 *buf; + u8 addr; + u32 isr_status; +}; + +static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg) +{ + return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0); +} + +static void mpfs_i2c_int_clear(struct mpfs_i2c_bus *bus) +{ + u8 ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl &= ~CTRL_SI; + writel(ctrl, bus->base + MPFS_I2C_CTRL); +} + +static void mpfs_i2c_core_disable(struct mpfs_i2c_bus *bus) +{ + u8 ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl &= ~CTRL_ENS1; + writel(ctrl, bus->base + MPFS_I2C_CTRL); +} + +static void mpfs_i2c_core_enable(struct mpfs_i2c_bus *bus) +{ + u8 ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl |= CTRL_ENS1; + writel(ctrl, bus->base + MPFS_I2C_CTRL); +} + +static void mpfs_i2c_reset(struct mpfs_i2c_bus *bus) +{ + mpfs_i2c_core_disable(bus); + mpfs_i2c_core_enable(bus); +} + +static inline void mpfs_i2c_stop(struct mpfs_i2c_bus *bus) +{ + u8 ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl |= CTRL_STO; + writel(ctrl, bus->base + MPFS_I2C_CTRL); +} + +static inline int mpfs_generate_divisor(u32 rate, u8 *code) +{ + int ret = 0; + + if (rate >= 960) + *code = PCLK_DIV_960; + else if (rate >= 256) + *code = PCLK_DIV_256; + else if (rate >= 224) + *code = PCLK_DIV_224; + else if (rate >= 192) + *code = PCLK_DIV_192; + else if (rate >= 160) + *code = PCLK_DIV_160; + else if (rate >= 120) + *code = PCLK_DIV_120; + else if (rate >= 60) + *code = PCLK_DIV_60; + else if (rate >= 8) + *code = BCLK_DIV_8; + else + ret = -EINVAL; + + return ret; +} + +static int mpfs_i2c_init(struct mpfs_i2c_bus *bus, struct udevice *dev) +{ + u32 clk_rate, divisor; + u8 clkval, ctrl; + int ret; + + ret = clk_get_by_index(dev, 0, &bus->i2c_clk); + if (ret) + return -EINVAL; + + ret = clk_enable(&bus->i2c_clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(&bus->i2c_clk); + if (!clk_rate) + return -EINVAL; + + clk_free(&bus->i2c_clk); + + divisor = clk_rate / bus->clk_rate; + + ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl &= ~CLK_MASK; + + ret = mpfs_generate_divisor(divisor, &clkval); + if (ret) + return -EINVAL; + + ctrl |= clkval; + + writel(ctrl, bus->base + MPFS_I2C_CTRL); + + ctrl = readl(bus->base + MPFS_I2C_CTRL); + + /* Reset I2C core */ + mpfs_i2c_reset(bus); + + return 0; +} + +static void mpfs_i2c_transfer(struct mpfs_i2c_bus *bus, u32 data) +{ + if (bus->msg_len > 0) + writel(data, bus->base + MPFS_I2C_DATA); +} + +static void mpfs_i2c_empty_rx(struct mpfs_i2c_bus *bus) +{ + u8 ctrl; + u8 data_read; + + if (bus->msg_len > 0) { + data_read = readl(bus->base + MPFS_I2C_DATA); + *bus->buf++ = data_read; + bus->msg_len--; + } + + if (bus->msg_len == 0) { + ctrl = readl(bus->base + MPFS_I2C_CTRL); + ctrl &= ~CTRL_AA; + writel(ctrl, bus->base + MPFS_I2C_CTRL); + } +} + +static int mpfs_i2c_fill_tx(struct mpfs_i2c_bus *bus) +{ + mpfs_i2c_transfer(bus, *bus->buf++); + bus->msg_len--; + + return 0; +} + +static int mpfs_i2c_service_handler(struct mpfs_i2c_bus *bus) +{ + bool finish = false; + u32 status; + u8 ctrl; + + status = bus->isr_status; + + switch (status) { + case STATUS_M_START_SENT: + case STATUS_M_REPEATED_START_SENT: + ctrl = readl(bus->base + MPFS_I2C_CTRL); + ctrl &= ~CTRL_STA; + writel(bus->addr, bus->base + MPFS_I2C_DATA); + writel(ctrl, bus->base + MPFS_I2C_CTRL); + break; + case STATUS_M_SLAW_ACK: + case STATUS_M_TX_DATA_ACK: + if (bus->msg_len > 0) { + mpfs_i2c_fill_tx(bus); + } else { + /* On the last byte to be transmitted, send STOP */ + mpfs_i2c_stop(bus); + finish = true; + } + break; + case STATUS_M_SLAR_ACK: + ctrl = readl(bus->base + MPFS_I2C_CTRL); + ctrl |= CTRL_AA; + writel(ctrl, bus->base + MPFS_I2C_CTRL); + if (bus->msg_len == 0) { + /* On the last byte to be transmitted, send STOP */ + mpfs_i2c_stop(bus); + finish = true; + } + break; + case STATUS_M_RX_DATA_ACKED: + mpfs_i2c_empty_rx(bus); + if (bus->msg_len == 0) { + /* On the last byte to be transmitted, send STOP */ + mpfs_i2c_stop(bus); + finish = true; + } + break; + case STATUS_M_TX_DATA_NACK: + case STATUS_M_RX_DATA_NACKED: + case STATUS_M_SLAR_NACK: + case STATUS_M_SLAW_NACK: + bus->msg_err = -ENXIO; + mpfs_i2c_stop(bus); + finish = true; + break; + + case STATUS_M_ARB_LOST: + /* Handle Lost Arbitration */ + bus->msg_err = -EAGAIN; + finish = true; + break; + default: + break; + } + + if (finish) { + ctrl = readl(bus->base + MPFS_I2C_CTRL); + ctrl &= ~CTRL_AA; + writel(ctrl, bus->base + MPFS_I2C_CTRL); + return 0; + } + + return 1; +} + +static int mpfs_i2c_service(struct mpfs_i2c_bus *bus) +{ + int ret = 0; + int si_bit; + + si_bit = readl(bus->base + MPFS_I2C_CTRL); + if (si_bit & CTRL_SI) { + bus->isr_status = readl(bus->base + MPFS_I2C_STATUS); + ret = mpfs_i2c_service_handler(bus); + } + /* Clear the si flag */ + mpfs_i2c_int_clear(bus); + si_bit = readl(bus->base + MPFS_I2C_CTRL); + + return ret; +} + +static int mpfs_i2c_check_service_change(struct mpfs_i2c_bus *bus) +{ + u8 ctrl; + u32 count = 0; + + while (1) { + ctrl = readl(bus->base + MPFS_I2C_CTRL); + if (ctrl & CTRL_SI) + break; + udelay(1); + count += 1; + if (count == MICROCHIP_I2C_TIMEOUT) + return -ETIMEDOUT; + } + return 0; +} + +static int mpfs_i2c_poll_device(struct mpfs_i2c_bus *bus) +{ + int ret; + + while (1) { + ret = mpfs_i2c_check_service_change(bus); + if (ret) + return ret; + + ret = mpfs_i2c_service(bus); + if (!ret) + /* all messages have been transferred */ + return ret; + } +} + +static int mpfs_i2c_xfer_msg(struct mpfs_i2c_bus *bus, struct i2c_msg *msg) +{ + u8 ctrl; + int ret; + + if (!msg->len || !msg->buf) + return -EINVAL; + + bus->addr = i2c_8bit_addr_from_msg(msg); + bus->msg_len = msg->len; + bus->buf = msg->buf; + bus->msg_err = 0; + + mpfs_i2c_core_enable(bus); + + ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl |= CTRL_STA; + + writel(ctrl, bus->base + MPFS_I2C_CTRL); + + ret = mpfs_i2c_poll_device(bus); + if (ret) + return ret; + + return bus->msg_err; +} + +static int mpfs_i2c_xfer(struct udevice *dev, struct i2c_msg *msgs, int num_msgs) +{ + struct mpfs_i2c_bus *bus = dev_get_priv(dev); + int idx, ret; + + if (!msgs || !num_msgs) + return -EINVAL; + + for (idx = 0; idx < num_msgs; idx++) { + ret = mpfs_i2c_xfer_msg(bus, msgs++); + if (ret) + return ret; + } + + return ret; +} + +static int mpfs_i2c_probe_chip(struct udevice *dev, uint addr, uint flags) +{ + struct mpfs_i2c_bus *bus = dev_get_priv(dev); + int ret; + u8 ctrl, reg = 0; + + /* + * Send the chip address and verify that the + * address was <ACK>ed. + */ + bus->addr = addr << 1 | I2C_M_RD; + bus->buf = ® + bus->msg_len = 0; + bus->msg_err = 0; + + mpfs_i2c_core_enable(bus); + + ctrl = readl(bus->base + MPFS_I2C_CTRL); + + ctrl |= CTRL_STA; + + writel(ctrl, bus->base + MPFS_I2C_CTRL); + + ret = mpfs_i2c_poll_device(bus); + if (ret) + return ret; + + return bus->msg_err; +} + +static int mpfs_i2c_probe(struct udevice *dev) +{ + int ret; + u32 val; + struct mpfs_i2c_bus *bus = dev_get_priv(dev); + + bus->base = dev_read_addr_ptr(dev); + if (!bus->base) + return -EINVAL; + + val = dev_read_u32(dev, "clock-frequency", &bus->clk_rate); + if (val) { + printf("Default to 100kHz\n"); + /* default clock rate */ + bus->clk_rate = 100000; + } + + if (bus->clk_rate > 400000 || bus->clk_rate <= 0) { + printf("Invalid clock-frequency %d\n", bus->clk_rate); + return -EINVAL; + } + + ret = mpfs_i2c_init(bus, dev); + + return ret; +} + +static const struct dm_i2c_ops mpfs_i2c_ops = { + .xfer = mpfs_i2c_xfer, + .probe_chip = mpfs_i2c_probe_chip, +}; + +static const struct udevice_id mpfs_i2c_ids[] = { + {.compatible = "microchip,mpfs-i2c"}, + {} +}; + +U_BOOT_DRIVER(mpfs_i2c) = { + .name = "mpfs_i2c", + .id = UCLASS_I2C, + .of_match = mpfs_i2c_ids, + .ops = &mpfs_i2c_ops, + .probe = mpfs_i2c_probe, + .priv_auto = sizeof(struct mpfs_i2c_bus), +}; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 585101804d..22dad5b203 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1045,16 +1045,10 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; - ret = eqos->config->ops->eqos_start_clks(dev); - if (ret < 0) { - pr_err("eqos_start_clks() failed: %d", ret); - goto err; - } - ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { pr_err("eqos_start_resets() failed: %d", ret); - goto err_stop_clks; + goto err; } udelay(10); @@ -1360,8 +1354,6 @@ err_shutdown_phy: phy_shutdown(eqos->phy); err_stop_resets: eqos->config->ops->eqos_stop_resets(dev); -err_stop_clks: - eqos->config->ops->eqos_stop_clks(dev); err: pr_err("FAILED: %d", ret); return ret; @@ -1416,7 +1408,6 @@ static void eqos_stop(struct udevice *dev) phy_shutdown(eqos->phy); } eqos->config->ops->eqos_stop_resets(dev); - eqos->config->ops->eqos_stop_clks(dev); debug("%s: OK\n", __func__); } @@ -1862,6 +1853,12 @@ static int eqos_probe(struct udevice *dev) goto err_remove_resources_core; } + ret = eqos->config->ops->eqos_start_clks(dev); + if (ret < 0) { + pr_err("eqos_start_clks() failed: %d", ret); + goto err_remove_resources_tegra; + } + #ifdef CONFIG_DM_ETH_PHY eqos->mii = eth_phy_get_mdio_bus(dev); #endif @@ -1870,7 +1867,7 @@ static int eqos_probe(struct udevice *dev) if (!eqos->mii) { pr_err("mdio_alloc() failed"); ret = -ENOMEM; - goto err_remove_resources_tegra; + goto err_stop_clks; } eqos->mii->read = eqos_mdio_read; eqos->mii->write = eqos_mdio_write; @@ -1893,6 +1890,8 @@ static int eqos_probe(struct udevice *dev) err_free_mdio: mdio_free(eqos->mii); +err_stop_clks: + eqos->config->ops->eqos_stop_clks(dev); err_remove_resources_tegra: eqos->config->ops->eqos_remove_resources(dev); err_remove_resources_core: @@ -1910,6 +1909,7 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); + eqos->config->ops->eqos_stop_clks(dev); eqos->config->ops->eqos_remove_resources(dev); eqos_probe_resources_core(dev); diff --git a/drivers/net/eth-phy-uclass.c b/drivers/net/eth-phy-uclass.c index c04bab944d..a9b358ee23 100644 --- a/drivers/net/eth-phy-uclass.c +++ b/drivers/net/eth-phy-uclass.c @@ -138,7 +138,7 @@ static int eth_phy_of_to_plat(struct udevice *dev) ret = gpio_request_by_name(dev, "reset-gpios", 0, &uc_priv->reset_gpio, GPIOD_IS_OUT); - if (ret != -ENOENT) + if (ret && ret != -ENOENT) return ret; uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 8c6461e717..37eed59a69 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1348,7 +1348,7 @@ static const struct macb_usrio_cfg macb_default_usrio = { .clken = MACB_BIT(CLKEN), }; -static const struct macb_config default_gem_config = { +static struct macb_config default_gem_config = { .dma_burst_length = 16, .hw_dma_cap = HW_DMA_CAP_32B, .clk_init = NULL, @@ -1383,8 +1383,13 @@ static int macb_eth_probe(struct udevice *dev) macb->is_big_endian = (cpu_to_be32(0x12345678) == 0x12345678); macb->config = (struct macb_config *)dev_get_driver_data(dev); - if (!macb->config) + if (!macb->config) { + if (IS_ENABLED(CONFIG_DMA_ADDR_T_64BIT)) { + if (GEM_BFEXT(DAW64, gem_readl(macb, DCFG6))) + default_gem_config.hw_dma_cap = HW_DMA_CAP_64B; + } macb->config = &default_gem_config; + } #ifdef CONFIG_CLK ret = macb_enable_clk(dev); @@ -1453,13 +1458,6 @@ static const struct macb_usrio_cfg sama7g5_usrio = { .clken = BIT(2), }; -static const struct macb_config microchip_config = { - .dma_burst_length = 16, - .hw_dma_cap = HW_DMA_CAP_64B, - .clk_init = NULL, - .usrio = &macb_default_usrio, -}; - static const struct macb_config sama5d4_config = { .dma_burst_length = 4, .hw_dma_cap = HW_DMA_CAP_32B, @@ -1502,8 +1500,6 @@ static const struct udevice_id macb_eth_ids[] = { { .compatible = "cdns,zynq-gem" }, { .compatible = "sifive,fu540-c000-gem", .data = (ulong)&sifive_config }, - { .compatible = "microchip,mpfs-mss-gem", - .data = (ulong)µchip_config }, { } }; diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 6953b7286a..1d1118c341 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -129,7 +129,7 @@ struct ravb_priv { struct phy_device *phydev; struct mii_dev *bus; void __iomem *iobase; - struct clk clk; + struct clk_bulk clks; struct gpio_desc reset_gpio; }; @@ -485,7 +485,7 @@ static int ravb_probe(struct udevice *dev) iobase = map_physmem(pdata->iobase, 0x1000, MAP_NOCACHE); eth->iobase = iobase; - ret = clk_get_by_index(dev, 0, ð->clk); + ret = clk_get_bulk(dev, ð->clks); if (ret < 0) goto err_mdio_alloc; @@ -518,7 +518,7 @@ static int ravb_probe(struct udevice *dev) eth->bus = miiphy_get_dev_by_name(dev->name); /* Bring up PHY */ - ret = clk_enable(ð->clk); + ret = clk_enable_bulk(ð->clks); if (ret) goto err_mdio_register; @@ -533,7 +533,7 @@ static int ravb_probe(struct udevice *dev) return 0; err_mdio_reset: - clk_disable(ð->clk); + clk_release_bulk(ð->clks); err_mdio_register: mdio_free(mdiodev); err_mdio_alloc: @@ -545,7 +545,7 @@ static int ravb_remove(struct udevice *dev) { struct ravb_priv *eth = dev_get_priv(dev); - clk_disable(ð->clk); + clk_release_bulk(ð->clks); free(eth->phydev); mdio_unregister(eth->bus); diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 4e94b776c5..a92f00d0af 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -202,7 +202,7 @@ struct pcie_advk { int sec_busno; struct udevice *dev; struct gpio_desc reset_gpio; - u32 cfgcache[0x34 - 0x10]; + u32 cfgcache[(0x3c - 0x10) / 4]; bool cfgcrssve; }; @@ -389,20 +389,19 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, } /* - * The configuration space of the PCI Bridge on primary (local) bus is + * The configuration space of the PCI Bridge on primary (first) bus is * not accessible via PIO transfers like all other PCIe devices. PCI * Bridge config registers are available directly in Aardvark memory - * space starting at offset zero. Moreover PCI Bridge registers in the - * range 0x10 - 0x34 are not available and register 0x38 (Expansion ROM - * Base Address) is at offset 0x30. - * We therefore read configuration space content of the primary PCI - * Bridge from our virtual cache. + * space starting at offset zero. The PCI Bridge config space is of + * Type 0, but the BAR registers (including ROM BAR) don't have the same + * meaning as in the PCIe specification. Therefore do not access BAR + * registers and non-common registers (those which have different + * meaning for Type 0 and Type 1 config space) of the primary PCI Bridge + * and instead read their content from driver virtual cfgcache[]. */ if (busno == pcie->first_busno) { - if (offset >= 0x10 && offset < 0x34) + if ((offset >= 0x10 && offset < 0x34) || (offset >= 0x38 && offset < 0x3c)) data = pcie->cfgcache[(offset - 0x10) / 4]; - else if ((offset & ~3) == PCI_ROM_ADDRESS1) - data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); else data = advk_readl(pcie, offset & ~3); @@ -576,23 +575,22 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, } /* - * As explained in pcie_advk_read_config(), for the configuration - * space of the primary PCI Bridge, we write the content into virtual - * cache. + * As explained in pcie_advk_read_config(), PCI Bridge config registers + * are available directly in Aardvark memory space starting at offset + * zero. Type 1 specific registers are not available, so we write their + * content only into driver virtual cfgcache[]. */ if (busno == pcie->first_busno) { - if (offset >= 0x10 && offset < 0x34) { + if ((offset >= 0x10 && offset < 0x34) || + (offset >= 0x38 && offset < 0x3c)) { data = pcie->cfgcache[(offset - 0x10) / 4]; data = pci_conv_size_to_32(data, value, offset, size); /* This PCI bridge does not have configurable bars */ if ((offset & ~3) == PCI_BASE_ADDRESS_0 || - (offset & ~3) == PCI_BASE_ADDRESS_1) + (offset & ~3) == PCI_BASE_ADDRESS_1 || + (offset & ~3) == PCI_ROM_ADDRESS1) data = 0x0; pcie->cfgcache[(offset - 0x10) / 4] = data; - } else if ((offset & ~3) == PCI_ROM_ADDRESS1) { - data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); - data = pci_conv_size_to_32(data, value, offset, size); - advk_writel(pcie, data, PCIE_CORE_EXP_ROM_BAR_REG); } else { data = advk_readl(pcie, offset & ~3); data = pci_conv_size_to_32(data, value, offset, size); @@ -830,12 +828,20 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) * * Note that this Aardvark PCI Bridge does not have a compliant Type 1 * Configuration Space and it even cannot be accessed via Aardvark's - * PCI config space access method. Something like config space is + * PCI config space access method. Aardvark PCI Bridge Config space is * available in internal Aardvark registers starting at offset 0x0 - * and is reported as Type 0. In range 0x10 - 0x34 it has totally - * different registers. So our driver reports Header Type as Type 1 and - * for the above mentioned range redirects access to the virtual - * cfgcache[] buffer, which avoids changing internal Aardvark registers. + * and has format of Type 0 config space. + * + * Moreover Type 0 BAR registers (ranges 0x10 - 0x28 and 0x30 - 0x34) + * have the same format in Marvell's specification as in PCIe + * specification, but their meaning is totally different (and not even + * the same meaning as explained in the corresponding comment in the + * pci_mvebu driver; aardvark is still different). + * + * So our driver converts Type 0 config space to Type 1 and reports + * Header Type as Type 1. Access to BAR registers and to non-existent + * Type 1 registers is redirected to the virtual cfgcache[] buffer, + * which avoids changing unrelated registers. */ reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); reg &= ~0xffffff00; diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 14cd82db6f..62a4df37a0 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -88,7 +88,7 @@ struct mvebu_pcie { unsigned int mem_attr; unsigned int io_target; unsigned int io_attr; - u32 cfgcache[0x34 - 0x10]; + u32 cfgcache[(0x3c - 0x10) / 4]; }; /* @@ -167,20 +167,20 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, } /* - * mvebu has different internal registers mapped into PCI config space - * in range 0x10-0x34 for PCI bridge, so do not access PCI config space - * for this range and instead read content from driver virtual cfgcache + * The configuration space of the PCI Bridge on primary (first) bus is + * of Type 0 but the BAR registers (including ROM BAR) don't have the + * same meaning as in the PCIe specification. Therefore do not access + * BAR registers and non-common registers (those which have different + * meaning for Type 0 and Type 1 config space) of the PCI Bridge and + * instead read their content from driver virtual cfgcache[]. */ - if (busno == pcie->first_busno && offset >= 0x10 && offset < 0x34) { + if (busno == pcie->first_busno && ((offset >= 0x10 && offset < 0x34) || + (offset >= 0x38 && offset < 0x3c))) { data = pcie->cfgcache[(offset - 0x10) / 4]; debug("(addr,size,val)=(0x%04x, %d, 0x%08x) from cfgcache\n", offset, size, data); *valuep = pci_conv_32_to_size(data, offset, size); return 0; - } else if (busno == pcie->first_busno && - (offset & ~3) == PCI_ROM_ADDRESS1) { - /* mvebu has Expansion ROM Base Address (0x38) at offset 0x30 */ - offset -= PCI_ROM_ADDRESS1 - PCIE_EXP_ROM_BAR_OFF; } /* @@ -247,17 +247,21 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf, } /* - * mvebu has different internal registers mapped into PCI config space - * in range 0x10-0x34 for PCI bridge, so do not access PCI config space - * for this range and instead write content to driver virtual cfgcache + * As explained in mvebu_pcie_read_config(), PCI Bridge Type 1 specific + * config registers are not available, so we write their content only + * into driver virtual cfgcache[]. + * And as explained in mvebu_pcie_probe(), mvebu has its own specific + * way for configuring primary and secondary bus numbers. */ - if (busno == pcie->first_busno && offset >= 0x10 && offset < 0x34) { + if (busno == pcie->first_busno && ((offset >= 0x10 && offset < 0x34) || + (offset >= 0x38 && offset < 0x3c))) { debug("Writing to cfgcache only\n"); data = pcie->cfgcache[(offset - 0x10) / 4]; data = pci_conv_size_to_32(data, value, offset, size); /* mvebu PCI bridge does not have configurable bars */ if ((offset & ~3) == PCI_BASE_ADDRESS_0 || - (offset & ~3) == PCI_BASE_ADDRESS_1) + (offset & ~3) == PCI_BASE_ADDRESS_1 || + (offset & ~3) == PCI_ROM_ADDRESS1) data = 0x0; pcie->cfgcache[(offset - 0x10) / 4] = data; /* mvebu has its own way how to set PCI primary bus number */ @@ -275,10 +279,6 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf, pcie->sec_busno); } return 0; - } else if (busno == pcie->first_busno && - (offset & ~3) == PCI_ROM_ADDRESS1) { - /* mvebu has Expansion ROM Base Address (0x38) at offset 0x30 */ - offset -= PCI_ROM_ADDRESS1 - PCIE_EXP_ROM_BAR_OFF; } /* @@ -384,13 +384,20 @@ static int mvebu_pcie_probe(struct udevice *dev) * U-Boot cannot recognize as P2P Bridge. * * Note that this mvebu PCI Bridge does not have compliant Type 1 - * Configuration Space. Header Type is reported as Type 0 and in - * range 0x10-0x34 it has aliased internal mvebu registers 0x10-0x34 - * (e.g. PCIE_BAR_LO_OFF) and register 0x38 is reserved. + * Configuration Space. Header Type is reported as Type 0 and it + * has format of Type 0 config space. * - * Driver for this range redirects access to virtual cfgcache[] buffer - * which avoids changing internal mvebu registers. And changes Header - * Type response value to Type 1. + * Moreover Type 0 BAR registers (ranges 0x10 - 0x28 and 0x30 - 0x34) + * have the same format in Marvell's specification as in PCIe + * specification, but their meaning is totally different and they do + * different things: they are aliased into internal mvebu registers + * (e.g. PCIE_BAR_LO_OFF) and these should not be changed or + * reconfigured by pci device drivers. + * + * So our driver converts Type 0 config space to Type 1 and reports + * Header Type as Type 1. Access to BAR registers and to non-existent + * Type 1 registers is redirected to the virtual cfgcache[] buffer, + * which avoids changing unrelated registers. */ reg = readl(pcie->base + PCIE_DEV_REV_OFF); reg &= ~0xffffff00; diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c index 6bca8e4b7e..93e4d38d34 100644 --- a/drivers/serial/serial_mvebu_a3700.c +++ b/drivers/serial/serial_mvebu_a3700.c @@ -9,6 +9,7 @@ #include <serial.h> #include <asm/io.h> #include <asm/arch/cpu.h> +#include <mach/soc.h> struct mvebu_plat { void __iomem *base; @@ -213,6 +214,7 @@ static int mvebu_serial_remove(struct udevice *dev) u32 new_oversampling; u32 oversampling; u32 d1, d2; + u32 nb_rst; /* * Switch UART base clock back to XTAL because older Linux kernel @@ -260,12 +262,22 @@ static int mvebu_serial_remove(struct udevice *dev) return 0; } + /* wait until TX empty */ while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY)) ; + /* external reset of UART via North Bridge Peripheral */ + nb_rst = readl(MVEBU_REGISTER(0x12400)); + writel(nb_rst & ~BIT(3), MVEBU_REGISTER(0x12400)); + writel(nb_rst | BIT(3), MVEBU_REGISTER(0x12400)); + + /* set baudrate and oversampling */ writel(new_divider, base + UART_BAUD_REG); writel(new_oversampling, base + UART_POSSR_REG); + /* No Parity, 1 Stop */ + writel(0, base + UART_CTRL_REG); + return 0; } @@ -305,7 +317,6 @@ U_BOOT_DRIVER(serial_mvebu) = { #ifdef CONFIG_DEBUG_MVEBU_A3700_UART #include <debug_uart.h> -#include <mach/soc.h> static inline void _debug_uart_init(void) { diff --git a/drivers/tpm/tpm2_tis_core.c b/drivers/tpm/tpm2_tis_core.c index ec8c730fe9..51392c4584 100644 --- a/drivers/tpm/tpm2_tis_core.c +++ b/drivers/tpm/tpm2_tis_core.c @@ -378,8 +378,14 @@ out: int tpm_tis_cleanup(struct udevice *dev) { struct tpm_chip *chip = dev_get_priv(dev); + int ret; + + ret = tpm_tis_request_locality(dev, 0); + if (ret) + return ret; tpm_tis_ready(dev); + tpm_tis_release_locality(dev, chip->locality); return 0; diff --git a/drivers/tpm/tpm2_tis_mmio.c b/drivers/tpm/tpm2_tis_mmio.c index 9cedff2225..a646ce41ff 100644 --- a/drivers/tpm/tpm2_tis_mmio.c +++ b/drivers/tpm/tpm2_tis_mmio.c @@ -118,10 +118,13 @@ iounmap: static int tpm_tis_remove(struct udevice *dev) { struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(dev); + int ret; + + ret = tpm_tis_cleanup(dev); iounmap(drv_data->iobase); - return tpm_tis_cleanup(dev); + return ret; } static const struct tpm_ops tpm_tis_ops = { |