GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user