spi: ich: Configure SPI BIOS parameters for Linux upon U-Boot exit

This patch adds a remove function to the Intel ICH SPI driver, that will
be called upon U-Boot exit, directly before the OS (Linux) is started.
This function takes care of configuring the BIOS registers in the SPI
controller (similar to what a "standard" BIOS or coreboot does), so that
the Linux MTD device driver is able to correctly read/write to the SPI
NOR chip. Without this, the chip is not detected at all.

Signed-off-by: Stefan Roese <sr@denx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
Cc: Bin Meng <bmeng.cn@gmail.com>
Cc: Jagan Teki <jteki@openedev.com>
This commit is contained in:
Stefan Roese 2017-04-24 09:48:04 +02:00 committed by Bin Meng
parent 7025b05415
commit 4759dffe23
2 changed files with 65 additions and 7 deletions

View File

@ -617,6 +617,22 @@ static int ich_spi_probe(struct udevice *dev)
return 0;
}
static int ich_spi_remove(struct udevice *bus)
{
struct ich_spi_priv *ctlr = dev_get_priv(bus);
/*
* Configure SPI controller so that the Linux MTD driver can fully
* access the SPI NOR chip
*/
ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop);
ich_writew(ctlr, SPI_OPTYPE, ctlr->optype);
ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu);
ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
return 0;
}
static int ich_spi_set_speed(struct udevice *bus, uint speed)
{
struct ich_spi_priv *priv = dev_get_priv(bus);
@ -700,4 +716,6 @@ U_BOOT_DRIVER(ich_spi) = {
.priv_auto_alloc_size = sizeof(struct ich_spi_priv),
.child_pre_probe = ich_spi_child_pre_probe,
.probe = ich_spi_probe,
.remove = ich_spi_remove,
.flags = DM_FLAG_OS_PREPARE,
};

View File

@ -101,13 +101,6 @@ enum {
HSFC_FSMIE = 0x8000
};
enum {
SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0,
SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1,
SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2,
SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3
};
enum {
ICH_MAX_CMD_LEN = 5,
};
@ -124,8 +117,55 @@ struct spi_trans {
uint32_t offset;
};
#define SPI_OPCODE_WRSR 0x01
#define SPI_OPCODE_PAGE_PROGRAM 0x02
#define SPI_OPCODE_READ 0x03
#define SPI_OPCODE_WRDIS 0x04
#define SPI_OPCODE_RDSR 0x05
#define SPI_OPCODE_WREN 0x06
#define SPI_OPCODE_FAST_READ 0x0b
#define SPI_OPCODE_ERASE_SECT 0x20
#define SPI_OPCODE_READ_ID 0x9f
#define SPI_OPCODE_ERASE_BLOCK 0xd8
#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
#define SPI_OPMENU_0 SPI_OPCODE_WRSR
#define SPI_OPTYPE_0 SPI_OPCODE_TYPE_WRITE_NO_ADDRESS
#define SPI_OPMENU_1 SPI_OPCODE_PAGE_PROGRAM
#define SPI_OPTYPE_1 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
#define SPI_OPMENU_2 SPI_OPCODE_READ
#define SPI_OPTYPE_2 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
#define SPI_OPMENU_3 SPI_OPCODE_RDSR
#define SPI_OPTYPE_3 SPI_OPCODE_TYPE_READ_NO_ADDRESS
#define SPI_OPMENU_4 SPI_OPCODE_ERASE_SECT
#define SPI_OPTYPE_4 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
#define SPI_OPMENU_5 SPI_OPCODE_READ_ID
#define SPI_OPTYPE_5 SPI_OPCODE_TYPE_READ_NO_ADDRESS
#define SPI_OPMENU_6 SPI_OPCODE_ERASE_BLOCK
#define SPI_OPTYPE_6 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
#define SPI_OPMENU_7 SPI_OPCODE_FAST_READ
#define SPI_OPTYPE_7 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
#define SPI_OPPREFIX ((SPI_OPCODE_WREN << 8) | SPI_OPCODE_WREN)
#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \
(SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) | \
(SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) | \
(SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0 << 0))
#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \
(SPI_OPMENU_5 << 8) | (SPI_OPMENU_4 << 0))
#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
(SPI_OPMENU_1 << 8) | (SPI_OPMENU_0 << 0))
enum ich_version {
ICHV_7,