X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fspi%2Fti_qspi.c;h=2dcce66de0482fac825f44dd5b3fcf29ef85af38;hb=cce289a928583a64db6ec8f813cc7884ae62c213;hp=78d8b1368de697df724fc8f63661f1c340e4155d;hpb=e6ac28b60be2d670948332197862e314b7977177;p=oweals%2Fu-boot.git diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 78d8b1368d..2dcce66de0 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * TI QSPI driver * * Copyright (C) 2013, Texas Instruments, Incorporated - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -16,12 +15,19 @@ #include #include #include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; /* ti qpsi register bit masks */ #define QSPI_TIMEOUT 2000000 -#define QSPI_FCLK 192000000 +#define QSPI_FCLK 192000000 +#define QSPI_DRA7XX_FCLK 76800000 +#define QSPI_WLEN_MAX_BITS 128 +#define QSPI_WLEN_MAX_BYTES (QSPI_WLEN_MAX_BITS >> 3) +#define QSPI_WLEN_MASK QSPI_WLEN(QSPI_WLEN_MAX_BITS) /* clock control */ #define QSPI_CLK_EN BIT(31) #define QSPI_CLK_DIV_MAX 0xffff @@ -45,22 +51,22 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_XFER_DONE QSPI_WC #define MM_SWITCH 0x01 #define MEM_CS(cs) ((cs + 1) << 8) -#define MEM_CS_UNSELECT 0xfffff0ff +#define MEM_CS_UNSELECT 0xfffff8ff #define MMAP_START_ADDR_DRA 0x5c000000 #define MMAP_START_ADDR_AM43x 0x30000000 #define CORE_CTRL_IO 0x4a002558 #define QSPI_CMD_READ (0x3 << 0) #define QSPI_CMD_READ_DUAL (0x6b << 0) -#define QSPI_CMD_READ_QUAD (0x6b << 0) +#define QSPI_CMD_READ_QUAD (0x6c << 0) #define QSPI_CMD_READ_FAST (0x0b << 0) -#define QSPI_SETUP0_NUM_A_BYTES (0x2 << 8) +#define QSPI_SETUP0_NUM_A_BYTES (0x3 << 8) #define QSPI_SETUP0_NUM_D_BYTES_NO_BITS (0x0 << 10) #define QSPI_SETUP0_NUM_D_BYTES_8_BITS (0x1 << 10) #define QSPI_SETUP0_READ_NORMAL (0x0 << 12) #define QSPI_SETUP0_READ_DUAL (0x1 << 12) #define QSPI_SETUP0_READ_QUAD (0x3 << 12) -#define QSPI_CMD_WRITE (0x2 << 16) +#define QSPI_CMD_WRITE (0x12 << 16) #define QSPI_NUM_DUMMY_BITS (0x0 << 24) /* ti qspi register set */ @@ -101,6 +107,7 @@ struct ti_qspi_priv { #endif struct ti_qspi_regs *base; void *ctrl_mod_mmap; + ulong fclk; unsigned int mode; u32 cmd; u32 dc; @@ -110,24 +117,21 @@ static void ti_spi_set_speed(struct ti_qspi_priv *priv, uint hz) { uint clk_div; - debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div); - if (!hz) clk_div = 0; else - clk_div = (QSPI_FCLK / hz) - 1; + clk_div = DIV_ROUND_UP(priv->fclk, hz) - 1; + + /* truncate clk_div value to QSPI_CLK_DIV_MAX */ + if (clk_div > QSPI_CLK_DIV_MAX) + clk_div = QSPI_CLK_DIV_MAX; + + debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div); /* disable SCLK */ writel(readl(&priv->base->clk_ctrl) & ~QSPI_CLK_EN, &priv->base->clk_ctrl); - - /* assign clk_div values */ - if (clk_div < 0) - clk_div = 0; - else if (clk_div > QSPI_CLK_DIV_MAX) - clk_div = QSPI_CLK_DIV_MAX; - - /* enable SCLK */ + /* enable SCLK and program the clk divider */ writel(QSPI_CLK_EN | clk_div, &priv->base->clk_ctrl); } @@ -221,20 +225,34 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, priv->cmd |= QSPI_3_PIN; priv->cmd |= 0xfff; -/* FIXME: This delay is required for successfull - * completion of read/write/erase. Once its root - * caused, it will be remove from the driver. - */ -#ifdef CONFIG_AM43XX - udelay(100); -#endif - while (words--) { + while (words) { + u8 xfer_len = 0; + if (txp) { - debug("tx cmd %08x dc %08x data %02x\n", - priv->cmd | QSPI_WR_SNGL, priv->dc, *txp); - writel(*txp++, &priv->base->data); - writel(priv->cmd | QSPI_WR_SNGL, - &priv->base->cmd); + u32 cmd = priv->cmd; + + if (words >= QSPI_WLEN_MAX_BYTES) { + u32 *txbuf = (u32 *)txp; + u32 data; + + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data3); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data2); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data1); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data); + cmd &= ~QSPI_WLEN_MASK; + cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); + xfer_len = QSPI_WLEN_MAX_BYTES; + } else { + writeb(*txp, &priv->base->data); + xfer_len = 1; + } + debug("tx cmd %08x dc %08x\n", + cmd | QSPI_WR_SNGL, priv->dc); + writel(cmd | QSPI_WR_SNGL, &priv->base->cmd); status = readl(&priv->base->status); timeout = QSPI_TIMEOUT; while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { @@ -244,16 +262,13 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, } status = readl(&priv->base->status); } + txp += xfer_len; debug("tx done, status %08x\n", status); } if (rxp) { - priv->cmd |= QSPI_RD_SNGL; debug("rx cmd %08x dc %08x\n", - priv->cmd, priv->dc); - #ifdef CONFIG_DRA7XX - udelay(500); - #endif - writel(priv->cmd, &priv->base->cmd); + ((u32)(priv->cmd | QSPI_RD_SNGL)), priv->dc); + writel(priv->cmd | QSPI_RD_SNGL, &priv->base->cmd); status = readl(&priv->base->status); timeout = QSPI_TIMEOUT; while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { @@ -264,9 +279,11 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, status = readl(&priv->base->status); } *rxp++ = readl(&priv->base->data); + xfer_len = 1; debug("rx done, status %08x, read %02x\n", status, *(rxp-1)); } + words -= xfer_len; } /* Terminate frame */ @@ -277,7 +294,7 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, } /* TODO: control from sf layer to here through dm-spi */ -#ifdef CONFIG_TI_EDMA3 +#if defined(CONFIG_TI_EDMA3) && !defined(CONFIG_DMA) void spi_flash_copy_mmap(void *data, void *offset, size_t len) { unsigned int addr = (unsigned int) (data); @@ -338,7 +355,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_priv *priv) QSPI_SETUP0_NUM_D_BYTES_8_BITS | QSPI_SETUP0_READ_QUAD | QSPI_CMD_WRITE | QSPI_NUM_DUMMY_BITS); - slave->mode_rx = SPI_RX_QUAD; + slave->mode |= SPI_RX_QUAD; #else memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | QSPI_SETUP0_NUM_D_BYTES_NO_BITS | @@ -367,11 +384,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, priv->base = (struct ti_qspi_regs *)QSPI_BASE; priv->mode = mode; -#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX) +#if defined(CONFIG_DRA7XX) priv->ctrl_mod_mmap = (void *)CORE_CTRL_IO; priv->slave.memory_map = (void *)MMAP_START_ADDR_DRA; + priv->fclk = QSPI_DRA7XX_FCLK; #else priv->slave.memory_map = (void *)MMAP_START_ADDR_AM43x; + priv->fclk = QSPI_FCLK; #endif ti_spi_set_speed(priv, max_hz); @@ -422,7 +441,7 @@ static void __ti_qspi_setup_memorymap(struct ti_qspi_priv *priv, bool enable) { u32 memval; - u32 mode = slave->mode_rx & (SPI_RX_QUAD | SPI_RX_DUAL); + u32 mode = slave->mode & (SPI_RX_QUAD | SPI_RX_DUAL); if (!enable) { writel(0, &priv->base->setup0); @@ -436,7 +455,7 @@ static void __ti_qspi_setup_memorymap(struct ti_qspi_priv *priv, memval |= QSPI_CMD_READ_QUAD; memval |= QSPI_SETUP0_NUM_D_BYTES_8_BITS; memval |= QSPI_SETUP0_READ_QUAD; - slave->mode_rx = SPI_RX_QUAD; + slave->mode |= SPI_RX_QUAD; break; case SPI_RX_DUAL: memval |= QSPI_CMD_READ_DUAL; @@ -524,21 +543,63 @@ static int ti_qspi_xfer(struct udevice *dev, unsigned int bitlen, static int ti_qspi_probe(struct udevice *bus) { - /* Nothing to do in probe */ + struct ti_qspi_priv *priv = dev_get_priv(bus); + + priv->fclk = dev_get_driver_data(bus); + return 0; } +static void *map_syscon_chipselects(struct udevice *bus) +{ +#if CONFIG_IS_ENABLED(SYSCON) + struct udevice *syscon; + struct regmap *regmap; + const fdt32_t *cell; + int len, err; + + err = uclass_get_device_by_phandle(UCLASS_SYSCON, bus, + "syscon-chipselects", &syscon); + if (err) { + debug("%s: unable to find syscon device (%d)\n", __func__, + err); + return NULL; + } + + regmap = syscon_get_regmap(syscon); + if (IS_ERR(regmap)) { + debug("%s: unable to find regmap (%ld)\n", __func__, + PTR_ERR(regmap)); + return NULL; + } + + cell = fdt_getprop(gd->fdt_blob, dev_of_offset(bus), + "syscon-chipselects", &len); + if (len < 2*sizeof(fdt32_t)) { + debug("%s: offset not available\n", __func__); + return NULL; + } + + return fdtdec_get_number(cell + 1, 1) + regmap_get_range(regmap, 0); +#else + fdt_addr_t addr; + addr = devfdt_get_addr_index(bus, 2); + return (addr == FDT_ADDR_T_NONE) ? NULL : + map_physmem(addr, 0, MAP_NOCACHE); +#endif +} + static int ti_qspi_ofdata_to_platdata(struct udevice *bus) { struct ti_qspi_priv *priv = dev_get_priv(bus); const void *blob = gd->fdt_blob; - int node = bus->of_offset; - fdt_addr_t addr; + int node = dev_of_offset(bus); - priv->base = (struct ti_qspi_regs *)dev_get_addr(bus); - priv->memory_map = (void *)dev_get_addr_index(bus, 1); - addr = dev_get_addr_index(bus, 2); - priv->ctrl_mod_mmap = (addr == FDT_ADDR_T_NONE) ? NULL : (void *)addr; + priv->ctrl_mod_mmap = map_syscon_chipselects(bus); + priv->base = map_physmem(devfdt_get_addr(bus), + sizeof(struct ti_qspi_regs), MAP_NOCACHE); + priv->memory_map = map_physmem(devfdt_get_addr_index(bus, 1), 0, + MAP_NOCACHE); priv->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", -1); if (priv->max_hz < 0) { @@ -572,8 +633,8 @@ static const struct dm_spi_ops ti_qspi_ops = { }; static const struct udevice_id ti_qspi_ids[] = { - { .compatible = "ti,dra7xxx-qspi" }, - { .compatible = "ti,am4372-qspi" }, + { .compatible = "ti,dra7xxx-qspi", .data = QSPI_DRA7XX_FCLK}, + { .compatible = "ti,am4372-qspi", .data = QSPI_FCLK}, { } };