diff options
Diffstat (limited to 'drivers')
29 files changed, 869 insertions, 110 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..a055387570 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, }; @@ -670,6 +672,19 @@ int blk_create_devicef(struct udevice *parent, const char *drv_name, return 0; } +int blk_probe_or_unbind(struct udevice *dev) +{ + int ret; + + ret = device_probe(dev); + if (ret) { + log_debug("probing %s failed\n", dev->name); + device_unbind(dev); + } + + return ret; +} + int blk_unbind_all(int if_type) { struct uclass *uc; 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/clk/clk-composite.c b/drivers/clk/clk-composite.c index bb5351ebc0..6eb2b8133a 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -4,14 +4,17 @@ * Copyright 2019 NXP */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> -#include <asm/io.h> -#include <malloc.h> +#include <clk.h> #include <clk-uclass.h> +#include <log.h> +#include <malloc.h> +#include <asm/io.h> #include <dm/device.h> #include <dm/devres.h> #include <linux/clk-provider.h> -#include <clk.h> #include <linux/err.h> #include "clk.h" diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 9df50a5e72..7e8e62feee 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -9,14 +9,18 @@ * */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> #include <asm/io.h> #include <malloc.h> #include <clk-uclass.h> +#include <log.h> #include <dm/device.h> #include <dm/devres.h> #include <dm/uclass.h> #include <dm/lists.h> +#include <dm/device_compat.h> #include <dm/device-internal.h> #include <linux/bug.h> #include <linux/clk-provider.h> @@ -190,7 +194,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { if (width + shift > 16) { - pr_warn("divider value exceeds LOWORD field\n"); + dev_warn(dev, "divider value exceeds LOWORD field\n"); return ERR_PTR(-EINVAL); } } diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 8d9823bdab..2a446788e1 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -5,17 +5,22 @@ * * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> */ + +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> -#include <malloc.h> +#include <clk.h> #include <clk-uclass.h> +#include <div64.h> +#include <log.h> +#include <malloc.h> #include <dm/device.h> #include <dm/devres.h> #include <linux/clk-provider.h> -#include <div64.h> -#include <clk.h> -#include "clk.h" #include <linux/err.h> +#include "clk.h" + #define UBOOT_DM_CLK_IMX_FIXED_FACTOR "ccf_clk_fixed_factor" static ulong clk_factor_recalc_rate(struct clk *clk) diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 006d3b6629..aa40daf3d7 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -7,18 +7,23 @@ * Gated clock implementation */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> -#include <asm/io.h> -#include <malloc.h> +#include <clk.h> +#include <log.h> #include <clk-uclass.h> +#include <malloc.h> +#include <asm/io.h> #include <dm/device.h> +#include <dm/device_compat.h> #include <dm/devres.h> #include <linux/bitops.h> #include <linux/clk-provider.h> -#include <clk.h> -#include "clk.h" #include <linux/err.h> +#include "clk.h" + #define UBOOT_DM_CLK_GATE "clk_gate" /** @@ -123,7 +128,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, if (clk_gate_flags & CLK_GATE_HIWORD_MASK) { if (bit_idx > 15) { - pr_err("gate bit exceeds LOWORD field\n"); + dev_err(dev, "gate bit exceeds LOWORD field\n"); return ERR_PTR(-EINVAL); } } diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index f1becd20d8..b49946fbcd 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -21,17 +21,22 @@ * clock. */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> #include <clk.h> #include <clk-uclass.h> +#include <log.h> +#include <malloc.h> +#include <asm/io.h> #include <dm/device.h> +#include <dm/device_compat.h> #include <dm/devres.h> #include <dm/uclass.h> #include <linux/bitops.h> -#include <malloc.h> -#include <asm/io.h> #include <linux/clk-provider.h> #include <linux/err.h> + #include "clk.h" #define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux" @@ -123,7 +128,7 @@ static int clk_mux_set_parent(struct clk *clk, struct clk *parent) index = clk_fetch_parent_index(clk, parent); if (index < 0) { - printf("Could not fetch index\n"); + log_err("Could not fetch index\n"); return index; } @@ -169,7 +174,7 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name, if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { width = fls(mask) - ffs(mask) + 1; if (width + shift > 16) { - pr_err("mux value exceeds LOWORD field\n"); + dev_err(dev, "mux value exceeds LOWORD field\n"); return ERR_PTR(-EINVAL); } } diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 493018b33e..f2d2642754 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -16,6 +16,7 @@ #include <errno.h> #include <log.h> #include <malloc.h> +#include <asm/global_data.h> #include <dm/device_compat.h> #include <dm/device-internal.h> #include <dm/devres.h> @@ -23,7 +24,6 @@ #include <linux/bug.h> #include <linux/clk-provider.h> #include <linux/err.h> -#include <asm/global_data.h> static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1efb7fe9f3..eff0fa134f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4,14 +4,16 @@ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> +#include <clk.h> #include <clk-uclass.h> #include <log.h> #include <dm/device.h> #include <dm/uclass.h> #include <dm/lists.h> #include <dm/device-internal.h> -#include <clk.h> int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) @@ -22,24 +24,24 @@ int clk_register(struct clk *clk, const char *drv_name, ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); if (ret) { - printf("%s: failed to get %s device (parent of %s)\n", - __func__, parent_name, name); + log_err("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); } else { - debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, - parent->name, parent); + log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, + parent->name, parent); } drv = lists_driver_lookup_name(drv_name); if (!drv) { - printf("%s: %s is not a valid driver name\n", - __func__, drv_name); + log_err("%s: %s is not a valid driver name\n", + __func__, drv_name); return -ENOENT; } ret = device_bind(parent, drv, name, NULL, ofnode_null(), &clk->dev); if (ret) { - printf("%s: CLK: %s driver bind error [%d]!\n", __func__, name, - ret); + log_err("%s: CLK: %s driver bind error [%d]!\n", __func__, name, + ret); return ret; } diff --git a/drivers/clk/clk_fixed_factor.c b/drivers/clk/clk_fixed_factor.c index 41b0d9c060..6c1139e5c5 100644 --- a/drivers/clk/clk_fixed_factor.c +++ b/drivers/clk/clk_fixed_factor.c @@ -5,10 +5,13 @@ * Author: Anup Patel <anup.patel@wdc.com> */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> #include <clk-uclass.h> #include <div64.h> #include <dm.h> +#include <log.h> #include <linux/err.h> struct clk_fixed_factor { diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index c5a2a42c92..b5e78c7055 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -3,9 +3,12 @@ * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com> */ +#define LOG_CATEGORY UCLASS_CLK + #include <common.h> #include <clk-uclass.h> #include <dm.h> +#include <log.h> #include <dm/device-internal.h> #include <linux/clk-provider.h> diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index b992e6f080..798e3a3f90 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -604,7 +604,8 @@ static int first_loading_rbf_to_buffer(struct udevice *dev, if (strstr(uname, "fpga-periph") && (!is_fpgamgr_early_user_mode() || - is_fpgamgr_user_mode())) { + is_fpgamgr_user_mode() || + is_periph_program_force())) { fpga_node_name = uname; printf("FPGA: Start to program "); printf("peripheral/full bitstream ...\n"); 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/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 236bfb8d8e..ff21e3c52b 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -860,6 +860,9 @@ static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) { struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); struct i2c_msg *dmsg, *omsg, dummy; + u8 *addr_buf_ptr; + u8 addr_buf[4]; + int i; memset(&dummy, 0, sizeof(struct i2c_msg)); @@ -873,12 +876,17 @@ static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) omsg = nmsgs == 1 ? &dummy : msg; dmsg = nmsgs == 1 ? msg : msg + 1; + /* We need to swap the register address if its size is > 1 */ + addr_buf_ptr = &addr_buf[0]; + for (i = omsg->len; i > 0; i--) + *addr_buf_ptr++ = omsg->buf[i - 1]; + if (dmsg->flags & I2C_M_RD) - return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf, + return __twsi_i2c_read(dev->base, dmsg->addr, addr_buf, omsg->len, dmsg->buf, dmsg->len, dev->tick); else - return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf, + return __twsi_i2c_write(dev->base, dmsg->addr, addr_buf, omsg->len, dmsg->buf, dmsg->len, dev->tick); } 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 6e5730cfc3..22b6d8b628 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -193,7 +193,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; }; @@ -380,20 +380,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); @@ -567,23 +566,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); @@ -821,12 +819,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 fad38b7db1..cc8ebff0c6 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -89,7 +89,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]; }; /* @@ -168,20 +168,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; } /* @@ -248,17 +248,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 */ @@ -276,10 +280,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; } /* @@ -385,13 +385,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 8c3c10c667..3e673bde57 100644 --- a/drivers/serial/serial_mvebu_a3700.c +++ b/drivers/serial/serial_mvebu_a3700.c @@ -10,6 +10,7 @@ #include <serial.h> #include <asm/io.h> #include <asm/arch/cpu.h> +#include <mach/soc.h> struct mvebu_plat { void __iomem *base; @@ -214,6 +215,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 @@ -261,12 +263,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; } @@ -306,7 +318,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 = { |