CI result shows no issue:
https://source.denx.de/u-boot/custodians/u-boot-riscv/-/pipelines/22315
----------------------------------------------------------------
- Aspeed: Add AST2700 board (Ibex RISC-V core) support
        - Add timer, dram controller, network support
- Sophgo: Add clock controller support for Milk-V Duo
This commit is contained in:
Tom Rini
2024-09-12 09:03:40 -06:00
50 changed files with 14220 additions and 51 deletions

View File

@@ -46,6 +46,9 @@ config TARGET_TH1520_LPI4A
config TARGET_XILINX_MBV
bool "Support AMD/Xilinx MicroBlaze V"
config TARGET_ASPEED_AST2700_IBEX
bool "Support Ibex RISC-V cores on Aspeed AST2700 SoC"
endchoice
config SYS_ICACHE_OFF
@@ -81,6 +84,7 @@ config SPL_ZERO_MEM_BEFORE_USE
# board-specific options below
source "board/andestech/ae350/Kconfig"
source "board/aspeed/ibex_ast2700/Kconfig"
source "board/emulation/qemu-riscv/Kconfig"
source "board/microchip/mpfs_icicle/Kconfig"
source "board/openpiton/riscv64/Kconfig"
@@ -97,6 +101,7 @@ source "arch/riscv/cpu/andes/Kconfig"
source "arch/riscv/cpu/cv1800b/Kconfig"
source "arch/riscv/cpu/fu540/Kconfig"
source "arch/riscv/cpu/fu740/Kconfig"
source "arch/riscv/cpu/ast2700/Kconfig"
source "arch/riscv/cpu/generic/Kconfig"
source "arch/riscv/cpu/jh7110/Kconfig"
@@ -308,7 +313,10 @@ config TPL_USE_ARCH_STRNCMP
endmenu
config RISCV_ISA_A
def_bool y
bool "Standard extension for Atomic Instructions"
default y
help
Adds "A" to the ISA string passed to the compiler.
config DMA_ADDR_T_64BIT
bool
@@ -450,7 +458,7 @@ config RISCV_PRIV_1_9
memory is configured was also changed.
config STACK_SIZE_SHIFT
int
int "Stack size shift"
default 14
config OF_BOARD_FIXUP

View File

@@ -0,0 +1,6 @@
config RISCV_AST2700
bool
imply CPU
imply CPU_RISCV
help
Run U-Boot on AST2700 with IBex RISC-V CPU integrated.

View File

@@ -0,0 +1 @@
obj-y += cpu.o

View File

@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
* Copyright (C) 2024, Aspeed Technology Inc.
*/
#include <irq_func.h>
#include <asm/cache.h>
/*
* cleanup_before_linux() is called just before we call linux
* it prepares the processor for linux
*
* we disable interrupt and caches.
*/
int cleanup_before_linux(void)
{
disable_interrupts();
cache_flush();
return 0;
}

View File

@@ -44,8 +44,6 @@ SECTIONS
__binman_sym_end = .;
} > .spl_mem
. = ALIGN(8);
_end = .;
_image_binary_end = .;

View File

@@ -11,6 +11,7 @@ dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
dtb-$(CONFIG_TARGET_STARFIVE_VISIONFIVE2) += jh7110-starfive-visionfive-2.dtb
dtb-$(CONFIG_TARGET_TH1520_LPI4A) += th1520-lichee-pi-4a.dtb
dtb-$(CONFIG_TARGET_XILINX_MBV) += xilinx-mbv32.dtb
dtb-$(CONFIG_TARGET_ASPEED_AST2700_IBEX) += ast2700-ibex.dtb
include $(srctree)/scripts/Makefile.dts

View File

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/dts-v1/;
#include "ast2700.dtsi"
/ {
chosen {
stdout-path = &uart12;
tick-timer = &ast_ibex_timer;
};
memory@0 {
device_type = "memory";
reg = <0x80000000 0x40000000>;
};
};
&uart12 {
status = "okay";
clock-frequency = <1846153>;
};

View File

@@ -0,0 +1,40 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/ {
cpus {
bootph-all;
};
memory@80000000 {
bootph-all;
};
soc0: soc@12000000 {
bootph-all;
sdrammc: sdrammc@12c00000 {
bootph-all;
};
syscon0: syscon@12c02000 {
bootph-all;
};
};
soc1: soc@14000000 {
bootph-all;
syscon1: syscon@14c02000 {
bootph-all;
};
uart12: serial@14c33b00 {
bootph-all;
};
ast_ibex_timer: timer {
bootph-all;
};
};
};

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0+
/ {
model = "Aspeed AST2700 Ibex BootMCU";
compatible = "aspeed,ast2700-ibex";
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "lowrisc,ibex";
device_type = "cpu";
reg = <0>;
comptaible = "riscv";
riscv,isa = "rv32imc";
};
};
memory@80000000 {
reg = <0x80000000 0x80000000>;
};
soc0: soc@12000000 {
compatible = "aspeed,soc1","simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
sdrammc: sdrammc@12c00000 {
compatible = "aspeed,ast2700-sdrammc";
reg = <0x12c00000 0x3000>, <0x13000000 0x1000>;
aspeed,scu0 = <&syscon0>;
aspeed,scu1 = <&syscon1>;
};
syscon0: syscon@12c02000 {
compatible = "aspeed,ast2700-scu0", "syscon", "simple-mfd";
reg = <0x12c02000 0x1000>;
ranges = <0 0x12c02000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
soc1: soc@14000000 {
compatible = "aspeed,soc1","simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
syscon1: syscon@14c02000 {
compatible = "aspeed,ast2700-scu1", "syscon", "simple-mfd";
reg = <0x14c02000 0x1000>;
ranges = <0 0x14c02000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
};
uart12: serial@14c33b00 {
compatible = "ns16550a";
reg = <0x14c33b00 0x20>;
reg-shift = <2>;
no-loopback-test;
clock-frequency = <1846153>;
status = "disabled";
};
ast_ibex_timer: timer {
compatible = "aspeed,ast2700-ibex-timer";
clock-frequency = <200000000>;
};
};
};

View File

@@ -5,6 +5,7 @@
*/
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/sophgo,cv1800.h>
/ {
#address-cells = <1>;
@@ -45,13 +46,6 @@
#clock-cells = <0>;
};
sdhci_clk: sdhci-clock {
compatible = "fixed-clock";
clock-frequency = <375000000>;
clock-output-names = "sdhci_clk";
#clock-cells = <0>;
};
eth_csrclk: eth-csrclk {
compatible = "fixed-clock";
clock-frequency = <250000000>;
@@ -66,13 +60,6 @@
#clock-cells = <0x0>;
};
spif_clk: spi-flash-clock {
compatible = "fixed-clock";
clock-frequency = <300000000>;
clock-output-names = "spif_clk";
#clock-cells = <0>;
};
soc {
compatible = "simple-bus";
interrupt-parent = <&plic>;
@@ -163,8 +150,8 @@
compatible = "sophgo,cv1800b-dwmac";
reg = <0x04070000 0x10000>;
interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&eth_csrclk>, <&eth_ptpclk>;
clock-names = "stmmaceth", "ptp_ref";
clocks = <&clk CLK_ETH0_500M>, <&clk CLK_AXI4_ETH0>;
clock-names = "stmmaceth", "pclk";
status = "disabled";
};
@@ -172,7 +159,8 @@
compatible = "snps,dw-apb-uart";
reg = <0x04140000 0x100>;
interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc>;
clocks = <&clk CLK_UART0>, <&clk CLK_APB_UART0>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
@@ -182,7 +170,8 @@
compatible = "snps,dw-apb-uart";
reg = <0x04150000 0x100>;
interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc>;
clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
@@ -192,7 +181,8 @@
compatible = "snps,dw-apb-uart";
reg = <0x04160000 0x100>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc>;
clocks = <&clk CLK_UART2>, <&clk CLK_APB_UART2>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
@@ -202,7 +192,8 @@
compatible = "snps,dw-apb-uart";
reg = <0x04170000 0x100>;
interrupts = <47 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc>;
clocks = <&clk CLK_UART3>, <&clk CLK_APB_UART3>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
@@ -212,7 +203,8 @@
compatible = "snps,dw-apb-uart";
reg = <0x041c0000 0x100>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc>;
clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
@@ -222,8 +214,8 @@
compatible = "sophgo,cv1800b-dwcmshc";
reg = <0x4310000 0x1000>;
interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdhci_clk>;
clock-names = "core";
clocks = <&clk CLK_AXI4_SD0>, <&clk CLK_SD0>;
clock-names = "core", "bus";
status = "disabled";
};
@@ -232,7 +224,7 @@
reg = <0x10000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spif_clk>;
clocks = <&clk CLK_AHB_SF>;
interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};

View File

@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) ASPEED Technology Inc.
*/
#ifndef __ASM_AST2700_FMC_HDR_H__
#define __ASM_AST2700_FMC_HDR_H__
#include <linux/types.h>
#define HDR_MAGIC 0x48545341 /* ASTH */
#define HDR_PB_MAX 30
enum prebuilt_type {
PBT_END_MARK = 0x0,
PBT_DDR4_PMU_TRAIN_IMEM,
PBT_DDR4_PMU_TRAIN_DMEM,
PBT_DDR4_2D_PMU_TRAIN_IMEM,
PBT_DDR4_2D_PMU_TRAIN_DMEM,
PBT_DDR5_PMU_TRAIN_IMEM,
PBT_DDR5_PMU_TRAIN_DMEM,
PBT_DP_FW,
PBT_UEFI_X64_AST2700,
PBT_NUM
};
struct fmc_hdr_preamble {
uint32_t magic;
uint32_t version;
};
struct fmc_hdr_body {
uint32_t fmc_size;
union {
struct {
uint32_t type;
uint32_t size;
} pbs[0];
uint32_t raz[29];
};
};
struct fmc_hdr {
struct fmc_hdr_preamble preamble;
struct fmc_hdr_body body;
} __packed;
int fmc_hdr_get_prebuilt(uint32_t type, uint32_t *ofst, uint32_t *size);
#endif

View File

@@ -0,0 +1,145 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) Aspeed Technology Inc.
*/
#ifndef __ASM_AST2700_SCU_H__
#define __ASM_AST2700_SCU_H__
/* SCU0: CPU-die SCU */
#define SCU0_HWSTRAP 0x010
#define SCU0_HWSTRAP_DIS_RVAS BIT(30)
#define SCU0_HWSTRAP_DIS_WDTFULL BIT(25)
#define SCU0_HWSTRAP_DISARMICE_TZ BIT(22)
#define SCU0_HWSTRAP_DISABLE_XHCI BIT(21)
#define SCU0_HWSTRAP_BOOTEMMCSPEED BIT(20)
#define SCU0_HWSTRAP_VGA_CC BIT(18)
#define SCU0_HWSTRAP_EN_OPROM BIT(17)
#define SCU0_HWSTRAP_DISARMICE BIT(16)
#define SCU0_HWSTRAP_TSPRSNTSEL BIT(9)
#define SCU0_HWSTRAP_DISDEBUG BIT(8)
#define SCU0_HWSTRAP_HCLKHPLL BIT(7)
#define SCU0_HWSTRAP_HCLKSEL GENMASK(6, 5)
#define SCU0_HWSTRAP_CPUHPLL BIT(4)
#define SCU0_HWSTRAP_HPLLFREQ GENMASK(3, 2)
#define SCU0_HWSTRAP_BOOTSPI BIT(1)
#define SCU0_HWSTRAP_HWSTRAP_DISCPU BIT(0)
#define SCU0_DBGCTL 0x0c8
#define SCU0_DBGCTL_MASK GENMASK(14, 0)
#define SCU0_DBGCTL_UARTDBG BIT(1)
#define SCU0_RSTCTL1 0x200
#define SCU0_RSTCTL1_EMMC BIT(17)
#define SCU0_RSTCTL1_HACE BIT(4)
#define SCU0_RSTCTL1_CLR 0x204
#define SCU0_RSTCTL1_CLR_EMMC BIT(17)
#define SCU0_RSTCTL1_CLR_HACE BIT(4)
#define SCU0_CLKGATE1 0x240
#define SCU0_CLKGATE1_EMMC BIT(27)
#define SCU0_CLKGATE1_HACE BIT(13)
#define SCU0_CLKGATE1_DDRPHY BIT(11)
#define SCU0_CLKGATE1_CLR 0x244
#define SCU0_CLKGATE1_CLR_EMMC BIT(27)
#define SCU0_CLKGATE1_CLR_HACE BIT(13)
#define SCU0_CLKGATE1_CLR_DDRPHY BIT(11)
#define SCU0_VGA0_SCRATCH 0x900
#define SCU0_VGA0_SCRATCH_DRAM_INIT BIT(6)
#define SCU0_PCI_MISC70 0xa70
#define SCU0_PCI_MISC70_EN_PCIEXHCI0 BIT(3)
#define SCU0_PCI_MISC70_EN_PCIEEHCI0 BIT(2)
#define SCU0_PCI_MISC70_EN_PCIEVGA0 BIT(0)
#define SCU0_PCI_MISC80 0xa80
#define SCU0_PCI_MISC80_EN_PCIEXHCI1 BIT(3)
#define SCU0_PCI_MISC80_EN_PCIEEHCI1 BIT(2)
#define SCU0_PCI_MISC80_EN_PCIEVGA1 BIT(0)
#define SCU0_PCI_MISCF0 0xaf0
#define SCU0_PCI_MISCF0_EN_PCIEXHCI1 BIT(3)
#define SCU0_PCI_MISCF0_EN_PCIEEHCI1 BIT(2)
#define SCU0_PCI_MISCF0_EN_PCIEVGA1 BIT(0)
#define SCU0_WPROT1 0xe04
#define SCU0_WPROT1_0C8 BIT(18)
/* SCU1: IO-die SCU */
#define SCU1_REVISION 0x000
#define SCU1_REVISION_HWID GENMASK(23, 16)
#define SCU1_REVISION_CHIP_EFUSE GENMASK(15, 8)
#define SCU1_HWSTRAP1 0x010
#define SCU1_HWSTRAP1_DIS_CPTRA BIT(30)
#define SCU1_HWSTRAP1_RECOVERY_USB_PORT GENMASK(29, 28)
#define SCU1_HWSTRAP1_RECOVERY_INTERFACE GENMASK(27, 26)
#define SCU1_HWSTRAP1_RECOVERY_I3C (BIT(26) | BIT(27))
#define SCU1_HWSTRAP1_RECOVERY_I2C BIT(27)
#define SCU1_HWSTRAP1_RECOVERY_USB BIT(26)
#define SCU1_HWSTRAP1_SPI_FLASH_4_BYTE_MODE BIT(25)
#define SCU1_HWSTRAP1_SPI_FLASH_WAIT_READY BIT(24)
#define SCU1_HWSTRAP1_BOOT_UFS BIT(23)
#define SCU1_HWSTRAP1_DIS_ROM BIT(22)
#define SCU1_HWSTRAP1_DIS_CPTRAJTAG BIT(20)
#define SCU1_HWSTRAP1_UARTDBGSEL BIT(19)
#define SCU1_HWSTRAP1_DIS_UARTDBG BIT(18)
#define SCU1_HWSTRAP1_DIS_WDTFULL BIT(17)
#define SCU1_HWSTRAP1_DISDEBUG1 BIT(16)
#define SCU1_HWSTRAP1_LTPI0_IO_DRIVING GENMASK(15, 14)
#define SCU1_HWSTRAP1_ACPI_1 BIT(13)
#define SCU1_HWSTRAP1_ACPI_0 BIT(12)
#define SCU1_HWSTRAP1_BOOT_EMMC_UFS BIT(11)
#define SCU1_HWSTRAP1_DDR4 BIT(10)
#define SCU1_HWSTRAP1_LOW_SECURE BIT(8)
#define SCU1_HWSTRAP1_EN_EMCS BIT(7)
#define SCU1_HWSTRAP1_EN_GPIOPT BIT(6)
#define SCU1_HWSTRAP1_EN_SECBOOT BIT(5)
#define SCU1_HWSTRAP1_EN_RECOVERY_BOOT BIT(4)
#define SCU1_HWSTRAP1_LTPI0_EN BIT(3)
#define SCU1_HWSTRAP1_LTPI_IDX BIT(2)
#define SCU1_HWSTRAP1_LTPI1_EN BIT(1)
#define SCU1_HWSTRAP1_LTPI_MODE BIT(0)
#define SCU1_HWSTRAP2 0x030
#define SCU1_HWSTRAP2_FMC_ABR_SINGLE_FLASH BIT(29)
#define SCU1_HWSTRAP2_FMC_ABR_CS_SWAP_DIS BIT(28)
#define SCU1_HWSTRAP2_SPI_TPM_PCR_EXT_EN BIT(27)
#define SCU1_HWSTRAP2_SPI_TPM_HASH_ALGO GENMASK(26, 25)
#define SCU1_HWSTRAP2_BOOT_SPI_FREQ GENMASK(24, 23)
#define SCU1_HWSTRAP2_RESERVED GENMASK(22, 19)
#define SCU1_HWSTRAP2_FWSPI_CRTM GENMASK(18, 17)
#define SCU1_HWSTRAP2_EN_FWSPIAUX BIT(16)
#define SCU1_HWSTRAP2_FWSPISIZE GENMASK(15, 13)
#define SCU1_HWSTRAP2_DIS_REC BIT(12)
#define SCU1_HWSTRAP2_EN_CPTRA_DBG BIT(11)
#define SCU1_HWSTRAP2_TPM_PCR_INDEX GENMASK(6, 2)
#define SCU1_HWSTRAP2_ROM_CLEAR_SRAM BIT(1)
#define SCU1_HWSTRAP2_ABR BIT(0)
#define SCU1_RSTLOG0 0x050
#define SCU1_RSTLOG0_BMC_CPU BIT(12)
#define SCU1_RSTLOG0_ABR BIT(2)
#define SCU1_RSTLOG0_EXTRSTN BIT(1)
#define SCU1_RSTLOG0_SRST BIT(0)
#define SCU1_MISC1 0x0c0
#define SCU1_MISC1_UARTDBG_ROUTE GENMASK(23, 22)
#define SCU1_MISC1_UART12_ROUTE GENMASK(21, 20)
#define SCU1_DBGCTL 0x0c8
#define SCU1_DBGCTL_MASK GENMASK(7, 0)
#define SCU1_DBGCTL_UARTDBG BIT(6)
#define SCU1_RNG_DATA 0x0f4
#define SCU1_RSTCTL1 0x200
#define SCU1_RSTCTL1_I3C(x) (BIT(16) << (x))
#define SCU1_RSTCTL1_CLR 0x204
#define SCU1_RSTCTL1_CLR_I3C(x) (BIT(16) << (x))
#define SCU1_RSTCTL2 0x220
#define SCU1_RSTCTL2_LTPI1 BIT(22)
#define SCU1_RSTCTL2_LTPI0 BIT(20)
#define SCU1_RSTCTL2_I2C BIT(15)
#define SCU1_RSTCTL2_CPTRA BIT(9)
#define SCU1_RSTCTL2_CLR 0x224
#define SCU1_RSTCTL2_CLR_I2C BIT(15)
#define SCU1_RSTCTL2_CLR_CPTRA BIT(9)
#define SCU1_CLKGATE1 0x240
#define SCU1_CLKGATE1_I3C(x) (BIT(16) << (x))
#define SCU1_CLKGATE1_I2C BIT(15)
#define SCU1_CLKGATE1_CLR 0x244
#define SCU1_CLKGATE1_CLR_I3C(x) (BIT(16) << (x))
#define SCU1_CLKGATE1_CLR_I2C BIT(15)
#define SCU1_CLKGATE2 0x260
#define SCU1_CLKGATE2_LTPI1_TX BIT(19)
#define SCU1_CLKGATE2_LTPI_AHB BIT(10)
#define SCU1_CLKGATE2_LTPI0_TX BIT(9)
#define SCU1_CLKGATE2_CLR 0x264
#endif

