Skip to content

Commit

Permalink
Merge pull request #12934 from aabadie/pr/cpu/fe310_cpu_rework
Browse files Browse the repository at this point in the history
cpu/fe310: several cleanup in implementation
  • Loading branch information
aabadie authored Jan 11, 2020
2 parents 3d1c7d8 + a953b74 commit fd248db
Show file tree
Hide file tree
Showing 14 changed files with 739 additions and 620 deletions.
93 changes: 0 additions & 93 deletions boards/hifive1/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,104 +18,14 @@
* @}
*/

#include <stdio.h>
#include <errno.h>

#include "cpu.h"
#include "board.h"
#include "periph/gpio.h"
#include "vendor/encoding.h"
#include "vendor/platform.h"
#include "vendor/prci_driver.h"

/*
* Configure the memory mapped flash for faster throughput
* to minimize interrupt latency on an I-Cache miss and refill
* from flash. Alternatively (and faster) the interrupt
* routine could be put in SRAM. The linker script supports
* code in SRAM using the ".hotcode" section.
* The flash chip on the HiFive1 is the ISSI 25LP128
* http://www.issi.com/WW/pdf/25LP128.pdf
* The maximum frequency it can run at is 133MHz in
* "Fast Read Dual I/O" mode.
* Note the updated data sheet:
* https://static.dev.sifive.com/SiFive-FE310-G000-datasheet-v1.0.4.pdf
* states "Address and write data using DQ[3] for transmission will not
* function properly." This rules out QPI for the XIP memory mapped flash.
* #define MAX_FLASH_FREQ 133000000
* On forum SiFive says "safe" operation would be 40MHz. 50MHz seems to work
* fine.
*/
#define MAX_FLASH_FREQ 50000000

/*
* CPU max is 320MHz+ according to datasheet but
* the relationship between cpu clock and spi clock is determined
* by SCKDIV. Given we're trying to achieve maximum I-cache refill
* for the flash we let MAX_FLASH_FREQ dictate the CPU clock.
*/
#define CPU_DESIRED_FREQ 200000000

/*
* The relationship between the input clock and SCK is given
* by the following formula (Fin is processor/tile-link clock):
* Fsck = Fin/(2(div + 1))
* FYI - For 320MHZ it seems to be tolerating a faster SPI clock (56MHz)
*/
#define SCKDIV ((CPU_DESIRED_FREQ - 1) / (MAX_FLASH_FREQ * 2))

/* This should work for any reasonable cpu clock value. */
#define SCKDIV_SAFE 3

/*
* By default the SPI initialized as:
* https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/spi/SPIFlash.scala
* insn.cmd.en := Bool(true)
* insn.cmd.code := Bits(0x03)
* insn.cmd.proto := SPIProtocol.Single
* insn.addr.len := UInt(3)
* insn.addr.proto := SPIProtocol.Single
* insn.pad.cnt := UInt(0)
* insn.pad.code := Bits(0)
* insn.data.proto := SPIProtocol.Single
*
* 25LP128 appears to left in post-reset default state. Boot code
* does not modify it. We change the SPI configuration here.
*/

void board_init_clock(void)
{
/* In case we are executing from QSPI, (which is quite likely) we need to
* set the QSPI clock divider appropriately before boosting the clock
* frequency. PRCI_set_hfrosctrim_for_f_cpu() tries multiple clocks
* so choose a safe value that should work for all frequencies.
*/
SPI0_REG(SPI_REG_SCKDIV) = SCKDIV_SAFE;

/* Note: The range is limited to ~100MHz and depends on PLL settings */
PRCI_set_hfrosctrim_for_f_cpu(CPU_DESIRED_FREQ, PRCI_FREQ_UNDERSHOOT);

/* begin{code-style-ignore} */
SPI0_REG(SPI_REG_FFMT) = /* setup "Fast Read Dual I/O" 1-1-2 */
SPI_INSN_CMD_EN | /* Enable memory-mapped flash */
SPI_INSN_ADDR_LEN(3) | /* 25LP128 read commands have 3 address bytes */
SPI_INSN_PAD_CNT(4) | /* 25LP128 Table 6.9 Read Dummy Cycles P4,P3=0,0 */
SPI_INSN_CMD_PROTO(SPI_PROTO_S) | /* 25LP128 Table 8.1 "Instruction */
SPI_INSN_ADDR_PROTO(SPI_PROTO_D) | /* Set" shows mode for cmd, addr, and */
SPI_INSN_DATA_PROTO(SPI_PROTO_D) | /* data protocol for given instruction */
SPI_INSN_CMD_CODE(0xbb) | /* Set the instruction to "Fast Read Dual I/O" */
SPI_INSN_PAD_CODE(0x00); /* Dummy cycle sends 0 value bits */
/* end{code-style-ignore} */

SPI0_REG(SPI_REG_SCKDIV) = SCKDIV;
}

