soc/fsp_baytrail: fix flashconsole on platform
Include spi.c in romstage. Since FSP 1.0 can't use NO_CAR_GLOBAL_MIGRATION, adjust global variables in spi.c to use CAR_GLOBAL. Adapted from early versions of CB:21107 Change-Id: I3487fb8ac317ce920bf1c3ef9d89590051932378 Signed-off-by: Matt DeVillier <matt.devillier@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32879 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
This commit is contained in:
committed by
Patrick Georgi
parent
8ef2a45bb9
commit
1caa3143d6
@ -35,6 +35,7 @@ romstage-y += tsc_freq.c
|
|||||||
postcar-y += tsc_freq.c
|
postcar-y += tsc_freq.c
|
||||||
smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c
|
smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c
|
||||||
ramstage-y += spi.c
|
ramstage-y += spi.c
|
||||||
|
romstage-y += spi.c
|
||||||
smm-$(CONFIG_HAVE_SMI_HANDLER) += spi.c
|
smm-$(CONFIG_HAVE_SMI_HANDLER) += spi.c
|
||||||
ramstage-y += chip.c
|
ramstage-y += chip.c
|
||||||
ramstage-y += iosf.c
|
ramstage-y += iosf.c
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* This file is derived from the flashrom project. */
|
/* This file is derived from the flashrom project. */
|
||||||
|
#include <arch/early_variables.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <commonlib/helpers.h>
|
#include <commonlib/helpers.h>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
typedef struct spi_slave ich_spi_slave;
|
typedef struct spi_slave ich_spi_slave;
|
||||||
|
|
||||||
static int ichspi_lock = 0;
|
static int g_ichspi_lock CAR_GLOBAL = 0;
|
||||||
|
|
||||||
typedef struct ich9_spi_regs {
|
typedef struct ich9_spi_regs {
|
||||||
uint32_t bfpr;
|
uint32_t bfpr;
|
||||||
@ -81,7 +81,7 @@ typedef struct ich_spi_controller {
|
|||||||
uint16_t *control;
|
uint16_t *control;
|
||||||
} ich_spi_controller;
|
} ich_spi_controller;
|
||||||
|
|
||||||
static ich_spi_controller cntlr;
|
static ich_spi_controller g_cntlr CAR_GLOBAL;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SPIS_SCIP = 0x0001,
|
SPIS_SCIP = 0x0001,
|
||||||
@ -239,18 +239,19 @@ static ich9_spi_regs *spi_regs(void)
|
|||||||
|
|
||||||
void spi_init(void)
|
void spi_init(void)
|
||||||
{
|
{
|
||||||
|
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
||||||
ich9_spi_regs *ich9_spi = spi_regs();
|
ich9_spi_regs *ich9_spi = spi_regs();
|
||||||
|
|
||||||
ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN;
|
car_set_var(g_ichspi_lock, readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN);
|
||||||
cntlr.opmenu = ich9_spi->opmenu;
|
cntlr->opmenu = ich9_spi->opmenu;
|
||||||
cntlr.menubytes = sizeof(ich9_spi->opmenu);
|
cntlr->menubytes = sizeof(ich9_spi->opmenu);
|
||||||
cntlr.optype = &ich9_spi->optype;
|
cntlr->optype = &ich9_spi->optype;
|
||||||
cntlr.addr = &ich9_spi->faddr;
|
cntlr->addr = &ich9_spi->faddr;
|
||||||
cntlr.data = (uint8_t *)ich9_spi->fdata;
|
cntlr->data = (uint8_t *)ich9_spi->fdata;
|
||||||
cntlr.databytes = sizeof(ich9_spi->fdata);
|
cntlr->databytes = sizeof(ich9_spi->fdata);
|
||||||
cntlr.status = &ich9_spi->ssfs;
|
cntlr->status = &ich9_spi->ssfs;
|
||||||
cntlr.control = (uint16_t *)ich9_spi->ssfc;
|
cntlr->control = (uint16_t *)ich9_spi->ssfc;
|
||||||
cntlr.preop = &ich9_spi->preop;
|
cntlr->preop = &ich9_spi->preop;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct spi_transaction {
|
typedef struct spi_transaction {
|
||||||
@ -311,17 +312,18 @@ static void spi_setup_type(spi_transaction *trans)
|
|||||||
|
|
||||||
static int spi_setup_opcode(spi_transaction *trans)
|
static int spi_setup_opcode(spi_transaction *trans)
|
||||||
{
|
{
|
||||||
|
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
||||||
uint16_t optypes;
|
uint16_t optypes;
|
||||||
uint8_t opmenu[cntlr.menubytes];
|
uint8_t opmenu[cntlr->menubytes];
|
||||||
|
|
||||||
trans->opcode = trans->out[0];
|
trans->opcode = trans->out[0];
|
||||||
spi_use_out(trans, 1);
|
spi_use_out(trans, 1);
|
||||||
if (!ichspi_lock) {
|
if (!car_get_var(g_ichspi_lock)) {
|
||||||
/* The lock is off, so just use index 0. */
|
/* The lock is off, so just use index 0. */
|
||||||
writeb_(trans->opcode, cntlr.opmenu);
|
writeb_(trans->opcode, cntlr->opmenu);
|
||||||
optypes = readw_(cntlr.optype);
|
optypes = readw_(cntlr->optype);
|
||||||
optypes = (optypes & 0xfffc) | (trans->type & 0x3);
|
optypes = (optypes & 0xfffc) | (trans->type & 0x3);
|
||||||
writew_(optypes, cntlr.optype);
|
writew_(optypes, cntlr->optype);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
/* The lock is on. See if what we need is on the menu. */
|
/* The lock is on. See if what we need is on the menu. */
|
||||||
@ -332,20 +334,20 @@ static int spi_setup_opcode(spi_transaction *trans)
|
|||||||
if (trans->opcode == SPI_OPCODE_WREN)
|
if (trans->opcode == SPI_OPCODE_WREN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
read_reg(cntlr.opmenu, opmenu, sizeof(opmenu));
|
read_reg(cntlr->opmenu, opmenu, sizeof(opmenu));
|
||||||
for (opcode_index = 0; opcode_index < cntlr.menubytes;
|
for (opcode_index = 0; opcode_index < cntlr->menubytes;
|
||||||
opcode_index++) {
|
opcode_index++) {
|
||||||
if (opmenu[opcode_index] == trans->opcode)
|
if (opmenu[opcode_index] == trans->opcode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode_index == cntlr.menubytes) {
|
if (opcode_index == cntlr->menubytes) {
|
||||||
printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n",
|
printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n",
|
||||||
trans->opcode);
|
trans->opcode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
optypes = readw_(cntlr.optype);
|
optypes = readw_(cntlr->optype);
|
||||||
optype = (optypes >> (opcode_index * 2)) & 0x3;
|
optype = (optypes >> (opcode_index * 2)) & 0x3;
|
||||||
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
|
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
|
||||||
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
|
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
|
||||||
@ -391,14 +393,15 @@ static int spi_setup_offset(spi_transaction *trans)
|
|||||||
*/
|
*/
|
||||||
static int ich_status_poll(uint16_t bitmask, int wait_til_set)
|
static int ich_status_poll(uint16_t bitmask, int wait_til_set)
|
||||||
{
|
{
|
||||||
|
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
||||||
int timeout = 40000; /* This will result in 400 ms */
|
int timeout = 40000; /* This will result in 400 ms */
|
||||||
uint16_t status = 0;
|
uint16_t status = 0;
|
||||||
|
|
||||||
while (timeout--) {
|
while (timeout--) {
|
||||||
status = readw_(cntlr.status);
|
status = readw_(cntlr->status);
|
||||||
if (wait_til_set ^ ((status & bitmask) == 0)) {
|
if (wait_til_set ^ ((status & bitmask) == 0)) {
|
||||||
if (wait_til_set)
|
if (wait_til_set)
|
||||||
writew_((status & bitmask), cntlr.status);
|
writew_((status & bitmask), cntlr->status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
udelay(10);
|
udelay(10);
|
||||||
@ -412,6 +415,7 @@ static int ich_status_poll(uint16_t bitmask, int wait_til_set)
|
|||||||
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
||||||
size_t bytesout, void *din, size_t bytesin)
|
size_t bytesout, void *din, size_t bytesin)
|
||||||
{
|
{
|
||||||
|
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
||||||
uint16_t control;
|
uint16_t control;
|
||||||
int16_t opcode_index;
|
int16_t opcode_index;
|
||||||
int with_address;
|
int with_address;
|
||||||
@ -437,7 +441,7 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
if (ich_status_poll(SPIS_SCIP, 0) == -1)
|
if (ich_status_poll(SPIS_SCIP, 0) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
writew_(SPIS_CDS | SPIS_FCERR, cntlr.status);
|
writew_(SPIS_CDS | SPIS_FCERR, cntlr->status);
|
||||||
|
|
||||||
spi_setup_type(&trans);
|
spi_setup_type(&trans);
|
||||||
if ((opcode_index = spi_setup_opcode(&trans)) < 0)
|
if ((opcode_index = spi_setup_opcode(&trans)) < 0)
|
||||||
@ -445,13 +449,13 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
if ((with_address = spi_setup_offset(&trans)) < 0)
|
if ((with_address = spi_setup_offset(&trans)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!ichspi_lock && trans.opcode == SPI_OPCODE_WREN) {
|
if (!car_get_var(g_ichspi_lock) && trans.opcode == SPI_OPCODE_WREN) {
|
||||||
/*
|
/*
|
||||||
* Treat Write Enable as Atomic Pre-Op if possible
|
* Treat Write Enable as Atomic Pre-Op if possible
|
||||||
* in order to prevent the Management Engine from
|
* in order to prevent the Management Engine from
|
||||||
* issuing a transaction between WREN and DATA.
|
* issuing a transaction between WREN and DATA.
|
||||||
*/
|
*/
|
||||||
writew_(trans.opcode, cntlr.preop);
|
writew_(trans.opcode, cntlr->preop);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,13 +463,13 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
|
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
|
||||||
|
|
||||||
/* Issue atomic preop cycle if needed */
|
/* Issue atomic preop cycle if needed */
|
||||||
if (readw_(cntlr.preop))
|
if (readw_(cntlr->preop))
|
||||||
control |= SPIC_ACS;
|
control |= SPIC_ACS;
|
||||||
|
|
||||||
if (!trans.bytesout && !trans.bytesin) {
|
if (!trans.bytesout && !trans.bytesin) {
|
||||||
/* SPI addresses are 24 bit only */
|
/* SPI addresses are 24 bit only */
|
||||||
if (with_address)
|
if (with_address)
|
||||||
writel_(trans.offset & 0x00FFFFFF, cntlr.addr);
|
writel_(trans.offset & 0x00FFFFFF, cntlr->addr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a 'no data' command (like Write Enable), its
|
* This is a 'no data' command (like Write Enable), its
|
||||||
@ -473,7 +477,7 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
* spi_setup_opcode() above. Tell the chip to send the
|
* spi_setup_opcode() above. Tell the chip to send the
|
||||||
* command.
|
* command.
|
||||||
*/
|
*/
|
||||||
writew_(control, cntlr.control);
|
writew_(control, cntlr->control);
|
||||||
|
|
||||||
/* wait for the result */
|
/* wait for the result */
|
||||||
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
|
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
|
||||||
@ -495,7 +499,7 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
* and followed by other SPI commands, and this sequence is controlled
|
* and followed by other SPI commands, and this sequence is controlled
|
||||||
* by the SPI chip driver.
|
* by the SPI chip driver.
|
||||||
*/
|
*/
|
||||||
if (trans.bytesout > cntlr.databytes) {
|
if (trans.bytesout > cntlr->databytes) {
|
||||||
printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use"
|
printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use"
|
||||||
" spi_crop_chunk()?\n");
|
" spi_crop_chunk()?\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -509,28 +513,28 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
uint32_t data_length;
|
uint32_t data_length;
|
||||||
|
|
||||||
/* SPI addresses are 24 bit only */
|
/* SPI addresses are 24 bit only */
|
||||||
writel_(trans.offset & 0x00FFFFFF, cntlr.addr);
|
writel_(trans.offset & 0x00FFFFFF, cntlr->addr);
|
||||||
|
|
||||||
if (trans.bytesout)
|
if (trans.bytesout)
|
||||||
data_length = min(trans.bytesout, cntlr.databytes);
|
data_length = min(trans.bytesout, cntlr->databytes);
|
||||||
else
|
else
|
||||||
data_length = min(trans.bytesin, cntlr.databytes);
|
data_length = min(trans.bytesin, cntlr->databytes);
|
||||||
|
|
||||||
/* Program data into FDATA0 to N */
|
/* Program data into FDATA0 to N */
|
||||||
if (trans.bytesout) {
|
if (trans.bytesout) {
|
||||||
write_reg(trans.out, cntlr.data, data_length);
|
write_reg(trans.out, cntlr->data, data_length);
|
||||||
spi_use_out(&trans, data_length);
|
spi_use_out(&trans, data_length);
|
||||||
if (with_address)
|
if (with_address)
|
||||||
trans.offset += data_length;
|
trans.offset += data_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add proper control fields' values */
|
/* Add proper control fields' values */
|
||||||
control &= ~((cntlr.databytes - 1) << 8);
|
control &= ~((cntlr->databytes - 1) << 8);
|
||||||
control |= SPIC_DS;
|
control |= SPIC_DS;
|
||||||
control |= (data_length - 1) << 8;
|
control |= (data_length - 1) << 8;
|
||||||
|
|
||||||
/* write it */
|
/* write it */
|
||||||
writew_(control, cntlr.control);
|
writew_(control, cntlr->control);
|
||||||
|
|
||||||
/* Wait for Cycle Done Status or Flash Cycle Error. */
|
/* Wait for Cycle Done Status or Flash Cycle Error. */
|
||||||
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
|
status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
|
||||||
@ -543,7 +547,7 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (trans.bytesin) {
|
if (trans.bytesin) {
|
||||||
read_reg(cntlr.data, trans.in, data_length);
|
read_reg(cntlr->data, trans.in, data_length);
|
||||||
spi_use_in(&trans, data_length);
|
spi_use_in(&trans, data_length);
|
||||||
if (with_address)
|
if (with_address)
|
||||||
trans.offset += data_length;
|
trans.offset += data_length;
|
||||||
@ -552,7 +556,7 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
|
|||||||
|
|
||||||
spi_xfer_exit:
|
spi_xfer_exit:
|
||||||
/* Clear atomic preop now that xfer is done */
|
/* Clear atomic preop now that xfer is done */
|
||||||
writew_(0, cntlr.preop);
|
writew_(0, cntlr->preop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user