drivers: espi: xec: Add support for eSPI flash channel
Add driver implementation to support flash read/writ transactions over eSPI bus. Signed-off-by: Jose Alberto Meza <jose.a.meza.arellano@intel.com>
This commit is contained in:
parent
f1a7a53850
commit
9538f7896e
2 changed files with 146 additions and 7 deletions
|
@ -14,6 +14,9 @@ if ESPI_XEC
|
|||
config ESPI_OOB_CHANNEL
|
||||
default y
|
||||
|
||||
config ESPI_FLASH_CHANNEL
|
||||
default y
|
||||
|
||||
config ESPI_PERIPHERAL_HOST_IO
|
||||
default y
|
||||
|
||||
|
|
|
@ -19,7 +19,12 @@
|
|||
/* Maximum timeout to transmit a virtual wire packet.
|
||||
* 10 ms expresed in multiples of 100us
|
||||
*/
|
||||
#define ESPI_XEC_VWIRE_SEND_TIMEOUT 100
|
||||
#define ESPI_XEC_VWIRE_SEND_TIMEOUT 100ul
|
||||
|
||||
/* 100ms */
|
||||
#define MAX_OOB_TIMEOUT 100ul
|
||||
/* 1s */
|
||||
#define MAX_FLASH_TIMEOUT 1000ul
|
||||
|
||||
/* OOB maximum address configuration */
|
||||
#define ESPI_XEC_OOB_ADDR_MSW 0x1FFFul
|
||||
|
@ -36,9 +41,8 @@
|
|||
#define ESPI_XEC_PORT80_BAR_ADDRESS 0x00800000
|
||||
#define ESPI_XEC_PORT81_BAR_ADDRESS 0x00810000
|
||||
|
||||
#define MAX_OOB_BUFFER_SIZE 128
|
||||
/* 1s */
|
||||
#define MAX_OOB_TIMEOUT 1000
|
||||
#define MAX_OOB_BUFFER_SIZE 128ul
|
||||
#define MAX_SLAVE_BUFFER_SIZE 128ul
|
||||
|
||||
LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL);
|
||||
|
||||
|
@ -58,6 +62,7 @@ struct espi_xec_data {
|
|||
sys_slist_t callbacks;
|
||||
struct k_sem tx_lock;
|
||||
struct k_sem rx_lock;
|
||||
struct k_sem flash_lock;
|
||||
u8_t plt_rst_asserted;
|
||||
u8_t espi_rst_asserted;
|
||||
u8_t sx_state;
|
||||
|
@ -189,6 +194,7 @@ static const struct xec_signal vw_tbl[] = {
|
|||
|
||||
static u32_t slave_rx_mem[MAX_OOB_BUFFER_SIZE];
|
||||
static u32_t slave_tx_mem[MAX_OOB_BUFFER_SIZE];
|
||||
static u32_t slave_mem[MAX_SLAVE_BUFFER_SIZE];
|
||||
|
||||
static int espi_xec_configure(struct device *dev, struct espi_cfg *cfg)
|
||||
{
|
||||
|
@ -263,6 +269,7 @@ static int espi_xec_configure(struct device *dev, struct espi_cfg *cfg)
|
|||
if (IS_ENABLED(CONFIG_ESPI_FLASH_CHANNEL)) {
|
||||
cap0 |= MCHP_ESPI_GBL_CAP0_FC_SUPP;
|
||||
} else {
|
||||
LOG_ERR("Flash channel not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +302,7 @@ static bool espi_xec_channel_ready(struct device *dev, enum espi_channel ch)
|
|||
sts = ESPI_CAP_REGS->OOB_RDY & MCHP_ESPI_OOB_READY;
|
||||
break;
|
||||
case ESPI_CHANNEL_FLASH:
|
||||
sts = ESPI_CAP_REGS->FC_RDY & MCHP_ESPI_PC_READY;
|
||||
sts = ESPI_CAP_REGS->FC_RDY & MCHP_ESPI_FC_READY;
|
||||
break;
|
||||
default:
|
||||
sts = false;
|
||||
|
@ -520,6 +527,105 @@ static int espi_xec_receive_oob(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int espi_xec_flash_read(struct device *dev,
|
||||
struct espi_flash_packet *pckt)
|
||||
{
|
||||
int ret;
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->driver_data);
|
||||
u32_t err_mask = MCHP_ESPI_FC_STS_IBERR |
|
||||
MCHP_ESPI_FC_STS_FAIL |
|
||||
MCHP_ESPI_FC_STS_OVFL |
|
||||
MCHP_ESPI_FC_STS_BADREQ;
|
||||
|
||||
LOG_DBG("%s", __func__);
|
||||
|
||||
if (!(ESPI_FC_REGS->STS & MCHP_ESPI_FC_STS_CHAN_EN)) {
|
||||
LOG_ERR("Flash channel is disabled");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (pckt->len > MAX_SLAVE_BUFFER_SIZE) {
|
||||
LOG_ERR("Invalid size request");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ESPI_FC_REGS->FL_ADDR_MSW = 0;
|
||||
ESPI_FC_REGS->FL_ADDR_LSW = pckt->flash_addr;
|
||||
ESPI_FC_REGS->MEM_ADDR_MSW = 0;
|
||||
ESPI_FC_REGS->MEM_ADDR_LSW = (u32_t)&slave_mem[0];
|
||||
ESPI_FC_REGS->XFR_LEN = pckt->len;
|
||||
ESPI_FC_REGS->CTRL = MCHP_ESPI_FC_CTRL_FUNC(MCHP_ESPI_FC_CTRL_RD0);
|
||||
ESPI_FC_REGS->CTRL |= MCHP_ESPI_FC_CTRL_START;
|
||||
|
||||
/* Wait until ISR or timeout */
|
||||
ret = k_sem_take(&data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT));
|
||||
if (ret == -EAGAIN) {
|
||||
LOG_ERR("%s timeout", __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ESPI_FC_REGS->STS & err_mask) {
|
||||
LOG_ERR("%s error %x", __func__, err_mask);
|
||||
ESPI_FC_REGS->STS = err_mask;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(pckt->buf, slave_mem, pckt->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int espi_xec_flash_write(struct device *dev,
|
||||
struct espi_flash_packet *pckt)
|
||||
{
|
||||
int ret;
|
||||
u32_t err_mask = MCHP_ESPI_FC_STS_IBERR |
|
||||
MCHP_ESPI_FC_STS_OVRUN |
|
||||
MCHP_ESPI_FC_STS_FAIL |
|
||||
MCHP_ESPI_FC_STS_BADREQ;
|
||||
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->driver_data);
|
||||
|
||||
LOG_DBG("%s", __func__);
|
||||
|
||||
if (!(ESPI_FC_REGS->STS & MCHP_ESPI_FC_STS_CHAN_EN)) {
|
||||
LOG_ERR("Flash channel is disabled");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((ESPI_FC_REGS->CFG & MCHP_ESPI_FC_CFG_BUSY)) {
|
||||
LOG_ERR("Flash channel is busy");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
memcpy(slave_mem, pckt->buf, pckt->len);
|
||||
|
||||
ESPI_FC_REGS->FL_ADDR_MSW = 0;
|
||||
ESPI_FC_REGS->FL_ADDR_LSW = pckt->flash_addr;
|
||||
ESPI_FC_REGS->MEM_ADDR_MSW = 0;
|
||||
ESPI_FC_REGS->MEM_ADDR_LSW = (u32_t)&slave_mem[0];
|
||||
ESPI_FC_REGS->XFR_LEN = pckt->len;
|
||||
ESPI_FC_REGS->CTRL = MCHP_ESPI_FC_CTRL_FUNC(MCHP_ESPI_FC_CTRL_WR0);
|
||||
ESPI_FC_REGS->CTRL |= MCHP_ESPI_FC_CTRL_START;
|
||||
|
||||
/* Wait until ISR or timeout */
|
||||
ret = k_sem_take(&data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT));
|
||||
if (ret == -EAGAIN) {
|
||||
LOG_ERR("%s timeout", __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ESPI_FC_REGS->STS & err_mask) {
|
||||
LOG_ERR("%s err: %x", __func__, err_mask);
|
||||
ESPI_FC_REGS->STS = err_mask;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(pckt->buf, slave_rx_mem, pckt->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int espi_xec_manage_callback(struct device *dev,
|
||||
struct espi_callback *callback, bool set)
|
||||
{
|
||||
|
@ -570,7 +676,15 @@ static void espi_init_flash(struct device *dev)
|
|||
struct espi_xec_config *config =
|
||||
(struct espi_xec_config *)(dev->config->config_info);
|
||||
|
||||
LOG_DBG("%s", __func__);
|
||||
|
||||
/* Indicate slave flash channel is ready */
|
||||
ESPI_CAP_REGS->FC_RDY |= MCHP_ESPI_FC_READY;
|
||||
|
||||
/* Enable interrupts */
|
||||
MCHP_GIRQ_ENSET(config->bus_girq_id) = BIT(MCHP_ESPI_FC_GIRQ_POS);
|
||||
ESPI_FC_REGS->IEN |= MCHP_ESPI_FC_IEN_CHG_EN;
|
||||
ESPI_FC_REGS->IEN |= MCHP_ESPI_FC_IEN_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -694,7 +808,9 @@ static void espi_vwire_chanel_isr(struct device *dev)
|
|||
{
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->driver_data);
|
||||
const struct espi_xec_config *config = dev->config->config_info;
|
||||
struct espi_event evt = { ESPI_BUS_EVENT_CHANNEL_READY, 0, 0 };
|
||||
struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_CHANNEL_READY,
|
||||
.evt_details = 0,
|
||||
.evt_data = 0 };
|
||||
u32_t status;
|
||||
|
||||
status = ESPI_IO_VW_REGS->VW_EN_STS;
|
||||
|
@ -758,14 +874,30 @@ static void espi_oob_up_isr(struct device *dev)
|
|||
static void espi_flash_isr(struct device *dev)
|
||||
{
|
||||
u32_t status;
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->driver_data);
|
||||
struct espi_event evt = { ESPI_BUS_EVENT_CHANNEL_READY, 0, 0 };
|
||||
|
||||
status = ESPI_FC_REGS->STS;
|
||||
LOG_DBG("%s %x", __func__, status);
|
||||
|
||||
if (status & MCHP_ESPI_FC_STS_DONE) {
|
||||
ESPI_FC_REGS->IEN = ~BIT(0);
|
||||
/* Ensure to clear only relevant bit */
|
||||
ESPI_FC_REGS->STS = MCHP_ESPI_FC_STS_DONE;
|
||||
|
||||
k_sem_give(&data->flash_lock);
|
||||
}
|
||||
|
||||
if (status & MCHP_ESPI_FC_STS_CHAN_EN_CHG) {
|
||||
/* Ensure to clear only relevant bit */
|
||||
ESPI_FC_REGS->STS = MCHP_ESPI_FC_STS_CHAN_EN_CHG;
|
||||
espi_init_flash(dev);
|
||||
|
||||
evt.evt_details = ESPI_CHANNEL_FLASH;
|
||||
if (status & MCHP_ESPI_FC_STS_CHAN_EN) {
|
||||
evt.evt_data = 1;
|
||||
}
|
||||
|
||||
espi_send_callbacks(&data->callbacks, dev, evt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1055,6 +1187,8 @@ static const struct espi_driver_api espi_xec_driver_api = {
|
|||
.receive_vwire = espi_xec_receive_vwire,
|
||||
.send_oob = espi_xec_send_oob,
|
||||
.receive_oob = espi_xec_receive_oob,
|
||||
.flash_read = espi_xec_flash_read,
|
||||
.flash_write = espi_xec_flash_write,
|
||||
.manage_callback = espi_xec_manage_callback,
|
||||
.read_lpc_request = espi_xec_read_lpc_request,
|
||||
.write_lpc_request = espi_xec_write_lpc_request,
|
||||
|
@ -1108,6 +1242,8 @@ static int espi_xec_init(struct device *dev)
|
|||
ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_FC_CAP_MAX_PLD_SZ_64;
|
||||
ESPI_CAP_REGS->FC_CAP |= MCHP_ESPI_FC_CAP_SHARE_MAF_SAF;
|
||||
ESPI_CAP_REGS->FC_CAP |= MCHP_ESPI_FC_CAP_MAX_RD_SZ_64;
|
||||
|
||||
k_sem_init(&data->flash_lock, 0, 1);
|
||||
#else
|
||||
ESPI_CAP_REGS->GLB_CAP0 &= ~MCHP_ESPI_GBL_CAP0_FC_SUPP;
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue