- Add ethernet driver for StarFive JH7110 SoC
- Add ACLINT mtimer and mswi devices support
- Add Lichee PI 4A board
This commit is contained in:
Tom Rini 2023-07-12 13:10:04 -04:00
commit bf5152d010
54 changed files with 2578 additions and 188 deletions

View file

@ -1330,7 +1330,7 @@ F: doc/arch/riscv.rst
F: doc/usage/sbi.rst
F: drivers/sysreset/sysreset_sbi.c
F: drivers/timer/andes_plmt_timer.c
F: drivers/timer/sifive_clint_timer.c
F: drivers/timer/riscv_aclint_timer.c
F: tools/prelink-riscv.c
RISC-V CANAAN KENDRYTE K210

View file

@ -27,6 +27,10 @@ config TARGET_SIFIVE_UNMATCHED
config TARGET_STARFIVE_VISIONFIVE2
bool "Support StarFive VisionFive2 Board"
config TARGET_TH1520_LPI4A
bool "Support Sipeed's TH1520 Lichee PI 4A Board"
select SYS_CACHE_SHIFT_6
config TARGET_SIPEED_MAIX
bool "Support Sipeed Maix Board"
select SYS_CACHE_SHIFT_6
@ -66,6 +70,7 @@ source "board/emulation/qemu-riscv/Kconfig"
source "board/microchip/mpfs_icicle/Kconfig"
source "board/sifive/unleashed/Kconfig"
source "board/sifive/unmatched/Kconfig"
source "board/thead/th1520_lpi4a/Kconfig"
source "board/openpiton/riscv64/Kconfig"
source "board/sipeed/maix/Kconfig"
source "board/starfive/visionfive2/Kconfig"
@ -185,18 +190,22 @@ config DMA_ADDR_T_64BIT
bool
default y if 64BIT
config SIFIVE_CLINT
config RISCV_ACLINT
bool
depends on RISCV_MMODE
select REGMAP
select SYSCON
help
The SiFive CLINT block holds memory-mapped control and status registers
The RISC-V ACLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
config SPL_SIFIVE_CLINT
config SPL_RISCV_ACLINT
bool
depends on SPL_RISCV_MMODE
select SPL_REGMAP
select SPL_SYSCON
help
The SiFive CLINT block holds memory-mapped control and status registers
The RISC-V ACLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
config SIFIVE_CACHE

View file

@ -11,7 +11,7 @@ config SIFIVE_FU540
imply CPU
imply CPU_RISCV
imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SPL_SIFIVE_CLINT
imply SPL_RISCV_ACLINT
imply CMD_CPU
imply SPL_CPU
imply SPL_OPENSBI

View file

@ -11,7 +11,7 @@ config SIFIVE_FU740
imply CPU
imply CPU_RISCV
imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SPL_SIFIVE_CLINT
imply SPL_RISCV_ACLINT
imply CMD_CPU
imply SPL_CPU
imply SPL_OPENSBI

View file

@ -9,8 +9,8 @@ config GENERIC_RISCV
imply CPU
imply CPU_RISCV
imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE)
imply SIFIVE_CLINT if RISCV_MMODE
imply SPL_SIFIVE_CLINT if SPL_RISCV_MMODE
imply RISCV_ACLINT if RISCV_MMODE
imply SPL_RISCV_ACLINT if SPL_RISCV_MMODE
imply CMD_CPU
imply SPL_CPU
imply SPL_OPENSBI

View file

@ -25,4 +25,4 @@ config STARFIVE_JH7110
imply SPL_CPU
imply SPL_LOAD_FIT
imply SPL_OPENSBI
imply SPL_SIFIVE_CLINT
imply SPL_RISCV_ACLINT

View file

@ -3,19 +3,49 @@
* Copyright (C) 2022 StarFive Technology Co., Ltd.
* Author: Yanhong Wang<yanhong.wang@starfivetech.com>
*/
#include <common.h>
#include <asm/arch/eeprom.h>
#include <asm/csr.h>
#include <asm/sections.h>
#include <dm.h>
#include <linux/sizes.h>
#include <log.h>
#include <init.h>
#define CSR_U74_FEATURE_DISABLE 0x7c1
#define L2_LIM_MEM_END 0x81FFFFFUL
DECLARE_GLOBAL_DATA_PTR;
static bool check_ddr_size(phys_size_t size)
{
switch (size) {
case SZ_2:
case SZ_4:
case SZ_8:
case SZ_16:
return true;
default:
return false;
}
}
int spl_soc_init(void)
{
int ret;
struct udevice *dev;
phys_size_t size;
ret = fdtdec_setup_mem_size_base();
if (ret)
return ret;
/* Read the definition of the DDR size from eeprom, and if not,
* use the definition in DT
*/
size = (get_ddr_size_from_eeprom() >> 16) & 0xFF;
if (check_ddr_size(size))
gd->ram_size = size << 30;
/* DDR init */
ret = uclass_get_device(UCLASS_RAM, 0, &dev);

View file

@ -7,8 +7,8 @@ dtb-$(CONFIG_TARGET_OPENPITON_RISCV64) += openpiton-riscv64.dtb
dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb
dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb
dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2-v1.3b.dtb
dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2-v1.2a.dtb
dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2.dtb
dtb-$(CONFIG_TARGET_TH1520_LPI4A) += th1520-lichee-pi-4a.dtb
include $(srctree)/scripts/Makefile.dts
targets += $(dtb-y)

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2022 StarFive Technology Co., Ltd.
* Copyright (C) 2023 StarFive Technology Co., Ltd.
*/
#include "binman.dtsi"
@ -67,3 +67,40 @@
};
};
&i2c5_pins {
bootph-pre-ram;
i2c-pins {
bootph-pre-ram;
};
};
&i2c5 {
bootph-pre-ram;
eeprom@50 {
bootph-pre-ram;
};
};
&binman {
itb {
fit {
images {
fdt-1 {
description = "NAME";
load = <0x40400000>;
compression = "none";
uboot_fdt_blob: blob-ext {
filename = "u-boot.dtb";
};
};
};
configurations {
conf-1 {
fdt = "fdt-1";
};
};
};
};
};

View file

@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
/dts-v1/;
#include "jh7110-starfive-visionfive-2.dtsi"
/ {
model = "StarFive VisionFive 2 v1.2A";
compatible = "starfive,visionfive-2-v1.2a", "starfive,jh7110";
};

View file

@ -1,69 +0,0 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
#include "binman.dtsi"
#include "jh7110-u-boot.dtsi"
/ {
chosen {
bootph-pre-ram;
};
firmware {
spi0 = &qspi;
bootph-pre-ram;
};
config {
bootph-pre-ram;
u-boot,spl-payload-offset = <0x100000>;
};
memory@40000000 {
bootph-pre-ram;
};
};
&uart0 {
bootph-pre-ram;
};
&mmc0 {
bootph-pre-ram;
};
&mmc1 {
bootph-pre-ram;
};
&qspi {
bootph-pre-ram;
nor-flash@0 {
bootph-pre-ram;
};
};
&sysgpio {
bootph-pre-ram;
};
&mmc0_pins {
bootph-pre-ram;
mmc0-pins-rest {
bootph-pre-ram;
};
};
&mmc1_pins {
bootph-pre-ram;
mmc1-pins0 {
bootph-pre-ram;
};
mmc1-pins1 {
bootph-pre-ram;
};
};

View file

@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2022 StarFive Technology Co., Ltd.
* Copyright (C) 2023 StarFive Technology Co., Ltd.
*/
/dts-v1/;
#include "jh7110-starfive-visionfive-2.dtsi"
/ {
model = "StarFive VisionFive 2 v1.3B";
compatible = "starfive,visionfive-2-v1.3b", "starfive,jh7110";
};

View file

@ -17,6 +17,8 @@
i2c2 = &i2c2;
i2c5 = &i2c5;
i2c6 = &i2c6;
ethernet0 = &gmac0;
ethernet1 = &gmac1;
};
chosen {
@ -118,6 +120,12 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c5_pins>;
status = "okay";
eeprom@50 {
compatible = "atmel,24c04";
reg = <0x50>;
pagesize = <16>;
};
};
&i2c6 {
@ -317,3 +325,35 @@
assigned-clock-parents = <&osc>;
assigned-clock-rates = <0>;
};
&gmac0 {
phy-handle = <&phy0>;
phy-mode = "rgmii-id";
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
phy0: ethernet-phy@0 {
reg = <0>;
};
};
};
&gmac1 {
phy-handle = <&phy1>;
phy-mode = "rgmii-id";
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
phy1: ethernet-phy@1 {
reg = <0>;
};
};
};

View file

