mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-21 01:18:52 +09:00
![Matthias Fuchs](/assets/img/avatar_default.png)
This patch adds some BSP commands and FPGA booting support for esd's PMC440 boards. Signed-off-by: Matthias Fuchs <matthias.fuchs@esd-electronics.com>
462 lines
9.5 KiB
C
462 lines
9.5 KiB
C
/*
|
|
* (C) Copyright 2007
|
|
* Matthias Fuchs, esd gmbh, matthias.fuchs@esd-electronics.com.
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <spartan2.h>
|
|
#include <spartan3.h>
|
|
#include <command.h>
|
|
#include "fpga.h"
|
|
#include "pmc440.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#if defined(CONFIG_FPGA)
|
|
|
|
#define USE_SP_CODE
|
|
|
|
#ifdef USE_SP_CODE
|
|
Xilinx_Spartan3_Slave_Parallel_fns pmc440_fpga_fns = {
|
|
fpga_pre_config_fn,
|
|
fpga_pgm_fn,
|
|
fpga_init_fn,
|
|
NULL, /* err */
|
|
fpga_done_fn,
|
|
fpga_clk_fn,
|
|
fpga_cs_fn,
|
|
fpga_wr_fn,
|
|
NULL, /* rdata */
|
|
fpga_wdata_fn,
|
|
fpga_busy_fn,
|
|
fpga_abort_fn,
|
|
fpga_post_config_fn,
|
|
};
|
|
#else
|
|
Xilinx_Spartan3_Slave_Serial_fns pmc440_fpga_fns = {
|
|
fpga_pre_config_fn,
|
|
fpga_pgm_fn,
|
|
fpga_clk_fn,
|
|
fpga_init_fn,
|
|
fpga_done_fn,
|
|
fpga_wr_fn,
|
|
fpga_post_config_fn,
|
|
};
|
|
#endif
|
|
|
|
Xilinx_Spartan2_Slave_Serial_fns ngcc_fpga_fns = {
|
|
ngcc_fpga_pre_config_fn,
|
|
ngcc_fpga_pgm_fn,
|
|
ngcc_fpga_clk_fn,
|
|
ngcc_fpga_init_fn,
|
|
ngcc_fpga_done_fn,
|
|
ngcc_fpga_wr_fn,
|
|
ngcc_fpga_post_config_fn
|
|
};
|
|
|
|
Xilinx_desc fpga[CONFIG_FPGA_COUNT] = {
|
|
XILINX_XC3S1200E_DESC(
|
|
#ifdef USE_SP_CODE
|
|
slave_parallel,
|
|
#else
|
|
slave_serial,
|
|
#endif
|
|
(void *)&pmc440_fpga_fns,
|
|
0),
|
|
XILINX_XC2S200_DESC(
|
|
slave_serial,
|
|
(void *)&ngcc_fpga_fns,
|
|
0)
|
|
};
|
|
|
|
|
|
/*
|
|
* Set the active-low FPGA reset signal.
|
|
*/
|
|
void fpga_reset(int assert)
|
|
{
|
|
debug("%s:%d: RESET ", __FUNCTION__, __LINE__);
|
|
if (assert) {
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) & ~GPIO1_FPGA_DATA);
|
|
debug("asserted\n");
|
|
} else {
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) | GPIO1_FPGA_DATA);
|
|
debug("deasserted\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize the SelectMap interface. We assume that the mode and the
|
|
* initial state of all of the port pins have already been set!
|
|
*/
|
|
void fpga_serialslave_init(void)
|
|
{
|
|
debug("%s:%d: Initialize serial slave interface\n", __FUNCTION__,
|
|
__LINE__);
|
|
fpga_pgm_fn(FALSE, FALSE, 0); /* make sure program pin is inactive */
|
|
}
|
|
|
|
|
|
/*
|
|
* Set the FPGA's active-low SelectMap program line to the specified level
|
|
*/
|
|
int fpga_pgm_fn(int assert, int flush, int cookie)
|
|
{
|
|
debug("%s:%d: FPGA PROGRAM ",
|
|
__FUNCTION__, __LINE__);
|
|
|
|
if (assert) {
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) & ~GPIO1_FPGA_PRG);
|
|
debug("asserted\n");
|
|
} else {
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) | GPIO1_FPGA_PRG);
|
|
debug("deasserted\n");
|
|
}
|
|
return assert;
|
|
}
|
|
|
|
|
|
/*
|
|
* Test the state of the active-low FPGA INIT line. Return 1 on INIT
|
|
* asserted (low).
|
|
*/
|
|
int fpga_init_fn(int cookie)
|
|
{
|
|
if (in_be32((void*)GPIO1_IR) & GPIO1_FPGA_INIT)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
#ifdef USE_SP_CODE
|
|
int fpga_abort_fn(int cookie)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
int fpga_cs_fn(int assert_cs, int flush, int cookie)
|
|
{
|
|
return assert_cs;
|
|
}
|
|
|
|
|
|
int fpga_busy_fn(int cookie)
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Test the state of the active-high FPGA DONE pin
|
|
*/
|
|
int fpga_done_fn(int cookie)
|
|
{
|
|
if (in_be32((void*)GPIO1_IR) & GPIO1_FPGA_DONE)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* FPGA pre-configuration function. Just make sure that
|
|
* FPGA reset is asserted to keep the FPGA from starting up after
|
|
* configuration.
|
|
*/
|
|
int fpga_pre_config_fn(int cookie)
|
|
{
|
|
debug("%s:%d: FPGA pre-configuration\n", __FUNCTION__, __LINE__);
|
|
fpga_reset(TRUE);
|
|
|
|
/* release init# */
|
|
out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | GPIO0_FPGA_FORCEINIT);
|
|
/* disable PLD IOs */
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) | GPIO1_IOEN_N);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* FPGA post configuration function. Blip the FPGA reset line and then see if
|
|
* the FPGA appears to be running.
|
|
*/
|
|
int fpga_post_config_fn(int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
int rc=0;
|
|
char *s;
|
|
|
|
debug("%s:%d: FPGA post configuration\n", __FUNCTION__, __LINE__);
|
|
|
|
/* enable PLD0..7 pins */
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) & ~GPIO1_IOEN_N);
|
|
|
|
fpga_reset(TRUE);
|
|
udelay (100);
|
|
fpga_reset(FALSE);
|
|
udelay (100);
|
|
|
|
FPGA_OUT32(&fpga->status, (gd->board_type << STATUS_HWREV_SHIFT) & STATUS_HWREV_MASK);
|
|
|
|
/* NGCC only: enable ledlink */
|
|
if ((s = getenv("bd_type")) && !strcmp(s, "ngcc"))
|
|
FPGA_SETBITS(&fpga->ctrla, 0x29f8c000);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
int fpga_clk_fn(int assert_clk, int flush, int cookie)
|
|
{
|
|
if (assert_clk)
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) | GPIO1_FPGA_CLK);
|
|
else
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) & ~GPIO1_FPGA_CLK);
|
|
|
|
return assert_clk;
|
|
}
|
|
|
|
|
|
int fpga_wr_fn(int assert_write, int flush, int cookie)
|
|
{
|
|
if (assert_write)
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) | GPIO1_FPGA_DATA);
|
|
else
|
|
out_be32((void*)GPIO1_OR, in_be32((void*)GPIO1_OR) & ~GPIO1_FPGA_DATA);
|
|
|
|
return assert_write;
|
|
}
|
|
|
|
#ifdef USE_SP_CODE
|
|
int fpga_wdata_fn(uchar data, int flush, int cookie)
|
|
{
|
|
uchar val = data;
|
|
ulong or = in_be32((void*)GPIO1_OR);
|
|
int i = 7;
|
|
do {
|
|
/* Write data */
|
|
if (val & 0x80)
|
|
or = (or & ~GPIO1_FPGA_CLK) | GPIO1_FPGA_DATA;
|
|
else
|
|
or = or & ~(GPIO1_FPGA_CLK | GPIO1_FPGA_DATA);
|
|
|
|
out_be32((void*)GPIO1_OR, or);
|
|
|
|
/* Assert the clock */
|
|
or |= GPIO1_FPGA_CLK;
|
|
out_be32((void*)GPIO1_OR, or);
|
|
val <<= 1;
|
|
i --;
|
|
} while (i > 0);
|
|
|
|
/* Write last data bit (the 8th clock comes from the sp_load() code */
|
|
if (val & 0x80)
|
|
or = (or & ~GPIO1_FPGA_CLK) | GPIO1_FPGA_DATA;
|
|
else
|
|
or = or & ~(GPIO1_FPGA_CLK | GPIO1_FPGA_DATA);
|
|
|
|
out_be32((void*)GPIO1_OR, or);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#define NGCC_FPGA_PRG CLOCK_EN
|
|
#define NGCC_FPGA_DATA RESET_OUT
|
|
#define NGCC_FPGA_DONE CLOCK_IN
|
|
#define NGCC_FPGA_INIT IRIGB_R_IN
|
|
#define NGCC_FPGA_CLK CLOCK_OUT
|
|
|
|
void ngcc_fpga_serialslave_init(void)
|
|
{
|
|
debug("%s:%d: Initialize serial slave interface\n",
|
|
__FUNCTION__, __LINE__);
|
|
|
|
/* make sure program pin is inactive */
|
|
ngcc_fpga_pgm_fn (FALSE, FALSE, 0);
|
|
}
|
|
|
|
/*
|
|
* Set the active-low FPGA reset signal.
|
|
*/
|
|
void ngcc_fpga_reset(int assert)
|
|
{
|
|
debug("%s:%d: RESET ", __FUNCTION__, __LINE__);
|
|
|
|
if (assert) {
|
|
FPGA_CLRBITS(NGCC_CTRL_BASE, NGCC_CTRL_FPGARST_N);
|
|
debug("asserted\n");
|
|
} else {
|
|
FPGA_SETBITS(NGCC_CTRL_BASE, NGCC_CTRL_FPGARST_N);
|
|
debug("deasserted\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Set the FPGA's active-low SelectMap program line to the specified level
|
|
*/
|
|
int ngcc_fpga_pgm_fn(int assert, int flush, int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
debug("%s:%d: FPGA PROGRAM ", __FUNCTION__, __LINE__);
|
|
|
|
if (assert) {
|
|
FPGA_CLRBITS(&fpga->ctrla, NGCC_FPGA_PRG);
|
|
debug("asserted\n");
|
|
} else {
|
|
FPGA_SETBITS(&fpga->ctrla, NGCC_FPGA_PRG);
|
|
debug("deasserted\n");
|
|
}
|
|
|
|
return assert;
|
|
}
|
|
|
|
|
|
/*
|
|
* Test the state of the active-low FPGA INIT line. Return 1 on INIT
|
|
* asserted (low).
|
|
*/
|
|
int ngcc_fpga_init_fn(int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
debug("%s:%d: INIT check... ", __FUNCTION__, __LINE__);
|
|
if (FPGA_IN32(&fpga->status) & NGCC_FPGA_INIT) {
|
|
debug("high\n");
|
|
return 0;
|
|
} else {
|
|
debug("low\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Test the state of the active-high FPGA DONE pin
|
|
*/
|
|
int ngcc_fpga_done_fn(int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
debug("%s:%d: DONE check... ", __FUNCTION__, __LINE__);
|
|
if (FPGA_IN32(&fpga->status) & NGCC_FPGA_DONE) {
|
|
debug("DONE high\n");
|
|
return 1;
|
|
} else {
|
|
debug("low\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* FPGA pre-configuration function.
|
|
*/
|
|
int ngcc_fpga_pre_config_fn(int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
debug("%s:%d: FPGA pre-configuration\n", __FUNCTION__, __LINE__);
|
|
|
|
ngcc_fpga_reset(TRUE);
|
|
FPGA_CLRBITS(&fpga->ctrla, 0xfffffe00);
|
|
|
|
ngcc_fpga_reset(TRUE);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* FPGA post configuration function. Blip the FPGA reset line and then see if
|
|
* the FPGA appears to be running.
|
|
*/
|
|
int ngcc_fpga_post_config_fn(int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
debug("%s:%d: NGCC FPGA post configuration\n", __FUNCTION__, __LINE__);
|
|
|
|
udelay (100);
|
|
ngcc_fpga_reset(FALSE);
|
|
|
|
FPGA_SETBITS(&fpga->ctrla, 0x29f8c000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ngcc_fpga_clk_fn(int assert_clk, int flush, int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
if (assert_clk)
|
|
FPGA_SETBITS(&fpga->ctrla, NGCC_FPGA_CLK);
|
|
else
|
|
FPGA_CLRBITS(&fpga->ctrla, NGCC_FPGA_CLK);
|
|
|
|
return assert_clk;
|
|
}
|
|
|
|
|
|
int ngcc_fpga_wr_fn(int assert_write, int flush, int cookie)
|
|
{
|
|
pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
|
|
|
|
if (assert_write)
|
|
FPGA_SETBITS(&fpga->ctrla, NGCC_FPGA_DATA);
|
|
else
|
|
FPGA_CLRBITS(&fpga->ctrla, NGCC_FPGA_DATA);
|
|
|
|
return assert_write;
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize the fpga. Return 1 on success, 0 on failure.
|
|
*/
|
|
int pmc440_init_fpga(void)
|
|
{
|
|
char *s;
|
|
|
|
debug("%s:%d: Initialize FPGA interface (relocation offset = 0x%.8lx)\n",
|
|
__FUNCTION__, __LINE__, gd->reloc_off);
|
|
fpga_init(gd->reloc_off);
|
|
|
|
fpga_serialslave_init ();
|
|
debug("%s:%d: Adding fpga 0\n", __FUNCTION__, __LINE__);
|
|
fpga_add (fpga_xilinx, &fpga[0]);
|
|
|
|
/* NGCC only */
|
|
if ((s = getenv("bd_type")) && !strcmp(s, "ngcc")) {
|
|
ngcc_fpga_serialslave_init ();
|
|
debug("%s:%d: Adding fpga 1\n", __FUNCTION__, __LINE__);
|
|
fpga_add (fpga_xilinx, &fpga[1]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_FPGA */
|