GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,249 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2003
* Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
#include <common.h> /* core U-Boot definitions */
#include <console.h>
#include <ACEX1K.h> /* ACEX device family */
/* Define FPGA_DEBUG to get debug printf's */
#ifdef FPGA_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
/* Note: The assumption is that we cannot possibly run fast enough to
* overrun the device (the Slave Parallel mode can free run at 50MHz).
* If there is a need to operate slower, define CONFIG_FPGA_DELAY in
* the board config file to slow things down.
*/
#ifndef CONFIG_FPGA_DELAY
#define CONFIG_FPGA_DELAY()
#endif
#ifndef CONFIG_SYS_FPGA_WAIT
#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10 /* 100 ms */
#endif
static int ACEX1K_ps_load(Altera_desc *desc, const void *buf, size_t bsize);
static int ACEX1K_ps_dump(Altera_desc *desc, const void *buf, size_t bsize);
/* static int ACEX1K_ps_info(Altera_desc *desc); */
/* ------------------------------------------------------------------------- */
/* ACEX1K Generic Implementation */
int ACEX1K_load(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
PRINTF ("%s: Launching Passive Serial Loader\n", __FUNCTION__);
ret_val = ACEX1K_ps_load (desc, buf, bsize);
break;
/* Add new interface types here */
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
int ACEX1K_dump(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
PRINTF ("%s: Launching Passive Serial Dump\n", __FUNCTION__);
ret_val = ACEX1K_ps_dump (desc, buf, bsize);
break;
/* Add new interface types here */
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
int ACEX1K_info( Altera_desc *desc )
{
return FPGA_SUCCESS;
}
/* ------------------------------------------------------------------------- */
/* ACEX1K Passive Serial Generic Implementation */
static int ACEX1K_ps_load(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
Altera_ACEX1K_Passive_Serial_fns *fn = desc->iface_fns;
int i;
PRINTF ("%s: start with interface functions @ 0x%p\n",
__FUNCTION__, fn);
if (fn) {
size_t bytecount = 0;
unsigned char *data = (unsigned char *) buf;
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF ("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"config:\t0x%p\n"
"status:\t0x%p\n"
"clk:\t0x%p\n"
"data:\t0x%p\n"
"done:\t0x%p\n\n",
__FUNCTION__, &fn, fn, fn->config, fn->status,
fn->clk, fn->data, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf ("Loading FPGA Device %d...", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre) {
(*fn->pre) (cookie);
}
/* Establish the initial state */
(*fn->config) (true, true, cookie); /* Assert nCONFIG */
udelay(2); /* T_cfg > 2us */
/* nSTATUS should be asserted now */
(*fn->done) (cookie);
if ( !(*fn->status) (cookie) ) {
puts ("** nSTATUS is not asserted.\n");
(*fn->abort) (cookie);
return FPGA_FAIL;
}
(*fn->config) (false, true, cookie); /* Deassert nCONFIG */
udelay(2); /* T_cf2st1 < 4us */
/* Wait for nSTATUS to be released (i.e. deasserted) */
ts = get_timer (0); /* get current time */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for STATUS to go high.\n");
(*fn->abort) (cookie);
return FPGA_FAIL;
}
(*fn->done) (cookie);
} while ((*fn->status) (cookie));
/* Get ready for the burn */
CONFIG_FPGA_DELAY ();
/* Load the data */
while (bytecount < bsize) {
unsigned char val=0;
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
if (ctrlc ()) {
(*fn->abort) (cookie);
return FPGA_FAIL;
}
#endif
/* Altera detects an error if INIT goes low (active)
while DONE is low (inactive) */
#if 0 /* not yet implemented */
if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
puts ("** CRC error during FPGA load.\n");
(*fn->abort) (cookie);
return (FPGA_FAIL);
}
#endif
val = data [bytecount ++ ];
i = 8;
do {
/* Deassert the clock */
(*fn->clk) (false, true, cookie);
CONFIG_FPGA_DELAY ();
/* Write data */
(*fn->data) ((val & 0x01), true, cookie);
CONFIG_FPGA_DELAY ();
/* Assert the clock */
(*fn->clk) (true, true, cookie);
CONFIG_FPGA_DELAY ();
val >>= 1;
i --;
} while (i > 0);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
CONFIG_FPGA_DELAY ();
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc (' '); /* terminate the dotted line */
#endif
/*
* Checking FPGA's CONF_DONE signal - correctly booted ?
*/
if ( ! (*fn->done) (cookie) ) {
puts ("** Booting failed! CONF_DONE is still deasserted.\n");
(*fn->abort) (cookie);
return (FPGA_FAIL);
}
/*
* "DCLK must be clocked an additional 10 times fpr ACEX 1K..."
*/
for (i = 0; i < 12; i++) {
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
}
ret_val = FPGA_SUCCESS;
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS) {
puts ("Done.\n");
}
else {
puts ("Fail.\n");
}
#endif
(*fn->post) (cookie);
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
static int ACEX1K_ps_dump(Altera_desc *desc, const void *buf, size_t bsize)
{
/* Readback is only available through the Slave Parallel and */
/* boundary-scan interfaces. */
printf ("%s: Passive Serial Dumping is unavailable\n",
__FUNCTION__);
return FPGA_FAIL;
}
@@ -0,0 +1,88 @@
menu "FPGA support"
config FPGA
bool
config FPGA_ALTERA
bool "Enable Altera FPGA drivers"
select FPGA
help
Say Y here to enable the Altera FPGA driver
This provides basic infrastructure to support Altera FPGA devices.
Enable Altera FPGA specific functions which includes bitstream
(in BIT format), fpga and device validation.
config FPGA_SOCFPGA
bool "Enable Gen5 and Arria10 common FPGA drivers"
select FPGA_ALTERA
help
Say Y here to enable the Gen5 and Arria10 common FPGA driver
This provides common functionality for Gen5 and Arria10 devices.
config FPGA_CYCLON2
bool "Enable Altera FPGA driver for Cyclone II"
depends on FPGA_ALTERA
help
Say Y here to enable the Altera Cyclone II FPGA specific driver
This provides common functionality for Altera Cyclone II devices.
Enable FPGA driver for loading bitstream in BIT and BIN format
on Altera Cyclone II device.
config FPGA_STRATIX10
bool "Enable Altera FPGA driver for Stratix 10"
depends on TARGET_SOCFPGA_STRATIX10
select FPGA_ALTERA
help
Say Y here to enable the Altera Stratix 10 FPGA specific driver
This provides common functionality for Altera Stratix 10 devices.
Enable FPGA driver for writing bitstream into Altera Stratix10
device.
config FPGA_XILINX
bool "Enable Xilinx FPGA drivers"
select FPGA
help
Enable Xilinx FPGA specific functions which includes bitstream
(in BIT format), fpga and device validation.
config FPGA_ZYNQMPPL
bool "Enable Xilinx FPGA driver for ZynqMP"
depends on FPGA_XILINX
help
Enable FPGA driver for loading bitstream in BIT and BIN format
on Xilinx Zynq UltraScale+ (ZynqMP) device.
config FPGA_VERSALPL
bool "Enable Xilinx FPGA driver for Versal"
depends on FPGA_XILINX
help
Enable FPGA driver for loading bitstream in PDI format on Xilinx
Versal device. PDI is a new programmable device image format for
Versal. The bitstream will only be generated as PDI for Versal
platform.
config FPGA_SPARTAN3
bool "Enable Spartan3 FPGA driver"
depends on FPGA_XILINX
help
Enable Spartan3 FPGA driver for loading in BIT format.
config FPGA_VIRTEX2
bool "Enable Xilinx Virtex-II and later FPGA driver"
depends on FPGA_XILINX
help
Enable Virtex-II FPGA driver for loading in BIT format. This driver
also supports many newer Xilinx FPGA families.
config FPGA_ZYNQPL
bool "Enable Xilinx FPGA for Zynq"
depends on ARCH_ZYNQ
help
Enable FPGA driver for loading bitstream in BIT and BIN format
on Xilinx Zynq devices.
endmenu
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2008
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += fpga.o
obj-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
obj-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
obj-$(CONFIG_FPGA_VERSALPL) += versalpl.o
obj-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
obj-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o
obj-$(CONFIG_FPGA_ZYNQMPPL) += zynqmppl.o
obj-$(CONFIG_FPGA_XILINX) += xilinx.o
obj-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o
ifdef CONFIG_FPGA_ALTERA
obj-y += altera.o
obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
obj-$(CONFIG_FPGA_STRATIX10) += stratix10.o
obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o
obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o
endif
@@ -0,0 +1,181 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2003
* Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
/*
* Altera FPGA support
*/
#include <common.h>
#include <errno.h>
#include <ACEX1K.h>
#include <stratixII.h>
/* Define FPGA_DEBUG to 1 to get debug printf's */
#define FPGA_DEBUG 0
static const struct altera_fpga {
enum altera_family family;
const char *name;
int (*load)(Altera_desc *, const void *, size_t);
int (*dump)(Altera_desc *, const void *, size_t);
int (*info)(Altera_desc *);
} altera_fpga[] = {
#if defined(CONFIG_FPGA_ACEX1K)
{ Altera_ACEX1K, "ACEX1K", ACEX1K_load, ACEX1K_dump, ACEX1K_info },
{ Altera_CYC2, "ACEX1K", ACEX1K_load, ACEX1K_dump, ACEX1K_info },
#elif defined(CONFIG_FPGA_CYCLON2)
{ Altera_ACEX1K, "CycloneII", CYC2_load, CYC2_dump, CYC2_info },
{ Altera_CYC2, "CycloneII", CYC2_load, CYC2_dump, CYC2_info },
#endif
#if defined(CONFIG_FPGA_STRATIX_II)
{ Altera_StratixII, "StratixII", StratixII_load,
StratixII_dump, StratixII_info },
#endif
#if defined(CONFIG_FPGA_STRATIX_V)
{ Altera_StratixV, "StratixV", stratixv_load, NULL, NULL },
#endif
#if defined(CONFIG_FPGA_STRATIX10)
{ Intel_FPGA_Stratix10, "Stratix10", stratix10_load, NULL, NULL },
#endif
#if defined(CONFIG_FPGA_SOCFPGA)
{ Altera_SoCFPGA, "SoC FPGA", socfpga_load, NULL, NULL },
#endif
};
static int altera_validate(Altera_desc *desc, const char *fn)
{
if (!desc) {
printf("%s: NULL descriptor!\n", fn);
return -EINVAL;
}
if ((desc->family < min_altera_type) ||
(desc->family > max_altera_type)) {
printf("%s: Invalid family type, %d\n", fn, desc->family);
return -EINVAL;
}
if ((desc->iface < min_altera_iface_type) ||
(desc->iface > max_altera_iface_type)) {
printf("%s: Invalid Interface type, %d\n", fn, desc->iface);
return -EINVAL;
}
if (!desc->size) {
printf("%s: NULL part size\n", fn);
return -EINVAL;
}
return 0;
}
static const struct altera_fpga *
altera_desc_to_fpga(Altera_desc *desc, const char *fn)
{
int i;
if (altera_validate(desc, fn)) {
printf("%s: Invalid device descriptor\n", fn);
return NULL;
}
for (i = 0; i < ARRAY_SIZE(altera_fpga); i++) {
if (desc->family == altera_fpga[i].family)
break;
}
if (i == ARRAY_SIZE(altera_fpga)) {
printf("%s: Unsupported family type, %d\n", fn, desc->family);
return NULL;
}
return &altera_fpga[i];
}
int altera_load(Altera_desc *desc, const void *buf, size_t bsize)
{
const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
if (!fpga)
return FPGA_FAIL;
debug_cond(FPGA_DEBUG, "%s: Launching the %s Loader...\n",
__func__, fpga->name);
if (fpga->load)
return fpga->load(desc, buf, bsize);
return 0;
}
int altera_dump(Altera_desc *desc, const void *buf, size_t bsize)
{
const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
if (!fpga)
return FPGA_FAIL;
debug_cond(FPGA_DEBUG, "%s: Launching the %s Reader...\n",
__func__, fpga->name);
if (fpga->dump)
return fpga->dump(desc, buf, bsize);
return 0;
}
int altera_info(Altera_desc *desc)
{
const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
if (!fpga)
return FPGA_FAIL;
printf("Family: \t%s\n", fpga->name);
printf("Interface type:\t");
switch (desc->iface) {
case passive_serial:
printf("Passive Serial (PS)\n");
break;
case passive_parallel_synchronous:
printf("Passive Parallel Synchronous (PPS)\n");
break;
case passive_parallel_asynchronous:
printf("Passive Parallel Asynchronous (PPA)\n");
break;
case passive_serial_asynchronous:
printf("Passive Serial Asynchronous (PSA)\n");
break;
case altera_jtag_mode: /* Not used */
printf("JTAG Mode\n");
break;
case fast_passive_parallel:
printf("Fast Passive Parallel (FPP)\n");
break;
case fast_passive_parallel_security:
printf("Fast Passive Parallel with Security (FPPS)\n");
break;
case secure_device_manager_mailbox:
puts("Secure Device Manager (SDM) Mailbox\n");
break;
/* Add new interface types here */
default:
printf("Unsupported interface type, %d\n", desc->iface);
}
printf("Device Size: \t%zd bytes\n"
"Cookie: \t0x%x (%d)\n",
desc->size, desc->cookie, desc->cookie);
if (desc->iface_fns) {
printf("Device Function Table @ 0x%p\n", desc->iface_fns);
if (fpga->info)
fpga->info(desc);
} else {
printf("No Device Function Table.\n");
}
return FPGA_SUCCESS;
}
@@ -0,0 +1,205 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2006
* Heiko Schocher, hs@denx.de
* Based on ACE1XK.c
*/
#include <common.h> /* core U-Boot definitions */
#include <altera.h>
#include <ACEX1K.h> /* ACEX device family */
/* Define FPGA_DEBUG to get debug printf's */
#ifdef FPGA_DEBUG
#define PRINTF(fmt, args...) printf(fmt, ##args)
#else
#define PRINTF(fmt, args...)
#endif
/* Note: The assumption is that we cannot possibly run fast enough to
* overrun the device (the Slave Parallel mode can free run at 50MHz).
* If there is a need to operate slower, define CONFIG_FPGA_DELAY in
* the board config file to slow things down.
*/
#ifndef CONFIG_FPGA_DELAY
#define CONFIG_FPGA_DELAY()
#endif
#ifndef CONFIG_SYS_FPGA_WAIT
#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ / 10 /* 100 ms */
#endif
static int CYC2_ps_load(Altera_desc *desc, const void *buf, size_t bsize);
static int CYC2_ps_dump(Altera_desc *desc, const void *buf, size_t bsize);
/* static int CYC2_ps_info( Altera_desc *desc ); */
/* ------------------------------------------------------------------------- */
/* CYCLON2 Generic Implementation */
int CYC2_load(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
PRINTF("%s: Launching Passive Serial Loader\n", __func__);
ret_val = CYC2_ps_load(desc, buf, bsize);
break;
case fast_passive_parallel:
/* Fast Passive Parallel (FPP) and PS only differ in what is
* done in the write() callback. Use the existing PS load
* function for FPP, too.
*/
PRINTF("%s: Launching Fast Passive Parallel Loader\n",
__func__);
ret_val = CYC2_ps_load(desc, buf, bsize);
break;
/* Add new interface types here */
default:
printf("%s: Unsupported interface type, %d\n",
__func__, desc->iface);
}
return ret_val;
}
int CYC2_dump(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
PRINTF("%s: Launching Passive Serial Dump\n", __func__);
ret_val = CYC2_ps_dump(desc, buf, bsize);
break;
/* Add new interface types here */
default:
printf("%s: Unsupported interface type, %d\n",
__func__, desc->iface);
}
return ret_val;
}
int CYC2_info(Altera_desc *desc)
{
return FPGA_SUCCESS;
}
/* ------------------------------------------------------------------------- */
/* CYCLON2 Passive Serial Generic Implementation */
static int CYC2_ps_load(Altera_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
Altera_CYC2_Passive_Serial_fns *fn = desc->iface_fns;
int ret = 0;
PRINTF("%s: start with interface functions @ 0x%p\n",
__func__, fn);
if (fn) {
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"config:\t0x%p\n"
"status:\t0x%p\n"
"write:\t0x%p\n"
"done:\t0x%p\n\n",
__func__, &fn, fn, fn->config, fn->status,
fn->write, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf("Loading FPGA Device %d...", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre)
(*fn->pre) (cookie);
/* Establish the initial state */
(*fn->config) (false, true, cookie); /* De-assert nCONFIG */
udelay(100);
(*fn->config) (true, true, cookie); /* Assert nCONFIG */
udelay(2); /* T_cfg > 2us */
/* Wait for nSTATUS to be asserted */
ts = get_timer(0); /* get current time */
do {
CONFIG_FPGA_DELAY();
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
/* check the time */
puts("** Timeout waiting for STATUS to go high.\n");
(*fn->abort) (cookie);
return FPGA_FAIL;
}
} while (!(*fn->status) (cookie));
/* Get ready for the burn */
CONFIG_FPGA_DELAY();
ret = (*fn->write) (buf, bsize, true, cookie);
if (ret) {
puts("** Write failed.\n");
(*fn->abort) (cookie);
return FPGA_FAIL;
}
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
puts(" OK? ...");
#endif
CONFIG_FPGA_DELAY();
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc(' '); /* terminate the dotted line */
#endif
/*
* Checking FPGA's CONF_DONE signal - correctly booted ?
*/
if (!(*fn->done) (cookie)) {
puts("** Booting failed! CONF_DONE is still deasserted.\n");
(*fn->abort) (cookie);
return FPGA_FAIL;
}
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
puts(" OK\n");
#endif
ret_val = FPGA_SUCCESS;
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS)
puts("Done.\n");
else
puts("Fail.\n");
#endif
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post) (cookie);
} else {
printf("%s: NULL Interface function table!\n", __func__);
}
return ret_val;
}
static int CYC2_ps_dump(Altera_desc *desc, const void *buf, size_t bsize)
{
/* Readback is only available through the Slave Parallel and */
/* boundary-scan interfaces. */
printf("%s: Passive Serial Dumping is unavailable\n", __func__);
return FPGA_FAIL;
}
@@ -0,0 +1,355 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
/* Generic FPGA support */
#include <common.h> /* core U-Boot definitions */
#include <xilinx.h> /* xilinx specific definitions */
#include <altera.h> /* altera specific definitions */
#include <lattice.h>
/* Local definitions */
#ifndef CONFIG_MAX_FPGA_DEVICES
#define CONFIG_MAX_FPGA_DEVICES 5
#endif
/* Local static data */
static int next_desc = FPGA_INVALID_DEVICE;
static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES];
/*
* fpga_no_sup
* 'no support' message function
*/
static void fpga_no_sup(char *fn, char *msg)
{
if (fn && msg)
printf("%s: No support for %s.\n", fn, msg);
else if (msg)
printf("No support for %s.\n", msg);
else
printf("No FPGA support!\n");
}
/* fpga_get_desc
* map a device number to a descriptor
*/
const fpga_desc *const fpga_get_desc(int devnum)
{
fpga_desc *desc = (fpga_desc *)NULL;
if ((devnum >= 0) && (devnum < next_desc)) {
desc = &desc_table[devnum];
debug("%s: found fpga descriptor #%d @ 0x%p\n",
__func__, devnum, desc);
}
return desc;
}
/*
* fpga_validate
* generic parameter checking code
*/
const fpga_desc *const fpga_validate(int devnum, const void *buf,
size_t bsize, char *fn)
{
const fpga_desc *desc = fpga_get_desc(devnum);
if (!desc)
printf("%s: Invalid device number %d\n", fn, devnum);
if (!buf) {
printf("%s: Null buffer.\n", fn);
return (fpga_desc * const)NULL;
}
return desc;
}
/*
* fpga_dev_info
* generic multiplexing code
*/
static int fpga_dev_info(int devnum)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc * const desc = fpga_get_desc(devnum);
if (desc) {
debug("%s: Device Descriptor @ 0x%p\n",
__func__, desc->devdesc);
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
printf("Xilinx Device\nDescriptor @ 0x%p\n", desc);
ret_val = xilinx_info(desc->devdesc);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
break;
case fpga_altera:
#if defined(CONFIG_FPGA_ALTERA)
printf("Altera Device\nDescriptor @ 0x%p\n", desc);
ret_val = altera_info(desc->devdesc);
#else
fpga_no_sup((char *)__func__, "Altera devices");
#endif
break;
case fpga_lattice:
#if defined(CONFIG_FPGA_LATTICE)
printf("Lattice Device\nDescriptor @ 0x%p\n", desc);
ret_val = lattice_info(desc->devdesc);
#else
fpga_no_sup((char *)__func__, "Lattice devices");
#endif
break;
default:
printf("%s: Invalid or unsupported device type %d\n",
__func__, desc->devtype);
}
} else {
printf("%s: Invalid device number %d\n", __func__, devnum);
}
return ret_val;
}
/*
* fpga_init is usually called from misc_init_r() and MUST be called
* before any of the other fpga functions are used.
*/
void fpga_init(void)
{
next_desc = 0;
memset(desc_table, 0, sizeof(desc_table));
debug("%s\n", __func__);
}
/*
* fpga_count
* Basic interface function to get the current number of devices available.
*/
int fpga_count(void)
{
return next_desc;
}
/*
* fpga_add
* Add the device descriptor to the device table.
*/
int fpga_add(fpga_type devtype, void *desc)
{
int devnum = FPGA_INVALID_DEVICE;
if (!desc) {
printf("%s: NULL device descriptor\n", __func__);
return devnum;
}
if (next_desc < 0) {
printf("%s: FPGA support not initialized!\n", __func__);
} else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) {
if (next_desc < CONFIG_MAX_FPGA_DEVICES) {
devnum = next_desc;
desc_table[next_desc].devtype = devtype;
desc_table[next_desc++].devdesc = desc;
} else {
printf("%s: Exceeded Max FPGA device count\n",
__func__);
}
} else {
printf("%s: Unsupported FPGA type %d\n", __func__, devtype);
}
return devnum;
}
/*
* Return 1 if the fpga data is partial.
* This is only required for fpga drivers that support bitstream_type.
*/
int __weak fpga_is_partial_data(int devnum, size_t img_len)
{
return 0;
}
/*
* Convert bitstream data and load into the fpga
*/
int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
bitstream_type bstype)
{
printf("Bitstream support not implemented for this FPGA device\n");
return FPGA_FAIL;
}
#if defined(CONFIG_CMD_FPGA_LOADFS)
int fpga_fsload(int devnum, const void *buf, size_t size,
fpga_fs_info *fpga_fsinfo)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc *desc = fpga_validate(devnum, buf, size,
(char *)__func__);
if (desc) {
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
ret_val = xilinx_loadfs(desc->devdesc, buf, size,
fpga_fsinfo);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
break;
default:
printf("%s: Invalid or unsupported device type %d\n",
__func__, desc->devtype);
}
}
return ret_val;
}
#endif
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
int fpga_loads(int devnum, const void *buf, size_t size,
struct fpga_secure_info *fpga_sec_info)
{
int ret_val = FPGA_FAIL;
const fpga_desc *desc = fpga_validate(devnum, buf, size,
(char *)__func__);
if (desc) {
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
ret_val = xilinx_loads(desc->devdesc, buf, size,
fpga_sec_info);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
break;
default:
printf("%s: Invalid or unsupported device type %d\n",
__func__, desc->devtype);
}
}
return ret_val;
}
#endif
/*
* Generic multiplexing code
*/
int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc *desc = fpga_validate(devnum, buf, bsize,
(char *)__func__);
if (desc) {
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
ret_val = xilinx_load(desc->devdesc, buf, bsize,
bstype);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
break;
case fpga_altera:
#if defined(CONFIG_FPGA_ALTERA)
ret_val = altera_load(desc->devdesc, buf, bsize);
#else
fpga_no_sup((char *)__func__, "Altera devices");
#endif
break;
case fpga_lattice:
#if defined(CONFIG_FPGA_LATTICE)
ret_val = lattice_load(desc->devdesc, buf, bsize);
#else
fpga_no_sup((char *)__func__, "Lattice devices");
#endif
break;
default:
printf("%s: Invalid or unsupported device type %d\n",
__func__, desc->devtype);
}
}
return ret_val;
}
/*
* fpga_dump
* generic multiplexing code
*/
int fpga_dump(int devnum, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc *desc = fpga_validate(devnum, buf, bsize,
(char *)__func__);
if (desc) {
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
ret_val = xilinx_dump(desc->devdesc, buf, bsize);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
break;
case fpga_altera:
#if defined(CONFIG_FPGA_ALTERA)
ret_val = altera_dump(desc->devdesc, buf, bsize);
#else
fpga_no_sup((char *)__func__, "Altera devices");
#endif
break;
case fpga_lattice:
#if defined(CONFIG_FPGA_LATTICE)
ret_val = lattice_dump(desc->devdesc, buf, bsize);
#else
fpga_no_sup((char *)__func__, "Lattice devices");
#endif
break;
default:
printf("%s: Invalid or unsupported device type %d\n",
__func__, desc->devtype);
}
}
return ret_val;
}
/*
* fpga_info
* front end to fpga_dev_info. If devnum is invalid, report on all
* available devices.
*/
int fpga_info(int devnum)
{
if (devnum == FPGA_INVALID_DEVICE) {
if (next_desc > 0) {
int dev;
for (dev = 0; dev < next_desc; dev++)
fpga_dev_info(dev);
return FPGA_SUCCESS;
} else {
printf("%s: No FPGA devices available.\n", __func__);
return FPGA_FAIL;
}
}
return fpga_dev_info(devnum);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,379 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*
* ispVM functions adapted from Lattice's ispmVMEmbedded code:
* Copyright 2009 Lattice Semiconductor Corp.
*/
#include <common.h>
#include <malloc.h>
#include <fpga.h>
#include <lattice.h>
static lattice_board_specific_func *pfns;
static const char *fpga_image;
static unsigned long read_bytes;
static unsigned long bufsize;
static unsigned short expectedCRC;
/*
* External variables and functions declared in ivm_core.c module.
*/
extern unsigned short g_usCalculatedCRC;
extern unsigned short g_usDataType;
extern unsigned char *g_pucIntelBuffer;
extern unsigned char *g_pucHeapMemory;
extern unsigned short g_iHeapCounter;
extern unsigned short g_iHEAPSize;
extern unsigned short g_usIntelDataIndex;
extern unsigned short g_usIntelBufferSize;
extern char *const g_szSupportedVersions[];
/*
* ispVMDelay
*
* Users must implement a delay to observe a_usTimeDelay, where
* bit 15 of the a_usTimeDelay defines the unit.
* 1 = milliseconds
* 0 = microseconds
* Example:
* a_usTimeDelay = 0x0001 = 1 microsecond delay.
* a_usTimeDelay = 0x8001 = 1 millisecond delay.
*
* This subroutine is called upon to provide a delay from 1 millisecond to a few
* hundreds milliseconds each time.
* It is understood that due to a_usTimeDelay is defined as unsigned short, a 16
* bits integer, this function is restricted to produce a delay to 64000
* micro-seconds or 32000 milli-second maximum. The VME file will never pass on
* to this function a delay time > those maximum number. If it needs more than
* those maximum, the VME file will launch the delay function several times to
* realize a larger delay time cummulatively.
* It is perfectly alright to provide a longer delay than required. It is not
* acceptable if the delay is shorter.
*/
void ispVMDelay(unsigned short delay)
{
if (delay & 0x8000)
delay = (delay & ~0x8000) * 1000;
udelay(delay);
}
void writePort(unsigned char a_ucPins, unsigned char a_ucValue)
{
a_ucValue = a_ucValue ? 1 : 0;
switch (a_ucPins) {
case g_ucPinTDI:
pfns->jtag_set_tdi(a_ucValue);
break;
case g_ucPinTCK:
pfns->jtag_set_tck(a_ucValue);
break;
case g_ucPinTMS:
pfns->jtag_set_tms(a_ucValue);
break;
default:
printf("%s: requested unknown pin\n", __func__);
}
}
unsigned char readPort(void)
{
return pfns->jtag_get_tdo();
}
void sclock(void)
{
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
}
void calibration(void)
{
/* Apply 2 pulses to TCK. */
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
ispVMDelay(0x8001);
/* Apply 2 pulses to TCK. */
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
writePort(g_ucPinTCK, 0x01);
writePort(g_ucPinTCK, 0x00);
}
/*
* GetByte
*
* Returns a byte to the caller. The returned byte depends on the
* g_usDataType register. If the HEAP_IN bit is set, then the byte
* is returned from the HEAP. If the LHEAP_IN bit is set, then
* the byte is returned from the intelligent buffer. Otherwise,
* the byte is returned directly from the VME file.
*/
unsigned char GetByte(void)
{
unsigned char ucData;
unsigned int block_size = 4 * 1024;
if (g_usDataType & HEAP_IN) {
/*
* Get data from repeat buffer.
*/
if (g_iHeapCounter > g_iHEAPSize) {
/*
* Data over-run.
*/
return 0xFF;
}
ucData = g_pucHeapMemory[g_iHeapCounter++];
} else if (g_usDataType & LHEAP_IN) {
/*
* Get data from intel buffer.
*/
if (g_usIntelDataIndex >= g_usIntelBufferSize) {
return 0xFF;
}
ucData = g_pucIntelBuffer[g_usIntelDataIndex++];
} else {
if (read_bytes == bufsize) {
return 0xFF;
}
ucData = *fpga_image++;
read_bytes++;
if (!(read_bytes % block_size)) {
printf("Downloading FPGA %ld/%ld completed\r",
read_bytes,
bufsize);
}
if (expectedCRC != 0) {
ispVMCalculateCRC32(ucData);
}
}
return ucData;
}
signed char ispVM(void)
{
char szFileVersion[9] = { 0 };
signed char cRetCode = 0;
signed char cIndex = 0;
signed char cVersionIndex = 0;
unsigned char ucReadByte = 0;
unsigned short crc;
g_pucHeapMemory = NULL;
g_iHeapCounter = 0;
g_iHEAPSize = 0;
g_usIntelDataIndex = 0;
g_usIntelBufferSize = 0;
g_usCalculatedCRC = 0;
expectedCRC = 0;
ucReadByte = GetByte();
switch (ucReadByte) {
case FILE_CRC:
crc = (unsigned char)GetByte();
crc <<= 8;
crc |= GetByte();
expectedCRC = crc;
for (cIndex = 0; cIndex < 8; cIndex++)
szFileVersion[cIndex] = GetByte();
break;
default:
szFileVersion[0] = (signed char) ucReadByte;
for (cIndex = 1; cIndex < 8; cIndex++)
szFileVersion[cIndex] = GetByte();
break;
}
/*
*
* Compare the VME file version against the supported version.
*
*/
for (cVersionIndex = 0; g_szSupportedVersions[cVersionIndex] != 0;
cVersionIndex++) {
for (cIndex = 0; cIndex < 8; cIndex++) {
if (szFileVersion[cIndex] !=
g_szSupportedVersions[cVersionIndex][cIndex]) {
cRetCode = VME_VERSION_FAILURE;
break;
}
cRetCode = 0;
}
if (cRetCode == 0) {
break;
}
}
if (cRetCode < 0) {
return VME_VERSION_FAILURE;
}
printf("VME file checked: starting downloading to FPGA\n");
ispVMStart();
cRetCode = ispVMCode();
ispVMEnd();
ispVMFreeMem();
puts("\n");
if (cRetCode == 0 && expectedCRC != 0 &&
(expectedCRC != g_usCalculatedCRC)) {
printf("Expected CRC: 0x%.4X\n", expectedCRC);
printf("Calculated CRC: 0x%.4X\n", g_usCalculatedCRC);
return VME_CRC_FAILURE;
}
return cRetCode;
}
static int lattice_validate(Lattice_desc *desc, const char *fn)
{
int ret_val = false;
if (desc) {
if ((desc->family > min_lattice_type) &&
(desc->family < max_lattice_type)) {
if ((desc->iface > min_lattice_iface_type) &&
(desc->iface < max_lattice_iface_type)) {
if (desc->size) {
ret_val = true;
} else {
printf("%s: NULL part size\n", fn);
}
} else {
printf("%s: Invalid Interface type, %d\n",
fn, desc->iface);
}
} else {
printf("%s: Invalid family type, %d\n",
fn, desc->family);
}
} else {
printf("%s: NULL descriptor!\n", fn);
}
return ret_val;
}
int lattice_load(Lattice_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
if (!lattice_validate(desc, (char *)__func__)) {
printf("%s: Invalid device descriptor\n", __func__);
} else {
pfns = desc->iface_fns;
switch (desc->family) {
case Lattice_XP2:
fpga_image = buf;
read_bytes = 0;
bufsize = bsize;
debug("%s: Launching the Lattice ISPVME Loader:"
" addr %p size 0x%lx...\n",
__func__, fpga_image, bufsize);
ret_val = ispVM();
if (ret_val)
printf("%s: error %d downloading FPGA image\n",
__func__, ret_val);
else
puts("FPGA downloaded successfully\n");
break;
default:
printf("%s: Unsupported family type, %d\n",
__func__, desc->family);
}
}
return ret_val;
}
int lattice_dump(Lattice_desc *desc, const void *buf, size_t bsize)
{
puts("Dump not supported for Lattice FPGA\n");
return FPGA_FAIL;
}
int lattice_info(Lattice_desc *desc)
{
int ret_val = FPGA_FAIL;
if (lattice_validate(desc, (char *)__func__)) {
printf("Family: \t");
switch (desc->family) {
case Lattice_XP2:
puts("XP2\n");
break;
/* Add new family types here */
default:
printf("Unknown family type, %d\n", desc->family);
}
puts("Interface type:\t");
switch (desc->iface) {
case lattice_jtag_mode:
puts("JTAG Mode\n");
break;
/* Add new interface types here */
default:
printf("Unsupported interface type, %d\n", desc->iface);
}
printf("Device Size: \t%d bytes\n",
desc->size);
if (desc->iface_fns) {
printf("Device Function Table @ 0x%p\n",
desc->iface_fns);
switch (desc->family) {
case Lattice_XP2:
break;
/* Add new family types here */
default:
break;
}
} else {
puts("No Device Function Table.\n");
}
if (desc->desc)
printf("Model: \t%s\n", desc->desc);
ret_val = FPGA_SUCCESS;
} else {
printf("%s: Invalid device descriptor\n", __func__);
}
return ret_val;
}
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (C) 2012-2017 Altera Corporation <www.altera.com>
* All rights reserved.
*/
#include <common.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/fpga_manager.h>
#include <asm/arch/reset_manager.h>
#include <asm/arch/system_manager.h>
/* Timeout count */
#define FPGA_TIMEOUT_CNT 0x1000000
static struct socfpga_fpga_manager *fpgamgr_regs =
(struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS;
int fpgamgr_dclkcnt_set(unsigned long cnt)
{
unsigned long i;
/* Clear any existing done status */
if (readl(&fpgamgr_regs->dclkstat))
writel(0x1, &fpgamgr_regs->dclkstat);
/* Write the dclkcnt */
writel(cnt, &fpgamgr_regs->dclkcnt);
/* Wait till the dclkcnt done */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
if (!readl(&fpgamgr_regs->dclkstat))
continue;
writel(0x1, &fpgamgr_regs->dclkstat);
return 0;
}
return -ETIMEDOUT;
}
/* Write the RBF data to FPGA Manager */
void fpgamgr_program_write(const void *rbf_data, size_t rbf_size)
{
uint32_t src = (uint32_t)rbf_data;
uint32_t dst = SOCFPGA_FPGAMGRDATA_ADDRESS;
/* Number of loops for 32-byte long copying. */
uint32_t loops32 = rbf_size / 32;
/* Number of loops for 4-byte long copying + trailing bytes */
uint32_t loops4 = DIV_ROUND_UP(rbf_size % 32, 4);
asm volatile(
" cmp %2, #0\n"
" beq 2f\n"
"1: ldmia %0!, {r0-r7}\n"
" stmia %1!, {r0-r7}\n"
" sub %1, #32\n"
" subs %2, #1\n"
" bne 1b\n"
"2: cmp %3, #0\n"
" beq 4f\n"
"3: ldr %2, [%0], #4\n"
" str %2, [%1]\n"
" subs %3, #1\n"
" bne 3b\n"
"4: nop\n"
: "+r"(src), "+r"(dst), "+r"(loops32), "+r"(loops4) :
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc");
}
@@ -0,0 +1,946 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
*/
#include <asm/io.h>
#include <asm/arch/fpga_manager.h>
#include <asm/arch/reset_manager.h>
#include <asm/arch/system_manager.h>
#include <asm/arch/sdram.h>
#include <asm/arch/misc.h>
#include <altera.h>
#include <asm/arch/pinmux.h>
#include <common.h>
#include <dm/ofnode.h>
#include <errno.h>
#include <fs_loader.h>
#include <wait_bit.h>
#include <watchdog.h>
#define CFGWDTH_32 1
#define MIN_BITSTREAM_SIZECHECK 230
#define ENCRYPTION_OFFSET 69
#define COMPRESSION_OFFSET 229
#define FPGA_TIMEOUT_MSEC 1000 /* timeout in ms */
#define FPGA_TIMEOUT_CNT 0x1000000
#define DEFAULT_DDR_LOAD_ADDRESS 0x400
DECLARE_GLOBAL_DATA_PTR;
static const struct socfpga_fpga_manager *fpga_manager_base =
(void *)SOCFPGA_FPGAMGRREGS_ADDRESS;
static const struct socfpga_system_manager *system_manager_base =
(void *)SOCFPGA_SYSMGR_ADDRESS;
static void fpgamgr_set_cd_ratio(unsigned long ratio);
static uint32_t fpgamgr_get_msel(void)
{
u32 reg;
reg = readl(&fpga_manager_base->imgcfg_stat);
reg = (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SET_MSD) >>
ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_LSB;
return reg;
}
static void fpgamgr_set_cfgwdth(int width)
{
if (width)
setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK);
else
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK);
}
int is_fpgamgr_user_mode(void)
{
return (readl(&fpga_manager_base->imgcfg_stat) &
ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) != 0;
}
static int wait_for_user_mode(void)
{
return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat,
ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK,
1, FPGA_TIMEOUT_MSEC, false);
}
int is_fpgamgr_early_user_mode(void)
{
return (readl(&fpga_manager_base->imgcfg_stat) &
ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK) != 0;
}
int fpgamgr_wait_early_user_mode(void)
{
u32 sync_data = 0xffffffff;
u32 i = 0;
unsigned start = get_timer(0);
unsigned long cd_ratio;
/* Getting existing CDRATIO */
cd_ratio = (readl(&fpga_manager_base->imgcfg_ctrl_02) &
ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK) >>
ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB;
/* Using CDRATIO_X1 for better compatibility */
fpgamgr_set_cd_ratio(CDRATIO_x1);
while (!is_fpgamgr_early_user_mode()) {
if (get_timer(start) > FPGA_TIMEOUT_MSEC)
return -ETIMEDOUT;
fpgamgr_program_write((const long unsigned int *)&sync_data,
sizeof(sync_data));
udelay(FPGA_TIMEOUT_MSEC);
i++;
}
debug("FPGA: Additional %i sync word needed\n", i);
/* restoring original CDRATIO */
fpgamgr_set_cd_ratio(cd_ratio);
return 0;
}
/* Read f2s_nconfig_pin and f2s_nstatus_pin; loop until de-asserted */
static int wait_for_nconfig_pin_and_nstatus_pin(void)
{
unsigned long mask = ALT_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN_SET_MSK |
ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK;
/*
* Poll until f2s_nconfig_pin and f2s_nstatus_pin; loop until
* de-asserted, timeout at 1000ms
*/
return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat, mask,
true, FPGA_TIMEOUT_MSEC, false);
}
static int wait_for_f2s_nstatus_pin(unsigned long value)
{
/* Poll until f2s to specific value, timeout at 1000ms */
return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat,
ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK,
value, FPGA_TIMEOUT_MSEC, false);
}
/* set CD ratio */
static void fpgamgr_set_cd_ratio(unsigned long ratio)
{
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK);
setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
(ratio << ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB) &
ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK);
}
/* get the MSEL value, verify we are set for FPP configuration mode */
static int fpgamgr_verify_msel(void)
{
u32 msel = fpgamgr_get_msel();
if (msel & ~BIT(0)) {
printf("Fail: read msel=%d\n", msel);
return -EPERM;
}
return 0;
}
/*
* Write cdratio and cdwidth based on whether the bitstream is compressed
* and/or encoded
*/
static int fpgamgr_set_cdratio_cdwidth(unsigned int cfg_width, u32 *rbf_data,
size_t rbf_size)
{
unsigned int cd_ratio;
bool encrypt, compress;
/*
* According to the bitstream specification,
* both encryption and compression status are
* in location before offset 230 of the buffer.
*/
if (rbf_size < MIN_BITSTREAM_SIZECHECK)
return -EINVAL;
encrypt = (rbf_data[ENCRYPTION_OFFSET] >> 2) & 3;
encrypt = encrypt != 0;
compress = (rbf_data[COMPRESSION_OFFSET] >> 1) & 1;
compress = !compress;
debug("FPGA: Header word %d = %08x.\n", 69, rbf_data[69]);
debug("FPGA: Header word %d = %08x.\n", 229, rbf_data[229]);
debug("FPGA: Read from rbf header: encrypt=%d compress=%d.\n", encrypt,
compress);
/*
* from the register map description of cdratio in imgcfg_ctrl_02:
* Normal Configuration : 32bit Passive Parallel
* Partial Reconfiguration : 16bit Passive Parallel
*/
/*
* cd ratio is dependent on cfg width and whether the bitstream
* is encrypted and/or compressed.
*
* | width | encr. | compr. | cd ratio |
* | 16 | 0 | 0 | 1 |
* | 16 | 0 | 1 | 4 |
* | 16 | 1 | 0 | 2 |
* | 16 | 1 | 1 | 4 |
* | 32 | 0 | 0 | 1 |
* | 32 | 0 | 1 | 8 |
* | 32 | 1 | 0 | 4 |
* | 32 | 1 | 1 | 8 |
*/
if (!compress && !encrypt) {
cd_ratio = CDRATIO_x1;
} else {
if (compress)
cd_ratio = CDRATIO_x4;
else
cd_ratio = CDRATIO_x2;
/* if 32 bit, double the cd ratio (so register
field setting is incremented) */
if (cfg_width == CFGWDTH_32)
cd_ratio += 1;
}
fpgamgr_set_cfgwdth(cfg_width);
fpgamgr_set_cd_ratio(cd_ratio);
return 0;
}
static int fpgamgr_reset(void)
{
unsigned long reg;
/* S2F_NCONFIG = 0 */
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
/* Wait for f2s_nstatus == 0 */
if (wait_for_f2s_nstatus_pin(0))
return -ETIME;
/* S2F_NCONFIG = 1 */
setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
/* Wait for f2s_nstatus == 1 */
if (wait_for_f2s_nstatus_pin(1))
return -ETIME;
/* read and confirm f2s_condone_pin = 0 and f2s_condone_oe = 1 */
reg = readl(&fpga_manager_base->imgcfg_stat);
if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) != 0)
return -EPERM;
if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_OE_SET_MSK) == 0)
return -EPERM;
return 0;
}
/* Start the FPGA programming by initialize the FPGA Manager */
int fpgamgr_program_init(u32 * rbf_data, size_t rbf_size)
{
int ret;
/* Step 1 */
if (fpgamgr_verify_msel())
return -EPERM;
/* Step 2 */
if (fpgamgr_set_cdratio_cdwidth(CFGWDTH_32, rbf_data, rbf_size))
return -EPERM;
/*
* Step 3:
* Make sure no other external devices are trying to interfere with
* programming:
*/
if (wait_for_nconfig_pin_and_nstatus_pin())
return -ETIME;
/*
* Step 4:
* Deassert the signal drives from HPS
*
* S2F_NCE = 1
* S2F_PR_REQUEST = 0
* EN_CFG_CTRL = 0
* EN_CFG_DATA = 0
* S2F_NCONFIG = 1
* S2F_NSTATUS_OE = 0
* S2F_CONDONE_OE = 0
*/
setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST_SET_MSK);
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE_SET_MSK |
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE_SET_MSK);
/*
* Step 5:
* Enable overrides
* S2F_NENABLE_CONFIG = 0
* S2F_NENABLE_NCONFIG = 0
*/
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK);
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK);
/*
* Disable driving signals that HPS doesn't need to drive.
* S2F_NENABLE_NSTATUS = 1
* S2F_NENABLE_CONDONE = 1
*/
setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS_SET_MSK |
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE_SET_MSK);
/*
* Step 6:
* Drive chip select S2F_NCE = 0
*/
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
/* Step 7 */
if (wait_for_nconfig_pin_and_nstatus_pin())
return -ETIME;
/* Step 8 */
ret = fpgamgr_reset();
if (ret)
return ret;
/*
* Step 9:
* EN_CFG_CTRL and EN_CFG_DATA = 1
*/
setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
return 0;
}
/* Ensure the FPGA entering config done */
static int fpgamgr_program_poll_cd(void)
{
unsigned long reg, i;
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
reg = readl(&fpga_manager_base->imgcfg_stat);
if (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK)
return 0;
if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == 0) {
printf("nstatus == 0 while waiting for condone\n");
return -EPERM;
}
WATCHDOG_RESET();
}
if (i == FPGA_TIMEOUT_CNT)
return -ETIME;
return 0;
}
/* Ensure the FPGA entering user mode */
static int fpgamgr_program_poll_usermode(void)
{
unsigned long reg;
int ret = 0;
if (fpgamgr_dclkcnt_set(0xf))
return -ETIME;
ret = wait_for_user_mode();
if (ret < 0) {
printf("%s: Failed to enter user mode with ", __func__);
printf("error code %d\n", ret);
return ret;
}
/*
* Step 14:
* Stop DATA path and Dclk
* EN_CFG_CTRL and EN_CFG_DATA = 0
*/
clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
/*
* Step 15:
* Disable overrides
* S2F_NENABLE_CONFIG = 1
* S2F_NENABLE_NCONFIG = 1
*/
setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK);
setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK);
/* Disable chip select S2F_NCE = 1 */
setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
/*
* Step 16:
* Final check
*/
reg = readl(&fpga_manager_base->imgcfg_stat);
if (((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) !=
ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) ||
((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) !=
ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) ||
((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) !=
ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK))
return -EPERM;
return 0;
}
int fpgamgr_program_finish(void)
{
/* Ensure the FPGA entering config done */
int status = fpgamgr_program_poll_cd();
if (status) {
printf("FPGA: Poll CD failed with error code %d\n", status);
return -EPERM;
}
/* Ensure the FPGA entering user mode */
status = fpgamgr_program_poll_usermode();
if (status) {
printf("FPGA: Poll usermode failed with error code %d\n",
status);
return -EPERM;
}
printf("Full Configuration Succeeded.\n");
return 0;
}
ofnode get_fpga_mgr_ofnode(ofnode from)
{
return ofnode_by_compatible(from, "altr,socfpga-a10-fpga-mgr");
}
const char *get_fpga_filename(void)
{
const char *fpga_filename = NULL;
ofnode fpgamgr_node = get_fpga_mgr_ofnode(ofnode_null());
if (ofnode_valid(fpgamgr_node))
fpga_filename = ofnode_read_string(fpgamgr_node,
"altr,bitstream");
return fpga_filename;
}
static void get_rbf_image_info(struct rbf_info *rbf, u16 *buffer)
{
/*
* Magic ID starting at:
* -> 1st dword[15:0] in periph.rbf
* -> 2nd dword[15:0] in core.rbf
* Note: dword == 32 bits
*/
u32 word_reading_max = 2;
u32 i;
for (i = 0; i < word_reading_max; i++) {
if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
rbf->security = unencrypted;
} else if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
rbf->security = encrypted;
} else if (*(buffer + i + 1) ==
FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
rbf->security = unencrypted;
} else if (*(buffer + i + 1) ==
FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
rbf->security = encrypted;
} else {
rbf->security = invalid;
continue;
}
/* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */
if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
rbf->section = periph_section;
break;
} else if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_CORE) {
rbf->section = core_section;
break;
} else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
rbf->section = periph_section;
break;
} else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_CORE) {
rbf->section = core_section;
break;
}
rbf->section = unknown;
break;
WATCHDOG_RESET();
}
}
#ifdef CONFIG_FS_LOADER
static int first_loading_rbf_to_buffer(struct udevice *dev,
struct fpga_loadfs_info *fpga_loadfs,
u32 *buffer, size_t *buffer_bsize)
{
u32 *buffer_p = (u32 *)*buffer;
u32 *loadable = buffer_p;
size_t buffer_size = *buffer_bsize;
size_t fit_size;
int ret, i, count, confs_noffset, images_noffset, rbf_offset, rbf_size;
const char *fpga_node_name = NULL;
const char *uname = NULL;
/* Load image header into buffer */
ret = request_firmware_into_buf(dev,
fpga_loadfs->fpga_fsinfo->filename,
buffer_p, sizeof(struct image_header),
0);
if (ret < 0) {
debug("FPGA: Failed to read image header from flash.\n");
return -ENOENT;
}
if (image_get_magic((struct image_header *)buffer_p) != FDT_MAGIC) {
debug("FPGA: No FDT magic was found.\n");
return -EBADF;
}
fit_size = fdt_totalsize(buffer_p);
if (fit_size > buffer_size) {
debug("FPGA: FIT image is larger than available buffer.\n");
debug("Please use FIT external data or increasing buffer.\n");
return -ENOMEM;
}
/* Load entire FIT into buffer */
ret = request_firmware_into_buf(dev,
fpga_loadfs->fpga_fsinfo->filename,
buffer_p, fit_size, 0);
if (ret < 0)
return ret;
ret = fit_check_format(buffer_p);
if (!ret) {
debug("FPGA: No valid FIT image was found.\n");
return -EBADF;
}
confs_noffset = fdt_path_offset(buffer_p, FIT_CONFS_PATH);
images_noffset = fdt_path_offset(buffer_p, FIT_IMAGES_PATH);
if (confs_noffset < 0 || images_noffset < 0) {
debug("FPGA: No Configurations or images nodes were found.\n");
return -ENOENT;
}
/* Get default configuration unit name from default property */
confs_noffset = fit_conf_get_node(buffer_p, NULL);
if (confs_noffset < 0) {
debug("FPGA: No default configuration was found in config.\n");
return -ENOENT;
}
count = fit_conf_get_prop_node_count(buffer_p, confs_noffset,
FIT_FPGA_PROP);
if (count < 0) {
debug("FPGA: Invalid configuration format for FPGA node.\n");
return count;
}
debug("FPGA: FPGA node count: %d\n", count);
for (i = 0; i < count; i++) {
images_noffset = fit_conf_get_prop_node_index(buffer_p,
confs_noffset,
FIT_FPGA_PROP, i);
uname = fit_get_name(buffer_p, images_noffset, NULL);
if (uname) {
debug("FPGA: %s\n", uname);
if (strstr(uname, "fpga-periph") &&
(!is_fpgamgr_early_user_mode() ||
is_fpgamgr_user_mode())) {
fpga_node_name = uname;
printf("FPGA: Start to program ");
printf("peripheral/full bitstream ...\n");
break;
} else if (strstr(uname, "fpga-core") &&
(is_fpgamgr_early_user_mode() &&
!is_fpgamgr_user_mode())) {
fpga_node_name = uname;
printf("FPGA: Start to program core ");
printf("bitstream ...\n");
break;
}
}
WATCHDOG_RESET();
}
if (!fpga_node_name) {
debug("FPGA: No suitable bitstream was found, count: %d.\n", i);
return 1;
}
images_noffset = fit_image_get_node(buffer_p, fpga_node_name);
if (images_noffset < 0) {
debug("FPGA: No node '%s' was found in FIT.\n",
fpga_node_name);
return -ENOENT;
}
if (!fit_image_get_data_position(buffer_p, images_noffset,
&rbf_offset)) {
debug("FPGA: Data position was found.\n");
} else if (!fit_image_get_data_offset(buffer_p, images_noffset,
&rbf_offset)) {
/*
* For FIT with external data, figure out where
* the external images start. This is the base
* for the data-offset properties in each image.
*/
rbf_offset += ((fdt_totalsize(buffer_p) + 3) & ~3);
debug("FPGA: Data offset was found.\n");
} else {
debug("FPGA: No data position/offset was found.\n");
return -ENOENT;
}
ret = fit_image_get_data_size(buffer_p, images_noffset, &rbf_size);
if (ret < 0) {
debug("FPGA: No data size was found (err=%d).\n", ret);
return -ENOENT;
}
if (gd->ram_size < rbf_size) {
debug("FPGA: Using default OCRAM buffer and size.\n");
} else {
ret = fit_image_get_load(buffer_p, images_noffset,
(ulong *)loadable);
if (ret < 0) {
buffer_p = (u32 *)DEFAULT_DDR_LOAD_ADDRESS;
debug("FPGA: No loadable was found.\n");
debug("FPGA: Using default DDR load address: 0x%x .\n",
DEFAULT_DDR_LOAD_ADDRESS);
} else {
buffer_p = (u32 *)*loadable;
debug("FPGA: Found loadable address = 0x%x.\n",
*loadable);
}
buffer_size = rbf_size;
}
debug("FPGA: External data: offset = 0x%x, size = 0x%x.\n",
rbf_offset, rbf_size);
fpga_loadfs->remaining = rbf_size;
/*
* Determine buffer size vs bitstream size, and calculating number of
* chunk by chunk transfer is required due to smaller buffer size
* compare to bitstream
*/
if (rbf_size <= buffer_size) {
/* Loading whole bitstream into buffer */
buffer_size = rbf_size;
fpga_loadfs->remaining = 0;
} else {
fpga_loadfs->remaining -= buffer_size;
}
fpga_loadfs->offset = rbf_offset;
/* Loading bitstream into buffer */
ret = request_firmware_into_buf(dev,
fpga_loadfs->fpga_fsinfo->filename,
buffer_p, buffer_size,
fpga_loadfs->offset);
if (ret < 0) {
debug("FPGA: Failed to read bitstream from flash.\n");
return -ENOENT;
}
/* Getting info about bitstream types */
get_rbf_image_info(&fpga_loadfs->rbfinfo, (u16 *)buffer_p);
/* Update next reading bitstream offset */
fpga_loadfs->offset += buffer_size;
/* Update the final addr for bitstream */
*buffer = (u32)buffer_p;
/* Update the size of bitstream to be programmed into FPGA */
*buffer_bsize = buffer_size;
return 0;
}
static int subsequent_loading_rbf_to_buffer(struct udevice *dev,
struct fpga_loadfs_info *fpga_loadfs,
u32 *buffer, size_t *buffer_bsize)
{
int ret = 0;
u32 *buffer_p = (u32 *)*buffer;
/* Read the bitstream chunk by chunk. */
if (fpga_loadfs->remaining > *buffer_bsize) {
fpga_loadfs->remaining -= *buffer_bsize;
} else {
*buffer_bsize = fpga_loadfs->remaining;
fpga_loadfs->remaining = 0;
}
ret = request_firmware_into_buf(dev,
fpga_loadfs->fpga_fsinfo->filename,
buffer_p, *buffer_bsize,
fpga_loadfs->offset);
if (ret < 0) {
debug("FPGA: Failed to read bitstream from flash.\n");
return -ENOENT;
}
/* Update next reading bitstream offset */
fpga_loadfs->offset += *buffer_bsize;
return 0;
}
int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize,
u32 offset)
{
struct fpga_loadfs_info fpga_loadfs;
struct udevice *dev;
int status, ret, size;
u32 buffer = (uintptr_t)buf;
size_t buffer_sizebytes = bsize;
size_t buffer_sizebytes_ori = bsize;
size_t total_sizeof_image = 0;
ofnode node;
const fdt32_t *phandle_p;
u32 phandle;
node = get_fpga_mgr_ofnode(ofnode_null());
if (ofnode_valid(node)) {
phandle_p = ofnode_get_property(node, "firmware-loader", &size);
if (!phandle_p) {
node = ofnode_path("/chosen");
if (!ofnode_valid(node)) {
debug("FPGA: /chosen node was not found.\n");
return -ENOENT;
}
phandle_p = ofnode_get_property(node, "firmware-loader",
&size);
if (!phandle_p) {
debug("FPGA: firmware-loader property was not");
debug(" found.\n");
return -ENOENT;
}
}
} else {
debug("FPGA: FPGA manager node was not found.\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER,
phandle, &dev);
if (ret)
return ret;
memset(&fpga_loadfs, 0, sizeof(fpga_loadfs));
fpga_loadfs.fpga_fsinfo = fpga_fsinfo;
fpga_loadfs.offset = offset;
printf("FPGA: Checking FPGA configuration setting ...\n");
/*
* Note: Both buffer and buffer_sizebytes values can be altered by
* function below.
*/
ret = first_loading_rbf_to_buffer(dev, &fpga_loadfs, &buffer,
&buffer_sizebytes);
if (ret == 1) {
printf("FPGA: Skipping configuration ...\n");
return 0;
} else if (ret) {
return ret;
}
if (fpga_loadfs.rbfinfo.section == core_section &&
!(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
debug("FPGA : Must be in Early Release mode to program ");
debug("core bitstream.\n");
return -EPERM;
}
/* Disable all signals from HPS peripheral controller to FPGA */
writel(0, &system_manager_base->fpgaintf_en_global);
/* Disable all axi bridges (hps2fpga, lwhps2fpga & fpga2hps) */
socfpga_bridges_reset();
if (fpga_loadfs.rbfinfo.section == periph_section) {
/* Initialize the FPGA Manager */
status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes);
if (status) {
debug("FPGA: Init with peripheral bitstream failed.\n");
return -EPERM;
}
}
/* Transfer bitstream to FPGA Manager */
fpgamgr_program_write((void *)buffer, buffer_sizebytes);
total_sizeof_image += buffer_sizebytes;
while (fpga_loadfs.remaining) {
ret = subsequent_loading_rbf_to_buffer(dev,
&fpga_loadfs,
&buffer,
&buffer_sizebytes_ori);
if (ret)
return ret;
/* Transfer data to FPGA Manager */
fpgamgr_program_write((void *)buffer,
buffer_sizebytes_ori);
total_sizeof_image += buffer_sizebytes_ori;
WATCHDOG_RESET();
}
if (fpga_loadfs.rbfinfo.section == periph_section) {
if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) {
config_pins(gd->fdt_blob, "shared");
puts("FPGA: Early Release Succeeded.\n");
} else {
debug("FPGA: Failed to see Early Release.\n");
return -EIO;
}
/* For monolithic bitstream */
if (is_fpgamgr_user_mode()) {
/* Ensure the FPGA entering config done */
status = fpgamgr_program_finish();
if (status)
return status;
config_pins(gd->fdt_blob, "fpga");
puts("FPGA: Enter user mode.\n");
}
} else if (fpga_loadfs.rbfinfo.section == core_section) {
/* Ensure the FPGA entering config done */
status = fpgamgr_program_finish();
if (status)
return status;
config_pins(gd->fdt_blob, "fpga");
puts("FPGA: Enter user mode.\n");
} else {
debug("FPGA: Config Error: Unsupported bitstream type.\n");
return -ENOEXEC;
}
return (int)total_sizeof_image;
}
void fpgamgr_program(const void *buf, size_t bsize, u32 offset)
{
fpga_fs_info fpga_fsinfo;
fpga_fsinfo.filename = get_fpga_filename();
if (fpga_fsinfo.filename)
socfpga_loadfs(&fpga_fsinfo, buf, bsize, offset);
}
#endif
/* This function is used to load the core bitstream from the OCRAM. */
int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
unsigned long status;
struct rbf_info rbfinfo;
memset(&rbfinfo, 0, sizeof(rbfinfo));
/* Disable all signals from hps peripheral controller to fpga */
writel(0, &system_manager_base->fpgaintf_en_global);
/* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
socfpga_bridges_reset();
/* Getting info about bitstream types */
get_rbf_image_info(&rbfinfo, (u16 *)rbf_data);
if (rbfinfo.section == periph_section) {
/* Initialize the FPGA Manager */
status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
if (status)
return status;
}
if (rbfinfo.section == core_section &&
!(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
debug("FPGA : Must be in early release mode to program ");
debug("core bitstream.\n");
return -EPERM;
}
/* Write the bitstream to FPGA Manager */
fpgamgr_program_write(rbf_data, rbf_size);
status = fpgamgr_program_finish();
if (status)
return status;
config_pins(gd->fdt_blob, "fpga");
puts("FPGA: Enter user mode.\n");
return status;
}
@@ -0,0 +1,249 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (C) 2012 Altera Corporation <www.altera.com>
* All rights reserved.
*/
#include <common.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/fpga_manager.h>
#include <asm/arch/reset_manager.h>
#include <asm/arch/system_manager.h>
#define FPGA_TIMEOUT_CNT 0x1000000
static struct socfpga_fpga_manager *fpgamgr_regs =
(struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS;
static struct socfpga_system_manager *sysmgr_regs =
(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
/* Set CD ratio */
static void fpgamgr_set_cd_ratio(unsigned long ratio)
{
clrsetbits_le32(&fpgamgr_regs->ctrl,
0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB,
(ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB);
}
/* Start the FPGA programming by initialize the FPGA Manager */
static int fpgamgr_program_init(void)
{
unsigned long msel, i;
/* Get the MSEL value */
msel = readl(&fpgamgr_regs->stat);
msel &= FPGAMGRREGS_STAT_MSEL_MASK;
msel >>= FPGAMGRREGS_STAT_MSEL_LSB;
/*
* Set the cfg width
* If MSEL[3] = 1, cfg width = 32 bit
*/
if (msel & 0x8) {
setbits_le32(&fpgamgr_regs->ctrl,
FPGAMGRREGS_CTRL_CFGWDTH_MASK);
/* To determine the CD ratio */
/* MSEL[1:0] = 0, CD Ratio = 1 */
if ((msel & 0x3) == 0x0)
fpgamgr_set_cd_ratio(CDRATIO_x1);
/* MSEL[1:0] = 1, CD Ratio = 4 */
else if ((msel & 0x3) == 0x1)
fpgamgr_set_cd_ratio(CDRATIO_x4);
/* MSEL[1:0] = 2, CD Ratio = 8 */
else if ((msel & 0x3) == 0x2)
fpgamgr_set_cd_ratio(CDRATIO_x8);
} else { /* MSEL[3] = 0 */
clrbits_le32(&fpgamgr_regs->ctrl,
FPGAMGRREGS_CTRL_CFGWDTH_MASK);
/* To determine the CD ratio */
/* MSEL[1:0] = 0, CD Ratio = 1 */
if ((msel & 0x3) == 0x0)
fpgamgr_set_cd_ratio(CDRATIO_x1);
/* MSEL[1:0] = 1, CD Ratio = 2 */
else if ((msel & 0x3) == 0x1)
fpgamgr_set_cd_ratio(CDRATIO_x2);
/* MSEL[1:0] = 2, CD Ratio = 4 */
else if ((msel & 0x3) == 0x2)
fpgamgr_set_cd_ratio(CDRATIO_x4);
}
/* To enable FPGA Manager configuration */
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK);
/* To enable FPGA Manager drive over configuration line */
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
/* Put FPGA into reset phase */
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
/* (1) wait until FPGA enter reset phase */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE)
break;
}
/* If not in reset state, return error */
if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) {
puts("FPGA: Could not reset\n");
return -1;
}
/* Release FPGA from reset phase */
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
/* (2) wait until FPGA enter configuration phase */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE)
break;
}
/* If not in configuration state, return error */
if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) {
puts("FPGA: Could not configure\n");
return -2;
}
/* Clear all interrupts in CB Monitor */
writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi);
/* Enable AXI configuration */
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
return 0;
}
/* Ensure the FPGA entering config done */
static int fpgamgr_program_poll_cd(void)
{
const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK |
FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK;
unsigned long reg, i;
/* (3) wait until full config done */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
reg = readl(&fpgamgr_regs->gpio_ext_porta);
/* Config error */
if (!(reg & mask)) {
printf("FPGA: Configuration error.\n");
return -3;
}
/* Config done without error */
if (reg & mask)
break;
}
/* Timeout happened, return error */
if (i == FPGA_TIMEOUT_CNT) {
printf("FPGA: Timeout waiting for program.\n");
return -4;
}
/* Disable AXI configuration */
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
return 0;
}
/* Ensure the FPGA entering init phase */
static int fpgamgr_program_poll_initphase(void)
{
unsigned long i;
/* Additional clocks for the CB to enter initialization phase */
if (fpgamgr_dclkcnt_set(0x4))
return -5;
/* (4) wait until FPGA enter init phase or user mode */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE)
break;
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
break;
}
/* If not in configuration state, return error */
if (i == FPGA_TIMEOUT_CNT)
return -6;
return 0;
}
/* Ensure the FPGA entering user mode */
static int fpgamgr_program_poll_usermode(void)
{
unsigned long i;
/* Additional clocks for the CB to exit initialization phase */
if (fpgamgr_dclkcnt_set(0x5000))
return -7;
/* (5) wait until FPGA enter user mode */
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
break;
}
/* If not in configuration state, return error */
if (i == FPGA_TIMEOUT_CNT)
return -8;
/* To release FPGA Manager drive over configuration line */
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
return 0;
}
/*
* FPGA Manager to program the FPGA. This is the interface used by FPGA driver.
* Return 0 for sucess, non-zero for error.
*/
int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
int status;
if ((uint32_t)rbf_data & 0x3) {
puts("FPGA: Unaligned data, realign to 32bit boundary.\n");
return -EINVAL;
}
/* Prior programming the FPGA, all bridges need to be shut off */
/* Disable all signals from hps peripheral controller to fpga */
writel(0, &sysmgr_regs->fpgaintfgrp_module);
/* Disable all signals from FPGA to HPS SDRAM */
#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080
writel(0, SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS);
/* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
socfpga_bridges_reset(1);
/* Unmap the bridges from NIC-301 */
writel(0x1, SOCFPGA_L3REGS_ADDRESS);
/* Initialize the FPGA Manager */
status = fpgamgr_program_init();
if (status)
return status;
/* Write the RBF data to FPGA Manager */
fpgamgr_program_write(rbf_data, rbf_size);
/* Ensure the FPGA entering config done */
status = fpgamgr_program_poll_cd();
if (status)
return status;
/* Ensure the FPGA entering init phase */
status = fpgamgr_program_poll_initphase();
if (status)
return status;
/* Ensure the FPGA entering user mode */
return fpgamgr_program_poll_usermode();
}
@@ -0,0 +1,455 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
#include <common.h> /* core U-Boot definitions */
#include <spartan2.h> /* Spartan-II device family */
/* Define FPGA_DEBUG to get debug printf's */
#ifdef FPGA_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
#undef CONFIG_SYS_FPGA_CHECK_BUSY
#undef CONFIG_SYS_FPGA_PROG_FEEDBACK
/* Note: The assumption is that we cannot possibly run fast enough to
* overrun the device (the Slave Parallel mode can free run at 50MHz).
* If there is a need to operate slower, define CONFIG_FPGA_DELAY in
* the board config file to slow things down.
*/
#ifndef CONFIG_FPGA_DELAY
#define CONFIG_FPGA_DELAY()
#endif
#ifndef CONFIG_SYS_FPGA_WAIT
#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
#endif
static int spartan2_sp_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* static int spartan2_sp_info(xilinx_desc *desc ); */
static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* static int spartan2_ss_info(xilinx_desc *desc ); */
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
ret_val = spartan2_ss_load(desc, buf, bsize);
break;
case slave_parallel:
PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
ret_val = spartan2_sp_load(desc, buf, bsize);
break;
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
static int spartan2_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
ret_val = spartan2_ss_dump(desc, buf, bsize);
break;
case slave_parallel:
PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
ret_val = spartan2_sp_dump(desc, buf, bsize);
break;
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
static int spartan2_info(xilinx_desc *desc)
{
return FPGA_SUCCESS;
}
/* ------------------------------------------------------------------------- */
/* Spartan-II Slave Parallel Generic Implementation */
static int spartan2_sp_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan2_slave_parallel_fns *fn = desc->iface_fns;
PRINTF ("%s: start with interface functions @ 0x%p\n",
__FUNCTION__, fn);
if (fn) {
size_t bytecount = 0;
unsigned char *data = (unsigned char *) buf;
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF ("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"pre: 0x%p\n"
"pgm:\t0x%p\n"
"init:\t0x%p\n"
"err:\t0x%p\n"
"clk:\t0x%p\n"
"cs:\t0x%p\n"
"wr:\t0x%p\n"
"read data:\t0x%p\n"
"write data:\t0x%p\n"
"busy:\t0x%p\n"
"abort:\t0x%p\n",
"post:\t0x%p\n\n",
__FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
fn->abort, fn->post);
/*
* This code is designed to emulate the "Express Style"
* Continuous Data Loading in Slave Parallel Mode for
* the Spartan-II Family.
*/
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf ("Loading FPGA Device %d...\n", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre) {
(*fn->pre) (cookie);
}
/* Establish the initial state */
(*fn->pgm) (true, true, cookie); /* Assert the program, commit */
/* Get ready for the burn */
CONFIG_FPGA_DELAY ();
(*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
ts = get_timer (0); /* get current time */
/* Now wait for INIT and BUSY to go high */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
return FPGA_FAIL;
}
} while ((*fn->init) (cookie) && (*fn->busy) (cookie));
(*fn->wr) (true, true, cookie); /* Assert write, commit */
(*fn->cs) (true, true, cookie); /* Assert chip select, commit */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
/* Load the data */
while (bytecount < bsize) {
/* XXX - do we check for an Ctrl-C press in here ??? */
/* XXX - Check the error bit? */
(*fn->wdata) (data[bytecount++], true, cookie); /* write the data */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
ts = get_timer (0); /* get current time */
while ((*fn->busy) (cookie)) {
/* XXX - we should have a check in here somewhere to
* make sure we aren't busy forever... */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for BUSY to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
return FPGA_FAIL;
}
}
#endif
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
CONFIG_FPGA_DELAY ();
(*fn->cs) (false, true, cookie); /* Deassert the chip select */
(*fn->wr) (false, true, cookie); /* Deassert the write pin */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
/* now check for done signal */
ts = get_timer (0); /* get current time */
ret_val = FPGA_SUCCESS;
while ((*fn->done) (cookie) == FPGA_FAIL) {
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for DONE to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
ret_val = FPGA_FAIL;
break;
}
}
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post) (cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS)
puts ("Done.\n");
else
puts ("Fail.\n");
#endif
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan2_slave_parallel_fns *fn = desc->iface_fns;
if (fn) {
unsigned char *data = (unsigned char *) buf;
size_t bytecount = 0;
int cookie = desc->cookie; /* make a local copy */
printf ("Starting Dump of FPGA Device %d...\n", cookie);
(*fn->cs) (true, true, cookie); /* Assert chip select, commit */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
/* dump the data */
while (bytecount < bsize) {
/* XXX - do we check for an Ctrl-C press in here ??? */
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
(*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
(*fn->cs) (false, false, cookie); /* Deassert the chip select */
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
puts ("Done.\n");
/* XXX - checksum the data? */
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
/* ------------------------------------------------------------------------- */
static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan2_slave_serial_fns *fn = desc->iface_fns;
int i;
unsigned char val;
PRINTF ("%s: start with interface functions @ 0x%p\n",
__FUNCTION__, fn);
if (fn) {
size_t bytecount = 0;
unsigned char *data = (unsigned char *) buf;
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF ("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"pgm:\t0x%p\n"
"init:\t0x%p\n"
"clk:\t0x%p\n"
"wr:\t0x%p\n"
"done:\t0x%p\n\n",
__FUNCTION__, &fn, fn, fn->pgm, fn->init,
fn->clk, fn->wr, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf ("Loading FPGA Device %d...\n", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre) {
(*fn->pre) (cookie);
}
/* Establish the initial state */
(*fn->pgm) (true, true, cookie); /* Assert the program, commit */
/* Wait for INIT state (init low) */
ts = get_timer (0); /* get current time */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to start.\n");
return FPGA_FAIL;
}
} while (!(*fn->init) (cookie));
/* Get ready for the burn */
CONFIG_FPGA_DELAY ();
(*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
ts = get_timer (0); /* get current time */
/* Now wait for INIT to go high */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to clear.\n");
return FPGA_FAIL;
}
} while ((*fn->init) (cookie));
/* Load the data */
while (bytecount < bsize) {
/* Xilinx detects an error if INIT goes low (active)
while DONE is low (inactive) */
if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
puts ("** CRC error during FPGA load.\n");
return (FPGA_FAIL);
}
val = data [bytecount ++];
i = 8;
do {
/* Deassert the clock */
(*fn->clk) (false, true, cookie);
CONFIG_FPGA_DELAY ();
/* Write data */
(*fn->wr) ((val & 0x80), true, cookie);
CONFIG_FPGA_DELAY ();
/* Assert the clock */
(*fn->clk) (true, true, cookie);
CONFIG_FPGA_DELAY ();
val <<= 1;
i --;
} while (i > 0);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
CONFIG_FPGA_DELAY ();
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
/* now check for done signal */
ts = get_timer (0); /* get current time */
ret_val = FPGA_SUCCESS;
(*fn->wr) (true, true, cookie);
while (! (*fn->done) (cookie)) {
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
putc ('*');
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for DONE to clear.\n");
ret_val = FPGA_FAIL;
break;
}
}
putc ('\n'); /* terminate the dotted line */
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post) (cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS)
puts ("Done.\n");
else
puts ("Fail.\n");
#endif
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
/* Readback is only available through the Slave Parallel and */
/* boundary-scan interfaces. */
printf ("%s: Slave Serial Dumping is unavailable\n",
__FUNCTION__);
return FPGA_FAIL;
}
struct xilinx_fpga_op spartan2_op = {
.load = spartan2_load,
.dump = spartan2_dump,
.info = spartan2_info,
};
@@ -0,0 +1,473 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
*/
/*
* Configuration support for Xilinx Spartan3 devices. Based
* on spartan2.c (Rich Ireland, rireland@enterasys.com).
*/
#include <common.h> /* core U-Boot definitions */
#include <spartan3.h> /* Spartan-II device family */
/* Define FPGA_DEBUG to get debug printf's */
#ifdef FPGA_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
#undef CONFIG_SYS_FPGA_CHECK_BUSY
/* Note: The assumption is that we cannot possibly run fast enough to
* overrun the device (the Slave Parallel mode can free run at 50MHz).
* If there is a need to operate slower, define CONFIG_FPGA_DELAY in
* the board config file to slow things down.
*/
#ifndef CONFIG_FPGA_DELAY
#define CONFIG_FPGA_DELAY()
#endif
#ifndef CONFIG_SYS_FPGA_WAIT
#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
#endif
static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* static int spartan3_sp_info(xilinx_desc *desc ); */
static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* static int spartan3_ss_info(xilinx_desc *desc); */
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
ret_val = spartan3_ss_load(desc, buf, bsize);
break;
case slave_parallel:
PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
ret_val = spartan3_sp_load(desc, buf, bsize);
break;
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
static int spartan3_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
ret_val = spartan3_ss_dump(desc, buf, bsize);
break;
case slave_parallel:
PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
ret_val = spartan3_sp_dump(desc, buf, bsize);
break;
default:
printf ("%s: Unsupported interface type, %d\n",
__FUNCTION__, desc->iface);
}
return ret_val;
}
static int spartan3_info(xilinx_desc *desc)
{
return FPGA_SUCCESS;
}
/* ------------------------------------------------------------------------- */
/* Spartan-II Slave Parallel Generic Implementation */
static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns;
PRINTF ("%s: start with interface functions @ 0x%p\n",
__FUNCTION__, fn);
if (fn) {
size_t bytecount = 0;
unsigned char *data = (unsigned char *) buf;
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF ("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"pre: 0x%p\n"
"pgm:\t0x%p\n"
"init:\t0x%p\n"
"err:\t0x%p\n"
"clk:\t0x%p\n"
"cs:\t0x%p\n"
"wr:\t0x%p\n"
"read data:\t0x%p\n"
"write data:\t0x%p\n"
"busy:\t0x%p\n"
"abort:\t0x%p\n",
"post:\t0x%p\n\n",
__FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
fn->abort, fn->post);
/*
* This code is designed to emulate the "Express Style"
* Continuous Data Loading in Slave Parallel Mode for
* the Spartan-II Family.
*/
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf ("Loading FPGA Device %d...\n", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre) {
(*fn->pre) (cookie);
}
/* Establish the initial state */
(*fn->pgm) (true, true, cookie); /* Assert the program, commit */
/* Get ready for the burn */
CONFIG_FPGA_DELAY ();
(*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
ts = get_timer (0); /* get current time */
/* Now wait for INIT and BUSY to go high */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
return FPGA_FAIL;
}
} while ((*fn->init) (cookie) && (*fn->busy) (cookie));
(*fn->wr) (true, true, cookie); /* Assert write, commit */
(*fn->cs) (true, true, cookie); /* Assert chip select, commit */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
/* Load the data */
while (bytecount < bsize) {
/* XXX - do we check for an Ctrl-C press in here ??? */
/* XXX - Check the error bit? */
(*fn->wdata) (data[bytecount++], true, cookie); /* write the data */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
ts = get_timer (0); /* get current time */
while ((*fn->busy) (cookie)) {
/* XXX - we should have a check in here somewhere to
* make sure we aren't busy forever... */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for BUSY to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
return FPGA_FAIL;
}
}
#endif
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
CONFIG_FPGA_DELAY ();
(*fn->cs) (false, true, cookie); /* Deassert the chip select */
(*fn->wr) (false, true, cookie); /* Deassert the write pin */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
/* now check for done signal */
ts = get_timer (0); /* get current time */
ret_val = FPGA_SUCCESS;
while ((*fn->done) (cookie) == FPGA_FAIL) {
/* XXX - we should have a check in here somewhere to
* make sure we aren't busy forever... */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for DONE to clear.\n");
(*fn->abort) (cookie); /* abort the burn */
ret_val = FPGA_FAIL;
break;
}
}
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post) (cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS)
puts ("Done.\n");
else
puts ("Fail.\n");
#endif
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns;
if (fn) {
unsigned char *data = (unsigned char *) buf;
size_t bytecount = 0;
int cookie = desc->cookie; /* make a local copy */
printf ("Starting Dump of FPGA Device %d...\n", cookie);
(*fn->cs) (true, true, cookie); /* Assert chip select, commit */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
/* dump the data */
while (bytecount < bsize) {
/* XXX - do we check for an Ctrl-C press in here ??? */
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
(*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
(*fn->cs) (false, false, cookie); /* Deassert the chip select */
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
puts ("Done.\n");
/* XXX - checksum the data? */
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
/* ------------------------------------------------------------------------- */
static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL; /* assume the worst */
xilinx_spartan3_slave_serial_fns *fn = desc->iface_fns;
int i;
unsigned char val;
PRINTF ("%s: start with interface functions @ 0x%p\n",
__FUNCTION__, fn);
if (fn) {
size_t bytecount = 0;
unsigned char *data = (unsigned char *) buf;
int cookie = desc->cookie; /* make a local copy */
unsigned long ts; /* timestamp */
PRINTF ("%s: Function Table:\n"
"ptr:\t0x%p\n"
"struct: 0x%p\n"
"pgm:\t0x%p\n"
"init:\t0x%p\n"
"clk:\t0x%p\n"
"wr:\t0x%p\n"
"done:\t0x%p\n\n",
__FUNCTION__, &fn, fn, fn->pgm, fn->init,
fn->clk, fn->wr, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf ("Loading FPGA Device %d...\n", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre) {
(*fn->pre) (cookie);
}
/* Establish the initial state */
(*fn->pgm) (true, true, cookie); /* Assert the program, commit */
/* Wait for INIT state (init low) */
ts = get_timer (0); /* get current time */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to start.\n");
if (*fn->abort)
(*fn->abort) (cookie);
return FPGA_FAIL;
}
} while (!(*fn->init) (cookie));
/* Get ready for the burn */
CONFIG_FPGA_DELAY ();
(*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
ts = get_timer (0); /* get current time */
/* Now wait for INIT to go high */
do {
CONFIG_FPGA_DELAY ();
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for INIT to clear.\n");
if (*fn->abort)
(*fn->abort) (cookie);
return FPGA_FAIL;
}
} while ((*fn->init) (cookie));
/* Load the data */
if(*fn->bwr)
(*fn->bwr) (data, bsize, true, cookie);
else {
while (bytecount < bsize) {
/* Xilinx detects an error if INIT goes low (active)
while DONE is low (inactive) */
if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
puts ("** CRC error during FPGA load.\n");
if (*fn->abort)
(*fn->abort) (cookie);
return (FPGA_FAIL);
}
val = data [bytecount ++];
i = 8;
do {
/* Deassert the clock */
(*fn->clk) (false, true, cookie);
CONFIG_FPGA_DELAY ();
/* Write data */
(*fn->wr) ((val & 0x80), true, cookie);
CONFIG_FPGA_DELAY ();
/* Assert the clock */
(*fn->clk) (true, true, cookie);
CONFIG_FPGA_DELAY ();
val <<= 1;
i --;
} while (i > 0);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc ('.'); /* let them know we are alive */
#endif
}
}
CONFIG_FPGA_DELAY ();
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc ('\n'); /* terminate the dotted line */
#endif
/* now check for done signal */
ts = get_timer (0); /* get current time */
ret_val = FPGA_SUCCESS;
(*fn->wr) (true, true, cookie);
while (! (*fn->done) (cookie)) {
/* XXX - we should have a check in here somewhere to
* make sure we aren't busy forever... */
CONFIG_FPGA_DELAY ();
(*fn->clk) (false, true, cookie); /* Deassert the clock pin */
CONFIG_FPGA_DELAY ();
(*fn->clk) (true, true, cookie); /* Assert the clock pin */
putc ('*');
if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
puts ("** Timeout waiting for DONE to clear.\n");
ret_val = FPGA_FAIL;
break;
}
}
putc ('\n'); /* terminate the dotted line */
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post) (cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (ret_val == FPGA_SUCCESS)
puts ("Done.\n");
else
puts ("Fail.\n");
#endif
} else {
printf ("%s: NULL Interface function table!\n", __FUNCTION__);
}
return ret_val;
}
static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
/* Readback is only available through the Slave Parallel and */
/* boundary-scan interfaces. */
printf ("%s: Slave Serial Dumping is unavailable\n",
__FUNCTION__);
return FPGA_FAIL;
}
struct xilinx_fpga_op spartan3_op = {
.load = spartan3_load,
.dump = spartan3_dump,
.info = spartan3_info,
};
@@ -0,0 +1,283 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Intel Corporation <www.intel.com>
*/
#include <common.h>
#include <altera.h>
#include <asm/arch/mailbox_s10.h>
#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000
#define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000
static const struct mbox_cfgstat_state {
int err_no;
const char *error_name;
} mbox_cfgstat_state[] = {
{MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
{MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
{MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgment failed!"},
{MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
{MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted bitstream!"},
{MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
{MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
{MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
{MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
{MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot info!"},
{MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
{MBOX_RESP_ERROR, "Mailbox general error!"},
{-ETIMEDOUT, "I/O timeout error"},
{-1, "Unknown error!"}
};
#define MBOX_CFGSTAT_MAX ARRAY_SIZE(mbox_cfgstat_state)
static const char *mbox_cfgstat_to_str(int err)
{
int i;
for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
if (mbox_cfgstat_state[i].err_no == err)
return mbox_cfgstat_state[i].error_name;
}
return mbox_cfgstat_state[MBOX_CFGSTAT_MAX - 1].error_name;
}
/*
* Add the ongoing transaction's command ID into pending list and return
* the command ID for next transfer.
*/
static u8 add_transfer(u32 *xfer_pending_list, size_t list_size, u8 id)
{
int i;
for (i = 0; i < list_size; i++) {
if (xfer_pending_list[i])
continue;
xfer_pending_list[i] = id;
debug("ID(%d) added to transaction pending list\n", id);
/*
* Increment command ID for next transaction.
* Valid command ID (4 bits) is from 1 to 15.
*/
id = (id % 15) + 1;
break;
}
return id;
}
/*
* Check whether response ID match the command ID in the transfer
* pending list. If a match is found in the transfer pending list,
* it clears the transfer pending list and return the matched
* command ID.
*/
static int get_and_clr_transfer(u32 *xfer_pending_list, size_t list_size,
u8 id)
{
int i;
for (i = 0; i < list_size; i++) {
if (id != xfer_pending_list[i])
continue;
xfer_pending_list[i] = 0;
return id;
}
return 0;
}
/*
* Polling the FPGA configuration status.
* Return 0 for success, non-zero for error.
*/
static int reconfig_status_polling_resp(void)
{
int ret;
unsigned long start = get_timer(0);
while (1) {
ret = mbox_get_fpga_config_status(MBOX_RECONFIG_STATUS);
if (!ret)
return 0; /* configuration success */
if (ret != MBOX_CFGSTAT_STATE_CONFIG)
return ret;
if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
break; /* time out */
puts(".");
udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
}
return -ETIMEDOUT;
}
static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32 *resp_count,
u32 *resp_buf, u32 buf_size, u32 client_id)
{
u32 buf[MBOX_RESP_BUFFER_SIZE];
u32 mbox_hdr;
u32 resp_len;
u32 hdr_len;
u32 i;
if (*resp_count < buf_size) {
u32 rcv_len_max = buf_size - *resp_count;
if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
rcv_len_max = MBOX_RESP_BUFFER_SIZE;
resp_len = mbox_rcv_resp(buf, rcv_len_max);
for (i = 0; i < resp_len; i++) {
resp_buf[(*w_index)++] = buf[i];
*w_index %= buf_size;
(*resp_count)++;
}
}
/* No response in buffer */
if (*resp_count == 0)
return 0;
mbox_hdr = resp_buf[*r_index];
hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
/* Insufficient header length to return a mailbox header */
if ((*resp_count - 1) < hdr_len)
return 0;
*r_index += (hdr_len + 1);
*r_index %= buf_size;
*resp_count -= (hdr_len + 1);
/* Make sure response belongs to us */
if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
return 0;
return mbox_hdr;
}
/* Send bit stream data to SDM via RECONFIG_DATA mailbox command */
static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
u32 xfer_max, u32 buf_size_max)
{
u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
u32 resp_rindex = 0;
u32 resp_windex = 0;
u32 resp_count = 0;
u32 xfer_count = 0;
int resp_err = 0;
u8 cmd_id = 1;
u32 args[3];
int ret;
debug("SDM xfer_max = %d\n", xfer_max);
debug("SDM buf_size_max = %x\n\n", buf_size_max);
memset(xfer_pending, 0, sizeof(xfer_pending));
while (rbf_size || xfer_count) {
if (!resp_err && rbf_size && xfer_count < xfer_max) {
args[0] = MBOX_ARG_DESC_COUNT(1);
args[1] = (u64)rbf_data;
if (rbf_size >= buf_size_max) {
args[2] = buf_size_max;
rbf_size -= buf_size_max;
rbf_data += buf_size_max;
} else {
args[2] = (u64)rbf_size;
rbf_size = 0;
}
resp_err = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
MBOX_CMD_INDIRECT, 3, args);
if (!resp_err) {
xfer_count++;
cmd_id = add_transfer(xfer_pending,
MBOX_RESP_BUFFER_SIZE,
cmd_id);
}
puts(".");
} else {
u32 resp_hdr = get_resp_hdr(&resp_rindex, &resp_windex,
&resp_count,
response_buffer,
MBOX_RESP_BUFFER_SIZE,
MBOX_CLIENT_ID_UBOOT);
/*
* If no valid response header found or
* non-zero length from RECONFIG_DATA
*/
if (!resp_hdr || MBOX_RESP_LEN_GET(resp_hdr))
continue;
/* Check for response's status */
if (!resp_err) {
resp_err = MBOX_RESP_ERR_GET(resp_hdr);
debug("Response error code: %08x\n", resp_err);
}
ret = get_and_clr_transfer(xfer_pending,
MBOX_RESP_BUFFER_SIZE,
MBOX_RESP_ID_GET(resp_hdr));
if (ret) {
/* Claim and reuse the ID */
cmd_id = (u8)ret;
xfer_count--;
}
if (resp_err && !xfer_count)
return resp_err;
}
}
return 0;
}
/*
* This is the interface used by FPGA driver.
* Return 0 for success, non-zero for error.
*/
int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
int ret;
u32 resp_len = 2;
u32 resp_buf[2];
debug("Sending MBOX_RECONFIG...\n");
ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0,
NULL, 0, &resp_len, resp_buf);
if (ret) {
puts("Failure in RECONFIG mailbox command!\n");
return ret;
}
ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0], resp_buf[1]);
if (ret) {
printf("RECONFIG_DATA error: %08x, %s\n", ret,
mbox_cfgstat_to_str(ret));
return ret;
}
/* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
debug("Polling with MBOX_RECONFIG_STATUS...\n");
ret = reconfig_status_polling_resp();
if (ret) {
printf("RECONFIG_STATUS Error: %08x, %s\n", ret,
mbox_cfgstat_to_str(ret));
return ret;
}
puts("FPGA reconfiguration OK!\n");
return ret;
}
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Eran Liberty, Extricom , eran.liberty@gmail.com
*/
#include <common.h> /* core U-Boot definitions */
#include <altera.h>
int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize,
int isSerial, int isSecure);
int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize);
/****************************************************************/
/* Stratix II Generic Implementation */
int StratixII_load (Altera_desc * desc, void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 1, 0);
break;
case fast_passive_parallel:
ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 0);
break;
case fast_passive_parallel_security:
ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 1);
break;
/* Add new interface types here */
default:
printf ("%s: Unsupported interface type, %d\n", __FUNCTION__,
desc->iface);
}
return ret_val;
}
int StratixII_dump (Altera_desc * desc, void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case passive_serial:
case fast_passive_parallel:
case fast_passive_parallel_security:
ret_val = StratixII_ps_fpp_dump (desc, buf, bsize);
break;
/* Add new interface types here */
default:
printf ("%s: Unsupported interface type, %d\n", __FUNCTION__,
desc->iface);
}
return ret_val;
}
int StratixII_info (Altera_desc * desc)
{
return FPGA_SUCCESS;
}
int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize)
{
printf ("Stratix II Fast Passive Parallel dump is not implemented\n");
return FPGA_FAIL;
}
int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize,
int isSerial, int isSecure)
{
altera_board_specific_func *fns;
int cookie;
int ret_val = FPGA_FAIL;
int bytecount;
char *buff = buf;
int i;
if (!desc) {
printf ("%s(%d) Altera_desc missing\n", __FUNCTION__, __LINE__);
return FPGA_FAIL;
}
if (!buff) {
printf ("%s(%d) buffer is missing\n", __FUNCTION__, __LINE__);
return FPGA_FAIL;
}
if (!bsize) {
printf ("%s(%d) size is zero\n", __FUNCTION__, __LINE__);
return FPGA_FAIL;
}
if (!desc->iface_fns) {
printf
("%s(%d) Altera_desc function interface table is missing\n",
__FUNCTION__, __LINE__);
return FPGA_FAIL;
}
fns = (altera_board_specific_func *) (desc->iface_fns);
cookie = desc->cookie;
if (!
(fns->config && fns->status && fns->done && fns->data
&& fns->abort)) {
printf
("%s(%d) Missing some function in the function interface table\n",
__FUNCTION__, __LINE__);
return FPGA_FAIL;
}
/* 1. give board specific a chance to do anything before we start */
if (fns->pre) {
if ((ret_val = fns->pre (cookie)) < 0) {
return ret_val;
}
}
/* from this point on we must fail gracfully by calling lower layer abort */
/* 2. Strat burn cycle by deasserting config for t_CFG and waiting t_CF2CK after reaserted */
fns->config (0, 1, cookie);
udelay (5); /* nCONFIG low pulse width 2usec */
fns->config (1, 1, cookie);
udelay (100); /* nCONFIG high to first rising edge on DCLK */
/* 3. Start the Data cycle with clk deasserted */
bytecount = 0;
fns->clk (0, 1, cookie);
printf ("loading to fpga ");
while (bytecount < bsize) {
/* 3.1 check stratix has not signaled us an error */
if (fns->status (cookie) != 1) {
printf
("\n%s(%d) Stratix failed (byte transferred till failure 0x%x)\n",
__FUNCTION__, __LINE__, bytecount);
fns->abort (cookie);
return FPGA_FAIL;
}
if (isSerial) {
int i;
uint8_t data = buff[bytecount++];
for (i = 0; i < 8; i++) {
/* 3.2(ps) put data on the bus */
fns->data ((data >> i) & 1, 1, cookie);
/* 3.3(ps) clock once */
fns->clk (1, 1, cookie);
fns->clk (0, 1, cookie);
}
} else {
/* 3.2(fpp) put data on the bus */
fns->data (buff[bytecount++], 1, cookie);
/* 3.3(fpp) clock once */
fns->clk (1, 1, cookie);
fns->clk (0, 1, cookie);
/* 3.4(fpp) for secure cycle push 3 more clocks */
for (i = 0; isSecure && i < 3; i++) {
fns->clk (1, 1, cookie);
fns->clk (0, 1, cookie);
}
}
/* 3.5 while clk is deasserted it is safe to print some progress indication */
if ((bytecount % (bsize / 100)) == 0) {
printf ("\b\b\b%02d\%", bytecount * 100 / bsize);
}
}
/* 4. Set one last clock and check conf done signal */
fns->clk (1, 1, cookie);
udelay (100);
if (!fns->done (cookie)) {
printf (" error!.\n");
fns->abort (cookie);
return FPGA_FAIL;
} else {
printf ("\b\b\b done.\n");
}
/* 5. call lower layer post configuration */
if (fns->post) {
if ((ret_val = fns->post (cookie)) < 0) {
fns->abort (cookie);
return ret_val;
}
}
return FPGA_SUCCESS;
}
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*/
#include <common.h>
#include <altera.h>
#include <spi.h>
#include <asm/io.h>
#include <linux/errno.h>
/* Write the RBF data to FPGA via SPI */
static int program_write(int spi_bus, int spi_dev, const void *rbf_data,
unsigned long rbf_size)
{
struct spi_slave *slave;
int ret;
debug("%s (%d): data=%p size=%ld\n",
__func__, __LINE__, rbf_data, rbf_size);
/* FIXME: How to get the max. SPI clock and SPI mode? */
slave = spi_setup_slave(spi_bus, spi_dev, 27777777, SPI_MODE_3);
if (!slave)
return -1;
if (spi_claim_bus(slave))
return -1;
ret = spi_xfer(slave, rbf_size * 8, rbf_data, (void *)rbf_data,
SPI_XFER_BEGIN | SPI_XFER_END);
spi_release_bus(slave);
return ret;
}
/*
* This is the interface used by FPGA driver.
* Return 0 for sucess, non-zero for error.
*/
int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
altera_board_specific_func *pfns = desc->iface_fns;
int cookie = desc->cookie;
int spi_bus;
int spi_dev;
int ret = 0;
if ((u32)rbf_data & 0x3) {
puts("FPGA: Unaligned data, realign to 32bit boundary.\n");
return -EINVAL;
}
/* Run the pre configuration function if there is one */
if (pfns->pre)
(pfns->pre)(cookie);
/* Establish the initial state */
if (pfns->config) {
/* De-assert nCONFIG */
(pfns->config)(false, true, cookie);
/* nConfig minimum low pulse width is 2us */
udelay(200);
/* Assert nCONFIG */
(pfns->config)(true, true, cookie);
/* nCONFIG high to first rising clock on DCLK min 1506 us */
udelay(1600);
}
/* Write the RBF data to FPGA */
if (pfns->write) {
/*
* Use board specific data function to write bitstream
* into the FPGA
*/
ret = (pfns->write)(rbf_data, rbf_size, true, cookie);
} else {
/*
* Use common SPI functions to write bitstream into the
* FPGA
*/
spi_bus = COOKIE2SPI_BUS(cookie);
spi_dev = COOKIE2SPI_DEV(cookie);
ret = program_write(spi_bus, spi_dev, rbf_data, rbf_size);
}
if (ret)
return ret;
/* Check done pin */
if (pfns->done) {
ret = (pfns->done)(cookie);
if (ret)
printf("Error: DONE not set (ret=%d)!\n", ret);
}
return ret;
}
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2019, Xilinx, Inc,
* Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <asm/arch/sys_proto.h>
#include <memalign.h>
#include <versalpl.h>
#include <zynqmp_firmware.h>
static ulong versal_align_dma_buffer(ulong *buf, u32 len)
{
ulong *new_buf;
if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
memcpy(new_buf, buf, len);
buf = new_buf;
}
return (ulong)buf;
}
static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
ulong bin_buf;
int ret;
u32 buf_lo, buf_hi;
u32 ret_payload[5];
bin_buf = versal_align_dma_buffer((ulong *)buf, bsize);
debug("%s called!\n", __func__);
flush_dcache_range(bin_buf, bin_buf + bsize);
buf_lo = lower_32_bits(bin_buf);
buf_hi = upper_32_bits(bin_buf);
ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
buf_hi, 0, ret_payload);
if (ret)
puts("PL FPGA LOAD fail\n");
return ret;
}
struct xilinx_fpga_op versal_op = {
.load = versal_load,
};
@@ -0,0 +1,527 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
* Keith Outwater, keith_outwater@mvis.com
*
* Copyright (c) 2019 SED Systems, a division of Calian Ltd.
*/
/*
* Configuration support for Xilinx Virtex2 devices. Based
* on spartan2.c (Rich Ireland, rireland@enterasys.com).
*/
#include <common.h>
#include <console.h>
#include <virtex2.h>
#if 0
#define FPGA_DEBUG
#endif
#ifdef FPGA_DEBUG
#define PRINTF(fmt, args...) printf(fmt, ##args)
#else
#define PRINTF(fmt, args...)
#endif
/*
* If the SelectMap interface can be overrun by the processor, define
* CONFIG_SYS_FPGA_CHECK_BUSY and/or CONFIG_FPGA_DELAY in the board
* configuration file and add board-specific support for checking BUSY status.
* By default, assume that the SelectMap interface cannot be overrun.
*/
#ifndef CONFIG_SYS_FPGA_CHECK_BUSY
#undef CONFIG_SYS_FPGA_CHECK_BUSY
#endif
#ifndef CONFIG_FPGA_DELAY
#define CONFIG_FPGA_DELAY()
#endif
#ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK
#define CONFIG_SYS_FPGA_PROG_FEEDBACK
#endif
/*
* Don't allow config cycle to be interrupted
*/
#ifndef CONFIG_SYS_FPGA_CHECK_CTRLC
#undef CONFIG_SYS_FPGA_CHECK_CTRLC
#endif
/*
* Check for errors during configuration by default
*/
#ifndef CONFIG_SYS_FPGA_CHECK_ERROR
#define CONFIG_SYS_FPGA_CHECK_ERROR
#endif
/*
* The default timeout in mS for INIT_B to deassert after PROG_B has
* been deasserted. Per the latest Virtex II Handbook (page 347), the
* max time from PORG_B deassertion to INIT_B deassertion is 4uS per
* data frame for the XC2V8000. The XC2V8000 has 2860 data frames
* which yields 11.44 mS. So let's make it bigger in order to handle
* an XC2V1000, if anyone can ever get ahold of one.
*/
#ifndef CONFIG_SYS_FPGA_WAIT_INIT
#define CONFIG_SYS_FPGA_WAIT_INIT CONFIG_SYS_HZ / 2 /* 500 ms */
#endif
/*
* The default timeout for waiting for BUSY to deassert during configuration.
* This is normally not necessary since for most reasonable configuration
* clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary.
*/
#ifndef CONFIG_SYS_FPGA_WAIT_BUSY
#define CONFIG_SYS_FPGA_WAIT_BUSY CONFIG_SYS_HZ / 200 /* 5 ms*/
#endif
/* Default timeout for waiting for FPGA to enter operational mode after
* configuration data has been written.
*/
#ifndef CONFIG_SYS_FPGA_WAIT_CONFIG
#define CONFIG_SYS_FPGA_WAIT_CONFIG CONFIG_SYS_HZ / 5 /* 200 ms */
#endif
static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF("%s: Launching Slave Serial Load\n", __func__);
ret_val = virtex2_ss_load(desc, buf, bsize);
break;
case slave_selectmap:
PRINTF("%s: Launching Slave Parallel Load\n", __func__);
ret_val = virtex2_ssm_load(desc, buf, bsize);
break;
default:
printf("%s: Unsupported interface type, %d\n",
__func__, desc->iface);
}
return ret_val;
}
static int virtex2_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
switch (desc->iface) {
case slave_serial:
PRINTF("%s: Launching Slave Serial Dump\n", __func__);
ret_val = virtex2_ss_dump(desc, buf, bsize);
break;
case slave_parallel:
PRINTF("%s: Launching Slave Parallel Dump\n", __func__);
ret_val = virtex2_ssm_dump(desc, buf, bsize);
break;
default:
printf("%s: Unsupported interface type, %d\n",
__func__, desc->iface);
}
return ret_val;
}
static int virtex2_info(xilinx_desc *desc)
{
return FPGA_SUCCESS;
}
/*
* Virtex-II Slave SelectMap or Serial configuration loader. Configuration
* is as follows:
* 1. Set the FPGA's PROG_B line low.
* 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high.
* 3. Write data to the SelectMap port. If INIT_B goes low at any time
* this process, a configuration error (most likely CRC failure) has
* ocurred. At this point a status word may be read from the
* SelectMap interface to determine the source of the problem (You
* could, for instance, put this in your 'abort' function handler).
* 4. After all data has been written, test the state of the FPGA
* INIT_B and DONE lines. If both are high, configuration has
* succeeded. Congratulations!
*/
static int virtex2_slave_pre(xilinx_virtex2_slave_fns *fn, int cookie)
{
unsigned long ts;
PRINTF("%s:%d: Start with interface functions @ 0x%p\n",
__func__, __LINE__, fn);
if (!fn) {
printf("%s:%d: NULL Interface function table!\n",
__func__, __LINE__);
return FPGA_FAIL;
}
/* Gotta split this one up (so the stack won't blow??) */
PRINTF("%s:%d: Function Table:\n"
" base 0x%p\n"
" struct 0x%p\n"
" pre 0x%p\n"
" prog 0x%p\n"
" init 0x%p\n"
" error 0x%p\n",
__func__, __LINE__,
&fn, fn, fn->pre, fn->pgm, fn->init, fn->err);
PRINTF(" clock 0x%p\n"
" cs 0x%p\n"
" write 0x%p\n"
" rdata 0x%p\n"
" wdata 0x%p\n"
" busy 0x%p\n"
" abort 0x%p\n"
" post 0x%p\n\n",
fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata,
fn->busy, fn->abort, fn->post);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf("Initializing FPGA Device %d...\n", cookie);
#endif
/*
* Run the pre configuration function if there is one.
*/
if (*fn->pre)
(*fn->pre)(cookie);
/*
* Assert the program line. The minimum pulse width for
* Virtex II devices is 300 nS (Tprogram parameter in datasheet).
* There is no maximum value for the pulse width. Check to make
* sure that INIT_B goes low after assertion of PROG_B
*/
(*fn->pgm)(true, true, cookie);
udelay(10);
ts = get_timer(0);
do {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
printf("%s:%d: ** Timeout after %d ticks waiting for INIT to assert.\n",
__func__, __LINE__, CONFIG_SYS_FPGA_WAIT_INIT);
(*fn->abort)(cookie);
return FPGA_FAIL;
}
} while (!(*fn->init)(cookie));
(*fn->pgm)(false, true, cookie);
CONFIG_FPGA_DELAY();
if (fn->clk)
(*fn->clk)(true, true, cookie);
/*
* Start a timer and wait for INIT_B to go high
*/
ts = get_timer(0);
do {
CONFIG_FPGA_DELAY();
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
printf("%s:%d: ** Timeout after %d ticks waiting for INIT to deassert.\n",
__func__, __LINE__, CONFIG_SYS_FPGA_WAIT_INIT);
(*fn->abort)(cookie);
return FPGA_FAIL;
}
} while ((*fn->init)(cookie) && (*fn->busy)(cookie));
if (fn->wr)
(*fn->wr)(true, true, cookie);
if (fn->cs)
(*fn->cs)(true, true, cookie);
mdelay(10);
return FPGA_SUCCESS;
}
static int virtex2_slave_post(xilinx_virtex2_slave_fns *fn,
int cookie)
{
int ret_val = FPGA_SUCCESS;
int num_done = 0;
unsigned long ts;
/*
* Finished writing the data; deassert FPGA CS_B and WRITE_B signals.
*/
CONFIG_FPGA_DELAY();
if (fn->cs)
(*fn->cs)(false, true, cookie);
if (fn->wr)
(*fn->wr)(false, true, cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc('\n');
#endif
/*
* Check for successful configuration. FPGA INIT_B and DONE
* should both be high upon successful configuration. Continue pulsing
* clock with data set to all ones until DONE is asserted and for 8
* clock cycles afterwards.
*/
ts = get_timer(0);
while (true) {
if ((*fn->done)(cookie) == FPGA_SUCCESS &&
!((*fn->init)(cookie))) {
if (num_done++ >= 8)
break;
}
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT_CONFIG) {
printf("%s:%d: ** Timeout after %d ticks waiting for DONE to assert and INIT to deassert\n",
__func__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG);
(*fn->abort)(cookie);
ret_val = FPGA_FAIL;
break;
}
if (fn->wbulkdata) {
unsigned char dummy = 0xff;
(*fn->wbulkdata)(&dummy, 1, true, cookie);
} else {
(*fn->wdata)(0xff, true, cookie);
CONFIG_FPGA_DELAY();
(*fn->clk)(false, true, cookie);
CONFIG_FPGA_DELAY();
(*fn->clk)(true, true, cookie);
}
}
if (ret_val == FPGA_SUCCESS) {
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf("Initialization of FPGA device %d complete\n", cookie);
#endif
/*
* Run the post configuration function if there is one.
*/
if (*fn->post)
(*fn->post)(cookie);
} else {
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
printf("** Initialization of FPGA device %d FAILED\n",
cookie);
#endif
}
return ret_val;
}
static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
xilinx_virtex2_slave_fns *fn = desc->iface_fns;
size_t bytecount = 0;
unsigned char *data = (unsigned char *)buf;
int cookie = desc->cookie;
ret_val = virtex2_slave_pre(fn, cookie);
if (ret_val != FPGA_SUCCESS)
return ret_val;
/*
* Load the data byte by byte
*/
while (bytecount < bsize) {
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
if (ctrlc()) {
(*fn->abort)(cookie);
return FPGA_FAIL;
}
#endif
if ((*fn->done)(cookie) == FPGA_SUCCESS) {
PRINTF("%s:%d:done went active early, bytecount = %d\n",
__func__, __LINE__, bytecount);
break;
}
#ifdef CONFIG_SYS_FPGA_CHECK_ERROR
if ((*fn->init)(cookie)) {
printf("\n%s:%d: ** Error: INIT asserted during configuration\n",
__func__, __LINE__);
printf("%zu = buffer offset, %zu = buffer size\n",
bytecount, bsize);
(*fn->abort)(cookie);
return FPGA_FAIL;
}
#endif
(*fn->wdata)(data[bytecount++], true, cookie);
CONFIG_FPGA_DELAY();
/*
* Cycle the clock pin
*/
(*fn->clk)(false, true, cookie);
CONFIG_FPGA_DELAY();
(*fn->clk)(true, true, cookie);
#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
ts = get_timer(0);
while ((*fn->busy)(cookie)) {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT_BUSY) {
printf("%s:%d: ** Timeout after %d ticks waiting for BUSY to deassert\n",
__func__, __LINE__,
CONFIG_SYS_FPGA_WAIT_BUSY);
(*fn->abort)(cookie);
return FPGA_FAIL;
}
}
#endif
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc('.');
#endif
}
return virtex2_slave_post(fn, cookie);
}
/*
* Read the FPGA configuration data
*/
static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
xilinx_virtex2_slave_fns *fn = desc->iface_fns;
if (fn) {
unsigned char *data = (unsigned char *)buf;
size_t bytecount = 0;
int cookie = desc->cookie;
printf("Starting Dump of FPGA Device %d...\n", cookie);
(*fn->cs)(true, true, cookie);
(*fn->clk)(true, true, cookie);
while (bytecount < bsize) {
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
if (ctrlc()) {
(*fn->abort)(cookie);
return FPGA_FAIL;
}
#endif
/*
* Cycle the clock and read the data
*/
(*fn->clk)(false, true, cookie);
(*fn->clk)(true, true, cookie);
(*fn->rdata)(&data[bytecount++], cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc('.');
#endif
}
/*
* Deassert CS_B and cycle the clock to deselect the device.
*/
(*fn->cs)(false, false, cookie);
(*fn->clk)(false, true, cookie);
(*fn->clk)(true, true, cookie);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
putc('\n');
#endif
puts("Done.\n");
} else {
printf("%s:%d: NULL Interface function table!\n",
__func__, __LINE__);
}
return ret_val;
}
static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
{
int ret_val = FPGA_FAIL;
xilinx_virtex2_slave_fns *fn = desc->iface_fns;
unsigned char *data = (unsigned char *)buf;
int cookie = desc->cookie;
ret_val = virtex2_slave_pre(fn, cookie);
if (ret_val != FPGA_SUCCESS)
return ret_val;
if (fn->wbulkdata) {
/* Load the data in a single chunk */
(*fn->wbulkdata)(data, bsize, true, cookie);
} else {
size_t bytecount = 0;
/*
* Load the data bit by bit
*/
while (bytecount < bsize) {
unsigned char curr_data = data[bytecount++];
int bit;
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
if (ctrlc()) {
(*fn->abort) (cookie);
return FPGA_FAIL;
}
#endif
if ((*fn->done)(cookie) == FPGA_SUCCESS) {
PRINTF("%s:%d:done went active early, bytecount = %d\n",
__func__, __LINE__, bytecount);
break;
}
#ifdef CONFIG_SYS_FPGA_CHECK_ERROR
if ((*fn->init)(cookie)) {
printf("\n%s:%d: ** Error: INIT asserted during configuration\n",
__func__, __LINE__);
printf("%zu = buffer offset, %zu = buffer size\n",
bytecount, bsize);
(*fn->abort)(cookie);
return FPGA_FAIL;
}
#endif
for (bit = 7; bit >= 0; --bit) {
unsigned char curr_bit = (curr_data >> bit) & 1;
(*fn->wdata)(curr_bit, true, cookie);
CONFIG_FPGA_DELAY();
(*fn->clk)(false, true, cookie);
CONFIG_FPGA_DELAY();
(*fn->clk)(true, true, cookie);
}
/* Slave serial never uses a busy pin */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
if (bytecount % (bsize / 40) == 0)
putc('.');
#endif
}
}
return virtex2_slave_post(fn, cookie);
}
static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
printf("%s: Slave Serial Dumping is unsupported\n", __func__);
return FPGA_FAIL;
}
/* vim: set ts=4 tw=78: */
struct xilinx_fpga_op virtex2_op = {
.load = virtex2_load,
.dump = virtex2_dump,
.info = virtex2_info,
};
@@ -0,0 +1,317 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2012-2013, Xilinx, Michal Simek
*
* (C) Copyright 2002
* Rich Ireland, Enterasys Networks, rireland@enterasys.com.
* Keith Outwater, keith_outwater@mvis.com
*/
/*
* Xilinx FPGA support
*/
#include <common.h>
#include <fpga.h>
#include <virtex2.h>
#include <spartan2.h>
#include <spartan3.h>
#include <zynqpl.h>
/* Local Static Functions */
static int xilinx_validate(xilinx_desc *desc, char *fn);
/* ------------------------------------------------------------------------- */
int fpga_is_partial_data(int devnum, size_t img_len)
{
const fpga_desc * const desc = fpga_get_desc(devnum);
xilinx_desc *desc_xilinx = desc->devdesc;
/* Check datasize against FPGA size */
if (img_len >= desc_xilinx->size)
return 0;
/* datasize is smaller, must be partial data */
return 1;
}
int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
bitstream_type bstype)
{
unsigned int length;
unsigned int swapsize;
unsigned char *dataptr;
unsigned int i;
const fpga_desc *desc;
xilinx_desc *xdesc;
dataptr = (unsigned char *)fpgadata;
/* Find out fpga_description */
desc = fpga_validate(devnum, dataptr, 0, (char *)__func__);
/* Assign xilinx device description */
xdesc = desc->devdesc;
/* skip the first bytes of the bitsteam, their meaning is unknown */
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
dataptr += length;
/* get design name (identifier, length, string) */
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
if (*dataptr++ != 0x61) {
debug("%s: Design name id not recognized in bitstream\n",
__func__);
return FPGA_FAIL;
}
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
printf(" design filename = \"%s\"\n", dataptr);
dataptr += length;
/* get part number (identifier, length, string) */
if (*dataptr++ != 0x62) {
printf("%s: Part number id not recognized in bitstream\n",
__func__);
return FPGA_FAIL;
}
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
if (xdesc->name) {
i = (ulong)strstr((char *)dataptr, xdesc->name);
if (!i) {
printf("%s: Wrong bitstream ID for this device\n",
__func__);
printf("%s: Bitstream ID %s, current device ID %d/%s\n",
__func__, dataptr, devnum, xdesc->name);
return FPGA_FAIL;
}
} else {
printf("%s: Please fill correct device ID to xilinx_desc\n",
__func__);
}
printf(" part number = \"%s\"\n", dataptr);
dataptr += length;
/* get date (identifier, length, string) */
if (*dataptr++ != 0x63) {
printf("%s: Date identifier not recognized in bitstream\n",
__func__);
return FPGA_FAIL;
}
length = (*dataptr << 8) + *(dataptr+1);
dataptr += 2;
printf(" date = \"%s\"\n", dataptr);
dataptr += length;
/* get time (identifier, length, string) */
if (*dataptr++ != 0x64) {
printf("%s: Time identifier not recognized in bitstream\n",
__func__);
return FPGA_FAIL;
}
length = (*dataptr << 8) + *(dataptr+1);
dataptr += 2;
printf(" time = \"%s\"\n", dataptr);
dataptr += length;
/* get fpga data length (identifier, length) */
if (*dataptr++ != 0x65) {
printf("%s: Data length id not recognized in bitstream\n",
__func__);
return FPGA_FAIL;
}
swapsize = ((unsigned int) *dataptr << 24) +
((unsigned int) *(dataptr + 1) << 16) +
((unsigned int) *(dataptr + 2) << 8) +
((unsigned int) *(dataptr + 3));
dataptr += 4;
printf(" bytes in bitstream = %d\n", swapsize);
return fpga_load(devnum, dataptr, swapsize, bstype);
}
int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
return FPGA_FAIL;
}
if (!desc->operations || !desc->operations->load) {
printf("%s: Missing load operation\n", __func__);
return FPGA_FAIL;
}
return desc->operations->load(desc, buf, bsize, bstype);
}
#if defined(CONFIG_CMD_FPGA_LOADFS)
int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
fpga_fs_info *fpga_fsinfo)
{
if (!xilinx_validate(desc, (char *)__func__)) {
printf("%s: Invalid device descriptor\n", __func__);
return FPGA_FAIL;
}
if (!desc->operations || !desc->operations->loadfs) {
printf("%s: Missing loadfs operation\n", __func__);
return FPGA_FAIL;
}
return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
}
#endif
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
int xilinx_loads(xilinx_desc *desc, const void *buf, size_t bsize,
struct fpga_secure_info *fpga_sec_info)
{
if (!xilinx_validate(desc, (char *)__func__)) {
printf("%s: Invalid device descriptor\n", __func__);
return FPGA_FAIL;
}
if (!desc->operations || !desc->operations->loads) {
printf("%s: Missing loads operation\n", __func__);
return FPGA_FAIL;
}
return desc->operations->loads(desc, buf, bsize, fpga_sec_info);
}
#endif
int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
return FPGA_FAIL;
}
if (!desc->operations || !desc->operations->dump) {
printf("%s: Missing dump operation\n", __func__);
return FPGA_FAIL;
}
return desc->operations->dump(desc, buf, bsize);
}
int xilinx_info(xilinx_desc *desc)
{
int ret_val = FPGA_FAIL;
if (xilinx_validate (desc, (char *)__FUNCTION__)) {
printf ("Family: \t");
switch (desc->family) {
case xilinx_spartan2:
printf ("Spartan-II\n");
break;
case xilinx_spartan3:
printf ("Spartan-III\n");
break;
case xilinx_virtex2:
printf ("Virtex-II\n");
break;
case xilinx_zynq:
printf("Zynq PL\n");
break;
case xilinx_zynqmp:
printf("ZynqMP PL\n");
break;
case xilinx_versal:
printf("Versal PL\n");
break;
/* Add new family types here */
default:
printf ("Unknown family type, %d\n", desc->family);
}
printf ("Interface type:\t");
switch (desc->iface) {
case slave_serial:
printf ("Slave Serial\n");
break;
case master_serial: /* Not used */
printf ("Master Serial\n");
break;
case slave_parallel:
printf ("Slave Parallel\n");
break;
case jtag_mode: /* Not used */
printf ("JTAG Mode\n");
break;
case slave_selectmap:
printf ("Slave SelectMap Mode\n");
break;
case master_selectmap:
printf ("Master SelectMap Mode\n");
break;
case devcfg:
printf("Device configuration interface (Zynq)\n");
break;
case csu_dma:
printf("csu_dma configuration interface (ZynqMP)\n");
break;
case cfi:
printf("CFI configuration interface (Versal)\n");
break;
/* Add new interface types here */
default:
printf ("Unsupported interface type, %d\n", desc->iface);
}
printf("Device Size: \t%zd bytes\n"
"Cookie: \t0x%x (%d)\n",
desc->size, desc->cookie, desc->cookie);
if (desc->name)
printf("Device name: \t%s\n", desc->name);
if (desc->iface_fns)
printf ("Device Function Table @ 0x%p\n", desc->iface_fns);
else
printf ("No Device Function Table.\n");
if (desc->operations && desc->operations->info)
desc->operations->info(desc);
ret_val = FPGA_SUCCESS;
} else {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
}
return ret_val;
}
/* ------------------------------------------------------------------------- */
static int xilinx_validate(xilinx_desc *desc, char *fn)
{
int ret_val = false;
if (desc) {
if ((desc->family > min_xilinx_type) &&
(desc->family < max_xilinx_type)) {
if ((desc->iface > min_xilinx_iface_type) &&
(desc->iface < max_xilinx_iface_type)) {
if (desc->size) {
ret_val = true;
} else
printf ("%s: NULL part size\n", fn);
} else
printf ("%s: Invalid Interface type, %d\n",
fn, desc->iface);
} else
printf ("%s: Invalid family type, %d\n", fn, desc->family);
} else
printf ("%s: NULL descriptor!\n", fn);
return ret_val;
}
@@ -0,0 +1,309 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2015 - 2016, Xilinx, Inc,
* Michal Simek <michal.simek@xilinx.com>
* Siva Durga Prasad <siva.durga.paladugu@xilinx.com>
*/
#include <console.h>
#include <common.h>
#include <cpu_func.h>
#include <zynqmppl.h>
#include <zynqmp_firmware.h>
#include <linux/sizes.h>
#include <asm/arch/sys_proto.h>
#include <memalign.h>
#define DUMMY_WORD 0xffffffff
/* Xilinx binary format header */
static const u32 bin_format[] = {
DUMMY_WORD, /* Dummy words */
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
0x000000bb, /* Sync word */
0x11220044, /* Sync word */
DUMMY_WORD,
DUMMY_WORD,
0xaa995566, /* Sync word */
};
#define SWAP_NO 1
#define SWAP_DONE 2
/*
* Load the whole word from unaligned buffer
* Keep in your mind that it is byte loading on little-endian system
*/
static u32 load_word(const void *buf, u32 swap)
{
u32 word = 0;
u8 *bitc = (u8 *)buf;
int p;
if (swap == SWAP_NO) {
for (p = 0; p < 4; p++) {
word <<= 8;
word |= bitc[p];
}
} else {
for (p = 3; p >= 0; p--) {
word <<= 8;
word |= bitc[p];
}
}
return word;
}
static u32 check_header(const void *buf)
{
u32 i, pattern;
int swap = SWAP_NO;
u32 *test = (u32 *)buf;
debug("%s: Let's check bitstream header\n", __func__);
/* Checking that passing bin is not a bitstream */
for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
pattern = load_word(&test[i], swap);
/*
* Bitstreams in binary format are swapped
* compare to regular bistream.
* Do not swap dummy word but if swap is done assume
* that parsing buffer is binary format
*/
if ((__swab32(pattern) != DUMMY_WORD) &&
(__swab32(pattern) == bin_format[i])) {
swap = SWAP_DONE;
debug("%s: data swapped - let's swap\n", __func__);
}
debug("%s: %d/%px: pattern %x/%x bin_format\n", __func__, i,
&test[i], pattern, bin_format[i]);
}
debug("%s: Found bitstream header at %px %s swapinng\n", __func__,
buf, swap == SWAP_NO ? "without" : "with");
return swap;
}
static void *check_data(u8 *buf, size_t bsize, u32 *swap)
{
u32 word, p = 0; /* possition */
/* Because buf doesn't need to be aligned let's read it by chars */
for (p = 0; p < bsize; p++) {
word = load_word(&buf[p], SWAP_NO);
debug("%s: word %x %x/%px\n", __func__, word, p, &buf[p]);
/* Find the first bitstream dummy word */
if (word == DUMMY_WORD) {
debug("%s: Found dummy word at position %x/%px\n",
__func__, p, &buf[p]);
*swap = check_header(&buf[p]);
if (*swap) {
/* FIXME add full bitstream checking here */
return &buf[p];
}
}
/* Loop can be huge - support CTRL + C */
if (ctrlc())
return NULL;
}
return NULL;
}
static ulong zynqmp_align_dma_buffer(u32 *buf, u32 len, u32 swap)
{
u32 *new_buf;
u32 i;
if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
new_buf = (u32 *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
/*
* This might be dangerous but permits to flash if
* ARCH_DMA_MINALIGN is greater than header size
*/
if (new_buf > (u32 *)buf) {
debug("%s: Aligned buffer is after buffer start\n",
__func__);
new_buf -= ARCH_DMA_MINALIGN;
}
printf("%s: Align buffer at %px to %px(swap %d)\n", __func__,
buf, new_buf, swap);
for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);
buf = new_buf;
} else if ((swap != SWAP_DONE) &&
(zynqmp_firmware_version() <= PMUFW_V1_0)) {
/* For bitstream which are aligned */
new_buf = buf;
printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
swap);
for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);
}
return (ulong)buf;
}
static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf,
size_t bsize, u32 blocksize, u32 *swap)
{
ulong *buf_start;
ulong diff;
buf_start = check_data((u8 *)buf, blocksize, swap);
if (!buf_start)
return FPGA_FAIL;
/* Check if data is postpone from start */
diff = (ulong)buf_start - (ulong)buf;
if (diff) {
printf("%s: Bitstream is not validated yet (diff %lx)\n",
__func__, diff);
return FPGA_FAIL;
}
if ((ulong)buf < SZ_1M) {
printf("%s: Bitstream has to be placed up to 1MB (%px)\n",
__func__, buf);
return FPGA_FAIL;
}
return 0;
}
static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1);
u32 swap = 0;
ulong bin_buf;
int ret;
u32 buf_lo, buf_hi;
u32 ret_payload[PAYLOAD_ARG_CNT];
bool xilfpga_old = false;
if (zynqmp_firmware_version() <= PMUFW_V1_0) {
puts("WARN: PMUFW v1.0 or less is detected\n");
puts("WARN: Not all bitstream formats are supported\n");
puts("WARN: Please upgrade PMUFW\n");
xilfpga_old = true;
if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap))
return FPGA_FAIL;
bsizeptr = (u32 *)&bsize;
flush_dcache_range((ulong)bsizeptr,
(ulong)bsizeptr + sizeof(size_t));
bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
}
bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap);
debug("%s called!\n", __func__);
flush_dcache_range(bin_buf, bin_buf + bsize);
buf_lo = (u32)bin_buf;
buf_hi = upper_32_bits(bin_buf);
if (xilfpga_old)
ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
buf_hi, (u32)(uintptr_t)bsizeptr,
bstype, ret_payload);
else
ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
buf_hi, (u32)bsize, 0, ret_payload);
if (ret)
puts("PL FPGA LOAD fail\n");
return ret;
}
#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD)
static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize,
struct fpga_secure_info *fpga_sec_info)
{
int ret;
u32 buf_lo, buf_hi;
u32 ret_payload[PAYLOAD_ARG_CNT];
u8 flag = 0;
flush_dcache_range((ulong)buf, (ulong)buf +
ALIGN(bsize, CONFIG_SYS_CACHELINE_SIZE));
if (!fpga_sec_info->encflag)
flag |= BIT(ZYNQMP_FPGA_BIT_ENC_DEV_KEY);
if (fpga_sec_info->userkey_addr &&
fpga_sec_info->encflag == FPGA_ENC_USR_KEY) {
flush_dcache_range((ulong)fpga_sec_info->userkey_addr,
(ulong)fpga_sec_info->userkey_addr +
ALIGN(KEY_PTR_LEN,
CONFIG_SYS_CACHELINE_SIZE));
flag |= BIT(ZYNQMP_FPGA_BIT_ENC_USR_KEY);
}
if (!fpga_sec_info->authflag)
flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_OCM);
if (fpga_sec_info->authflag == ZYNQMP_FPGA_AUTH_DDR)
flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_DDR);
buf_lo = lower_32_bits((ulong)buf);
buf_hi = upper_32_bits((ulong)buf);
ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
buf_hi,
(u32)(uintptr_t)fpga_sec_info->userkey_addr,
flag, ret_payload);
if (ret)
puts("PL FPGA LOAD fail\n");
else
puts("Bitstream successfully loaded\n");
return ret;
}
#endif
static int zynqmp_pcap_info(xilinx_desc *desc)
{
int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_STATUS, 0, 0, 0,
0, ret_payload);
if (!ret)
printf("PCAP status\t0x%x\n", ret_payload[1]);
return ret;
}
struct xilinx_fpga_op zynqmp_op = {
.load = zynqmp_load,
#if defined CONFIG_CMD_FPGA_LOAD_SECURE
.loads = zynqmp_loads,
#endif
.info = zynqmp_pcap_info,
};
@@ -0,0 +1,548 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2012-2013, Xilinx, Michal Simek
*
* (C) Copyright 2012
* Joe Hershberger <joe.hershberger@ni.com>
*/
#include <common.h>
#include <console.h>
#include <cpu_func.h>
#include <asm/io.h>
#include <fs.h>
#include <zynqpl.h>
#include <linux/sizes.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000
#define DEVCFG_CTRL_PCFG_AES_EFUSE_MASK 0x00001000
#define DEVCFG_CTRL_PCAP_RATE_EN_MASK 0x02000000
#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040
#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840
#define DEVCFG_ISR_RX_FIFO_OV 0x00040000
#define DEVCFG_ISR_DMA_DONE 0x00002000
#define DEVCFG_ISR_PCFG_DONE 0x00000004
#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000
#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000
#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000
#define DEVCFG_STATUS_PCFG_INIT 0x00000010
#define DEVCFG_MCTRL_PCAP_LPBK 0x00000010
#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002
#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001
#ifndef CONFIG_SYS_FPGA_WAIT
#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
#endif
#ifndef CONFIG_SYS_FPGA_PROG_TIME
#define CONFIG_SYS_FPGA_PROG_TIME (CONFIG_SYS_HZ * 4) /* 4 s */
#endif
#define DUMMY_WORD 0xffffffff
/* Xilinx binary format header */
static const u32 bin_format[] = {
DUMMY_WORD, /* Dummy words */
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
DUMMY_WORD,
0x000000bb, /* Sync word */
0x11220044, /* Sync word */
DUMMY_WORD,
DUMMY_WORD,
0xaa995566, /* Sync word */
};
#define SWAP_NO 1
#define SWAP_DONE 2
/*
* Load the whole word from unaligned buffer
* Keep in your mind that it is byte loading on little-endian system
*/
static u32 load_word(const void *buf, u32 swap)
{
u32 word = 0;
u8 *bitc = (u8 *)buf;
int p;
if (swap == SWAP_NO) {
for (p = 0; p < 4; p++) {
word <<= 8;
word |= bitc[p];
}
} else {
for (p = 3; p >= 0; p--) {
word <<= 8;
word |= bitc[p];
}
}
return word;
}
static u32 check_header(const void *buf)
{
u32 i, pattern;
int swap = SWAP_NO;
u32 *test = (u32 *)buf;
debug("%s: Let's check bitstream header\n", __func__);
/* Checking that passing bin is not a bitstream */
for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
pattern = load_word(&test[i], swap);
/*
* Bitstreams in binary format are swapped
* compare to regular bistream.
* Do not swap dummy word but if swap is done assume
* that parsing buffer is binary format
*/
if ((__swab32(pattern) != DUMMY_WORD) &&
(__swab32(pattern) == bin_format[i])) {
pattern = __swab32(pattern);
swap = SWAP_DONE;
debug("%s: data swapped - let's swap\n", __func__);
}
debug("%s: %d/%x: pattern %x/%x bin_format\n", __func__, i,
(u32)&test[i], pattern, bin_format[i]);
if (pattern != bin_format[i]) {
debug("%s: Bitstream is not recognized\n", __func__);
return 0;
}
}
debug("%s: Found bitstream header at %x %s swapinng\n", __func__,
(u32)buf, swap == SWAP_NO ? "without" : "with");
return swap;
}
static void *check_data(u8 *buf, size_t bsize, u32 *swap)
{
u32 word, p = 0; /* possition */
/* Because buf doesn't need to be aligned let's read it by chars */
for (p = 0; p < bsize; p++) {
word = load_word(&buf[p], SWAP_NO);
debug("%s: word %x %x/%x\n", __func__, word, p, (u32)&buf[p]);
/* Find the first bitstream dummy word */
if (word == DUMMY_WORD) {
debug("%s: Found dummy word at position %x/%x\n",
__func__, p, (u32)&buf[p]);
*swap = check_header(&buf[p]);
if (*swap) {
/* FIXME add full bitstream checking here */
return &buf[p];
}
}
/* Loop can be huge - support CTRL + C */
if (ctrlc())
return NULL;
}
return NULL;
}
static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
{
unsigned long ts;
u32 isr_status;
/* Set up the transfer */
writel((u32)srcbuf, &devcfg_base->dma_src_addr);
writel(dstbuf, &devcfg_base->dma_dst_addr);
writel(srclen, &devcfg_base->dma_src_len);
writel(dstlen, &devcfg_base->dma_dst_len);
isr_status = readl(&devcfg_base->int_sts);
/* Polling the PCAP_INIT status for Set */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
debug("%s: Error: isr = 0x%08X\n", __func__,
isr_status);
debug("%s: Write count = 0x%08X\n", __func__,
readl(&devcfg_base->write_count));
debug("%s: Read count = 0x%08X\n", __func__,
readl(&devcfg_base->read_count));
return FPGA_FAIL;
}
if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
printf("%s: Timeout wait for DMA to complete\n",
__func__);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);
}
debug("%s: DMA transfer is done\n", __func__);
/* Clear out the DMA status */
writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
return FPGA_SUCCESS;
}
static int zynq_dma_xfer_init(bitstream_type bstype)
{
u32 status, control, isr_status;
unsigned long ts;
/* Clear loopback bit */
clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
if (bstype != BIT_PARTIAL) {
zynq_slcr_devcfg_disable();
/* Setting PCFG_PROG_B signal to high */
control = readl(&devcfg_base->ctrl);
writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
/*
* Delay is required if AES efuse is selected as
* key source.
*/
if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
mdelay(5);
/* Setting PCFG_PROG_B signal to low */
writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
/*
* Delay is required if AES efuse is selected as
* key source.
*/
if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
mdelay(5);
/* Polling the PCAP_INIT status for Reset */
ts = get_timer(0);
while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
printf("%s: Timeout wait for INIT to clear\n",
__func__);
return FPGA_FAIL;
}
}
/* Setting PCFG_PROG_B signal to high */
writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
/* Polling the PCAP_INIT status for Set */
ts = get_timer(0);
while (!(readl(&devcfg_base->status) &
DEVCFG_STATUS_PCFG_INIT)) {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
printf("%s: Timeout wait for INIT to set\n",
__func__);
return FPGA_FAIL;
}
}
}
isr_status = readl(&devcfg_base->int_sts);
/* Clear it all, so if Boot ROM comes back, it can proceed */
writel(0xFFFFFFFF, &devcfg_base->int_sts);
if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) {
debug("%s: Fatal errors in PCAP 0x%X\n", __func__, isr_status);
/* If RX FIFO overflow, need to flush RX FIFO first */
if (isr_status & DEVCFG_ISR_RX_FIFO_OV) {
writel(DEVCFG_MCTRL_RFIFO_FLUSH, &devcfg_base->mctrl);
writel(0xFFFFFFFF, &devcfg_base->int_sts);
}
return FPGA_FAIL;
}
status = readl(&devcfg_base->status);
debug("%s: Status = 0x%08X\n", __func__, status);
if (status & DEVCFG_STATUS_DMA_CMD_Q_F) {
debug("%s: Error: device busy\n", __func__);
return FPGA_FAIL;
}
debug("%s: Device ready\n", __func__);
if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) {
if (!(readl(&devcfg_base->int_sts) & DEVCFG_ISR_DMA_DONE)) {
/* Error state, transfer cannot occur */
debug("%s: ISR indicates error\n", __func__);
return FPGA_FAIL;
} else {
/* Clear out the status */
writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
}
}
if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) {
/* Clear the count of completed DMA transfers */
writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status);
}
return FPGA_SUCCESS;
}
static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
{
u32 *new_buf;
u32 i;
if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) {
new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN);
/*
* This might be dangerous but permits to flash if
* ARCH_DMA_MINALIGN is greater than header size
*/
if (new_buf > buf) {
debug("%s: Aligned buffer is after buffer start\n",
__func__);
new_buf -= ARCH_DMA_MINALIGN;
}
printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
(u32)buf, (u32)new_buf, swap);
for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);
buf = new_buf;
} else if (swap != SWAP_DONE) {
/* For bitstream which are aligned */
u32 *new_buf = (u32 *)buf;
printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
swap);
for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);
}
return buf;
}
static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
size_t bsize, u32 blocksize, u32 *swap,
bitstream_type *bstype)
{
u32 *buf_start;
u32 diff;
buf_start = check_data((u8 *)buf, blocksize, swap);
if (!buf_start)
return FPGA_FAIL;
/* Check if data is postpone from start */
diff = (u32)buf_start - (u32)buf;
if (diff) {
printf("%s: Bitstream is not validated yet (diff %x)\n",
__func__, diff);
return FPGA_FAIL;
}
if ((u32)buf < SZ_1M) {
printf("%s: Bitstream has to be placed up to 1MB (%x)\n",
__func__, (u32)buf);
return FPGA_FAIL;
}
if (zynq_dma_xfer_init(*bstype))
return FPGA_FAIL;
return 0;
}
static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
bitstream_type bstype)
{
unsigned long ts; /* Timestamp */
u32 isr_status, swap;
/*
* send bsize inplace of blocksize as it was not a bitstream
* in chunks
*/
if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
&bstype))
return FPGA_FAIL;
buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
debug("%s: Source = 0x%08X\n", __func__, (u32)buf);
debug("%s: Size = %zu\n", __func__, bsize);
/* flush(clean & invalidate) d-cache range buf */
flush_dcache_range((u32)buf, (u32)buf +
roundup(bsize, ARCH_DMA_MINALIGN));
if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
return FPGA_FAIL;
isr_status = readl(&devcfg_base->int_sts);
/* Check FPGA configuration completion */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
printf("%s: Timeout wait for FPGA to config\n",
__func__);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);
}
debug("%s: FPGA config done\n", __func__);
if (bstype != BIT_PARTIAL)
zynq_slcr_devcfg_enable();
puts("INFO:post config was not run, please run manually if needed\n");
return FPGA_SUCCESS;
}
#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD)
static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
fpga_fs_info *fsinfo)
{
unsigned long ts; /* Timestamp */
u32 isr_status, swap;
u32 partialbit = 0;
loff_t blocksize, actread;
loff_t pos = 0;
int fstype;
char *interface, *dev_part;
const char *filename;
blocksize = fsinfo->blocksize;
interface = fsinfo->interface;
dev_part = fsinfo->dev_part;
filename = fsinfo->filename;
fstype = fsinfo->fstype;
if (fs_set_blk_dev(interface, dev_part, fstype))
return FPGA_FAIL;
if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
return FPGA_FAIL;
if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
&partialbit))
return FPGA_FAIL;
dcache_disable();
do {
buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
if (zynq_dma_transfer((u32)buf | 1, blocksize >> 2,
0xffffffff, 0))
return FPGA_FAIL;
bsize -= blocksize;
pos += blocksize;
if (fs_set_blk_dev(interface, dev_part, fstype))
return FPGA_FAIL;
if (bsize > blocksize) {
if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
return FPGA_FAIL;
} else {
if (fs_read(filename, (u32) buf, pos, bsize, &actread) < 0)
return FPGA_FAIL;
}
} while (bsize > blocksize);
buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
return FPGA_FAIL;
dcache_enable();
isr_status = readl(&devcfg_base->int_sts);
/* Check FPGA configuration completion */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
printf("%s: Timeout wait for FPGA to config\n",
__func__);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);
}
debug("%s: FPGA config done\n", __func__);
if (!partialbit)
zynq_slcr_devcfg_enable();
return FPGA_SUCCESS;
}
#endif
struct xilinx_fpga_op zynq_op = {
.load = zynq_load,
#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD)
.loadfs = zynq_loadfs,
#endif
};
#ifdef CONFIG_CMD_ZYNQ_AES
/*
* Load the encrypted image from src addr and decrypt the image and
* place it back the decrypted image into dstaddr.
*/
int zynq_decrypt_load(u32 srcaddr, u32 srclen, u32 dstaddr, u32 dstlen)
{
if (srcaddr < SZ_1M || dstaddr < SZ_1M) {
printf("%s: src and dst addr should be > 1M\n",
__func__);
return FPGA_FAIL;
}
if (zynq_dma_xfer_init(BIT_NONE)) {
printf("%s: zynq_dma_xfer_init FAIL\n", __func__);
return FPGA_FAIL;
}
writel((readl(&devcfg_base->ctrl) | DEVCFG_CTRL_PCAP_RATE_EN_MASK),
&devcfg_base->ctrl);
debug("%s: Source = 0x%08X\n", __func__, (u32)srcaddr);
debug("%s: Size = %zu\n", __func__, srclen);
/* flush(clean & invalidate) d-cache range buf */
flush_dcache_range((u32)srcaddr, (u32)srcaddr +
roundup(srclen << 2, ARCH_DMA_MINALIGN));
/*
* Flush destination address range only if image is not
* bitstream.
*/
flush_dcache_range((u32)dstaddr, (u32)dstaddr +
roundup(dstlen << 2, ARCH_DMA_MINALIGN));
if (zynq_dma_transfer(srcaddr | 1, srclen, dstaddr | 1, dstlen))
return FPGA_FAIL;
writel((readl(&devcfg_base->ctrl) & ~DEVCFG_CTRL_PCAP_RATE_EN_MASK),
&devcfg_base->ctrl);
return FPGA_SUCCESS;
}
#endif