@ -235,6 +235,13 @@
#clock-cells = <0>;
};
stmmac_axi_setup: stmmac-axi-config {
snps,lpi_en;
snps,wr_osr_lmt = <4>;
snps,rd_osr_lmt = <4>;
snps,blen = <256 128 64 32 0 0 0>;
};
soc {
compatible = "simple-bus";
interrupt-parent = <&plic>;
@ -539,6 +546,68 @@
status = "disabled";
};
gmac0: ethernet@16030000 {
compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20";
reg = <0x0 0x16030000 0x0 0x10000>;
clocks = <&aoncrg JH7110_AONCLK_GMAC0_AXI>,
<&aoncrg JH7110_AONCLK_GMAC0_AHB>,
<&syscrg JH7110_SYSCLK_GMAC0_PTP>,
<&aoncrg JH7110_AONCLK_GMAC0_TX_INV>,
<&syscrg JH7110_SYSCLK_GMAC0_GTXC>;
clock-names = "stmmaceth", "pclk", "ptp_ref",
"tx", "gtx";
resets = <&aoncrg JH7110_AONRST_GMAC0_AXI>,
<&aoncrg JH7110_AONRST_GMAC0_AHB>;
reset-names = "stmmaceth", "ahb";
interrupts = <7>, <6>, <5>;
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
snps,multicast-filter-bins = <64>;
snps,perfect-filter-entries = <8>;
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
snps,fixed-burst;
snps,no-pbl-x8;
snps,force_thresh_dma_mode;
snps,axi-config = <&stmmac_axi_setup>;
snps,tso;
snps,en-tx-lpi-clockgating;
snps,txpbl = <16>;
snps,rxpbl = <16>;
starfive,syscon = <&aon_syscon 0xc 0x12>;
status = "disabled";
};
gmac1: ethernet@16040000 {
compatible = "starfive,jh7110-dwmac", "snps,dwmac-5.20";
reg = <0x0 0x16040000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_GMAC1_AXI>,
<&syscrg JH7110_SYSCLK_GMAC1_AHB>,
<&syscrg JH7110_SYSCLK_GMAC1_PTP>,
<&syscrg JH7110_SYSCLK_GMAC1_TX_INV>,
<&syscrg JH7110_SYSCLK_GMAC1_GTXC>;
clock-names = "stmmaceth", "pclk", "ptp_ref",
"tx", "gtx";
resets = <&syscrg JH7110_SYSRST_GMAC1_AXI>,
<&syscrg JH7110_SYSRST_GMAC1_AHB>;
reset-names = "stmmaceth", "ahb";
interrupts = <78>, <77>, <76>;
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
snps,multicast-filter-bins = <64>;
snps,perfect-filter-entries = <8>;
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
snps,fixed-burst;
snps,no-pbl-x8;
snps,force_thresh_dma_mode;
snps,axi-config = <&stmmac_axi_setup>;
snps,tso;
snps,en-tx-lpi-clockgating;
snps,txpbl = <16>;
snps,rxpbl = <16>;
starfive,syscon = <&sys_syscon 0x90 0x2>;
status = "disabled";
};
aoncrg: clock-controller@17000000 {
compatible = "starfive,jh7110-aoncrg";
reg = <0x0 0x17000000 0x0 0x10000>;

View file

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
*/
/dts-v1/;
#include "th1520.dtsi"
/ {
model = "Sipeed Lichee Module 4A";
compatible = "sipeed,lichee-module-4a", "thead,th1520";
memory@0 {
device_type = "memory";
reg = <0x0 0x00000000 0x2 0x00000000>;
};
};
&osc {
clock-frequency = <24000000>;
};
&osc_32k {
clock-frequency = <32768>;
};
&apb_clk {
clock-frequency = <62500000>;
};
&uart_sclk {
clock-frequency = <100000000>;
};

View file

@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
*/
#include "th1520-lichee-module-4a.dtsi"
/ {
model = "Sipeed Lichee Pi 4A";
compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520";
aliases {
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
gpio3 = &gpio3;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
serial3 = &uart3;
serial4 = &uart4;
serial5 = &uart5;
};
chosen {
stdout-path = "serial0:115200n8";
};
};
&uart0 {
status = "okay";
};

406
arch/riscv/dts/th1520.dtsi Normal file
View file

@ -0,0 +1,406 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Alibaba Group Holding Limited.
* Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
*/
#include <dt-bindings/interrupt-controller/irq.h>
/ {
compatible = "thead,th1520";
#address-cells = <2>;
#size-cells = <2>;
cpus: cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
c910_0: cpu@0 {
compatible = "thead,c910", "riscv";
device_type = "cpu";
riscv,isa = "rv64imafdc";
reg = <0>;
i-cache-block-size = <64>;
i-cache-size = <65536>;
i-cache-sets = <512>;
d-cache-block-size = <64>;
d-cache-size = <65536>;
d-cache-sets = <512>;
next-level-cache = <&l2_cache>;
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
c910_1: cpu@1 {
compatible = "thead,c910", "riscv";
device_type = "cpu";
riscv,isa = "rv64imafdc";
reg = <1>;
i-cache-block-size = <64>;
i-cache-size = <65536>;
i-cache-sets = <512>;
d-cache-block-size = <64>;
d-cache-size = <65536>;
d-cache-sets = <512>;
next-level-cache = <&l2_cache>;
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
c910_2: cpu@2 {
compatible = "thead,c910", "riscv";
device_type = "cpu";
riscv,isa = "rv64imafdc";
reg = <2>;
i-cache-block-size = <64>;
i-cache-size = <65536>;
i-cache-sets = <512>;
d-cache-block-size = <64>;
d-cache-size = <65536>;
d-cache-sets = <512>;
next-level-cache = <&l2_cache>;
mmu-type = "riscv,sv39";
cpu2_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
c910_3: cpu@3 {
compatible = "thead,c910", "riscv";
device_type = "cpu";
riscv,isa = "rv64imafdc";
reg = <3>;
i-cache-block-size = <64>;
i-cache-size = <65536>;
i-cache-sets = <512>;
d-cache-block-size = <64>;
d-cache-size = <65536>;
d-cache-sets = <512>;
next-level-cache = <&l2_cache>;
mmu-type = "riscv,sv39";
cpu3_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
l2_cache: l2-cache {
compatible = "cache";
cache-block-size = <64>;
cache-level = <2>;
cache-size = <1048576>;
cache-sets = <1024>;
cache-unified;
};
};
osc: oscillator {
compatible = "fixed-clock";
clock-output-names = "osc_24m";
#clock-cells = <0>;
};
osc_32k: 32k-oscillator {
compatible = "fixed-clock";
clock-output-names = "osc_32k";
#clock-cells = <0>;
};
apb_clk: apb-clk-clock {
compatible = "fixed-clock";
clock-output-names = "apb_clk";
#clock-cells = <0>;
};
uart_sclk: uart-sclk-clock {
compatible = "fixed-clock";
clock-output-names = "uart_sclk";
#clock-cells = <0>;
};
soc {
compatible = "simple-bus";
interrupt-parent = <&plic>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
plic: interrupt-controller@ffd8000000 {
compatible = "thead,th1520-plic", "thead,c900-plic";
reg = <0xff 0xd8000000 0x0 0x01000000>;
interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>,
<&cpu1_intc 11>, <&cpu1_intc 9>,
<&cpu2_intc 11>, <&cpu2_intc 9>,
<&cpu3_intc 11>, <&cpu3_intc 9>;
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
riscv,ndev = <240>;
};
clint: timer@ffdc000000 {
compatible = "thead,th1520-clint", "thead,c900-clint";
reg = <0xff 0xdc000000 0x0 0x00010000>;
interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
<&cpu1_intc 3>, <&cpu1_intc 7>,
<&cpu2_intc 3>, <&cpu2_intc 7>,
<&cpu3_intc 3>, <&cpu3_intc 7>;
};
uart0: serial@ffe7014000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xe7014000 0x0 0x100>;
interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
uart1: serial@ffe7f00000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xe7f00000 0x0 0x100>;
interrupts = <37 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
uart3: serial@ffe7f04000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xe7f04000 0x0 0x100>;
interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
gpio2: gpio@ffe7f34000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xe7f34000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
portc: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <58 IRQ_TYPE_LEVEL_HIGH>;
};
};
gpio3: gpio@ffe7f38000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xe7f38000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
portd: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <59 IRQ_TYPE_LEVEL_HIGH>;
};
};
gpio0: gpio@ffec005000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xec005000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
porta: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
};
};
gpio1: gpio@ffec006000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xec006000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
portb: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <57 IRQ_TYPE_LEVEL_HIGH>;
};
};
uart2: serial@ffec010000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xec010000 0x0 0x4000>;
interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
timer0: timer@ffefc32000 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xefc32000 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer1: timer@ffefc32014 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xefc32014 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer2: timer@ffefc32028 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xefc32028 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <18 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer3: timer@ffefc3203c {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xefc3203c 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
uart4: serial@fff7f08000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xf7f08000 0x0 0x4000>;
interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
uart5: serial@fff7f0c000 {
compatible = "snps,dw-apb-uart";
reg = <0xff 0xf7f0c000 0x0 0x4000>;
interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_sclk>;
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
};
timer4: timer@ffffc33000 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xffc33000 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer5: timer@ffffc33014 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xffc33014 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer6: timer@ffffc33028 {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xffc33028 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
timer7: timer@ffffc3303c {
compatible = "snps,dw-apb-timer";
reg = <0xff 0xffc3303c 0x0 0x14>;
clocks = <&apb_clk>;
clock-names = "timer";
interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
ao_gpio0: gpio@fffff41000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xfff41000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
porte: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <76 IRQ_TYPE_LEVEL_HIGH>;
};
};
ao_gpio1: gpio@fffff52000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff 0xfff52000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
portf: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
};
};
};
};

View file

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
* Author: Yanhong Wang<yanhong.wang@starfivetech.com>
*/
#ifndef _ASM_RISCV_EEPROM_H
#define _ASM_RISCV_EEPROM_H
u8 get_pcb_revision_from_eeprom(void);
u32 get_ddr_size_from_eeprom(void);
#endif /* _ASM_RISCV_EEPROM_H */

View file

@ -18,8 +18,8 @@
struct arch_global_data {
long boot_hart; /* boot hart id */
phys_addr_t firmware_fdt_addr;
#if CONFIG_IS_ENABLED(SIFIVE_CLINT)
void __iomem *clint; /* clint base address */
#if CONFIG_IS_ENABLED(RISCV_ACLINT)
void __iomem *aclint; /* aclint base address */
#endif
#ifdef CONFIG_ANDES_PLICSW
void __iomem *plicsw; /* andes plicsw base address */

View file

@ -12,7 +12,7 @@
*/
enum {
RISCV_NONE,
RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
RISCV_SYSCON_ACLINT, /* Advanced Core Local Interruptor (ACLINT) */
RISCV_SYSCON_PLICSW, /* Andes PLICSW */
};

View file

@ -12,7 +12,7 @@ obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
obj-$(CONFIG_SIFIVE_CACHE) += sifive_cache.o
ifeq ($(CONFIG_$(SPL_)RISCV_MMODE),y)
obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint.o
obj-$(CONFIG_$(SPL_)RISCV_ACLINT) += aclint_ipi.o
obj-$(CONFIG_ANDES_PLICSW) += andes_plicsw.o
else
obj-$(CONFIG_SBI) += sbi.o

View file

@ -10,9 +10,12 @@
#include <common.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/syscon.h>
#include <linux/err.h>
/* MSIP registers */
@ -26,12 +29,16 @@ int riscv_init_ipi(void)
struct udevice *dev;
ret = uclass_get_device_by_driver(UCLASS_TIMER,
DM_DRIVER_GET(sifive_clint), &dev);
DM_DRIVER_GET(riscv_aclint_timer), &dev);
if (ret)
return ret;
gd->arch.clint = dev_read_addr_ptr(dev);
if (!gd->arch.clint)
if (dev_get_driver_data(dev) != 0)
gd->arch.aclint = dev_read_addr_ptr(dev);
else
gd->arch.aclint = syscon_get_first_range(RISCV_SYSCON_ACLINT);
if (!gd->arch.aclint)
return -EINVAL;
return 0;
@ -39,21 +46,33 @@ int riscv_init_ipi(void)
int riscv_send_ipi(int hart)
{
writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
writel(1, (void __iomem *)MSIP_REG(gd->arch.aclint, hart));
return 0;
}
int riscv_clear_ipi(int hart)
{
writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
writel(0, (void __iomem *)MSIP_REG(gd->arch.aclint, hart));
return 0;
}
int riscv_get_ipi(int hart, int *pending)
{
*pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
*pending = readl((void __iomem *)MSIP_REG(gd->arch.aclint, hart));
return 0;
}
static const struct udevice_id riscv_aclint_swi_ids[] = {
{ .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_ACLINT },
{ }
};
U_BOOT_DRIVER(riscv_aclint_swi) = {
.name = "riscv_aclint_swi",
.id = UCLASS_SYSCON,
.of_match = riscv_aclint_swi_ids,
.flags = DM_FLAG_PRE_RELOC,
};

View file

@ -29,7 +29,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
select SUPPORT_SPL
imply CPU_RISCV
imply RISCV_TIMER
imply SPL_SIFIVE_CLINT
imply SPL_RISCV_ACLINT
imply CMD_CPU
imply SPL_CPU_SUPPORT
imply SPL_SMP

View file

@ -34,7 +34,7 @@ config BOARD_SPECIFIC_OPTIONS
imply SMP
imply DM_SERIAL
imply SIFIVE_SERIAL
imply SIFIVE_CLINT
imply RISCV_ACLINT
imply POWER_DOMAIN
imply SIMPLE_PM_BUS
imply CLK_K210

View file

@ -5,3 +5,4 @@
obj-y := starfive_visionfive2.o
obj-$(CONFIG_SPL_BUILD) += spl.o
obj-$(CONFIG_ID_EEPROM) += visionfive2-i2c-eeprom.o

View file

@ -5,16 +5,173 @@
*/
#include <common.h>
#include <asm/arch/eeprom.h>
#include <asm/arch/regs.h>
#include <asm/arch/spl.h>
#include <asm/io.h>
#include <dt-bindings/clock/starfive,jh7110-crg.h>
#include <fdt_support.h>
#include <linux/libfdt.h>
#include <log.h>
#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
#define JH7110_CLK_CPU_ROOT_OFFSET 0x0U
#define JH7110_CLK_CPU_ROOT_SHIFT 24
#define JH7110_CLK_CPU_ROOT_MASK GENMASK(29, 24)
struct starfive_vf2_pro {
const char *path;
const char *name;
const char *value;
};
static const struct starfive_vf2_pro starfive_vera[] = {
{"/soc/ethernet@16030000/mdio/ethernet-phy@0", "rx-internal-delay-ps",
"1900"},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0", "tx-internal-delay-ps",
"1350"}
};
static const struct starfive_vf2_pro starfive_verb[] = {
{"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL},
{"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
"motorcomm,tx-clk-adj-enabled", NULL},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
"motorcomm,tx-clk-100-inverted", NULL},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
"motorcomm,tx-clk-1000-inverted", NULL},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
"rx-internal-delay-ps", "1900"},
{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
"tx-internal-delay-ps", "1500"},
{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
"motorcomm,tx-clk-adj-enabled", NULL},
{ "/soc/ethernet@16040000/mdio/ethernet-phy@1",
"motorcomm,tx-clk-100-inverted", NULL},
{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
"rx-internal-delay-ps", "0"},
{"/soc/ethernet@16040000/mdio/ethernet-phy@1",
"tx-internal-delay-ps", "0"},
};
void spl_fdt_fixup_version_a(void *fdt)
{
u32 phandle;
u8 i;
int offset;
int ret;
fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
"StarFive VisionFive 2 v1.2A");
offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000");
phandle = fdt_get_phandle(fdt, offset);
offset = fdt_path_offset(fdt, "/soc/ethernet@16040000");
fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX);
fdt_appendprop_u32(fdt, offset, "assigned-clocks", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_RX);
fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clock-parents",
JH7110_SYSCLK_GMAC1_RMII_RTX);
fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clock-parents",
JH7110_SYSCLK_GMAC1_RMII_RTX);
fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"),
"phy-mode", "rmii");
for (i = 0; i < ARRAY_SIZE(starfive_vera); i++) {
offset = fdt_path_offset(fdt, starfive_vera[i].path);
if (starfive_vera[i].value)
ret = fdt_setprop_u32(fdt, offset, starfive_vera[i].name,
dectoul(starfive_vera[i].value, NULL));
else
ret = fdt_setprop_empty(fdt, offset, starfive_vera[i].name);
if (ret) {
pr_err("%s set prop %s fail.\n", __func__, starfive_vera[i].name);
break;
}
}
}
void spl_fdt_fixup_version_b(void *fdt)
{
u32 phandle;
u8 i;
int offset;
int ret;
fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
"StarFive VisionFive 2 v1.3B");
/* gmac0 */
offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000");
phandle = fdt_get_phandle(fdt, offset);
offset = fdt_path_offset(fdt, "/soc/ethernet@16030000");
fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX);
fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clock-parents",
JH7110_AONCLK_GMAC0_RMII_RTX);
/* gmac1 */
offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000");
phandle = fdt_get_phandle(fdt, offset);
offset = fdt_path_offset(fdt, "/soc/ethernet@16040000");
fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX);
fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle);
fdt_appendprop_u32(fdt, offset, "assigned-clock-parents",
JH7110_SYSCLK_GMAC1_RMII_RTX);
for (i = 0; i < ARRAY_SIZE(starfive_verb); i++) {
offset = fdt_path_offset(fdt, starfive_verb[i].path);
if (starfive_verb[i].value)
ret = fdt_setprop_u32(fdt, offset, starfive_verb[i].name,
dectoul(starfive_verb[i].value, NULL));
else
ret = fdt_setprop_empty(fdt, offset, starfive_verb[i].name);
if (ret) {
pr_err("%s set prop %s fail.\n", __func__, starfive_verb[i].name);
break;
}
}
}
void spl_perform_fixups(struct spl_image_info *spl_image)
{
u8 version;
version = get_pcb_revision_from_eeprom();
switch (version) {
case 'a':
case 'A':
spl_fdt_fixup_version_a(spl_image->fdt_addr);
break;
case 'b':
case 'B':
default:
spl_fdt_fixup_version_b(spl_image->fdt_addr);
break;
};
/* Update the memory size which read form eeprom or DT */
fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size);
}
int spl_board_init_f(void)
{
int ret;

View file

@ -6,7 +6,9 @@
#include <common.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <cpu_func.h>
#include <dm.h>
#include <linux/bitops.h>
#define JH7110_L2_PREFETCHER_BASE_ADDR 0x2030000
@ -38,3 +40,14 @@ int board_init(void)
return 0;
}
void *board_fdt_blob_setup(int *err)
{
*err = 0;
if (IS_ENABLED(CONFIG_OF_SEPARATE) || IS_ENABLED(CONFIG_OF_BOARD)) {
if (gd->arch.firmware_fdt_addr)
return (ulong *)(uintptr_t)gd->arch.firmware_fdt_addr;
}
return (ulong *)&_end;
}

View file