View File

@@ -0,0 +1,137 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) Aspeed Technology Inc.
*/
#ifndef __ASM_AST2700_SDRAM_H__
#define __ASM_AST2700_SDRAM_H__
struct sdrammc_regs {
u32 prot_key;
u32 intr_status;
u32 intr_clear;
u32 intr_mask;
u32 mcfg;
u32 mctl;
u32 msts;
u32 error_status;
u32 actime1;
u32 actime2;
u32 actime3;
u32 actime4;
u32 actime5;
u32 actime6;
u32 actime7;
u32 dfi_timing;
u32 dcfg;
u32 dctl;
u32 mrctl;
u32 mrwr;
u32 mrrd;
u32 mr01;
u32 mr23;
u32 mr45;
u32 mr67;
u32 refctl;
u32 refmng_ctl;
u32 refsts;
u32 zqctl;
u32 ecc_addr_range;
u32 ecc_failure_status;
u32 ecc_failure_addr;
u32 ecc_test_control;
u32 ecc_test_status;
u32 arbctl;
u32 enccfg;
u32 protect_lock_set;
u32 protect_lock_status;
u32 protect_lock_reset;
u32 enc_min_addr;
u32 enc_max_addr;
u32 enc_key[4];
u32 enc_iv[3];
u32 bistcfg;
u32 bist_addr;
u32 bist_size;
u32 bist_patt;
u32 bist_res;
u32 bist_fail_addr;
u32 bist_fail_data[4];
u32 reserved2[2];
u32 debug_control;
u32 debug_status;
u32 phy_intf_status;
u32 testcfg;
u32 gfmcfg;
u32 gfm0ctl;
u32 gfm1ctl;
u32 reserved3[0xf8];
};
#define DRAMC_UNLK_KEY 0x1688a8a8
/* offset 0x04 */
#define DRAMC_IRQSTA_PWRCTL_ERR BIT(16)
#define DRAMC_IRQSTA_PHY_ERR BIT(15)
#define DRAMC_IRQSTA_LOWPOWER_DONE BIT(12)
#define DRAMC_IRQSTA_FREQ_CHG_DONE BIT(11)
#define DRAMC_IRQSTA_REF_DONE BIT(10)
#define DRAMC_IRQSTA_ZQ_DONE BIT(9)
#define DRAMC_IRQSTA_BIST_DONE BIT(8)
#define DRAMC_IRQSTA_ECC_RCVY_ERR BIT(5)
#define DRAMC_IRQSTA_ECC_ERR BIT(4)
#define DRAMC_IRQSTA_PROT_ERR BIT(3)
#define DRAMC_IRQSTA_OVERSZ_ERR BIT(2)
#define DRAMC_IRQSTA_MR_DONE BIT(1)
#define DRAMC_IRQSTA_PHY_INIT_DONE BIT(0)
/* offset 0x14 */
#define DRAMC_MCTL_WB_SOFT_RESET BIT(24)
#define DRAMC_MCTL_PHY_CLK_DIS BIT(18)
#define DRAMC_MCTL_PHY_RESET BIT(17)
#define DRAMC_MCTL_PHY_POWER_ON BIT(16)
#define DRAMC_MCTL_FREQ_CHG_START BIT(3)
#define DRAMC_MCTL_PHY_LOWPOWER_START BIT(2)
#define DRAMC_MCTL_SELF_REF_START BIT(1)
#define DRAMC_MCTL_PHY_INIT_START BIT(0)
/* offset 0x40 */
#define DRAMC_DFICFG_WD_POL BIT(18)
#define DRAMC_DFICFG_CKE_OUT BIT(17)
#define DRAMC_DFICFG_RESET BIT(16)
/* offset 0x48 */
#define DRAMC_MRCTL_ERR_STATUS BIT(31)
#define DRAMC_MRCTL_READY_STATUS BIT(30)
#define DRAMC_MRCTL_MR_ADDR BIT(8)
#define DRAMC_MRCTL_CMD_DLL_RST BIT(7)
#define DRAMC_MRCTL_CMD_DQ_SEL BIT(6)
#define DRAMC_MRCTL_CMD_TYPE BIT(2)
#define DRAMC_MRCTL_CMD_WR_CTL BIT(1)
#define DRAMC_MRCTL_CMD_START BIT(0)
/* offset 0xC0 */
#define DRAMC_BISTRES_RUNNING BIT(10)
#define DRAMC_BISTRES_FAIL BIT(9)
#define DRAMC_BISTRES_DONE BIT(8)
#define DRAMC_BISTCFG_INIT_MODE BIT(7)
#define DRAMC_BISTCFG_PMODE GENMASK(6, 4)
#define DRAMC_BISTCFG_BMODE GENMASK(3, 2)
#define DRAMC_BISTCFG_ENABLE BIT(1)
#define DRAMC_BISTCFG_START BIT(0)
#define BIST_PMODE_CRC (3)
#define BIST_BMODE_RW_SWITCH (3)
/* DRAMC048 MR Control Register */
#define MR_TYPE_SHIFT 2
#define MR_RW (0 << MR_TYPE_SHIFT)
#define MR_MPC BIT(2)
#define MR_VREFCS (2 << MR_TYPE_SHIFT)
#define MR_VREFCA (3 << MR_TYPE_SHIFT)
#define MR_ADDRESS_SHIFT 8
#define MR_ADDR(n) (((n) << MR_ADDRESS_SHIFT) | DRAMC_MRCTL_CMD_WR_CTL)
#define MR_NUM_SHIFT 4
#define MR_NUM(n) ((n) << MR_NUM_SHIFT)
#define MR_DLL_RESET BIT(7)
#define MR_1T_MODE BIT(16)
#endif

View File

@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) Aspeed Technology Inc.
*/
#ifndef __ASM_AST2700_SLI_H__
#define __ASM_AST2700_SLI_H__
#define SLI_CPU_ADRBASE 0x12c17000
#define SLI_IOD_ADRBASE 0x14c1e000
#define SLIM_CPU_BASE (SLI_CPU_ADRBASE + 0x000)
#define SLIH_CPU_BASE (SLI_CPU_ADRBASE + 0x200)
#define SLIV_CPU_BASE (SLI_CPU_ADRBASE + 0x400)
#define SLIM_IOD_BASE (SLI_IOD_ADRBASE + 0x000)
#define SLIH_IOD_BASE (SLI_IOD_ADRBASE + 0x200)
#define SLIV_IOD_BASE (SLI_IOD_ADRBASE + 0x400)
#define SLI_CTRL_I 0x00
#define SLIV_RAW_MODE BIT(15)
#define SLI_TX_MODE BIT(14)
#define SLI_RX_PHY_LAH_SEL_REV BIT(13)
#define SLI_RX_PHY_LAH_SEL_NEG BIT(12)
#define SLI_AUTO_SEND_TRN_OFF BIT(8)
#define SLI_CLEAR_BUS BIT(6)
#define SLI_TRANS_EN BIT(5)
#define SLI_CLEAR_RX BIT(2)
#define SLI_CLEAR_TX BIT(1)
#define SLI_RESET_TRIGGER BIT(0)
#define SLI_CTRL_II 0x04
#define SLI_CTRL_III 0x08
#define SLI_CLK_SEL GENMASK(31, 28)
#define SLI_CLK_500M 0x6
#define SLI_CLK_200M 0x3
#define SLI_PHYCLK_SEL GENMASK(27, 24)
#define SLI_PHYCLK_25M 0x0
#define SLI_PHYCLK_800M 0x1
#define SLI_PHYCLK_400M 0x2
#define SLI_PHYCLK_200M 0x3
#define SLI_PHYCLK_788M 0x5
#define SLI_PHYCLK_500M 0x6
#define SLI_PHYCLK_250M 0x7
#define SLIH_PAD_DLY_TX1 GENMASK(23, 18)
#define SLIH_PAD_DLY_TX0 GENMASK(17, 12)
#define SLIH_PAD_DLY_RX1 GENMASK(11, 6)
#define SLIH_PAD_DLY_RX0 GENMASK(5, 0)
#define SLIM_PAD_DLY_RX3 GENMASK(23, 18)
#define SLIM_PAD_DLY_RX2 GENMASK(17, 12)
#define SLIM_PAD_DLY_RX1 GENMASK(11, 6)
#define SLIM_PAD_DLY_RX0 GENMASK(5, 0)
#define SLI_CTRL_IV 0x0c
#define SLIM_PAD_DLY_TX3 GENMASK(23, 18)
#define SLIM_PAD_DLY_TX2 GENMASK(17, 12)
#define SLIM_PAD_DLY_TX1 GENMASK(11, 6)
#define SLIM_PAD_DLY_TX0 GENMASK(5, 0)
#define SLI_INTR_EN 0x10
#define SLI_INTR_STATUS 0x14
#define SLI_INTR_RX_SYNC BIT(15)
#define SLI_INTR_RX_ERR BIT(13)
#define SLI_INTR_RX_NACK BIT(12)
#define SLI_INTR_RX_TRAIN_PKT BIT(10)
#define SLI_INTR_RX_DISCONN BIT(6)
#define SLI_INTR_TX_SUSPEND BIT(4)
#define SLI_INTR_TX_TRAIN BIT(3)
#define SLI_INTR_TX_IDLE BIT(2)
#define SLI_INTR_RX_SUSPEND BIT(1)
#define SLI_INTR_RX_IDLE BIT(0)
#define SLI_INTR_RX_ERRORS \
(SLI_INTR_RX_ERR | SLI_INTR_RX_NACK | SLI_INTR_RX_DISCONN)
#define SLIM_MARB_FUNC_I 0x60
#define SLIM_SLI_MARB_RR BIT(0)
#define SLI_TARGET_PHYCLK SLI_PHYCLK_400M
#define SLIH_DEFAULT_DELAY 11
#if (SLI_TARGET_PHYCLK == SLI_PHYCLK_800M) || (SLI_TARGET_PHYCLK == SLI_PHYCLK_788M)
#define SLIM_DEFAULT_DELAY 5
#define SLIM_LAH_CONFIG 1
#else
#define SLIM_DEFAULT_DELAY 12
#define SLIM_LAH_CONFIG 0
#endif
#endif
int sli_init(void);

View File

@@ -0,0 +1,21 @@
if TARGET_ASPEED_AST2700_IBEX
config SYS_BOARD
default "ibex_ast2700"
config SYS_VENDOR
default "aspeed"
config SYS_CPU
default "ast2700"
config SYS_CONFIG_NAME
default "ibex_ast2700"
config BOARD_SPECIFIC_OPTIONS
def_bool y
select RISCV_AST2700
select SUPPORT_SPL
imply SPL_DRIVERS_MISC
endif

View File

@@ -0,0 +1,7 @@
AST2700 using Ibex RISC-V Core as the boot MCU
M: Chia-Wei, Wang <chiawei_wang@aspeedtech.com>
S: Maintained
F: arch/riscv/include/asm/arch-ast2700/
F: board/aspeed/ibex_ast2700/
F: configs/ibex-ast2700_defconfig
F: include/configs/ibex_ast2700.h

View File

@@ -0,0 +1,3 @@
obj-y += ibex_ast2700.o
obj-y += fmc_hdr.o
obj-y += sli.o

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) Aspeed Technology Inc.
*/
#include <asm/arch/fmc_hdr.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <errno.h>
#include <spl.h>
#include <string.h>
int fmc_hdr_get_prebuilt(uint32_t type, uint32_t *ofst, uint32_t *size)
{
struct fmc_hdr_preamble *preamble;
struct fmc_hdr_body *body;
struct fmc_hdr *hdr;
uint32_t t, s, o;
int i;
if (type >= PBT_NUM)
return -EINVAL;
if (!ofst || !size)
return -EINVAL;
hdr = (struct fmc_hdr *)(_start - sizeof(*hdr));
preamble = &hdr->preamble;
body = &hdr->body;
if (preamble->magic != HDR_MAGIC)
return -EIO;
for (i = 0, o = sizeof(*hdr) + body->fmc_size; i < HDR_PB_MAX; ++i) {
t = body->pbs[i].type;
s = body->pbs[i].size;
/* skip if unrecognized, yet */
if (t >= PBT_NUM) {
o += s;
continue;
}
/* prebuilt end mark */
if (t == 0 && s == 0)
break;
/* return the prebuilt info if found */
if (t == type) {
*ofst = o;
*size = s;
goto found;
}
/* update offset for next prebuilt */
o += s;
}
return -ENODATA;
found:
return 0;
}

View File

@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) Aspeed Technology Inc.
*/
#include <asm/io.h>
#include <asm/arch/sli.h>
#include <dm.h>
#include <ram.h>
#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
int ret;
struct udevice *dev;
struct ram_info ram;
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
if (ret) {
printf("cannot get DRAM driver\n");
return ret;
}
ret = ram_get_info(dev, &ram);
if (ret) {
printf("cannot get DRAM information\n");
return ret;
}
gd->ram_size = ram.size;
return 0;
}
int spl_board_init_f(void)
{
sli_init();
dram_init();
return 0;
}
struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
{
return (struct legacy_img_hdr *)CONFIG_SYS_LOAD_ADDR;
}
void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len)
{
return (void *)spl_get_load_buffer(sectors, bl_len);
}
u32 spl_boot_device(void)
{
return BOOT_DEVICE_RAM;
}
int board_init(void)
{
struct udevice *dev;
int i = 0;
int ret;
/*
* Loop over all MISC uclass drivers to call the comphy code
* and init all CP110 devices enabled in the DT
*/
while (1) {
/* Call the comphy code via the MISC uclass driver */
ret = uclass_get_device(UCLASS_MISC, i++, &dev);
/* We're done, once no further CP110 device is found */
if (ret)
break;
}
return 0;
}
int board_late_init(void)
{
return 0;
}

View File

@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) Aspeed Technology Inc.
*/
#include <asm/io.h>
#include <asm/arch/sli.h>
#include <asm/arch/scu.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#define SLI_POLL_TIMEOUT_US 100
static void sli_clear_interrupt_status(uint32_t base)
{
writel(-1, (void *)base + SLI_INTR_STATUS);
}
static int sli_wait(uint32_t base, uint32_t mask)
{
uint32_t value;
sli_clear_interrupt_status(base);
do {
value = readl((void *)base + SLI_INTR_STATUS);
if (value & SLI_INTR_RX_ERRORS)
return -1;
} while ((value & mask) != mask);
return 0;
}
static int sli_wait_suspend(uint32_t base)
{
return sli_wait(base, SLI_INTR_TX_SUSPEND | SLI_INTR_RX_SUSPEND);
}
/*
* CPU die --- downstream pads ---> I/O die
* CPU die <--- upstream pads ----- I/O die
*
* US/DS PAD[3:0] : SLIM[3:0]
* US/DS PAD[5:4] : SLIH[1:0]
* US/DS PAD[7:6] : SLIV[1:0]
*/
int sli_init(void)
{
uint32_t value;
/* The following training sequence is designed for AST2700A0 */
value = FIELD_GET(SCU1_REVISION_HWID, readl(SCU1_REVISION));
if (value)
return 0;
/* Return if SLI had been calibrated */
value = readl((void *)SLIH_IOD_BASE + SLI_CTRL_III);
value = FIELD_GET(SLI_CLK_SEL, value);
if (value) {
debug("SLI has been initialized\n");
return 0;
}
/* 25MHz PAD delay for AST2700A0 */
value = SLI_RX_PHY_LAH_SEL_NEG | SLI_TRANS_EN | SLI_CLEAR_BUS;
writel(value, (void *)SLIH_IOD_BASE + SLI_CTRL_I);
writel(value, (void *)SLIM_IOD_BASE + SLI_CTRL_I);
writel(value | SLIV_RAW_MODE, (void *)SLIV_IOD_BASE + SLI_CTRL_I);
sli_wait_suspend(SLIH_IOD_BASE);
sli_wait_suspend(SLIH_CPU_BASE);
return 0;
}

View File

