/* * init_fpga.c * * This file is part of BaS_gcc. * * BaS_gcc 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 3 of the License, or * (at your option) any later version. * * BaS_gcc 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 BaS_gcc. If not, see . * * Copyright 2010 - 2012 F. Aschwanden * Copyright 2011 - 2012 V. Riviere * Copyright 2012 M. Froeschle * */ #include "MCF5475.h" #include "sysinit.h" #include "bas_printf.h" #include "wait.h" // #define FPGA_DEBUG #if defined(FPGA_DEBUG) #define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0) #else #define dbg(format, arg...) do { ; } while (0) #endif #define FPGA_STATUS (1 << 0) #define FPGA_CLOCK (1 << 1) #define FPGA_CONFIG (1 << 2) #define FPGA_DATA0 (1 << 3) #define FPGA_CONF_DONE (1 << 5) extern uint8_t _FPGA_CONFIG[]; #define FPGA_FLASH_DATA &_FPGA_CONFIG[0] extern uint8_t _FPGA_CONFIG_SIZE[]; #define FPGA_FLASH_DATA_SIZE ((uint32_t) &_FPGA_CONFIG_SIZE[0]) #define ACP_FPGA_DATE_REG *(volatile uint32_t *)(0xF0040100) /* * flag located in processor SRAM1 that indicates that the FPGA configuration has * been loaded through the onboard JTAG interface. * init_fpga() will honour this and not overwrite config. */ extern uint32_t _FPGA_JTAG_LOADED; extern uint32_t _FPGA_JTAG_VALID; #define VALID_JTAG 0xaffeaffe void config_gpio_for_fpga_config(void) { #if defined(MACHINE_FIREBEE) /* * Configure GPIO FEC1L port directions (needed to load FPGA configuration) */ MCF_GPIO_PDDR_FEC1L = 0 | /* bit 7 = input */ 0 | /* bit 6 = input */ 0 | /* bit 5 = input */ MCF_GPIO_PDDR_FEC1L_PDDR_FEC1L4 | /* bit 4 = LED => output */ MCF_GPIO_PDDR_FEC1L_PDDR_FEC1L3 | /* bit 3 = PRG_DQ0 => output */ MCF_GPIO_PDDR_FEC1L_PDDR_FEC1L2 | /* bit 2 = FPGA_CONFIG => output */ MCF_GPIO_PDDR_FEC1L_PDDR_FEC1L1 | /* bit 1 = PRG_CLK (FPGA) => output */ 0; /* bit 0 => input */ #endif /* MACHINE_FIREBEE */ } void config_gpio_for_jtag_config(void) { /* * configure FEC1L port directions to enable external JTAG configuration download to FPGA */ MCF_GPIO_PDDR_FEC1L = 0 | MCF_GPIO_PDDR_FEC1L_PDDR_FEC1L4; /* bit 4 = LED => output */ /* all other bits = input */ /* * unfortunately, the GPIO module cannot trigger interrupts. That means CONF_DONE needs to be polled to detect * external FPGA (re)configuration and reset the system in that case. Could be done from the OS as well... */ } void show_fpga_date(void) { uint32_t date = ACP_FPGA_DATE_REG; uint8_t day = (uint8_t)(date >> 24 & 0xffL); uint8_t month = (uint8_t)(date >> 16 & 0xffL); uint16_t year = (uint16_t)(date & 0xffffL); xprintf("FPGA date: %02x/%02x/%04x (dd/mm/yyyy) \r\n", day, month, year); } /* * load FPGA */ bool init_fpga(void) { uint8_t *fpga_data; volatile int32_t time, start, end; int i; xprintf("FPGA load config...\r\n"); xprintf("_FPGA_JTAG_LOADED = 0x%x\r\n", _FPGA_JTAG_LOADED); xprintf("_FPGA_JTAG_VALID = 0x%x\r\n", _FPGA_JTAG_VALID); if (_FPGA_JTAG_LOADED == 1 && _FPGA_JTAG_VALID == VALID_JTAG) { xprintf("detected _FPGA_JTAG_LOADED flag. FPGA config skipped.\r\n"); /* reset the flag so that next boot will load config again from flash */ // _FPGA_JTAG_LOADED = 0; // _FPGA_JTAG_VALID = 0; show_fpga_date(); return true; } start = MCF_SLT0_SCNT; config_gpio_for_fpga_config(); MCF_GPIO_PODR_FEC1L &= ~FPGA_CLOCK; /* FPGA clock => low */ /* pulling FPGA_CONFIG to low resets the FPGA */ MCF_GPIO_PODR_FEC1L &= ~FPGA_CONFIG; /* FPGA config => low */ wait(10); /* give it some time to do its reset stuff */ while ((MCF_GPIO_PPDSDR_FEC1L & FPGA_STATUS) && (MCF_GPIO_PPDSDR_FEC1L & FPGA_CONF_DONE)); MCF_GPIO_PODR_FEC1L |= FPGA_CONFIG; /* pull FPGA_CONFIG high to start config cycle */ while (!(MCF_GPIO_PPDSDR_FEC1L & FPGA_STATUS)) ; /* wait until status becomes high */ /* * excerpt from an Altera configuration manual: * * The low-to-high transition of nCONFIG on the FPGA begins the configuration cycle. The * configuration cycle consists of 3 stages: reset, configuration, and initialization. * While nCONFIG is low, the device is in reset. When the device comes out of reset, * nCONFIG must be at a logic high level in order for the device to release the open-drain * nSTATUS pin. After nSTATUS is released, it is pulled high by a pull-up resistor and the FPGA * is ready to receive configuration data. Before and during configuration, all user I/O pins * are tri-stated. Stratix series, Arria series, and Cyclone series have weak pull-up resistors * on the I/O pins which are on, before and during configuration. * * To begin configuration, nCONFIG and nSTATUS must be at a logic high level. You can delay * configuration by holding the nCONFIG low. The device receives configuration data on its * DATA0 pins. Configuration data is latched into the FPGA on the rising edge of DCLK. After * the FPGA has received all configuration data successfully, it releases the CONF_DONE pin, * which is pulled high by a pull-up resistor. A low to high transition on CONF_DONE indicates * configuration is complete and initialization of the device can begin. */ const uint8_t *fpga_flash_data_end = FPGA_FLASH_DATA + FPGA_FLASH_DATA_SIZE; fpga_data = (uint8_t *) FPGA_FLASH_DATA; do { uint8_t value = *fpga_data++; for (i = 0; i < 8; i++, value >>= 1) { if (value & 1) { /* bit set -> toggle DATA0 to high */ MCF_GPIO_PODR_FEC1L |= FPGA_DATA0; } else { /* bit is cleared -> toggle DATA0 to low */ MCF_GPIO_PODR_FEC1L &= ~FPGA_DATA0; } /* toggle DCLK -> FPGA reads the bit */ MCF_GPIO_PODR_FEC1L |= FPGA_CLOCK; MCF_GPIO_PODR_FEC1L &= ~FPGA_CLOCK; } } while ((!(MCF_GPIO_PPDSDR_FEC1L & FPGA_CONF_DONE)) && (fpga_data < fpga_flash_data_end)); if (fpga_data < fpga_flash_data_end) { #ifdef _NOT_USED_ while (fpga_data++ < fpga_flash_data_end) { /* toggle a little more since it's fun ;) */ MCF_GPIO_PODR_FEC1L |= FPGA_CLOCK; MCF_GPIO_PODR_FEC1L &= ~FPGA_CLOCK; } #endif /* _NOT_USED_ */ end = MCF_SLT0_SCNT; time = (start - end) / (SYSCLK / 1000) / 1000; xprintf("finished (took %f seconds).\r\n", time / 1000.0); config_gpio_for_jtag_config(); /* * assure skipping fpga load on warm boot */ _FPGA_JTAG_LOADED = 1; _FPGA_JTAG_VALID = VALID_JTAG; xprintf("SRAM now set to FPGA load skip\r\n"); show_fpga_date(); return true; } xprintf("FAILED!\r\n"); config_gpio_for_jtag_config(); return false; }