@ -0,0 +1,561 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
* Author: Yanhong Wang<yanhong.wang@starfivetech.com>
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <i2c.h>
#include <init.h>
#include <u-boot/crc.h>
#include <linux/delay.h>
#define FORMAT_VERSION 0x2
#define PCB_VERSION 0xB1
#define BOM_VERSION 'A'
/*
* BYTES_PER_EEPROM_PAGE: the 24FC04H datasheet says that data can
* only be written in page mode, which means 16 bytes at a time:
* 16-Byte Page Write Buffer
*/
#define BYTES_PER_EEPROM_PAGE 16
/*
* EEPROM_WRITE_DELAY_MS: the 24FC04H datasheet says it takes up to
* 5ms to complete a given write:
* Write Cycle Time (byte or page) ro Page Write Time 5 ms, Maximum
*/
#define EEPROM_WRITE_DELAY_MS 5000
/*
* StarFive OUI. Registration Date is 20xx-xx-xx
*/
#define STARFIVE_OUI_PREFIX "6C:CF:39:"
#define STARFIVE_DEFAULT_MAC0 "6C:CF:39:6C:DE:AD"
#define STARFIVE_DEFAULT_MAC1 "6C:CF:39:6C:DE:AE"
/* Magic number at the first four bytes of EEPROM HATs */
#define STARFIVE_EEPROM_HATS_SIG "SFVF" /* StarFive VisionFive */
#define STARFIVE_EEPROM_HATS_SIZE_MAX 256 /* Header + Atom1&4(v1) */
#define STARFIVE_EEPROM_WP_OFFSET 0 /* Read only field */
#define STARFIVE_EEPROM_ATOM1_PSTR "VF7110A1-2228-D008E000-00000001\0"
#define STARFIVE_EEPROM_ATOM1_PSTR_SIZE 32
#define STARFIVE_EEPROM_ATOM1_SN_OFFSET 23
#define STARFIVE_EEPROM_ATOM1_VSTR "StarFive Technology Co., Ltd.\0\0\0"
#define STARFIVE_EEPROM_ATOM1_VSTR_SIZE 32
#define MAGIC_NUMBER_BYTES 4
#define MAC_ADDR_BYTES 6
#define MAC_ADDR_STRLEN 17
/*
* Atom Types
* 0x0000 = invalid
* 0x0001 = vendor info
* 0x0002 = GPIO map
* 0x0003 = Linux device tree blob
* 0x0004 = manufacturer custom data
* 0x0005-0xfffe = reserved for future use
* 0xffff = invalid
*/
#define HATS_ATOM_INVALID 0x0000
#define HATS_ATOM_VENDOR 0x0001
#define HATS_ATOM_GPIO 0x0002
#define HATS_ATOM_DTB 0x0003
#define HATS_ATOM_CUSTOM 0x0004
#define HATS_ATOM_INVALID_END 0xffff
struct eeprom_header {
char signature[MAGIC_NUMBER_BYTES]; /* ASCII table signature */
u8 version; /* EEPROM data format version */
/* (0x00 reserved, 0x01 = first version) */
u8 reversed; /* 0x00, Reserved field */
u16 numatoms; /* total atoms in EEPROM */
u32 eeplen; /* total length in bytes of all eeprom data */
/* (including this header) */
};
struct eeprom_atom_header {
u16 type;
u16 count;
u32 dlen;
};
struct eeprom_atom1_data {
u8 uuid[16];
u16 pid;
u16 pver;
u8 vslen;
u8 pslen;
uchar vstr[STARFIVE_EEPROM_ATOM1_VSTR_SIZE];
uchar pstr[STARFIVE_EEPROM_ATOM1_PSTR_SIZE]; /* product SN */
};
struct starfive_eeprom_atom1 {
struct eeprom_atom_header header;
struct eeprom_atom1_data data;
u16 crc;
};
struct eeprom_atom4_data {
u16 version;
u8 pcb_revision; /* PCB version */
u8 bom_revision; /* BOM version */
u8 mac0_addr[MAC_ADDR_BYTES]; /* Ethernet0 MAC */
u8 mac1_addr[MAC_ADDR_BYTES]; /* Ethernet1 MAC */
u8 reserved[2];
};
struct starfive_eeprom_atom4 {
struct eeprom_atom_header header;
struct eeprom_atom4_data data;
u16 crc;
};
struct starfive_eeprom {
struct eeprom_header header;
struct starfive_eeprom_atom1 atom1;
struct starfive_eeprom_atom4 atom4;
};
static union {
struct starfive_eeprom eeprom;
uchar buf[STARFIVE_EEPROM_HATS_SIZE_MAX];
} pbuf __section(".data");
/* Set to 1 if we've read EEPROM into memory */
static int has_been_read __section(".data");
static inline int is_match_magic(void)
{
return strncmp(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG,
MAGIC_NUMBER_BYTES);
}
/* Calculate the current CRC */
static inline u32 calculate_crc16(struct eeprom_atom_header *head)
{
uint len = sizeof(struct eeprom_atom_header) + head->dlen - sizeof(u16);
return crc16(0, (void *)head, len);
}
/* This function should be called after each update to the EEPROM structure */
static inline void update_crc(void)
{
pbuf.eeprom.atom1.crc = calculate_crc16(&pbuf.eeprom.atom1.header);
pbuf.eeprom.atom4.crc = calculate_crc16(&pbuf.eeprom.atom4.header);
}
static void dump_raw_eeprom(void)
{
unsigned int i;
u32 len;
len = sizeof(struct starfive_eeprom);
for (i = 0; i < len; i++) {
if ((i % 16) == 0)
printf("%02X: ", i);
printf("%02X ", ((u8 *)pbuf.buf)[i]);
if (((i % 16) == 15) || (i == len - 1))
printf("\n");
}
}
/**
* show_eeprom - display the contents of the EEPROM
*/
static void show_eeprom(void)
{
if (has_been_read != 1)
return;
printf("\n--------EEPROM INFO--------\n");
printf("Vendor : %s\n", pbuf.eeprom.atom1.data.vstr);
printf("Product full SN: %s\n", pbuf.eeprom.atom1.data.pstr);
printf("data version: 0x%x\n", pbuf.eeprom.atom4.data.version);
if (pbuf.eeprom.atom4.data.version == 2) {
printf("PCB revision: 0x%x\n", pbuf.eeprom.atom4.data.pcb_revision);
printf("BOM revision: %c\n", pbuf.eeprom.atom4.data.bom_revision);
printf("Ethernet MAC0 address: %02x:%02x:%02x:%02x:%02x:%02x\n",
pbuf.eeprom.atom4.data.mac0_addr[0], pbuf.eeprom.atom4.data.mac0_addr[1],
pbuf.eeprom.atom4.data.mac0_addr[2], pbuf.eeprom.atom4.data.mac0_addr[3],
pbuf.eeprom.atom4.data.mac0_addr[4], pbuf.eeprom.atom4.data.mac0_addr[5]);
printf("Ethernet MAC1 address: %02x:%02x:%02x:%02x:%02x:%02x\n",
pbuf.eeprom.atom4.data.mac1_addr[0], pbuf.eeprom.atom4.data.mac1_addr[1],
pbuf.eeprom.atom4.data.mac1_addr[2], pbuf.eeprom.atom4.data.mac1_addr[3],
pbuf.eeprom.atom4.data.mac1_addr[4], pbuf.eeprom.atom4.data.mac1_addr[5]);
} else {
printf("Custom data v%d is not Supported\n", pbuf.eeprom.atom4.data.version);
}
printf("--------EEPROM INFO--------\n\n");
}
/**
* set_mac_address() - stores a MAC address into the local EEPROM copy
*
* This function takes a pointer to MAC address string
* (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number),
* stores it in the MAC address field of the EEPROM local copy, and
* updates the local copy of the CRC.
*/
static void set_mac_address(char *string, int index)
{
u8 i;
u8 *mac;
if (strncasecmp(STARFIVE_OUI_PREFIX, string,
strlen(STARFIVE_OUI_PREFIX))) {
printf("The MAC address doesn't match StarFive OUI %s\n",
STARFIVE_OUI_PREFIX);
return;
}
mac = (index == 0) ? pbuf.eeprom.atom4.data.mac0_addr :
pbuf.eeprom.atom4.data.mac1_addr;
for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) {
mac[i] = hextoul(string, &string);
if (*string == ':')
string++;
}
update_crc();
}
/**
* init_local_copy() - initialize the in-memory EEPROM copy
*
* Initialize the in-memory EEPROM copy with the magic number. Must
* be done when preparing to initialize a blank EEPROM, or overwrite
* one with a corrupted magic number.
*/
static void init_local_copy(void)
{
memset((void *)pbuf.buf, 0, sizeof(struct starfive_eeprom));
memcpy(pbuf.eeprom.header.signature, STARFIVE_EEPROM_HATS_SIG,
strlen(STARFIVE_EEPROM_HATS_SIG));
pbuf.eeprom.header.version = FORMAT_VERSION;
pbuf.eeprom.header.numatoms = 2;
pbuf.eeprom.header.eeplen = sizeof(struct starfive_eeprom);
pbuf.eeprom.atom1.header.type = HATS_ATOM_VENDOR;
pbuf.eeprom.atom1.header.count = 1;
pbuf.eeprom.atom1.header.dlen = sizeof(struct eeprom_atom1_data) + sizeof(u16);
pbuf.eeprom.atom1.data.vslen = STARFIVE_EEPROM_ATOM1_VSTR_SIZE;
pbuf.eeprom.atom1.data.pslen = STARFIVE_EEPROM_ATOM1_PSTR_SIZE;
memcpy(pbuf.eeprom.atom1.data.vstr, STARFIVE_EEPROM_ATOM1_VSTR,
strlen(STARFIVE_EEPROM_ATOM1_VSTR));
memcpy(pbuf.eeprom.atom1.data.pstr, STARFIVE_EEPROM_ATOM1_PSTR,
strlen(STARFIVE_EEPROM_ATOM1_PSTR));
pbuf.eeprom.atom4.header.type = HATS_ATOM_CUSTOM;
pbuf.eeprom.atom4.header.count = 2;
pbuf.eeprom.atom4.header.dlen = sizeof(struct eeprom_atom4_data) + sizeof(u16);
pbuf.eeprom.atom4.data.version = FORMAT_VERSION;
pbuf.eeprom.atom4.data.pcb_revision = PCB_VERSION;
pbuf.eeprom.atom4.data.bom_revision = BOM_VERSION;
set_mac_address(STARFIVE_DEFAULT_MAC0, 0);
set_mac_address(STARFIVE_DEFAULT_MAC1, 1);
}
/**
* prog_eeprom() - write the EEPROM from memory
*/
static int prog_eeprom(unsigned int size)
{
unsigned int i;
void *p;
uchar tmp_buff[STARFIVE_EEPROM_HATS_SIZE_MAX];
struct udevice *dev;
int ret;
if (is_match_magic()) {
printf("MAGIC ERROR, Please check the data@%p.\n", pbuf.buf);
return -1;
}
ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
CONFIG_SYS_I2C_EEPROM_ADDR,
CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
&dev);
if (ret) {
printf("Get i2c bus:%d addr:%d fail.\n", CONFIG_SYS_EEPROM_BUS_NUM,
CONFIG_SYS_I2C_EEPROM_ADDR);
return ret;
}
for (i = 0, p = (u8 *)pbuf.buf; i < size; ) {
if (!ret)
ret = dm_i2c_write(dev, i, p, min((int)(size - i),
BYTES_PER_EEPROM_PAGE));
if (ret)
break;
udelay(EEPROM_WRITE_DELAY_MS);
i += BYTES_PER_EEPROM_PAGE;
p += BYTES_PER_EEPROM_PAGE;
}
if (!ret) {
/* Verify the write by reading back the EEPROM and comparing */
ret = dm_i2c_read(dev,
STARFIVE_EEPROM_WP_OFFSET,
tmp_buff,
STARFIVE_EEPROM_HATS_SIZE_MAX);
if (!ret && memcmp((void *)pbuf.buf, (void *)tmp_buff,
STARFIVE_EEPROM_HATS_SIZE_MAX))
ret = -1;
}
if (ret) {
has_been_read = -1;
printf("Programming failed.\n");
return -1;
}
printf("Programming passed.\n");
return 0;
}
/**
* read_eeprom() - read the EEPROM into memory, if it hasn't been read already
*/
static int read_eeprom(void)
{
int ret;
struct udevice *dev;
if (has_been_read == 1)
return 0;
ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
CONFIG_SYS_I2C_EEPROM_ADDR, 1, &dev);
if (!ret)
ret = dm_i2c_read(dev, 0, (u8 *)pbuf.buf,
STARFIVE_EEPROM_HATS_SIZE_MAX);
has_been_read = (ret == 0) ? 1 : 0;
return ret;
}
/**
* set_pcb_revision() - stores a StarFive PCB revision into the local EEPROM copy
*
* Takes a pointer to a string representing the numeric PCB revision in
* decimal ("0" - "255"), stores it in the pcb_revision field of the
* EEPROM local copy, and updates the CRC of the local copy.
*/
static void set_pcb_revision(char *string)
{
u32 p;
p = simple_strtoul(string, &string, 16);
if (p > U8_MAX) {
printf("%s must not be greater than %d\n", "PCB revision",
U8_MAX);
return;
}
pbuf.eeprom.atom4.data.pcb_revision = p;
update_crc();
}
/**
* set_bom_revision() - stores a StarFive BOM revision into the local EEPROM copy
*
* Takes a pointer to a uppercase ASCII character representing the BOM
* revision ("A" - "Z"), stores it in the bom_revision field of the
* EEPROM local copy, and updates the CRC of the local copy.
*/
static void set_bom_revision(char *string)
{
if (string[0] < 'A' || string[0] > 'Z') {
printf("BOM revision must be an uppercase letter between A and Z\n");
return;
}
pbuf.eeprom.atom4.data.bom_revision = string[0];
update_crc();
}
/**
* set_product_id() - stores a StarFive product ID into the local EEPROM copy
*
* Takes a pointer to a string representing the numeric product ID in
* string ("VF7100A1-2150-D008E000-00000001\0"), stores it in the product string
* field of the EEPROM local copy, and updates the CRC of the local copy.
*/
static void set_product_id(char *string)
{
u32 len;
len = (strlen(string) > STARFIVE_EEPROM_ATOM1_PSTR_SIZE) ?
STARFIVE_EEPROM_ATOM1_PSTR_SIZE : strlen(string);
memcpy((void *)pbuf.eeprom.atom1.data.pstr, (void *)string, len);
update_crc();
}
static int print_usage(void)
{
printf("display and program the system ID and MAC addresses in EEPROM\n"
"[read_eeprom|initialize|write_eeprom|mac_address|pcb_revision|bom_revision|product_id]\n"
"mac read_eeprom\n"
" - read EEPROM content into memory data structure\n"
"mac write_eeprom\n"
" - save memory data structure to the EEPROM\n"
"mac initialize\n"
" - initialize the in-memory EEPROM copy with default data\n"
"mac mac0_address <xx:xx:xx:xx:xx:xx>\n"
" - stores a MAC0 address into the local EEPROM copy\n"
"mac mac1_address <xx:xx:xx:xx:xx:xx>\n"
" - stores a MAC1 address into the local EEPROM copy\n"
"mac pcb_revision <?>\n"
" - stores a StarFive PCB revision into the local EEPROM copy\n"
"mac bom_revision <A>\n"
" - stores a StarFive BOM revision into the local EEPROM copy\n"
"mac product_id <VF7110A1-2228-D008E000-xxxxxxxx>\n"
" - stores a StarFive product ID into the local EEPROM copy\n");
return 0;
}
int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *cmd;
if (argc == 1) {
show_eeprom();
return 0;
}
if (argc > 3)
return print_usage();
cmd = argv[1];
/* Commands with no argument */
if (!strcmp(cmd, "read_eeprom")) {
has_been_read = 0;
return read_eeprom();
} else if (!strcmp(cmd, "initialize")) {
init_local_copy();
return 0;
} else if (!strcmp(cmd, "write_eeprom")) {
return prog_eeprom(STARFIVE_EEPROM_HATS_SIZE_MAX);
}
if (argc != 3)
return print_usage();
if (is_match_magic()) {
printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
return 0;
}
if (!strcmp(cmd, "mac0_address")) {
set_mac_address(argv[2], 0);
return 0;
} else if (!strcmp(cmd, "mac1_address")) {
set_mac_address(argv[2], 1);
return 0;
} else if (!strcmp(cmd, "pcb_revision")) {
set_pcb_revision(argv[2]);
return 0;
} else if (!strcmp(cmd, "bom_revision")) {
set_bom_revision(argv[2]);
return 0;
} else if (!strcmp(cmd, "product_id")) {
set_product_id(argv[2]);
return 0;
}
return print_usage();
}
/**
* mac_read_from_eeprom() - read the MAC address & the serial number in EEPROM
*
* This function reads the MAC address and the serial number from EEPROM and
* sets the appropriate environment variables for each one read.
*
* The environment variables are only set if they haven't been set already.
* This ensures that any user-saved variables are never overwritten.
*
* If CONFIG_ID_EEPROM is enabled, this function will be called in
* "static init_fnc_t init_sequence_r[]" of u-boot/common/board_r.c.
*/
int mac_read_from_eeprom(void)
{
/**
* try to fill the buff from EEPROM,
* always return SUCCESS, even some error happens.
*/
if (read_eeprom()) {
dump_raw_eeprom();
return 0;
}
// 1, setup ethaddr env
eth_env_set_enetaddr("eth0addr", pbuf.eeprom.atom4.data.mac0_addr);
eth_env_set_enetaddr("eth1addr", pbuf.eeprom.atom4.data.mac1_addr);
/**
* 2, setup serial# env, reference to hifive-platform-i2c-eeprom.c,
* serial# can be a ASCII string, but not just a hex number, so we
* setup serial# in the 32Byte format:
* "VF7100A1-2201-D008E000-00000001;"
* "<product>-<date>-<DDR&eMMC>-<serial_number>"
* <date>: 4Byte, should be the output of `date +%y%W`
* <DDR&eMMC>: 8Byte, "D008" means 8GB, "D01T" means 1TB;
* "E000" means no eMMC"E032" means 32GB, "E01T" means 1TB.
* <serial_number>: 8Byte, the Unique Identifier of board in hex.
*/
if (!env_get("serial#"))
env_set("serial#", pbuf.eeprom.atom1.data.pstr);
printf("StarFive EEPROM format v%u\n", pbuf.eeprom.header.version);
show_eeprom();
return 0;
}
/**
* get_pcb_revision_from_eeprom - get the PCB revision
*
* 1.2A return 'A'/'a', 1.3B return 'B'/'b',other values are illegal
*/
u8 get_pcb_revision_from_eeprom(void)
{
u8 pv = 0xFF;
if (read_eeprom())
return pv;
return pbuf.eeprom.atom1.data.pstr[6];
}
/**
* get_ddr_size_from_eeprom - get the DDR size
* pstr: VF7110A1-2228-D008E000-00000001
* VF7110A1/VF7110B1 : VisionFive JH7110A /VisionFive JH7110B
* D008: 8GB LPDDR4
* E000: No emmc device, ECxx: include emmc device, xx: Capacity size[GB]
* return: the field of 'D008E000'
*/
u32 get_ddr_size_from_eeprom(void)
{
u32 pv = 0xFFFFFFFF;
if (read_eeprom())
return pv;
return hextoul(&pbuf.eeprom.atom1.data.pstr[14], NULL);
}