@@ -0,0 +1,94 @@
CONFIG_RISCV=y
CONFIG_SYS_DCACHE_OFF=y
# CONFIG_SPL_USE_ARCH_MEMCPY is not set
# CONFIG_SPL_USE_ARCH_MEMMOVE is not set
# CONFIG_SPL_USE_ARCH_MEMSET is not set
CONFIG_TEXT_BASE=0x80000000
CONFIG_SYS_MALLOC_LEN=0xf00
CONFIG_SYS_MALLOC_F_LEN=0xf00
CONFIG_NR_DRAM_BANKS=1
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x14bd7800
CONFIG_ENV_SIZE=0x20000
CONFIG_DEFAULT_DEVICE_TREE="ast2700-ibex"
CONFIG_SPL_TEXT_BASE=0x14bc0080
CONFIG_DM_RESET=y
CONFIG_SPL_BSS_START_ADDR=0x14bd7800
CONFIG_SPL_BSS_MAX_SIZE=0x800
CONFIG_SPL_SIZE_LIMIT=0x16000
CONFIG_SPL=y
CONFIG_SYS_MEM_TOP_HIDE=0x10000000
CONFIG_SYS_LOAD_ADDR=0x83000000
CONFIG_BUILD_TARGET=""
CONFIG_TARGET_ASPEED_AST2700_IBEX=y
# CONFIG_RISCV_ISA_F is not set
# CONFIG_RISCV_ISA_A is not set
# CONFIG_SPL_SMP is not set
CONFIG_XIP=y
CONFIG_SPL_XIP=y
# CONFIG_AVAILABLE_HARTS is not set
CONFIG_STACK_SIZE_SHIFT=11
CONFIG_ENV_VARS_UBOOT_CONFIG=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_STACK_SIZE=0x100000
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_LOAD_FIT_ADDRESS=0x200c0000
# CONFIG_BOOTSTD is not set
CONFIG_SYS_BOOTM_LEN=0x4000000
# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
CONFIG_SYS_CBSIZE=256
CONFIG_SYS_PBSIZE=276
# CONFIG_CONSOLE_FLUSH_SUPPORT is not set
# CONFIG_CONSOLE_MUX is not set
CONFIG_SYS_STDIO_DEREGISTER=y
CONFIG_BOARD_LATE_INIT=y
CONFIG_SPL_MAX_SIZE=0x16000
# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
CONFIG_SPL_RAM_SUPPORT=y
CONFIG_SPL_RAM_DEVICE=y
# CONFIG_CMD_BOOTD is not set
# CONFIG_CMD_BOOTI is not set
# CONFIG_BOOTM_LINUX is not set
# 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_CMD_ELF is not set
# CONFIG_CMD_FDT is not set
# CONFIG_CMD_IMI is not set
# CONFIG_CMD_XIMG is not set
# CONFIG_CMD_SAVEENV is not set
# CONFIG_CMD_CRC32 is not set
# CONFIG_CMD_LOADS is not set
CONFIG_CMD_SYSBOOT=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_DEVICE_TREE_INCLUDES="ast2700-u-boot.dtsi"
# CONFIG_OF_TAG_MIGRATE is not set
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
# CONFIG_NET is not set
CONFIG_SYS_RX_ETH_BUFFER=2
# CONFIG_DM_DEVICE_REMOVE is not set
# CONFIG_DM_SEQ_ALIAS is not set
# CONFIG_BLOCK_CACHE is not set
# CONFIG_CPU is not set
# CONFIG_GPIO is not set
# CONFIG_I2C is not set
CONFIG_MMC=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_SDHCI=y
# CONFIG_MTD is not set
# CONFIG_POWER is not set
CONFIG_RAM=y
CONFIG_SPL_RAM=y
CONFIG_ASPEED_RAM=y
# CONFIG_RAM_SIFIVE is not set
CONFIG_SYS_NS16550=y
CONFIG_SYS_NS16550_MEM32=y
CONFIG_AST_IBEX_TIMER=y
CONFIG_VIDEO=y
# CONFIG_VIDEO_LOGO is not set
# CONFIG_RSA is not set
# CONFIG_EFI_LOADER is not set

View File

@@ -1,6 +1,6 @@
CONFIG_RISCV=y
CONFIG_SYS_MALLOC_LEN=0x820000
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_NR_DRAM_BANKS=1
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x82300000
@@ -26,6 +26,7 @@ CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_ENV_OVERWRITE=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_CLK_SOPHGO_CV1800B=y
CONFIG_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y

View File

@@ -0,0 +1,26 @@
.. SPDX-License-Identifier: GPL-2.0+
IBex AST2700
============
AST2700 integrates an IBex RISC-V 32-bits CPU as the boot MCU to execute the
first stage bootlaoder, namely SPL.
Build
-----
1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
2. Use `make ibex-ast2700_defconfig` in u-boot root to build the image
Running U-Boot SPL
------------------
The U-Boot SPL will boot in M mode and load the FIT image which includes
the 2nd stage bootloaders executed by the main processor Cortex-A35.
Burn U-Boot to SPI Flash
------------------------
Use SPI flash programmer (e.g. SF100) to program the u-book-spl.bin with the
offset 0x80 bytes to the SPI flash beginning.

View File

@@ -0,0 +1,9 @@
.. SPDX-License-Identifier: GPL-2.0+
Aspeed
======
.. toctree::
:maxdepth: 2
ibex-ast2700

View File

@@ -14,6 +14,7 @@ Board-specific doc
anbernic/index
apple/index
armltd/index
aspeed/index
asus/index
atmel/index
beacon/index

View File

@@ -257,6 +257,7 @@ source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/owl/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/sophgo/Kconfig"
source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/sifive/Kconfig"
source "drivers/clk/starfive/Kconfig"

View File

@@ -44,6 +44,7 @@ obj-$(CONFIG_CLK_QCOM) += qcom/
obj-$(CONFIG_CLK_RENESAS) += renesas/
obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_CLK_SOPHGO) += sophgo/
obj-$(CONFIG_CLK_SUNXI) += sunxi/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o

View File

@@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
config CLK_SOPHGO
bool
config CLK_SOPHGO_CV1800B
bool "Sophgo CV1800B clock support"
depends on CLK
select CLK_CCF
select CLK_SOPHGO
help
This enables support clock driver for Sophgo CV1800B SoC.

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
obj-y += clk-ip.o clk-pll.o
obj-$(CONFIG_CLK_SOPHGO_CV1800B) += clk-cv1800b.o

View File

@@ -0,0 +1,74 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
*
*/
#ifndef __CLK_SOPHGO_COMMON_H__
#define __CLK_SOPHGO_COMMON_H__
#include <linux/bitops.h>
#include <linux/io.h>
#define CV1800B_CLK_OSC 1
#define CV1800B_CLK_BYPASS 2
#define CV1800B_CLK_ID_TRANSFORM(_id) ((_id) + 3)
struct cv1800b_clk_regbit {
u32 offset;
u8 shift;
};
struct cv1800b_clk_regfield {
u32 offset;
u8 shift;
u8 width;
};
#define CV1800B_CLK_REGBIT(_offset, _shift) \
{ \
.offset = _offset, \
.shift = _shift, \
}
#define CV1800B_CLK_REGFIELD(_offset, _shift, _width) \
{ \
.offset = _offset, \
.shift = _shift, \
.width = _width, \
}
static inline u32 cv1800b_clk_getbit(void *base, struct cv1800b_clk_regbit *bit)
{
return readl(base + bit->offset) & (BIT(bit->shift));
}
static inline u32 cv1800b_clk_setbit(void *base, struct cv1800b_clk_regbit *bit)
{
return setbits_le32(base + bit->offset, BIT(bit->shift));
}
static inline u32 cv1800b_clk_clrbit(void *base, struct cv1800b_clk_regbit *bit)
{
return clrbits_le32(base + bit->offset, BIT(bit->shift));
}
static inline u32 cv1800b_clk_getfield(void *base,
struct cv1800b_clk_regfield *field)
{
u32 mask = GENMASK(field->shift + field->width - 1, field->shift);
return (readl(base + field->offset) & mask) >> field->shift;
}
static inline void
cv1800b_clk_setfield(void *base, struct cv1800b_clk_regfield *field, u32 val)
{
u32 mask = GENMASK(field->shift + field->width - 1, field->shift);
u32 new_val = (readl(base + field->offset) & ~mask) |
((val << field->shift) & mask);
return writel(new_val, base + field->offset);
}
#endif /* __CLK_SOPHGO_COMMON_H__ */

View File

