soc: riscv: add initial support for SiFive Freedom U740

This patch adds support for SiFive Freedom U740 SoC.
First version is minimum only using UART, SPI and L2-LIM area.

Signed-off-by: Katsuhiro Suzuki <katsuhiro@katsuster.net>
This commit is contained in:
Katsuhiro Suzuki 2021-08-22 15:54:41 +09:00 committed by Christopher Friedt
commit ca853af0b9
6 changed files with 276 additions and 1 deletions

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2021 Katsuhiro Suzuki
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <dt-bindings/gpio/gpio.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "sifive,FU740-C000", "fu740-dev", "sifive-dev";
model = "sifive,FU740";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu: cpu@0 {
compatible = "sifive,s7", "riscv";
device_type = "cpu";
reg = <0>;
riscv,isa = "rv64imac";
status = "okay";
hlic: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;
modeselect: rom@1000 {
compatible = "sifive,modeselect0";
reg = <0x1000 0x1000>;
reg-names = "mem";
};
maskrom: rom@10000 {
compatible = "sifive,maskrom0";
reg = <0x10000 0x8000>;
reg-names = "mem";
};
dtim: dtim@1000000 {
compatible = "sifive,dtim0";
reg = <0x1000000 0x2000>;
reg-names = "mem";
};
clint: clint@2000000 {
#interrupt-cells = <1>;
compatible = "riscv,clint0";
interrupt-controller;
interrupts-extended = <&hlic 3 &hlic 7>;
reg = <0x2000000 0x10000>;
reg-names = "control";
};
l2lim: l2lim@8000000 {
compatible = "sifive,l2lim0";
reg = <0x8000000 0x200000>;
reg-names = "mem";
};
plic: interrupt-controller@c000000 {
#interrupt-cells = <2>;
compatible = "sifive,plic-1.0.0";
interrupt-controller;
interrupts-extended = <&hlic 11>;
reg = <0x0c000000 0x00002000
0x0c002000 0x001fe000
0x0c200000 0x03e00000>;
reg-names = "prio", "irq_en", "reg";
riscv,max-priority = <7>;
riscv,ndev = <52>;
};
uart0: serial@10010000 {
compatible = "sifive,uart0";
interrupt-parent = <&plic>;
interrupts = <4 1>;
reg = <0x10010000 0x1000>;
reg-names = "control";
label = "uart_0";
status = "disabled";
};
uart1: serial@10011000 {
compatible = "sifive,uart0";
interrupt-parent = <&plic>;
interrupts = <5 1>;
reg = <0x10011000 0x1000>;
reg-names = "control";
label = "uart_1";
status = "disabled";
};
spi0: spi@10040000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <51 1>;
reg = <0x10040000 0x1000 0x20000000 0x10000000>;
reg-names = "control", "mem";
label = "spi_0";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
spi1: spi@10041000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <52 1>;
reg = <0x10041000 0x1000>;
reg-names = "control";
label = "spi_1";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
spi2: spi@10050000 {
compatible = "sifive,spi0";
interrupt-parent = <&plic>;
interrupts = <6 1>;
reg = <0x10050000 0x1000>;
reg-names = "control";
label = "spi_2";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
};
};

View file

@ -3,3 +3,4 @@
zephyr_sources() zephyr_sources()
zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FREEDOM fe310_clock.c) zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FREEDOM fe310_clock.c)
zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU540 fu540_clock.c) zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU540 fu540_clock.c)
zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU740 fu740_clock.c)

View file

