diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/fpga/Kconfig | 20 | ||||
-rw-r--r-- | drivers/fpga/Makefile | 1 | ||||
-rw-r--r-- | drivers/fpga/xilinx.c | 6 | ||||
-rw-r--r-- | drivers/fpga/zynqmppl.c | 238 | ||||
-rw-r--r-- | drivers/mtd/spi/sandbox.c | 5 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_internal.h | 41 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_params.c | 200 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_flash.c | 36 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 14 | ||||
-rw-r--r-- | drivers/spi/cadence_qspi.c | 2 | ||||
-rw-r--r-- | drivers/spi/ich.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-uclass.c | 11 | ||||
-rw-r--r-- | drivers/spi/ti_qspi.c | 52 | ||||
-rw-r--r-- | drivers/spi/zynq_spi.c | 9 |
15 files changed, 448 insertions, 195 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 4f84469955..4c555a0c1f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -20,6 +20,8 @@ source "drivers/dfu/Kconfig" source "drivers/dma/Kconfig" +source "drivers/fpga/Kconfig" + source "drivers/gpio/Kconfig" source "drivers/hwmon/Kconfig" diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig new file mode 100644 index 0000000000..f3f6bf7f67 --- /dev/null +++ b/drivers/fpga/Kconfig @@ -0,0 +1,20 @@ +menu "FPGA support" + +config FPGA + bool + +config FPGA_XILINX + bool "Enable Xilinx FPGA drivers" + select FPGA + help + Enable Xilinx FPGA specific functions which includes bitstream + (in BIT format), fpga and device validation. + +config FPGA_ZYNQMPPL + bool "Enable Xilinx FPGA driver for ZynqMP" + depends on FPGA_XILINX + help + Enable FPGA driver for loading bitstream in BIT and BIN format + on Xilinx Zynq UltraScale+ (ZynqMP) device. + +endmenu diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index fec3fecbdf..777706f186 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_FPGA_SPARTAN2) += spartan2.o obj-$(CONFIG_FPGA_SPARTAN3) += spartan3.o obj-$(CONFIG_FPGA_VIRTEX2) += virtex2.o obj-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o +obj-$(CONFIG_FPGA_ZYNQMPPL) += zynqmppl.o obj-$(CONFIG_FPGA_XILINX) += xilinx.o obj-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o ifdef CONFIG_FPGA_ALTERA diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index d459a2f7a5..2cd0104d8b 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -199,6 +199,9 @@ int xilinx_info(xilinx_desc *desc) case xilinx_zynq: printf("Zynq PL\n"); break; + case xilinx_zynqmp: + printf("ZynqMP PL\n"); + break; /* Add new family types here */ default: printf ("Unknown family type, %d\n", desc->family); @@ -227,6 +230,9 @@ int xilinx_info(xilinx_desc *desc) case devcfg: printf("Device configuration interface (Zynq)\n"); break; + case csu_dma: + printf("csu_dma configuration interface (ZynqMP)\n"); + break; /* Add new interface types here */ default: printf ("Unsupported interface type, %d\n", desc->iface); diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c new file mode 100644 index 0000000000..23039c3eb2 --- /dev/null +++ b/drivers/fpga/zynqmppl.c @@ -0,0 +1,238 @@ +/* + * (C) Copyright 2015 - 2016, Xilinx, Inc, + * Michal Simek <michal.simek@xilinx.com> + * Siva Durga Prasad <siva.durga.paladugu@xilinx.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <console.h> +#include <common.h> +#include <zynqmppl.h> +#include <linux/sizes.h> + +#define DUMMY_WORD 0xffffffff + +/* Xilinx binary format header */ +static const u32 bin_format[] = { + DUMMY_WORD, /* Dummy words */ + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + 0x000000bb, /* Sync word */ + 0x11220044, /* Sync word */ + DUMMY_WORD, + DUMMY_WORD, + 0xaa995566, /* Sync word */ +}; + +#define SWAP_NO 1 +#define SWAP_DONE 2 + +/* + * Load the whole word from unaligned buffer + * Keep in your mind that it is byte loading on little-endian system + */ +static u32 load_word(const void *buf, u32 swap) +{ + u32 word = 0; + u8 *bitc = (u8 *)buf; + int p; + + if (swap == SWAP_NO) { + for (p = 0; p < 4; p++) { + word <<= 8; + word |= bitc[p]; + } + } else { + for (p = 3; p >= 0; p--) { + word <<= 8; + word |= bitc[p]; + } + } + + return word; +} + +static u32 check_header(const void *buf) +{ + u32 i, pattern; + int swap = SWAP_NO; + u32 *test = (u32 *)buf; + + debug("%s: Let's check bitstream header\n", __func__); + + /* Checking that passing bin is not a bitstream */ + for (i = 0; i < ARRAY_SIZE(bin_format); i++) { + pattern = load_word(&test[i], swap); + + /* + * Bitstreams in binary format are swapped + * compare to regular bistream. + * Do not swap dummy word but if swap is done assume + * that parsing buffer is binary format + */ + if ((__swab32(pattern) != DUMMY_WORD) && + (__swab32(pattern) == bin_format[i])) { + swap = SWAP_DONE; + debug("%s: data swapped - let's swap\n", __func__); + } + + debug("%s: %d/%px: pattern %x/%x bin_format\n", __func__, i, + &test[i], pattern, bin_format[i]); + } + debug("%s: Found bitstream header at %px %s swapinng\n", __func__, + buf, swap == SWAP_NO ? "without" : "with"); + + return swap; +} + +static void *check_data(u8 *buf, size_t bsize, u32 *swap) +{ + u32 word, p = 0; /* possition */ + + /* Because buf doesn't need to be aligned let's read it by chars */ + for (p = 0; p < bsize; p++) { + word = load_word(&buf[p], SWAP_NO); + debug("%s: word %x %x/%px\n", __func__, word, p, &buf[p]); + + /* Find the first bitstream dummy word */ + if (word == DUMMY_WORD) { + debug("%s: Found dummy word at position %x/%px\n", + __func__, p, &buf[p]); + *swap = check_header(&buf[p]); + if (*swap) { + /* FIXME add full bitstream checking here */ + return &buf[p]; + } + } + /* Loop can be huge - support CTRL + C */ + if (ctrlc()) + return NULL; + } + return NULL; +} + +static ulong zynqmp_align_dma_buffer(u32 *buf, u32 len, u32 swap) +{ + u32 *new_buf; + u32 i; + + if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) { + new_buf = (u32 *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN); + + /* + * This might be dangerous but permits to flash if + * ARCH_DMA_MINALIGN is greater than header size + */ + if (new_buf > (u32 *)buf) { + debug("%s: Aligned buffer is after buffer start\n", + __func__); + new_buf -= ARCH_DMA_MINALIGN; + } + printf("%s: Align buffer at %px to %px(swap %d)\n", __func__, + buf, new_buf, swap); + + for (i = 0; i < (len/4); i++) + new_buf[i] = load_word(&buf[i], swap); + + buf = new_buf; + } else if (swap != SWAP_DONE) { + /* For bitstream which are aligned */ + u32 *new_buf = (u32 *)buf; + + printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__, + swap); + + for (i = 0; i < (len/4); i++) + new_buf[i] = load_word(&buf[i], swap); + } + + return (ulong)buf; +} + +static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf, + size_t bsize, u32 blocksize, u32 *swap) +{ + ulong *buf_start; + ulong diff; + + buf_start = check_data((u8 *)buf, blocksize, swap); + + if (!buf_start) + return FPGA_FAIL; + + /* Check if data is postpone from start */ + diff = (ulong)buf_start - (ulong)buf; + if (diff) { + printf("%s: Bitstream is not validated yet (diff %lx)\n", + __func__, diff); + return FPGA_FAIL; + } + + if ((ulong)buf < SZ_1M) { + printf("%s: Bitstream has to be placed up to 1MB (%px)\n", + __func__, buf); + return FPGA_FAIL; + } + + return 0; +} + +static int invoke_smc(ulong id, ulong reg0, ulong reg1, ulong reg2) +{ + struct pt_regs regs; + regs.regs[0] = id; + regs.regs[1] = reg0; + regs.regs[2] = reg1; + regs.regs[3] = reg2; + + smc_call(®s); + + return regs.regs[0]; +} + +static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize, + bitstream_type bstype) +{ + u32 swap; + ulong bin_buf, flags; + int ret; + + if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap)) + return FPGA_FAIL; + + bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap); + + debug("%s called!\n", __func__); + flush_dcache_range(bin_buf, bin_buf + bsize); + + if (bsize % 4) + bsize = bsize / 4 + 1; + else + bsize = bsize / 4; + + flags = (u32)bsize | ((u64)bstype << 32); + + ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, bin_buf, flags, 0); + if (ret) + debug("PL FPGA LOAD fail\n"); + + return ret; +} + +struct xilinx_fpga_op zynqmp_op = { + .load = zynqmp_load, +}; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 53470b90ce..f59134ff92 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -292,10 +292,7 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, sbsf->data->nr_sectors; } else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) { sbsf->erase_size = 4 << 10; - } else if (sbsf->cmd == CMD_ERASE_32K && (flags & SECT_32K)) { - sbsf->erase_size = 32 << 10; - } else if (sbsf->cmd == CMD_ERASE_64K && - !(flags & (SECT_4K | SECT_32K))) { + } else if (sbsf->cmd == CMD_ERASE_64K && !(flags & SECT_4K)) { sbsf->erase_size = 64 << 10; } else { debug(" cmd unknown: %#x\n", sbsf->cmd); diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index da2bb7b5d2..cde4cfbf2e 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -20,34 +20,6 @@ enum spi_dual_flash { SF_DUAL_PARALLEL_FLASH = BIT(1), }; -/* Enum list - Full read commands */ -enum spi_read_cmds { - ARRAY_SLOW = BIT(0), - ARRAY_FAST = BIT(1), - DUAL_OUTPUT_FAST = BIT(2), - QUAD_OUTPUT_FAST = BIT(3), - DUAL_IO_FAST = BIT(4), - QUAD_IO_FAST = BIT(5), -}; - -/* Normal - Extended - Full command set */ -#define RD_NORM (ARRAY_SLOW | ARRAY_FAST) -#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST) -#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST) - -/* sf param flags */ -enum { -#ifndef CONFIG_SPI_FLASH_USE_4K_SECTORS - SECT_4K = 0, -#else - SECT_4K = BIT(0), -#endif - SECT_32K = BIT(1), - E_FSR = BIT(2), - SST_WR = BIT(3), - WR_QPP = BIT(4), -}; - enum spi_nor_option_flags { SNOR_F_SST_WR = BIT(0), SNOR_F_USE_FSR = BIT(1), @@ -67,7 +39,6 @@ enum spi_nor_option_flags { /* Erase commands */ #define CMD_ERASE_4K 0x20 -#define CMD_ERASE_32K 0x52 #define CMD_ERASE_CHIP 0xc7 #define CMD_ERASE_64K 0xd8 @@ -141,7 +112,6 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len, * @sector_size: Isn't necessarily a sector size from vendor, * the size listed here is what works with CMD_ERASE_64K * @nr_sectors: No.of sectors on this device - * @e_rd_cmd: Enum list for read commands * @flags: Important param, for flash specific behaviour */ struct spi_flash_params { @@ -150,8 +120,17 @@ struct spi_flash_params { u16 ext_jedec; u32 sector_size; u32 nr_sectors; - u8 e_rd_cmd; + u16 flags; +#define SECT_4K BIT(0) +#define E_FSR BIT(1) +#define SST_WR BIT(2) +#define WR_QPP BIT(3) +#define RD_QUAD BIT(4) +#define RD_DUAL BIT(5) +#define RD_QUADIO BIT(6) +#define RD_DUALIO BIT(7) +#define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO) }; extern const struct spi_flash_params spi_flash_params_table[]; diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c index 70ca236ace..5b50114dda 100644 --- a/drivers/mtd/spi/sf_params.c +++ b/drivers/mtd/spi/sf_params.c @@ -15,122 +15,122 @@ /* SPI/QSPI flash device params structure */ const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"AT25DF321A", 0x1f4701, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, - {"AT25DF321", 0x1f4700, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, - {"AT26DF081A", 0x1f4501, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, + {"AT25DF321A", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT25DF321", 0x1f4700, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT26DF081A", 0x1f4501, 0x0, 64 * 1024, 16, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, RD_NORM, 0}, - {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, RD_NORM, 0}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, + {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */ - {"IS25LP032", 0x9d6016, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"IS25LP064", 0x9d6017, 0x0, 64 * 1024, 128, RD_NORM, 0}, - {"IS25LP128", 0x9d6018, 0x0, 64 * 1024, 256, RD_NORM, 0}, + {"IS25LP032", 0x9d6016, 0x0, 64 * 1024, 64, 0}, + {"IS25LP064", 0x9d6017, 0x0, 64 * 1024, 128, 0}, + {"IS25LP128", 0x9d6018, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, RD_NORM, 0}, - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, RD_NORM, 0}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, RD_NORM, 0}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, RD_NORM, 0}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, RD_NORM, 0}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP}, - {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, + {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP}, + {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, RD_NORM, 0}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, RD_NORM, 0}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, RD_NORM, 0}, - {"S25FL116K", 0x014015, 0x0, 64 * 1024, 128, RD_NORM, 0}, - {"S25FL164K", 0x014017, 0x0140, 64 * 1024, 128, RD_NORM, 0}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL, WR_QPP}, - {"S25FL128S_256K", 0x012018, 0x4d00, 256 * 1024, 64, RD_FULL, WR_QPP}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"S25FL256S_256K", 0x010219, 0x4d00, 256 * 1024, 128, RD_FULL, WR_QPP}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP}, - {"S25FS512S", 0x010220, 0x4D00, 128 * 1024, 512, RD_FULL, WR_QPP}, - {"S25FL512S_256K", 0x010220, 0x4d00, 256 * 1024, 256, RD_FULL, WR_QPP}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP}, - {"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL, WR_QPP}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, + {"S25FL116K", 0x014015, 0x0, 64 * 1024, 128, 0}, + {"S25FL164K", 0x014017, 0x0140, 64 * 1024, 128, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL | WR_QPP}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL | WR_QPP}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL | WR_QPP}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL | WR_QPP}, + {"S25FL128S_256K", 0x012018, 0x4d00, 256 * 1024, 64, RD_FULL | WR_QPP}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL | WR_QPP}, + {"S25FL256S_256K", 0x010219, 0x4d00, 256 * 1024, 128, RD_FULL | WR_QPP}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL | WR_QPP}, + {"S25FS512S", 0x010220, 0x4D00, 128 * 1024, 512, RD_FULL | WR_QPP}, + {"S25FL512S_256K", 0x010220, 0x4d00, 256 * 1024, 256, RD_FULL | WR_QPP}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL | WR_QPP}, + {"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL | WR_QPP}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, RD_NORM, 0}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, RD_NORM, 0}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, RD_NORM, 0}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, RD_NORM, 0}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, RD_NORM, 0}, - {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, RD_NORM, 0}, - {"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_EXTN, 0}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, RD_NORM, 0}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, RD_NORM, 0}, - {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"N25Q016A", 0x20bb15, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, + {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, 0}, + {"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, + {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q016A", 0x20bb15, 0x0, 64 * 1024, 32, SECT_4K}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K | SST_WR}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K | SST_WR}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, RD_NORM, SECT_4K | SST_WR}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, RD_NORM, SECT_4K | SST_WR}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K | SST_WR}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR}, - {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WR}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WR}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WR}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WR}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WR}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WR}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WR}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WR}, + {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, SECT_4K}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WR}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, RD_NORM, 0}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, RD_NORM, 0}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, RD_NORM, 0}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K}, #endif {}, /* Empty entry to terminate the list */ /* diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 64d4e0f947..7f6e9ae23e 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -1013,15 +1013,8 @@ int spi_flash_scan(struct spi_flash *flash) struct spi_slave *spi = flash->spi; const struct spi_flash_params *params; u16 jedec, ext_jedec; - u8 cmd, idcode[5]; + u8 idcode[5]; int ret; - static u8 spi_read_cmds_array[] = { - CMD_READ_ARRAY_SLOW, - CMD_READ_ARRAY_FAST, - CMD_READ_DUAL_OUTPUT_FAST, - CMD_READ_QUAD_OUTPUT_FAST, - CMD_READ_DUAL_IO_FAST, - CMD_READ_QUAD_IO_FAST }; /* Read the ID codes */ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); @@ -1162,14 +1155,14 @@ int spi_flash_scan(struct spi_flash *flash) flash->size <<= 1; #endif +#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS /* Compute erase sector and command */ if (params->flags & SECT_4K) { flash->erase_cmd = CMD_ERASE_4K; flash->erase_size = 4096 << flash->shift; - } else if (params->flags & SECT_32K) { - flash->erase_cmd = CMD_ERASE_32K; - flash->erase_size = 32768 << flash->shift; - } else { + } else +#endif + { flash->erase_cmd = CMD_ERASE_64K; flash->erase_size = flash->sector_size; } @@ -1177,17 +1170,16 @@ int spi_flash_scan(struct spi_flash *flash) /* Now erase size becomes valid sector size */ flash->sector_size = flash->erase_size; - /* Look for the fastest read cmd */ - cmd = fls(params->e_rd_cmd & spi->mode_rx); - if (cmd) { - cmd = spi_read_cmds_array[cmd - 1]; - flash->read_cmd = cmd; - } else { - /* Go for default supported read cmd */ - flash->read_cmd = CMD_READ_ARRAY_FAST; - } + /* Look for read commands */ + flash->read_cmd = CMD_READ_ARRAY_FAST; + if (spi->mode & SPI_RX_SLOW) + flash->read_cmd = CMD_READ_ARRAY_SLOW; + else if (spi->mode & SPI_RX_QUAD && params->flags & RD_QUAD) + flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST; + else if (spi->mode & SPI_RX_DUAL && params->flags & RD_DUAL) + flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST; - /* Not require to look for fastest only two write cmds yet */ + /* Look for write commands */ if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD) flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; else diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aca385d5e5..5da66a6de0 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -61,13 +61,6 @@ config FSL_DSPI this Freescale DSPI IP core. LS102xA and Colibri VF50/VF61 platforms use this driver. -config FSL_QSPI - bool "Freescale QSPI driver" - help - Enable the Freescale Quad-SPI (QSPI) driver. This driver can be - used to access the SPI NOR flash on platforms embedding this - Freescale IP core. - config ICH_SPI bool "Intel ICH SPI driver" help @@ -188,6 +181,13 @@ config FSL_ESPI access the SPI interface and SPI NOR flash on platforms embedding this Freescale eSPI IP core. +config FSL_QSPI + bool "Freescale QSPI driver" + help + Enable the Freescale Quad-SPI (QSPI) driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Freescale IP core. + config TI_QSPI bool "TI QSPI driver" help diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index a5244fff4d..1d50f135c9 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -251,7 +251,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen, break; case CQSPI_INDIRECT_READ: err = cadence_qspi_apb_indirect_read_setup(plat, - priv->cmd_len, dm_plat->mode_rx, cmd_buf); + priv->cmd_len, dm_plat->mode, cmd_buf); if (!err) { err = cadence_qspi_apb_indirect_read_execute (plat, data_bytes, din); diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 00b2fed7b7..caf0103dc3 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -649,10 +649,8 @@ static int ich_spi_child_pre_probe(struct udevice *dev) * ICH 7 SPI controller only supports array read command * and byte program command for SST flash */ - if (plat->ich_version == ICHV_7) { - slave->mode_rx = SPI_RX_SLOW; - slave->mode = SPI_TX_BYTE; - } + if (plat->ich_version == ICHV_7) + slave->mode = SPI_RX_SLOW | SPI_TX_BYTE; return 0; } diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 247abfa72b..d9c49e4e8c 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -164,7 +164,6 @@ static int spi_child_pre_probe(struct udevice *dev) slave->max_hz = plat->max_hz; slave->mode = plat->mode; - slave->mode_rx = plat->mode_rx; slave->wordlen = SPI_DEFAULT_WORDLEN; return 0; @@ -381,7 +380,7 @@ void spi_free_slave(struct spi_slave *slave) int spi_slave_ofdata_to_platdata(const void *blob, int node, struct dm_spi_slave_platdata *plat) { - int mode = 0, mode_rx = 0; + int mode = 0; int value; plat->cs = fdtdec_get_int(blob, node, "reg", -1); @@ -413,24 +412,22 @@ int spi_slave_ofdata_to_platdata(const void *blob, int node, break; } - plat->mode = mode; - value = fdtdec_get_uint(blob, node, "spi-rx-bus-width", 1); switch (value) { case 1: break; case 2: - mode_rx |= SPI_RX_DUAL; + mode |= SPI_RX_DUAL; break; case 4: - mode_rx |= SPI_RX_QUAD; + mode |= SPI_RX_QUAD; break; default: error("spi-rx-bus-width %d not supported\n", value); break; } - plat->mode_rx = mode_rx; + plat->mode = mode; return 0; } diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index bb72cb03ec..52520dff63 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -23,6 +23,9 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_TIMEOUT 2000000 #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 @@ -223,20 +226,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) { @@ -246,6 +263,7 @@ 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) { @@ -262,9 +280,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 */ @@ -336,7 +356,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 | @@ -422,7 +442,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 +456,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; diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 09ae1be7e9..15ca271ea4 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -92,7 +92,8 @@ static void zynq_spi_init_hw(struct zynq_spi_priv *priv) u32 confr; /* Disable SPI */ - writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr); + confr = ZYNQ_SPI_ENR_SPI_EN_MASK; + writel(~confr, ®s->enr); /* Disable Interrupts */ writel(ZYNQ_SPI_IXR_ALL_MASK, ®s->idr); @@ -173,8 +174,10 @@ static int zynq_spi_release_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; + u32 confr; - writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr); + confr = ZYNQ_SPI_ENR_SPI_EN_MASK; + writel(~confr, ®s->enr); return 0; } @@ -230,7 +233,7 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Read the data from RX FIFO */ status = readl(®s->isr); - while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) { + while ((status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) && rx_len) { buf = readl(®s->rxdr); if (rx_buf) *rx_buf++ = buf; |