@@ -0,0 +1,754 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
*/
#include <clk-uclass.h>
#include <dm.h>
#include <linux/clk-provider.h>
#include "clk-common.h"
#include "clk-cv1800b.h"
#include "clk-ip.h"
#include "clk-pll.h"
static const char *const clk_cam_parents[] = {
"clk_cam0pll",
"clk_cam0pll_d2",
"clk_cam0pll_d3",
"clk_mipimpll_d3"
};
static const char *const clk_tpu_parents[] = {
"clk_tpll",
"clk_a0pll",
"clk_mipimpll",
"clk_fpll"
};
static const char *const clk_axi4_parents[] = { "clk_fpll", "clk_disppll" };
static const char *const clk_aud_parents[] = { "clk_a0pll", "clk_a24m" };
static const char *const clk_cam0_200_parents[] = { "osc", "clk_disppll" };
static const char *const clk_vip_sys_parents[] = {
"clk_mipimpll",
"clk_cam0pll",
"clk_disppll",
"clk_fpll"
};
static const char *const clk_axi_video_codec_parents[] = {
"clk_a0pll",
"clk_mipimpll",
"clk_cam1pll",
"clk_fpll"
};
static const char *const clk_vc_src0_parents[] = {
"clk_disppll",
"clk_mipimpll",
"clk_cam1pll",
"clk_fpll"
};
static const struct cv1800b_mmux_parent_info clk_c906_0_parents[] = {
{ "clk_tpll", 0, 0 },
{ "clk_a0pll", 0, 1 },
{ "clk_mipimpll", 0, 2 },
{ "clk_mpll", 0, 3 },
{ "clk_fpll", 1, 0 },
};
static const struct cv1800b_mmux_parent_info clk_c906_1_parents[] = {
{ "clk_tpll", 0, 0 },
{ "clk_a0pll", 0, 1 },
{ "clk_disppll", 0, 2 },
{ "clk_mpll", 0, 3 },
{ "clk_fpll", 1, 0 },
};
static const struct cv1800b_mmux_parent_info clk_a53_parents[] = {
{ "clk_tpll", 0, 0 },
{ "clk_a0pll", 0, 1 },
{ "clk_mipimpll", 0, 2 },
{ "clk_mpll", 0, 3 },
{ "clk_fpll", 1, 0 },
};
static struct cv1800b_clk_gate cv1800b_gate_info[] = {
CV1800B_GATE(CLK_XTAL_AP, "clk_xtal_ap", "osc", REG_CLK_EN_0, 3, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_RTC_25M, "clk_rtc_25m", "osc", REG_CLK_EN_0, 8, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TEMPSEN, "clk_tempsen", "osc", REG_CLK_EN_0, 9, 0),
CV1800B_GATE(CLK_SARADC, "clk_saradc", "osc", REG_CLK_EN_0, 10, 0),
CV1800B_GATE(CLK_EFUSE, "clk_efuse", "osc", REG_CLK_EN_0, 11, 0),
CV1800B_GATE(CLK_APB_EFUSE, "clk_apb_efuse", "osc", REG_CLK_EN_0, 12, 0),
CV1800B_GATE(CLK_DEBUG, "clk_debug", "osc", REG_CLK_EN_0, 13, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_XTAL_MISC, "clk_xtal_misc", "osc", REG_CLK_EN_0, 14, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_APB_WDT, "clk_apb_wdt", "osc", REG_CLK_EN_1, 7, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_WGN, "clk_wgn", "osc", REG_CLK_EN_3, 22, 0),
CV1800B_GATE(CLK_WGN0, "clk_wgn0", "osc", REG_CLK_EN_3, 23, 0),
CV1800B_GATE(CLK_WGN1, "clk_wgn1", "osc", REG_CLK_EN_3, 24, 0),
CV1800B_GATE(CLK_WGN2, "clk_wgn2", "osc", REG_CLK_EN_3, 25, 0),
CV1800B_GATE(CLK_KEYSCAN, "clk_keyscan", "osc", REG_CLK_EN_3, 26, 0),
CV1800B_GATE(CLK_TPU_FAB, "clk_tpu_fab", "clk_mipimpll", REG_CLK_EN_0, 5, 0),
CV1800B_GATE(CLK_AHB_ROM, "clk_ahb_rom", "clk_axi4", REG_CLK_EN_0, 6, 0),
CV1800B_GATE(CLK_AXI4_EMMC, "clk_axi4_emmc", "clk_axi4", REG_CLK_EN_0, 15, 0),
CV1800B_GATE(CLK_AXI4_SD0, "clk_axi4_sd0", "clk_axi4", REG_CLK_EN_0, 18, 0),
CV1800B_GATE(CLK_AXI4_SD1, "clk_axi4_sd1", "clk_axi4", REG_CLK_EN_0, 21, 0),
CV1800B_GATE(CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4", REG_CLK_EN_0, 26, 0),
CV1800B_GATE(CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4", REG_CLK_EN_0, 28, 0),
CV1800B_GATE(CLK_AHB_SF, "clk_ahb_sf", "clk_axi4", REG_CLK_EN_1, 0, 0),
CV1800B_GATE(CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi4", REG_CLK_EN_1, 1, 0),
CV1800B_GATE(CLK_APB_I2C, "clk_apb_i2c", "clk_axi4", REG_CLK_EN_1, 6, 0),
CV1800B_GATE(CLK_APB_SPI0, "clk_apb_spi0", "clk_axi4", REG_CLK_EN_1, 9, 0),
CV1800B_GATE(CLK_APB_SPI1, "clk_apb_spi1", "clk_axi4", REG_CLK_EN_1, 10, 0),
CV1800B_GATE(CLK_APB_SPI2, "clk_apb_spi2", "clk_axi4", REG_CLK_EN_1, 11, 0),
CV1800B_GATE(CLK_APB_SPI3, "clk_apb_spi3", "clk_axi4", REG_CLK_EN_1, 12, 0),
CV1800B_GATE(CLK_APB_UART0, "clk_apb_uart0", "clk_axi4", REG_CLK_EN_1, 15, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_APB_UART1, "clk_apb_uart1", "clk_axi4", REG_CLK_EN_1, 17, 0),
CV1800B_GATE(CLK_APB_UART2, "clk_apb_uart2", "clk_axi4", REG_CLK_EN_1, 19, 0),
CV1800B_GATE(CLK_APB_UART3, "clk_apb_uart3", "clk_axi4", REG_CLK_EN_1, 21, 0),
CV1800B_GATE(CLK_APB_UART4, "clk_apb_uart4", "clk_axi4", REG_CLK_EN_1, 23, 0),
CV1800B_GATE(CLK_APB_I2S0, "clk_apb_i2s0", "clk_axi4", REG_CLK_EN_1, 24, 0),
CV1800B_GATE(CLK_APB_I2S1, "clk_apb_i2s1", "clk_axi4", REG_CLK_EN_1, 25, 0),
CV1800B_GATE(CLK_APB_I2S2, "clk_apb_i2s2", "clk_axi4", REG_CLK_EN_1, 26, 0),
CV1800B_GATE(CLK_APB_I2S3, "clk_apb_i2s3", "clk_axi4", REG_CLK_EN_1, 27, 0),
CV1800B_GATE(CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4", REG_CLK_EN_1, 28, 0),
CV1800B_GATE(CLK_APB_USB, "clk_apb_usb", "clk_axi4", REG_CLK_EN_1, 29, 0),
CV1800B_GATE(CLK_APB_I2C0, "clk_apb_i2c0", "clk_axi4", REG_CLK_EN_3, 17, 0),
CV1800B_GATE(CLK_APB_I2C1, "clk_apb_i2c1", "clk_axi4", REG_CLK_EN_3, 18, 0),
CV1800B_GATE(CLK_APB_I2C2, "clk_apb_i2c2", "clk_axi4", REG_CLK_EN_3, 19, 0),
CV1800B_GATE(CLK_APB_I2C3, "clk_apb_i2c3", "clk_axi4", REG_CLK_EN_3, 20, 0),
CV1800B_GATE(CLK_APB_I2C4, "clk_apb_i2c4", "clk_axi4", REG_CLK_EN_3, 21, 0),
CV1800B_GATE(CLK_AHB_SF1, "clk_ahb_sf1", "clk_axi4", REG_CLK_EN_3, 27, 0),
CV1800B_GATE(CLK_APB_AUDSRC, "clk_apb_audsrc", "clk_axi4", REG_CLK_EN_4, 2, 0),
CV1800B_GATE(CLK_DDR_AXI_REG, "clk_ddr_axi_reg", "clk_axi6", REG_CLK_EN_0, 7,
CLK_IS_CRITICAL),
CV1800B_GATE(CLK_APB_GPIO, "clk_apb_gpio", "clk_axi6", REG_CLK_EN_0, 29, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_axi6", REG_CLK_EN_0, 30,
CLK_IS_CRITICAL),
CV1800B_GATE(CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6", REG_CLK_EN_2, 13, CLK_IGNORE_UNUSED),
CV1800B_GATE(CLK_APB_H264C, "clk_apb_h264c", "clk_axi6", REG_CLK_EN_2, 14, 0),
CV1800B_GATE(CLK_APB_H265C, "clk_apb_h265c", "clk_axi6", REG_CLK_EN_2, 15, 0),
CV1800B_GATE(CLK_PM, "clk_pm", "clk_axi6", REG_CLK_EN_3, 8, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_CFG_REG_VIP, "clk_cfg_reg_vip", "clk_axi6", REG_CLK_EN_3, 31, 0),
CV1800B_GATE(CLK_CFG_REG_VC, "clk_cfg_reg_vc", "clk_axi6", REG_CLK_EN_4, 0,
CLK_IGNORE_UNUSED),
CV1800B_GATE(CLK_PWM, "clk_pwm", "clk_pwm_src", REG_CLK_EN_1, 8, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_UART0, "clk_uart0", "clk_cam0_200", REG_CLK_EN_1, 14, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_UART1, "clk_uart1", "clk_cam0_200", REG_CLK_EN_1, 16, 0),
CV1800B_GATE(CLK_UART2, "clk_uart2", "clk_cam0_200", REG_CLK_EN_1, 18, 0),
CV1800B_GATE(CLK_UART3, "clk_uart3", "clk_cam0_200", REG_CLK_EN_1, 20, 0),
CV1800B_GATE(CLK_UART4, "clk_uart4", "clk_cam0_200", REG_CLK_EN_1, 22, 0),
CV1800B_GATE(CLK_H264C, "clk_h264c", "clk_axi_video_codec", REG_CLK_EN_2, 10, 0),
CV1800B_GATE(CLK_H265C, "clk_h265c", "clk_axi_video_codec", REG_CLK_EN_2, 11, 0),
CV1800B_GATE(CLK_JPEG, "clk_jpeg", "clk_axi_video_codec", REG_CLK_EN_2, 12,
CLK_IGNORE_UNUSED),
CV1800B_GATE(CLK_CSI_MAC0_VIP, "clk_csi_mac0_vip", "clk_axi_vip", REG_CLK_EN_2, 18, 0),
CV1800B_GATE(CLK_CSI_MAC1_VIP, "clk_csi_mac1_vip", "clk_axi_vip", REG_CLK_EN_2, 19, 0),
CV1800B_GATE(CLK_ISP_TOP_VIP, "clk_isp_top_vip", "clk_axi_vip", REG_CLK_EN_2, 20, 0),
CV1800B_GATE(CLK_IMG_D_VIP, "clk_img_d_vip", "clk_axi_vip", REG_CLK_EN_2, 21, 0),
CV1800B_GATE(CLK_IMG_V_VIP, "clk_img_v_vip", "clk_axi_vip", REG_CLK_EN_2, 22, 0),
CV1800B_GATE(CLK_SC_TOP_VIP, "clk_sc_top_vip", "clk_axi_vip", REG_CLK_EN_2, 23, 0),
CV1800B_GATE(CLK_SC_D_VIP, "clk_sc_d_vip", "clk_axi_vip", REG_CLK_EN_2, 24, 0),
CV1800B_GATE(CLK_SC_V1_VIP, "clk_sc_v1_vip", "clk_axi_vip", REG_CLK_EN_2, 25, 0),
CV1800B_GATE(CLK_SC_V2_VIP, "clk_sc_v2_vip", "clk_axi_vip", REG_CLK_EN_2, 26, 0),
CV1800B_GATE(CLK_SC_V3_VIP, "clk_sc_v3_vip", "clk_axi_vip", REG_CLK_EN_2, 27, 0),
CV1800B_GATE(CLK_DWA_VIP, "clk_dwa_vip", "clk_axi_vip", REG_CLK_EN_2, 28, 0),
CV1800B_GATE(CLK_BT_VIP, "clk_bt_vip", "clk_axi_vip", REG_CLK_EN_2, 29, 0),
CV1800B_GATE(CLK_DISP_VIP, "clk_disp_vip", "clk_axi_vip", REG_CLK_EN_2, 30, 0),
CV1800B_GATE(CLK_DSI_MAC_VIP, "clk_dsi_mac_vip", "clk_axi_vip", REG_CLK_EN_2, 31, 0),
CV1800B_GATE(CLK_LVDS0_VIP, "clk_lvds0_vip", "clk_axi_vip", REG_CLK_EN_3, 0, 0),
CV1800B_GATE(CLK_LVDS1_VIP, "clk_lvds1_vip", "clk_axi_vip", REG_CLK_EN_3, 1, 0),
CV1800B_GATE(CLK_CSI0_RX_VIP, "clk_csi0_rx_vip", "clk_axi_vip", REG_CLK_EN_3, 2, 0),
CV1800B_GATE(CLK_CSI1_RX_VIP, "clk_csi1_rx_vip", "clk_axi_vip", REG_CLK_EN_3, 3, 0),
CV1800B_GATE(CLK_PAD_VI_VIP, "clk_pad_vi_vip", "clk_axi_vip", REG_CLK_EN_3, 4, 0),
CV1800B_GATE(CLK_PAD_VI1_VIP, "clk_pad_vi1_vip", "clk_axi_vip", REG_CLK_EN_3, 30, 0),
CV1800B_GATE(CLK_PAD_VI2_VIP, "clk_pad_vi2_vip", "clk_axi_vip", REG_CLK_EN_4, 7, 0),
CV1800B_GATE(CLK_CSI_BE_VIP, "clk_csi_be_vip", "clk_axi_vip", REG_CLK_EN_4, 8, 0),
CV1800B_GATE(CLK_VIP_IP0, "clk_vip_ip0", "clk_axi_vip", REG_CLK_EN_4, 9, 0),
CV1800B_GATE(CLK_VIP_IP1, "clk_vip_ip1", "clk_axi_vip", REG_CLK_EN_4, 10, 0),
CV1800B_GATE(CLK_VIP_IP2, "clk_vip_ip2", "clk_axi_vip", REG_CLK_EN_4, 11, 0),
CV1800B_GATE(CLK_VIP_IP3, "clk_vip_ip3", "clk_axi_vip", REG_CLK_EN_4, 12, 0),
CV1800B_GATE(CLK_IVE_VIP, "clk_ive_vip", "clk_axi_vip", REG_CLK_EN_4, 17, 0),
CV1800B_GATE(CLK_RAW_VIP, "clk_raw_vip", "clk_axi_vip", REG_CLK_EN_4, 18, 0),
CV1800B_GATE(CLK_OSDC_VIP, "clk_osdc_vip", "clk_axi_vip", REG_CLK_EN_4, 19, 0),
CV1800B_GATE(CLK_CSI_MAC2_VIP, "clk_csi_mac2_vip", "clk_axi_vip", REG_CLK_EN_4, 20, 0),
CV1800B_GATE(CLK_CAM0_VIP, "clk_cam0_vip", "clk_axi_vip", REG_CLK_EN_4, 21, 0),
CV1800B_GATE(CLK_TIMER0, "clk_timer0", "clk_xtal_misc", REG_CLK_EN_3, 9, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER1, "clk_timer1", "clk_xtal_misc", REG_CLK_EN_3, 10, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER2, "clk_timer2", "clk_xtal_misc", REG_CLK_EN_3, 11, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER3, "clk_timer3", "clk_xtal_misc", REG_CLK_EN_3, 12, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER4, "clk_timer4", "clk_xtal_misc", REG_CLK_EN_3, 13, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER5, "clk_timer5", "clk_xtal_misc", REG_CLK_EN_3, 14, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER6, "clk_timer6", "clk_xtal_misc", REG_CLK_EN_3, 15, CLK_IS_CRITICAL),
CV1800B_GATE(CLK_TIMER7, "clk_timer7", "clk_xtal_misc", REG_CLK_EN_3, 16, CLK_IS_CRITICAL),
};
struct cv1800b_clk_div cv1800b_div_info[] = {
CV1800B_DIV(CLK_1M, "clk_1m", "osc", REG_CLK_EN_3, 5,
REG_DIV_CLK_1M, 16, 6, 25, CLK_IS_CRITICAL),
CV1800B_DIV(CLK_EMMC_100K, "clk_emmc_100k", "clk_1m", REG_CLK_EN_0, 17,
REG_DIV_CLK_EMMC_100K, 16, 8, 10, 0),
CV1800B_DIV(CLK_SD0_100K, "clk_sd0_100k", "clk_1m", REG_CLK_EN_0, 20,
REG_DIV_CLK_SD0_100K, 16, 8, 10, 0),
CV1800B_DIV(CLK_SD1_100K, "clk_sd1_100k", "clk_1m", REG_CLK_EN_0, 23,
REG_DIV_CLK_SD1_100K, 16, 8, 10, 0),
CV1800B_DIV(CLK_GPIO_DB, "clk_gpio_db", "clk_1m", REG_CLK_EN_0, 31,
REG_DIV_CLK_GPIO_DB, 16, 16, 10, CLK_IS_CRITICAL)
};
struct cv1800b_clk_bypass_div cv1800b_bypass_div_info[] = {
CV1800B_BYPASS_DIV(CLK_AP_DEBUG, "clk_ap_debug", "clk_fpll", REG_CLK_EN_4, 5,
REG_DIV_CLK_AP_DEBUG, 16, 4, 5, REG_CLK_BYP_1, 4, CLK_IS_CRITICAL),
CV1800B_BYPASS_DIV(CLK_SRC_RTC_SYS_0, "clk_src_rtc_sys_0", "clk_fpll", REG_CLK_EN_4, 6,
REG_DIV_CLK_RTCSYS_SRC_0, 16, 4, 5, REG_CLK_BYP_1, 5, CLK_IS_CRITICAL),
CV1800B_BYPASS_DIV(CLK_CPU_GIC, "clk_cpu_gic", "clk_fpll", REG_CLK_EN_0, 2,
REG_DIV_CLK_CPU_GIC, 16, 4, 5, REG_CLK_BYP_0, 2, CLK_IS_CRITICAL),
CV1800B_BYPASS_DIV(CLK_ETH0_500M, "clk_eth0_500m", "clk_fpll", REG_CLK_EN_0, 25,
REG_DIV_CLK_GPIO_DB, 16, 4, 3, REG_CLK_BYP_0, 9, 0),
CV1800B_BYPASS_DIV(CLK_ETH1_500M, "clk_eth1_500m", "clk_fpll", REG_CLK_EN_0, 27,
REG_DIV_CLK_GPIO_DB, 16, 4, 3, REG_CLK_BYP_0, 10, 0),
CV1800B_BYPASS_DIV(CLK_AXI6, "clk_axi6", "clk_fpll", REG_CLK_EN_2, 2, REG_DIV_CLK_AXI6, 16,
4, 15, REG_CLK_BYP_0, 20, CLK_IS_CRITICAL),
CV1800B_BYPASS_DIV(CLK_SPI, "clk_spi", "clk_fpll", REG_CLK_EN_3, 6, REG_DIV_CLK_SPI, 16, 6,
8, REG_CLK_BYP_0, 30, 0),
CV1800B_BYPASS_DIV(CLK_DISP_SRC_VIP, "clk_disp_src_vip", "clk_disppll", REG_CLK_EN_2, 7,
REG_DIV_CLK_DISP_SRC_VIP, 16, 4, 8, REG_CLK_BYP_0, 25, 0),
CV1800B_BYPASS_DIV(CLK_CPU_AXI0, "clk_cpu_axi0", "clk_axi4", REG_CLK_EN_0, 1,
REG_DIV_CLK_CPU_AXI0, 16, 4, 3, REG_CLK_BYP_0, 1, CLK_IS_CRITICAL),
CV1800B_BYPASS_DIV(CLK_DSI_ESC, "clk_dsi_esc", "clk_axi6", REG_CLK_EN_2, 3,
REG_DIV_CLK_DSI_ESC, 16, 4, 5, REG_CLK_BYP_0, 21, 0),
CV1800B_BYPASS_DIV(CLK_I2C, "clk_i2c", "clk_axi6", REG_CLK_EN_3, 7, REG_DIV_CLK_I2C, 16, 4,
1, REG_CLK_BYP_0, 31, 0),
};
struct cv1800b_clk_fixed_div cv1800b_fixed_div_info[] = {
CV1800B_FIXED_DIV(CLK_CAM0PLL_D2, "clk_cam0pll_d2", "clk_cam0pll",
REG_CAM0PLL_CLK_CSR, 1, 2,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
CV1800B_FIXED_DIV(CLK_CAM0PLL_D3, "clk_cam0pll_d3", "clk_cam0pll",
REG_CAM0PLL_CLK_CSR, 2, 3,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
CV1800B_FIXED_DIV(CLK_MIPIMPLL_D3, "clk_mipimpll_d3", "clk_mipimpll",
REG_MIPIMPLL_CLK_CSR, 2, 3,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
CV1800B_FIXED_DIV(CLK_USB_33K, "clk_usb_33k", "clk_1m",
REG_CLK_EN_1, 31, 3,
0),
};
struct cv1800b_clk_bypass_fixed_div cv1800b_bypass_fixed_div_info[] = {
CV1800B_BYPASS_FIXED_DIV(CLK_USB_125M, "clk_usb_125m", "clk_fpll",
REG_CLK_EN_1, 30, 12,
REG_CLK_BYP_0, 17,
CLK_SET_RATE_PARENT),
CV1800B_BYPASS_FIXED_DIV(CLK_USB_12M, "clk_usb_12m", "clk_fpll",
REG_CLK_EN_2, 0, 125,
REG_CLK_BYP_0, 18,
CLK_SET_RATE_PARENT),
CV1800B_BYPASS_FIXED_DIV(CLK_VC_SRC1, "clk_vc_src1", "clk_fpll",
REG_CLK_EN_3, 28, 2,
REG_CLK_BYP_1, 0,
CLK_SET_RATE_PARENT),
CV1800B_BYPASS_FIXED_DIV(CLK_VC_SRC2, "clk_vc_src2", "clk_fpll",
REG_CLK_EN_4, 3, 3,
REG_CLK_BYP_1, 3,
CLK_SET_RATE_PARENT),
};
struct cv1800b_clk_mux cv1800b_mux_info[] = {
CV1800B_MUX(CLK_CAM0, "clk_cam0", clk_cam_parents,
REG_CLK_EN_2, 16,
REG_CLK_CAM0_SRC_DIV, 16, 6, 0,
REG_CLK_CAM0_SRC_DIV, 8, 2,
CLK_IGNORE_UNUSED),
CV1800B_MUX(CLK_CAM1, "clk_cam1", clk_cam_parents,
REG_CLK_EN_2, 17,
REG_CLK_CAM1_SRC_DIV, 16, 6, 0,
REG_CLK_CAM1_SRC_DIV, 8, 2,
CLK_IGNORE_UNUSED),
};
struct cv1800b_clk_bypass_mux cv1800b_bypass_mux_info[] = {
CV1800B_BYPASS_MUX(CLK_TPU, "clk_tpu", clk_tpu_parents,
REG_CLK_EN_0, 4,
REG_DIV_CLK_TPU, 16, 4, 3,
REG_DIV_CLK_TPU, 8, 2,
REG_CLK_BYP_0, 3,
0),
CV1800B_BYPASS_MUX(CLK_EMMC, "clk_emmc", clk_axi4_parents,
REG_CLK_EN_0, 16,
REG_DIV_CLK_EMMC, 16, 5, 15,
REG_DIV_CLK_EMMC, 8, 2,
REG_CLK_BYP_0, 5,
0),
CV1800B_BYPASS_MUX(CLK_SD0, "clk_sd0", clk_axi4_parents,
REG_CLK_EN_0, 19,
REG_DIV_CLK_SD0, 16, 5, 15,
REG_DIV_CLK_SD0, 8, 2,
REG_CLK_BYP_0, 6,
0),
CV1800B_BYPASS_MUX(CLK_SD1, "clk_sd1", clk_axi4_parents,
REG_CLK_EN_0, 22,
REG_DIV_CLK_SD1, 16, 5, 15,
REG_DIV_CLK_SD1, 8, 2,
REG_CLK_BYP_0, 7,
0),
CV1800B_BYPASS_MUX(CLK_SPI_NAND, "clk_spi_nand", clk_axi4_parents,
REG_CLK_EN_0, 24,
REG_DIV_CLK_SPI_NAND, 16, 5, 8,
REG_DIV_CLK_SPI_NAND, 8, 2,
REG_CLK_BYP_0, 8,
0),
CV1800B_BYPASS_MUX(CLK_AXI4, "clk_axi4", clk_axi4_parents,
REG_CLK_EN_2, 1,
REG_DIV_CLK_AXI4, 16, 4, 5,
REG_DIV_CLK_AXI4, 8, 2,
REG_CLK_BYP_0, 19,
CLK_IS_CRITICAL),
CV1800B_BYPASS_MUX(CLK_PWM_SRC, "clk_pwm_src", clk_axi4_parents,
REG_CLK_EN_4, 4,
REG_DIV_CLK_PWM_SRC_0, 16, 6, 10,
REG_DIV_CLK_PWM_SRC_0, 8, 2,
REG_CLK_BYP_0, 15,
CLK_IS_CRITICAL),
CV1800B_BYPASS_MUX(CLK_AUDSRC, "clk_audsrc", clk_aud_parents,
REG_CLK_EN_4, 1,
REG_DIV_CLK_AUDSRC, 16, 8, 18,
REG_DIV_CLK_AUDSRC, 8, 2,
REG_CLK_BYP_1, 2,
0),
CV1800B_BYPASS_MUX(CLK_SDMA_AUD0, "clk_sdma_aud0", clk_aud_parents,
REG_CLK_EN_1, 2,
REG_DIV_CLK_SDMA_AUD0, 16, 8, 18,
REG_DIV_CLK_SDMA_AUD0, 8, 2,
REG_CLK_BYP_0, 11,
0),
CV1800B_BYPASS_MUX(CLK_SDMA_AUD1, "clk_sdma_aud1", clk_aud_parents,
REG_CLK_EN_1, 3,
REG_DIV_CLK_SDMA_AUD1, 16, 8, 18,
REG_DIV_CLK_SDMA_AUD1, 8, 2,
REG_CLK_BYP_0, 12,
0),
CV1800B_BYPASS_MUX(CLK_SDMA_AUD2, "clk_sdma_aud2", clk_aud_parents,
REG_CLK_EN_1, 3,
REG_DIV_CLK_SDMA_AUD2, 16, 8, 18,
REG_DIV_CLK_SDMA_AUD2, 8, 2,
REG_CLK_BYP_0, 13,
0),
CV1800B_BYPASS_MUX(CLK_SDMA_AUD3, "clk_sdma_aud3", clk_aud_parents,
REG_CLK_EN_1, 3,
REG_DIV_CLK_SDMA_AUD3, 16, 8, 18,
REG_DIV_CLK_SDMA_AUD3, 8, 2,
REG_CLK_BYP_0, 14,
0),
CV1800B_BYPASS_MUX(CLK_CAM0_200, "clk_cam0_200", clk_cam0_200_parents,
REG_CLK_EN_1, 13,
REG_DIV_CLK_CAM0_200, 16, 4, 1,
REG_DIV_CLK_CAM0_200, 8, 2,
REG_CLK_BYP_0, 16,
CLK_IS_CRITICAL),
CV1800B_BYPASS_MUX(CLK_AXI_VIP, "clk_axi_vip", clk_vip_sys_parents,
REG_CLK_EN_2, 4,
REG_DIV_CLK_AXI_VIP, 16, 4, 3,
REG_DIV_CLK_AXI_VIP, 8, 2,
REG_CLK_BYP_0, 22,
0),
CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_0, "clk_src_vip_sys_0", clk_vip_sys_parents,
REG_CLK_EN_2, 5,
REG_DIV_CLK_SRC_VIP_SYS_0, 16, 4, 6,
REG_DIV_CLK_SRC_VIP_SYS_0, 8, 2,
REG_CLK_BYP_0, 23,
0),
CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_1, "clk_src_vip_sys_1", clk_vip_sys_parents,
REG_CLK_EN_2, 6,
REG_DIV_CLK_SRC_VIP_SYS_1, 16, 4, 6,
REG_DIV_CLK_SRC_VIP_SYS_1, 8, 2,
REG_CLK_BYP_0, 24,
0),
CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_2, "clk_src_vip_sys_2", clk_vip_sys_parents,
REG_CLK_EN_3, 29,
REG_DIV_CLK_SRC_VIP_SYS_2, 16, 4, 2,
REG_DIV_CLK_SRC_VIP_SYS_2, 8, 2,
REG_CLK_BYP_1, 1,
0),
CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_3, "clk_src_vip_sys_3", clk_vip_sys_parents,
REG_CLK_EN_4, 15,
REG_DIV_CLK_SRC_VIP_SYS_3, 16, 4, 2,
REG_DIV_CLK_SRC_VIP_SYS_3, 8, 2,
REG_CLK_BYP_1, 8,
0),
CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_4, "clk_src_vip_sys_4", clk_vip_sys_parents,
REG_CLK_EN_4, 16,
REG_DIV_CLK_SRC_VIP_SYS_4, 16, 4, 3,
REG_DIV_CLK_SRC_VIP_SYS_4, 8, 2,
REG_CLK_BYP_1, 9,
0),
CV1800B_BYPASS_MUX(CLK_AXI_VIDEO_CODEC, "clk_axi_video_codec", clk_axi_video_codec_parents,
REG_CLK_EN_2, 8,
REG_DIV_CLK_AXI_VIDEO_CODEC, 16, 4, 2,
REG_DIV_CLK_AXI_VIDEO_CODEC, 8, 2,
REG_CLK_BYP_0, 26,
0),
CV1800B_BYPASS_MUX(CLK_VC_SRC0, "clk_vc_src0", clk_vc_src0_parents,
REG_CLK_EN_2, 9,
REG_DIV_CLK_VC_SRC0, 16, 4, 2,
REG_DIV_CLK_VC_SRC0, 8, 2,
REG_CLK_BYP_0, 27,
0),
};
struct cv1800b_clk_mmux cv1800b_mmux_info[] = {
CV1800B_MMUX(CLK_C906_0, "clk_c906_0", clk_c906_0_parents,
REG_CLK_EN_4, 13,
REG_DIV_CLK_C906_0_0, 16, 4, 1,
REG_DIV_CLK_C906_0_1, 16, 4, 2,
REG_DIV_CLK_C906_0_0, 8, 2,
REG_DIV_CLK_C906_0_1, 8, 2,
REG_CLK_BYP_1, 6,
REG_CLK_SEL_0, 23,
CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
CV1800B_MMUX(CLK_C906_1, "clk_c906_1", clk_c906_1_parents,
REG_CLK_EN_4, 14,
REG_DIV_CLK_C906_1_0, 16, 4, 2,
REG_DIV_CLK_C906_1_1, 16, 4, 3,
REG_DIV_CLK_C906_1_0, 8, 2,
REG_DIV_CLK_C906_1_1, 8, 2,
REG_CLK_BYP_1, 7,
REG_CLK_SEL_0, 24,
CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
CV1800B_MMUX(CLK_A53, "clk_a53", clk_a53_parents,
REG_CLK_EN_0, 0,
REG_DIV_CLK_A53_0, 16, 4, 1,
REG_DIV_CLK_A53_1, 16, 4, 2,
REG_DIV_CLK_A53_0, 8, 2,
REG_DIV_CLK_A53_1, 8, 2,
REG_CLK_BYP_0, 0,
REG_CLK_SEL_0, 0,
CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
};
static struct cv1800b_clk_audio cv1800b_audio_info[] = {
CV1800B_AUDIO(CLK_A24M, "clk_a24m", "clk_mipimpll",
REG_APLL_FRAC_DIV_CTRL, 0,
REG_APLL_FRAC_DIV_CTRL, 3,
REG_APLL_FRAC_DIV_CTRL, 1,
REG_APLL_FRAC_DIV_CTRL, 2,
REG_APLL_FRAC_DIV_M, 0, 22,
REG_APLL_FRAC_DIV_N, 0, 22,
0),
};
static struct cv1800b_clk_ipll cv1800b_ipll_info[] = {
CV1800B_IPLL(CLK_FPLL, "clk_fpll", "osc", REG_FPLL_CSR,
REG_PLL_G6_CTRL, 8,
REG_PLL_G6_STATUS, 2,
CLK_IS_CRITICAL),
CV1800B_IPLL(CLK_MIPIMPLL, "clk_mipimpll", "osc", REG_MIPIMPLL_CSR,
REG_PLL_G2_CTRL, 0,
REG_PLL_G2_STATUS, 0,
CLK_IS_CRITICAL),
};
static struct cv1800b_clk_fpll cv1800b_fpll_info[] = {
CV1800B_FPLL(CLK_MPLL, "clk_mpll", "osc", REG_MPLL_CSR,
REG_PLL_G6_CTRL, 0,
REG_PLL_G6_STATUS, 0,
REG_PLL_G6_SSC_SYN_CTRL, 2,
REG_PLL_G6_SSC_SYN_CTRL, 0,
REG_MPLL_SSC_SYN_CTRL, REG_MPLL_SSC_SYN_SET,
CLK_IS_CRITICAL),
CV1800B_FPLL(CLK_TPLL, "clk_tpll", "osc", REG_TPLL_CSR,
REG_PLL_G6_CTRL, 4,
REG_PLL_G6_STATUS, 1,
REG_PLL_G6_SSC_SYN_CTRL, 3,
REG_PLL_G6_SSC_SYN_CTRL, 0,
REG_TPLL_SSC_SYN_CTRL, REG_TPLL_SSC_SYN_SET,
CLK_IS_CRITICAL),
CV1800B_FPLL(CLK_A0PLL, "clk_a0pll", "clk_mipimpll", REG_A0PLL_CSR,
REG_PLL_G2_CTRL, 4,
REG_PLL_G2_STATUS, 1,
REG_PLL_G2_SSC_SYN_CTRL, 2,
REG_PLL_G2_SSC_SYN_CTRL, 0,
REG_A0PLL_SSC_SYN_CTRL, REG_A0PLL_SSC_SYN_SET,
CLK_IS_CRITICAL),
CV1800B_FPLL(CLK_DISPPLL, "clk_disppll", "clk_mipimpll", REG_DISPPLL_CSR,
REG_PLL_G2_CTRL, 8,
REG_PLL_G2_STATUS, 2,
REG_PLL_G2_SSC_SYN_CTRL, 3,
REG_PLL_G2_SSC_SYN_CTRL, 0,
REG_DISPPLL_SSC_SYN_CTRL, REG_DISPPLL_SSC_SYN_SET,
CLK_IS_CRITICAL),
CV1800B_FPLL(CLK_CAM0PLL, "clk_cam0pll", "clk_mipimpll", REG_CAM0PLL_CSR,
REG_PLL_G2_CTRL, 12,
REG_PLL_G2_STATUS, 3,
REG_PLL_G2_SSC_SYN_CTRL, 4,
REG_PLL_G2_SSC_SYN_CTRL, 0,
REG_CAM0PLL_SSC_SYN_CTRL, REG_CAM0PLL_SSC_SYN_SET,
CLK_IGNORE_UNUSED),
CV1800B_FPLL(CLK_CAM1PLL, "clk_cam1pll", "clk_mipimpll", REG_CAM1PLL_CSR,
REG_PLL_G2_CTRL, 16,
REG_PLL_G2_STATUS, 4,
REG_PLL_G2_SSC_SYN_CTRL, 5,
REG_PLL_G2_SSC_SYN_CTRL, 0,
REG_CAM1PLL_SSC_SYN_CTRL, REG_CAM1PLL_SSC_SYN_SET,
CLK_IS_CRITICAL),
};
static int cv1800b_register_clk(struct udevice *dev)
{
struct clk osc;
ulong osc_rate;
void *base = devfdt_get_addr_ptr(dev);
int i, ret;
ret = clk_get_by_index(dev, 0, &osc);
if (ret) {
pr_err("Failed to get clock\n");
return ret;
}
osc_rate = clk_get_rate(&osc);
clk_dm(CV1800B_CLK_OSC, clk_register_fixed_rate(NULL, "osc", osc_rate));
clk_dm(CV1800B_CLK_BYPASS, clk_register_fixed_rate(NULL, "bypass", osc_rate));
for (i = 0; i < ARRAY_SIZE(cv1800b_ipll_info); i++) {
struct cv1800b_clk_ipll *ipll = &cv1800b_ipll_info[i];
ipll->base = base;
ret = clk_register(&ipll->clk, "cv1800b_clk_ipll", ipll->name,
ipll->parent_name);
if (ret) {
pr_err("Failed to register ipll %s\n", ipll->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_fpll_info); i++) {
struct cv1800b_clk_fpll *fpll = &cv1800b_fpll_info[i];
fpll->ipll.base = base;
ret = clk_register(&fpll->ipll.clk, "cv1800b_clk_fpll",
fpll->ipll.name, fpll->ipll.parent_name);
if (ret) {
pr_err("Failed to register fpll %s\n", fpll->ipll.name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_div_info); i++) {
struct cv1800b_clk_div *div = &cv1800b_div_info[i];
div->base = base;
ret = clk_register(&div->clk, "cv1800b_clk_div", div->name,
div->parent_name);
if (ret) {
pr_err("Failed to register div %s\n", div->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_fixed_div_info); i++) {
struct cv1800b_clk_fixed_div *fixed_div =
&cv1800b_fixed_div_info[i];
fixed_div->base = base;
ret = clk_register(&fixed_div->clk, "cv1800b_clk_fixed_div",
fixed_div->name, fixed_div->parent_name);
if (ret) {
pr_err("Failed to register fixed div %s\n",
fixed_div->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_fixed_div_info); i++) {
struct cv1800b_clk_bypass_fixed_div *bypass_fixed_div =
&cv1800b_bypass_fixed_div_info[i];
bypass_fixed_div->div.base = base;
ret = clk_register(&bypass_fixed_div->div.clk,
"cv1800b_clk_bypass_fixed_div",
bypass_fixed_div->div.name,
bypass_fixed_div->div.parent_name);
if (ret) {
pr_err("Failed to register bypass fixed div %s\n",
bypass_fixed_div->div.name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_mux_info); i++) {
struct cv1800b_clk_mux *mux = &cv1800b_mux_info[i];
int parent;
mux->base = base;
parent = cv1800b_clk_getfield(base, &mux->mux);
ret = clk_register(&mux->clk, "cv1800b_clk_mux", mux->name,
mux->parent_names[parent]);
if (ret) {
pr_err("Failed to register mux %s\n", mux->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_mmux_info); i++) {
struct cv1800b_clk_mmux *mmux = &cv1800b_mmux_info[i];
int clk_sel, parent, idx;
mmux->base = base;
clk_sel = cv1800b_clk_getbit(base, &mmux->clk_sel) ? 0 : 1;
parent = cv1800b_clk_getfield(base, &mmux->mux[clk_sel]);
for (idx = 0; idx < mmux->num_parents; idx++) {
if (clk_sel == mmux->parent_infos[idx].clk_sel &&
parent == mmux->parent_infos[idx].index)
break;
}
ret = clk_register(&mmux->clk, "cv1800b_clk_mmux", mmux->name,
mmux->parent_infos[idx].name);
if (ret) {
pr_err("Failed to register mmux %s\n", mmux->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_audio_info); i++) {
struct cv1800b_clk_audio *audio = &cv1800b_audio_info[i];
audio->base = base;
ret = clk_register(&audio->clk, "cv1800b_clk_audio",
audio->name, audio->parent_name);
if (ret) {
pr_err("Failed to register audio %s\n", audio->name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_mux_info); i++) {
struct cv1800b_clk_bypass_mux *bypass_mux =
&cv1800b_bypass_mux_info[i];
int parent;
bypass_mux->mux.base = base;
parent = cv1800b_clk_getfield(base, &bypass_mux->mux.mux);
ret = clk_register(&bypass_mux->mux.clk,
"cv1800b_clk_bypass_mux",
bypass_mux->mux.name,
bypass_mux->mux.parent_names[parent]);
if (ret) {
pr_err("Failed to register bypass mux %s\n",
bypass_mux->mux.name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_div_info); i++) {
struct cv1800b_clk_bypass_div *bypass_div =
&cv1800b_bypass_div_info[i];
bypass_div->div.base = base;
ret = clk_register(&bypass_div->div.clk,
"cv1800b_clk_bypass_div",
bypass_div->div.name,
bypass_div->div.parent_name);
if (ret) {
pr_err("Failed to register bypass div %s\n",
bypass_div->div.name);
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(cv1800b_gate_info); i++) {
struct cv1800b_clk_gate *gate = &cv1800b_gate_info[i];
gate->base = base;
ret = clk_register(&gate->clk, "cv1800b_clk_gate", gate->name,
gate->parent_name);
if (ret) {
pr_err("Failed to register gate %s\n", gate->name);
return ret;
}
}
return 0;
}
static int cv1800b_clk_probe(struct udevice *dev)
{
return cv1800b_register_clk(dev);
}
static int cv1800b_clk_enable(struct clk *clk)
{
struct clk *c;
int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
if (err)
return err;
return clk_enable(c);
}
static int cv1800b_clk_disable(struct clk *clk)
{
struct clk *c;
int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
if (err)
return err;
return clk_disable(c);
}
static ulong cv1800b_clk_get_rate(struct clk *clk)
{
struct clk *c;
int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
if (err)
return err;
return clk_get_rate(c);
}
static ulong cv1800b_clk_set_rate(struct clk *clk, ulong rate)
{
struct clk *c;
int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
if (err)
return err;
return clk_set_rate(c, rate);
}
static int cv1800b_clk_set_parent(struct clk *clk, struct clk *parent)
{
struct clk *c, *p;
int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
if (err)
return err;
err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(parent->id), &p);
if (err)
return err;
return clk_set_parent(c, p);
}
const struct clk_ops cv1800b_clk_ops = {
.enable = cv1800b_clk_enable,
.disable = cv1800b_clk_disable,
.get_rate = cv1800b_clk_get_rate,
.set_rate = cv1800b_clk_set_rate,
.set_parent = cv1800b_clk_set_parent,
};
static const struct udevice_id cv1800b_clk_of_match[] = {
{ .compatible = "sophgo,cv1800-clk" },
{ },
};
U_BOOT_DRIVER(sophgo_clk) = {
.name = "cv1800b_clk",
.id = UCLASS_CLK,
.of_match = cv1800b_clk_of_match,
.probe = cv1800b_clk_probe,
.ops = &cv1800b_clk_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@@ -0,0 +1,123 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
*/
#ifndef _CLK_SOPHGO_CV1800_H_
#define _CLK_SOPHGO_CV1800_H_
#include <dt-bindings/clock/sophgo,cv1800.h>
#define CV1800_CLK_MAX (CLK_XTAL_AP + 1)
#define CV1810_CLK_MAX (CLK_DISP_SRC_VIP + 1)
#define REG_PLL_G2_CTRL 0x800
#define REG_PLL_G2_STATUS 0x804
#define REG_MIPIMPLL_CSR 0x808
#define REG_A0PLL_CSR 0x80C
#define REG_DISPPLL_CSR 0x810
#define REG_CAM0PLL_CSR 0x814
#define REG_CAM1PLL_CSR 0x818
#define REG_PLL_G2_SSC_SYN_CTRL 0x840
#define REG_A0PLL_SSC_SYN_CTRL 0x850
#define REG_A0PLL_SSC_SYN_SET 0x854
#define REG_A0PLL_SSC_SYN_SPAN 0x858
#define REG_A0PLL_SSC_SYN_STEP 0x85C
#define REG_DISPPLL_SSC_SYN_CTRL 0x860
#define REG_DISPPLL_SSC_SYN_SET 0x864
#define REG_DISPPLL_SSC_SYN_SPAN 0x868
#define REG_DISPPLL_SSC_SYN_STEP 0x86C
#define REG_CAM0PLL_SSC_SYN_CTRL 0x870
#define REG_CAM0PLL_SSC_SYN_SET 0x874
#define REG_CAM0PLL_SSC_SYN_SPAN 0x878
#define REG_CAM0PLL_SSC_SYN_STEP 0x87C
#define REG_CAM1PLL_SSC_SYN_CTRL 0x880
#define REG_CAM1PLL_SSC_SYN_SET 0x884
#define REG_CAM1PLL_SSC_SYN_SPAN 0x888
#define REG_CAM1PLL_SSC_SYN_STEP 0x88C
#define REG_APLL_FRAC_DIV_CTRL 0x890
#define REG_APLL_FRAC_DIV_M 0x894
#define REG_APLL_FRAC_DIV_N 0x898
#define REG_MIPIMPLL_CLK_CSR 0x8A0
#define REG_A0PLL_CLK_CSR 0x8A4
#define REG_DISPPLL_CLK_CSR 0x8A8
#define REG_CAM0PLL_CLK_CSR 0x8AC
#define REG_CAM1PLL_CLK_CSR 0x8B0
#define REG_CLK_CAM0_SRC_DIV 0x8C0
#define REG_CLK_CAM1_SRC_DIV 0x8C4
/* top_pll_g6 */
#define REG_PLL_G6_CTRL 0x900
#define REG_PLL_G6_STATUS 0x904
#define REG_MPLL_CSR 0x908
#define REG_TPLL_CSR 0x90C
#define REG_FPLL_CSR 0x910
#define REG_PLL_G6_SSC_SYN_CTRL 0x940
#define REG_DPLL_SSC_SYN_CTRL 0x950
#define REG_DPLL_SSC_SYN_SET 0x954
#define REG_DPLL_SSC_SYN_SPAN 0x958
#define REG_DPLL_SSC_SYN_STEP 0x95C
#define REG_MPLL_SSC_SYN_CTRL 0x960
#define REG_MPLL_SSC_SYN_SET 0x964
#define REG_MPLL_SSC_SYN_SPAN 0x968
#define REG_MPLL_SSC_SYN_STEP 0x96C
#define REG_TPLL_SSC_SYN_CTRL 0x970
#define REG_TPLL_SSC_SYN_SET 0x974
#define REG_TPLL_SSC_SYN_SPAN 0x978
#define REG_TPLL_SSC_SYN_STEP 0x97C
/* clkgen */
#define REG_CLK_EN_0 0x000
#define REG_CLK_EN_1 0x004
#define REG_CLK_EN_2 0x008
#define REG_CLK_EN_3 0x00C
#define REG_CLK_EN_4 0x010
#define REG_CLK_SEL_0 0x020
#define REG_CLK_BYP_0 0x030
#define REG_CLK_BYP_1 0x034
#define REG_DIV_CLK_A53_0 0x040
#define REG_DIV_CLK_A53_1 0x044
#define REG_DIV_CLK_CPU_AXI0 0x048
#define REG_DIV_CLK_CPU_GIC 0x050
#define REG_DIV_CLK_TPU 0x054
#define REG_DIV_CLK_EMMC 0x064
#define REG_DIV_CLK_EMMC_100K 0x06C
#define REG_DIV_CLK_SD0 0x070
#define REG_DIV_CLK_SD0_100K 0x078
#define REG_DIV_CLK_SD1 0x07C
#define REG_DIV_CLK_SD1_100K 0x084
#define REG_DIV_CLK_SPI_NAND 0x088
#define REG_DIV_CLK_ETH0_500M 0x08C
#define REG_DIV_CLK_ETH1_500M 0x090
#define REG_DIV_CLK_GPIO_DB 0x094
#define REG_DIV_CLK_SDMA_AUD0 0x098
#define REG_DIV_CLK_SDMA_AUD1 0x09C
#define REG_DIV_CLK_SDMA_AUD2 0x0A0
#define REG_DIV_CLK_SDMA_AUD3 0x0A4
#define REG_DIV_CLK_CAM0_200 0x0A8
#define REG_DIV_CLK_AXI4 0x0B8
#define REG_DIV_CLK_AXI6 0x0BC
#define REG_DIV_CLK_DSI_ESC 0x0C4
#define REG_DIV_CLK_AXI_VIP 0x0C8
#define REG_DIV_CLK_SRC_VIP_SYS_0 0x0D0
#define REG_DIV_CLK_SRC_VIP_SYS_1 0x0D8
#define REG_DIV_CLK_DISP_SRC_VIP 0x0E0
#define REG_DIV_CLK_AXI_VIDEO_CODEC 0x0E4
#define REG_DIV_CLK_VC_SRC0 0x0EC
#define REG_DIV_CLK_1M 0x0FC
#define REG_DIV_CLK_SPI 0x100
#define REG_DIV_CLK_I2C 0x104
#define REG_DIV_CLK_SRC_VIP_SYS_2 0x110
#define REG_DIV_CLK_AUDSRC 0x118
#define REG_DIV_CLK_PWM_SRC_0 0x120
#define REG_DIV_CLK_AP_DEBUG 0x128
#define REG_DIV_CLK_RTCSYS_SRC_0 0x12C
#define REG_DIV_CLK_C906_0_0 0x130
#define REG_DIV_CLK_C906_0_1 0x134
#define REG_DIV_CLK_C906_1_0 0x138
#define REG_DIV_CLK_C906_1_1 0x13C
#define REG_DIV_CLK_SRC_VIP_SYS_3 0x140
#define REG_DIV_CLK_SRC_VIP_SYS_4 0x144
#endif /* _CLK_SOPHGO_CV1800_H_ */

594
drivers/clk/sophgo/clk-ip.c Normal file
View File

@@ -0,0 +1,594 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
*/
#include <dm.h>
#include <div64.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include "clk-common.h"
#include "clk-ip.h"
static int get_parent_index(struct clk *clk, const char *const *parent_name,
u8 num_parents)
{
const char *name = clk_hw_get_name(clk);
int i;
for (i = 0; i < num_parents; i++) {
if (!strcmp(name, parent_name[i]))
return i;
}
return -1;
}
/* GATE */
#define to_cv1800b_clk_gate(_clk) \
container_of(_clk, struct cv1800b_clk_gate, clk)
static int gate_enable(struct clk *clk)
{
struct cv1800b_clk_gate *gate = to_cv1800b_clk_gate(clk);
return cv1800b_clk_setbit(gate->base, &gate->gate);
}
static int gate_disable(struct clk *clk)
{
struct cv1800b_clk_gate *gate = to_cv1800b_clk_gate(clk);
return cv1800b_clk_clrbit(gate->base, &gate->gate);
}
static ulong gate_get_rate(struct clk *clk)
{
return clk_get_parent_rate(clk);
}
const struct clk_ops cv1800b_clk_gate_ops = {
.disable = gate_disable,
.enable = gate_enable,
.get_rate = gate_get_rate,
};
U_BOOT_DRIVER(cv1800b_clk_gate) = {
.name = "cv1800b_clk_gate",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_gate_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* DIV */
#define CLK_DIV_EN_FACTOR BIT(3)
#define to_cv1800b_clk_div(_clk) container_of(_clk, struct cv1800b_clk_div, clk)
static int div_enable(struct clk *clk)
{
struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
return cv1800b_clk_setbit(div->base, &div->gate);
}
static int div_disable(struct clk *clk)
{
struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
return cv1800b_clk_clrbit(div->base, &div->gate);
}
static ulong div_get_rate(struct clk *clk)
{
struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
ulong val;
if (div->div_init == 0 ||
readl(div->base + div->div.offset) & CLK_DIV_EN_FACTOR)
val = cv1800b_clk_getfield(div->base, &div->div);
else
val = div->div_init;
return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
}
static ulong div_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
ulong parent_rate = clk_get_parent_rate(clk);
u32 val;
val = DIV_ROUND_UP_ULL(parent_rate, rate);
val = min_t(u32, val, clk_div_mask(div->div.width));
cv1800b_clk_setfield(div->base, &div->div, val);
if (div->div_init > 0)
setbits_le32(div->base + div->div.offset, CLK_DIV_EN_FACTOR);
return DIV_ROUND_UP_ULL(parent_rate, val);
}
const struct clk_ops cv1800b_clk_div_ops = {
.disable = div_disable,
.enable = div_enable,
.get_rate = div_get_rate,
.set_rate = div_set_rate,
};
U_BOOT_DRIVER(cv1800b_clk_div) = {
.name = "cv1800b_clk_div",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_div_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#define to_cv1800b_clk_bypass_div(_clk) \
container_of(_clk, struct cv1800b_clk_bypass_div, div.clk)
static ulong bypass_div_get_rate(struct clk *clk)
{
struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
if (cv1800b_clk_getbit(div->div.base, &div->bypass))
return 0;
return div_get_rate(clk);
}
static ulong bypass_div_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
if (cv1800b_clk_getbit(div->div.base, &div->bypass))
return 0;
return div_set_rate(clk, rate);
}
static int bypass_div_set_parent(struct clk *clk, struct clk *pclk)
{
struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
if (pclk->id == CV1800B_CLK_BYPASS) {
cv1800b_clk_setbit(div->div.base, &div->bypass);
return 0;
}
if (strcmp(clk_hw_get_name(pclk), div->div.parent_name))
return -EINVAL;
cv1800b_clk_clrbit(div->div.base, &div->bypass);
return 0;
}
const struct clk_ops cv1800b_clk_bypass_div_ops = {
.disable = div_disable,
.enable = div_enable,
.get_rate = bypass_div_get_rate,
.set_rate = bypass_div_set_rate,
.set_parent = bypass_div_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_bypass_div) = {
.name = "cv1800b_clk_bypass_div",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_bypass_div_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* FIXED DIV */
#define to_cv1800b_clk_fixed_div(_clk) \
container_of(_clk, struct cv1800b_clk_fixed_div, clk)
static int fixed_div_enable(struct clk *clk)
{
struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
return cv1800b_clk_setbit(div->base, &div->gate);
}
static int fixed_div_disable(struct clk *clk)
{
struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
return cv1800b_clk_clrbit(div->base, &div->gate);
}
static ulong fixed_div_get_rate(struct clk *clk)
{
struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), div->div);
}
const struct clk_ops cv1800b_clk_fixed_div_ops = {
.disable = fixed_div_disable,
.enable = fixed_div_enable,
.get_rate = fixed_div_get_rate,
};
U_BOOT_DRIVER(cv1800b_clk_fixed_div) = {
.name = "cv1800b_clk_fixed_div",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_fixed_div_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#define to_cv1800b_clk_bypass_fixed_div(_clk) \
container_of(_clk, struct cv1800b_clk_bypass_fixed_div, div.clk)
static ulong bypass_fixed_div_get_rate(struct clk *clk)
{
struct cv1800b_clk_bypass_fixed_div *div =
to_cv1800b_clk_bypass_fixed_div(clk);
if (cv1800b_clk_getbit(div->div.base, &div->bypass))
return 0;
return fixed_div_get_rate(clk);
}
static int bypass_fixed_div_set_parent(struct clk *clk, struct clk *pclk)
{
struct cv1800b_clk_bypass_fixed_div *div =
to_cv1800b_clk_bypass_fixed_div(clk);
if (pclk->id == CV1800B_CLK_BYPASS) {
cv1800b_clk_setbit(div->div.base, &div->bypass);
return 0;
}
if (strcmp(clk_hw_get_name(pclk), div->div.parent_name))
return -EINVAL;
cv1800b_clk_clrbit(div->div.base, &div->bypass);
return 0;
}
const struct clk_ops cv1800b_clk_bypass_fixed_div_ops = {
.disable = fixed_div_disable,
.enable = fixed_div_enable,
.get_rate = bypass_fixed_div_get_rate,
.set_parent = bypass_fixed_div_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_bypass_fixed_div) = {
.name = "cv1800b_clk_bypass_fixed_div",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_bypass_fixed_div_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* MUX */
#define to_cv1800b_clk_mux(_clk) container_of(_clk, struct cv1800b_clk_mux, clk)
static int mux_enable(struct clk *clk)
{
struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
return cv1800b_clk_setbit(mux->base, &mux->gate);
}
static int mux_disable(struct clk *clk)
{
struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
return cv1800b_clk_clrbit(mux->base, &mux->gate);
}
static ulong mux_get_rate(struct clk *clk)
{
struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
ulong val;
if (mux->div_init == 0 ||
readl(mux->base + mux->div.offset) & CLK_DIV_EN_FACTOR)
val = cv1800b_clk_getfield(mux->base, &mux->div);
else
val = mux->div_init;
return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
}
static ulong mux_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
ulong parent_rate = clk_get_parent_rate(clk);
ulong val;
val = DIV_ROUND_UP_ULL(parent_rate, rate);
val = min_t(u32, val, clk_div_mask(mux->div.width));
cv1800b_clk_setfield(mux->base, &mux->div, val);
if (mux->div_init > 0)
setbits_le32(mux->base + mux->div.offset, CLK_DIV_EN_FACTOR);
return DIV_ROUND_UP_ULL(parent_rate, val);
}
static int mux_set_parent(struct clk *clk, struct clk *pclk)
{
struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
int index = get_parent_index(pclk, mux->parent_names, mux->num_parents);
if (index < 0)
return -EINVAL;
cv1800b_clk_setfield(mux->base, &mux->mux, index);
return 0;
}
const struct clk_ops cv1800b_clk_mux_ops = {
.disable = mux_disable,
.enable = mux_enable,
.get_rate = mux_get_rate,
.set_rate = mux_set_rate,
.set_parent = mux_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_mux) = {
.name = "cv1800b_clk_mux",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_mux_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#define to_cv1800b_clk_bypass_mux(_clk) \
container_of(_clk, struct cv1800b_clk_bypass_mux, mux.clk)
static ulong bypass_mux_get_rate(struct clk *clk)
{
struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
if (cv1800b_clk_getbit(mux->mux.base, &mux->bypass))
return 0;
return mux_get_rate(clk);
}
static ulong bypass_mux_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
if (cv1800b_clk_getbit(mux->mux.base, &mux->bypass))
return 0;
return mux_set_rate(clk, rate);
}
static int bypass_mux_set_parent(struct clk *clk, struct clk *pclk)
{
struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
int index;
if (pclk->id == CV1800B_CLK_BYPASS) {
cv1800b_clk_setbit(mux->mux.base, &mux->bypass);
return 0;
}
index = get_parent_index(pclk, mux->mux.parent_names,
mux->mux.num_parents);
if (index < 0)
return -EINVAL;
cv1800b_clk_clrbit(mux->mux.base, &mux->bypass);
cv1800b_clk_setfield(mux->mux.base, &mux->mux.mux, index);
return 0;
}
const struct clk_ops cv1800b_clk_bypass_mux_ops = {
.disable = mux_disable,
.enable = mux_enable,
.get_rate = bypass_mux_get_rate,
.set_rate = bypass_mux_set_rate,
.set_parent = bypass_mux_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_bypass_mux) = {
.name = "cv1800b_clk_bypass_mux",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_bypass_mux_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* MMUX */
#define to_cv1800b_clk_mmux(_clk) \
container_of(_clk, struct cv1800b_clk_mmux, clk)
static int mmux_enable(struct clk *clk)
{
struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
return cv1800b_clk_setbit(mmux->base, &mmux->gate);
}
static int mmux_disable(struct clk *clk)
{
struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
return cv1800b_clk_clrbit(mmux->base, &mmux->gate);
}
static ulong mmux_get_rate(struct clk *clk)
{
struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
int clk_sel = 1;
ulong reg, val;
if (cv1800b_clk_getbit(mmux->base, &mmux->bypass))
return 0;
if (cv1800b_clk_getbit(mmux->base, &mmux->clk_sel))
clk_sel = 0;
reg = readl(mmux->base + mmux->div[clk_sel].offset);
if (mmux->div_init[clk_sel] == 0 || reg & CLK_DIV_EN_FACTOR)
val = cv1800b_clk_getfield(mmux->base, &mmux->div[clk_sel]);
else
val = mmux->div_init[clk_sel];
return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
}
static ulong mmux_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
int clk_sel = 1;
ulong parent_rate = clk_get_parent_rate(clk);
ulong val;
if (cv1800b_clk_getbit(mmux->base, &mmux->bypass))
return 0;
if (cv1800b_clk_getbit(mmux->base, &mmux->clk_sel))
clk_sel = 0;
val = DIV_ROUND_UP_ULL(parent_rate, rate);
val = min_t(u32, val, clk_div_mask(mmux->div[clk_sel].width));
cv1800b_clk_setfield(mmux->base, &mmux->div[clk_sel], val);
if (mmux->div_init[clk_sel] > 0)
setbits_le32(mmux->base + mmux->div[clk_sel].offset,
CLK_DIV_EN_FACTOR);
return DIV_ROUND_UP_ULL(parent_rate, val);
}
static int mmux_set_parent(struct clk *clk, struct clk *pclk)
{
struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
const char *pname = clk_hw_get_name(pclk);
int i;
u8 clk_sel, index;
if (pclk->id == CV1800B_CLK_BYPASS) {
cv1800b_clk_setbit(mmux->base, &mmux->bypass);
return 0;
}
for (i = 0; i < mmux->num_parents; i++) {
if (!strcmp(pname, mmux->parent_infos[i].name))
break;
}
if (i == mmux->num_parents)
return -EINVAL;
clk_sel = mmux->parent_infos[i].clk_sel;
index = mmux->parent_infos[i].index;
cv1800b_clk_clrbit(mmux->base, &mmux->bypass);
if (clk_sel)
cv1800b_clk_clrbit(mmux->base, &mmux->clk_sel);
else
cv1800b_clk_setbit(mmux->base, &mmux->clk_sel);
cv1800b_clk_setfield(mmux->base, &mmux->mux[clk_sel], index);
return 0;
}
const struct clk_ops cv1800b_clk_mmux_ops = {
.disable = mmux_disable,
.enable = mmux_enable,
.get_rate = mmux_get_rate,
.set_rate = mmux_set_rate,
.set_parent = mmux_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_mmux) = {
.name = "cv1800b_clk_mmux",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_mmux_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* AUDIO CLK */
#define to_cv1800b_clk_audio(_clk) \
container_of(_clk, struct cv1800b_clk_audio, clk)
static int aclk_enable(struct clk *clk)
{
struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
cv1800b_clk_setbit(aclk->base, &aclk->src_en);
cv1800b_clk_setbit(aclk->base, &aclk->output_en);
return 0;
}
static int aclk_disable(struct clk *clk)
{
struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
cv1800b_clk_clrbit(aclk->base, &aclk->src_en);
cv1800b_clk_clrbit(aclk->base, &aclk->output_en);
return 0;
}
static ulong aclk_get_rate(struct clk *clk)
{
struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
u64 parent_rate = clk_get_parent_rate(clk);
u32 m, n;
if (!cv1800b_clk_getbit(aclk->base, &aclk->div_en))
return 0;
m = cv1800b_clk_getfield(aclk->base, &aclk->m);
n = cv1800b_clk_getfield(aclk->base, &aclk->n);
return DIV_ROUND_UP_ULL(n * parent_rate, m * 2);
}
static u32 gcd(u32 a, u32 b)
{
u32 t;
while (b != 0) {
t = a % b;
a = b;
b = t;
}
return a;
}
static void aclk_determine_mn(ulong parent_rate, ulong rate, u32 *m, u32 *n)
{
u32 tm = parent_rate / 2;
u32 tn = rate;
u32 tcommon = gcd(tm, tn);
*m = tm / tcommon;
*n = tn / tcommon;
}
static ulong aclk_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
ulong parent_rate = clk_get_parent_rate(clk);
u32 m, n;
aclk_determine_mn(parent_rate, rate, &m, &n);
cv1800b_clk_setfield(aclk->base, &aclk->m, m);
cv1800b_clk_setfield(aclk->base, &aclk->n, n);
cv1800b_clk_setbit(aclk->base, &aclk->div_en);
cv1800b_clk_setbit(aclk->base, &aclk->div_up);
return DIV_ROUND_UP_ULL(parent_rate * n, m * 2);
}
const struct clk_ops cv1800b_clk_audio_ops = {
.disable = aclk_disable,
.enable = aclk_enable,
.get_rate = aclk_get_rate,
.set_rate = aclk_set_rate,
};
U_BOOT_DRIVER(cv1800b_clk_audio) = {
.name = "cv1800b_clk_audio",
.id = UCLASS_CLK,
.ops = &cv1800b_clk_audio_ops,
.flags = DM_FLAG_PRE_RELOC,
};

288
drivers/clk/sophgo/clk-ip.h Normal file
View File

@@ -0,0 +1,288 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
*
*/
#ifndef __CLK_SOPHGO_IP_H__
#define __CLK_SOPHGO_IP_H__
#include <clk.h>
#include "clk-common.h"
struct cv1800b_mmux_parent_info {
const char *name;
u8 clk_sel;
u8 index;
};
struct cv1800b_clk_gate {
struct clk clk;
const char *name;
const char *parent_name;
void __iomem *base;
struct cv1800b_clk_regbit gate;
};
struct cv1800b_clk_div {
struct clk clk;
const char *name;
const char *parent_name;
void __iomem *base;
struct cv1800b_clk_regbit gate;
struct cv1800b_clk_regfield div;
int div_init;
};
struct cv1800b_clk_bypass_div {
struct cv1800b_clk_div div;
struct cv1800b_clk_regbit bypass;
};
struct cv1800b_clk_fixed_div {
struct clk clk;
const char *name;
const char *parent_name;
void __iomem *base;
struct cv1800b_clk_regbit gate;
int div;
};
struct cv1800b_clk_bypass_fixed_div {
struct cv1800b_clk_fixed_div div;
struct cv1800b_clk_regbit bypass;
};
struct cv1800b_clk_mux {
struct clk clk;
const char *name;
const char * const *parent_names;
u8 num_parents;
void __iomem *base;
struct cv1800b_clk_regbit gate;
struct cv1800b_clk_regfield div;
int div_init;
struct cv1800b_clk_regfield mux;
};
struct cv1800b_clk_bypass_mux {
struct cv1800b_clk_mux mux;
struct cv1800b_clk_regbit bypass;
};
struct cv1800b_clk_mmux {
struct clk clk;
const char *name;
const struct cv1800b_mmux_parent_info *parent_infos;
u8 num_parents;
void __iomem *base;
struct cv1800b_clk_regbit gate;
struct cv1800b_clk_regfield div[2];
int div_init[2];
struct cv1800b_clk_regfield mux[2];
struct cv1800b_clk_regbit bypass;
struct cv1800b_clk_regbit clk_sel;
};
struct cv1800b_clk_audio {
struct clk clk;
const char *name;
const char *parent_name;
void __iomem *base;
struct cv1800b_clk_regbit src_en;
struct cv1800b_clk_regbit output_en;
struct cv1800b_clk_regbit div_en;
struct cv1800b_clk_regbit div_up;
struct cv1800b_clk_regfield m;
struct cv1800b_clk_regfield n;
};
#define CV1800B_GATE(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_name = _parent, \
.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift), \
}
#define CV1800B_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, _div_width, \
_div_init, _flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_name = _parent, \
.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift), \
.div = CV1800B_CLK_REGFIELD(_div_offset, _div_shift, \
_div_width), \
.div_init = _div_init, \
}
#define CV1800B_BYPASS_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, \
_div_width, _div_init, \
_bypass_offset, _bypass_shift, \
_flags) \
{ \
.div = CV1800B_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, _div_width, \
_div_init, _flags), \
.bypass = CV1800B_CLK_REGBIT(_bypass_offset, \
_bypass_shift), \
}
#define CV1800B_FIXED_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div, _flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_name = _parent, \
.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift), \
.div = _div, \
}
#define CV1800B_BYPASS_FIXED_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div, \
_bypass_offset, _bypass_shift, \
_flags) \
{ \
.div = CV1800B_FIXED_DIV(_id, _name, _parent, \
_gate_offset, _gate_shift, \
_div, _flags), \
.bypass = CV1800B_CLK_REGBIT(_bypass_offset, \
_bypass_shift) \
}
#define CV1800B_MUX(_id, _name, _parents, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, _div_width, _div_init, \
_mux_offset, _mux_shift, _mux_width, \
_flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_names = _parents, \
.num_parents = ARRAY_SIZE(_parents), \
.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift), \
.div = CV1800B_CLK_REGFIELD(_div_offset, _div_shift, \
_div_width), \
.div_init = _div_init, \
.mux = CV1800B_CLK_REGFIELD(_mux_offset, _mux_shift, \
_mux_width), \
}
#define CV1800B_BYPASS_MUX(_id, _name, _parents, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, \
_div_width, _div_init, \
_mux_offset, _mux_shift, _mux_width, \
_bypass_offset, _bypass_shift, \
_flags) \
{ \
.mux = CV1800B_MUX(_id, _name, _parents, \
_gate_offset, _gate_shift, \
_div_offset, _div_shift, \
_div_width, _div_init, \
_mux_offset, _mux_shift, _mux_width, \
_flags), \
.bypass = CV1800B_CLK_REGBIT(_bypass_offset, \
_bypass_shift), \
}
#define CV1800B_MMUX(_id, _name, _parents, \
_gate_offset, _gate_shift, \
_div0_offset, _div0_shift, _div0_width, _div0_init,\
_div1_offset, _div1_shift, _div1_width, _div1_init,\
_mux0_offset, _mux0_shift, _mux0_width, \
_mux1_offset, _mux1_shift, _mux1_width, \
_bypass_offset, _bypass_shift, \
_clk_sel_offset, _clk_sel_shift, \
_flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_infos = _parents, \
.num_parents = ARRAY_SIZE(_parents), \
.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift), \
.div = { \
CV1800B_CLK_REGFIELD(_div0_offset, _div0_shift, \
_div0_width), \
CV1800B_CLK_REGFIELD(_div1_offset, _div1_shift, \
_div1_width), \
}, \
.div_init = { _div0_init, _div1_init }, \
.mux = { \
CV1800B_CLK_REGFIELD(_mux0_offset, _mux0_shift, \
_mux0_width), \
CV1800B_CLK_REGFIELD(_mux1_offset, _mux1_shift, \
_mux1_width), \
}, \
.bypass = CV1800B_CLK_REGBIT(_bypass_offset, \
_bypass_shift), \
.clk_sel = CV1800B_CLK_REGBIT(_clk_sel_offset, \
_clk_sel_shift), \
}
#define CV1800B_AUDIO(_id, _name, _parent, \
_src_en_offset, _src_en_shift, \
_output_en_offset, _output_en_shift, \
_div_en_offset, _div_en_shift, \
_div_up_offset, _div_up_shift, \
_m_offset, _m_shift, _m_width, \
_n_offset, _n_shift, _n_width, \
_flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_name = _parent, \
.src_en = CV1800B_CLK_REGBIT(_src_en_offset, \
_src_en_shift), \
.output_en = CV1800B_CLK_REGBIT(_output_en_offset, \
_output_en_shift), \
.div_en = CV1800B_CLK_REGBIT(_div_en_offset, \
_div_en_shift), \
.div_up = CV1800B_CLK_REGBIT(_div_up_offset, \
_div_up_shift), \
.m = CV1800B_CLK_REGFIELD(_m_offset, _m_shift, \
_m_width), \
.n = CV1800B_CLK_REGFIELD(_n_offset, _n_shift, \
_n_width), \
}
extern const struct clk_ops cv1800b_clk_gate_ops;
extern const struct clk_ops cv1800b_clk_div_ops;
extern const struct clk_ops cv1800b_clk_bypass_div_ops;
extern const struct clk_ops cv1800b_clk_fixed_div_ops;
extern const struct clk_ops cv1800b_clk_bypass_fixed_div_ops;
extern const struct clk_ops cv1800b_clk_mux_ops;
extern const struct clk_ops cv1800b_clk_bypass_mux_ops;
extern const struct clk_ops cv1800b_clk_mmux_ops;
extern const struct clk_ops cv1800b_clk_audio_ops;
#endif /* __CLK_SOPHGO_IP_H__ */

View File

@@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
*/
#include <clk-uclass.h>
#include <dm.h>
#include <div64.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/kernel.h>
#include "clk-common.h"
#include "clk-pll.h"
#define PLL_PRE_DIV_MIN 1
#define PLL_PRE_DIV_MAX 127
#define PLL_POST_DIV_MIN 1
#define PLL_POST_DIV_MAX 127
#define PLL_DIV_MIN 6
#define PLL_DIV_MAX 127
#define PLL_ICTRL_MIN 0
#define PLL_ICTRL_MAX 7
#define PLL_MODE_MIN 0
#define PLL_MODE_MAX 3
#define FOR_RANGE(x, RANGE) for (x = RANGE##_MIN; x <= RANGE##_MAX; x++)
#define PLL_ICTRL GENMASK(26, 24)
#define PLL_DIV_SEL GENMASK(23, 17)
#define PLL_SEL_MODE GENMASK(16, 15)
#define PLL_POST_DIV_SEL GENMASK(14, 8)
#define PLL_PRE_DIV_SEL GENMASK(6, 0)
#define PLL_MASK_ALL (PLL_ICTRL | PLL_DIV_SEL | PLL_SEL_MODE | PLL_POST_DIV_SEL | PLL_PRE_DIV_SEL)
/* IPLL */
#define to_clk_ipll(dev) container_of(dev, struct cv1800b_clk_ipll, clk)
static int cv1800b_ipll_enable(struct clk *clk)
{
struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
cv1800b_clk_clrbit(pll->base, &pll->pll_pwd);
return 0;
}
static int cv1800b_ipll_disable(struct clk *clk)
{
struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
cv1800b_clk_setbit(pll->base, &pll->pll_pwd);
return 0;
}
static ulong cv1800b_ipll_get_rate(struct clk *clk)
{
struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
ulong parent_rate = clk_get_parent_rate(clk);
u32 reg = readl(pll->base + pll->pll_reg);
u32 pre_div = FIELD_GET(PLL_PRE_DIV_SEL, reg);
u32 post_div = FIELD_GET(PLL_POST_DIV_SEL, reg);
u32 div = FIELD_GET(PLL_DIV_SEL, reg);
return DIV_ROUND_DOWN_ULL(parent_rate * div, pre_div * post_div);
}
static ulong cv1800b_ipll_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
ulong parent_rate = clk_get_parent_rate(clk);
u32 pre_div, post_div, div;
u32 pre_div_sel, post_div_sel, div_sel;
ulong new_rate, best_rate = 0;
u32 mode, ictrl;
u32 test, val;
FOR_RANGE(pre_div, PLL_PRE_DIV)
{
FOR_RANGE(post_div, PLL_POST_DIV)
{
FOR_RANGE(div, PLL_DIV)
{
new_rate =
DIV_ROUND_DOWN_ULL(parent_rate * div, pre_div * post_div);
if (rate - new_rate < rate - best_rate) {
best_rate = new_rate;
pre_div_sel = pre_div;
post_div_sel = post_div;
div_sel = div;
}
}
}
}
FOR_RANGE(mode, PLL_MODE)
{
FOR_RANGE(ictrl, PLL_ICTRL)
{
test = 184 * (1 + mode) * (1 + ictrl) / 2;
if (test > 20 * div_sel && test < 35 * div_sel) {
val = FIELD_PREP(PLL_PRE_DIV_SEL, pre_div_sel) |
FIELD_PREP(PLL_POST_DIV_SEL, post_div_sel) |
FIELD_PREP(PLL_DIV_SEL, div_sel) |
FIELD_PREP(PLL_ICTRL, ictrl) |
FIELD_PREP(PLL_SEL_MODE, mode);
clrsetbits_le32(pll->base + pll->pll_reg, PLL_MASK_ALL, val);
return best_rate;
}
}
}
return -EINVAL;
}
const struct clk_ops cv1800b_ipll_ops = {
.enable = cv1800b_ipll_enable,
.disable = cv1800b_ipll_disable,
.get_rate = cv1800b_ipll_get_rate,
.set_rate = cv1800b_ipll_set_rate,
};
U_BOOT_DRIVER(cv1800b_clk_ipll) = {
.name = "cv1800b_clk_ipll",
.id = UCLASS_CLK,
.ops = &cv1800b_ipll_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* FPLL */
#define to_clk_fpll(dev) container_of(dev, struct cv1800b_clk_fpll, ipll.clk)
static ulong cv1800b_fpll_get_rate(struct clk *clk)
{
struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
u32 val, syn_set;
u32 pre_div, post_div, div;
u8 mult = 1;
ulong divisor, remainder, rate;
if (!cv1800b_clk_getbit(pll->ipll.base, &pll->syn.en))
return cv1800b_ipll_get_rate(clk);
syn_set = readl(pll->ipll.base + pll->syn.set);
if (syn_set == 0)
return 0;
val = readl(pll->ipll.base + pll->ipll.pll_reg);
pre_div = FIELD_GET(PLL_PRE_DIV_SEL, val);
post_div = FIELD_GET(PLL_POST_DIV_SEL, val);
div = FIELD_GET(PLL_DIV_SEL, val);
if (cv1800b_clk_getbit(pll->ipll.base, &pll->syn.clk_half))
mult = 2;
divisor = (ulong)pre_div * post_div * syn_set;
rate = (clk_get_parent_rate(clk) * div) << 25;
remainder = rate % divisor;
rate /= divisor;
return rate * mult + DIV_ROUND_CLOSEST_ULL(remainder * mult, divisor);
}
static ulong cv1800b_find_syn(ulong rate, ulong parent_rate, ulong pre_div, ulong post_div,
ulong div, u32 *syn)
{
u32 syn_min = (4 << 26) + 1;
u32 syn_max = U32_MAX;
u32 mid;
ulong new_rate;
u32 mult = 1;
ulong divisor, remainder;
while (syn_min < syn_max) {
mid = ((ulong)syn_min + syn_max) / 2;
divisor = pre_div * post_div * mid;
new_rate = (parent_rate * div) << 25;
remainder = do_div(new_rate, divisor);
new_rate = new_rate * mult + DIV_ROUND_CLOSEST_ULL(remainder * mult, divisor);
if (new_rate > rate) {
syn_max = mid + 1;
} else if (new_rate < rate) {
syn_min = mid - 1;
} else {
syn_min = mid;
break;
}
}
*syn = syn_min;
return new_rate;
}
static ulong cv1800b_fpll_set_rate(struct clk *clk, ulong rate)
{
struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
ulong parent_rate = clk_get_parent_rate(clk);
u32 pre_div, post_div, div;
u32 pre_div_sel, post_div_sel, div_sel;
u32 syn, syn_sel;
ulong new_rate, best_rate = 0;
u32 mult = 1;
u32 mode, ictrl;
if (!cv1800b_clk_getbit(pll->ipll.base, &pll->syn.en))
return cv1800b_ipll_set_rate(clk, rate);
if (cv1800b_clk_getbit(pll->ipll.base, &pll->syn.clk_half))
mult = 2;
FOR_RANGE(pre_div, PLL_PRE_DIV)
{
FOR_RANGE(post_div, PLL_POST_DIV)
{
FOR_RANGE(div, PLL_DIV)
{
new_rate = cv1800b_find_syn(rate, parent_rate, pre_div, post_div,
div, &syn);
if (rate - new_rate < rate - best_rate) {
best_rate = new_rate;
pre_div_sel = pre_div;
post_div_sel = post_div;
div_sel = div;
syn_sel = syn;
}
}
}
}
FOR_RANGE(mode, PLL_MODE)
{
FOR_RANGE(ictrl, PLL_ICTRL)
{
u32 test = 184 * (1 + mode) * (1 + ictrl) / 2;
if (test > 10 * div_sel && test <= 24 * div_sel) {
u32 val = FIELD_PREP(PLL_PRE_DIV_SEL, pre_div_sel) |
FIELD_PREP(PLL_POST_DIV_SEL, post_div_sel) |
FIELD_PREP(PLL_DIV_SEL, div_sel) |
FIELD_PREP(PLL_ICTRL, ictrl) |
FIELD_PREP(PLL_SEL_MODE, mode);
clrsetbits_le32(pll->ipll.base + pll->ipll.pll_reg, PLL_MASK_ALL,
val);
writel(syn_sel, pll->ipll.base + pll->syn.set);
return best_rate;
}
}
}
return -EINVAL;
}
static int cv1800b_fpll_set_parent(struct clk *clk, struct clk *parent)
{
struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
if (parent->id == CV1800B_CLK_BYPASS)
cv1800b_clk_setbit(pll->ipll.base, &pll->syn.en);
else
cv1800b_clk_clrbit(pll->ipll.base, &pll->syn.en);
return 0;
}
const struct clk_ops cv1800b_fpll_ops = {
.enable = cv1800b_ipll_enable,
.disable = cv1800b_ipll_disable,
.get_rate = cv1800b_fpll_get_rate,
.set_rate = cv1800b_fpll_set_rate,
.set_parent = cv1800b_fpll_set_parent,
};
U_BOOT_DRIVER(cv1800b_clk_fpll) = {
.name = "cv1800b_clk_fpll",
.id = UCLASS_CLK,
.ops = &cv1800b_fpll_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@@ -0,0 +1,74 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
*
*/
#ifndef __clk_SOPHGO_PLL_H__
#define __clk_SOPHGO_PLL_H__
#include <clk.h>
#include "clk-common.h"
struct cv1800b_clk_synthesizer {
struct cv1800b_clk_regbit en;
struct cv1800b_clk_regbit clk_half;
u32 ctrl;
u32 set;
};
struct cv1800b_clk_ipll {
struct clk clk;
const char *name;
const char *parent_name;
void __iomem *base;
u32 pll_reg;
struct cv1800b_clk_regbit pll_pwd;
struct cv1800b_clk_regbit pll_status;
};
struct cv1800b_clk_fpll {
struct cv1800b_clk_ipll ipll;
struct cv1800b_clk_synthesizer syn;
};
#define CV1800B_IPLL(_id, _name, _parent_name, _pll_reg, _pll_pwd_offset, \
_pll_pwd_shift, _pll_status_offset, _pll_status_shift, \
_flags) \
{ \
.clk = { \
.id = CV1800B_CLK_ID_TRANSFORM(_id), \
.flags = _flags, \
}, \
.name = _name, \
.parent_name = _parent_name, \
.pll_reg = _pll_reg, \
.pll_pwd = CV1800B_CLK_REGBIT(_pll_pwd_offset, _pll_pwd_shift), \
.pll_status = CV1800B_CLK_REGBIT(_pll_status_offset, \
_pll_status_shift), \
}
#define CV1800B_FPLL(_id, _name, _parent_name, _pll_reg, _pll_pwd_offset, \
_pll_pwd_shift, _pll_status_offset, _pll_status_shift, \
_syn_en_offset, _syn_en_shift, _syn_clk_half_offset, \
_syn_clk_half_shift, _syn_ctrl_offset, _syn_set_offset, \
_flags) \
{ \
.ipll = CV1800B_IPLL(_id, _name, _parent_name, _pll_reg, \
_pll_pwd_offset, _pll_pwd_shift, \
_pll_status_offset, _pll_status_shift, \
_flags), \
.syn = { \
.en = CV1800B_CLK_REGBIT(_syn_en_offset, _syn_en_shift),\
.clk_half = CV1800B_CLK_REGBIT(_syn_clk_half_offset, \
_syn_clk_half_shift), \
.ctrl = _syn_ctrl_offset, \
.set = _syn_set_offset, \
}, \
}
extern const struct clk_ops cv1800b_ipll_ops;
extern const struct clk_ops cv1800b_fpll_ops;
#endif /* __clk_SOPHGO_PLL_H__ */

