Skip to content

Commit

Permalink
raw/ifpga/base: add SPI and MAX10 device driver
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Figo-zhang authored and Ferruh Yigit committed Apr 19, 2019
1 parent e4dc499 commit 96ebfcf
Show file tree
Hide file tree
Showing 15 changed files with 1,285 additions and 1 deletion.
3 changes: 3 additions & 0 deletions drivers/raw/ifpga_rawdev/base/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ SRCS-y += opae_hw_api.c
SRCS-y += opae_ifpga_hw_api.c
SRCS-y += opae_debug.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)
5 changes: 5 additions & 0 deletions drivers/raw/ifpga_rawdev/base/ifpga_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#define FME_FEATURE_HSSI_ETH "fme_hssi"
#define FME_FEATURE_GLOBAL_DPERF "fme_dperf"
#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_UAFU "port_uafu"
Expand All @@ -43,6 +45,7 @@
#define FME_HSSI_ETH_REVISION 0
#define FME_GLOBAL_DPERF_REVISION 0
#define FME_QSPI_REVISION 0
#define FME_MAX10_SPI 0

#define PORT_HEADER_REVISION 0
/* UAFU's header info depends on the downloaded GBS */
Expand Down Expand Up @@ -80,6 +83,8 @@ enum fpga_id_type {
#define FME_FEATURE_ID_GLOBAL_DPERF 0x7
#define FME_FEATURE_ID_QSPI_FLASH 0x8
#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_ERROR 0x10
Expand Down
4 changes: 4 additions & 0 deletions drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ static struct feature_driver fme_feature_drvs[] = {
&fme_hssi_eth_ops),},
{FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT,
&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 */
};

Expand Down
2 changes: 2 additions & 0 deletions drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_hssi_eth_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_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop);
Expand Down
196 changes: 196 additions & 0 deletions drivers/raw/ifpga_rawdev/base/ifpga_fme.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

#include "ifpga_feature_dev.h"
#include "opae_spi.h"
#include "opae_intel_max10.h"

#define PWR_THRESHOLD_MAX 0x7F

Expand Down Expand Up @@ -764,3 +766,197 @@ struct feature_ops fme_emif_ops = {
.init = fme_emif_init,
.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,
};
2 changes: 2 additions & 0 deletions drivers/raw/ifpga_rawdev/base/ifpga_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct ifpga_fme_hw {
u32 cache_size;

u32 capability;

void *max10_dev; /* MAX10 device */
};

enum ifpga_port_state {
Expand Down
5 changes: 4 additions & 1 deletion drivers/raw/ifpga_rawdev/base/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ sources = [
'ifpga_fme_pr.c',
'opae_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',
Expand Down
1 change: 1 addition & 0 deletions drivers/raw/ifpga_rawdev/base/opae_hw_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sys/queue.h>

#include "opae_osdep.h"
#include "opae_intel_max10.h"

#ifndef PCI_MAX_RESOURCE
#define PCI_MAX_RESOURCE 6
Expand Down
88 changes: 88 additions & 0 deletions drivers/raw/ifpga_rawdev/base/opae_intel_max10.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 96ebfcf

Please sign in to comment.