diff options
Diffstat (limited to 'stm-fmc.c')
-rw-r--r-- | stm-fmc.c | 149 |
1 files changed, 39 insertions, 110 deletions
@@ -3,7 +3,9 @@ * --------- * Functions to set up and use the FMC bus. * - * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright 2015-2019 NORDUnet A/S + * Copyright 2021 The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -31,113 +33,20 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-fmc.h" static SRAM_HandleTypeDef _fmc_fpga_inst; -static HAL_StatusTypeDef _fmc_init_params(void); -static int _fmc_nwait_idle(void); - - -HAL_StatusTypeDef fmc_init(void) +void fmc_init(void) { static int initialized = 0; - - if (initialized) { - return HAL_OK; - } + if (initialized) return; initialized = 1; // configure fmc pins - fmc_init_gpio(); - - // configure fmc registers - return _fmc_init_params(); -} - - -int fmc_write_32(uint32_t addr, uint32_t *data) -{ - // calculate target fpga address - uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK); - - // write data to fpga - HAL_StatusTypeDef ok = HAL_SRAM_Write_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - - // check for error - if (ok != HAL_OK) return -1; - - // wait for transaction to complete - int wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // everything went ok - return 0; -} - - -int fmc_read_32(uint32_t addr, uint32_t *data) -{ - // calculate target fpga address - uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK); - - // perform dummy read transaction - HAL_StatusTypeDef ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - - // check for error - if (ok != HAL_OK) return -1; - - // wait for dummy transaction to complete - int wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // read data from fpga - ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - // check for error - if (ok != HAL_OK) return -1; - - // wait for read transaction to complete - wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // everything went ok - return 0; -} - - -static int _fmc_nwait_idle() -{ - int cnt; // counter - - // poll NWAIT (number of iterations is limited) - for (cnt=0; cnt<FMC_FPGA_NWAIT_MAX_POLL_TICKS; cnt++) - { - // read pin state - GPIO_PinState nwait = HAL_GPIO_ReadPin(FMC_GPIO_PORT_NWAIT, FMC_GPIO_PIN_NWAIT); - - // stop waiting if fpga is ready - if (nwait == FMC_NWAIT_IDLE) break; - } - - // check for timeout - if (cnt >= FMC_FPGA_NWAIT_MAX_POLL_TICKS) return -1; - - // ok - return 0; -} - -void fmc_init_gpio(void) -{ GPIO_InitTypeDef GPIO_InitStruct; // enable fmc clock @@ -155,7 +64,7 @@ void fmc_init_gpio(void) */ GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); fmc_af_gpio(GPIOE, GPIO_PIN_2 @@ -171,11 +80,9 @@ void fmc_init_gpio(void) | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); fmc_af_gpio(GPIOI, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10); -} + // configure fmc registers -static HAL_StatusTypeDef _fmc_init_params(void) -{ /* * fill internal fields */ @@ -210,7 +117,7 @@ static HAL_StatusTypeDef _fmc_init_params(void) _fmc_fpga_inst.Init.WrapMode = FMC_WRAP_MODE_DISABLE; // don't care in fixed latency mode - _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_DURING_WS; + _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; // allow write access to fpga _fmc_fpga_inst.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; @@ -244,18 +151,40 @@ static HAL_StatusTypeDef _fmc_init_params(void) // don't care in sync mode fmc_timing.DataSetupTime = 255; - // not needed, since nwait will be polled manually + // not needed fmc_timing.BusTurnAroundDuration = 0; - // use smallest allowed divisor for best performance - fmc_timing.CLKDivision = 2; + // use 45 MHz to match what FMC arbiter in the FPGA expects + fmc_timing.CLKDivision = 4; // 180/4 - // stm is too slow to work with min allowed 2-cycle latency - fmc_timing.DataLatency = 3; + // use 6 to match what FMC arbiter in the FPGA expects + fmc_timing.DataLatency = 6; // don't care in sync mode fmc_timing.AccessMode = FMC_ACCESS_MODE_A; // initialize fmc - return HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL); + HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL); + + // STM32 only enables FMC clock right before the very first read/write + // access. FPGA takes certain time (<= 100 us) to lock its PLL to this frequency, + // so a certain number of initial FMC transactions may be missed. One read transaction + // takes ~0.22 us (10 ticks @ 45 MHz), so doing ~500 dummy reads will make sure, that FPGA + // has already locked its PLL and is ready. Another way around is to repeatedly read + // some register that is guaranteed to have known value until reading starts returning + // correct data. + + // to prevent compiler from optimizing this away, we pretent we're calculating sum + int cyc; + uint32_t sum = 0; + volatile uint32_t part; + + for (cyc=0; cyc<500; cyc++) + { + part = *(__IO uint32_t *)FMC_FPGA_BASE_ADDR; + sum += part; + } + + // dummy write to read-only address to not let the compiler remove the above loop + *(__IO uint32_t *)FMC_FPGA_BASE_ADDR = sum; } |