View File

@@ -113,6 +113,7 @@ static int aspeed_mdio_probe(struct udevice *dev)
static const struct udevice_id aspeed_mdio_ids[] = {
{ .compatible = "aspeed,ast2600-mdio" },
{ .compatible = "aspeed,ast2700-mdio" },
{ }
};

View File

@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/printk.h>
#include <linux/bitfield.h>
#include "ftgmac100.h"
@@ -57,6 +58,15 @@
enum ftgmac100_model {
FTGMAC100_MODEL_FARADAY,
FTGMAC100_MODEL_ASPEED,
FTGMAC100_MODEL_ASPEED_AST2700,
};
union ftgmac100_dma_addr {
dma_addr_t addr;
struct {
u32 lo;
u32 hi;
};
};
/**
@@ -96,6 +106,8 @@ struct ftgmac100_data {
/* End of RX/TX ring buffer bits. Depend on model */
u32 rxdes0_edorr_mask;
u32 txdes0_edotr_mask;
bool is_ast2700;
};
/*
@@ -222,7 +234,7 @@ static int ftgmac100_phy_init(struct udevice *dev)
struct phy_device *phydev;
int ret;
if (IS_ENABLED(CONFIG_DM_MDIO))
if (IS_ENABLED(CONFIG_DM_MDIO) && priv->phy_mode != PHY_INTERFACE_MODE_NCSI)
phydev = dm_eth_phy_connect(dev);
else
phydev = phy_connect(priv->bus, priv->phy_addr, dev, priv->phy_mode);
@@ -320,8 +332,9 @@ static int ftgmac100_start(struct udevice *dev)
struct eth_pdata *plat = dev_get_plat(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
union ftgmac100_dma_addr dma_addr = {.hi = 0, .lo = 0};
struct phy_device *phydev = priv->phydev;
unsigned int maccr;
unsigned int maccr, dblac, desc_size;
ulong start, end;
int ret;
int i;
@@ -341,6 +354,7 @@ static int ftgmac100_start(struct udevice *dev)
priv->rx_index = 0;
for (i = 0; i < PKTBUFSTX; i++) {
priv->txdes[i].txdes2 = 0;
priv->txdes[i].txdes3 = 0;
priv->txdes[i].txdes0 = 0;
}
@@ -351,7 +365,14 @@ static int ftgmac100_start(struct udevice *dev)
flush_dcache_range(start, end);
for (i = 0; i < PKTBUFSRX; i++) {
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
unsigned int ip_align = 0;
dma_addr.addr = (dma_addr_t)net_rx_packets[i];
priv->rxdes[i].rxdes2 = FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, dma_addr.hi);
/* For IP alignment */
if ((dma_addr.lo & (PKTALIGN - 1)) == 0)
ip_align = 2;
priv->rxdes[i].rxdes3 = dma_addr.lo + ip_align;
priv->rxdes[i].rxdes0 = 0;
}
priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask;
@@ -361,10 +382,25 @@ static int ftgmac100_start(struct udevice *dev)
flush_dcache_range(start, end);
/* transmit ring */
writel((u32)priv->txdes, &ftgmac100->txr_badr);
dma_addr.addr = (dma_addr_t)priv->txdes;
writel(dma_addr.lo, &ftgmac100->txr_badr);
writel(dma_addr.hi, &ftgmac100->txr_badr_hi);
/* receive ring */
writel((u32)priv->rxdes, &ftgmac100->rxr_badr);
dma_addr.addr = (dma_addr_t)priv->rxdes;
writel(dma_addr.lo, &ftgmac100->rxr_badr);
writel(dma_addr.hi, &ftgmac100->rxr_badr_hi);
/* Configure TX/RX decsriptor size
* This size is calculated based on cache line.
*/
desc_size = ARCH_DMA_MINALIGN / FTGMAC100_DESC_UNIT;
/* The descriptor size is at least 2 descriptor units. */
if (desc_size < 2)
desc_size = 2;
dblac = readl(&ftgmac100->dblac) & ~GENMASK(19, 12);
dblac |= FTGMAC100_DBLAC_RXDES_SIZE(desc_size) | FTGMAC100_DBLAC_TXDES_SIZE(desc_size);
writel(dblac, &ftgmac100->dblac);
/* poll receive descriptor automatically */
writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -382,6 +418,10 @@ static int ftgmac100_start(struct udevice *dev)
FTGMAC100_MACCR_RX_RUNT |
FTGMAC100_MACCR_RX_BROADPKT;
if (priv->is_ast2700 && (priv->phydev->interface == PHY_INTERFACE_MODE_RMII ||
priv->phydev->interface == PHY_INTERFACE_MODE_NCSI))
maccr |= FTGMAC100_MACCR_RMII_ENABLE;
writel(maccr, &ftgmac100->maccr);
ret = phy_startup(phydev);
@@ -410,6 +450,14 @@ static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length)
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/*
* Make sure there are no stale data in write-back over this area, which
* might get written into the memory while the ftgmac100 also writes
* into the same memory area.
*/
flush_dcache_range((ulong)net_rx_packets[priv->rx_index],
(ulong)net_rx_packets[priv->rx_index] + PKTSIZE_ALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
@@ -431,9 +479,11 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp)
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
union ftgmac100_dma_addr data_start = { .lo = 0, .hi = 0 };
ulong data_end;
data_start.hi = FIELD_GET(FTGMAC100_RXDES2_RXBUF_BADR_HI, curr_des->rxdes2);
data_start.lo = curr_des->rxdes3;
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
@@ -453,9 +503,9 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp)
__func__, priv->rx_index, rxlen);
/* Invalidate received data */
data_end = data_start + roundup(rxlen, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
data_end = data_start.addr + roundup(rxlen, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start.addr, data_end);
*packetp = (uchar *)data_start.addr;
return rxlen;
}
@@ -481,6 +531,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length)
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
union ftgmac100_dma_addr dma_addr;
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
@@ -499,10 +550,12 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length)
length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
curr_des->txdes3 = (unsigned int)packet;
dma_addr.addr = (dma_addr_t)packet;
curr_des->txdes2 = FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI, dma_addr.hi);
curr_des->txdes3 = dma_addr.lo;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_start = (ulong)dma_addr.addr;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
@@ -565,6 +618,11 @@ static int ftgmac100_of_to_plat(struct udevice *dev)
if (dev_get_driver_data(dev) == FTGMAC100_MODEL_ASPEED) {
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_ast2700 = false;
} else if (dev_get_driver_data(dev) == FTGMAC100_MODEL_ASPEED_AST2700) {
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_ast2700 = true;
} else {
priv->rxdes0_edorr_mask = BIT(15);
priv->txdes0_edotr_mask = BIT(15);
@@ -655,10 +713,11 @@ static const struct eth_ops ftgmac100_ops = {
};
static const struct udevice_id ftgmac100_ids[] = {
{ .compatible = "faraday,ftgmac100", .data = FTGMAC100_MODEL_FARADAY },
{ .compatible = "aspeed,ast2500-mac", .data = FTGMAC100_MODEL_ASPEED },
{ .compatible = "aspeed,ast2600-mac", .data = FTGMAC100_MODEL_ASPEED },
{ }
{ .compatible = "faraday,ftgmac100", .data = FTGMAC100_MODEL_FARADAY },
{ .compatible = "aspeed,ast2500-mac", .data = FTGMAC100_MODEL_ASPEED },
{ .compatible = "aspeed,ast2600-mac", .data = FTGMAC100_MODEL_ASPEED },
{ .compatible = "aspeed,ast2700-mac", .data = FTGMAC100_MODEL_ASPEED_AST2700 },
{}
};
U_BOOT_DRIVER(ftgmac100) = {

View File

@@ -66,6 +66,13 @@ struct ftgmac100 {
unsigned int rx_runt; /* 0xc0 */
unsigned int rx_crcer_ftl; /* 0xc4 */
unsigned int rx_col_lost; /* 0xc8 */
unsigned int reserved[43]; /* 0xcc - 0x174 */
unsigned int txr_badr_lo; /* 0x178, defined in ast2700 */
unsigned int txr_badr_hi; /* 0x17c, defined in ast2700 */
unsigned int hptxr_badr_lo; /* 0x180, defined in ast2700 */
unsigned int hptxr_badr_hi; /* 0x184, defined in ast2700 */
unsigned int rxr_badr_lo; /* 0x188, defined in ast2700 */
unsigned int rxr_badr_hi; /* 0x18c, defined in ast2700 */
};
/*
@@ -111,6 +118,7 @@ struct ftgmac100 {
#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10)
#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12)
#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16)
#define FTGMAC100_DESC_UNIT 8
#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20)
#define FTGMAC100_DBLAC_IFG_INC BIT(23)
@@ -157,6 +165,7 @@ struct ftgmac100 {
#define FTGMAC100_MACCR_RX_BROADPKT BIT(17)
#define FTGMAC100_MACCR_DISCARD_CRCERR BIT(18)
#define FTGMAC100_MACCR_FAST_MODE BIT(19)
#define FTGMAC100_MACCR_RMII_ENABLE BIT(20) /* defined in ast2700 */
#define FTGMAC100_MACCR_SW_RST BIT(31)
/*
@@ -183,7 +192,7 @@ struct ftgmac100_txdes {
unsigned int txdes1;
unsigned int txdes2; /* not used by HW */
unsigned int txdes3; /* TXBUF_BADR */
} __aligned(16);
} __aligned(ARCH_DMA_MINALIGN);
#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
#define FTGMAC100_TXDES0_EDOTR BIT(15)
@@ -201,6 +210,8 @@ struct ftgmac100_txdes {
#define FTGMAC100_TXDES1_TX2FIC BIT(30)
#define FTGMAC100_TXDES1_TXIC BIT(31)
#define FTGMAC100_TXDES2_TXBUF_BADR_HI GENMASK(18, 16)
/*
* Receive descriptor, aligned to 16 bytes
*/
@@ -209,7 +220,7 @@ struct ftgmac100_rxdes {
unsigned int rxdes1;
unsigned int rxdes2; /* not used by HW */
unsigned int rxdes3; /* RXBUF_BADR */
} __aligned(16);
} __aligned(ARCH_DMA_MINALIGN);
#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff)
#define FTGMAC100_RXDES0_EDORR BIT(15)
@@ -240,4 +251,6 @@ struct ftgmac100_rxdes {
#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR BIT(26)
#define FTGMAC100_RXDES1_IP_CHKSUM_ERR BIT(27)
#define FTGMAC100_RXDES2_RXBUF_BADR_HI GENMASK(18, 16)
#endif /* __FTGMAC100_H */

View File

@@ -14,7 +14,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_ASPEED_RAM) += aspeed/
obj-$(CONFIG_K3_DDRSS) += k3-ddrss/
obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o

