diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.c | 12 | ||||
-rw-r--r-- | drivers/dma/apbh_dma.c | 2 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 5 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 129 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/mxs_nand.c | 2 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 2 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 2 | ||||
-rw-r--r-- | drivers/net/sh_eth.c | 3 | ||||
-rw-r--r-- | drivers/nvme/nvme.c | 4 | ||||
-rw-r--r-- | drivers/nvme/nvme_show.c | 4 | ||||
-rw-r--r-- | drivers/video/video-uclass.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/bcm6345_wdt.c | 21 |
12 files changed, 129 insertions, 59 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 188d8431975..e3135bb75fd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -55,17 +55,6 @@ __weak void __iomem *ahci_port_base(void __iomem *base, u32 port) return base + 0x100 + (port * 0x80); } - -static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base, - unsigned int port_idx) -{ - base = ahci_port_base(base, port_idx); - - port->cmd_addr = base; - port->scr_addr = base + PORT_SCR; -} - - #define msleep(a) udelay(a * 1000) static void ahci_dcache_flush_range(unsigned long begin, unsigned long len) @@ -240,7 +229,6 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv) continue; uc_priv->port[i].port_mmio = ahci_port_base(mmio, i); port_mmio = (u8 *)uc_priv->port[i].port_mmio; - ahci_setup_port(&uc_priv->port[i], mmio, i); /* make sure port is not active */ tmp = readl(port_mmio + PORT_CMD); diff --git a/drivers/dma/apbh_dma.c b/drivers/dma/apbh_dma.c index 017cc89a89f..ac589feeb7d 100644 --- a/drivers/dma/apbh_dma.c +++ b/drivers/dma/apbh_dma.c @@ -81,7 +81,7 @@ static int mxs_dma_read_semaphore(int channel) return tmp; } -#ifndef CONFIG_SYS_DCACHE_OFF +#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) void mxs_dma_flush_desc(struct mxs_dma_desc *desc) { uint32_t addr; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 215624020f6..095a9bc6a4d 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -161,7 +161,10 @@ config SYS_I2C_MXC channels and operating on standard mode up to 100 kbits/s and fast mode up to 400 kbits/s. -if SYS_I2C_MXC +# These settings are not used with DM_I2C, however SPL doesn't use +# DM_I2C even if DM_I2C is enabled, and so might use these settings even +# when main u-boot does not! +if SYS_I2C_MXC && (!DM_I2C || SPL) config SYS_I2C_MXC_I2C1 bool "NXP MXC I2C1" help diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 5420afbc8e0..23119cce65d 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -482,8 +482,13 @@ static int i2c_write_data(struct mxc_i2c_bus *i2c_bus, u8 chip, const u8 *buf, return ret; } +/* Will generate a STOP after the last byte if "last" is true, i.e. this is the + * final message of a transaction. If not, it switches the bus back to TX mode + * and does not send a STOP, leaving the bus in a state where a repeated start + * and address can be sent for another message. + */ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf, - int len) + int len, bool last) { int ret; unsigned int temp; @@ -513,17 +518,31 @@ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf, return ret; } - /* - * It must generate STOP before read I2DR to prevent - * controller from generating another clock cycle - */ if (i == (len - 1)) { - i2c_imx_stop(i2c_bus); + /* Final byte has already been received by master! When + * we read it from I2DR, the master will start another + * cycle. We must program it first to send a STOP or + * switch to TX to avoid this. + */ + if (last) { + i2c_imx_stop(i2c_bus); + } else { + /* Final read, no stop, switch back to tx */ + temp = readb(base + (I2CR << reg_shift)); + temp |= I2CR_MTX | I2CR_TX_NO_AK; + writeb(temp, base + (I2CR << reg_shift)); + } } else if (i == (len - 2)) { + /* Master has already recevied penultimate byte. When + * we read it from I2DR, master will start RX of final + * byte. We must set TX_NO_AK now so it does not ACK + * that final byte. + */ temp = readb(base + (I2CR << reg_shift)); temp |= I2CR_TX_NO_AK; writeb(temp, base + (I2CR << reg_shift)); } + writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift)); buf[i] = readb(base + (I2DR << reg_shift)); } @@ -533,13 +552,34 @@ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf, debug(" 0x%02x", buf[ret]); debug("\n"); - i2c_imx_stop(i2c_bus); + /* It is not clear to me that this is necessary */ + if (last) + i2c_imx_stop(i2c_bus); return 0; } #ifndef CONFIG_DM_I2C /* * Read data from I2C device + * + * The transactions use the syntax defined in the Linux kernel I2C docs. + * + * If alen is > 0, then this function will send a transaction of the form: + * S Chip Wr [A] Addr [A] S Chip Rd [A] [data] A ... NA P + * This is a normal I2C register read: writing the register address, then doing + * a repeated start and reading the data. + * + * If alen == 0, then we get this transaction: + * S Chip Wr [A] S Chip Rd [A] [data] A ... NA P + * This is somewhat unusual, though valid, transaction. It addresses the chip + * in write mode, but doesn't actually write any register address or data, then + * does a repeated start and reads data. + * + * If alen < 0, then we get this transaction: + * S Chip Rd [A] [data] A ... NA P + * The chip is addressed in read mode and then data is read. No register + * address is written first. This is perfectly valid on most devices and + * required on some (usually those that don't act like an array of registers). */ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, int alen, u8 *buf, int len) @@ -566,7 +606,7 @@ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, return ret; } - ret = i2c_read_data(i2c_bus, chip, buf, len); + ret = i2c_read_data(i2c_bus, chip, buf, len, true); i2c_imx_stop(i2c_bus); return ret; @@ -574,6 +614,20 @@ static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, /* * Write data to I2C device + * + * If alen > 0, we get this transaction: + * S Chip Wr [A] addr [A] data [A] ... [A] P + * An ordinary write register command. + * + * If alen == 0, then we get this: + * S Chip Wr [A] data [A] ... [A] P + * This is a simple I2C write. + * + * If alen < 0, then we get this: + * S data [A] ... [A] P + * This is most likely NOT something that should be used. It doesn't send the + * chip address first, so in effect, the first byte of data will be used as the + * address. */ static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, int alen, const u8 *buf, int len) @@ -881,6 +935,7 @@ static int mxc_i2c_probe(struct udevice *bus) return 0; } +/* Sends: S Addr Wr [A|NA] P */ static int mxc_i2c_probe_chip(struct udevice *bus, u32 chip_addr, u32 chip_flags) { @@ -905,42 +960,54 @@ static int mxc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) ulong base = i2c_bus->base; int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; + int read_mode; - /* - * Here the 3rd parameter addr and the 4th one alen are set to 0, - * because here we only want to send out chip address. The register - * address is wrapped in msg. + /* Here address len is set to -1 to not send any address at first. + * Otherwise i2c_init_transfer will send the chip address with write + * mode set. This is wrong if the 1st message is read. */ - ret = i2c_init_transfer(i2c_bus, msg->addr, 0, 0); + ret = i2c_init_transfer(i2c_bus, msg->addr, 0, -1); if (ret < 0) { debug("i2c_init_transfer error: %d\n", ret); return ret; } + read_mode = -1; /* So it's always different on the first message */ for (; nmsgs > 0; nmsgs--, msg++) { - bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); - debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); - if (msg->flags & I2C_M_RD) - ret = i2c_read_data(i2c_bus, msg->addr, msg->buf, - msg->len); - else { - ret = i2c_write_data(i2c_bus, msg->addr, msg->buf, - msg->len); - if (ret) - break; - if (next_is_read) { - /* Reuse ret */ + const int msg_is_read = !!(msg->flags & I2C_M_RD); + + debug("i2c_xfer: chip=0x%x, len=0x%x, dir=%c\n", msg->addr, + msg->len, msg_is_read ? 'R' : 'W'); + + if (msg_is_read != read_mode) { + /* Send repeated start if not 1st message */ + if (read_mode != -1) { + debug("i2c_xfer: [RSTART]\n"); ret = readb(base + (I2CR << reg_shift)); ret |= I2CR_RSTA; writeb(ret, base + (I2CR << reg_shift)); - - ret = tx_byte(i2c_bus, (msg->addr << 1) | 1); - if (ret < 0) { - i2c_imx_stop(i2c_bus); - break; - } } + debug("i2c_xfer: [ADDR %02x | %c]\n", msg->addr, + msg_is_read ? 'R' : 'W'); + ret = tx_byte(i2c_bus, (msg->addr << 1) | msg_is_read); + if (ret < 0) { + debug("i2c_xfer: [STOP]\n"); + i2c_imx_stop(i2c_bus); + break; + } + read_mode = msg_is_read; } + + if (msg->flags & I2C_M_RD) + ret = i2c_read_data(i2c_bus, msg->addr, msg->buf, + msg->len, nmsgs == 1 || + (msg->flags & I2C_M_STOP)); + else + ret = i2c_write_data(i2c_bus, msg->addr, msg->buf, + msg->len); + + if (ret < 0) + break; } if (ret) diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index be4ee2c7f8a..b93d77a3951 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -50,7 +50,7 @@ struct nand_ecclayout fake_ecc_layout; /* * Cache management functions */ -#ifndef CONFIG_SYS_DCACHE_OFF +#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) static void mxs_nand_flush_data_buf(struct mxs_nand_info *info) { uint32_t addr = (uint32_t)info->data_buf; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9f1c5af46e9..590e756f5c6 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -241,7 +241,7 @@ struct eqos_tegra186_regs { */ #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning Cache line size is larger than descriptor size #endif #endif diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index bc052e72564..521e5909a25 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -302,7 +302,7 @@ static unsigned char rxdata[RX_BUF_LEN]; */ #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning cache-line size is larger than descriptor size #endif #endif diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 8e54e7cc7a7..da79b766a62 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -34,7 +34,8 @@ # error "Please define CONFIG_SH_ETHER_PHY_ADDR" #endif -#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF) +#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && \ + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) #define flush_cache_wback(addr, len) \ flush_dcache_range((u32)addr, \ (u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE))) diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 1ee0a0aefb1..d4965e2ef63 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -577,7 +577,7 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev) int ret; int shift = NVME_CAP_MPSMIN(dev->cap) + 12; - ret = nvme_identify(dev, 0, 1, (dma_addr_t)ctrl); + ret = nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl); if (ret) return -EIO; @@ -646,7 +646,7 @@ static int nvme_blk_probe(struct udevice *udev) ns->dev = ndev; /* extract the namespace id from the block device name */ ns->ns_id = trailing_strtol(udev->name) + 1; - if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)id)) + if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) return -EIO; flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK; diff --git a/drivers/nvme/nvme_show.c b/drivers/nvme/nvme_show.c index 395b0618e64..15e459da1ac 100644 --- a/drivers/nvme/nvme_show.c +++ b/drivers/nvme/nvme_show.c @@ -111,14 +111,14 @@ int nvme_print_info(struct udevice *udev) ALLOC_CACHE_ALIGN_BUFFER(char, buf_ctrl, sizeof(struct nvme_id_ctrl)); struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf_ctrl; - if (nvme_identify(dev, 0, 1, (dma_addr_t)ctrl)) + if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl)) return -EIO; print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum); print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum); print_format_nvme_attributes(ctrl->fna, ns->devnum); - if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)id)) + if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id)) return -EIO; print_formats(id, ns); diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 14aac88d6d2..b19bfb4f2ff 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -149,7 +149,7 @@ void video_sync(struct udevice *vid, bool force) * architectures do not actually implement it. Is there a way to find * out whether it exists? For now, ARM is safe. */ -#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF) +#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) struct video_priv *priv = dev_get_uclass_priv(vid); if (priv->flush_dcache) { diff --git a/drivers/watchdog/bcm6345_wdt.c b/drivers/watchdog/bcm6345_wdt.c index 44f56620382..9f14e7d7774 100644 --- a/drivers/watchdog/bcm6345_wdt.c +++ b/drivers/watchdog/bcm6345_wdt.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <wdt.h> +#include <clk.h> #include <asm/io.h> /* WDT Value register */ @@ -26,6 +27,7 @@ struct bcm6345_wdt_priv { void __iomem *regs; + unsigned long clk_rate; }; static int bcm6345_wdt_reset(struct udevice *dev) @@ -41,16 +43,17 @@ static int bcm6345_wdt_reset(struct udevice *dev) static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + u32 val = priv->clk_rate / 1000 * timeout; - if (timeout < WDT_VAL_MIN) { + if (val < WDT_VAL_MIN) { debug("watchdog won't fire with less than 2 ticks\n"); - timeout = WDT_VAL_MIN; - } else if (timeout > WDT_VAL_MAX) { + val = WDT_VAL_MIN; + } else if (val > WDT_VAL_MAX) { debug("maximum watchdog timeout exceeded\n"); - timeout = WDT_VAL_MAX; + val = WDT_VAL_MAX; } - writel(timeout, priv->regs + WDT_VAL_REG); + writel(val, priv->regs + WDT_VAL_REG); return bcm6345_wdt_reset(dev); } @@ -85,11 +88,19 @@ static const struct udevice_id bcm6345_wdt_ids[] = { static int bcm6345_wdt_probe(struct udevice *dev) { struct bcm6345_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; priv->regs = dev_remap_addr(dev); if (!priv->regs) return -EINVAL; + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) + priv->clk_rate = clk_get_rate(&clk); + else + return -EINVAL; + bcm6345_wdt_stop(dev); return 0; |