View file

@ -0,0 +1,42 @@
if TARGET_TH1520_LPI4A
config ARCH_THEAD
bool
default y
config SYS_BOARD
default "th1520_lpi4a"
config SYS_VENDOR
default "thead"
config SYS_CPU
default "generic"
config SYS_CONFIG_NAME
default "th1520_lpi4a"
config TEXT_BASE
default 0x01b00000 if SPL
default 0x01c00000 if !RISCV_SMODE
default 0x01c00000 if RISCV_SMODE
config SPL_TEXT_BASE
default 0x08000000
config SPL_OPENSBI_LOAD_ADDR
default 0x80000000
config BOARD_SPECIFIC_OPTIONS
def_bool y
select ARCH_EARLY_INIT_R
imply CPU
imply CPU_RISCV
imply RISCV_TIMER if RISCV_SMODE
imply CMD_CPU
imply SMP
imply SUPPORT_OF_CONTROL
imply OF_CONTROL
imply OF_REAL
endif

View file

@ -0,0 +1,7 @@
Lichee PI 4A
M: Wei Fu <wefu@redhat.com>
M: Yixun Lan <dlan@gentoo.org>
S: Maintained
F: board/thead/th1520_lpi4a/
F: configs/th1520_lpi4a_defconfig
F: doc/board/thead/lpi4a.rst

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2023, Yixun Lan <dlan@gentoo.org>
obj-y += board.o

View file

@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2023, Yixun Lan <dlan@gentoo.org>
*
*/
#include <common.h>
#include <cpu_func.h>
int board_init(void)
{
enable_caches();
return 0;
}

View file

@ -7,12 +7,13 @@ CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80000000
CONFIG_SF_DEFAULT_SPEED=100000000
CONFIG_SPL_DM_SPI=y
CONFIG_DEFAULT_DEVICE_TREE="jh7110-starfive-visionfive-2-v1.3b"
CONFIG_DEFAULT_DEVICE_TREE="jh7110-starfive-visionfive-2"
CONFIG_SPL_TEXT_BASE=0x8000000
CONFIG_SYS_PROMPT="StarFive #"
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_DM_RESET=y
CONFIG_SPL_MMC=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_STACK=0x8180000
CONFIG_SPL=y
CONFIG_SPL_SPI_FLASH_SUPPORT=y
@ -23,6 +24,7 @@ CONFIG_SPL_OPENSBI_LOAD_ADDR=0x40000000
CONFIG_ARCH_RV64I=y
CONFIG_CMODEL_MEDANY=y
CONFIG_RISCV_SMODE=y
# CONFIG_OF_BOARD_FIXUP is not set
CONFIG_FIT=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_QSPI_BOOT=y
@ -31,9 +33,11 @@ CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 debug rootwait earlycon=sbi"
CONFIG_USE_PREBOOT=y
CONFIG_PREBOOT="setenv fdt_addr ${fdtcontroladdr};fdt addr ${fdtcontroladdr};"
CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2-v1.3b.dtb"
CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2.dtb"
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_ID_EEPROM=y
CONFIG_SYS_EEPROM_BUS_NUM=5
CONFIG_SPL_MAX_SIZE=0x40000
CONFIG_SPL_PAD_TO=0x0
CONFIG_SPL_BSS_START_ADDR=0x8040000
@ -45,19 +49,34 @@ CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x80000000
CONFIG_SYS_SPL_MALLOC_SIZE=0x400000
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x2
CONFIG_SPL_I2C=y
CONFIG_SPL_DM_SPI_FLASH=y
CONFIG_SPL_DM_RESET=y
CONFIG_SPL_SPI_LOAD=y
CONFIG_SYS_CBSIZE=256
CONFIG_SYS_PBSIZE=276
CONFIG_SYS_BOOTM_LEN=0x4000000
CONFIG_CMD_EEPROM=y
CONFIG_SYS_EEPROM_SIZE=512
CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=4
CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=5
CONFIG_CMD_MEMINFO=y
CONFIG_CMD_I2C=y
CONFIG_CMD_TFTPPUT=y
CONFIG_OF_BOARD=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_SPL_CLK_COMPOSITE_CCF=y
CONFIG_CLK_COMPOSITE_CCF=y
CONFIG_SPL_CLK_JH7110=y
# CONFIG_I2C is not set
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_DW=y
CONFIG_MISC=y
CONFIG_I2C_EEPROM=y
CONFIG_SPL_I2C_EEPROM=y
CONFIG_SYS_I2C_EEPROM_ADDR=0X50
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_SPL_MMC_HS400_SUPPORT=y
CONFIG_MMC_DW=y
@ -66,6 +85,13 @@ CONFIG_SPI_FLASH_EON=y
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_SPI_FLASH_ISSI=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_PHY_MOTORCOMM=y
CONFIG_DM_MDIO=y
CONFIG_DM_ETH_PHY=y
CONFIG_DWC_ETH_QOS=y
CONFIG_DWC_ETH_QOS_STARFIVE=y
CONFIG_RGMII=y
CONFIG_RMII=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
CONFIG_SPL_PINCTRL=y

View file

@ -0,0 +1,82 @@
CONFIG_RISCV=y
CONFIG_SYS_MALLOC_LEN=0x800000
CONFIG_SYS_MALLOC_F_LEN=0x3000
CONFIG_NR_DRAM_BANKS=1
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80200000
CONFIG_DEFAULT_DEVICE_TREE="th1520-lichee-pi-4a"
CONFIG_SYS_PROMPT="LPI4A=> "
CONFIG_SYS_LOAD_ADDR=0x80200000
# CONFIG_SMP is not set
CONFIG_TARGET_TH1520_LPI4A=y
CONFIG_ARCH_RV64I=y
CONFIG_OF_BOARD_FIXUP=y
CONFIG_SYS_BOOT_GET_CMDLINE=y
CONFIG_SYS_BOOT_GET_KBD=y
CONFIG_FIT=y
# CONFIG_FIT_FULL_CHECK is not set
# CONFIG_FIT_PRINT is not set
# CONFIG_BOOTSTD is not set
# CONFIG_LEGACY_IMAGE_FORMAT is not set
CONFIG_DISTRO_DEFAULTS=y
CONFIG_BOOTARGS_SUBST=y
CONFIG_BOOTCOMMAND=""
CONFIG_DEFAULT_FDT_FILE="thead/th1520-lichee-pi-4a.dtb"
CONFIG_LOG=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_SYS_CBSIZE=256
CONFIG_SYS_PBSIZE=276
CONFIG_CMD_CONFIG=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
# CONFIG_BOOTM_NETBSD is not set
# CONFIG_BOOTM_PLAN9 is not set
# CONFIG_BOOTM_RTEMS is not set
# CONFIG_BOOTM_VXWORKS is not set
CONFIG_SYS_BOOTM_LEN=0x4000000
CONFIG_CMD_BOOTMENU=y
# CONFIG_CMD_ELF is not set
# CONFIG_CMD_IMI is not set
# CONFIG_CMD_XIMG is not set
# CONFIG_CMD_EXPORTENV is not set
# CONFIG_CMD_IMPORTENV is not set
# CONFIG_CMD_EDITENV is not set
# CONFIG_CMD_SAVEENV is not set
# CONFIG_CMD_CRC32 is not set
# CONFIG_CMD_MEMORY is not set
# CONFIG_CMD_LZMADEC is not set
# CONFIG_CMD_UNLZ4 is not set
# CONFIG_CMD_UNZIP is not set
# CONFIG_CMD_LOADB is not set
# CONFIG_CMD_LOADS is not set
# CONFIG_CMD_ITEST is not set
# CONFIG_CMD_SOURCE is not set
# CONFIG_CMD_SETEXPR is not set
# CONFIG_CMD_SLEEP is not set
CONFIG_PARTITION_TYPE_GUID=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_VERSION_VARIABLE=y
# CONFIG_NET is not set
# CONFIG_BLOCK_CACHE is not set
# CONFIG_GPIO is not set
# CONFIG_I2C is not set
# CONFIG_INPUT is not set
# CONFIG_DM_MMC is not set
# CONFIG_MTD is not set
# CONFIG_POWER is not set
CONFIG_SYS_NS16550=y
CONFIG_RISCV_TIMER=y
CONFIG_AES=y
CONFIG_BLAKE2=y
CONFIG_SHA512=y
CONFIG_LZ4=y
CONFIG_LZMA=y
CONFIG_LZO=y
CONFIG_ZLIB_UNCOMPRESS=y
CONFIG_BZIP2=y
CONFIG_ZSTD=y
CONFIG_LIB_RATIONAL=y
# CONFIG_EFI_LOADER is not set
# CONFIG_LMB_USE_MAX_REGIONS is not set

View file

@ -45,6 +45,7 @@ Board-specific doc
starfive/index
ste/index
tbs/index
thead/index
ti/index
toradex/index
variscite/index

View file

@ -62,7 +62,7 @@ Now build the U-Boot SPL and U-Boot proper
.. code-block:: console
cd <U-Boot-dir>
make starfive_visionfive2_13b_defconfig
make starfive_visionfive2_defconfig
make OPENSBI=$(opensbi_dir)/opensbi/build/platform/generic/firmware/fw_dynamic.bin
This will generate spl/u-boot-spl.bin and FIT image (u-boot.itb)
@ -118,7 +118,7 @@ Program the SD card
sudo cp u-boot.itb /mnt/
sudo cp Image.gz /mnt/
sudo cp initramfs.cpio.gz /mnt/
sudo cp jh7110-starfive-visionfive-2-v1.3b.dtb /mnt/
sudo cp jh7110-starfive-visionfive-2.dtb /mnt/
sudo umount /mnt
Booting
@ -264,7 +264,7 @@ Sample boot log from StarFive VisionFive2 board
StarFive #fatload mmc 1:3 ${kernel_addr_r} Image.gz
6429424 bytes read in 394 ms (15.6 MiB/s)
StarFive #fatload mmc 1:3 ${fdt_addr_r} jh7110-starfive-visionfive-2-v1.3b.dtb
StarFive #fatload mmc 1:3 ${fdt_addr_r} jh7110-starfive-visionfive-2.dtb
11285 bytes read in 5 ms (2.2 MiB/s)
StarFive #fatload mmc 1:3 ${ramdisk_addr_r} initramfs.cpio.gz
152848495 bytes read in 9271 ms (15.7 MiB/s)

View file

@ -0,0 +1,9 @@
.. SPDX-License-Identifier: GPL-2.0+
T-HEAD
========
.. toctree::
:maxdepth: 1
lpi4a

129
doc/board/thead/lpi4a.rst Normal file
View file

@ -0,0 +1,129 @@
.. SPDX-License-Identifier: GPL-2.0+
Sipeed's Lichee PI 4A based on T-HEAD TH1520 SoC
================================================
The LicheePi4A is a high-performance RISC-V SBC based on TH1520(4xC910@1.85GHz),
comes with 4/8/16 GB RAM, and up to 128GB eMMC, and rich peripherals.
- SoC T-HEAD TH1520 SoC
- System Memory 4GB, 8GB, or 16GB LPDDR4X
- Storage eMMC flash with 8/32/128 GB
- external microSD slot
- Networking 2x Gigabit Ethernet
- WiFi+BT
- Display HDMI2.0, 4-lane MIPI DSI
- Camera 4-lane MIPI CSI + 2x2-lane MIPI CSI
- Audio Onboard Speaker, 2xMEMS MIC, 3.5mm headphone jack
- USB 4xUSB3.0 Type-A, 1xUSB2.0 Type-C
- GPIO 2x10Pin breakout, UART/IIC/SPI
- Power DC 12V/2A, POE 5V/2.4A, USB Type-C 5V/2A
TH1520 RISC-V SoC
-----------------
The TH1520 SoC consist of quad-core RISC-V Xuantie C910 (RV64GCV) processor,
Xuantie C906 audio DSP, low power Xuantie E902 core, it also integrate
Imagination GPU for graphics, and 4 TOPS NPU for AI acceleration.
Mainline support
----------------
The support for following drivers are already enabled:
1. ns16550 UART Driver.
Building
~~~~~~~~
1. Add the RISC-V toolchain to your PATH.
2. Setup ARCH & cross compilation environment variable:
.. code-block:: none
export CROSS_COMPILE=<riscv64 toolchain prefix>
The U-Boot is capable of running in M-Mode, so we can directly build it.
.. code-block:: console
cd <U-Boot-dir>
make th1520_lpi4a_defconfig
make
This will generate u-boot-dtb.bin
Booting
~~~~~~~
Currently, we rely on vendor u-boot to initialize the clock, pinctrl subsystem,
and chain load the mainline u-boot image either via tftp or emmc storage,
then bootup from it.
Sample boot log from Lichee PI 4A board via tftp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: none
brom_ver 8
[APP][E] protocol_connect failed, exit.
U-Boot SPL 2020.01-00016-g8c870a6be8 (May 20 2023 - 01:04:49 +0000)
FM[1] lpddr4x dualrank freq=3733 64bit dbi_off=n sdram init
ddr initialized, jump to uboot
image has no header
U-Boot 2020.01-00016-g8c870a6be8 (May 20 2023 - 01:04:49 +0000)
CPU: rv64imafdcvsu
Model: T-HEAD c910 light
DRAM: 8 GiB
C910 CPU FREQ: 750MHz
AHB2_CPUSYS_HCLK FREQ: 250MHz
AHB3_CPUSYS_PCLK FREQ: 125MHz
PERISYS_AHB_HCLK FREQ: 250MHz
PERISYS_APB_PCLK FREQ: 62MHz
GMAC PLL POSTDIV FREQ: 1000MHZ
DPU0 PLL POSTDIV FREQ: 1188MHZ
DPU1 PLL POSTDIV FREQ: 1188MHZ
MMC: sdhci@ffe7080000: 0, sd@ffe7090000: 1
Loading Environment from MMC... OK
Error reading output register
Warning: cannot get lcd-en GPIO
LCD panel cannot be found : -121
splash screen startup cost 16 ms
In: serial
Out: serial
Err: serial
Net:
Warning: ethernet@ffe7070000 using MAC address from ROM
eth0: ethernet@ffe7070000ethernet@ffe7070000:0 is connected to ethernet@ffe7070000. Reconnecting to ethernet@ffe7060000
Warning: ethernet@ffe7060000 (eth1) using random MAC address - 42:25:d4:16:5f:fc
, eth1: ethernet@ffe7060000
Hit any key to stop autoboot: 2
ethernet@ffe7060000 Waiting for PHY auto negotiation to complete.. done
Speed: 1000, full duplex
Using ethernet@ffe7070000 device
TFTP from server 192.168.8.50; our IP address is 192.168.8.45
Filename 'u-boot-dtb.bin'.
Load address: 0x1c00000
Loading: * #########################
8 MiB/s
done
Bytes transferred = 376686 (5bf6e hex)
## Starting application at 0x01C00000 ...
U-Boot 2023.07-rc2-00004-g1befbe31c1 (May 23 2023 - 18:40:01 +0800)
CPU: rv64imafdc
Model: Sipeed Lichee Pi 4A
DRAM: 8 GiB
Core: 13 devices, 6 uclasses, devicetree: separate
Loading Environment from <NULL>... OK
In: serial@ffe7014000
Out: serial@ffe7014000
Err: serial@ffe7014000
Model: Sipeed Lichee Pi 4A
LPI4A=>

View file

@ -249,6 +249,13 @@ config DWC_ETH_QOS_QCOM
The Synopsys Designware Ethernet QOS IP block with specific
configuration used in Qcom QCS404 SoC.
config DWC_ETH_QOS_STARFIVE
bool "Synopsys DWC Ethernet QOS device support for STARFIVE"
depends on DWC_ETH_QOS
help
The Synopsys Designware Ethernet QOS IP block with specific
configuration used in STARFIVE JH7110 soc.
config E1000
bool "Intel PRO/1000 Gigabit Ethernet support"
depends on PCI

View file

@ -21,6 +21,7 @@ obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o
obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o
obj-$(CONFIG_E1000) += e1000.o
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
obj-$(CONFIG_EEPRO100) += eepro100.o

View file

@ -1725,6 +1725,12 @@ static const struct udevice_id eqos_ids[] = {
.data = (ulong)&eqos_qcom_config
},
#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_STARFIVE)
{
.compatible = "starfive,jh7110-dwmac",
.data = (ulong)&eqos_jh7110_config
},
#endif
{ }
};

View file

@ -289,3 +289,4 @@ int eqos_null_ops(struct udevice *dev);
extern struct eqos_config eqos_imx_config;
extern struct eqos_config eqos_qcom_config;
extern struct eqos_config eqos_jh7110_config;

View file

@ -0,0 +1,249 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
* Author: Yanhong Wang<yanhong.wang@starfivetech.com>
*/
#include <common.h>
#include <asm/cache.h>
#include <asm/gpio.h>
#include <clk.h>
#include <dm.h>
#include <eth_phy.h>
#include <net.h>
#include <regmap.h>
#include <reset.h>
#include <syscon.h>
#include "dwc_eth_qos.h"
#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1
#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4
#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U
struct starfive_platform_data {
struct regmap *regmap;
struct reset_ctl_bulk resets;
struct clk_bulk clks;
phy_interface_t interface;
u32 offset;
u32 shift;
bool tx_use_rgmii_clk;
};
static int eqos_interface_init_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
struct ofnode_phandle_args args;
unsigned int mode;
int ret;
switch (data->interface) {
case PHY_INTERFACE_MODE_RMII:
mode = STARFIVE_DWMAC_PHY_INFT_RMII;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
mode = STARFIVE_DWMAC_PHY_INFT_RGMII;
break;
default:
return -EINVAL;
}
ret = dev_read_phandle_with_args(dev, "starfive,syscon", NULL,
2, 0, &args);
if (ret)
return ret;
if (args.args_count != 2)
return -EINVAL;
data->offset = args.args[0];
data->shift = args.args[1];
data->regmap = syscon_regmap_lookup_by_phandle(dev, "starfive,syscon");
if (IS_ERR(data->regmap)) {
ret = PTR_ERR(data->regmap);
pr_err("Failed to get regmap: %d\n", ret);
return ret;
}
return regmap_update_bits(data->regmap, data->offset,
STARFIVE_DWMAC_PHY_INFT_FIELD << data->shift,
mode << data->shift);
}
static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
struct clk *pclk, *c;
ulong rate;
int ret;
/* Generally, the rgmii_tx clock is provided by the internal clock,
* which needs to match the corresponding clock frequency according
* to different speeds. If the rgmii_tx clock is provided by the
* external rgmii_rxin, there is no need to configure the clock
* internally, because rgmii_rxin will be adaptively adjusted.
*/
if (data->tx_use_rgmii_clk)
return 0;
switch (eqos->phy->speed) {
case SPEED_1000:
rate = 125 * 1000 * 1000;
break;
case SPEED_100:
rate = 25 * 1000 * 1000;
break;
case SPEED_10:
rate = 2.5 * 1000 * 1000;
break;
default:
pr_err("invalid speed %d", eqos->phy->speed);
return -EINVAL;
}
/* eqos->clk_tx clock has no set rate operation, so just set the parent
* clock rate directly
*/
ret = clk_get_by_id(eqos->clk_tx.id, &c);
if (ret)
return ret;
pclk = clk_get_parent(c);
if (pclk) {
ret = clk_set_rate(pclk, rate);
if (ret < 0) {
pr_err("jh7110 (clk_tx, %lu) failed: %d", rate, ret);
return ret;
}
}
return 0;
}
static ulong eqos_get_tick_clk_rate_jh7110(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
return clk_get_rate(&eqos->clk_tx);
}
static int eqos_start_clks_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
return clk_enable_bulk(&data->clks);
}
static int eqos_stop_clks_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
return clk_disable_bulk(&data->clks);
}
static int eqos_start_resets_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
return reset_deassert_bulk(&data->resets);
}
static int eqos_stop_resets_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
return reset_assert_bulk(&data->resets);
}
static int eqos_remove_resources_jh7110(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data = pdata->priv_pdata;
reset_assert_bulk(&data->resets);
clk_disable_bulk(&data->clks);
return 0;
}
static int eqos_probe_resources_jh7110(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_plat(dev);
struct starfive_platform_data *data;
int ret;
data = calloc(1, sizeof(struct starfive_platform_data));
if (!data)
return -ENOMEM;
pdata->priv_pdata = data;
data->interface = eqos->config->interface(dev);
if (data->interface == PHY_INTERFACE_MODE_NA) {
pr_err("Invalid PHY interface\n");
return -EINVAL;
}
ret = reset_get_bulk(dev, &data->resets);
if (ret < 0)
return ret;
ret = clk_get_bulk(dev, &data->clks);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "gtx", &eqos->clk_tx);
if (ret)
return ret;
data->tx_use_rgmii_clk = dev_read_bool(dev, "starfive,tx-use-rgmii-clk");
return eqos_interface_init_jh7110(dev);
}
static struct eqos_ops eqos_jh7110_ops = {
.eqos_inval_desc = eqos_inval_desc_generic,
.eqos_flush_desc = eqos_flush_desc_generic,
.eqos_inval_buffer = eqos_inval_buffer_generic,
.eqos_flush_buffer = eqos_flush_buffer_generic,
.eqos_probe_resources = eqos_probe_resources_jh7110,
.eqos_remove_resources = eqos_remove_resources_jh7110,
.eqos_stop_resets = eqos_stop_resets_jh7110,
.eqos_start_resets = eqos_start_resets_jh7110,
.eqos_stop_clks = eqos_stop_clks_jh7110,
.eqos_start_clks = eqos_start_clks_jh7110,
.eqos_calibrate_pads = eqos_null_ops,
.eqos_disable_calibration = eqos_null_ops,
.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_jh7110,
.eqos_get_enetaddr = eqos_null_ops,
.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_jh7110
};
/* mdio_wait: There is no need to wait after setting the MAC_MDIO_Address register
* swr_wait: Software reset bit must be read at least 4 CSR clock cycles
* after it is written to 1.
* config_mac: Enable rx queue to DCB mode.
* config_mac_mdio: CSR clock range is 250-300 Mhz.
* axi_bus_width: The width of the data bus is 64 bit.
*/
struct eqos_config __maybe_unused eqos_jh7110_config = {
.reg_access_always_ok = false,
.mdio_wait = 0,
.swr_wait = 4,
.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
.axi_bus_width = EQOS_AXI_WIDTH_64,
.interface = dev_read_phy_mode,
.ops = &eqos_jh7110_ops
};

