aboutsummaryrefslogtreecommitdiff
path: root/stm-fmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm-fmc.c')
-rw-r--r--stm-fmc.c149
1 files changed, 39 insertions, 110 deletions
diff --git a/stm-fmc.c b/stm-fmc.c
index 698f7af..18b6c8f 100644
--- a/stm-fmc.c
+++ b/stm-fmc.c
@@ -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;
}