raw/ifpga/base: add SPI and MAX10 device driver
There is a SPI bus link between A10 FPGA and MAX10 FPGA. MAX10 is in charge of board management, like power management, sensors, flash devices. Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com>
This commit is contained in:
parent
e4dc499d56
commit
96ebfcf812
@ -22,5 +22,8 @@ SRCS-y += opae_hw_api.c
|
|||||||
SRCS-y += opae_ifpga_hw_api.c
|
SRCS-y += opae_ifpga_hw_api.c
|
||||||
SRCS-y += opae_debug.c
|
SRCS-y += opae_debug.c
|
||||||
SRCS-y += ifpga_fme_pr.c
|
SRCS-y += ifpga_fme_pr.c
|
||||||
|
SRCS-y += opae_spi.c
|
||||||
|
SRCS-y += opae_spi_transaction.c
|
||||||
|
SRCS-y += opae_intel_max10.c
|
||||||
|
|
||||||
SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c)
|
SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c)
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#define FME_FEATURE_HSSI_ETH "fme_hssi"
|
#define FME_FEATURE_HSSI_ETH "fme_hssi"
|
||||||
#define FME_FEATURE_GLOBAL_DPERF "fme_dperf"
|
#define FME_FEATURE_GLOBAL_DPERF "fme_dperf"
|
||||||
#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash"
|
#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash"
|
||||||
|
#define FME_FEATURE_MAX10_SPI "fme_max10_spi"
|
||||||
|
#define FME_FEATURE_NIOS_SPI "fme_nios_spi"
|
||||||
|
|
||||||
#define PORT_FEATURE_HEADER "port_hdr"
|
#define PORT_FEATURE_HEADER "port_hdr"
|
||||||
#define PORT_FEATURE_UAFU "port_uafu"
|
#define PORT_FEATURE_UAFU "port_uafu"
|
||||||
@ -43,6 +45,7 @@
|
|||||||
#define FME_HSSI_ETH_REVISION 0
|
#define FME_HSSI_ETH_REVISION 0
|
||||||
#define FME_GLOBAL_DPERF_REVISION 0
|
#define FME_GLOBAL_DPERF_REVISION 0
|
||||||
#define FME_QSPI_REVISION 0
|
#define FME_QSPI_REVISION 0
|
||||||
|
#define FME_MAX10_SPI 0
|
||||||
|
|
||||||
#define PORT_HEADER_REVISION 0
|
#define PORT_HEADER_REVISION 0
|
||||||
/* UAFU's header info depends on the downloaded GBS */
|
/* UAFU's header info depends on the downloaded GBS */
|
||||||
@ -80,6 +83,8 @@ enum fpga_id_type {
|
|||||||
#define FME_FEATURE_ID_GLOBAL_DPERF 0x7
|
#define FME_FEATURE_ID_GLOBAL_DPERF 0x7
|
||||||
#define FME_FEATURE_ID_QSPI_FLASH 0x8
|
#define FME_FEATURE_ID_QSPI_FLASH 0x8
|
||||||
#define FME_FEATURE_ID_EMIF_MGMT 0x9
|
#define FME_FEATURE_ID_EMIF_MGMT 0x9
|
||||||
|
#define FME_FEATURE_ID_MAX10_SPI 0xe
|
||||||
|
#define FME_FEATURE_ID_NIOS_SPI 0xd
|
||||||
|
|
||||||
#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER
|
#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER
|
||||||
#define PORT_FEATURE_ID_ERROR 0x10
|
#define PORT_FEATURE_ID_ERROR 0x10
|
||||||
|
@ -197,6 +197,10 @@ static struct feature_driver fme_feature_drvs[] = {
|
|||||||
&fme_hssi_eth_ops),},
|
&fme_hssi_eth_ops),},
|
||||||
{FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT,
|
{FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT,
|
||||||
&fme_emif_ops),},
|
&fme_emif_ops),},
|
||||||
|
{FEATURE_DRV(FME_FEATURE_ID_MAX10_SPI, FME_FEATURE_MAX10_SPI,
|
||||||
|
&fme_spi_master_ops),},
|
||||||
|
{FEATURE_DRV(FME_FEATURE_ID_NIOS_SPI, FME_FEATURE_NIOS_SPI,
|
||||||
|
&fme_nios_spi_master_ops),},
|
||||||
{0, NULL, NULL}, /* end of arrary */
|
{0, NULL, NULL}, /* end of arrary */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,6 +171,8 @@ extern struct feature_ops fme_global_iperf_ops;
|
|||||||
extern struct feature_ops fme_global_dperf_ops;
|
extern struct feature_ops fme_global_dperf_ops;
|
||||||
extern struct feature_ops fme_hssi_eth_ops;
|
extern struct feature_ops fme_hssi_eth_ops;
|
||||||
extern struct feature_ops fme_emif_ops;
|
extern struct feature_ops fme_emif_ops;
|
||||||
|
extern struct feature_ops fme_spi_master_ops;
|
||||||
|
extern struct feature_ops fme_nios_spi_master_ops;
|
||||||
|
|
||||||
int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop);
|
int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop);
|
||||||
int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop);
|
int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop);
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ifpga_feature_dev.h"
|
#include "ifpga_feature_dev.h"
|
||||||
|
#include "opae_spi.h"
|
||||||
|
#include "opae_intel_max10.h"
|
||||||
|
|
||||||
#define PWR_THRESHOLD_MAX 0x7F
|
#define PWR_THRESHOLD_MAX 0x7F
|
||||||
|
|
||||||
@ -764,3 +766,197 @@ struct feature_ops fme_emif_ops = {
|
|||||||
.init = fme_emif_init,
|
.init = fme_emif_init,
|
||||||
.uinit = fme_emif_uinit,
|
.uinit = fme_emif_uinit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int spi_self_checking(void)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = max10_reg_read(0x30043c, &val);
|
||||||
|
if (ret)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (val != 0x87654321) {
|
||||||
|
dev_err(NULL, "Read MAX10 test register fail: 0x%x\n", val);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(NULL, "Read MAX10 test register success, SPI self-test done\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fme_spi_init(struct feature *feature)
|
||||||
|
{
|
||||||
|
struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent;
|
||||||
|
struct altera_spi_device *spi_master;
|
||||||
|
struct intel_max10_device *max10;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dev_info(fme, "FME SPI Master (Max10) Init.\n");
|
||||||
|
dev_debug(fme, "FME SPI base addr %p.\n",
|
||||||
|
feature->addr);
|
||||||
|
dev_debug(fme, "spi param=0x%llx\n",
|
||||||
|
(unsigned long long)opae_readq(feature->addr + 0x8));
|
||||||
|
|
||||||
|
spi_master = altera_spi_alloc(feature->addr, TYPE_SPI);
|
||||||
|
if (!spi_master)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
altera_spi_init(spi_master);
|
||||||
|
|
||||||
|
max10 = intel_max10_device_probe(spi_master, 0);
|
||||||
|
if (!max10) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
dev_err(fme, "max10 init fail\n");
|
||||||
|
goto spi_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fme->max10_dev = max10;
|
||||||
|
|
||||||
|
/* SPI self test */
|
||||||
|
if (spi_self_checking()) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto max10_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
max10_fail:
|
||||||
|
intel_max10_device_remove(fme->max10_dev);
|
||||||
|
spi_fail:
|
||||||
|
altera_spi_release(spi_master);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fme_spi_uinit(struct feature *feature)
|
||||||
|
{
|
||||||
|
struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent;
|
||||||
|
|
||||||
|
if (fme->max10_dev)
|
||||||
|
intel_max10_device_remove(fme->max10_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct feature_ops fme_spi_master_ops = {
|
||||||
|
.init = fme_spi_init,
|
||||||
|
.uinit = fme_spi_uinit,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int nios_spi_wait_init_done(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
unsigned long timeout = msecs_to_timer_cycles(10000);
|
||||||
|
unsigned long ticks;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (spi_reg_read(dev, NIOS_SPI_INIT_DONE, &val))
|
||||||
|
return -EIO;
|
||||||
|
if (val)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ticks = rte_get_timer_cycles();
|
||||||
|
if (time_after(ticks, timeout))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
msleep(100);
|
||||||
|
} while (!val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nios_spi_check_error(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
u32 value = 0;
|
||||||
|
|
||||||
|
if (spi_reg_read(dev, NIOS_SPI_INIT_STS0, &value))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
dev_debug(dev, "SPI init status0 0x%x\n", value);
|
||||||
|
|
||||||
|
/* Error code: 0xFFF0 to 0xFFFC */
|
||||||
|
if (value >= 0xFFF0 && value <= 0xFFFC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
value = 0;
|
||||||
|
if (spi_reg_read(dev, NIOS_SPI_INIT_STS1, &value))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
dev_debug(dev, "SPI init status1 0x%x\n", value);
|
||||||
|
|
||||||
|
/* Error code: 0xFFF0 to 0xFFFC */
|
||||||
|
if (value >= 0xFFF0 && value <= 0xFFFC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fme_nios_spi_init(struct feature *feature)
|
||||||
|
{
|
||||||
|
struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent;
|
||||||
|
struct altera_spi_device *spi_master;
|
||||||
|
struct intel_max10_device *max10;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dev_info(fme, "FME SPI Master (NIOS) Init.\n");
|
||||||
|
dev_debug(fme, "FME SPI base addr %p.\n",
|
||||||
|
feature->addr);
|
||||||
|
dev_debug(fme, "spi param=0x%llx\n",
|
||||||
|
(unsigned long long)opae_readq(feature->addr + 0x8));
|
||||||
|
|
||||||
|
spi_master = altera_spi_alloc(feature->addr, TYPE_NIOS_SPI);
|
||||||
|
if (!spi_master)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. wait A10 NIOS initial finished and
|
||||||
|
* release the SPI master to Host
|
||||||
|
*/
|
||||||
|
ret = nios_spi_wait_init_done(spi_master);
|
||||||
|
if (ret != 0) {
|
||||||
|
dev_err(fme, "FME NIOS_SPI init fail\n");
|
||||||
|
goto release_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(fme, "FME NIOS_SPI initial done\n");
|
||||||
|
|
||||||
|
/* 2. check if error occur? */
|
||||||
|
if (nios_spi_check_error(spi_master))
|
||||||
|
dev_info(fme, "NIOS_SPI INIT done, but found some error\n");
|
||||||
|
|
||||||
|
/* 3. init the spi master*/
|
||||||
|
altera_spi_init(spi_master);
|
||||||
|
|
||||||
|
/* init the max10 device */
|
||||||
|
max10 = intel_max10_device_probe(spi_master, 0);
|
||||||
|
if (!max10) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
dev_err(fme, "max10 init fail\n");
|
||||||
|
goto release_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
fme->max10_dev = max10;
|
||||||
|
|
||||||
|
/* SPI self test */
|
||||||
|
if (spi_self_checking())
|
||||||
|
goto spi_fail;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
spi_fail:
|
||||||
|
intel_max10_device_remove(fme->max10_dev);
|
||||||
|
release_dev:
|
||||||
|
altera_spi_release(spi_master);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fme_nios_spi_uinit(struct feature *feature)
|
||||||
|
{
|
||||||
|
struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent;
|
||||||
|
|
||||||
|
if (fme->max10_dev)
|
||||||
|
intel_max10_device_remove(fme->max10_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct feature_ops fme_nios_spi_master_ops = {
|
||||||
|
.init = fme_nios_spi_init,
|
||||||
|
.uinit = fme_nios_spi_uinit,
|
||||||
|
};
|
||||||
|
@ -79,6 +79,8 @@ struct ifpga_fme_hw {
|
|||||||
u32 cache_size;
|
u32 cache_size;
|
||||||
|
|
||||||
u32 capability;
|
u32 capability;
|
||||||
|
|
||||||
|
void *max10_dev; /* MAX10 device */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ifpga_port_state {
|
enum ifpga_port_state {
|
||||||
|
@ -14,7 +14,10 @@ sources = [
|
|||||||
'ifpga_fme_pr.c',
|
'ifpga_fme_pr.c',
|
||||||
'opae_hw_api.c',
|
'opae_hw_api.c',
|
||||||
'opae_ifpga_hw_api.c',
|
'opae_ifpga_hw_api.c',
|
||||||
'opae_debug.c'
|
'opae_debug.c',
|
||||||
|
'opae_spi.c',
|
||||||
|
'opae_spi_transaction.c',
|
||||||
|
'opae_intel_max10.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
error_cflags = ['-Wno-sign-compare', '-Wno-unused-value',
|
error_cflags = ['-Wno-sign-compare', '-Wno-unused-value',
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include "opae_osdep.h"
|
#include "opae_osdep.h"
|
||||||
|
#include "opae_intel_max10.h"
|
||||||
|
|
||||||
#ifndef PCI_MAX_RESOURCE
|
#ifndef PCI_MAX_RESOURCE
|
||||||
#define PCI_MAX_RESOURCE 6
|
#define PCI_MAX_RESOURCE 6
|
||||||
|
88
drivers/raw/ifpga_rawdev/base/opae_intel_max10.c
Normal file
88
drivers/raw/ifpga_rawdev/base/opae_intel_max10.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opae_intel_max10.h"
|
||||||
|
|
||||||
|
static struct intel_max10_device *g_max10;
|
||||||
|
|
||||||
|
int max10_reg_read(unsigned int reg, unsigned int *val)
|
||||||
|
{
|
||||||
|
if (!g_max10)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return spi_transaction_read(g_max10->spi_tran_dev,
|
||||||
|
reg, 4, (unsigned char *)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int max10_reg_write(unsigned int reg, unsigned int val)
|
||||||
|
{
|
||||||
|
if (!g_max10)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return spi_transaction_write(g_max10->spi_tran_dev,
|
||||||
|
reg, 4, (unsigned char *)&val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct intel_max10_device *
|
||||||
|
intel_max10_device_probe(struct altera_spi_device *spi,
|
||||||
|
int chipselect)
|
||||||
|
{
|
||||||
|
struct intel_max10_device *dev;
|
||||||
|
int ret;
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
dev = opae_malloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dev->spi_master = spi;
|
||||||
|
|
||||||
|
dev->spi_tran_dev = spi_transaction_init(spi, chipselect);
|
||||||
|
if (!dev->spi_tran_dev) {
|
||||||
|
dev_err(dev, "%s spi tran init fail\n", __func__);
|
||||||
|
goto free_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the max10 device firstly */
|
||||||
|
g_max10 = dev;
|
||||||
|
|
||||||
|
/* read FPGA loading information */
|
||||||
|
ret = max10_reg_read(FPGA_PAGE_INFO_OFF, &val);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "fail to get FPGA loading info\n");
|
||||||
|
goto spi_tran_fail;
|
||||||
|
}
|
||||||
|
dev_info(dev, "FPGA loaded from %s Image\n", val ? "User" : "Factory");
|
||||||
|
|
||||||
|
/* set PKVL Polling manually in BBS */
|
||||||
|
ret = max10_reg_write(PKVL_POLLING_CTRL, 0x3);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "%s set PKVL polling fail\n", __func__);
|
||||||
|
goto spi_tran_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
|
||||||
|
spi_tran_fail:
|
||||||
|
spi_transaction_remove(dev->spi_tran_dev);
|
||||||
|
free_dev:
|
||||||
|
g_max10 = NULL;
|
||||||
|
opae_free(dev);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_max10_device_remove(struct intel_max10_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dev->spi_tran_dev)
|
||||||
|
spi_transaction_remove(dev->spi_tran_dev);
|
||||||
|
|
||||||
|
g_max10 = NULL;
|
||||||
|
opae_free(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
60
drivers/raw/ifpga_rawdev/base/opae_intel_max10.h
Normal file
60
drivers/raw/ifpga_rawdev/base/opae_intel_max10.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _OPAE_INTEL_MAX10_H_
|
||||||
|
#define _OPAE_INTEL_MAX10_H_
|
||||||
|
|
||||||
|
#include "opae_osdep.h"
|
||||||
|
#include "opae_spi.h"
|
||||||
|
|
||||||
|
#define INTEL_MAX10_MAX_MDIO_DEVS 2
|
||||||
|
#define PKVL_NUMBER_PORTS 4
|
||||||
|
|
||||||
|
/* max10 capability flags */
|
||||||
|
#define MAX10_FLAGS_NO_I2C2 BIT(0)
|
||||||
|
#define MAX10_FLAGS_NO_BMCIMG_FLASH BIT(1)
|
||||||
|
#define MAX10_FLAGS_DEVICE_TABLE BIT(2)
|
||||||
|
#define MAX10_FLAGS_SPI BIT(3)
|
||||||
|
#define MAX10_FLGAS_NIOS_SPI BIT(4)
|
||||||
|
#define MAX10_FLAGS_PKVL BIT(5)
|
||||||
|
|
||||||
|
struct intel_max10_device {
|
||||||
|
unsigned int flags; /*max10 hardware capability*/
|
||||||
|
struct altera_spi_device *spi_master;
|
||||||
|
struct spi_transaction_dev *spi_tran_dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FLASH_BASE 0x10000000
|
||||||
|
#define FLASH_OPTION_BITS 0x10000
|
||||||
|
|
||||||
|
#define NIOS2_FW_VERSION_OFF 0x300400
|
||||||
|
#define RSU_REG_OFF 0x30042c
|
||||||
|
#define FPGA_RP_LOAD BIT(3)
|
||||||
|
#define NIOS2_PRERESET BIT(4)
|
||||||
|
#define NIOS2_HANG BIT(5)
|
||||||
|
#define RSU_ENABLE BIT(6)
|
||||||
|
#define NIOS2_RESET BIT(7)
|
||||||
|
#define NIOS2_I2C2_POLL_STOP BIT(13)
|
||||||
|
#define FPGA_RECONF_REG_OFF 0x300430
|
||||||
|
#define COUNTDOWN_START BIT(18)
|
||||||
|
#define MAX10_BUILD_VER_OFF 0x300468
|
||||||
|
#define PCB_INFO GENMASK(31, 24)
|
||||||
|
#define MAX10_BUILD_VERION GENMASK(23, 0)
|
||||||
|
#define FPGA_PAGE_INFO_OFF 0x30046c
|
||||||
|
#define DT_AVAIL_REG_OFF 0x300490
|
||||||
|
#define DT_AVAIL BIT(0)
|
||||||
|
#define DT_BASE_ADDR_REG_OFF 0x300494
|
||||||
|
#define PKVL_POLLING_CTRL 0x300480
|
||||||
|
#define PKVL_LINK_STATUS 0x300564
|
||||||
|
|
||||||
|
#define DFT_MAX_SIZE 0x7e0000
|
||||||
|
|
||||||
|
int max10_reg_read(unsigned int reg, unsigned int *val);
|
||||||
|
int max10_reg_write(unsigned int reg, unsigned int val);
|
||||||
|
struct intel_max10_device *
|
||||||
|
intel_max10_device_probe(struct altera_spi_device *spi,
|
||||||
|
int chipselect);
|
||||||
|
int intel_max10_device_remove(struct intel_max10_device *dev);
|
||||||
|
|
||||||
|
#endif
|
@ -35,6 +35,7 @@ struct uuid {
|
|||||||
#ifndef BIT
|
#ifndef BIT
|
||||||
#define BIT(a) (1UL << (a))
|
#define BIT(a) (1UL << (a))
|
||||||
#endif /* BIT */
|
#endif /* BIT */
|
||||||
|
#define U64_C(x) x ## ULL
|
||||||
#ifndef BIT_ULL
|
#ifndef BIT_ULL
|
||||||
#define BIT_ULL(a) (1ULL << (a))
|
#define BIT_ULL(a) (1ULL << (a))
|
||||||
#endif /* BIT_ULL */
|
#endif /* BIT_ULL */
|
||||||
@ -76,5 +77,8 @@ struct uuid {
|
|||||||
#define msleep(x) opae_udelay(1000 * (x))
|
#define msleep(x) opae_udelay(1000 * (x))
|
||||||
#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
|
#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
|
||||||
|
|
||||||
|
#define time_after(a, b) ((long)((b) - (a)) < 0)
|
||||||
|
#define time_before(a, b) time_after(b, a)
|
||||||
#define opae_memset(a, b, c) memset((a), (b), (c))
|
#define opae_memset(a, b, c) memset((a), (b), (c))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
304
drivers/raw/ifpga_rawdev/base/opae_spi.c
Normal file
304
drivers/raw/ifpga_rawdev/base/opae_spi.c
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opae_osdep.h"
|
||||||
|
#include "opae_spi.h"
|
||||||
|
|
||||||
|
static int nios_spi_indirect_read(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
u64 ctrl = 0;
|
||||||
|
u64 stat = 0;
|
||||||
|
int loops = SPI_MAX_RETRY;
|
||||||
|
|
||||||
|
ctrl = NIOS_SPI_RD | ((u64)reg << 32);
|
||||||
|
opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL);
|
||||||
|
|
||||||
|
stat = opae_readq(dev->regs + NIOS_SPI_STAT);
|
||||||
|
while (!(stat & NIOS_SPI_VALID) && --loops)
|
||||||
|
stat = opae_readq(dev->regs + NIOS_SPI_STAT);
|
||||||
|
|
||||||
|
*val = stat & NIOS_SPI_READ_DATA;
|
||||||
|
|
||||||
|
return loops ? 0 : -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nios_spi_indirect_write(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
|
||||||
|
u64 ctrl = 0;
|
||||||
|
u64 stat = 0;
|
||||||
|
int loops = SPI_MAX_RETRY;
|
||||||
|
|
||||||
|
ctrl |= NIOS_SPI_WR | (u64)reg << 32;
|
||||||
|
ctrl |= value & NIOS_SPI_WRITE_DATA;
|
||||||
|
|
||||||
|
opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL);
|
||||||
|
|
||||||
|
stat = opae_readq(dev->regs + NIOS_SPI_STAT);
|
||||||
|
while (!(stat & NIOS_SPI_VALID) && --loops)
|
||||||
|
stat = opae_readq(dev->regs + NIOS_SPI_STAT);
|
||||||
|
|
||||||
|
return loops ? 0 : -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_indirect_write(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
u64 ctrl;
|
||||||
|
|
||||||
|
opae_writeq(value & WRITE_DATA_MASK, dev->regs + SPI_WRITE);
|
||||||
|
|
||||||
|
ctrl = CTRL_W | (reg >> 2);
|
||||||
|
opae_writeq(ctrl, dev->regs + SPI_CTRL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_indirect_read(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
u64 tmp;
|
||||||
|
u64 ctrl;
|
||||||
|
|
||||||
|
ctrl = CTRL_R | (reg >> 2);
|
||||||
|
opae_writeq(ctrl, dev->regs + SPI_CTRL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Read one more time to avoid HW timing issue. This is
|
||||||
|
* a short term workaround solution, and must be removed once
|
||||||
|
* hardware fixing is done.
|
||||||
|
*/
|
||||||
|
tmp = opae_readq(dev->regs + SPI_READ);
|
||||||
|
|
||||||
|
*val = (u32)tmp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_reg_write(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
return dev->reg_write(dev, reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_reg_read(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
return dev->reg_read(dev, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select)
|
||||||
|
{
|
||||||
|
spi_reg_write(dev, ALTERA_SPI_SLAVE_SEL, 1 << chip_select);
|
||||||
|
spi_reg_write(dev, ALTERA_SPI_CONTROL, ALTERA_SPI_CONTROL_SSO_MSK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_cs_deactivate(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
spi_reg_write(dev, ALTERA_SPI_CONTROL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_flush_rx(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val & ALTERA_SPI_STATUS_RRDY_MSK) {
|
||||||
|
ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int spi_write_bytes(struct altera_spi_device *dev, int count)
|
||||||
|
{
|
||||||
|
unsigned int val = 0;
|
||||||
|
u16 *p16;
|
||||||
|
u32 *p32;
|
||||||
|
|
||||||
|
if (dev->txbuf) {
|
||||||
|
switch (dev->data_width) {
|
||||||
|
case 1:
|
||||||
|
val = dev->txbuf[count];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
p16 = (u16 *)(dev->txbuf + 2*count);
|
||||||
|
val = *p16;
|
||||||
|
if (dev->endian == SPI_BIG_ENDIAN)
|
||||||
|
val = cpu_to_be16(val);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
p32 = (u32 *)(dev->txbuf + 4*count);
|
||||||
|
val = *p32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_fill_readbuffer(struct altera_spi_device *dev,
|
||||||
|
unsigned int value, int count)
|
||||||
|
{
|
||||||
|
u16 *p16;
|
||||||
|
u32 *p32;
|
||||||
|
|
||||||
|
if (dev->rxbuf) {
|
||||||
|
switch (dev->data_width) {
|
||||||
|
case 1:
|
||||||
|
dev->rxbuf[count] = value;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
p16 = (u16 *)(dev->rxbuf + 2*count);
|
||||||
|
if (dev->endian == SPI_BIG_ENDIAN)
|
||||||
|
*p16 = cpu_to_be16((u16)value);
|
||||||
|
else
|
||||||
|
*p16 = (u16)value;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
p32 = (u32 *)(dev->rxbuf + 4*count);
|
||||||
|
if (dev->endian == SPI_BIG_ENDIAN)
|
||||||
|
*p32 = cpu_to_be32(value);
|
||||||
|
else
|
||||||
|
*p32 = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_txrx(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
u32 rxd;
|
||||||
|
unsigned int tx_data;
|
||||||
|
u32 status;
|
||||||
|
int retry = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (count < dev->len) {
|
||||||
|
tx_data = spi_write_bytes(dev, count);
|
||||||
|
spi_reg_write(dev, ALTERA_SPI_TXDATA, tx_data);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &status);
|
||||||
|
if (ret)
|
||||||
|
return -EIO;
|
||||||
|
if (status & ALTERA_SPI_STATUS_RRDY_MSK)
|
||||||
|
break;
|
||||||
|
if (retry++ > SPI_MAX_RETRY) {
|
||||||
|
dev_err(dev, "%s, read timeout\n", __func__);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &rxd);
|
||||||
|
if (ret)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
spi_fill_readbuffer(dev, rxd, count);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_command(struct altera_spi_device *dev, unsigned int chip_select,
|
||||||
|
unsigned int wlen, void *wdata,
|
||||||
|
unsigned int rlen, void *rdata)
|
||||||
|
{
|
||||||
|
if (((wlen > 0) && !wdata) || ((rlen > 0) && !rdata)) {
|
||||||
|
dev_err(dev, "error on spi command checking\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlen = wlen / dev->data_width;
|
||||||
|
rlen = rlen / dev->data_width;
|
||||||
|
|
||||||
|
/* flush rx buffer */
|
||||||
|
spi_flush_rx(dev);
|
||||||
|
|
||||||
|
spi_cs_activate(dev, chip_select);
|
||||||
|
if (wlen) {
|
||||||
|
dev->txbuf = wdata;
|
||||||
|
dev->rxbuf = rdata;
|
||||||
|
dev->len = wlen;
|
||||||
|
spi_txrx(dev);
|
||||||
|
}
|
||||||
|
if (rlen) {
|
||||||
|
dev->rxbuf = rdata;
|
||||||
|
dev->txbuf = NULL;
|
||||||
|
dev->len = rlen;
|
||||||
|
spi_txrx(dev);
|
||||||
|
}
|
||||||
|
spi_cs_deactivate(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct altera_spi_device *altera_spi_alloc(void *base, int type)
|
||||||
|
{
|
||||||
|
struct altera_spi_device *spi_dev =
|
||||||
|
opae_malloc(sizeof(struct altera_spi_device));
|
||||||
|
|
||||||
|
if (!spi_dev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
spi_dev->regs = base;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_SPI:
|
||||||
|
spi_dev->reg_read = spi_indirect_read;
|
||||||
|
spi_dev->reg_write = spi_indirect_write;
|
||||||
|
break;
|
||||||
|
case TYPE_NIOS_SPI:
|
||||||
|
spi_dev->reg_read = nios_spi_indirect_read;
|
||||||
|
spi_dev->reg_write = nios_spi_indirect_write;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "%s: invalid SPI type\n", __func__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spi_dev;
|
||||||
|
|
||||||
|
error:
|
||||||
|
altera_spi_release(spi_dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void altera_spi_init(struct altera_spi_device *spi_dev)
|
||||||
|
{
|
||||||
|
spi_dev->spi_param.info = opae_readq(spi_dev->regs + SPI_CORE_PARAM);
|
||||||
|
|
||||||
|
spi_dev->data_width = spi_dev->spi_param.data_width / 8;
|
||||||
|
spi_dev->endian = spi_dev->spi_param.endian;
|
||||||
|
spi_dev->num_chipselect = spi_dev->spi_param.num_chipselect;
|
||||||
|
dev_info(spi_dev, "spi param: type=%d, data width:%d, endian:%d, clock_polarity=%d, clock=%dMHz, chips=%d, cpha=%d\n",
|
||||||
|
spi_dev->spi_param.type,
|
||||||
|
spi_dev->data_width, spi_dev->endian,
|
||||||
|
spi_dev->spi_param.clock_polarity,
|
||||||
|
spi_dev->spi_param.clock,
|
||||||
|
spi_dev->num_chipselect,
|
||||||
|
spi_dev->spi_param.clock_phase);
|
||||||
|
|
||||||
|
/* clear */
|
||||||
|
spi_reg_write(spi_dev, ALTERA_SPI_CONTROL, 0);
|
||||||
|
spi_reg_write(spi_dev, ALTERA_SPI_STATUS, 0);
|
||||||
|
/* flush rxdata */
|
||||||
|
spi_flush_rx(spi_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void altera_spi_release(struct altera_spi_device *dev)
|
||||||
|
{
|
||||||
|
if (dev)
|
||||||
|
opae_free(dev);
|
||||||
|
}
|
160
drivers/raw/ifpga_rawdev/base/opae_spi.h
Normal file
160
drivers/raw/ifpga_rawdev/base/opae_spi.h
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _OPAE_SPI_H
|
||||||
|
#define _OPAE_SPI_H
|
||||||
|
|
||||||
|
#include "opae_osdep.h"
|
||||||
|
|
||||||
|
#define ALTERA_SPI_RXDATA 0
|
||||||
|
#define ALTERA_SPI_TXDATA 4
|
||||||
|
#define ALTERA_SPI_STATUS 8
|
||||||
|
#define ALTERA_SPI_CONTROL 12
|
||||||
|
#define ALTERA_SPI_SLAVE_SEL 20
|
||||||
|
|
||||||
|
#define ALTERA_SPI_STATUS_ROE_MSK 0x8
|
||||||
|
#define ALTERA_SPI_STATUS_TOE_MSK 0x10
|
||||||
|
#define ALTERA_SPI_STATUS_TMT_MSK 0x20
|
||||||
|
#define ALTERA_SPI_STATUS_TRDY_MSK 0x40
|
||||||
|
#define ALTERA_SPI_STATUS_RRDY_MSK 0x80
|
||||||
|
#define ALTERA_SPI_STATUS_E_MSK 0x100
|
||||||
|
|
||||||
|
#define ALTERA_SPI_CONTROL_IROE_MSK 0x8
|
||||||
|
#define ALTERA_SPI_CONTROL_ITOE_MSK 0x10
|
||||||
|
#define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40
|
||||||
|
#define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80
|
||||||
|
#define ALTERA_SPI_CONTROL_IE_MSK 0x100
|
||||||
|
#define ALTERA_SPI_CONTROL_SSO_MSK 0x400
|
||||||
|
|
||||||
|
#define SPI_CORE_PARAM 0x8
|
||||||
|
#define SPI_CTRL 0x10
|
||||||
|
#define CTRL_R BIT_ULL(9)
|
||||||
|
#define CTRL_W BIT_ULL(8)
|
||||||
|
#define CTRL_ADDR_MASK GENMASK_ULL(2, 0)
|
||||||
|
#define SPI_READ 0x18
|
||||||
|
#define READ_DATA_VALID BIT_ULL(32)
|
||||||
|
#define READ_DATA_MASK GENMASK_ULL(31, 0)
|
||||||
|
#define SPI_WRITE 0x20
|
||||||
|
#define WRITE_DATA_MASK GENMASK_ULL(31, 0)
|
||||||
|
|
||||||
|
#define SPI_MAX_RETRY 100000
|
||||||
|
|
||||||
|
#define TYPE_SPI 0
|
||||||
|
#define TYPE_NIOS_SPI 1
|
||||||
|
|
||||||
|
struct spi_core_param {
|
||||||
|
union {
|
||||||
|
u64 info;
|
||||||
|
struct {
|
||||||
|
u8 type:1;
|
||||||
|
u8 endian:1;
|
||||||
|
u8 data_width:6;
|
||||||
|
u8 num_chipselect:6;
|
||||||
|
u8 clock_polarity:1;
|
||||||
|
u8 clock_phase:1;
|
||||||
|
u8 stages:2;
|
||||||
|
u8 resvd:4;
|
||||||
|
u16 clock:10;
|
||||||
|
u16 peripheral_id:16;
|
||||||
|
u8 controller_type:1;
|
||||||
|
u16 resvd1:15;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct altera_spi_device {
|
||||||
|
u8 *regs;
|
||||||
|
struct spi_core_param spi_param;
|
||||||
|
int data_width; /* how many bytes for data width */
|
||||||
|
int endian;
|
||||||
|
#define SPI_BIG_ENDIAN 0
|
||||||
|
#define SPI_LITTLE_ENDIAN 1
|
||||||
|
int num_chipselect;
|
||||||
|
unsigned char *rxbuf;
|
||||||
|
unsigned char *txbuf;
|
||||||
|
unsigned int len;
|
||||||
|
int (*reg_read)(struct altera_spi_device *dev, u32 reg, u32 *val);
|
||||||
|
int (*reg_write)(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 value);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HEADER_LEN 8
|
||||||
|
#define RESPONSE_LEN 4
|
||||||
|
#define SPI_TRANSACTION_MAX_LEN 1024
|
||||||
|
#define TRAN_SEND_MAX_LEN (SPI_TRANSACTION_MAX_LEN + HEADER_LEN)
|
||||||
|
#define TRAN_RESP_MAX_LEN SPI_TRANSACTION_MAX_LEN
|
||||||
|
#define PACKET_SEND_MAX_LEN (2*TRAN_SEND_MAX_LEN + 4)
|
||||||
|
#define PACKET_RESP_MAX_LEN (2*TRAN_RESP_MAX_LEN + 4)
|
||||||
|
#define BYTES_SEND_MAX_LEN (2*PACKET_SEND_MAX_LEN)
|
||||||
|
#define BYTES_RESP_MAX_LEN (2*PACKET_RESP_MAX_LEN)
|
||||||
|
|
||||||
|
struct spi_tran_buffer {
|
||||||
|
unsigned char tran_send[TRAN_SEND_MAX_LEN];
|
||||||
|
unsigned char tran_resp[TRAN_RESP_MAX_LEN];
|
||||||
|
unsigned char packet_send[PACKET_SEND_MAX_LEN];
|
||||||
|
unsigned char packet_resp[PACKET_RESP_MAX_LEN];
|
||||||
|
unsigned char bytes_send[BYTES_SEND_MAX_LEN];
|
||||||
|
unsigned char bytes_resp[2*BYTES_RESP_MAX_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spi_transaction_dev {
|
||||||
|
struct altera_spi_device *dev;
|
||||||
|
int chipselect;
|
||||||
|
struct spi_tran_buffer *buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spi_tran_header {
|
||||||
|
u8 trans_type;
|
||||||
|
u8 reserve;
|
||||||
|
u16 size;
|
||||||
|
u32 addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int spi_command(struct altera_spi_device *dev, unsigned int chip_select,
|
||||||
|
unsigned int wlen, void *wdata, unsigned int rlen, void *rdata);
|
||||||
|
void spi_cs_deactivate(struct altera_spi_device *dev);
|
||||||
|
void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select);
|
||||||
|
struct altera_spi_device *altera_spi_alloc(void *base, int type);
|
||||||
|
void altera_spi_init(struct altera_spi_device *dev);
|
||||||
|
void altera_spi_release(struct altera_spi_device *dev);
|
||||||
|
int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr,
|
||||||
|
unsigned int size, unsigned char *data);
|
||||||
|
int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr,
|
||||||
|
unsigned int size, unsigned char *data);
|
||||||
|
struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev,
|
||||||
|
int chipselect);
|
||||||
|
void spi_transaction_remove(struct spi_transaction_dev *dev);
|
||||||
|
int spi_reg_write(struct altera_spi_device *dev, u32 reg,
|
||||||
|
u32 value);
|
||||||
|
int spi_reg_read(struct altera_spi_device *dev, u32 reg, u32 *val);
|
||||||
|
|
||||||
|
#define NIOS_SPI_PARAM 0x8
|
||||||
|
#define CONTROL_TYPE BIT_ULL(48)
|
||||||
|
#define PERI_ID GENMASK_ULL(47, 32)
|
||||||
|
#define SPI_CLK GENMASK_ULL(31, 22)
|
||||||
|
#define SYNC_STAGES GENMASK_ULL(17, 16)
|
||||||
|
#define CLOCK_PHASE BIT_ULL(15)
|
||||||
|
#define CLOCK_POLARITY BIT_ULL(14)
|
||||||
|
#define NUM_SELECT GENMASK_ULL(13, 8)
|
||||||
|
#define DATA_WIDTH GENMASK_ULL(7, 2)
|
||||||
|
#define SHIFT_DIRECTION BIT_ULL(1)
|
||||||
|
#define SPI_TYPE BIT_ULL(0)
|
||||||
|
#define NIOS_SPI_CTRL 0x10
|
||||||
|
#define NIOS_SPI_RD (0x1ULL << 62)
|
||||||
|
#define NIOS_SPI_WR (0x2ULL << 62)
|
||||||
|
#define NIOS_SPI_COMMAND GENMASK_ULL(63, 62)
|
||||||
|
#define NIOS_SPI_ADDR GENMASK_ULL(44, 32)
|
||||||
|
#define NIOS_SPI_WRITE_DATA GENMASK_ULL(31, 0)
|
||||||
|
#define NIOS_SPI_STAT 0x18
|
||||||
|
#define NIOS_SPI_VALID BIT_ULL(32)
|
||||||
|
#define NIOS_SPI_READ_DATA GENMASK_ULL(31, 0)
|
||||||
|
#define NIOS_SPI_INIT_DONE 0x1000
|
||||||
|
|
||||||
|
#define NIOS_SPI_INIT_DONE 0x1000
|
||||||
|
#define NIOS_SPI_INIT_STS0 0x1020
|
||||||
|
#define NIOS_SPI_INIT_STS1 0x1024
|
||||||
|
#define PKVL_STATUS_RESET 0
|
||||||
|
#define PKVL_10G_MODE 1
|
||||||
|
#define PKVL_25G_MODE 2
|
||||||
|
#endif
|
438
drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c
Normal file
438
drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opae_spi.h"
|
||||||
|
#include "ifpga_compat.h"
|
||||||
|
|
||||||
|
/*transaction opcodes*/
|
||||||
|
#define SPI_TRAN_SEQ_WRITE 0x04 /* SPI transaction sequential write */
|
||||||
|
#define SPI_TRAN_SEQ_READ 0x14 /* SPI transaction sequential read */
|
||||||
|
#define SPI_TRAN_NON_SEQ_WRITE 0x00 /* SPI transaction non-sequential write */
|
||||||
|
#define SPI_TRAN_NON_SEQ_READ 0x10 /* SPI transaction non-sequential read*/
|
||||||
|
|
||||||
|
/*specail packet characters*/
|
||||||
|
#define SPI_PACKET_SOP 0x7a
|
||||||
|
#define SPI_PACKET_EOP 0x7b
|
||||||
|
#define SPI_PACKET_CHANNEL 0x7c
|
||||||
|
#define SPI_PACKET_ESC 0x7d
|
||||||
|
|
||||||
|
/*special byte characters*/
|
||||||
|
#define SPI_BYTE_IDLE 0x4a
|
||||||
|
#define SPI_BYTE_ESC 0x4d
|
||||||
|
|
||||||
|
#define SPI_REG_BYTES 4
|
||||||
|
|
||||||
|
#define INIT_SPI_TRAN_HEADER(trans_type, size, address) \
|
||||||
|
({ \
|
||||||
|
header.trans_type = trans_type; \
|
||||||
|
header.reserve = 0; \
|
||||||
|
header.size = cpu_to_be16(size); \
|
||||||
|
header.addr = cpu_to_be32(addr); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#ifdef OPAE_SPI_DEBUG
|
||||||
|
static void print_buffer(const char *string, void *buffer, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char *p = buffer;
|
||||||
|
|
||||||
|
printf("%s print buffer, len=%d\n", string, len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
printf("%x ", *(p+i));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void print_buffer(const char *string, void *buffer, int len)
|
||||||
|
{
|
||||||
|
UNUSED(string);
|
||||||
|
UNUSED(buffer);
|
||||||
|
UNUSED(len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static unsigned char xor_20(unsigned char val)
|
||||||
|
{
|
||||||
|
return val^0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reorder_phy_data(u8 bits_per_word,
|
||||||
|
void *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int count = len / (bits_per_word/8);
|
||||||
|
u32 *p;
|
||||||
|
|
||||||
|
if (bits_per_word == 32) {
|
||||||
|
p = (u32 *)buf;
|
||||||
|
while (count--) {
|
||||||
|
*p = cpu_to_be32(*p);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SPI_FOUND_SOP,
|
||||||
|
SPI_FOUND_EOP,
|
||||||
|
SPI_NOT_FOUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int resp_find_sop_eop(unsigned char *resp, unsigned int len,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
int ret = SPI_NOT_FOUND;
|
||||||
|
|
||||||
|
unsigned char *b = resp;
|
||||||
|
|
||||||
|
/* find SOP */
|
||||||
|
if (flags != SPI_FOUND_SOP) {
|
||||||
|
while (b < resp + len && *b != SPI_PACKET_SOP)
|
||||||
|
b++;
|
||||||
|
|
||||||
|
if (*b != SPI_PACKET_SOP)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
ret = SPI_FOUND_SOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find EOP */
|
||||||
|
while (b < resp + len && *b != SPI_PACKET_EOP)
|
||||||
|
b++;
|
||||||
|
|
||||||
|
if (*b != SPI_PACKET_EOP)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
ret = SPI_FOUND_EOP;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int byte_to_core_convert(struct spi_transaction_dev *dev,
|
||||||
|
unsigned int send_len, unsigned char *send_data,
|
||||||
|
unsigned int resp_len, unsigned char *resp_data,
|
||||||
|
unsigned int *valid_resp_len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned char *send_packet = dev->buffer->bytes_send;
|
||||||
|
unsigned char *resp_packet = dev->buffer->bytes_resp;
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned char current_byte;
|
||||||
|
unsigned char *tx_buffer;
|
||||||
|
unsigned int tx_len = 0;
|
||||||
|
unsigned char *rx_buffer;
|
||||||
|
unsigned int rx_len = 0;
|
||||||
|
int retry = 0;
|
||||||
|
int spi_flags;
|
||||||
|
unsigned int resp_max_len = 2 * resp_len;
|
||||||
|
|
||||||
|
print_buffer("before bytes:", send_data, send_len);
|
||||||
|
|
||||||
|
p = send_packet;
|
||||||
|
|
||||||
|
for (i = 0; i < send_len; i++) {
|
||||||
|
current_byte = send_data[i];
|
||||||
|
switch (current_byte) {
|
||||||
|
case SPI_BYTE_IDLE:
|
||||||
|
*p++ = SPI_BYTE_IDLE;
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
break;
|
||||||
|
case SPI_BYTE_ESC:
|
||||||
|
*p++ = SPI_BYTE_ESC;
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = current_byte;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_buffer("before spi:", send_packet, p-send_packet);
|
||||||
|
|
||||||
|
reorder_phy_data(32, send_packet, p - send_packet);
|
||||||
|
|
||||||
|
print_buffer("after order to spi:", send_packet, p-send_packet);
|
||||||
|
|
||||||
|
/* call spi */
|
||||||
|
tx_buffer = send_packet;
|
||||||
|
tx_len = p - send_packet;
|
||||||
|
rx_buffer = resp_packet;
|
||||||
|
rx_len = resp_max_len;
|
||||||
|
spi_flags = SPI_NOT_FOUND;
|
||||||
|
|
||||||
|
read_again:
|
||||||
|
ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer,
|
||||||
|
rx_len, rx_buffer);
|
||||||
|
if (ret)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
print_buffer("read from spi:", rx_buffer, rx_len);
|
||||||
|
|
||||||
|
/* look for SOP firstly*/
|
||||||
|
ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags);
|
||||||
|
if (ret != SPI_FOUND_EOP) {
|
||||||
|
tx_buffer = NULL;
|
||||||
|
tx_len = 0;
|
||||||
|
if (retry++ > 10) {
|
||||||
|
dev_err(NULL, "cannot found valid data from SPI\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == SPI_FOUND_SOP) {
|
||||||
|
rx_buffer += rx_len;
|
||||||
|
resp_max_len += rx_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_flags = ret;
|
||||||
|
goto read_again;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_buffer("found valid data:", resp_packet, resp_max_len);
|
||||||
|
|
||||||
|
/* analyze response packet */
|
||||||
|
i = 0;
|
||||||
|
p = resp_data;
|
||||||
|
while (i < resp_max_len) {
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
switch (current_byte) {
|
||||||
|
case SPI_BYTE_IDLE:
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
case SPI_BYTE_ESC:
|
||||||
|
i++;
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = current_byte;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive "4a" means the SPI is idle, not valid data */
|
||||||
|
*valid_resp_len = p - resp_data;
|
||||||
|
if (*valid_resp_len == 0) {
|
||||||
|
dev_err(NULL, "error: repond package without valid data\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int packet_to_byte_conver(struct spi_transaction_dev *dev,
|
||||||
|
unsigned int send_len, unsigned char *send_buf,
|
||||||
|
unsigned int resp_len, unsigned char *resp_buf,
|
||||||
|
unsigned int *valid)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned char current_byte;
|
||||||
|
unsigned int resp_max_len;
|
||||||
|
unsigned char *send_packet = dev->buffer->packet_send;
|
||||||
|
unsigned char *resp_packet = dev->buffer->packet_resp;
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned int valid_resp_len = 0;
|
||||||
|
|
||||||
|
print_buffer("before packet:", send_buf, send_len);
|
||||||
|
|
||||||
|
resp_max_len = 2 * resp_len + 4;
|
||||||
|
|
||||||
|
p = send_packet;
|
||||||
|
|
||||||
|
/* SOP header */
|
||||||
|
*p++ = SPI_PACKET_SOP;
|
||||||
|
|
||||||
|
*p++ = SPI_PACKET_CHANNEL;
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
/* append the data into a packet */
|
||||||
|
for (i = 0; i < send_len; i++) {
|
||||||
|
current_byte = send_buf[i];
|
||||||
|
|
||||||
|
/* EOP for last byte */
|
||||||
|
if (i == send_len - 1)
|
||||||
|
*p++ = SPI_PACKET_EOP;
|
||||||
|
|
||||||
|
switch (current_byte) {
|
||||||
|
case SPI_PACKET_SOP:
|
||||||
|
case SPI_PACKET_EOP:
|
||||||
|
case SPI_PACKET_CHANNEL:
|
||||||
|
case SPI_PACKET_ESC:
|
||||||
|
*p++ = SPI_PACKET_ESC;
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = current_byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = byte_to_core_convert(dev, p - send_packet,
|
||||||
|
send_packet, resp_max_len, resp_packet,
|
||||||
|
&valid_resp_len);
|
||||||
|
if (ret)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
print_buffer("after byte conver:", resp_packet, valid_resp_len);
|
||||||
|
|
||||||
|
/* analyze the response packet */
|
||||||
|
p = resp_buf;
|
||||||
|
|
||||||
|
/* look for SOP */
|
||||||
|
for (i = 0; i < valid_resp_len; i++) {
|
||||||
|
if (resp_packet[i] == SPI_PACKET_SOP)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == valid_resp_len) {
|
||||||
|
dev_err(NULL, "error on analyze response packet 0x%x\n",
|
||||||
|
resp_packet[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
/* continue parsing data after SOP */
|
||||||
|
while (i < valid_resp_len) {
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
|
||||||
|
switch (current_byte) {
|
||||||
|
case SPI_PACKET_ESC:
|
||||||
|
case SPI_PACKET_CHANNEL:
|
||||||
|
case SPI_PACKET_SOP:
|
||||||
|
i++;
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
case SPI_PACKET_EOP:
|
||||||
|
i++;
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
if (current_byte == SPI_PACKET_ESC ||
|
||||||
|
current_byte == SPI_PACKET_CHANNEL ||
|
||||||
|
current_byte == SPI_PACKET_SOP) {
|
||||||
|
i++;
|
||||||
|
current_byte = resp_packet[i];
|
||||||
|
*p++ = xor_20(current_byte);
|
||||||
|
} else
|
||||||
|
*p++ = current_byte;
|
||||||
|
i = valid_resp_len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = current_byte;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
*valid = p - resp_buf;
|
||||||
|
|
||||||
|
print_buffer("after packet:", resp_buf, *valid);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_transaction(struct spi_transaction_dev *dev, unsigned int addr,
|
||||||
|
unsigned int size, unsigned char *data,
|
||||||
|
unsigned int trans_type)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct spi_tran_header header;
|
||||||
|
unsigned char *transaction = dev->buffer->tran_send;
|
||||||
|
unsigned char *response = dev->buffer->tran_resp;
|
||||||
|
unsigned char *p;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int valid_len = 0;
|
||||||
|
|
||||||
|
/* make transacation header */
|
||||||
|
INIT_SPI_TRAN_HEADER(trans_type, size, addr);
|
||||||
|
|
||||||
|
/* fill the header */
|
||||||
|
p = transaction;
|
||||||
|
opae_memcpy(p, &header, sizeof(struct spi_tran_header));
|
||||||
|
p = p + sizeof(struct spi_tran_header);
|
||||||
|
|
||||||
|
switch (trans_type) {
|
||||||
|
case SPI_TRAN_SEQ_WRITE:
|
||||||
|
case SPI_TRAN_NON_SEQ_WRITE:
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
*p++ = *data++;
|
||||||
|
|
||||||
|
ret = packet_to_byte_conver(dev, size + HEADER_LEN,
|
||||||
|
transaction, RESPONSE_LEN, response,
|
||||||
|
&valid_len);
|
||||||
|
if (ret)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
/* check the result */
|
||||||
|
if (size != ((unsigned int)(response[2] & 0xff) << 8 |
|
||||||
|
(unsigned int)(response[3] & 0xff)))
|
||||||
|
ret = -EBUSY;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SPI_TRAN_SEQ_READ:
|
||||||
|
case SPI_TRAN_NON_SEQ_READ:
|
||||||
|
ret = packet_to_byte_conver(dev, HEADER_LEN,
|
||||||
|
transaction, size, response,
|
||||||
|
&valid_len);
|
||||||
|
if (ret || valid_len != size)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
*data++ = *response++;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr,
|
||||||
|
unsigned int size, unsigned char *data)
|
||||||
|
{
|
||||||
|
return do_transaction(dev, addr, size, data,
|
||||||
|
(size > SPI_REG_BYTES) ?
|
||||||
|
SPI_TRAN_SEQ_READ : SPI_TRAN_NON_SEQ_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr,
|
||||||
|
unsigned int size, unsigned char *data)
|
||||||
|
{
|
||||||
|
return do_transaction(dev, addr, size, data,
|
||||||
|
(size > SPI_REG_BYTES) ?
|
||||||
|
SPI_TRAN_SEQ_WRITE : SPI_TRAN_NON_SEQ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev,
|
||||||
|
int chipselect)
|
||||||
|
{
|
||||||
|
struct spi_transaction_dev *spi_tran_dev;
|
||||||
|
|
||||||
|
spi_tran_dev = opae_malloc(sizeof(struct spi_transaction_dev));
|
||||||
|
if (!spi_tran_dev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
spi_tran_dev->dev = dev;
|
||||||
|
spi_tran_dev->chipselect = chipselect;
|
||||||
|
|
||||||
|
spi_tran_dev->buffer = opae_malloc(sizeof(struct spi_tran_buffer));
|
||||||
|
if (!spi_tran_dev->buffer) {
|
||||||
|
opae_free(spi_tran_dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spi_tran_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_transaction_remove(struct spi_transaction_dev *dev)
|
||||||
|
{
|
||||||
|
if (dev && dev->buffer)
|
||||||
|
opae_free(dev->buffer);
|
||||||
|
if (dev)
|
||||||
|
opae_free(dev);
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#include <rte_log.h>
|
#include <rte_log.h>
|
||||||
#include <rte_io.h>
|
#include <rte_io.h>
|
||||||
#include <rte_malloc.h>
|
#include <rte_malloc.h>
|
||||||
|
#include <rte_byteorder.h>
|
||||||
#include <rte_memcpy.h>
|
#include <rte_memcpy.h>
|
||||||
|
|
||||||
#define dev_printf(level, fmt, args...) \
|
#define dev_printf(level, fmt, args...) \
|
||||||
@ -43,5 +44,18 @@
|
|||||||
#define spinlock_lock(x) rte_spinlock_lock(x)
|
#define spinlock_lock(x) rte_spinlock_lock(x)
|
||||||
#define spinlock_unlock(x) rte_spinlock_unlock(x)
|
#define spinlock_unlock(x) rte_spinlock_unlock(x)
|
||||||
|
|
||||||
|
#define cpu_to_be16(o) rte_cpu_to_be_16(o)
|
||||||
|
#define cpu_to_be32(o) rte_cpu_to_be_32(o)
|
||||||
|
#define cpu_to_be64(o) rte_cpu_to_be_64(o)
|
||||||
|
#define cpu_to_le16(o) rte_cpu_to_le_16(o)
|
||||||
|
#define cpu_to_le32(o) rte_cpu_to_le_32(o)
|
||||||
|
#define cpu_to_le64(o) rte_cpu_to_le_64(o)
|
||||||
|
|
||||||
#define opae_memcpy(a, b, c) rte_memcpy((a), (b), (c))
|
#define opae_memcpy(a, b, c) rte_memcpy((a), (b), (c))
|
||||||
|
|
||||||
|
static inline unsigned long msecs_to_timer_cycles(unsigned int m)
|
||||||
|
{
|
||||||
|
return rte_get_timer_hz() * (m / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user