@ -16,4 +16,9 @@ config SOC_RISCV_SIFIVE_FU540
select ATOMIC_OPERATIONS_C select ATOMIC_OPERATIONS_C
select 64BIT select 64BIT
config SOC_RISCV_SIFIVE_FU740
bool "SiFive Freedom U740 SOC implementation"
select ATOMIC_OPERATIONS_C
select 64BIT
endchoice endchoice

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 Katsuhiro Suzuki
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <init.h>
#include "fu740_prci.h"
/*
* Switch the clock source
* - core: to 1GHz PLL (CORE_PLL) from 26MHz oscilator (HFCLK)
* - peri: to 250MHz PLL (HFPCLKPLL) from HFCLK
* on the HiFive Unmatched board.
*
* Note: Valid PLL VCO range is 2400MHz to 4800MHz
*/
static int fu740_clock_init(const struct device *dev)
{
ARG_UNUSED(dev);
PRCI_REG(PRCI_COREPLLCFG) =
PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */
PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
PLL_Q(2) | /* output divider: VCO / 2^2 = 1001MHz */
PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
PLL_BYPASS(PLL_BYPASS_DISABLE) |
PLL_FSE(PLL_FSE_INTERNAL);
while ((PRCI_REG(PRCI_COREPLLCFG) & PLL_LOCK(1)) == 0)
;
/* Switch CORE_CLK to CORE_PLL from HFCLK */
PRCI_REG(PRCI_COREPLLSEL) = COREPLLSEL_SEL(COREPLLSEL_COREPLL);
PRCI_REG(PRCI_CORECLKSEL) = CLKSEL_SEL(CLKSEL_PLL);
PRCI_REG(PRCI_HFPCLKPLLCFG) =
PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */
PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
PLL_Q(4) | /* output divider: VCO / 2^4 = 250.25MHz */
PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
PLL_BYPASS(PLL_BYPASS_DISABLE) |
PLL_FSE(PLL_FSE_INTERNAL);
while ((PRCI_REG(PRCI_HFPCLKPLLCFG) & PLL_LOCK(1)) == 0)
;
/* Switch PCLK to HFPCLKPLL/2 from HFCLK/2 */
PRCI_REG(PRCI_HFPCLKPLLOUTDIV) = OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA);
PRCI_REG(PRCI_HFPCLKPLLSEL) = CLKSEL_SEL(CLKSEL_PLL);
return 0;
}
SYS_INIT(fu740_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2021 Katsuhiro Suzuki
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SIFIVE_FU740_PRCI_H
#define _SIFIVE_FU740_PRCI_H
#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i)))
#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset)
/* Register offsets */
#define PRCI_HFXOSCCFG (0x0000)
#define PRCI_COREPLLCFG (0x0004)
#define PRCI_COREPLLOUTDIV (0x0008)
#define PRCI_DDRPLLCFG (0x000c)
#define PRCI_DDRPLLOUTDIV (0x0010)
#define PRCI_GEMGXLPLLCFG (0x001c)
#define PRCI_GEMGXLPLLOUTDIV (0x0020)
#define PRCI_CORECLKSEL (0x0024)
#define PRCI_DEVICESRESETN (0x0028)
#define PRCI_CLKMUXSTATUS (0x002c)
#define PRCI_COREPLLSEL (0x0040)
#define PRCI_HFPCLKPLLCFG (0x0050)
#define PRCI_HFPCLKPLLOUTDIV (0x0054)
#define PRCI_HFPCLKPLLSEL (0x0058)
#define PLL_R(x) (((x) & 0x3f) << 0)
#define PLL_F(x) (((x) & 0x1ff) << 6)
#define PLL_Q(x) (((x) & 0x7) << 15)
#define PLL_RANGE(x) (((x) & 0x7) << 18)
#define PLL_BYPASS(x) (((x) & 0x1) << 24)
#define PLL_FSE(x) (((x) & 0x1) << 25)
#define PLL_LOCK(x) (((x) & 0x1) << 31)
#define PLL_RANGE_RESET 0
#define PLL_RANGE_0MHZ 1
#define PLL_RANGE_11MHZ 2
#define PLL_RANGE_18MHZ 3
#define PLL_RANGE_30MHZ 4
#define PLL_RANGE_50MHZ 5
#define PLL_RANGE_80MHZ 6
#define PLL_RANGE_130MHZ 7
#define PLL_BYPASS_DISABLE 0
#define PLL_BYPASS_ENABLE 1
#define PLL_FSE_INTERNAL 1
#define OUTDIV_PLLCKE(x) (((x) & 0x1) << 31)
#define OUTDIV_PLLCKE_DIS 0
#define OUTDIV_PLLCKE_ENA 1
#define CLKSEL_SEL(x) (((x) & 0x1) << 0)
#define CLKSEL_PLL 0
#define CLKSEL_HFCLK 1
#define CLKMUXSTATUS_CORECLKPLLSEL_OFF 0
#define CLKMUXSTATUS_TLCLKSEL_OFF 1
#define CLKMUXSTATUS_RTCXSEL_OFF 2
#define CLKMUXSTATUS_DDRCTRLCLKSEL_OFF 3
#define CLKMUXSTATUS_DDRPHYCLKSEL_OFF 4
#define CLKMUXSTATUS_GEMGXLCLKSEL_OFF 6
#define CLKMUXSTATUS_MAINMEMCLKSEL_OFF 7
#define COREPLLSEL_SEL(x) (((x) & 0x1) << 0)
#define COREPLLSEL_COREPLL 0
#define COREPLLSEL_DVFSCOREPLL 1
#endif /* _SIFIVE_FU740_PRCI_H */

View file

@ -35,7 +35,7 @@
#define SIFIVE_BACKUP_REG_BASE 0x10000080 #define SIFIVE_BACKUP_REG_BASE 0x10000080
#elif defined(CONFIG_SOC_RISCV_SIFIVE_FU540) #elif defined(CONFIG_SOC_RISCV_SIFIVE_FU540) || defined(CONFIG_SOC_RISCV_SIFIVE_FU740)
/* Clock controller. */ /* Clock controller. */
#define PRCI_BASE_ADDR 0x10000000 #define PRCI_BASE_ADDR 0x10000000