View file

@ -220,6 +220,12 @@ config PHY_MICREL_KSZ8XXX
endif # PHY_MICREL
config PHY_MOTORCOMM
tristate "Motorcomm PHYs"
help
Enables support for Motorcomm network PHYs.
Currently supports the YT8531 Gigabit Ethernet PHYs.
config PHY_MSCC
bool "Microsemi Corp Ethernet PHYs support"

View file

@ -24,6 +24,7 @@ obj-$(CONFIG_PHY_MARVELL_10G) += marvell10g.o
obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o
obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o
obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o
obj-$(CONFIG_PHY_MOTORCOMM) += motorcomm.o
obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o
obj-$(CONFIG_PHY_NXP_TJA11XX) += nxp-tja11xx.o

437
drivers/net/phy/motorcomm.c Normal file
View file

@ -0,0 +1,437 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Motorcomm 8531 PHY driver.
*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
*/
#include <config.h>
#include <common.h>
#include <malloc.h>
#include <phy.h>
#include <linux/bitfield.h>
#define PHY_ID_YT8531 0x4f51e91b
#define PHY_ID_MASK GENMASK(31, 0)
/* Extended Register's Address Offset Register */
#define YTPHY_PAGE_SELECT 0x1E
/* Extended Register's Data Register */
#define YTPHY_PAGE_DATA 0x1F
#define YTPHY_SYNCE_CFG_REG 0xA012
#define YTPHY_DTS_OUTPUT_CLK_DIS 0
#define YTPHY_DTS_OUTPUT_CLK_25M 25000000
#define YTPHY_DTS_OUTPUT_CLK_125M 125000000
#define YT8531_SCR_SYNCE_ENABLE BIT(6)
/* 1b0 output 25m clock *default*
* 1b1 output 125m clock
*/
#define YT8531_SCR_CLK_FRE_SEL_125M BIT(4)
#define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1)
#define YT8531_SCR_CLK_SRC_PLL_125M 0
#define YT8531_SCR_CLK_SRC_UTP_RX 1
#define YT8531_SCR_CLK_SRC_SDS_RX 2
#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3
#define YT8531_SCR_CLK_SRC_REF_25M 4
#define YT8531_SCR_CLK_SRC_SSC_25M 5
/* 1b0 use original tx_clk_rgmii *default*
* 1b1 use inverted tx_clk_rgmii.
*/
#define YT8531_RC1R_TX_CLK_SEL_INVERTED BIT(14)
#define YT8531_RC1R_RX_DELAY_MASK GENMASK(13, 10)
#define YT8531_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4)
#define YT8531_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0)
#define YT8531_RC1R_RGMII_0_000_NS 0
#define YT8531_RC1R_RGMII_0_150_NS 1
#define YT8531_RC1R_RGMII_0_300_NS 2
#define YT8531_RC1R_RGMII_0_450_NS 3
#define YT8531_RC1R_RGMII_0_600_NS 4
#define YT8531_RC1R_RGMII_0_750_NS 5
#define YT8531_RC1R_RGMII_0_900_NS 6
#define YT8531_RC1R_RGMII_1_050_NS 7
#define YT8531_RC1R_RGMII_1_200_NS 8
#define YT8531_RC1R_RGMII_1_350_NS 9
#define YT8531_RC1R_RGMII_1_500_NS 10
#define YT8531_RC1R_RGMII_1_650_NS 11
#define YT8531_RC1R_RGMII_1_800_NS 12
#define YT8531_RC1R_RGMII_1_950_NS 13
#define YT8531_RC1R_RGMII_2_100_NS 14
#define YT8531_RC1R_RGMII_2_250_NS 15
/* Phy gmii clock gating Register */
#define YT8531_CLOCK_GATING_REG 0xC
#define YT8531_CGR_RX_CLK_EN BIT(12)
/* Specific Status Register */
#define YTPHY_SPECIFIC_STATUS_REG 0x11
#define YTPHY_DUPLEX_MASK BIT(13)
#define YTPHY_DUPLEX_SHIFT 13
#define YTPHY_SPEED_MODE_MASK GENMASK(15, 14)
#define YTPHY_SPEED_MODE_SHIFT 14
#define YT8531_EXTREG_SLEEP_CONTROL1_REG 0x27
#define YT8531_ESC1R_SLEEP_SW BIT(15)
#define YT8531_ESC1R_PLLON_SLP BIT(14)
#define YT8531_RGMII_CONFIG1_REG 0xA003
#define YT8531_CHIP_CONFIG_REG 0xA001
#define YT8531_CCR_SW_RST BIT(15)
/* 1b0 disable 1.9ns rxc clock delay *default*
* 1b1 enable 1.9ns rxc clock delay
*/
#define YT8531_CCR_RXC_DLY_EN BIT(8)
#define YT8531_CCR_RXC_DLY_1_900_NS 1900
/* bits in struct ytphy_plat_priv->flag */
#define TX_CLK_ADJ_ENABLED BIT(0)
#define AUTO_SLEEP_DISABLED BIT(1)
#define KEEP_PLL_ENABLED BIT(2)
#define TX_CLK_10_INVERTED BIT(3)
#define TX_CLK_100_INVERTED BIT(4)
#define TX_CLK_1000_INVERTED BIT(5)
struct ytphy_plat_priv {
u32 rx_delay_ps;
u32 tx_delay_ps;
u32 clk_out_frequency;
u32 flag;
};
/**
* struct ytphy_cfg_reg_map - map a config value to a register value
* @cfg: value in device configuration
* @reg: value in the register
*/
struct ytphy_cfg_reg_map {
u32 cfg;
u32 reg;
};
static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = {
/* for tx delay / rx delay with YT8531_CCR_RXC_DLY_EN is not set. */
{ 0, YT8531_RC1R_RGMII_0_000_NS },
{ 150, YT8531_RC1R_RGMII_0_150_NS },
{ 300, YT8531_RC1R_RGMII_0_300_NS },
{ 450, YT8531_RC1R_RGMII_0_450_NS },
{ 600, YT8531_RC1R_RGMII_0_600_NS },
{ 750, YT8531_RC1R_RGMII_0_750_NS },
{ 900, YT8531_RC1R_RGMII_0_900_NS },
{ 1050, YT8531_RC1R_RGMII_1_050_NS },
{ 1200, YT8531_RC1R_RGMII_1_200_NS },
{ 1350, YT8531_RC1R_RGMII_1_350_NS },
{ 1500, YT8531_RC1R_RGMII_1_500_NS },
{ 1650, YT8531_RC1R_RGMII_1_650_NS },
{ 1800, YT8531_RC1R_RGMII_1_800_NS },
{ 1950, YT8531_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */
{ 2100, YT8531_RC1R_RGMII_2_100_NS },
{ 2250, YT8531_RC1R_RGMII_2_250_NS },
/* only for rx delay with YT8531_CCR_RXC_DLY_EN is set. */
{ 0 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_000_NS },
{ 150 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_150_NS },
{ 300 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_300_NS },
{ 450 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_450_NS },
{ 600 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_600_NS },
{ 750 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_750_NS },
{ 900 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_900_NS },
{ 1050 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_050_NS },
{ 1200 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_200_NS },
{ 1350 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_350_NS },
{ 1500 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_500_NS },
{ 1650 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_650_NS },
{ 1800 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_800_NS },
{ 1950 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_950_NS },
{ 2100 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_100_NS },
{ 2250 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_250_NS }
};
static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
u32 val,
u16 *rxc_dly_en)
{
int tb_size = ARRAY_SIZE(ytphy_rgmii_delays);
int tb_size_half = tb_size / 2;
int i;
/* when rxc_dly_en is NULL, it is get the delay for tx, only half of
* tb_size is valid.
*/
if (!rxc_dly_en)
tb_size = tb_size_half;
for (i = 0; i < tb_size; i++) {
if (ytphy_rgmii_delays[i].cfg == val) {
if (rxc_dly_en && i < tb_size_half)
*rxc_dly_en = 0;
return ytphy_rgmii_delays[i].reg;
}
}
pr_warn("Unsupported value %d, using default (%u)\n",
val, YT8531_RC1R_RGMII_1_950_NS);
/* when rxc_dly_en is not NULL, it is get the delay for rx.
* The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps,
* so YT8531_CCR_RXC_DLY_EN should not be set.
*/
if (rxc_dly_en)
*rxc_dly_en = 0;
return YT8531_RC1R_RGMII_1_950_NS;
}
static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask,
u16 set)
{
int ret;
ret = phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_SELECT, regnum);
if (ret < 0)
return ret;
return phy_modify(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, mask, set);
}
static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
u16 rxc_dly_en = YT8531_CCR_RXC_DLY_EN;
u32 rx_reg, tx_reg;
u16 mask, val = 0;
int ret;
rx_reg = ytphy_get_delay_reg_value(phydev, priv->rx_delay_ps,
&rxc_dly_en);
tx_reg = ytphy_get_delay_reg_value(phydev, priv->tx_delay_ps,
NULL);
switch (phydev->interface) {
case PHY_INTERFACE_MODE_RGMII:
rxc_dly_en = 0;
break;
case PHY_INTERFACE_MODE_RGMII_RXID:
val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg);
break;
case PHY_INTERFACE_MODE_RGMII_TXID:
rxc_dly_en = 0;
val |= FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg);
break;
case PHY_INTERFACE_MODE_RGMII_ID:
val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg) |
FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg);
break;
default: /* do not support other modes */
return -EOPNOTSUPP;
}
ret = ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG,
YT8531_CCR_RXC_DLY_EN, rxc_dly_en);
if (ret < 0)
return ret;
/* Generally, it is not necessary to adjust YT8531_RC1R_FE_TX_DELAY */
mask = YT8531_RC1R_RX_DELAY_MASK | YT8531_RC1R_GE_TX_DELAY_MASK;
return ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, mask, val);
}
static int yt8531_parse_status(struct phy_device *phydev)
{
int val;
int speed, speed_mode;
val = phy_read(phydev, MDIO_DEVAD_NONE, YTPHY_SPECIFIC_STATUS_REG);
if (val < 0)
return val;
speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT;
switch (speed_mode) {
case 2:
speed = SPEED_1000;
break;
case 1:
speed = SPEED_100;
break;
default:
speed = SPEED_10;
break;
}
phydev->speed = speed;
phydev->duplex = (val & YTPHY_DUPLEX_MASK) >> YTPHY_DUPLEX_SHIFT;
return 0;
}
static int yt8531_startup(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
u16 val = 0;
int ret;
ret = genphy_update_link(phydev);
if (ret)
return ret;
ret = yt8531_parse_status(phydev);
if (ret)
return ret;
if (phydev->speed < 0)
return -EINVAL;
if (!(priv->flag & TX_CLK_ADJ_ENABLED))
return 0;
switch (phydev->speed) {
case SPEED_1000:
if (priv->flag & TX_CLK_1000_INVERTED)
val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
break;
case SPEED_100:
if (priv->flag & TX_CLK_100_INVERTED)
val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
break;
case SPEED_10:
if (priv->flag & TX_CLK_10_INVERTED)
val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
break;
default:
printf("UNKNOWN SPEED\n");
return -EINVAL;
}
ret = ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG,
YT8531_RC1R_TX_CLK_SEL_INVERTED, val);
if (ret < 0)
pr_warn("Modify TX_CLK_SEL err:%d\n", ret);
return 0;
}
static void ytphy_dt_parse(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
priv->clk_out_frequency = ofnode_read_u32_default(phydev->node,
"motorcomm,clk-out-frequency-hz",
YTPHY_DTS_OUTPUT_CLK_DIS);
priv->rx_delay_ps = ofnode_read_u32_default(phydev->node,
"rx-internal-delay-ps",
YT8531_RC1R_RGMII_1_950_NS);
priv->tx_delay_ps = ofnode_read_u32_default(phydev->node,
"tx-internal-delay-ps",
YT8531_RC1R_RGMII_1_950_NS);
if (ofnode_read_bool(phydev->node, "motorcomm,auto-sleep-disabled"))
priv->flag |= AUTO_SLEEP_DISABLED;
if (ofnode_read_bool(phydev->node, "motorcomm,keep-pll-enabled"))
priv->flag |= KEEP_PLL_ENABLED;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled"))
priv->flag |= TX_CLK_ADJ_ENABLED;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-10-inverted"))
priv->flag |= TX_CLK_10_INVERTED;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-100-inverted"))
priv->flag |= TX_CLK_100_INVERTED;
if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-1000-inverted"))
priv->flag |= TX_CLK_1000_INVERTED;
}
static int yt8531_config(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
u16 mask, val;
int ret;
ret = genphy_config_aneg(phydev);
if (ret < 0)
return ret;
ytphy_dt_parse(phydev);
switch (priv->clk_out_frequency) {
case YTPHY_DTS_OUTPUT_CLK_DIS:
mask = YT8531_SCR_SYNCE_ENABLE;
val = 0;
break;
case YTPHY_DTS_OUTPUT_CLK_25M:
mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
YT8531_SCR_CLK_FRE_SEL_125M;
val = YT8531_SCR_SYNCE_ENABLE |
FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
YT8531_SCR_CLK_SRC_REF_25M);
break;
case YTPHY_DTS_OUTPUT_CLK_125M:
mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
YT8531_SCR_CLK_FRE_SEL_125M;
val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M |
FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
YT8531_SCR_CLK_SRC_PLL_125M);
break;
default:
pr_warn("Freq err:%u\n", priv->clk_out_frequency);
return -EINVAL;
}
ret = ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask,
val);
if (ret < 0)
return ret;
ret = ytphy_rgmii_clk_delay_config(phydev);
if (ret < 0)
return ret;
if (priv->flag & AUTO_SLEEP_DISABLED) {
/* disable auto sleep */
ret = ytphy_modify_ext(phydev,
YT8531_EXTREG_SLEEP_CONTROL1_REG,
YT8531_ESC1R_SLEEP_SW, 0);
if (ret < 0)
return ret;
}
if (priv->flag & KEEP_PLL_ENABLED) {
/* enable RXC clock when no wire plug */
ret = ytphy_modify_ext(phydev,
YT8531_CLOCK_GATING_REG,
YT8531_CGR_RX_CLK_EN, 0);
if (ret < 0)
return ret;
}
return 0;
}
static int yt8531_probe(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv;
priv = calloc(1, sizeof(struct ytphy_plat_priv));
if (!priv)
return -ENOMEM;
phydev->priv = priv;
return 0;
}
U_BOOT_PHY_DRIVER(motorcomm8531) = {
.name = "YT8531 Gigabit Ethernet",
.uid = PHY_ID_YT8531,
.mask = PHY_ID_MASK,
.features = PHY_GBIT_FEATURES,
.probe = &yt8531_probe,
.config = &yt8531_config,
.startup = &yt8531_startup,
.shutdown = &genphy_shutdown,
};

