mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-21 17:38:51 +09:00
![Peter Tyser](/assets/img/avatar_default.png)
PPC boards are the only users of the current FPGA code which is littered with manual relocation fixups. Now that proper relocation is supported for PPC boards, remove FPGA manual relocation. Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
463 lines
9.5 KiB
C
463 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/CANDES only: enable ledlink */
|
|
if ((s = getenv("bd_type")) &&
|
|
((!strcmp(s, "ngcc")) || (!strcmp(s, "candes"))))
|
|
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\n",
|
|
__FUNCTION__, __LINE__);
|
|
fpga_init();
|
|
|
|
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 */
|