View File

@@ -1,6 +1,7 @@
menuconfig ASPEED_RAM
bool "ASPEED SDRAM configuration"
depends on RAM && ARCH_ASPEED
depends on RAM
depends on ARCH_ASPEED || TARGET_ASPEED_AST2700_IBEX
default ARCH_ASPEED
help
Configuration options for DDR SDRAM on ASPEED systems.
@@ -8,8 +9,6 @@ menuconfig ASPEED_RAM
RAM initialisation is always built in for the platform. This menu
allows customisation of the configuration used.
if ASPEED_RAM
config ASPEED_DDR4_DUALX8
bool "Enable Dual X8 DDR4 die"
depends on ASPEED_RAM
@@ -74,4 +73,24 @@ config ASPEED_DDR4_1600
select DDR4 target data rate at 1600M
endchoice
endif # End of ASPEED_RAM
choice
prompt "AST2700 DDR target date rate"
default ASPEED_DDR_3200
depends on ASPEED_RAM
depends on TARGET_ASPEED_AST2700_IBEX
config ASPEED_DDR_1600
bool "1600 Mbps"
help
select DDR target data rate at 1600M
config ASPEED_DDR_2400
bool "2400 Mbps"
help
select DDR target data rate at 2400M
config ASPEED_DDR_3200
bool "3200 Mbps"
help
select DDR target data rate at 3200M
endchoice

