raw/ifpga/base: update flash operation interface

In N6000 ADP platform, SPI protocol, master and QSPI flash are
transparent to host software. The SPI master implemented in PMCI
automatically converts the mailbox commands to the SPI protocol
required by SPI slave.
That means flash operation is different from old platform, new
interfaces are introduced to adapt these changes.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
This commit is contained in:
Wei Huang 2022-06-17 03:19:34 -04:00 committed by Thomas Monjalon
parent 7c4fe2ad3b
commit b74ee6c808
8 changed files with 379 additions and 0 deletions

View File

@ -268,6 +268,14 @@ static int ifpga_mgr_reload(struct opae_manager *mgr, int type, int page)
return fpga_reload(fme, type, page);
}
static int ifpga_mgr_read_flash(struct opae_manager *mgr, u32 address,
u32 size, void *buf)
{
struct ifpga_fme_hw *fme = mgr->data;
return fme_mgr_read_flash(fme, address, size, buf);
}
struct opae_manager_ops ifpga_mgr_ops = {
.flash = ifpga_mgr_flash,
.get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info,
@ -277,6 +285,7 @@ struct opae_manager_ops ifpga_mgr_ops = {
.update_flash = ifpga_mgr_update_flash,
.stop_flash_update = ifpga_mgr_stop_flash_update,
.reload = ifpga_mgr_reload,
.read_flash = ifpga_mgr_read_flash
};
static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset,

View File

@ -223,4 +223,6 @@ int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme,
int fme_mgr_get_sensor_value(struct ifpga_fme_hw *fme,
struct opae_sensor_info *sensor,
unsigned int *value);
int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
u32 size, void *buf);
#endif /* _IFPGA_FEATURE_DEV_H_ */

View File

@ -1658,3 +1658,11 @@ struct ifpga_feature_ops fme_pmci_ops = {
.init = fme_pmci_init,
.uinit = fme_pmci_uinit,
};
int fme_mgr_read_flash(struct ifpga_fme_hw *fme, u32 address,
u32 size, void *buf)
{
struct intel_max10_device *max10 = fme->max10_dev;
return opae_read_flash(max10, address, size, buf);
}

View File

@ -1041,3 +1041,23 @@ int opae_mgr_reload(struct opae_manager *mgr, int type, int page)
return -ENOENT;
}
/**
* opae_mgr_read_flash - read flash content
* @mgr: targeted manager
* @address: the start address of flash
* @size: the size of flash
* @buf: the read buffer
*
* Return: 0 on success, otherwise error code.
*/
int opae_mgr_read_flash(struct opae_manager *mgr, u32 address,
u32 size, void *buf)
{
if (!mgr)
return -EINVAL;
if (mgr->ops && mgr->ops->read_flash)
return mgr->ops->read_flash(mgr, address, size, buf);
return -ENOENT;
}

View File

@ -60,6 +60,7 @@ struct opae_manager_ops {
u64 *status);
int (*stop_flash_update)(struct opae_manager *mgr, int force);
int (*reload)(struct opae_manager *mgr, int type, int page);
int (*read_flash)(struct opae_manager *mgr, u32 address, u32 size, void *buf);
};
/* networking management ops in FME */
@ -368,4 +369,5 @@ int opae_mgr_update_flash(struct opae_manager *mgr, const char *image,
uint64_t *status);
int opae_mgr_stop_flash_update(struct opae_manager *mgr, int force);
int opae_mgr_reload(struct opae_manager *mgr, int type, int page);
int opae_mgr_read_flash(struct opae_manager *mgr, u32 address, u32 size, void *buf);
#endif /* _OPAE_HW_API_H_*/

View File

