/* * (C) Copyright 2007 * Matthias Fuchs, esd gmbh, matthias.fuchs@esd-electronics.com. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #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 */