Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c84fb6e819 | |||
| cb31306b7a | |||
| 3a635f0b71 | |||
| 5c7b37d082 | |||
| efdd9326a2 | |||
| c432453da6 | |||
| 75ba4f42c1 | |||
| 7bf984bee7 | |||
| 1b58103415 |
@@ -47,6 +47,9 @@ config TARGET_SIPEED_MAIX
|
||||
bool "Support Sipeed Maix Board"
|
||||
select SYS_CACHE_SHIFT_6
|
||||
|
||||
config TARGET_SPACEMIT_K3
|
||||
bool "Support SpacemiT K3 based Boards"
|
||||
|
||||
config TARGET_STARFIVE_VISIONFIVE2
|
||||
bool "Support StarFive VisionFive2 Board"
|
||||
select BOARD_LATE_INIT
|
||||
@@ -116,6 +119,7 @@ source "board/sipeed/maix/Kconfig"
|
||||
source "board/sophgo/milkv_duo/Kconfig"
|
||||
source "board/sophgo/licheerv_nano/Kconfig"
|
||||
source "board/spacemit/bananapi-f3/Kconfig"
|
||||
source "board/spacemit/k3-generic/Kconfig"
|
||||
source "board/starfive/visionfive2/Kconfig"
|
||||
source "board/thead/th1520_lpi4a/Kconfig"
|
||||
source "board/xilinx/mbv/Kconfig"
|
||||
@@ -129,6 +133,7 @@ source "arch/riscv/cpu/ast2700/Kconfig"
|
||||
source "arch/riscv/cpu/generic/Kconfig"
|
||||
source "arch/riscv/cpu/jh7110/Kconfig"
|
||||
source "arch/riscv/cpu/k1/Kconfig"
|
||||
source "arch/riscv/cpu/k3/Kconfig"
|
||||
source "arch/riscv/cpu/k230/Kconfig"
|
||||
source "arch/riscv/cpu/th1520/Kconfig"
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
|
||||
# Due to limitation of Kconfig, the following symbols cannot be selected here:
|
||||
# CONFIG_ARCH_RV64I
|
||||
# CONFIG_RISCV_SMODE
|
||||
|
||||
config SPACEMIT_K3
|
||||
bool
|
||||
select ARCH_EARLY_INIT_R
|
||||
select SUPPORT_SPL
|
||||
select SPL
|
||||
select BINMAN
|
||||
imply CPU
|
||||
imply CPU_RISCV
|
||||
imply SPL_CPU
|
||||
imply RISCV_ISA_ZICBOM
|
||||
imply FIT
|
||||
imply SPL_LOAD_FIT
|
||||
imply SPL_LOAD_FIT_FULL
|
||||
imply PINCTRL
|
||||
imply SPL_PINCTRL
|
||||
imply PINCTRL_SINGLE
|
||||
imply SYS_NS16550
|
||||
|
||||
if SPACEMIT_K3
|
||||
|
||||
config SYS_CPU
|
||||
default "k3"
|
||||
|
||||
config SPL_SMP
|
||||
default n
|
||||
|
||||
config SPL_TEXT_BASE
|
||||
hex
|
||||
default 0xc0801000
|
||||
|
||||
config SPL_MAX_SIZE
|
||||
hex
|
||||
default 0x6AF00
|
||||
|
||||
config SPL_BSS_START_ADDR
|
||||
hex
|
||||
default 0xc0874000
|
||||
|
||||
config SPL_BSS_MAX_SIZE
|
||||
hex
|
||||
default 0x3000
|
||||
|
||||
config SPL_OPENSBI_LOAD_ADDR
|
||||
hex
|
||||
default 0x100000000
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
|
||||
obj-$(CONFIG_XPL_BUILD) += spl.o
|
||||
obj-y += cpu.o
|
||||
obj-y += cache.o
|
||||
obj-y += dram.o
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <cpu_func.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#if CONFIG_IS_ENABLED(RISCV_MMODE)
|
||||
void icache_enable(void)
|
||||
{
|
||||
csr_set(0x7c0, 0x2);
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
csr_set(0x7c0, 0x1);
|
||||
csr_set(0x7f0, 0x1);
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return (csr_read(0x7c0) & 0x2) != 0;
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return (csr_read(0x7c0) & 0x1) != 0;
|
||||
}
|
||||
#endif /* CONFIG_IS_ENABLED(RISCV_MMODE) */
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#include <fdtdec.h>
|
||||
#include <init.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
__weak int dram_init(void)
|
||||
{
|
||||
return fdtdec_setup_mem_size_base();
|
||||
}
|
||||
|
||||
__weak int dram_init_banksize(void)
|
||||
{
|
||||
return fdtdec_setup_memory_banksize();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/spl.h>
|
||||
#include <spl.h>
|
||||
#include <cpu_func.h>
|
||||
|
||||
|
||||
void harts_early_init(void)
|
||||
{
|
||||
icache_enable();
|
||||
dcache_enable();
|
||||
}
|
||||
|
||||
void board_boot_order(u32 *spl_boot_list)
|
||||
{
|
||||
/* Boot from SPI NOR with YMODEM UART fallback. */
|
||||
spl_boot_list[0] = BOOT_DEVICE_SPI;
|
||||
spl_boot_list[1] = BOOT_DEVICE_UART;
|
||||
spl_boot_list[2] = BOOT_DEVICE_NONE;
|
||||
}
|
||||
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spl_early_init();
|
||||
if (ret)
|
||||
panic("spl_early_init() failed: %d\n", ret);
|
||||
|
||||
riscv_cpu_setup();
|
||||
|
||||
preloader_console_init();
|
||||
|
||||
ret = spl_board_init_f();
|
||||
if (ret)
|
||||
panic("spl_board_init_f() failed: %d\n", ret);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/ {
|
||||
cpus {
|
||||
bootph-all;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <24000000>;
|
||||
|
||||
cpu_0: cpu@0 {
|
||||
bootph-all;
|
||||
compatible = "spacemit,x100", "riscv";
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
riscv,isa = "rv64imafdcvh_zicbom_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zfhmin_zba_zbb_zbc_zbs_zkt_zvbb_zvbc_zvfh_zvfhmin_zvkb_zvkg_zvkn_zvknc_zvkned_zvkng_zvknha_zvknhb_zvks_zvksc_zvksed_zvksh_zvksg_zvkt_ssaia_sscofpmf_sstc_svinval_svnapot_svpbmt_smstateen";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "h",
|
||||
"zicbom", "zicboz", "zicntr", "zicond", "zicsr",
|
||||
"zifencei", "zihintpause", "zihpm", "zfh", "zfhmin",
|
||||
"zba", "zbb", "zbc", "zbs", "zkt", "zvbb", "zvbc",
|
||||
"zvfh", "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
|
||||
"zvkned", "zvkng", "zvknha", "zvknhb", "zvks",
|
||||
"zvksc", "zvksed", "zvksh", "zvksg", "zvkt", "ssaia",
|
||||
"sscofpmf", "sstc", "svinval", "svnapot", "svpbmt",
|
||||
"smstateen";
|
||||
riscv,cbom-block-size = <64>;
|
||||
/*riscv,cbop-block-size = <64>;*/
|
||||
riscv,cboz-block-size = <64>;
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <65536>;
|
||||
i-cache-sets = <256>;
|
||||
d-cache-block-size = <64>;
|
||||
d-cache-size = <65536>;
|
||||
d-cache-sets = <256>;
|
||||
next-level-cache = <&cluster0_l2_cache>;
|
||||
mmu-type = "riscv,sv39";
|
||||
};
|
||||
|
||||
cluster0_l2_cache: l2-cache0 {
|
||||
bootph-all;
|
||||
compatible = "cache";
|
||||
cache-block-size = <64>;
|
||||
cache-level = <2>;
|
||||
cache-size = <4194304>;
|
||||
cache-sets = <4096>;
|
||||
cache-unified;
|
||||
};
|
||||
|
||||
cluster1_l2_cache: l2-cache1 {
|
||||
compatible = "cache";
|
||||
cache-block-size = <64>;
|
||||
cache-level = <2>;
|
||||
cache-size = <4194304>;
|
||||
cache-sets = <4096>;
|
||||
cache-unified;
|
||||
};
|
||||
|
||||
cluster2_l2_cache: l2-cache2 {
|
||||
compatible = "cache";
|
||||
cache-block-size = <64>;
|
||||
cache-level = <2>;
|
||||
cache-size = <1048576>;
|
||||
cache-sets = <1024>;
|
||||
cache-unified;
|
||||
};
|
||||
|
||||
cluster3_l2_cache: l2-cache3 {
|
||||
compatible = "cache";
|
||||
cache-block-size = <64>;
|
||||
cache-level = <2>;
|
||||
cache-size = <1048576>;
|
||||
cache-sets = <1024>;
|
||||
cache-unified;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Copyright (c) 2025 Spacemit, Inc */
|
||||
|
||||
#include <dt-bindings/pinctrl/k3-pinctrl.h>
|
||||
|
||||
&pinctrl {
|
||||
pinctrl_uart0_0: uart0_0_grp {
|
||||
bootph-all;
|
||||
pinctrl-single,pins = <
|
||||
K3_PADCONF(149, MUX_MODE2, (PULL_UP | PAD_DS8)) /* tx */
|
||||
K3_PADCONF(150, MUX_MODE2, (PULL_UP | PAD_DS8)) /* rx */
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_uart0_1: uart0_1_grp {
|
||||
bootph-all;
|
||||
pinctrl-single,pins = <
|
||||
K3_PADCONF(132, MUX_MODE2, (PULL_UP | PAD_DS8)) /* tx */
|
||||
K3_PADCONF(133, MUX_MODE2, (PULL_UP | PAD_DS8)) /* rx */
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_uart0_2: uart0_2_grp {
|
||||
bootph-all;
|
||||
pinctrl-single,pins = <
|
||||
K3_PADCONF(145, MUX_MODE5, (PULL_UP | PAD_DS8)) /* tx */
|
||||
K3_PADCONF(146, MUX_MODE5, (PULL_UP | PAD_DS8)) /* rx */
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_uart0_3: uart0_3_grp {
|
||||
bootph-all;
|
||||
pinctrl-single,pins = <
|
||||
K3_PADCONF(42, MUX_MODE2, (PULL_UP | PAD_DS8)) /* tx */
|
||||
K3_PADCONF(43, MUX_MODE2, (PULL_UP | PAD_DS8)) /* rx */
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_uart0_4: uart0_4_grp {
|
||||
bootph-all;
|
||||
pinctrl-single,pins = <
|
||||
K3_PADCONF(93, MUX_MODE3, (PULL_UP | PAD_DS8)) /* tx */
|
||||
K3_PADCONF(94, MUX_MODE3, (PULL_UP | PAD_DS8)) /* rx */
|
||||
>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
/*
|
||||
* Copyright (C) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#include "k3.dtsi"
|
||||
#include "k3-pinctrl.dtsi"
|
||||
#include "binman.dtsi"
|
||||
|
||||
/ {
|
||||
model = "SpacemiT K3 DEB1 Board";
|
||||
compatible = "spacemit,k3-deb1", "spacemit,k3";
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&serial0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_uart0_0>;
|
||||
status = "okay";
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
&binman {
|
||||
bootinfo_nor {
|
||||
filename = "bootinfo_nor.bin";
|
||||
|
||||
mkimage {
|
||||
args = "-s -T spacemit-binfo";
|
||||
};
|
||||
};
|
||||
|
||||
spl {
|
||||
filename = "spacemit-spl-unsigned.bin";
|
||||
|
||||
mkimage {
|
||||
args = "-T spacemit-spl";
|
||||
offset = <0xFE0>;
|
||||
|
||||
section {
|
||||
// Use a section to pad SPL at 32B align-size, before passing to mkimage
|
||||
blob {
|
||||
align-size = <32>;
|
||||
filename = "spl/u-boot-spl.bin";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
/*
|
||||
* Copyright (C) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "k3-cpus.dtsi"
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
model = "SpacemiT K3";
|
||||
compatible = "spacemit,k3";
|
||||
|
||||
aliases {
|
||||
serial0 = &serial0;
|
||||
};
|
||||
|
||||
clocks {
|
||||
clk0: osc {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <66667000>;
|
||||
};
|
||||
vctcxo_24: vctcxo_24 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "vctcxo_24";
|
||||
};
|
||||
vctcxo_3: vctcxo_3 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <3000000>;
|
||||
clock-output-names = "vctcxo_3";
|
||||
};
|
||||
vctcxo_1: vctcxo_1 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <1000000>;
|
||||
clock-output-names = "vctcxo_1";
|
||||
};
|
||||
pll1_vco: pll1_vco {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24576000>;
|
||||
clock-output-names = "pll1_vco";
|
||||
};
|
||||
osc_32k: osc_32k {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32000>;
|
||||
clock-output-names = "osc_32k";
|
||||
};
|
||||
clk_dummy: clk_dummy {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "clk_dummy";
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
bootph-all;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
|
||||
ccu: clock-controller@d4050000 {
|
||||
bootph-all;
|
||||
compatible = "spacemit,k3-ccu";
|
||||
reg = <0x0 0xd4050000 0x0 0x209c>,
|
||||
<0x0 0xd4282800 0x0 0x400>,
|
||||
<0x0 0xd4015000 0x0 0x1000>,
|
||||
<0x0 0xd4090000 0x0 0x1000>,
|
||||
<0x0 0xd4282c00 0x0 0x400>,
|
||||
<0x0 0xd8440000 0x0 0x98>,
|
||||
<0x0 0xc0000000 0x0 0x4280>,
|
||||
<0x0 0xf0610000 0x0 0x20>,
|
||||
<0x0 0xc0880000 0x0 0xd100>;
|
||||
reg-names = "mpmu", "apmu", "apbc", "apbs", "ciu", "dciu", "ddrc", "apbc2", "rcpu";
|
||||
clocks = <&vctcxo_24>, <&vctcxo_3>, <&vctcxo_1>, <&pll1_vco>,
|
||||
<&osc_32k>, <&clk_dummy>;
|
||||
clock-names = "vctcxo_24", "vctcxo_3", "vctcxo_1", "pll1_vco",
|
||||
"osc_32k", "clk_dummy";
|
||||
#clock-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@d401e000 {
|
||||
bootph-all;
|
||||
compatible = "pinctrl-single";
|
||||
reg = <0x0 0xd401e000 0x0 0x400>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
#pinctrl-cells = <1>;
|
||||
#gpio-range-cells = <3>;
|
||||
pinctrl-single,register-width = <32>;
|
||||
pinctrl-single,function-mask = <0xffff>;
|
||||
|
||||
range: gpio-range {
|
||||
bootph-all;
|
||||
#pinctrl-single,gpio-range-cells = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
serial0: serial@d4017000 {
|
||||
bootph-all;
|
||||
compatible = "intel,xscale-uart";
|
||||
reg = <0x00000000 0xD4017000 0x00000000 0x00000100>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
clock-frequency = <14745600>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
|
||||
if TARGET_SPACEMIT_K3
|
||||
|
||||
config SYS_VENDOR
|
||||
default "spacemit"
|
||||
|
||||
config SYS_BOARD
|
||||
default "k3-generic"
|
||||
|
||||
config SYS_CONFIG_NAME
|
||||
default "spacemit-k3-generic"
|
||||
|
||||
config CUSTOM_SYS_INIT_SP_ADDR
|
||||
default 0xc0880000
|
||||
|
||||
config TEXT_BASE
|
||||
hex
|
||||
default 0x80200000 if RISCV_SMODE
|
||||
|
||||
config SYS_LOAD_ADDR
|
||||
hex
|
||||
default 0x102000000
|
||||
|
||||
config DEFAULT_DEVICE_TREE
|
||||
default "k3-spacemit-deb1"
|
||||
|
||||
config BOARD_SPECIFIC_OPTIONS
|
||||
def_bool y
|
||||
select SPACEMIT_K3
|
||||
select HAS_CUSTOM_SYS_INIT_SP_ADDR
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
|
||||
obj-y := k3-generic.o
|
||||
@@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
int board_init(void)
|
||||
{
|
||||
/* Add board-specific initialization */
|
||||
return 0;
|
||||
}
|
||||
@@ -185,6 +185,8 @@ static const table_entry_t uimage_type[] = {
|
||||
{ IH_TYPE_STARFIVE_SPL, "sfspl", "StarFive SPL Image" },
|
||||
{ IH_TYPE_TFA_BL31, "tfa-bl31", "TFA BL31 Image", },
|
||||
{ IH_TYPE_STM32IMAGE_V2, "stm32imagev2", "STMicroelectronics STM32 Image V2.0" },
|
||||
{ IH_TYPE_SPACEMIT_BOOTINFO, "spacemit-binfo", "SpacemiT BootInfo Binary Header" },
|
||||
{ IH_TYPE_SPACEMIT_SPL, "spacemit-spl", "SpacemiT BootROM loadable Image" },
|
||||
{ -1, "", "", },
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
CONFIG_RISCV=y
|
||||
CONFIG_TARGET_SPACEMIT_K3=y
|
||||
CONFIG_ARCH_RV64I=y
|
||||
CONFIG_RISCV_SMODE=y
|
||||
CONFIG_SPL_CLK=y
|
||||
CONFIG_SPACEMIT_K3_CCU=y
|
||||
@@ -284,5 +284,6 @@ source "drivers/clk/tegra/Kconfig"
|
||||
source "drivers/clk/ti/Kconfig"
|
||||
source "drivers/clk/thead/Kconfig"
|
||||
source "drivers/clk/uniphier/Kconfig"
|
||||
source "drivers/clk/spacemit/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -61,3 +61,4 @@ obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
|
||||
obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
|
||||
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
|
||||
obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
|
||||
obj-$(CONFIG_TARGET_SPACEMIT_K3) += spacemit/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# common clock support for SPACEMIT SoC family.
|
||||
|
||||
config SPACEMIT_K3_CCU
|
||||
tristate "Clock support for Spacemit k3 SoCs"
|
||||
depends on TARGET_SPACEMIT_K3
|
||||
select CLK
|
||||
select CLK_CCF
|
||||
select SPL_CLK_CCF if SPL
|
||||
help
|
||||
Build the driver for Spacemit K3 Clock Driver.
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Spacemit Clock specific Makefile
|
||||
#
|
||||
#SoC support
|
||||
obj-$(CONFIG_SPACEMIT_K3_CCU) += ccu-k3.o ccu_mix.o ccu_plla.o
|
||||
@@ -0,0 +1,308 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Spacemit k3 clock controller driver
|
||||
*
|
||||
* Copyright (c) 2023, spacemit Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <clk.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <asm/io.h>
|
||||
#include "common.h"
|
||||
#include "ccu_mix.h"
|
||||
#include "ccu_plla.h"
|
||||
#include "ccu-k3.h"
|
||||
|
||||
|
||||
struct spacemit_ccu_clk k3_clock_controller;
|
||||
struct clk vctcxo_24, vctcxo_3, vctcxo_1, pll1_vco, osc_32k, clk_dummy;
|
||||
|
||||
static SPACEMIT_CCU_FACTOR(pll1_2457p6_vco, "pll1_2457p6_vco", "pll1_vco",
|
||||
1, 100);
|
||||
|
||||
static const struct ccu_plla_rate_tbl pll2_rate_tbl[] = {
|
||||
PLLA_RATE(3000000000UL, 0x0b3e2000, 0x00000000, 0xa0558c8c),
|
||||
};
|
||||
|
||||
static SPACEMIT_CCU_PLLA(pll2, "pll2", &pll2_rate_tbl, ARRAY_SIZE(pll2_rate_tbl),
|
||||
BASE_TYPE_APBS, APBS_PLL2_SWCR1, APBS_PLL2_SWCR2, APBS_PLL2_SWCR3,
|
||||
MPMU_POSR, POSR_PLL2_LOCK, 1,
|
||||
0);
|
||||
|
||||
static SPACEMIT_CCU_GATE_FACTOR(pll1_d5, "pll1_d5", "pll1_2457p6_vco",
|
||||
BASE_TYPE_APBS, APBS_PLL1_SWCR2,
|
||||
BIT(4), BIT(4), 0x0,
|
||||
5, 1, 0);
|
||||
static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco",
|
||||
BASE_TYPE_APBS, APBS_PLL1_SWCR2,
|
||||
BIT(5), BIT(5), 0x0,
|
||||
6, 1, 0);
|
||||
static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco",
|
||||
BASE_TYPE_APBS, APBS_PLL1_SWCR2,
|
||||
BIT(7), BIT(7), 0x0,
|
||||
8, 1, 0);
|
||||
|
||||
static SPACEMIT_CCU_DIV_GATE(pll1_dx, "pll1_dx", "pll1_2457p6_vco",
|
||||
BASE_TYPE_APBS, APBS_PLL1_SWCR2,
|
||||
23, 5, BIT(22), BIT(22), 0x0,
|
||||
0);
|
||||
|
||||
static SPACEMIT_CCU_GATE_FACTOR(pll2_d8, "pll2_d8", "pll2",
|
||||
BASE_TYPE_APBS, APBS_PLL2_SWCR2,
|
||||
BIT(7), BIT(7), 0x0,
|
||||
8, 1, 0);
|
||||
|
||||
static SPACEMIT_CCU_GATE(pll1_d8_307p2, "pll1_d8_307p2", "pll1_d8",
|
||||
BASE_TYPE_MPMU, MPMU_ACGR,
|
||||
BIT(13), BIT(13), 0x0,
|
||||
0);
|
||||
static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6",
|
||||
BASE_TYPE_MPMU, MPMU_ACGR,
|
||||
BIT(0), BIT(0), 0x0,
|
||||
0);
|
||||
static SPACEMIT_CCU_GATE(pll1_d5_491p52, "pll1_d5_491p52", "pll1_d5",
|
||||
BASE_TYPE_MPMU, MPMU_ACGR,
|
||||
BIT(21), BIT(21), 0x0,
|
||||
0);
|
||||
static SPACEMIT_CCU_GATE_FACTOR(pll1_d10_245p76, "pll1_d10_245p76", "pll1_d5",
|
||||
BASE_TYPE_MPMU, MPMU_ACGR,
|
||||
BIT(18), BIT(18), 0x0,
|
||||
2, 1, 0);
|
||||
|
||||
static const char * const qspi_parent_names[] = {
|
||||
"pll1_d6_409p6", "pll2_d8", "pll1_d8_307p2", "pll1_d10_245p76",
|
||||
"clk_dummy", "pll1_dx", "pll1_d5_491p52", "clk_dummy"
|
||||
};
|
||||
|
||||
static SPACEMIT_CCU_DIV_MFC_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
|
||||
BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
|
||||
9, 3, BIT(12),
|
||||
6, 3, BIT(4), BIT(4), 0x0,
|
||||
0);
|
||||
|
||||
static SPACEMIT_CCU_GATE(qspi_bus_clk, "qspi_bus_clk", "clk_dummy",
|
||||
BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
|
||||
BIT(3), BIT(3), 0x0,
|
||||
0);
|
||||
|
||||
static struct spacemit_clk_table spacemit_k3_clks = {
|
||||
.clks = {
|
||||
[CLK_PLL1_2457P6] = &pll1_2457p6_vco.common.clk,
|
||||
[CLK_PLL2] = &pll2.common.clk,
|
||||
[CLK_PLL1_D5] = &pll1_d5.common.clk,
|
||||
[CLK_PLL1_D6] = &pll1_d6.common.clk,
|
||||
[CLK_PLL1_D8] = &pll1_d8.common.clk,
|
||||
[CLK_PLL1_DX] = &pll1_dx.common.clk,
|
||||
[CLK_PLL2_D8] = &pll2_d8.common.clk,
|
||||
[CLK_PLL1_307P2] = &pll1_d8_307p2.common.clk,
|
||||
[CLK_PLL1_409P6] = &pll1_d6_409p6.common.clk,
|
||||
[CLK_PLL1_491] = &pll1_d5_491p52.common.clk,
|
||||
[CLK_PLL1_245P76] = &pll1_d10_245p76.common.clk,
|
||||
[CLK_QSPI] = &qspi_clk.common.clk,
|
||||
[CLK_QSPI_BUS] = &qspi_bus_clk.common.clk,
|
||||
},
|
||||
.num = CLK_MAX_NO,
|
||||
};
|
||||
|
||||
static int ccu_of_xlate(struct clk *clk,
|
||||
struct ofnode_phandle_args *args)
|
||||
{
|
||||
if (args->args_count > 1) {
|
||||
pr_debug("Invalid args_count: %d\n", args->args_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (args->args_count) {
|
||||
clk->id = args->args[0];
|
||||
if (clk->id >= spacemit_k3_clks.num ||
|
||||
!spacemit_k3_clks.clks[clk->id]) {
|
||||
pr_debug("Unsupported clock id: %u\n", args->args[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
clk->id = 0;
|
||||
}
|
||||
|
||||
clk->data = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong ccu_clk_round_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
struct clk *c;
|
||||
int err = clk_get_by_id(clk->id, &c);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return clk_round_rate(c, rate);
|
||||
}
|
||||
|
||||
const struct clk_ops ccu_clk_ops = {
|
||||
.get_rate = ccf_clk_get_rate,
|
||||
.round_rate = ccu_clk_round_rate,
|
||||
.set_parent = ccf_clk_set_parent,
|
||||
.disable = ccf_clk_disable,
|
||||
.set_rate = ccf_clk_set_rate,
|
||||
.enable = ccf_clk_enable,
|
||||
.of_xlate = ccu_of_xlate,
|
||||
};
|
||||
|
||||
int ccu_common_init(struct clk * clk, struct spacemit_ccu_clk *clk_info, struct spacemit_clk_table *clks)
|
||||
{
|
||||
struct ccu_common *common = clk_to_ccu_common(clk);
|
||||
int ret;
|
||||
|
||||
if (!common)
|
||||
return -1;
|
||||
|
||||
switch(common->base_type){
|
||||
case BASE_TYPE_MPMU:
|
||||
common->base = clk_info->mpmu_base;
|
||||
break;
|
||||
case BASE_TYPE_APMU:
|
||||
common->base = clk_info->apmu_base;
|
||||
break;
|
||||
case BASE_TYPE_APBC:
|
||||
common->base = clk_info->apbc_base;
|
||||
break;
|
||||
case BASE_TYPE_APBS:
|
||||
common->base = clk_info->apbs_base;
|
||||
break;
|
||||
case BASE_TYPE_CIU:
|
||||
common->base = clk_info->ciu_base;
|
||||
break;
|
||||
case BASE_TYPE_DCIU:
|
||||
common->base = clk_info->dciu_base;
|
||||
break;
|
||||
case BASE_TYPE_DDRC:
|
||||
common->base = clk_info->ddrc_base;
|
||||
break;
|
||||
case BASE_TYPE_AUDC:
|
||||
common->base = clk_info->audio_ctrl_base;
|
||||
break;
|
||||
case BASE_TYPE_APBC2:
|
||||
common->base = clk_info->apbc2_base;
|
||||
break;
|
||||
case BASE_TYPE_RCPU:
|
||||
common->base = clk_info->rcpu_base;
|
||||
break;
|
||||
default:
|
||||
common->base = clk_info->apbc_base;
|
||||
break;
|
||||
|
||||
}
|
||||
common->clk_tbl = clks;
|
||||
if (common->is_pll) {
|
||||
struct ccu_plla *pll = clk_to_ccu_plla(clk);
|
||||
|
||||
pll->pll.lock_base = clk_info->mpmu_base;
|
||||
}
|
||||
|
||||
if(common->parent_name == NULL && common->parent_names != NULL)
|
||||
common->parent_name = common->parent_names[ccu_mix_get_parent(clk)];
|
||||
|
||||
ret = clk_register(clk, common->driver_name, common->name, common->parent_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spacemit_ccu_probe(struct spacemit_ccu_clk *clk_info,
|
||||
struct spacemit_clk_table *clks)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = CLK_PLL1_2457P6; i < clks->num ; i++) {
|
||||
struct clk *clk = clks->clks[i];
|
||||
int ret;
|
||||
|
||||
if (!clk)
|
||||
continue;
|
||||
|
||||
if (i >= CLK_VCTCXO_24)
|
||||
continue;
|
||||
|
||||
clk->id = i;
|
||||
ret = ccu_common_init(clk, clk_info, clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ccu_clk_dm(ulong id, struct clk *clk)
|
||||
{
|
||||
if (!IS_ERR(clk)){
|
||||
clk->id = id;
|
||||
spacemit_k3_clks.clks[id] = clk;
|
||||
}
|
||||
}
|
||||
|
||||
static int spacemit_k3_ccu_probe(struct udevice *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct spacemit_ccu_clk *clk_info = &k3_clock_controller;
|
||||
struct spacemit_clk_table *clks = &spacemit_k3_clks;
|
||||
|
||||
pr_debug("init clock start \n");
|
||||
|
||||
clk_info->mpmu_base = (void __iomem *)dev_remap_addr_index(dev, 0);
|
||||
if (!clk_info->mpmu_base) {
|
||||
pr_err("failed to map mpmu registers\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
clk_info->apmu_base = (void __iomem *)dev_remap_addr_index(dev, 1);
|
||||
if (!clk_info->apmu_base) {
|
||||
pr_err("failed to map apmu registers\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
clk_info->apbc_base = (void __iomem *)dev_remap_addr_index(dev, 2);
|
||||
if (!clk_info->apbc_base) {
|
||||
pr_err("failed to map apbc registers\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
clk_info->apbs_base = (void __iomem *)dev_remap_addr_index(dev, 3);
|
||||
if (!clk_info->apbs_base) {
|
||||
pr_err("failed to map apbs registers\n");
|
||||
goto out;
|
||||
}
|
||||
clk_get_by_name(dev, "vctcxo_24", &vctcxo_24);
|
||||
ccu_clk_dm(CLK_VCTCXO_24, dev_get_clk_ptr(vctcxo_24.dev));
|
||||
clk_get_by_name(dev, "vctcxo_3", &vctcxo_3);
|
||||
ccu_clk_dm(CLK_VCTCXO_3, dev_get_clk_ptr(vctcxo_3.dev));
|
||||
clk_get_by_name(dev, "vctcxo_1", &vctcxo_1);
|
||||
ccu_clk_dm(CLK_VCTCXO_1, dev_get_clk_ptr(vctcxo_1.dev));
|
||||
clk_get_by_name(dev, "pll1_vco", &pll1_vco);
|
||||
ccu_clk_dm(CLK_PLL1, dev_get_clk_ptr(pll1_vco.dev));
|
||||
clk_get_by_name(dev, "osc_32k", &osc_32k);
|
||||
ccu_clk_dm(OSC_32K, dev_get_clk_ptr(osc_32k.dev));
|
||||
clk_get_by_name(dev, "clk_dummy", &clk_dummy);
|
||||
ccu_clk_dm(CLK_DUMMY, dev_get_clk_ptr(clk_dummy.dev));
|
||||
|
||||
ret = spacemit_ccu_probe(clk_info, clks);
|
||||
pr_debug("init clock finish ret=%d \n", ret);
|
||||
if (!ret)
|
||||
return 0;
|
||||
out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct udevice_id ccu_clk_ids[] = {
|
||||
{ .compatible = "spacemit,k3-ccu" },
|
||||
{ },
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(spacemit_k3_ccu) = {
|
||||
.name = "k3-ccu",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = ccu_clk_ids,
|
||||
.ops = &ccu_clk_ops,
|
||||
.probe = spacemit_k3_ccu_probe,
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2025, spacemit Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CCU_SPACEMIT_K3_H_
|
||||
#define _CCU_SPACEMIT_K3_H_
|
||||
|
||||
#define APBS_PLL1_SWCR2 0x104
|
||||
#define APBS_PLL2_SWCR1 0x118
|
||||
#define APBS_PLL2_SWCR2 0x11c
|
||||
#define APBS_PLL2_SWCR3 0x120
|
||||
|
||||
#define MPMU_FCCR 0x0008
|
||||
#define MPMU_POSR 0x0010
|
||||
#define POSR_PLL2_LOCK BIT(25)
|
||||
#define MPMU_ACGR 0x1024
|
||||
|
||||
#define APMU_QSPI_CLK_RES_CTRL 0x060
|
||||
|
||||
#endif /* _CCU_SPACEMIT_K3_H_ */
|
||||
@@ -0,0 +1,453 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Spacemit clock type mix(div/mux/gate/factor)
|
||||
*
|
||||
* Copyright (c) 2023, spacemit Corporation.
|
||||
*
|
||||
*/
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <clk.h>
|
||||
#include <div64.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ccu_mix.h"
|
||||
|
||||
#define TIMEOUT_LIMIT (20000) /* max timeout 10000us */
|
||||
|
||||
static unsigned long ccu_rate_delta(unsigned long rate1, unsigned long rate2)
|
||||
{
|
||||
return rate1 > rate2 ? rate1 - rate2 : rate2 - rate1;
|
||||
}
|
||||
|
||||
static int ccu_mix_trigger_fc(struct clk *clk)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
unsigned long val = 0;
|
||||
|
||||
int ret = 0, timeout = 50;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 ||
|
||||
common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5 ||
|
||||
common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
|
||||
timeout = 50;
|
||||
val = readl(common->base + common->reg_ctrl);
|
||||
val |= common->fc;
|
||||
writel(val, common->base + common->reg_ctrl);
|
||||
|
||||
do {
|
||||
val = readl(common->base + common->reg_ctrl);
|
||||
timeout--;
|
||||
if (!(val & (common->fc)))
|
||||
break;
|
||||
} while (timeout);
|
||||
|
||||
if (timeout == 0) {
|
||||
timeout = 5000;
|
||||
do {
|
||||
val = readl(common->base + common->reg_ctrl);
|
||||
timeout--;
|
||||
if (!(val & (common->fc)))
|
||||
break;
|
||||
} while (timeout);
|
||||
if (timeout != 0) {
|
||||
ret = 0;
|
||||
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ccu_mix_disable(struct clk *clk)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_gate_config *gate = mix->gate;
|
||||
u32 tmp;
|
||||
|
||||
if (!gate)
|
||||
return 0;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
tmp = readl(common->base + common->reg_sel);
|
||||
else
|
||||
tmp = readl(common->base + common->reg_ctrl);
|
||||
|
||||
tmp &= ~gate->gate_mask;
|
||||
tmp |= gate->val_disable;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
writel(tmp, common->base + common->reg_sel);
|
||||
else
|
||||
writel(tmp, common->base + common->reg_ctrl);
|
||||
|
||||
if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
|
||||
udelay(200);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong ccu_mix_round_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int ccu_mix_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_mux_config *mux = mix->mux;
|
||||
int index = -ENOENT;
|
||||
u32 reg, i;
|
||||
int ret;
|
||||
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < common->num_parents; i++) {
|
||||
if (!strcmp(parent->dev->name, common->parent_names[i])) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
pr_info("Could not fetch index\n");
|
||||
return index;
|
||||
}
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
reg = readl(common->base + common->reg_sel);
|
||||
else
|
||||
reg = readl(common->base + common->reg_ctrl);
|
||||
|
||||
reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
writel(reg | (index << mux->shift),
|
||||
common->base + common->reg_sel);
|
||||
else
|
||||
writel(reg | (index << mux->shift),
|
||||
common->base + common->reg_ctrl);
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 ||
|
||||
common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
|
||||
ret = ccu_mix_trigger_fc(clk);
|
||||
if (ret)
|
||||
pr_info("%s of %s timeout\n", __func__, clk->dev->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccu_mix_enable(struct clk *clk)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_gate_config *gate = mix->gate;
|
||||
u32 tmp;
|
||||
u32 val = 0;
|
||||
int timeout_power = 1;
|
||||
|
||||
if (!gate)
|
||||
return 0;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
tmp = readl(common->base + common->reg_sel);
|
||||
else
|
||||
tmp = readl(common->base + common->reg_ctrl);
|
||||
|
||||
tmp &= ~gate->gate_mask;
|
||||
tmp |= gate->val_enable;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
writel(tmp, common->base + common->reg_sel);
|
||||
else
|
||||
writel(tmp, common->base + common->reg_ctrl);
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
val = readl(common->base + common->reg_sel);
|
||||
else
|
||||
val = readl(common->base + common->reg_ctrl);
|
||||
|
||||
while ((val & gate->gate_mask) != gate->val_enable &&
|
||||
(timeout_power < TIMEOUT_LIMIT)) {
|
||||
udelay(timeout_power);
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
val = readl(common->base + common->reg_sel);
|
||||
else
|
||||
val = readl(common->base + common->reg_ctrl);
|
||||
timeout_power *= 10;
|
||||
}
|
||||
|
||||
if (timeout_power > 1) {
|
||||
if (val == tmp)
|
||||
pr_info("write clk_gate %s timeout occur, read pass after %d us delay\n",
|
||||
clk_hw_get_name(&common->clk), timeout_power);
|
||||
else
|
||||
pr_info("write clk_gate %s timeout after %d us!\n",
|
||||
clk_hw_get_name(&common->clk), timeout_power);
|
||||
}
|
||||
|
||||
if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
|
||||
udelay(200);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong ccu_mix_get_rate(struct clk *clk)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_div_config *div = mix->div;
|
||||
unsigned long parent_rate = clk_get_parent_rate(clk);
|
||||
unsigned long val;
|
||||
u32 reg;
|
||||
|
||||
if (!div) {
|
||||
if (mix->factor)
|
||||
val = parent_rate * mix->factor->mul / mix->factor->div;
|
||||
else
|
||||
val = parent_rate;
|
||||
return val;
|
||||
}
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
reg = readl(common->base + common->reg_sel);
|
||||
else
|
||||
reg = readl(common->base + common->reg_ctrl);
|
||||
|
||||
val = reg >> div->shift;
|
||||
val &= (1 << div->width) - 1;
|
||||
|
||||
val = divider_recalc_rate(clk, parent_rate, val, div->table, div->flags,
|
||||
div->width);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned long ccu_mix_calc_best_rate(struct clk *clk, unsigned long rate,
|
||||
u32 *mux_val, u32 *div_val, u32 *parent_id)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_div_config *div = mix->div ? mix->div : NULL;
|
||||
struct ccu_mux_config *mux = mix->mux ? mix->mux : NULL;
|
||||
struct clk *parent = NULL;
|
||||
unsigned long parent_rate = 0, best_rate = 0, best_delta = ULONG_MAX;
|
||||
u32 i, j, p_id, div_max;
|
||||
|
||||
if (mux) {
|
||||
for (i = 0; i < common->num_parents; i++) {
|
||||
parent = NULL;
|
||||
for (p_id = 0; p_id < common->clk_tbl->num; p_id++) {
|
||||
parent = common->clk_tbl->clks[p_id];
|
||||
if (!parent)
|
||||
continue;
|
||||
if (!strcmp(parent->dev->name,
|
||||
common->parent_names[i])) {
|
||||
break;
|
||||
}
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = clk_get_rate(parent);
|
||||
if (!parent_rate)
|
||||
continue;
|
||||
|
||||
if (div)
|
||||
div_max = 1 << div->width;
|
||||
else
|
||||
div_max = 1;
|
||||
for (j = 1; j <= div_max; j++) {
|
||||
unsigned long candidate_rate =
|
||||
DIV_ROUND_UP_ULL(parent_rate, j);
|
||||
unsigned long delta =
|
||||
ccu_rate_delta(candidate_rate, rate);
|
||||
|
||||
if (delta < best_delta) {
|
||||
best_rate = candidate_rate;
|
||||
best_delta = delta;
|
||||
*mux_val = i;
|
||||
*div_val = j - 1;
|
||||
*parent_id = p_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent_rate = clk_get_parent_rate(clk);
|
||||
if (!parent_rate)
|
||||
return 0;
|
||||
|
||||
if (div)
|
||||
div_max = 1 << div->width;
|
||||
else
|
||||
div_max = 1;
|
||||
for (j = 1; j <= div_max; j++) {
|
||||
unsigned long candidate_rate =
|
||||
DIV_ROUND_UP_ULL(parent_rate, j);
|
||||
unsigned long delta = ccu_rate_delta(candidate_rate,
|
||||
rate);
|
||||
|
||||
if (delta < best_delta) {
|
||||
best_rate = candidate_rate;
|
||||
best_delta = delta;
|
||||
*div_val = j - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static ulong ccu_mix_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_div_config *div_config = mix->div ? mix->div : NULL;
|
||||
struct ccu_mux_config *mux_config = mix->mux ? mix->mux : NULL;
|
||||
unsigned long best_rate = 0;
|
||||
u32 cur_mux, cur_div, mux_val = 0, div_val = 0, parent_id = 0;
|
||||
struct clk *parent;
|
||||
unsigned long val;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
if (!div_config && !mux_config) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
best_rate = ccu_mix_calc_best_rate(clk, rate, &mux_val, &div_val,
|
||||
&parent_id);
|
||||
if (!best_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
reg = readl(common->base + common->reg_sel);
|
||||
else
|
||||
reg = readl(common->base + common->reg_ctrl);
|
||||
|
||||
if (mux_config) {
|
||||
cur_mux = reg >> mux_config->shift;
|
||||
cur_mux &= (1 << mux_config->width) - 1;
|
||||
if (cur_mux != mux_val) {
|
||||
parent = common->clk_tbl->clks[parent_id];
|
||||
if (!clk_valid(parent))
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_set_parent(clk, parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (div_config) {
|
||||
cur_div = reg >> div_config->shift;
|
||||
cur_div &= (1 << div_config->width) - 1;
|
||||
if (cur_div == div_val)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
val = div_val;
|
||||
if (val > BIT(div_config->width) - 1)
|
||||
return 0;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
reg = readl(common->base + common->reg_sel);
|
||||
else
|
||||
reg = readl(common->base + common->reg_ctrl);
|
||||
|
||||
reg &= ~GENMASK(div_config->width + div_config->shift - 1,
|
||||
div_config->shift);
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
writel(reg | (val << div_config->shift),
|
||||
common->base + common->reg_sel);
|
||||
else
|
||||
writel(reg | (val << div_config->shift),
|
||||
common->base + common->reg_ctrl);
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 ||
|
||||
common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5 ||
|
||||
common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
|
||||
ret = ccu_mix_trigger_fc(clk);
|
||||
if (ret)
|
||||
pr_info("%s of %s timeout\n", __func__, clk->dev->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int ccu_mix_get_parent(struct clk *clk)
|
||||
{
|
||||
struct ccu_mix *mix = clk_to_ccu_mix(clk);
|
||||
struct ccu_common *common = &mix->common;
|
||||
struct ccu_mux_config *mux = mix->mux;
|
||||
u32 reg;
|
||||
unsigned int parent;
|
||||
|
||||
if (!mux)
|
||||
return 0;
|
||||
|
||||
if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 ||
|
||||
common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
|
||||
reg = readl(common->base + common->reg_sel);
|
||||
else
|
||||
reg = readl(common->base + common->reg_ctrl);
|
||||
|
||||
parent = reg >> mux->shift;
|
||||
parent &= (1 << mux->width) - 1;
|
||||
|
||||
if (mux->table) {
|
||||
int num_parents = common->num_parents;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
if (mux->table[i] == parent)
|
||||
return i;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
const struct clk_ops ccu_mix_ops = {
|
||||
.disable = ccu_mix_disable,
|
||||
.round_rate = ccu_mix_round_rate,
|
||||
.set_parent = ccu_mix_set_parent,
|
||||
.enable = ccu_mix_enable,
|
||||
.get_rate = ccu_mix_get_rate,
|
||||
.set_rate = ccu_mix_set_rate,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ccu_clk_mix) = {
|
||||
.name = CCU_CLK_MIX,
|
||||
.id = UCLASS_CLK,
|
||||
.ops = &ccu_mix_ops,
|
||||
};
|
||||
@@ -0,0 +1,368 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023, spacemit Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CCU_MIX_H_
|
||||
#define _CCU_MIX_H_
|
||||
|
||||
#include "ccu-k3.h"
|
||||
#include "common.h"
|
||||
|
||||
#define CCU_CLK_MIX "ccu_clk_mix"
|
||||
#define SPACEMIT_CLK_GATE_NEED_DELAY BIT(0)
|
||||
|
||||
struct ccu_gate_config {
|
||||
u32 gate_mask;
|
||||
u32 val_enable;
|
||||
u32 val_disable;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct ccu_factor_config {
|
||||
u32 div;
|
||||
u32 mul;
|
||||
};
|
||||
|
||||
struct ccu_mux_config {
|
||||
u8 shift;
|
||||
u8 width;
|
||||
const u8 *table;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct ccu_div_config {
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u32 max;
|
||||
u32 offset;
|
||||
u32 flags;
|
||||
struct clk_div_table *table;
|
||||
};
|
||||
|
||||
struct ccu_mix {
|
||||
struct ccu_gate_config *gate;
|
||||
struct ccu_factor_config *factor;
|
||||
struct ccu_div_config *div;
|
||||
struct ccu_mux_config *mux;
|
||||
struct ccu_common common;
|
||||
};
|
||||
|
||||
#define CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, _flags) \
|
||||
(&(struct ccu_gate_config) { \
|
||||
.gate_mask = _gate_mask, \
|
||||
.val_enable = _val_enable, \
|
||||
.val_disable = _val_disable, \
|
||||
.flags = _flags, \
|
||||
})
|
||||
|
||||
#define CCU_FACTOR_INIT(_div, _mul) \
|
||||
(&(struct ccu_factor_config) { \
|
||||
.div = _div, \
|
||||
.mul = _mul, \
|
||||
})
|
||||
|
||||
|
||||
#define CCU_MUX_INIT(_shift, _width, _table, _flags) \
|
||||
(&(struct ccu_mux_config) { \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.table = _table, \
|
||||
.flags = _flags, \
|
||||
})
|
||||
|
||||
#define CCU_DIV_INIT(_shift, _width, _table, _flags) \
|
||||
(&(struct ccu_div_config) { \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.flags = _flags, \
|
||||
.table = _table, \
|
||||
})
|
||||
|
||||
#define SPACEMIT_CCU_GATE(_struct, _name, _parent, _base_type, _reg, \
|
||||
_gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
#define SPACEMIT_CCU_GATE_NO_PARENT(_struct, _name, _parent, _base_type, _reg, \
|
||||
_gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = SPACEMIT_CLK_NO_PARENT, \
|
||||
.num_parents = 0, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_FACTOR(_struct, _name, _parent, \
|
||||
_div, _mul) \
|
||||
struct ccu_mix _struct = { \
|
||||
.factor = CCU_FACTOR_INIT(_div, _mul), \
|
||||
.common = { \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_MUX(_struct, _name, _parents, _base_type, _reg, \
|
||||
_shift, _width, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.mux = CCU_MUX_INIT(_shift, _width, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV(_struct, _name, _parent, _base_type, _reg, \
|
||||
_shift, _width, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.div = CCU_DIV_INIT(_shift, _width, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_GATE_FACTOR(_struct, _name, _parent, _base_type, _reg, \
|
||||
_gate_mask, _val_enable, _val_disable, \
|
||||
_div, _mul, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.factor = CCU_FACTOR_INIT(_div, _mul), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define SPACEMIT_CCU_MUX_GATE(_struct, _name, _parents, _base_type, _reg, \
|
||||
_shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.mux = CCU_MUX_INIT(_shift, _width, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV_GATE(_struct, _name, _parent, _base_type, _reg, \
|
||||
_shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_shift, _width, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define SPACEMIT_CCU_DIV_MUX_GATE(_struct, _name, _parents, \
|
||||
_base_type, _reg_ctrl, \
|
||||
_mshift, _mwidth, \
|
||||
_muxshift, _muxwidth, \
|
||||
_gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV2_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, _reg_sel, \
|
||||
_mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable, \
|
||||
_flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_2REG_FC_V4, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.reg_sel = _reg_sel, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
|
||||
#define SPACEMIT_CCU_DIV_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \
|
||||
_mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable, \
|
||||
_flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_V2, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV_MFC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \
|
||||
_mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable, \
|
||||
_flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_MUX_V6, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV_FC_WITH_GATE(_struct, _name, _parent, _base_type, _reg_ctrl, \
|
||||
_mshift, _mwidth, _fc, _gate_mask, _val_enable, _val_disable, \
|
||||
_flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_V2, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_DIV_FC_MUX(_struct, _name, _parents, _base_type, _reg_ctrl, \
|
||||
_mshift, _mwidth, _fc, _muxshift, _muxwidth, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.div = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_V2, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_MUX_FC_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \
|
||||
_fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_V2, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_MUX_FC(_struct, _name, _parents, _base_type, _reg_ctrl, \
|
||||
_fc, _muxshift, _muxwidth, _flags) \
|
||||
struct ccu_mix _struct = { \
|
||||
.mux = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
|
||||
.common = { \
|
||||
.reg_type = CLK_DIV_TYPE_1REG_FC_V2, \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.fc = _fc, \
|
||||
.base_type = _base_type, \
|
||||
.name = _name, \
|
||||
.parent_names = _parents, \
|
||||
.num_parents = ARRAY_SIZE(_parents), \
|
||||
.driver_name = CCU_CLK_MIX, \
|
||||
.flags = _flags, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static inline struct ccu_mix *clk_to_ccu_mix(struct clk *clk)
|
||||
{
|
||||
struct ccu_common *common = clk_to_ccu_common(clk);
|
||||
|
||||
return container_of(common, struct ccu_mix, common);
|
||||
}
|
||||
|
||||
unsigned int ccu_mix_get_parent(struct clk *clk);
|
||||
|
||||
#endif /* _CCU_DIV_H_ */
|
||||
@@ -0,0 +1,267 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2024 SpacemiT Technology Co. Ltd
|
||||
* Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org>
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <clk.h>
|
||||
#include <div64.h>
|
||||
#include "ccu_plla.h"
|
||||
|
||||
#define PLL_MIN_FREQ 600000000
|
||||
#define PLL_MAX_FREQ 3400000000
|
||||
#define PLL_DELAYTIME 590 //(590*5)us
|
||||
|
||||
#define PLLA_SWCR2_MASK GENMASK(15, 8)
|
||||
|
||||
#define plla_readl(reg) readl(reg)
|
||||
#define plla_readl_pll_swcr1(p) plla_readl(p.base + p.reg_ctrl)
|
||||
#define plla_readl_pll_swcr2(p) plla_readl(p.base + p.reg_sel)
|
||||
#define plla_readl_pll_swcr3(p) plla_readl(p.base + p.reg_xtc)
|
||||
|
||||
#define plla_writel(val, reg) writel(val, reg)
|
||||
#define plla_writel_pll_swcr1(val, p) plla_writel(val, p.base + p.reg_ctrl)
|
||||
#define plla_writel_pll_swcr2(val, p) plla_writel(val, p.base + p.reg_sel)
|
||||
#define plla_writel_pll_swcr3(val, p) plla_writel(val, p.base + p.reg_xtc)
|
||||
|
||||
/* unified pllax_swcr1 for plla */
|
||||
union pllax_swcr1 {
|
||||
struct {
|
||||
unsigned int reg1:8;
|
||||
unsigned int reg2:8;
|
||||
unsigned int reg3:8;
|
||||
unsigned int reg4:8;
|
||||
} b;
|
||||
unsigned int v;
|
||||
};
|
||||
|
||||
/* unified pllax_swcr2 for plla */
|
||||
union pllax_swcr2 {
|
||||
struct {
|
||||
unsigned int div1_en:1;
|
||||
unsigned int div2_en:1;
|
||||
unsigned int div3_en:1;
|
||||
unsigned int div4_en:1;
|
||||
unsigned int div5_en:1;
|
||||
unsigned int div6_en:1;
|
||||
unsigned int div7_en:1;
|
||||
unsigned int div8_en:1;
|
||||
unsigned int reg0:8;
|
||||
unsigned int pll_en:1;
|
||||
unsigned int mon_cfg:4;
|
||||
unsigned int div10_en:1;
|
||||
unsigned int mmd_en:1;
|
||||
unsigned int mmd:5;
|
||||
unsigned int reserved2:3;
|
||||
unsigned int div64_en:1;
|
||||
} b;
|
||||
unsigned int v;
|
||||
};
|
||||
|
||||
/* unified pllax_swcr3 for plla */
|
||||
union pllax_swcr3{
|
||||
struct {
|
||||
unsigned int reg5:8;
|
||||
unsigned int reg6:8;
|
||||
unsigned int reg7:8;
|
||||
unsigned int reg8:8;
|
||||
} b;
|
||||
|
||||
unsigned int v;
|
||||
};
|
||||
|
||||
static int ccu_plla_is_enabled(struct clk *clk)
|
||||
{
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
union pllax_swcr2 swcr2;
|
||||
unsigned int enabled;
|
||||
|
||||
swcr2.v = plla_readl_pll_swcr2(p->common);
|
||||
enabled = swcr2.b.pll_en;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/* frequency unit Mhz, return pll vco freq */
|
||||
static ulong __get_vco_freq(struct clk *clk)
|
||||
{
|
||||
unsigned int size, i;
|
||||
struct ccu_plla_rate_tbl *freq_pll_regs_table;
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
union pllax_swcr1 swcr1;
|
||||
union pllax_swcr2 swcr2;
|
||||
union pllax_swcr3 swcr3;
|
||||
|
||||
swcr1.v = plla_readl_pll_swcr1(p->common);
|
||||
swcr2.v = plla_readl_pll_swcr2(p->common);
|
||||
swcr2.v &= PLLA_SWCR2_MASK;
|
||||
swcr3.v = plla_readl_pll_swcr3(p->common);
|
||||
|
||||
freq_pll_regs_table = p->pll.rate_tbl;
|
||||
size = p->pll.tbl_size;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((freq_pll_regs_table[i].swcr1 == swcr1.v) &&
|
||||
(freq_pll_regs_table[i].swcr2 == swcr2.v) &&
|
||||
(freq_pll_regs_table[i].swcr3 == swcr3.v))
|
||||
return freq_pll_regs_table[i].rate;
|
||||
}
|
||||
|
||||
pr_info("Unknown rate for clock\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccu_plla_enable(struct clk *clk)
|
||||
{
|
||||
unsigned int delaytime = PLL_DELAYTIME;
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
union pllax_swcr2 swcr2;
|
||||
|
||||
if (ccu_plla_is_enabled(clk))
|
||||
return 0;
|
||||
|
||||
swcr2.v = plla_readl_pll_swcr2(p->common);
|
||||
swcr2.b.pll_en = 1;
|
||||
plla_writel_pll_swcr2(swcr2.v, p->common);
|
||||
|
||||
/* check lock status */
|
||||
udelay(50);
|
||||
|
||||
while ((!(readl(p->pll.lock_base + p->pll.reg_lock) & p->pll.lock_enable_bit))
|
||||
&& delaytime) {
|
||||
udelay(5);
|
||||
delaytime--;
|
||||
}
|
||||
if (unlikely(!delaytime))
|
||||
pr_err("ccu_pll_enable enabling didn't get stable within 3000us!!!\n" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccu_plla_disable(struct clk *clk)
|
||||
{
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
union pllax_swcr2 swcr2;
|
||||
|
||||
swcr2.v = plla_readl_pll_swcr2(p->common);
|
||||
swcr2.b.pll_en = 0;
|
||||
plla_writel_pll_swcr2(swcr2.v, p->common);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* pll rate change requires sequence:
|
||||
* clock off -> change rate setting -> clock on
|
||||
* This function doesn't really change rate, but cache the config
|
||||
*/
|
||||
static ulong ccu_plla_set_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
unsigned int i, reg0 = 0;
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
struct ccu_plla_config *params = &p->pll;
|
||||
union pllax_swcr1 swcr1;
|
||||
union pllax_swcr1 swcr2;
|
||||
union pllax_swcr3 swcr3;
|
||||
bool found = false;
|
||||
bool pll_enabled = false;
|
||||
|
||||
if (ccu_plla_is_enabled(clk)) {
|
||||
pll_enabled = true;
|
||||
ccu_plla_disable(clk);
|
||||
}
|
||||
|
||||
/* setp 1: calculate fbd frcd kvco and band */
|
||||
if (params->rate_tbl) {
|
||||
for (i = 0; i < params->tbl_size; i++) {
|
||||
if (rate == params->rate_tbl[i].rate) {
|
||||
found = true;
|
||||
|
||||
swcr1.v = params->rate_tbl[i].swcr1;
|
||||
reg0 = params->rate_tbl[i].swcr2;
|
||||
swcr3.v = params->rate_tbl[i].swcr3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_err("don't find freq table for pll\n");
|
||||
if (pll_enabled)
|
||||
ccu_plla_enable(clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pr_err("unsupported pll rate %lu\n", rate);
|
||||
if (pll_enabled)
|
||||
ccu_plla_enable(clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* setp 2: set pll kvco/band and fbd/frcd setting */
|
||||
plla_writel_pll_swcr1(swcr1.v, p->common);
|
||||
|
||||
swcr2.v = plla_readl_pll_swcr2(p->common);
|
||||
swcr2.v &= ~PLLA_SWCR2_MASK;
|
||||
swcr2.v |= reg0;
|
||||
plla_writel_pll_swcr2(swcr2.v, p->common);
|
||||
|
||||
plla_writel_pll_swcr3(swcr3.v, p->common);
|
||||
|
||||
if (pll_enabled)
|
||||
ccu_plla_enable(clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong ccu_plla_get_rate(struct clk *clk)
|
||||
{
|
||||
ulong val;
|
||||
val = __get_vco_freq(clk);
|
||||
return val;
|
||||
}
|
||||
|
||||
static ulong ccu_plla_round_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
struct ccu_plla *p = clk_to_ccu_plla(clk);
|
||||
unsigned long max_rate = 0;
|
||||
unsigned int i;
|
||||
struct ccu_plla_config *params = &p->pll;
|
||||
|
||||
if (rate > PLL_MAX_FREQ || rate < PLL_MIN_FREQ) {
|
||||
pr_err("%lu rate out of range!\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->rate_tbl) {
|
||||
for (i = 0; i < params->tbl_size; i++) {
|
||||
if (params->rate_tbl[i].rate <= rate) {
|
||||
if (max_rate < params->rate_tbl[i].rate)
|
||||
max_rate = params->rate_tbl[i].rate;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_info("don't find freq table for pll\n");
|
||||
}
|
||||
return max_rate;
|
||||
}
|
||||
|
||||
const struct clk_ops ccu_plla_ops = {
|
||||
.enable = ccu_plla_enable,
|
||||
.disable = ccu_plla_disable,
|
||||
.set_rate = ccu_plla_set_rate,
|
||||
.get_rate = ccu_plla_get_rate,
|
||||
.round_rate = ccu_plla_round_rate,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ccu_clk_plla) = {
|
||||
.name = CCU_CLK_PLLA,
|
||||
.id = UCLASS_CLK,
|
||||
.ops = &ccu_plla_ops,
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2024 SpacemiT Technology Co. Ltd
|
||||
* Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org>
|
||||
*/
|
||||
|
||||
#ifndef _CCU_PLLA_H_
|
||||
#define _CCU_PLLA_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define CCU_CLK_PLLA "ccu_clk_plla"
|
||||
struct ccu_plla_rate_tbl {
|
||||
unsigned long long rate;
|
||||
u32 swcr1;
|
||||
u32 swcr2;
|
||||
u32 swcr3;
|
||||
};
|
||||
|
||||
struct ccu_plla_config {
|
||||
struct ccu_plla_rate_tbl *rate_tbl;
|
||||
u32 tbl_size;
|
||||
void __iomem *lock_base;
|
||||
u32 reg_lock;
|
||||
u32 lock_enable_bit;
|
||||
};
|
||||
|
||||
#define PLLA_RATE(_rate, _swcr1, _swcr2, _swcr3) \
|
||||
{ \
|
||||
.rate = _rate, \
|
||||
.swcr1 = _swcr1, \
|
||||
.swcr2 = _swcr2, \
|
||||
.swcr3 = _swcr3, \
|
||||
}
|
||||
|
||||
struct ccu_plla {
|
||||
struct ccu_plla_config pll;
|
||||
struct ccu_common common;
|
||||
};
|
||||
|
||||
#define _SPACEMIT_CCU_PLLA_CONFIG(_table, _size, _reg_lock, _lock_enable_bit) \
|
||||
{ \
|
||||
.rate_tbl = (struct ccu_plla_rate_tbl *)_table, \
|
||||
.tbl_size = _size, \
|
||||
.reg_lock = _reg_lock, \
|
||||
.lock_enable_bit = _lock_enable_bit, \
|
||||
}
|
||||
|
||||
#define SPACEMIT_CCU_PLLA(_struct, _name, _table, _size, \
|
||||
_base_type, _reg_ctrl, _reg_sel, _reg_xtc, \
|
||||
_reg_lock, _lock_enable_bit, _is_pll, \
|
||||
_flags) \
|
||||
struct ccu_plla _struct = { \
|
||||
.pll = _SPACEMIT_CCU_PLLA_CONFIG(_table, _size, _reg_lock, _lock_enable_bit), \
|
||||
.common = { \
|
||||
.reg_ctrl = _reg_ctrl, \
|
||||
.reg_sel = _reg_sel, \
|
||||
.reg_xtc = _reg_xtc, \
|
||||
.base_type = _base_type, \
|
||||
.is_pll = _is_pll, \
|
||||
.name = _name, \
|
||||
.parent_name = SPACEMIT_CLK_NO_PARENT, \
|
||||
.num_parents = 1, \
|
||||
.driver_name = CCU_CLK_PLLA, \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
static inline struct ccu_plla *clk_to_ccu_plla(struct clk *clk)
|
||||
{
|
||||
struct ccu_common *common = clk_to_ccu_common(clk);
|
||||
|
||||
return container_of(common, struct ccu_plla, common);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023, spacemit Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CCU_SPACEMIT_COMMON_H_
|
||||
#define _CCU_SPACEMIT_COMMON_H_
|
||||
|
||||
#include <clk.h>
|
||||
#include <clk-uclass.h>
|
||||
|
||||
#include <dt-bindings/clock/spacemit-k3-clock.h>
|
||||
|
||||
#define SPACEMIT_CLK_NO_PARENT "clk_dummy"
|
||||
|
||||
enum ccu_base_type{
|
||||
BASE_TYPE_MPMU = 0,
|
||||
BASE_TYPE_APMU = 1,
|
||||
BASE_TYPE_APBC = 2,
|
||||
BASE_TYPE_APBS = 3,
|
||||
BASE_TYPE_CIU = 4,
|
||||
BASE_TYPE_DCIU = 5,
|
||||
BASE_TYPE_DDRC = 6,
|
||||
BASE_TYPE_AUDC = 7,
|
||||
BASE_TYPE_APBC2 = 8,
|
||||
BASE_TYPE_RCPU = 9,
|
||||
};
|
||||
|
||||
enum {
|
||||
CLK_DIV_TYPE_1REG_NOFC_V1 = 0,
|
||||
CLK_DIV_TYPE_1REG_FC_V2,
|
||||
CLK_DIV_TYPE_2REG_NOFC_V3,
|
||||
CLK_DIV_TYPE_2REG_FC_V4,
|
||||
CLK_DIV_TYPE_1REG_FC_DIV_V5,
|
||||
CLK_DIV_TYPE_1REG_FC_MUX_V6,
|
||||
};
|
||||
|
||||
struct ccu_common {
|
||||
void __iomem *base;
|
||||
enum ccu_base_type base_type;
|
||||
u32 reg_type;
|
||||
u32 reg_ctrl;
|
||||
u32 reg_sel;
|
||||
u32 reg_xtc;
|
||||
u32 fc;
|
||||
bool is_pll;
|
||||
const char *name;
|
||||
const char *driver_name;
|
||||
const char *parent_name;
|
||||
const char * const *parent_names;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
struct clk clk;
|
||||
struct spacemit_clk_table * clk_tbl;
|
||||
};
|
||||
|
||||
struct spacemit_ccu_clk {
|
||||
void __iomem *mpmu_base;
|
||||
void __iomem *apmu_base;
|
||||
void __iomem *apbc_base;
|
||||
void __iomem *apbs_base;
|
||||
void __iomem *ciu_base;
|
||||
void __iomem *dciu_base;
|
||||
void __iomem *ddrc_base;
|
||||
void __iomem *audio_ctrl_base;
|
||||
void __iomem *apbc2_base;
|
||||
void __iomem *rcpu_base;
|
||||
u32 pll2_freq;
|
||||
};
|
||||
|
||||
struct spacemit_clk_table{
|
||||
struct clk* clks[CLK_MAX_NO];
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
static inline struct ccu_common *clk_to_ccu_common(struct clk *clk)
|
||||
{
|
||||
return container_of(clk, struct ccu_common, clk);
|
||||
}
|
||||
|
||||
#endif /* _CCU_SPACEMIT_COMMON_H_ */
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2026, Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
#define CFG_SYS_NS16550_IER 0x40
|
||||
|
||||
#endif /* __CONFIG_H */
|
||||
@@ -0,0 +1,302 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ or MIT)
|
||||
|
||||
#ifndef _DT_BINDINGS_CLK_SPACEMIT_K3_H_
|
||||
#define _DT_BINDINGS_CLK_SPACEMIT_K3_H_
|
||||
|
||||
#define CLK_PLL1_2457P6 0
|
||||
#define CLK_PLL2 1
|
||||
#define CLK_PLL3 2
|
||||
#define CLK_PLL4 3
|
||||
#define CLK_PLL5 4
|
||||
#define CLK_PLL6 5
|
||||
#define CLK_PLL7 6
|
||||
#define CLK_PLL8 7
|
||||
#define CLK_PLL1_D2 8
|
||||
#define CLK_PLL1_D3 9
|
||||
#define CLK_PLL1_D4 10
|
||||
#define CLK_PLL1_D5 11
|
||||
#define CLK_PLL1_D6 12
|
||||
#define CLK_PLL1_D7 13
|
||||
#define CLK_PLL1_D8 14
|
||||
#define CLK_PLL1_DX 15
|
||||
#define CLK_PLL1_D64 16
|
||||
#define CLK_PLL1_D10_AUD 17
|
||||
#define CLK_PLL1_D100_AUD 18
|
||||
#define CLK_PLL2_D1 19
|
||||
#define CLK_PLL2_D2 20
|
||||
#define CLK_PLL2_D3 21
|
||||
#define CLK_PLL2_D4 22
|
||||
#define CLK_PLL2_D5 23
|
||||
#define CLK_PLL2_D6 24
|
||||
#define CLK_PLL2_D7 25
|
||||
#define CLK_PLL2_D8 26
|
||||
#define CLK_PLL2_66 27
|
||||
#define CLK_PLL2_33 28
|
||||
#define CLK_PLL2_50 29
|
||||
#define CLK_PLL2_25 30
|
||||
#define CLK_PLL2_20 31
|
||||
#define CLK_PLL2_D24_125 32
|
||||
#define CLK_PLL2_D120_25 33
|
||||
#define CLK_PLL3_D1 34
|
||||
#define CLK_PLL3_D2 35
|
||||
#define CLK_PLL3_D3 36
|
||||
#define CLK_PLL3_D4 37
|
||||
#define CLK_PLL3_D5 38
|
||||
#define CLK_PLL3_D6 39
|
||||
#define CLK_PLL3_D7 40
|
||||
#define CLK_PLL3_D8 41
|
||||
#define CLK_PLL4_D1 42
|
||||
#define CLK_PLL4_D2 43
|
||||
#define CLK_PLL4_D3 44
|
||||
#define CLK_PLL4_D4 45
|
||||
#define CLK_PLL4_D5 46
|
||||
#define CLK_PLL4_D6 47
|
||||
#define CLK_PLL4_D7 48
|
||||
#define CLK_PLL4_D8 49
|
||||
#define CLK_PLL5_D1 50
|
||||
#define CLK_PLL5_D2 51
|
||||
#define CLK_PLL5_D3 52
|
||||
#define CLK_PLL5_D4 53
|
||||
#define CLK_PLL5_D5 54
|
||||
#define CLK_PLL5_D6 55
|
||||
#define CLK_PLL5_D7 56
|
||||
#define CLK_PLL5_D8 57
|
||||
#define CLK_PLL6_D1 58
|
||||
#define CLK_PLL6_D2 59
|
||||
#define CLK_PLL6_D3 60
|
||||
#define CLK_PLL6_D4 61
|
||||
#define CLK_PLL6_D5 62
|
||||
#define CLK_PLL6_D6 63
|
||||
#define CLK_PLL6_D7 64
|
||||
#define CLK_PLL6_D8 65
|
||||
#define CLK_PLL6_80 66
|
||||
#define CLK_PLL6_40 67
|
||||
#define CLK_PLL6_20 68
|
||||
#define CLK_PLL7_D1 69
|
||||
#define CLK_PLL7_D2 70
|
||||
#define CLK_PLL7_D3 71
|
||||
#define CLK_PLL7_D4 72
|
||||
#define CLK_PLL7_D5 73
|
||||
#define CLK_PLL7_D6 74
|
||||
#define CLK_PLL7_D7 75
|
||||
#define CLK_PLL7_D8 76
|
||||
#define CLK_PLL8_D1 77
|
||||
#define CLK_PLL8_D2 78
|
||||
#define CLK_PLL8_D3 79
|
||||
#define CLK_PLL8_D4 80
|
||||
#define CLK_PLL8_D5 81
|
||||
#define CLK_PLL8_D6 82
|
||||
#define CLK_PLL8_D7 83
|
||||
#define CLK_PLL8_D8 84
|
||||
#define CLK_PLL1_307P2 85
|
||||
#define CLK_PLL1_76P8 86
|
||||
#define CLK_PLL1_61P44 87
|
||||
#define CLK_PLL1_153P6 88
|
||||
#define CLK_PLL1_102P4 89
|
||||
#define CLK_PLL1_51P2 90
|
||||
#define CLK_PLL1_51P2_AP 91
|
||||
#define CLK_PLL1_57P6 92
|
||||
#define CLK_PLL1_25P6 93
|
||||
#define CLK_PLL1_12P8 94
|
||||
#define CLK_PLL1_12P8_WDT 95
|
||||
#define CLK_PLL1_6P4 96
|
||||
#define CLK_PLL1_3P2 97
|
||||
#define CLK_PLL1_1P6 98
|
||||
#define CLK_PLL1_0P8 99
|
||||
#define CLK_PLL1_351 100
|
||||
#define CLK_PLL1_409P6 101
|
||||
#define CLK_PLL1_204P8 102
|
||||
#define CLK_PLL1_491 103
|
||||
#define CLK_PLL1_245P76 104
|
||||
#define CLK_PLL1_614 105
|
||||
#define CLK_PLL1_47P26 106
|
||||
#define CLK_PLL1_31P5 107
|
||||
#define CLK_PLL1_819 108
|
||||
#define CLK_PLL1_1228 109
|
||||
#define CLK_APB 110
|
||||
#define CLK_SLOW_UART1 111
|
||||
#define CLK_SLOW_UART2 112
|
||||
#define CLK_WDT 113
|
||||
#define CLK_RIPC 114
|
||||
#define CLK_UART1 115
|
||||
#define CLK_UART2 116
|
||||
#define CLK_UART3 117
|
||||
#define CLK_UART4 118
|
||||
#define CLK_UART5 119
|
||||
#define CLK_UART6 120
|
||||
#define CLK_UART7 121
|
||||
#define CLK_UART8 122
|
||||
#define CLK_UART9 123
|
||||
#define CLK_UART10 124
|
||||
#define CLK_GPIO 125
|
||||
#define CLK_PWM0 126
|
||||
#define CLK_PWM1 127
|
||||
#define CLK_PWM2 128
|
||||
#define CLK_PWM3 129
|
||||
#define CLK_PWM4 130
|
||||
#define CLK_PWM5 131
|
||||
#define CLK_PWM6 132
|
||||
#define CLK_PWM7 133
|
||||
#define CLK_PWM8 134
|
||||
#define CLK_PWM9 135
|
||||
#define CLK_PWM10 136
|
||||
#define CLK_PWM11 137
|
||||
#define CLK_PWM12 138
|
||||
#define CLK_PWM13 139
|
||||
#define CLK_PWM14 140
|
||||
#define CLK_PWM15 141
|
||||
#define CLK_PWM16 142
|
||||
#define CLK_PWM17 143
|
||||
#define CLK_PWM18 144
|
||||
#define CLK_PWM19 145
|
||||
#define CLK_SPI0 146
|
||||
#define CLK_SPI1 147
|
||||
#define CLK_SPI3 148
|
||||
#define CLK_RTC 149
|
||||
#define CLK_TWSI0 150
|
||||
#define CLK_TWSI1 151
|
||||
#define CLK_TWSI2 152
|
||||
#define CLK_TWSI4 153
|
||||
#define CLK_TWSI5 154
|
||||
#define CLK_TWSI6 155
|
||||
#define CLK_TWSI8 156
|
||||
#define CLK_TIMERS0 157
|
||||
#define CLK_TIMERS1 158
|
||||
#define CLK_TIMERS2 159
|
||||
#define CLK_TIMERS3 160
|
||||
#define CLK_TIMERS4 161
|
||||
#define CLK_TIMERS5 162
|
||||
#define CLK_TIMERS6 163
|
||||
#define CLK_TIMERS7 164
|
||||
#define CLK_AIB 165
|
||||
#define CLK_ONEWIRE 166
|
||||
#define CLK_I2S0 167
|
||||
#define CLK_I2S1 168
|
||||
#define CLK_I2S2 169
|
||||
#define CLK_I2S3 170
|
||||
#define CLK_I2S4 171
|
||||
#define CLK_I2S5 172
|
||||
#define CLK_DRO 173
|
||||
#define CLK_IR0 174
|
||||
#define CLK_IR1 175
|
||||
#define CLK_TSEN 176
|
||||
#define CLK_IPC_AP2RCPU 177
|
||||
#define CLK_CAN0 178
|
||||
#define CLK_CAN1 179
|
||||
#define CLK_CAN2 180
|
||||
#define CLK_CAN3 181
|
||||
#define CLK_CAN4 182
|
||||
#define CLK_CAN0_BUS 183
|
||||
#define CLK_CAN1_BUS 184
|
||||
#define CLK_CAN2_BUS 185
|
||||
#define CLK_CAN3_BUS 186
|
||||
#define CLK_CAN4_BUS 187
|
||||
#define CLK_AXICLK 188
|
||||
#define CLK_CCI550 189
|
||||
#define CLK_CPU_C1_PLL_SRC 190
|
||||
#define CLK_CPU_C3_PLL_SRC 191
|
||||
#define CLK_CPU_C0_CORE 192
|
||||
#define CLK_CPU_C1_CORE 193
|
||||
#define CLK_CPU_C2_CORE 194
|
||||
#define CLK_CPU_C3_CORE 195
|
||||
#define CLK_CCIC2PHY 196
|
||||
#define CLK_CCIC3PHY 197
|
||||
#define CLK_CSI 198
|
||||
#define CLK_ISP_BUS 199
|
||||
#define CLK_D1P_1228P8 200
|
||||
#define CLK_D1P_819P2 201
|
||||
#define CLK_D1P_614P4 202
|
||||
#define CLK_D1P_491P52 203
|
||||
#define CLK_D1P_409P6 204
|
||||
#define CLK_D1P_307P2 205
|
||||
#define CLK_D1P_245P76 206
|
||||
#define CLK_V2D 207
|
||||
#define CLK_DSI_ESC 208
|
||||
#define CLK_LCD_HCLK 209
|
||||
#define CLK_LCD_DSC 210
|
||||
#define CLK_LCD_PXCLK 211
|
||||
#define CLK_LCD_MCLK 212
|
||||
#define CLK_CCIC_4X 213
|
||||
#define CLK_CCIC1PHY 214
|
||||
#define CLK_SC2_HCLK 215
|
||||
#define CLK_SDH_AXI 216
|
||||
#define CLK_SDH0 217
|
||||
#define CLK_SDH1 218
|
||||
#define CLK_SDH2 219
|
||||
#define CLK_USB2_BUS 220
|
||||
#define CLK_USB3_PORTA_BUS 221
|
||||
#define CLK_USB3_PORTB_BUS 222
|
||||
#define CLK_USB3_PORTC_BUS 223
|
||||
#define CLK_USB3_PORTD_BUS 224
|
||||
#define CLK_QSPI 225
|
||||
#define CLK_QSPI_BUS 226
|
||||
#define CLK_DMA 227
|
||||
#define CLK_AES_WTM 228
|
||||
#define CLK_VPU 229
|
||||
#define CLK_DTC 230
|
||||
#define CLK_GPU 231
|
||||
#define CLK_MC_AHB 232
|
||||
#define CLK_TOP_DCLK 233
|
||||
#define CLK_UCIE 234
|
||||
#define CLK_UCIE_SBCLK 235
|
||||
#define CLK_RCPU 236
|
||||
#define CLK_DSI4LN2_DSI_ESC 237
|
||||
#define CLK_DSI4LN2_LCD_DSC 238
|
||||
#define CLK_DSI4LN2_LCD_PXCLK 239
|
||||
#define CLK_DSI4LN2_LCD_MCLK 240
|
||||
#define CLK_DSI4LN2_DPU_ACLK 241
|
||||
#define CLK_DPU_ACLK 242
|
||||
#define CLK_UFS_ACLK 243
|
||||
#define CLK_EDP0_PXCLK 244
|
||||
#define CLK_EDP1_PXCLK 245
|
||||
#define CLK_PCIEA 246
|
||||
#define CLK_PCIEB 247
|
||||
#define CLK_PCIEC 248
|
||||
#define CLK_PCIED 249
|
||||
#define CLK_PCIEE 250
|
||||
#define CLK_EMAC0_BUS 251
|
||||
#define CLK_EMAC0_REF 252
|
||||
#define CLK_EMAC0_1588 253
|
||||
#define CLK_EMAC0_RGMII_TX 254
|
||||
#define CLK_EMAC1_BUS 255
|
||||
#define CLK_EMAC1_REF 256
|
||||
#define CLK_EMAC1_1588 257
|
||||
#define CLK_EMAC1_RGMII_TX 258
|
||||
#define CLK_EMAC2_BUS 259
|
||||
#define CLK_EMAC2_REF 260
|
||||
#define CLK_EMAC2_1588 261
|
||||
#define CLK_EMAC2_RGMII_TX 262
|
||||
#define CLK_ESPI_SCLK_SRC 263
|
||||
#define CLK_ESPI_SCLK 264
|
||||
#define CLK_ESPI_MCLK 265
|
||||
#define CLK_CAM_SRC1 266
|
||||
#define CLK_CAM_SRC2 267
|
||||
#define CLK_CAM_SRC3 268
|
||||
#define CLK_CAM_SRC4 269
|
||||
#define CLK_ISIM_VCLK0 270
|
||||
#define CLK_ISIM_VCLK1 271
|
||||
#define CLK_ISIM_VCLK2 272
|
||||
#define CLK_ISIM_VCLK3 273
|
||||
#define CLK_HDMA 274
|
||||
#define CLK_DMA350 275
|
||||
#define CLK_C2_TCM_PIPE 276
|
||||
#define CLK_C3_TCM_PIPE 277
|
||||
#define CLK_RCPU_RT24_CORE0 278
|
||||
#define CLK_RCPU_RT24_CORE1 279
|
||||
#define CLK_SEC_UART1 280
|
||||
#define CLK_SEC_SSP2 281
|
||||
#define CLK_SEC_TWSI3 282
|
||||
#define CLK_SEC_RTC 283
|
||||
#define CLK_SEC_TIMERS0 284
|
||||
#define CLK_SEC_GPIO 285
|
||||
|
||||
#define CLK_VCTCXO_24 286
|
||||
#define CLK_VCTCXO_3 287
|
||||
#define CLK_VCTCXO_1 288
|
||||
#define CLK_PLL1 289
|
||||
#define OSC_32K 290
|
||||
#define CLK_DUMMY 291
|
||||
|
||||
#define CLK_MAX_NO 292
|
||||
|
||||
#endif /* _DT_BINDINGS_CLK_SPACEMIT_K3_H_ */
|
||||
@@ -0,0 +1,229 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef __DT_BINDINGS_K3_PINCTRL_H
|
||||
#define __DT_BINDINGS_K3_PINCTRL_H
|
||||
|
||||
/*
|
||||
* For K3:
|
||||
* +---------+----------+-----------+--------+--------+----------+--------+
|
||||
* | pull | drive | schmitter | slew | edge | strong | mux |
|
||||
* | up/down | strength | trigger | rate | detect | pull | mode |
|
||||
* +---------+----------+-----------+--------+--------+----------+--------+
|
||||
* 3 bits 4 bits 1 bits 1 bit 3 bits 1 bit 3 bits
|
||||
*/
|
||||
|
||||
/* pinnum list */
|
||||
#define GPIO_00 (0)
|
||||
#define GPIO_01 (1)
|
||||
#define GPIO_02 (2)
|
||||
#define GPIO_03 (3)
|
||||
#define GPIO_04 (4)
|
||||
#define GPIO_05 (5)
|
||||
#define GPIO_06 (6)
|
||||
#define GPIO_07 (7)
|
||||
#define GPIO_08 (8)
|
||||
#define GPIO_09 (9)
|
||||
#define GPIO_10 (10)
|
||||
#define GPIO_11 (11)
|
||||
#define GPIO_12 (12)
|
||||
#define GPIO_13 (13)
|
||||
#define GPIO_14 (14)
|
||||
#define GPIO_15 (15)
|
||||
#define GPIO_16 (16)
|
||||
#define GPIO_17 (17)
|
||||
#define GPIO_18 (18)
|
||||
#define GPIO_19 (19)
|
||||
#define GPIO_20 (20)
|
||||
#define GPIO_21 (21)
|
||||
#define GPIO_22 (22)
|
||||
#define GPIO_23 (23)
|
||||
#define GPIO_24 (24)
|
||||
#define GPIO_25 (25)
|
||||
#define GPIO_26 (26)
|
||||
#define GPIO_27 (27)
|
||||
#define GPIO_28 (28)
|
||||
#define GPIO_29 (29)
|
||||
#define GPIO_30 (30)
|
||||
#define GPIO_31 (31)
|
||||
#define GPIO_32 (32)
|
||||
#define GPIO_33 (33)
|
||||
#define GPIO_34 (34)
|
||||
#define GPIO_35 (35)
|
||||
#define GPIO_36 (36)
|
||||
#define GPIO_37 (37)
|
||||
#define GPIO_38 (38)
|
||||
#define GPIO_39 (39)
|
||||
#define GPIO_40 (40)
|
||||
#define GPIO_41 (41)
|
||||
#define GPIO_42 (42)
|
||||
#define GPIO_43 (43)
|
||||
#define GPIO_44 (44)
|
||||
#define GPIO_45 (45)
|
||||
#define GPIO_46 (46)
|
||||
#define GPIO_47 (47)
|
||||
#define GPIO_48 (48)
|
||||
#define GPIO_49 (49)
|
||||
#define GPIO_50 (50)
|
||||
#define GPIO_51 (51)
|
||||
#define GPIO_52 (52)
|
||||
#define GPIO_53 (53)
|
||||
#define GPIO_54 (54)
|
||||
#define GPIO_55 (55)
|
||||
#define GPIO_56 (56)
|
||||
#define GPIO_57 (57)
|
||||
#define GPIO_58 (58)
|
||||
#define GPIO_59 (59)
|
||||
#define GPIO_60 (60)
|
||||
#define GPIO_61 (61)
|
||||
#define GPIO_62 (62)
|
||||
#define GPIO_63 (63)
|
||||
#define GPIO_64 (64)
|
||||
#define GPIO_65 (65)
|
||||
#define GPIO_66 (66)
|
||||
#define GPIO_67 (67)
|
||||
#define GPIO_68 (68)
|
||||
#define GPIO_69 (69)
|
||||
#define GPIO_70 (70)
|
||||
#define GPIO_71 (71)
|
||||
#define GPIO_72 (72)
|
||||
#define GPIO_73 (73)
|
||||
#define GPIO_74 (74)
|
||||
#define GPIO_75 (75)
|
||||
#define GPIO_76 (76)
|
||||
#define GPIO_77 (77)
|
||||
#define GPIO_78 (78)
|
||||
#define GPIO_79 (79)
|
||||
#define GPIO_80 (80)
|
||||
#define GPIO_81 (81)
|
||||
#define GPIO_82 (82)
|
||||
#define GPIO_83 (83)
|
||||
#define GPIO_84 (84)
|
||||
#define GPIO_85 (85)
|
||||
#define GPIO_86 (86)
|
||||
#define GPIO_87 (87)
|
||||
#define GPIO_88 (88)
|
||||
#define GPIO_89 (89)
|
||||
#define GPIO_90 (90)
|
||||
#define GPIO_91 (91)
|
||||
#define GPIO_92 (92)
|
||||
#define GPIO_93 (93)
|
||||
#define GPIO_94 (94)
|
||||
#define GPIO_95 (95)
|
||||
#define GPIO_96 (96)
|
||||
#define GPIO_97 (97)
|
||||
#define GPIO_98 (98)
|
||||
#define GPIO_99 (99)
|
||||
#define GPIO_100 (100)
|
||||
#define GPIO_101 (101)
|
||||
#define GPIO_102 (102)
|
||||
#define GPIO_103 (103)
|
||||
#define GPIO_104 (104)
|
||||
#define GPIO_105 (105)
|
||||
#define GPIO_106 (106)
|
||||
#define GPIO_107 (107)
|
||||
#define GPIO_108 (108)
|
||||
#define GPIO_109 (109)
|
||||
#define GPIO_110 (110)
|
||||
#define GPIO_111 (111)
|
||||
#define GPIO_112 (112)
|
||||
#define GPIO_113 (113)
|
||||
#define GPIO_114 (114)
|
||||
#define GPIO_115 (115)
|
||||
#define GPIO_116 (116)
|
||||
#define GPIO_117 (117)
|
||||
#define GPIO_118 (118)
|
||||
#define GPIO_119 (119)
|
||||
#define GPIO_120 (120)
|
||||
#define GPIO_121 (121)
|
||||
#define GPIO_122 (122)
|
||||
#define GPIO_123 (123)
|
||||
#define GPIO_124 (124)
|
||||
#define GPIO_125 (125)
|
||||
#define GPIO_126 (126)
|
||||
#define GPIO_127 (127)
|
||||
#define PWR_SCL (128)
|
||||
#define PWR_SDA (129)
|
||||
#define VCXO_EN (130)
|
||||
#define PMIC_INT_N (131)
|
||||
#define MMC1_DAT3 (132)
|
||||
#define MMC1_DAT2 (133)
|
||||
#define MMC1_DAT1 (134)
|
||||
#define MMC1_DAT0 (135)
|
||||
#define MMC1_CMD (136)
|
||||
#define MMC1_CLK (137)
|
||||
#define QSPI_DAT0 (138)
|
||||
#define QSPI_DAT1 (139)
|
||||
#define QSPI_DAT2 (140)
|
||||
#define QSPI_DAT3 (141)
|
||||
#define QSPI_CS0 (142)
|
||||
#define QSPI_CS1 (143)
|
||||
#define QSPI_CLK (144)
|
||||
#define PRI_TDI (145)
|
||||
#define PRI_TMS (146)
|
||||
#define PRI_TCK (147)
|
||||
#define PRI_TDO (148)
|
||||
#define PWR_SSP_SCLK (149)
|
||||
#define PWR_SSP_FRM (150)
|
||||
#define PWR_SSP_TXD (151)
|
||||
#define PWR_SSP_RXD (152)
|
||||
|
||||
/* pin mux */
|
||||
#define PAD_MUX GENMASK(2, 0)
|
||||
#define MUX_MODE0 0
|
||||
#define MUX_MODE1 1
|
||||
#define MUX_MODE2 2
|
||||
#define MUX_MODE3 3
|
||||
#define MUX_MODE4 4
|
||||
#define MUX_MODE5 5
|
||||
#define MUX_MODE6 6
|
||||
#define MUX_MODE7 7
|
||||
|
||||
#define PAD_STRONG_PULL BIT(3)
|
||||
|
||||
#define PAD_EDGE GENMASK(6, 4)
|
||||
#define PAD_EDGE_RISE BIT(4)
|
||||
#define PAD_EDGE_FALL BIT(5)
|
||||
#define PAD_EDGE_CLEAR BIT(6)
|
||||
|
||||
#define PAD_SLEW_RATE_EN BIT(7)
|
||||
|
||||
#define PAD_SCHMITT BIT(8)
|
||||
|
||||
#define PAD_PULLDOWN BIT(13)
|
||||
#define PAD_PULLUP BIT(14)
|
||||
#define PAD_PULL_EN BIT(15)
|
||||
|
||||
/*
|
||||
* drive strength
|
||||
* DRIVE[3:0] -> bits[12:9]
|
||||
*/
|
||||
#define PAD_DRIVE GENMASK(12, 9)
|
||||
#define PAD_DS0 (0 << 9) /* bit[12:9] 0000 */
|
||||
#define PAD_DS1 (1 << 9) /* bit[12:9] 0001 */
|
||||
#define PAD_DS2 (2 << 9) /* bit[12:9] 0010 */
|
||||
#define PAD_DS3 (3 << 9) /* bit[12:9] 0011 */
|
||||
#define PAD_DS4 (4 << 9) /* bit[12:9] 0100 */
|
||||
#define PAD_DS5 (5 << 9) /* bit[12:9] 0101 */
|
||||
#define PAD_DS6 (6 << 9) /* bit[12:9] 0110 */
|
||||
#define PAD_DS7 (7 << 9) /* bit[12:9] 0111 */
|
||||
#define PAD_DS8 (8 << 9) /* bit[12:9] 1000 */
|
||||
#define PAD_DS9 (9 << 9) /* bit[12:9] 1001 */
|
||||
#define PAD_DS10 (10 << 9) /* bit[12:9] 1010 */
|
||||
#define PAD_DS11 (11 << 9) /* bit[12:9] 1011 */
|
||||
#define PAD_DS12 (12 << 9) /* bit[12:9] 1100 */
|
||||
#define PAD_DS13 (13 << 9) /* bit[12:9] 1101 */
|
||||
#define PAD_DS14 (14 << 9) /* bit[12:9] 1110 */
|
||||
#define PAD_DS15 (15 << 9) /* bit[12:9] 1111 */
|
||||
|
||||
/* pull up/down */
|
||||
#define PULL_DIS (0 << 13) /* bit[15:13] 000 */
|
||||
#define PULL_UP (6 << 13) /* bit[15:13] 110 */
|
||||
#define PULL_DOWN (5 << 13) /* bit[15:13] 101 */
|
||||
|
||||
// pin reg offset
|
||||
#define PIN_ID(x) ((x) > 130? (x) + 2: (x))
|
||||
|
||||
// pinctrl-single,pins
|
||||
#define K3_PADCONF(pinid, mux, conf) ((PIN_ID(pinid)) << 2) ((conf) | (mux))
|
||||
|
||||
#endif /* __DT_BINDINGS_K3_PINCTRL_H */
|
||||
@@ -234,6 +234,8 @@ enum image_type_t {
|
||||
IH_TYPE_STARFIVE_SPL, /* StarFive SPL image */
|
||||
IH_TYPE_TFA_BL31, /* TFA BL31 image */
|
||||
IH_TYPE_STM32IMAGE_V2, /* STMicroelectronics STM32 Image V2.0 */
|
||||
IH_TYPE_SPACEMIT_BOOTINFO, /* SpacemiT BootInfo Binary Header */
|
||||
IH_TYPE_SPACEMIT_SPL, /* SpacemiT BootROM loadable Image */
|
||||
|
||||
IH_TYPE_COUNT, /* Number of image types */
|
||||
};
|
||||
|
||||
@@ -108,6 +108,8 @@ KWB_IMAGE_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := kwbimage.o
|
||||
|
||||
ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
|
||||
|
||||
SPACEMIT_OBJS = spacemit-boot.o spacemit-spl.o
|
||||
|
||||
# common objs for dumpimage and mkimage
|
||||
dumpimage-mkimage-objs := aisimage.o \
|
||||
atmelimage.o \
|
||||
@@ -140,6 +142,7 @@ dumpimage-mkimage-objs := aisimage.o \
|
||||
stm32image.o \
|
||||
$(ROCKCHIP_OBS) \
|
||||
socfpgaimage.o \
|
||||
$(SPACEMIT_OBJS) \
|
||||
sunxi_egon.o \
|
||||
generated/lib/crc16-ccitt.o \
|
||||
generated/lib/hash-checksum.o \
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
|
||||
#include "imagetool.h"
|
||||
|
||||
struct bootinfo_hdr {
|
||||
struct {
|
||||
/** @magic: MAGIC value, always 0xB00714F0 */
|
||||
uint32_t magic;
|
||||
/** @version: ???*/
|
||||
uint32_t version;
|
||||
/** @flash_type: oneof "NORF", "BLCK" */
|
||||
uint32_t flash_type;
|
||||
/** @mid: ???*/
|
||||
uint8_t mid;
|
||||
uint8_t _reserved_0[1];
|
||||
/** @did: ???*/
|
||||
uint16_t did;
|
||||
/** @page_size: ???*/
|
||||
uint32_t page_size;
|
||||
/** @block_size: ???*/
|
||||
uint32_t block_size;
|
||||
/** @total_size: ???*/
|
||||
uint32_t total_size;
|
||||
/** @multi_plane: ???*/
|
||||
uint8_t multi_plane;
|
||||
uint8_t _reserved_1[3];
|
||||
/** @spl0_offset: Offset to primary SPL image */
|
||||
uint32_t spl0_offset;
|
||||
/** @spl1_offset: Offset to backup SPL image */
|
||||
uint32_t spl1_offset;
|
||||
/** @spl_size_limit: Max size of SPL image */
|
||||
uint32_t spl_size_limit;
|
||||
/** @partitiontable0_offset: ??? */
|
||||
uint32_t partitiontable0_offset;
|
||||
/** @partitiontable1_offset: ??? */
|
||||
uint32_t partitiontable1_offset;
|
||||
uint8_t _reserved_2[12];
|
||||
} data;
|
||||
struct {
|
||||
/** @crc32: crc32 of data */
|
||||
uint32_t crc32;
|
||||
uint8_t _reserved_0[12];
|
||||
} checksum;
|
||||
};
|
||||
|
||||
static int spacemit_bootinfo_check_params(struct image_tool_params *params)
|
||||
{
|
||||
/* Only the RISC-V architecture is supported */
|
||||
if (params->Aflag && params->arch != IH_ARCH_RISCV)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int spacemit_bootinfo_verify_header(unsigned char *buf, int size,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
printf("spacemit_bootinfo_verify_header\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void spacemit_bootinfo_print_header(const void *buf,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
printf("spacemit_bootinfo_print_header\n");
|
||||
}
|
||||
|
||||
static void spacemit_bootinfo_set_header(void *buf, struct stat *sbuf, int infd,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
printf("spacemit_bootinfo_set_header\n");
|
||||
}
|
||||
|
||||
static int spacemit_bootinfo_check_image_type(uint8_t type)
|
||||
{
|
||||
if (type == IH_TYPE_SPACEMIT_BOOTINFO)
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static struct bootinfo_hdr spacemit_bootinfo_hdr;
|
||||
|
||||
U_BOOT_IMAGE_TYPE(
|
||||
spacemit_bootinfo, /* id */
|
||||
"SpacemiT BootInfo Header", /* name */
|
||||
sizeof(struct bootinfo_hdr), /* header_size */
|
||||
&spacemit_bootinfo_hdr, /* header */
|
||||
spacemit_bootinfo_check_params, /* check_params */
|
||||
spacemit_bootinfo_verify_header, /* verify header */
|
||||
spacemit_bootinfo_print_header, /* print header */
|
||||
spacemit_bootinfo_set_header, /* set header */
|
||||
NULL, /* extract_subimage */
|
||||
spacemit_bootinfo_check_image_type, /* check_image_type */
|
||||
NULL, /* fflag_handle */
|
||||
NULL /* vrec_header */
|
||||
);
|
||||
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2026 Hangfan Li <lihangfan@iscas.ac.cn>
|
||||
*/
|
||||
|
||||
|
||||
#include "imagetool.h"
|
||||
#include <u-boot/crc.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#define SPACEMIT_SPL_HDR_MAGIC_LE32 0x44484941
|
||||
|
||||
struct spl_hdr {
|
||||
struct {
|
||||
/** @magic: MAGIC value, always 0x44484941 */
|
||||
uint32_t magic;
|
||||
/** @version: ??? */
|
||||
uint8_t version;
|
||||
/** @secure: ??? */
|
||||
uint8_t secure;
|
||||
uint8_t _reserved_0[2];
|
||||
/** @payload_size: Size of payload only */
|
||||
uint64_t payload_size;
|
||||
/** @loadaddr: Target load address */
|
||||
uint64_t loadaddr;
|
||||
} header;
|
||||
struct {
|
||||
/** @header: crc32 of header data */
|
||||
uint32_t header;
|
||||
/** @payload: crc32 of payload image */
|
||||
uint32_t payload;
|
||||
} checksum;
|
||||
// Useful for mmap-ed output file
|
||||
uint8_t payload[0];
|
||||
};
|
||||
|
||||
static int spacemit_spl_check_params(struct image_tool_params *params)
|
||||
{
|
||||
/* Only the RISC-V architecture is supported */
|
||||
if (params->Aflag && params->arch != IH_ARCH_RISCV)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int spacemit_spl_verify_header(unsigned char *buf, int size,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
const struct spl_hdr *hdr = (void *)buf;
|
||||
if (le32_to_cpu(hdr->header.magic) != SPACEMIT_SPL_HDR_MAGIC_LE32) {
|
||||
printf("Unmatched header MAGIC value: %08x\n", le32_to_cpu(hdr->header.magic));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (le32_to_cpu(hdr->checksum.header) != crc32(0, (void *)&hdr->header, sizeof(hdr->header))) {
|
||||
printf("Unmatched header checksum\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (le32_to_cpu(hdr->header.payload_size) + sizeof(struct spl_hdr) > params->file_size) {
|
||||
printf("Payload size (%lu) exceeds file size (%u) - header size (%lu)\n",
|
||||
le32_to_cpu(hdr->header.payload_size), params->file_size, sizeof(struct spl_hdr));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (le32_to_cpu(hdr->checksum.payload) != crc32(0, (void *)&hdr->payload, le32_to_cpu(hdr->header.payload_size))) {
|
||||
printf("Unmatched payload checksum\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void spacemit_spl_print_header(const void *buf,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
const struct spl_hdr *hdr = buf;
|
||||
printf("SpacemiT BootROM Loadable Image\n");
|
||||
printf("-> Header Version: 0x%02x\n", hdr->header.version);
|
||||
printf("-> Secure Mode: ");
|
||||
if (hdr->header.secure == 0) {
|
||||
printf("Disabled\n");
|
||||
} else {
|
||||
printf("Enabled (0x%02x)\n", hdr->header.secure);
|
||||
}
|
||||
printf("-> Payload Size: %lu\n", le64_to_cpu(hdr->header.payload_size));
|
||||
printf("-> Payload Load Addr: %lu\n", le64_to_cpu(hdr->header.loadaddr));
|
||||
}
|
||||
|
||||
static void spacemit_spl_set_header(void *buf, struct stat *sbuf, int infd,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
// Filling header info
|
||||
struct spl_hdr *hdr = buf;
|
||||
memset((void *)hdr, 0, sizeof(struct spl_hdr));
|
||||
hdr->header.magic = cpu_to_le32(SPACEMIT_SPL_HDR_MAGIC_LE32);
|
||||
hdr->header.version = 0x01;
|
||||
hdr->header.secure = 0;
|
||||
hdr->header.payload_size = cpu_to_le64(params->file_size - sizeof(struct spl_hdr));
|
||||
hdr->header.loadaddr = cpu_to_le64(0x0);
|
||||
hdr->checksum.header = cpu_to_le32(crc32(0, (void *)&hdr->header, sizeof(hdr->header)));
|
||||
hdr->checksum.payload = cpu_to_le32(crc32(0, (void *)hdr->payload, le64_to_cpu(hdr->header.payload_size)));
|
||||
|
||||
// Payload is already copied by mkimage
|
||||
|
||||
// Generate signature
|
||||
// Here we directly call into OpenSSL to avoid U-Boot overheads
|
||||
}
|
||||
|
||||
static int spacemit_spl_check_image_type(uint8_t type)
|
||||
{
|
||||
if (type == IH_TYPE_SPACEMIT_SPL)
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static struct spl_hdr spacemit_spl_hdr;
|
||||
|
||||
U_BOOT_IMAGE_TYPE(
|
||||
spacemit_spl, /* id */
|
||||
"SpacemiT BROM loadable Image", /* name */
|
||||
sizeof(struct spl_hdr), /* header_size */
|
||||
&spacemit_spl_hdr, /* header */
|
||||
spacemit_spl_check_params, /* check_params */
|
||||
spacemit_spl_verify_header, /* verify header */
|
||||
spacemit_spl_print_header, /* print header */
|
||||
spacemit_spl_set_header, /* set header */
|
||||
NULL, /* extract_subimage */
|
||||
spacemit_spl_check_image_type, /* check_image_type */
|
||||
NULL, /* fflag_handle */
|
||||
NULL /* vrec_header */
|
||||
);
|
||||
Reference in New Issue
Block a user