Commit 968294bd authored by Tom Rini's avatar Tom Rini
Browse files

Merge branch 'master' of git://git.denx.de/u-boot-spi

parents b770e88a c4a79632
......@@ -170,7 +170,7 @@ static const struct dpll_params per_dpll_params_768mhz_es2[NUM_SYS_CLKS] = {
static const struct dpll_params per_dpll_params_768mhz_dra7xx[NUM_SYS_CLKS] = {
{32, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 12 MHz */
{96, 4, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 20 MHz */
{96, 4, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1}, /* 20 MHz */
{160, 6, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 16.8 MHz */
{20, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 19.2 MHz */
{192, 12, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 26 MHz */
......@@ -426,6 +426,10 @@ void enable_basic_clocks(void)
#ifdef CONFIG_DRIVER_TI_CPSW
(*prcm)->cm_gmac_gmac_clkctrl,
#endif
#ifdef CONFIG_TI_QSPI
(*prcm)->cm_l4per_qspi_clkctrl,
#endif
0
};
......@@ -454,6 +458,10 @@ void enable_basic_clocks(void)
clk_modules_explicit_en_essential,
1);
#ifdef CONFIG_TI_QSPI
setbits_le32((*prcm)->cm_l4per_qspi_clkctrl, (1<<24));
#endif
/* Enable SCRM OPT clocks for PER and CORE dpll */
setbits_le32((*prcm)->cm_wkupaon_scrm_clkctrl,
OPTFCLKEN_SCRM_PER_MASK);
......
......@@ -921,6 +921,7 @@ struct prcm_regs const dra7xx_prcm = {
.cm_l4per_gpio8_clkctrl = 0x4a009818,
.cm_l4per_mmcsd3_clkctrl = 0x4a009820,
.cm_l4per_mmcsd4_clkctrl = 0x4a009828,
.cm_l4per_qspi_clkctrl = 0x4a009838,
.cm_l4per_uart1_clkctrl = 0x4a009840,
.cm_l4per_uart2_clkctrl = 0x4a009848,
.cm_l4per_uart3_clkctrl = 0x4a009850,
......
......@@ -22,7 +22,7 @@ struct exynos_spi {
unsigned int rx_data; /* 0x1c */
unsigned int pkt_cnt; /* 0x20 */
unsigned char reserved2[4];
unsigned char reserved3[4];
unsigned int swap_cfg; /* 0x28 */
unsigned int fb_clk; /* 0x2c */
unsigned char padding[0xffd0];
};
......@@ -62,5 +62,14 @@ struct exynos_spi {
/* Packet Count */
#define SPI_PACKET_CNT_EN (1 << 16)
/* Swap config */
#define SPI_TX_SWAP_EN (1 << 0)
#define SPI_TX_BYTE_SWAP (1 << 2)
#define SPI_TX_HWORD_SWAP (1 << 3)
#define SPI_TX_BYTE_SWAP (1 << 2)
#define SPI_RX_SWAP_EN (1 << 4)
#define SPI_RX_BYTE_SWAP (1 << 6)
#define SPI_RX_HWORD_SWAP (1 << 7)
#endif /* __ASSEMBLY__ */
#endif
......@@ -61,6 +61,9 @@
/* GPMC */
#define OMAP54XX_GPMC_BASE 0x50000000
/* QSPI */
#define QSPI_BASE 0x4B300000
/*
* Hardware Register Details
*/
......
......@@ -15,6 +15,7 @@
#define BOOT_DEVICE_MMC1 5
#define BOOT_DEVICE_MMC2 6
#define BOOT_DEVICE_MMC2_2 7
#define BOOT_DEVICE_SPI 10
#define MMC_BOOT_DEVICES_START BOOT_DEVICE_MMC1
#define MMC_BOOT_DEVICES_END BOOT_DEVICE_MMC2_2
......
......@@ -266,6 +266,7 @@ struct prcm_regs {
u32 cm_l4per_mmcsd4_clkctrl;
u32 cm_l4per_msprohg_clkctrl;
u32 cm_l4per_slimbus2_clkctrl;
u32 cm_l4per_qspi_clkctrl;
u32 cm_l4per_uart1_clkctrl;
u32 cm_l4per_uart2_clkctrl;
u32 cm_l4per_uart3_clkctrl;
......
......@@ -51,5 +51,15 @@ const struct pad_conf_entry core_padconf_array_essential[] = {
{RGMII0_RXD2, (IEN | M0) },
{RGMII0_RXD1, (IEN | M0) },
{RGMII0_RXD0, (IEN | M0) },
{GPMC_A13, (IEN | PDIS | M1)}, /* QSPI1_RTCLK */
{GPMC_A14, (IEN | PDIS | M1)}, /* QSPI1_D[3] */
{GPMC_A15, (IEN | PDIS | M1)}, /* QSPI1_D[2] */
{GPMC_A16, (IEN | PDIS | M1)}, /* QSPI1_D[1] */
{GPMC_A17, (IEN | PDIS | M1)}, /* QSPI1_D[0] */
{GPMC_A18, (M1)}, /* QSPI1_SCLK */
{GPMC_A3, (IEN | PDIS | M1)}, /* QSPI1_CS2 */
{GPMC_A4, (IEN | PDIS | M1)}, /* QSPI1_CS3 */
{GPMC_CS2, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS0 */
{GPMC_CS3, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS1*/
};
#endif /* _MUX_DATA_DRA7XX_H_ */
-------------------------------------------------
Simple steps used to test the QSPI at U-Boot
-------------------------------------------------
For #1, build the patched U-Boot and load MLO/u-boot.img
----------------------------------
Boot from another medium like MMC
----------------------------------
U-Boot# mmc dev 0
mmc0 is current device
U-Boot# fatload mmc 0 0x82000000 MLO
reading MLO
55872 bytes read in 8 ms (6.7 MiB/s)
U-Boot# fatload mmc 0 0x83000000 u-boot.img
reading u-boot.img
248600 bytes read in 19 ms (12.5 MiB/s)
--------------------------------------------------
Commands to erase/write u-boot/mlo to flash device
--------------------------------------------------
U-Boot# sf probe 0
SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB, mapped at 5c000000
SF: Warning - Only lower 16MiB accessible, Full access #define CONFIG_SPI_FLASH_BAR
U-Boot# sf erase 0 0x10000
SF: 65536 bytes @ 0x0 Erased: OK
U-Boot# sf erase 0x20000 0x10000
SF: 65536 bytes @ 0x20000 Erased: OK
U-Boot# sf erase 0x30000 0x10000
SF: 65536 bytes @ 0x30000 Erased: OK
U-Boot# sf erase 0x40000 0x10000
SF: 65536 bytes @ 0x40000 Erased: OK
U-Boot# sf erase 0x50000 0x10000
SF: 65536 bytes @ 0x50000 Erased: OK
U-Boot# sf erase 0x60000 0x10000
SF: 65536 bytes @ 0x60000 Erased: OK
U-Boot# sf write 82000000 0 0x10000
SF: 65536 bytes @ 0x0 Written: OK
U-Boot# sf write 83000000 0x20000 0x60000
SF: 393216 bytes @ 0x20000 Written: OK
For #2, set sysboot to QSPI-1 boot mode(SYSBOOT[5:0] = 100110) and power
on. ROM should find the GP header at offset 0 and load/execute SPL. SPL
then detects that ROM was in QSPI-1 mode (boot code 10) and attempts to
find a U-Boot image header at offset 0x20000 (set in the config file)
and proceeds to load that image using the U-Boot image payload offset/size
from the header. It will then start U-Boot.
QSPI U-boot support
------------------
Host processor is connected to serial flash device via qpsi
interface. QSPI is a kind of spi module that allows single,
dual and quad read access to external spi devices. The module
has a memory mapped interface which provide direct interface
for accessing data form external spi devices.
The one QSPI in the device is primarily intended for fast booting
from Quad SPI flash devices.
Usecase
-------
MLO/u-boot.img will be flashed from SD/MMC to the flash device
using serial flash erase and write commands. Then, switch settings
will be changed to qspi boot. Then, the ROM code will read MLO
from the predefined location in the flash, where it was flashed and
execute it after storing it in SDRAM. Then, the MLO will read
u-boot.img from flash and execute it from SDRAM.
SPI mode
-------
SPI mode uses mtd spi framework for transfer and reception of data.
Can be used in:
1. Normal mode: use single pin for transfers
2. Dual Mode: use two pins for transfers.
3. Quad mode: use four pin for transfer
Memory mapped read mode
-----------------------
In this, SPI controller is configured using configuration port and then
controler is switched to memory mapped port for data read.
Driver
------
drivers/qspi/ti_qspi.c
- Newly created file which is responsible for configuring the
qspi controller and also for providing the low level api which
is responsible for transferring the datas from host controller
to flash device and vice versa.
Testing
-------
A seperated file named README.dra_qspi_test has been created which gives all the
details about the commands required to test qspi at u-boot level.
Status on SPI subsystem:
=======================
SPI COMMAND (common/cmd_sf, cmd_spi):
-
SPI FLASH (drivers/mtd/spi):
- sf_probe.c: SPI flash probing code.
- sf_ops.c: SPI flash operations code.
- sf.c: SPI flash interface, which interacts controller driver.
- Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing)
- Added memory_mapped support for read operations.
- Common probe support for all supported flash vendors except, ramtron.
SPI DRIVERS (drivers/spi):
-
TODO:
- Runtime detection of spi_flash params, SFDP(if possible)
- Add support for multibus build/accessing.
- Extended read commands support(dual read, dual IO read)
- Quad Page Program support.
- Quad Read support(quad fast read, quad IO read)
- Dual flash connection topology support(accessing two spi flash memories with single cs)
- Banking support on dual flash connection topology.
- Need proper cleanups on spi_flash and drivers.
--
Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>
18-09-2013.
07-10-2013.
......@@ -14,16 +14,11 @@ COBJS-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o
COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
endif
COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o
COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o
COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o
COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o
COBJS-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o
COBJS-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o
COBJS-$(CONFIG_SPI_FLASH_SST) += sst.o
COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o
COBJS-$(CONFIG_SPI_FLASH_WINBOND) += winbond.o
COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
ifdef CONFIG_CMD_SF
COBJS-y += sf.o
endif
COBJS-$(CONFIG_SPI_FLASH) += sf_probe.o sf_ops.o
COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
COBJS := $(COBJS-y)
......
/*
* Atmel SPI DataFlash support
*
* Copyright (C) 2008 Atmel Corporation
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <malloc.h>
#include <spi_flash.h>
#include "spi_flash_internal.h"
/* AT45-specific commands */
#define CMD_AT45_READ_STATUS 0xd7
#define CMD_AT45_ERASE_PAGE 0x81
#define CMD_AT45_LOAD_PROG_BUF1 0x82
#define CMD_AT45_LOAD_BUF1 0x84
#define CMD_AT45_LOAD_PROG_BUF2 0x85
#define CMD_AT45_LOAD_BUF2 0x87
#define CMD_AT45_PROG_BUF1 0x88
#define CMD_AT45_PROG_BUF2 0x89
/* AT45 status register bits */
#define AT45_STATUS_P2_PAGE_SIZE (1 << 0)
#define AT45_STATUS_READY (1 << 7)
/* DataFlash family IDs, as obtained from the second idcode byte */
#define DF_FAMILY_AT26F 0
#define DF_FAMILY_AT45 1
#define DF_FAMILY_AT26DF 2 /* AT25DF and AT26DF */
struct atmel_spi_flash_params {
u8 idcode1;
/* Log2 of page size in power-of-two mode */
u8 l2_page_size;
u8 pages_per_block;
u8 blocks_per_sector;
u8 nr_sectors;
const char *name;
};
/* spi_flash needs to be first so upper layers can free() it */
struct atmel_spi_flash {
struct spi_flash flash;
const struct atmel_spi_flash_params *params;
};
static inline struct atmel_spi_flash *
to_atmel_spi_flash(struct spi_flash *flash)
{
return container_of(flash, struct atmel_spi_flash, flash);
}
static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
{
.idcode1 = 0x22,
.l2_page_size = 8,
.pages_per_block = 8,
.blocks_per_sector = 16,
.nr_sectors = 4,
.name = "AT45DB011D",
},
{
.idcode1 = 0x23,
.l2_page_size = 8,
.pages_per_block = 8,
.blocks_per_sector = 16,
.nr_sectors = 8,
.name = "AT45DB021D",
},
{
.idcode1 = 0x24,
.l2_page_size = 8,
.pages_per_block = 8,
.blocks_per_sector = 32,
.nr_sectors = 8,
.name = "AT45DB041D",
},
{
.idcode1 = 0x25,
.l2_page_size = 8,
.pages_per_block = 8,
.blocks_per_sector = 32,
.nr_sectors = 16,
.name = "AT45DB081D",
},
{
.idcode1 = 0x26,
.l2_page_size = 9,
.pages_per_block = 8,
.blocks_per_sector = 32,
.nr_sectors = 16,
.name = "AT45DB161D",
},
{
.idcode1 = 0x27,
.l2_page_size = 9,
.pages_per_block = 8,
.blocks_per_sector = 64,
.nr_sectors = 64,
.name = "AT45DB321D",
},
{
.idcode1 = 0x28,
.l2_page_size = 10,
.pages_per_block = 8,
.blocks_per_sector = 32,
.nr_sectors = 32,
.name = "AT45DB642D",
},
{
.idcode1 = 0x47,
.l2_page_size = 8,
.pages_per_block = 16,
.blocks_per_sector = 16,
.nr_sectors = 64,
.name = "AT25DF321",
},
};
static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout)
{
struct spi_slave *spi = flash->spi;
unsigned long timebase;
int ret;
u8 cmd = CMD_AT45_READ_STATUS;
u8 status;
timebase = get_timer(0);
ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
if (ret)
return -1;
do {
ret = spi_xfer(spi, 8, NULL, &status, 0);
if (ret)
return -1;
if (status & AT45_STATUS_READY)
break;
} while (get_timer(timebase) < timeout);
/* Deactivate CS */
spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
if (status & AT45_STATUS_READY)
return 0;
/* Timed out */
return -1;
}
/*
* Assemble the address part of a command for AT45 devices in
* non-power-of-two page size mode.
*/
static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset)
{
unsigned long page_addr;
unsigned long byte_addr;
unsigned long page_size;
unsigned int page_shift;
/*
* The "extra" space per page is the power-of-two page size
* divided by 32.
*/
page_shift = asf->params->l2_page_size;
page_size = (1 << page_shift) + (1 << (page_shift - 5));
page_shift++;
page_addr = offset / page_size;
byte_addr = offset % page_size;
cmd[0] = page_addr >> (16 - page_shift);
cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8);
cmd[2] = byte_addr;
}
static int dataflash_read_fast_at45(struct spi_flash *flash,
u32 offset, size_t len, void *buf)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
u8 cmd[5];
cmd[0] = CMD_READ_ARRAY_FAST;
at45_build_address(asf, cmd + 1, offset);
cmd[4] = 0x00;
return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
}
/*
* TODO: the two write funcs (_p2/_at45) should get unified ...
*/
static int dataflash_write_p2(struct spi_flash *flash,
u32 offset, size_t len, const void *buf)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
unsigned long page_size;
u32 addr = offset;
size_t chunk_len;
size_t actual;
int ret;
u8 cmd[4];
/*
* TODO: This function currently uses only page buffer #1. We can
* speed this up by using both buffers and loading one buffer while
* the other is being programmed into main memory.
*/
page_size = (1 << asf->params->l2_page_size);
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: Unable to claim SPI bus\n");
return ret;
}
for (actual = 0; actual < len; actual += chunk_len) {
chunk_len = min(len - actual, page_size - (addr % page_size));
/* Use the same address bits for both commands */
cmd[0] = CMD_AT45_LOAD_BUF1;
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr;
ret = spi_flash_cmd_write(flash->spi, cmd, 4,
buf + actual, chunk_len);
if (ret < 0) {
debug("SF: Loading AT45 buffer failed\n");
goto out;
}
cmd[0] = CMD_AT45_PROG_BUF1;
ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
if (ret < 0) {
debug("SF: AT45 page programming failed\n");
goto out;
}
ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug("SF: AT45 page programming timed out\n");
goto out;
}
addr += chunk_len;
}
debug("SF: AT45: Successfully programmed %zu bytes @ 0x%x\n",
len, offset);
ret = 0;
out:
spi_release_bus(flash->spi);
return ret;
}
static int dataflash_write_at45(struct spi_flash *flash,
u32 offset, size_t len, const void *buf)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
unsigned long page_addr;
unsigned long byte_addr;
unsigned long page_size;
unsigned int page_shift;
size_t chunk_len;
size_t actual;
int ret;
u8 cmd[4];
/*
* TODO: This function currently uses only page buffer #1. We can
* speed this up by using both buffers and loading one buffer while
* the other is being programmed into main memory.
*/
page_shift = asf->params->l2_page_size;
page_size = (1 << page_shift) + (1 << (page_shift - 5));
page_shift++;
page_addr = offset / page_size;
byte_addr = offset % page_size;
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: Unable to claim SPI bus\n");
return ret;
}
for (actual = 0; actual < len; actual += chunk_len) {
chunk_len = min(len - actual, page_size - byte_addr);
/* Use the same address bits for both commands */
cmd[0] = CMD_AT45_LOAD_BUF1;
cmd[1] = page_addr >> (16 - page_shift);
cmd[2] = page_addr << (page_shift - 8) | (byte_addr >> 8);
cmd[3] = byte_addr;
ret = spi_flash_cmd_write(flash->spi, cmd, 4,
buf + actual, chunk_len);
if (ret < 0) {
debug("SF: Loading AT45 buffer failed\n");
goto out;
}
cmd[0] = CMD_AT45_PROG_BUF1;
ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
if (ret < 0) {
debug("SF: AT45 page programming failed\n");
goto out;
}
ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret < 0) {
debug("SF: AT45 page programming timed out\n");
goto out;
}
page_addr++;
byte_addr = 0;
}
debug("SF: AT45: Successfully programmed %zu bytes @ 0x%x\n",
len, offset);
ret = 0;
out:
spi_release_bus(flash->spi);
return ret;
}
/*
* TODO: the two erase funcs (_p2/_at45) should get unified ...
*/
static int dataflash_erase_p2(struct spi_flash *flash, u32 offset, size_t len)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
unsigned long page_size;
size_t actual;
int ret;
u8 cmd[4];
/*
* TODO: This function currently uses page erase only. We can
* probably speed things up by using block and/or sector erase
* when possible.
*/
page_size = (1 << asf->params->l2_page_size);