@ -58,6 +58,279 @@ int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset,
return max10_sys_write(dev, offset, temp);
}
static int n3000_bulk_raw_write(struct intel_max10_device *dev, uint32_t addr,
void *buf, uint32_t len)
{
uint32_t v = 0;
uint32_t i = 0;
char *p = buf;
int ret = 0;
len = IFPGA_ALIGN(len, 4);
for (i = 0; i < len; i += 4) {
v = *(uint32_t *)(p + i);
ret = max10_reg_write(dev, addr + i, v);
if (ret < 0) {
dev_err(dev,
"Failed to write to staging area 0x%08x [e:%d]\n",
addr + i, ret);
return ret;
}
}
return 0;
}
static int n3000_bulk_raw_read(struct intel_max10_device *dev,
uint32_t addr, void *buf, uint32_t len)
{
u32 v, i;
char *p = buf;
int ret;
len = IFPGA_ALIGN(len, 4);
for (i = 0; i < len; i += 4) {
ret = max10_reg_read(dev, addr + i, &v);
if (ret < 0) {
dev_err(dev,
"Failed to write to staging area 0x%08x [e:%d]\n",
addr + i, ret);
return ret;
}
*(u32 *)(p + i) = v;
}
return 0;
}
static int n3000_flash_read(struct intel_max10_device *dev,
u32 addr, void *buf, u32 size)
{
if (!dev->raw_blk_ops.read_blk)
return -ENODEV;
return dev->raw_blk_ops.read_blk(dev, addr, buf, size);
}
static int n3000_flash_write(struct intel_max10_device *dev,
u32 addr, void *buf, u32 size)
{
if (!dev->raw_blk_ops.write_blk)
return -ENODEV;
return dev->raw_blk_ops.write_blk(dev, addr, buf, size);
}
static u32
pmci_get_write_space(struct intel_max10_device *dev, u32 size)
{
u32 count, val;
int ret;
ret = opae_readl_poll_timeout(dev->mmio + PMCI_FLASH_CTRL, val,
GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) ==
PMCI_FIFO_MAX_WORDS,
PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US);
if (ret == -ETIMEDOUT)
return 0;
count = GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) * 4;
return (size > count) ? count : size;
}
static void pmci_write_fifo(void __iomem *base, char *buf, size_t count)
{
size_t i;
u32 val;
for (i = 0; i < count/4 ; i++) {
val = *(u32 *)(buf + i * 4);
writel(val, base);
}
}
static void pmci_read_fifo(void __iomem *base, char *buf, size_t count)
{
size_t i;
u32 val;
for (i = 0; i < count/4; i++) {
val = readl(base);
*(u32 *)(buf + i * 4) = val;
}
}
static int
__pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr,
void *buf, u32 size)
{
UNUSED(addr);
u32 blk_size, n_offset = 0;
while (size) {
blk_size = pmci_get_write_space(dev, size);
if (blk_size == 0) {
dev_err(pmci->dev, "get FIFO available size fail\n");
return -EIO;
}
size -= blk_size;
pmci_write_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + n_offset,
blk_size);
n_offset += blk_size;
}
return 0;
}
static int
pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr,
void *buf, u32 size)
{
int ret;
pthread_mutex_lock(dev->bmc_ops.mutex);
ret = __pmci_flash_bulk_write(dev, addr, buf, size);
pthread_mutex_unlock(dev->bmc_ops.mutex);
return ret;
}
static int
pmci_set_flash_host_mux(struct intel_max10_device *dev, bool request)
{
u32 ctrl;
int ret;
ret = max10_sys_update_bits(dev,
m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL,
FLASH_HOST_REQUEST,
SET_FIELD(FLASH_HOST_REQUEST, request));
if (ret)
return ret;
return opae_max10_read_poll_timeout(dev, m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL,
ctrl, request ? (get_flash_mux(ctrl) == FLASH_MUX_HOST) :
(get_flash_mux(ctrl) != FLASH_MUX_HOST),
PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US);
}
static int
pmci_get_mux(struct intel_max10_device *dev)
{
pthread_mutex_lock(dev->bmc_ops.mutex);
return pmci_set_flash_host_mux(dev, true);
}
static int
pmci_put_mux(struct intel_max10_device *dev)
{
int ret;
ret = pmci_set_flash_host_mux(dev, false);
pthread_mutex_unlock(dev->bmc_ops.mutex);
return ret;
}
static int
__pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr,
void *buf, u32 size)
{
u32 blk_size, offset = 0, val;
int ret;
while (size) {
blk_size = min_t(u32, size, PMCI_READ_BLOCK_SIZE);
opae_writel(addr + offset, dev->mmio + PMCI_FLASH_ADDR);
opae_writel(SET_FIELD(PMCI_FLASH_READ_COUNT, blk_size / 4)
| PMCI_FLASH_RD_MODE,
dev->mmio + PMCI_FLASH_CTRL);
ret = opae_readl_poll_timeout((dev->mmio + PMCI_FLASH_CTRL),
val, !(val & PMCI_FLASH_BUSY),
PMCI_FLASH_INT_US,
PMCI_FLASH_TIMEOUT_US);
if (ret) {
dev_err(dev, "%s timed out on reading flash 0x%xn",
__func__, val);
return ret;
}
pmci_read_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + offset,
blk_size);
size -= blk_size;
offset += blk_size;
opae_writel(0, dev->mmio + PMCI_FLASH_CTRL);
}
return 0;
}
static int
pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr,
void *buf, u32 size)
{
int ret;
ret = pmci_get_mux(dev);
if (ret)
goto fail;
ret = __pmci_flash_bulk_read(dev, addr, buf, size);
if (ret)
goto fail;
return pmci_put_mux(dev);
fail:
pmci_put_mux(dev);
return ret;
}
static int pmci_check_flash_address(u32 start, u32 end)
{
if (start < PMCI_FLASH_START || end > PMCI_FLASH_END)
return -EINVAL;
return 0;
}
int opae_read_flash(struct intel_max10_device *dev, u32 addr,
u32 size, void *buf)
{
int ret;
if (!dev->bmc_ops.flash_read)
return -ENODEV;
if (!buf)
return -EINVAL;
if (dev->bmc_ops.check_flash_range) {
ret = dev->bmc_ops.check_flash_range(addr, addr + size);
if (ret)
return ret;
} else {
u32 top_addr = dev->staging_area_base + dev->staging_area_size;
if ((addr < dev->staging_area_base) ||
((addr + size) >= top_addr))
return -EINVAL;
}
ret = dev->bmc_ops.flash_read(dev, addr, buf, size);
if (ret)
return ret;
return 0;
}
static int max10_spi_read(struct intel_max10_device *dev,
unsigned int addr, unsigned int *val)
{
@ -841,6 +1114,11 @@ intel_max10_device_init(struct intel_max10_device *dev)
dev->ops = &m10bmc_n3000_regmap;
dev->csr = &m10bmc_spi_csr;
dev->raw_blk_ops.write_blk = n3000_bulk_raw_write;
dev->raw_blk_ops.read_blk = n3000_bulk_raw_read;
dev->bmc_ops.flash_read = n3000_flash_read;
dev->bmc_ops.flash_write = n3000_flash_write;
/* check the max10 version */
ret = check_max10_version(dev);
if (ret) {
@ -871,6 +1149,10 @@ intel_max10_device_init(struct intel_max10_device *dev)
dev->staging_area_size = MAX_STAGING_AREA_SIZE;
dev->flags |= MAX10_FLAGS_SECURE;
dev->bmc_ops.flash_read = pmci_flash_bulk_read;
dev->bmc_ops.flash_write = pmci_flash_bulk_write;
dev->bmc_ops.check_flash_range = pmci_check_flash_address;
ret = pthread_mutex_init(&dev->bmc_ops.lock, NULL);
if (ret)
return ret;

View File

@ -61,10 +61,23 @@ struct m10bmc_csr {
unsigned int auth_result;
};
/**
* struct flash_raw_blk_ops - device specific operations for flash R/W
* @write_blk: write a block of data to flash
* @read_blk: read a block of data from flash
*/
struct flash_raw_blk_ops {
int (*write_blk)(struct intel_max10_device *dev, uint32_t addr,
void *buf, uint32_t size);
int (*read_blk)(struct intel_max10_device *dev, uint32_t addr,
void *buf, uint32_t size);
};
/**
* struct m10bmc_ops - device specific operations
* @lock: prevent concurrent flash read/write
* @mutex: prevent concurrent bmc read/write
* @check_flash_range: validate flash address
* @flash_read: read a block of data from flash
* @flash_write: write a block of data to flash
*/
@ -92,6 +105,7 @@ struct intel_max10_device {
enum m10bmc_type type;
const struct m10bmc_regmap *ops;
const struct m10bmc_csr *csr;
struct flash_raw_blk_ops raw_blk_ops;
struct m10bmc_ops bmc_ops;
u8 *mmio; /* mmio address for PMCI */
};
@ -431,6 +445,22 @@ struct opae_sensor_info {
#define PMCI_FPGA_RECONF_PAGE GENMASK(22, 20)
#define PMCI_FPGA_RP_LOAD BIT(23)
#define PMCI_FLASH_CTRL 0x40
#define PMCI_FLASH_WR_MODE BIT(0)
#define PMCI_FLASH_RD_MODE BIT(1)
#define PMCI_FLASH_BUSY BIT(2)
#define PMCI_FLASH_FIFO_SPACE GENMASK(13, 4)
#define PMCI_FLASH_READ_COUNT GENMASK(25, 16)
#define PMCI_FLASH_INT_US 1
#define PMCI_FLASH_TIMEOUT_US 10000
#define PMCI_FLASH_ADDR 0x44
#define PMCI_FLASH_FIFO 0x800
#define PMCI_READ_BLOCK_SIZE 0x800
#define PMCI_FIFO_MAX_BYTES 0x800
#define PMCI_FIFO_MAX_WORDS (PMCI_FIFO_MAX_BYTES / 4)
#define M10BMC_PMCI_FPGA_POC 0xb0
#define PMCI_FPGA_POC BIT(0)
#define PMCI_NIOS_REQ_CLEAR BIT(1)
@ -447,6 +477,16 @@ struct opae_sensor_info {
#define PMCI_FPGA_BOOT_PAGE GENMASK(2, 0)
#define PMCI_FPGA_CONFIGURED BIT(3)
#define M10BMC_PMCI_FLASH_CTRL 0x1d0
#define FLASH_MUX_SELECTION GENMASK(2, 0)
#define FLASH_MUX_IDLE 0
#define FLASH_MUX_NIOS 1
#define FLASH_MUX_HOST 2
#define FLASH_MUX_PFL 4
#define get_flash_mux(mux) GET_FIELD(FLASH_MUX_SELECTION, mux)
#define FLASH_NIOS_REQUEST BIT(4)
#define FLASH_HOST_REQUEST BIT(5)
#define M10BMC_PMCI_SDM_CTRL_STS 0x230
#define PMCI_SDM_IMG_REQ BIT(0)
#define PMCI_SDM_STAT GENMASK(23, 16)
@ -472,4 +512,10 @@ struct opae_sensor_info {
#define SDM_STAT_CS_MIS 0x12
#define SDM_STAT_PR_MIS 0x13
#define SDM_STAT_MAX SDM_STAT_PR_MIS
#define PMCI_FLASH_START 0x10000
#define PMCI_FLASH_END 0xC7FFFFF
int opae_read_flash(struct intel_max10_device *dev, u32 addr,
u32 size, void *buf);
#endif

View File

@ -39,6 +39,16 @@
#define min(a, b) RTE_MIN(a, b)
#define max(a, b) RTE_MAX(a, b)
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1 : __min2; })
#define max_t(type, x, y) ({ \
type __max1 = (x); \
type __max2 = (y); \
__max1 > __max2 ? __max1 : __max2; })
#define spinlock_t rte_spinlock_t
#define spinlock_init(x) rte_spinlock_init(x)
#define spinlock_lock(x) rte_spinlock_lock(x)