View file

@ -72,8 +72,6 @@ static int starfive_ddr_probe(struct udevice *dev)
u64 rate;
int ret;
/* Read memory base and size from DT */
fdtdec_setup_mem_size_base();
priv->info.base = gd->ram_base;
priv->info.size = gd->ram_size;

View file

@ -25,7 +25,7 @@ obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_SP804_TIMER) += sp804_timer.o
obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint_timer.o
obj-$(CONFIG_$(SPL_)RISCV_ACLINT) += riscv_aclint_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
obj-$(CONFIG_TEGRA_TIMER) += tegra-timer.o

View file

@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <timer.h>
#include <asm/io.h>
#include <dm/device-internal.h>
#include <linux/err.h>
#define CLINT_MTIME_OFFSET 0xbff8
#define ACLINT_MTIME_OFFSET 0
/* mtime register */
#define MTIME_REG(base, offset) ((ulong)(base) + (offset))
static u64 notrace riscv_aclint_timer_get_count(struct udevice *dev)
{
return readq((void __iomem *)MTIME_REG(dev_get_priv(dev),
dev_get_driver_data(dev)));
}
#if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
/**
* timer_early_get_rate() - Get the timer rate before driver model
*/
unsigned long notrace timer_early_get_rate(void)
{
return RISCV_MMODE_TIMER_FREQ;
}
/**
* timer_early_get_count() - Get the timer count before driver model
*
*/
u64 notrace timer_early_get_count(void)
{
return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE,
RISCV_MMODE_TIMEROFF));
}
#endif
static const struct timer_ops riscv_aclint_timer_ops = {
.get_count = riscv_aclint_timer_get_count,
};
static int riscv_aclint_timer_probe(struct udevice *dev)
{
dev_set_priv(dev, dev_read_addr_ptr(dev));
if (!dev_get_priv(dev))
return -EINVAL;
return timer_timebase_fallback(dev);
}
static const struct udevice_id riscv_aclint_timer_ids[] = {
{ .compatible = "riscv,clint0", .data = CLINT_MTIME_OFFSET },
{ .compatible = "sifive,clint0", .data = CLINT_MTIME_OFFSET },
{ .compatible = "riscv,aclint-mtimer", .data = ACLINT_MTIME_OFFSET },
{ }
};
U_BOOT_DRIVER(riscv_aclint_timer) = {
.name = "riscv_aclint_timer",
.id = UCLASS_TIMER,
.of_match = riscv_aclint_timer_ids,
.probe = riscv_aclint_timer_probe,
.ops = &riscv_aclint_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View file

@ -1,68 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <timer.h>
#include <asm/io.h>
#include <dm/device-internal.h>
#include <linux/err.h>
/* mtime register */
#define MTIME_REG(base) ((ulong)(base) + 0xbff8)
static u64 notrace sifive_clint_get_count(struct udevice *dev)
{
return readq((void __iomem *)MTIME_REG(dev_get_priv(dev)));
}
#if CONFIG_IS_ENABLED(RISCV_MMODE) && IS_ENABLED(CONFIG_TIMER_EARLY)
/**
* timer_early_get_rate() - Get the timer rate before driver model
*/
unsigned long notrace timer_early_get_rate(void)
{
return RISCV_MMODE_TIMER_FREQ;
}
/**
* timer_early_get_count() - Get the timer count before driver model
*
*/
u64 notrace timer_early_get_count(void)
{
return readq((void __iomem *)MTIME_REG(RISCV_MMODE_TIMERBASE));
}
#endif
static const struct timer_ops sifive_clint_ops = {
.get_count = sifive_clint_get_count,
};
static int sifive_clint_probe(struct udevice *dev)
{
dev_set_priv(dev, dev_read_addr_ptr(dev));
if (!dev_get_priv(dev))
return -EINVAL;
return timer_timebase_fallback(dev);
}
static const struct udevice_id sifive_clint_ids[] = {
{ .compatible = "riscv,clint0" },
{ .compatible = "sifive,clint0" },
{ }
};
U_BOOT_DRIVER(sifive_clint) = {
.name = "sifive_clint",
.id = UCLASS_TIMER,
.of_match = sifive_clint_ids,
.probe = sifive_clint_probe,
.ops = &sifive_clint_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View file

@ -11,8 +11,8 @@
#define CFG_SYS_SDRAM_BASE 0x80000000
#define RISCV_MMODE_TIMERBASE 0x2000000
#define RISCV_MMODE_TIMEROFF 0xbff8
#define RISCV_MMODE_TIMER_FREQ 1000000
#define RISCV_SMODE_TIMER_FREQ 1000000
/* Environment options */

View file

@ -14,8 +14,8 @@
#define CFG_SYS_SDRAM_BASE 0x80000000
#define RISCV_MMODE_TIMERBASE 0x2000000
#define RISCV_MMODE_TIMEROFF 0xbff8
#define RISCV_MMODE_TIMER_FREQ 1000000
#define RISCV_SMODE_TIMER_FREQ 1000000
/* Environment options */

View file

@ -9,6 +9,7 @@
#define _STARFIVE_VISIONFIVE2_H
#define RISCV_MMODE_TIMERBASE 0x2000000
#define RISCV_MMODE_TIMEROFF 0xbff8
#define RISCV_MMODE_TIMER_FREQ 4000000
#define RISCV_SMODE_TIMER_FREQ 4000000

View file

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2023 Yixun Lan <dlan@gentoo.org>
*
*/
#ifndef __TH1520_LPI4A_H
#define __TH1520_LPI4A_H
#include <linux/sizes.h>
#define CFG_SYS_SDRAM_BASE 0x00000000
#define UART_BASE 0xffe7014000
#define UART_REG_WIDTH 32
/* Environment options */
#define CFG_EXTRA_ENV_SETTINGS \
"PS1=[LPi4A]# \0"
#endif /* __TH1520_LPI4A_H */