void board_init(void)
{
/* Initialize CPU and clocks */
cpu_init();
board_init_clock();

/* Configure GPIOs for LEDs */
gpio_init(LED0_PIN, GPIO_OUT);
Expand All @@ -126,7 +36,4 @@ void board_init(void)
LED0_OFF;
LED1_OFF;
LED2_OFF;

/* Initialize newlib-nano library stubs */
nanostubs_init();
}
7 changes: 7 additions & 0 deletions boards/hifive1/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
extern "C" {
#endif

/**
* @name Xtimer configuration
* @{
*/
#define XTIMER_HZ (32768UL)
/** @} */

/**
* @name Macros for controlling the on-board LEDs
* @{
Expand Down
65 changes: 46 additions & 19 deletions boards/hifive1/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,53 @@ extern "C" {
* @name Core Clock configuration
* @{
*/
/* As defined in boards/hifive1/board.c CPU_DESIRED_FREQ **/
#define CLOCK_CORECLOCK (200000000ul)
/** @} */
#define USE_CLOCK_HFXOSC_PLL (1)
#define USE_CLOCK_HFXOSC (0)
#define USE_CLOCK_HFROSC_PLL (0)

/**
* @name Xtimer configuration
* @{
*/
#define XTIMER_DEV (0)
#define XTIMER_CHAN (0)
#define XTIMER_WIDTH (32)
#define XTIMER_HZ (32768ul)
#if USE_CLOCK_HFROSC_PLL && (USE_CLOCK_HFXOSC_PLL || USE_CLOCK_HFXOSC)
#error "Cannot use HFROSC_PLL with HFXOSC based configurations"
#endif

#if USE_CLOCK_HFXOSC_PLL && USE_CLOCK_HFXOSC
#error "Cannot use HFXOSC with HFXOSC_PLL"
#endif

#if USE_CLOCK_HFXOSC_PLL
#define CLOCK_PLL_R (1) /* Divide input clock by 2, mandatory with HFXOSC */
#define CLOCK_PLL_F (39) /* Multiply REFR by 80, e.g 2 * (39 + 1) */
#define CLOCK_PLL_Q (1) /* Divide VCO by 2, e.g 2^1 */
#define CLOCK_PLL_INPUT_CLOCK (16000000UL)
#define CLOCK_PLL_REFR (CLOCK_PLL_INPUT_CLOCK / (CLOCK_PLL_R + 1))
#define CLOCK_PLL_VCO (CLOCK_PLL_REFR * (2 * (CLOCK_PLL_F + 1)))
#define CLOCK_PLL_OUT (CLOCK_PLL_VCO / (1 << CLOCK_PLL_Q))
#define CLOCK_CORECLOCK (CLOCK_PLL_OUT) /* 320000000Hz with the values used above */

/* Check PLL settings */
#if CLOCK_PLL_REFR != 8000000
#error "Only R=2 can be used when using HFXOSC"
#endif
#if (CLOCK_PLL_VCO < 384000000) || (CLOCK_PLL_VCO > 768000000)
#error "VCO frequency must be in the range [384MHz - 768MHz], check the CLOCK_PLL_F value"
#endif
#if (CLOCK_PLL_OUT < 48000000) || (CLOCK_PLL_OUT > 384000000)
#error "PLL output frequency must be in the range [48MHz - 384MHz], check the CLOCK_PLL_Q value"
#endif

#elif USE_CLOCK_HFXOSC
#define CLOCK_CORECLOCK (16000000UL)

/*
When using HFROSC input clock, the core clock cannot be computed from settings,
call cpu_freq() to get the configured CPU frequency.
*/
#elif USE_CLOCK_HFROSC_PLL
#define CLOCK_DESIRED_FREQUENCY (320000000UL)

#else
#define CLOCK_HFROSC_TRIM (6) /* ~72000000Hz input freq */
#define CLOCK_HFROSC_DIV (1) /* Divide by 2 */
#endif
/** @} */

/**
Expand Down Expand Up @@ -85,14 +120,6 @@ static const uart_conf_t uart_config[] = {

/** @} */

/**
* @name GPIO configuration
*
* @{
*/
#define GPIO_INTR_PRIORITY (3)
/** @} */

/**
* @name PWM configuration
*
Expand Down
115 changes: 0 additions & 115 deletions boards/hifive1b/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,126 +18,14 @@
* @}
*/

#include <stdio.h>
#include <errno.h>

#include "cpu.h"
#include "board.h"
#include "periph/gpio.h"
#include "vendor/encoding.h"
#include "vendor/platform.h"
#include "vendor/prci_driver.h"

/*
* Configure the memory mapped flash for faster throughput
* to minimize interrupt latency on an I-Cache miss and refill
* from flash. Alternatively (and faster) the interrupt
* routine could be put in SRAM.
* The flash chip on the HiFive1b is the ISSI 25LP03D
* http://www.issi.com/WW/pdf/25LP-WP032D.pdf
* The maximum frequency it can run at is 115MHz in
* "Fast Read Dual I/O" mode.
* #define MAX_FLASH_FREQ 115000000
*
* FYI - Like the FE310-G000, the G002 has problems with reading flash
* faster than 50MHz
*/
#define MAX_FLASH_FREQ 50000000

/*
* CPU max is 320MHz+ according to datasheet but
* the relationship between cpu clock and spi clock is determined
* by SCKDIV. Given we're trying to achieve maximum I-cache refill
* for the flash we let MAX_FLASH_FREQ dictate the CPU clock.
*/
#define CPU_DESIRED_FREQ 320000000

/*
* The relationship between the input clock and SCK is given
* by the following formula (Fin is processor/tile-link clock):
* Fsck = Fin/(2(div + 1))
*/
#define SCKDIV ((CPU_DESIRED_FREQ - 1) / (MAX_FLASH_FREQ * 2))

/* This should work for any reasonable cpu clock value. */
#define SCKDIV_SAFE 3

/*
* By default the SPI FFMT initialized as:
* cmd_en = 1
* addr_len = 3
* cmd_code = 3
* all other fields = 0
*/

void board_init_clock(void)
{
/* In case we are executing from QSPI, (which is quite likely) we need to
* set the QSPI clock divider appropriately before boosting the clock
* frequency. PRCI_set_hfrosctrim_for_f_cpu() tries multiple clocks
* so choose a safe value that should work for all frequencies.
*/
SPI0_REG(SPI_REG_SCKDIV) = SCKDIV_SAFE;

/* Note: The range is limited to ~100MHz and depends on PLL settings */
PRCI_set_hfrosctrim_for_f_cpu(CPU_DESIRED_FREQ, PRCI_FREQ_UNDERSHOOT);

/* begin{code-style-ignore} */
SPI0_REG(SPI_REG_FFMT) = /* setup "Fast Read Dual I/O" */
SPI_INSN_CMD_EN | /* Enable memory-mapped flash */
SPI_INSN_ADDR_LEN(3) | /* 25LP03D read commands have 3 address bytes */
SPI_INSN_PAD_CNT(4) | /* 25LP03D Table 6.11 Read Dummy Cycles = 4 */
SPI_INSN_CMD_PROTO(SPI_PROTO_S) | /* 25LP03D Table 8.1 "Instruction */
SPI_INSN_ADDR_PROTO(SPI_PROTO_D) | /* Set" shows mode for cmd, addr, and */
SPI_INSN_DATA_PROTO(SPI_PROTO_D) | /* data protocol for given instruction */
SPI_INSN_CMD_CODE(0xBB) | /* Set the instruction to "Fast Read Dual I/O" */
SPI_INSN_PAD_CODE(0x00); /* Dummy cycle sends 0 value bits */
/* end{code-style-ignore} */

SPI0_REG(SPI_REG_SCKDIV) = SCKDIV;
}

__attribute__ ((section (".ramfunc")))
void board_init_flash(void)
{
/* Update the QSPI interface to adjust to the CPU speed
* This function needs to execute from the RAM
* when the QSPI interface is being reconfigured because the flash
* can't be accessed during this time
*/

/* Disable SPI flash mode */
SPI0_REG(SPI_REG_FCTRL) &= ~SPI_FCTRL_EN;

/* Enable QPI mode by sending command to flash */
SPI0_REG(SPI_REG_TXFIFO) = 0x35;

/* begin{code-style-ignore} */
SPI0_REG(SPI_REG_FFMT) = /* setup "Fast Read Quad I/O (QPI mode)" */
SPI_INSN_CMD_EN | /* Enable memory-mapped flash */
SPI_INSN_ADDR_LEN(3) | /* 25LP03D read commands have 3 address bytes */
SPI_INSN_PAD_CNT(6) | /* 25LP03D Table 6.11 Read Dummy Cycles = 6 */
SPI_INSN_CMD_PROTO(SPI_PROTO_Q) | /* 25LP03D Table 8.1 "Instruction */
SPI_INSN_ADDR_PROTO(SPI_PROTO_Q) | /* Set" shows mode for cmd, addr, and */
SPI_INSN_DATA_PROTO(SPI_PROTO_Q) | /* data protocol for given instruction */
SPI_INSN_CMD_CODE(0xEB) | /* Set the instruction to "Fast Read Quad I/O" */
SPI_INSN_PAD_CODE(0x00); /* Dummy cycle sends 0 value bits */
/* end{code-style-ignore} */

/* Re-enable SPI flash mode */
SPI0_REG(SPI_REG_FCTRL) |= SPI_FCTRL_EN;

/* Adjust the SPI clk divider for to boost flash speed */
// SPI0_REG(SPI_REG_SCKDIV) = SCKDIV;
}

void board_init(void)
{
/* Initialize CPU and clocks */
cpu_init();
board_init_clock();
// board_init_flash();

/* Configure GPIOs for LEDs */
gpio_init(LED0_PIN, GPIO_OUT);
Expand All @@ -148,7 +36,4 @@ void board_init(void)
LED0_OFF;
LED1_OFF;
LED2_OFF;

/* Initialize newlib-nano library stubs */
nanostubs_init();
}
7 changes: 7 additions & 0 deletions boards/hifive1b/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
extern "C" {
#endif

/**
* @name Xtimer configuration
* @{
*/
#define XTIMER_HZ (32768UL)
/** @} */

/**
* @name Macros for controlling the on-board LEDs
* @{
Expand Down
Loading

0 comments on commit fd248db

Please sign in to comment.