View File

@@ -2,3 +2,4 @@
#
obj-$(CONFIG_ASPEED_AST2500) += sdram_ast2500.o
obj-$(CONFIG_ASPEED_AST2600) += sdram_ast2600.o
obj-$(CONFIG_TARGET_ASPEED_AST2700_IBEX) += sdram_ast2700.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -106,6 +106,12 @@ config AST_TIMER
This is mostly because they all share several registers which
makes it difficult to completely separate them.
config AST_IBEX_TIMER
bool "Aspeed ast2700 Ibex timer"
depends on TIMER
help
Select this to enable a timer support for the Ibex RV32-based MCUs in AST2700.
config ATCPIT100_TIMER
bool "ATCPIT100 timer support"
depends on TIMER

View File

@@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_)ANDES_PLMT_TIMER) += andes_plmt_timer.o
obj-$(CONFIG_ARC_TIMER) += arc_timer.o
obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o
obj-$(CONFIG_AST_TIMER) += ast_timer.o
obj-$(CONFIG_AST_IBEX_TIMER) += ast_ibex_timer.o
obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
obj-$(CONFIG_$(SPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o

View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2024 Aspeed Technology Inc.
*/
#include <asm/csr.h>
#include <asm/io.h>
#include <dm.h>
#include <errno.h>
#include <timer.h>
#define CSR_MCYCLE 0xb00
#define CSR_MCYCLEH 0xb80
static u64 ast_ibex_timer_get_count(struct udevice *dev)
{
uint32_t cnt_l, cnt_h;
cnt_l = csr_read(CSR_MCYCLE);
cnt_h = csr_read(CSR_MCYCLEH);
return ((uint64_t)cnt_h << 32) | cnt_l;
}
static int ast_ibex_timer_probe(struct udevice *dev)
{
return 0;
}
static const struct timer_ops ast_ibex_timer_ops = {
.get_count = ast_ibex_timer_get_count,
};
static const struct udevice_id ast_ibex_timer_ids[] = {
{ .compatible = "aspeed,ast2700-ibex-timer" },
{ }
};
U_BOOT_DRIVER(ast_ibex_timer) = {
.name = "ast_ibex_timer",
.id = UCLASS_TIMER,
.of_match = ast_ibex_timer_ids,
.probe = ast_ibex_timer_probe,
.ops = &ast_ibex_timer_ops,
};

View File

@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) Aspeed Technology Inc.
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#define CFG_SYS_UBOOT_BASE CONFIG_TEXT_BASE
#define CFG_SYS_SDRAM_BASE 0x80000000
#endif /* __CONFIG_H */

View File

@@ -0,0 +1,176 @@
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
/*
* Copyright (C) 2023 Sophgo Ltd.
*/
#ifndef __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
#define __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
#define CLK_MPLL 0
#define CLK_TPLL 1
#define CLK_FPLL 2
#define CLK_MIPIMPLL 3
#define CLK_A0PLL 4
#define CLK_DISPPLL 5
#define CLK_CAM0PLL 6
#define CLK_CAM1PLL 7
#define CLK_MIPIMPLL_D3 8
#define CLK_CAM0PLL_D2 9
#define CLK_CAM0PLL_D3 10
#define CLK_TPU 11
#define CLK_TPU_FAB 12
#define CLK_AHB_ROM 13
#define CLK_DDR_AXI_REG 14
#define CLK_RTC_25M 15
#define CLK_SRC_RTC_SYS_0 16
#define CLK_TEMPSEN 17
#define CLK_SARADC 18
#define CLK_EFUSE 19
#define CLK_APB_EFUSE 20
#define CLK_DEBUG 21
#define CLK_AP_DEBUG 22
#define CLK_XTAL_MISC 23
#define CLK_AXI4_EMMC 24
#define CLK_EMMC 25
#define CLK_EMMC_100K 26
#define CLK_AXI4_SD0 27
#define CLK_SD0 28
#define CLK_SD0_100K 29
#define CLK_AXI4_SD1 30
#define CLK_SD1 31
#define CLK_SD1_100K 32
#define CLK_SPI_NAND 33
#define CLK_ETH0_500M 34
#define CLK_AXI4_ETH0 35
#define CLK_ETH1_500M 36
#define CLK_AXI4_ETH1 37
#define CLK_APB_GPIO 38
#define CLK_APB_GPIO_INTR 39
#define CLK_GPIO_DB 40
#define CLK_AHB_SF 41
#define CLK_AHB_SF1 42
#define CLK_A24M 43
#define CLK_AUDSRC 44
#define CLK_APB_AUDSRC 45
#define CLK_SDMA_AXI 46
#define CLK_SDMA_AUD0 47
#define CLK_SDMA_AUD1 48
#define CLK_SDMA_AUD2 49
#define CLK_SDMA_AUD3 50
#define CLK_I2C 51
#define CLK_APB_I2C 52
#define CLK_APB_I2C0 53
#define CLK_APB_I2C1 54
#define CLK_APB_I2C2 55
#define CLK_APB_I2C3 56
#define CLK_APB_I2C4 57
#define CLK_APB_WDT 58
#define CLK_PWM_SRC 59
#define CLK_PWM 60
#define CLK_SPI 61
#define CLK_APB_SPI0 62
#define CLK_APB_SPI1 63
#define CLK_APB_SPI2 64
#define CLK_APB_SPI3 65
#define CLK_1M 66
#define CLK_CAM0_200 67
#define CLK_PM 68
#define CLK_TIMER0 69
#define CLK_TIMER1 70
#define CLK_TIMER2 71
#define CLK_TIMER3 72
#define CLK_TIMER4 73
#define CLK_TIMER5 74
#define CLK_TIMER6 75
#define CLK_TIMER7 76
#define CLK_UART0 77
#define CLK_APB_UART0 78
#define CLK_UART1 79
#define CLK_APB_UART1 80
#define CLK_UART2 81
#define CLK_APB_UART2 82
#define CLK_UART3 83
#define CLK_APB_UART3 84
#define CLK_UART4 85
#define CLK_APB_UART4 86
#define CLK_APB_I2S0 87
#define CLK_APB_I2S1 88
#define CLK_APB_I2S2 89
#define CLK_APB_I2S3 90
#define CLK_AXI4_USB 91
#define CLK_APB_USB 92
#define CLK_USB_125M 93
#define CLK_USB_33K 94
#define CLK_USB_12M 95
#define CLK_AXI4 96
#define CLK_AXI6 97
#define CLK_DSI_ESC 98
#define CLK_AXI_VIP 99
#define CLK_SRC_VIP_SYS_0 100
#define CLK_SRC_VIP_SYS_1 101
#define CLK_SRC_VIP_SYS_2 102
#define CLK_SRC_VIP_SYS_3 103
#define CLK_SRC_VIP_SYS_4 104
#define CLK_CSI_BE_VIP 105
#define CLK_CSI_MAC0_VIP 106
#define CLK_CSI_MAC1_VIP 107
#define CLK_CSI_MAC2_VIP 108
#define CLK_CSI0_RX_VIP 109
#define CLK_CSI1_RX_VIP 110
#define CLK_ISP_TOP_VIP 111
#define CLK_IMG_D_VIP 112
#define CLK_IMG_V_VIP 113
#define CLK_SC_TOP_VIP 114
#define CLK_SC_D_VIP 115
#define CLK_SC_V1_VIP 116
#define CLK_SC_V2_VIP 117
#define CLK_SC_V3_VIP 118
#define CLK_DWA_VIP 119
#define CLK_BT_VIP 120
#define CLK_DISP_VIP 121
#define CLK_DSI_MAC_VIP 122
#define CLK_LVDS0_VIP 123
#define CLK_LVDS1_VIP 124
#define CLK_PAD_VI_VIP 125
#define CLK_PAD_VI1_VIP 126
#define CLK_PAD_VI2_VIP 127
#define CLK_CFG_REG_VIP 128
#define CLK_VIP_IP0 129
#define CLK_VIP_IP1 130
#define CLK_VIP_IP2 131
#define CLK_VIP_IP3 132
#define CLK_IVE_VIP 133
#define CLK_RAW_VIP 134
#define CLK_OSDC_VIP 135
#define CLK_CAM0_VIP 136
#define CLK_AXI_VIDEO_CODEC 137
#define CLK_VC_SRC0 138
#define CLK_VC_SRC1 139
#define CLK_VC_SRC2 140
#define CLK_H264C 141
#define CLK_APB_H264C 142
#define CLK_H265C 143
#define CLK_APB_H265C 144
#define CLK_JPEG 145
#define CLK_APB_JPEG 146
#define CLK_CAM0 147
#define CLK_CAM1 148
#define CLK_WGN 149
#define CLK_WGN0 150
#define CLK_WGN1 151
#define CLK_WGN2 152
#define CLK_KEYSCAN 153
#define CLK_CFG_REG_VC 154
#define CLK_C906_0 155
#define CLK_C906_1 156
#define CLK_A53 157
#define CLK_CPU_AXI0 158
#define CLK_CPU_GIC 159
#define CLK_XTAL_AP 160
// Only for CV181x
#define CLK_DISP_SRC_VIP 161
#endif /* __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ */