8 Commits

Author SHA1 Message Date
Chao Wei
15c8ab7701 SG2044: add t-head c9xx jtlb errta
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2026-01-06 16:44:47 +08:00
haijiao.liu
78f021d248 lib: Add SG2044 CPPC support
Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2025-04-25 06:30:33 +08:00
Xiaoguang Xing
df02b2f353 github: Do not use upstream review
Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:09:32 +08:00
Xiaoguang Xing
7f6a748be6 makefile: Remove linker garbage collection print
See commmit 0171cfc("Makefile: enable --gc-sections").

Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:09:24 +08:00
haijiao.liu
da2348b161 lib: Fix warning message of timer in boot phase
Optimize the reset driver to prevent the use of the timer function
before the timer driver initialization is completed, which resloves
the following warning messages:

sbi_timer_delay_loop: called without timer device

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2025-03-31 15:09:17 +08:00
Xiaoguang Xing
999ec3b2e7 platform: Fix when no serial node in dtb
SOPHGO BM1690 SoC TP dtb has not serial node.

Signed-off-by: bowen.pang <bowen.pang@sophgo.com>
2025-03-31 15:09:17 +08:00
Xiaoguang Xing
e285bad3c3 lib: Add mtimer and mswi support for BM1690 AP and TP
mswi and mtimer' address of bm1690 ap and tp is not contiguous,
so make them separately.

Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:08:44 +08:00
Inochi Amaoto
7225632021 platform: generic: thead: Add Sophgo SG2044
The Sophgo SG2044 is a new version of C920, although it supports
sscofpmf, it still needs this pmu quirks its cores.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2025-03-31 15:08:18 +08:00
25 changed files with 1001 additions and 33 deletions

View File

@@ -427,7 +427,6 @@ DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assemble
ifneq ($(DEBUG),)
CFLAGS += -O0
ELFFLAGS += -Wl,--print-gc-sections
else
CFLAGS += -O2
endif

32
include/sbi/sbi_clk.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef __SBI_CLK_H__
#define __SBI_CLK_H__
#include <sbi/sbi_types.h>
/* clock device */
struct sbi_clk_device {
char name[32];
int (*clk_set_rate)(const char *name, uint64_t rate);
uint64_t (*clk_get_rate)(const char *name);
int (*clk_enable)(const char *name);
int (*clk_disable)(const char *name);
};
int sbi_clk_set_rate(const char *name, uint64_t rate);
uint64_t sbi_clk_get_rate(const char *name);
int sbi_clk_enable(const char *name);
int sbi_clk_disable(const char *name);
const struct sbi_clk_device *sbi_clk_get_device(const void *fdt);
void sbi_clk_set_device(const struct sbi_clk_device *dev);
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef __FDT_CLK_H__
#define __FDT_CLK_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_CLK
void fdt_clk_init(const void *fdt);
#else
static inline void fdt_clk_init(const void *fdt) { }
#endif
#endif

View File

@@ -0,0 +1,104 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef _SG2044_CLK_H_
#define _SG2044_CLK_H_
#include <sbi/sbi_string.h>
#include <sbi/sbi_bitops.h>
#define KHZ 1000UL
#define MHZ (KHZ * KHZ)
#define SG2044_CLK_USE_INIT_VAL BIT(0) /* use default value */
#define SG2044_CLK_USE_REG_VAL BIT(1) /* use reg divider value */
#define SG2044_CLK_RO BIT(2) /* use reg divider value */
#define CLK_PLL BIT(0)
#define CLK_MUX BIT(1)
#define PLL_CTRL_OFFSET 0xC4
#define PLL_STAT_LOCK_OFFSET 0x10
#define PLL_SELECT_OFFSET 0x2020
#define CLK_MODE 0x4
#define CLK_MODE_MASK 0x3
#define FBDIV_SHIFT 0
#define FBDIV_WIDTH 12
#define REFDIV_SHIFT 12
#define REFDIV_WIDTH 6
#define POSTDIV1_SHIFT 18
#define POSTDIV1_WIDTH 3
#define POSTDIV2_SHIFT 21
#define POSTDIV2_WIDTH 3
#define REFDIV_MIN 1
#define REFDIV_MAX 63
#define FBDIV_MIN 8
#define FBDIV_MAX 1066
#define PLL_FREQ_MIN (1600 * MHZ)
#define PLL_FREQ_MAX (3200 * MHZ)
#define div_mask(width) ((1 << (width)) - 1)
#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \
(BIT(30) | (0x2 << 27) | BIT(24) | (((p2 - 1) & 0x7) << 21) | \
(((p1 - 1) & 0x7) << 18) | ((refdiv & 0x3f) << 12) | (fbdiv & 0xfff))
#define MPLL0_CLK 0
#define MPLL1_CLK 1
#define MPLL2_CLK 2
#define MPLL3_CLK 3
#define MPLL4_CLK 4
#define MPLL5_CLK 5
#define FPLL0_CLK 6
#define FPLL1_CLK 7
#define DPLL0_CLK 8
#define DPLL1_CLK 9
#define DPLL2_CLK 10
#define DPLL3_CLK 11
#define DPLL4_CLK 12
#define DPLL5_CLK 13
#define DPLL6_CLK 14
#define DPLL7_CLK 15
static inline char is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
#define do_div(n, base) ({ \
uint32_t __base = (base); \
uint32_t __rem; \
__rem = (uint32_t)(n) % __base; \
(n) = (uint32_t)(n) / __base; \
__rem; \
})
struct sg2044_pll_ctrl {
unsigned int mode;
unsigned long freq;
unsigned int fbdiv;
unsigned int postdiv1;
unsigned int postdiv2;
unsigned int refdiv;
};
struct sg2044_pll_clock {
unsigned int id;
char *name;
unsigned int status_offset;
unsigned int enable_offset;
uint64_t default_rate;
struct sg2044_pll_ctrl pctrl_table[4];
};
#endif

View File

@@ -99,3 +99,4 @@ libsbi-objs-y += sbi_trap_v_ldst.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_expected_trap.o
libsbi-objs-y += sbi_cppc.o
libsbi-objs-y += sbi_clk.o

64
lib/sbi/sbi_clk.c Normal file
View File

@@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_clk.h>
#include <sbi_utils/clk/fdt_clk.h>
static const struct sbi_clk_device *clk_dev = NULL;
const struct sbi_clk_device *sbi_clk_get_device(const void *fdt)
{
if (!clk_dev)
fdt_clk_init(fdt);
return clk_dev ? clk_dev : NULL;
}
void sbi_clk_set_device(const struct sbi_clk_device *dev)
{
if (!dev || clk_dev)
return;
clk_dev = dev;
}
int sbi_clk_set_rate(const char *name, uint64_t rate)
{
if (!clk_dev || !clk_dev->clk_set_rate)
return SBI_EFAIL;
clk_dev->clk_set_rate(name, rate);
return 0;
}
uint64_t sbi_clk_get_rate(const char *name)
{
if (!clk_dev || !clk_dev->clk_get_rate)
return SBI_EFAIL;
return clk_dev->clk_get_rate(name);
}
int sbi_clk_enable(const char *name)
{
if (!clk_dev || !clk_dev->clk_enable)
return SBI_EFAIL;
return clk_dev->clk_enable(name);
}
int sbi_clk_disable(const char *name)
{
if (!clk_dev || !clk_dev->clk_disable)
return SBI_EFAIL;
return clk_dev->clk_disable(name);
}

View File

@@ -79,12 +79,15 @@ static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
{
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
#endif
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_RCVD);
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
tlb_flush_all();
return;
@@ -96,6 +99,10 @@ static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
: "r"(start + i)
: "memory");
}
#else
tlb_flush_all();
return;
#endif
}
static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
@@ -148,7 +155,9 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
unsigned long i;
#endif
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
@@ -161,12 +170,20 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
return;
}
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0, %1"
:
: "r"(start + i), "r"(asid)
: "memory");
}
#else
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
: "memory");
#endif
}
static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)

View File

@@ -34,4 +34,6 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/mpxy/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/clk/Kconfig"
endmenu

18
lib/utils/clk/Kconfig Normal file
View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "Clock Support"
config FDT_CLK
bool "FDT based CLK drivers"
depends on FDT
default n
if FDT_CLK
config FDT_CLK_SG2044
bool "SG2044 clock drivers"
default n
endif
endmenu

18
lib/utils/clk/fdt_clk.c Normal file
View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <sbi_utils/clk/fdt_clk.h>
/* List of FDT clock drivers generated at compile time */
extern const struct fdt_driver *const fdt_clk_drivers[];
void fdt_clk_init(const void *fdt)
{
fdt_driver_init_all(fdt, fdt_clk_drivers);
}

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/clk/fdt_clk.h
TYPE: const struct fdt_driver
NAME: fdt_clk_drivers

14
lib/utils/clk/objects.mk Normal file
View File

@@ -0,0 +1,14 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2025 Sophgo Inc
#
# Authors:
# Haijiao Liu <haijiao.liu@sophgo.com>
#
libsbiutils-objs-$(CONFIG_FDT_CLK) += clk/fdt_clk.o
libsbiutils-objs-$(CONFIG_FDT_CLK) += clk/fdt_clk_drivers.carray.o
carray-fdt_clk_drivers-$(CONFIG_FDT_CLK_SG2044) += fdt_clk_sg2044
libsbiutils-objs-$(CONFIG_FDT_CLK_SG2044) += clk/sg2044_clk.o

553
lib/utils/clk/sg2044_clk.c Normal file
View File

@@ -0,0 +1,553 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_clk.h>
#include <sbi/riscv_io.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/clk/sg2044_clk.h>
#define POSTDIV_RESULT_INDEX 2
static u64 top_base_addr;
static int sg2044_pll_mux[][2] = {
{MPLL0_CLK, 0}, {MPLL1_CLK, 1}, {MPLL2_CLK, 2}, {MPLL3_CLK, 3},
{MPLL4_CLK, 4}, {MPLL5_CLK, 5}, {FPLL1_CLK, 6}, {DPLL0_CLK, 7},
{DPLL1_CLK, 8}, {DPLL2_CLK, 9}, {DPLL3_CLK, 10}, {DPLL4_CLK, 11},
{DPLL5_CLK, 12}, {DPLL6_CLK, 13}, {DPLL7_CLK, 14}
};
static int postdiv1_2[][3] = {
{2, 4, 8}, {3, 3, 9}, {2, 5, 10}, {2, 6, 12},
{2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18},
{4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25},
{4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36},
{6, 7, 42}, {7, 7, 49}
};
static inline unsigned long abs_diff(unsigned long a, unsigned long b)
{
return (a > b) ? (a - b) : (b - a);
}
static struct sg2044_pll_clock sg2044_root_pll_clks[] = {
{
.id = MPLL0_CLK,
.name = "mpll0-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL1_CLK,
.name = "mpll1-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL2_CLK,
.name = "mpll2-clock",
.default_rate = 1000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL3_CLK,
.name = "mpll3-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL4_CLK,
.name = "mpll4-clock",
.default_rate = 1050 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL5_CLK,
.name = "mpll5-clock",
.default_rate = 900 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = FPLL0_CLK,
.name = "fpll0-clock",
}, {
.id = FPLL1_CLK,
.name = "fpll1-clock",
}, {
.id = DPLL0_CLK,
.name = "dpll0-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL1_CLK,
.name = "dpll1-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL2_CLK,
.name = "dpll2-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL3_CLK,
.name = "dpll3-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL4_CLK,
.name = "dpll4-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL5_CLK,
.name = "dpll5-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL6_CLK,
.name = "dpll6-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL7_CLK,
.name = "dpll7-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}
};
static inline void top_misc_read(uintptr_t offset, uint32_t *value)
{
*value = readl((const volatile void *)top_base_addr + offset);
}
static inline void top_misc_write(uintptr_t offset, uint32_t value)
{
writel(value, (volatile void *)(top_base_addr + offset));
}
static void sg2044_pll_write_h(int id, int value)
{
top_misc_write(PLL_CTRL_OFFSET + (id << 3), value);
}
static void sg2044_pll_read_h(int id, uint32_t *pvalue)
{
top_misc_read(PLL_CTRL_OFFSET + (id << 3), pvalue);
}
static void sg2044_pll_write_l(int id, int value)
{
top_misc_write(PLL_CTRL_OFFSET + (id << 3) - 4, value);
}
static void sg2044_pll_read_l(int id, uint32_t *pvalue)
{
top_misc_read(PLL_CTRL_OFFSET + (id << 3) - 4, pvalue);
}
static int __pll_get_postdiv_1_2(uint64_t rate, uint64_t prate,
uint32_t fbdiv, uint32_t refdiv,
uint32_t *postdiv1, uint32_t *postdiv2)
{
int index = 0;
int ret = 0;
uint64_t tmp0;
/*
* calculate (parent_rate/refdiv)
* and result save to tmp0
*/
tmp0 = prate;
do_div(tmp0, refdiv);
/*
* calcuate ((parent_rate/REFDIV) x FBDIV)
* and result save to prate
*/
tmp0 *= fbdiv;
/*
* calcuate (((parent_rate/REFDIV) x FBDIV)/input_rate)
* and result save to tmp0
* here tmp0 is (POSTDIV1*POSTDIV2)
*/
do_div(tmp0, rate);
/* calculate div1 and div2 value */
if (tmp0 <= 7) {
/* (div1 * div2) <= 7, no need to use array search */
*postdiv1 = tmp0;
*postdiv2 = 1;
} else {
/* (div1 * div2) > 7, use array search */
for (index = 0; index < array_size(postdiv1_2); index++) {
if (tmp0 > postdiv1_2[index][POSTDIV_RESULT_INDEX]) {
continue;
} else {
/* found it */
break;
}
}
if (index < array_size(postdiv1_2)) {
*postdiv1 = postdiv1_2[index][1];
*postdiv2 = postdiv1_2[index][0];
} else {
sbi_printf("%s out of postdiv array range!\n", __func__);
ret = -1;
}
}
return ret;
}
/*
* The function uses the following mapping for frequency range selection:
* - 2'd2 (bit[17:16] = 0b10): for frequencies from 1.6 GHz to 2.4 GHz.
* - 2'd3 (bit[17:16] = 0b11): for frequencies from 2.4 GHz to 3.2 GHz.
*/
static void __set_pll_vcosel(struct sg2044_pll_clock *sg2044_pll, uint64_t foutvco)
{
int vcosel;
uint32_t value;
if (foutvco < (2400 * MHZ))
vcosel = 0x2;
else
vcosel = 0x3;
sg2044_pll_read_l(sg2044_pll->id, &value);
value &= ~(0x3 << 16);
value |= (vcosel << 16);
sg2044_pll_write_l(sg2044_pll->id, value);
}
static inline int sg2044_pll_id2shift(uint32_t id)
{
for (int i = 0; i < 15; i++) {
if (sg2044_pll_mux[i][0] == id)
return sg2044_pll_mux[i][1];
}
return -1;
}
static inline int sg2044_pll_switch_mux(struct sg2044_pll_clock *pll, char en)
{
uint32_t value;
uint32_t id = pll->id;
int shift;
shift = sg2044_pll_id2shift(id);
if (shift == -1) {
sbi_printf("%s Unable to find a suitable shift!\n", __func__);
return -1;
}
top_misc_read(PLL_SELECT_OFFSET, &value);
if (en)
top_misc_write(PLL_SELECT_OFFSET, value & (~(1 << shift)));
else
top_misc_write(PLL_SELECT_OFFSET, value | (1 << shift));
return 0;
}
static inline int sg2044_pll_enable(struct sg2044_pll_clock *pll, char en)
{
uint32_t value;
uint64_t wait = 0;
uint32_t id = pll->id;
if (en) {
/* wait pll lock */
top_misc_read(pll->status_offset, &value);
while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) {
top_misc_read(pll->status_offset, &value);
wait++;
sbi_timer_udelay(10);
if (wait > 10000)
sbi_printf("%s not locked\n", pll->name);
}
/* wait pll updating */
wait = 0;
top_misc_read(pll->status_offset, &value);
while (((value >> id) & 0x1)) {
top_misc_read(pll->status_offset, &value);
wait++;
sbi_timer_udelay(10);
if (wait > 10000)
sbi_printf("%s still updating\n", pll->name);
}
/* enable pll */
top_misc_read(pll->enable_offset, &value);
top_misc_write(pll->enable_offset, value | (1 << id));
} else {
/* disable pll */
top_misc_read(pll->enable_offset, &value);
top_misc_write(pll->enable_offset, value & (~(1 << id)));
}
return 0;
}
/**
* The PLL output frequency calculation is based on the formula:
* FOUTPOSTDIV = FREF * FBDIV / REFDIV / (POSTDIV1 + 1) * (POSTDIV2 + 1)
* where:
* - FREF: Reference Clock Input (12MHz to 1600MHz).
* - FOUTPOSTDIV: Output Clock (25MHz to 3200MHz).
* - REFDIV: Reference divide value (1 to 63).
* - FBDIV: Feedback divide value (8 to 1066).
* - POSTDIV1: Post Divide 1 setting (0 to 7).
* - POSTDIV2: Post Divide 2 setting (0 to 7).
*
* Additionally, other check points inside PLL are listed here:
* 1.FOUTVCO = FREF * FBDIV / REFDIV 1600MHz to 3200MHz
* - VCOSEL = 2'd2, FOUTVCO 1.6G~2.4G;
* - VCOSEL = 2'd3, FOUTVCO 2.4G~3.2G
* 2.POSTDIV1 >= POSTDIV2
*/
static int __get_pll_ctl_setting(struct sg2044_pll_ctrl *best,
uint64_t req_rate, uint64_t parent_rate)
{
int ret;
uint32_t fbdiv, refdiv, fref, postdiv1, postdiv2;
uint64_t tmp = 0, foutvco;
fref = parent_rate;
for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) {
for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) {
foutvco = fref * fbdiv / refdiv;
/* check fpostdiv pfd */
if (foutvco < PLL_FREQ_MIN || foutvco > PLL_FREQ_MAX
|| (fref / refdiv) < 10)
continue;
ret = __pll_get_postdiv_1_2(req_rate, fref, fbdiv,
refdiv, &postdiv1, &postdiv2);
if (ret)
continue;
tmp = foutvco / (postdiv1 * postdiv2);
if (abs_diff(tmp, req_rate) < abs_diff(best->freq, req_rate)) {
best->freq = tmp;
best->refdiv = refdiv;
best->fbdiv = fbdiv;
best->postdiv1 = postdiv1;
best->postdiv2 = postdiv2;
if (tmp == req_rate)
return 0;
}
continue;
}
}
return -1;
}
/**
* The function performs the following steps:
* 1. Switch the PLL source to fpll before modifying settings.
* 2. Disable the MPLL to allow safe modifications to its configuration.
* 3. Calculate the new PLL settings based on the desired rate and the parent rate.
* 5. Set the frequency range based on the foutvco .
* 6. Write the new settings to the PLL control register.
* 7. Re-enable the PLL.
* 8. Switch back the PLL source to mpll after modifications.
*/
static int sg2044_clk_pll_set_rate(struct sg2044_pll_clock *sg2044_pll,
uint64_t rate, uint64_t parent_rate)
{
int ret = 0;
uint32_t value;
uint64_t foutvco;
struct sg2044_pll_ctrl pctrl_table;
sbi_memset(&pctrl_table, 0, sizeof(struct sg2044_pll_ctrl));
/* switch to fpll before modify mpll */
ret = sg2044_pll_switch_mux(sg2044_pll, 1);
if (ret == -1) {
sbi_printf("switch to fpll fail!\n");
goto out;
}
if (sg2044_pll_enable(sg2044_pll, 0)) {
sbi_printf("Can't disable pll(%s), status error\n", sg2044_pll->name);
ret = -1;
goto out;
}
sg2044_pll_read_h(sg2044_pll->id, &value);
__get_pll_ctl_setting(&pctrl_table, rate, parent_rate);
if (!pctrl_table.freq) {
sbi_printf("%s: Can't find a proper pll setting\n", sg2044_pll->name);
ret = -1;
goto out;
}
value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1,
pctrl_table.postdiv2, pctrl_table.refdiv);
foutvco = parent_rate * pctrl_table.fbdiv / pctrl_table.refdiv;
__set_pll_vcosel(sg2044_pll, foutvco);
/* write the value to top register */
sg2044_pll_write_h(sg2044_pll->id, value);
sg2044_pll_enable(sg2044_pll, 1);
/* switch back to mpll after modify mpll */
ret = sg2044_pll_switch_mux(sg2044_pll, 0);
if (ret == -1) {
sbi_printf("switch back to mpll fail!\n");
goto out;
}
out:
return ret;
}
static uint64_t sg2044_clk_pll_get_rate(struct sg2044_pll_clock *sg2044_pll,
uint64_t parent_rate)
{
uint32_t value;
uint64_t fref;
int refdiv, fbdiv;
int postdiv1, postdiv2;
sg2044_pll_read_h(sg2044_pll->id, &value);
fref = parent_rate;
fbdiv = (value >> FBDIV_SHIFT) & div_mask(FBDIV_WIDTH);
refdiv = (value >> REFDIV_SHIFT) & div_mask(REFDIV_WIDTH);
postdiv1 = (value >> POSTDIV1_SHIFT) & div_mask(POSTDIV1_WIDTH);
postdiv2 = (value >> POSTDIV2_SHIFT) & div_mask(POSTDIV2_WIDTH);
return fref * fbdiv / refdiv / (postdiv1 + 1) * (postdiv2 + 1);
}
static struct sg2044_pll_clock *sg2044_get_clk_by_name(const char *name)
{
int index;
for (index = 0; index < array_size(sg2044_root_pll_clks); index++) {
if (!sbi_strcmp(name, sg2044_root_pll_clks[index].name))
return &sg2044_root_pll_clks[index];
}
return 0;
}
static int sg2044_clk_set_rate(const char *name, uint64_t rate)
{
int ret;
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
ret = sg2044_clk_pll_set_rate(clk, rate, 25 * MHZ);
if (ret != 0)
sbi_printf("%s set rate fail, ret = %d\n", name, ret);
return ret;
}
static uint64_t sg2044_clk_get_rate(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
return sg2044_clk_pll_get_rate(clk, 25 * MHZ);
}
static int sg2044_clk_enable(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
sg2044_pll_enable(clk, 1);
return 0;
}
static int sg2044_clk_disable(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
sg2044_pll_enable(clk, 0);
return 0;
}
static struct sbi_clk_device sbi_sg2044_clk = {
.name = "sg2044-clk",
.clk_set_rate = sg2044_clk_set_rate,
.clk_get_rate = sg2044_clk_get_rate,
.clk_enable = sg2044_clk_enable,
.clk_disable = sg2044_clk_disable,
};
static int sg2044_clk_init(const void *fdt, int nodeoff,
const struct fdt_match *match)
{
int top_offset, len;
const fdt32_t *phandle;
const fdt32_t *reg;
if (top_base_addr)
return 0;
phandle = fdt_getprop(fdt, nodeoff, "subctrl-syscon", &len);
if (!phandle)
return SBI_EINVAL;
top_offset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*phandle));
if (top_offset < 0)
return top_offset;
reg = fdt_getprop(fdt, top_offset, "reg", &len);
if (!reg || len <= 0)
return SBI_EINVAL;
top_base_addr = fdt32_to_cpu(reg[0]);
top_base_addr = (top_base_addr << 32) | fdt32_to_cpu(reg[1]);
sbi_clk_set_device(&sbi_sg2044_clk);
return 0;
}
static const struct fdt_match sg2044_clk_match[] = {
{ .compatible = "sg2044, pll-clock" },
{},
};
struct fdt_driver fdt_clk_sg2044 = {
.match_table = sg2044_clk_match,
.init = sg2044_clk_init,
};

View File

@@ -14,6 +14,11 @@ config FDT_CPPC_RPMI
depends on FDT_MAILBOX && RPMI_MAILBOX
default n
config FDT_CPPC_SG2044
bool "FDT SG2044 CPPC driver"
select FDT_CLK_SG2044
default n
endif
endmenu

View File

@@ -0,0 +1,115 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_clk.h>
#include <sbi/sbi_cppc.h>
#include <sbi_utils/cppc/fdt_cppc.h>
#define CPPC_REGISTER_WIDTH 64
#define CPPC_REGISTER_NOT_IMPLEMENTED 0
static char clock_names[64];
static uint64_t clk_granularity;
static int sg2044_cppc_read(unsigned long reg, u64 *val)
{
int rc = SBI_SUCCESS;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
*val = sbi_clk_get_rate(clock_names) / clk_granularity;
break;
default:
rc = SBI_ERR_NOT_SUPPORTED;
}
return rc;
}
static int sg2044_cppc_write(unsigned long reg, u64 val)
{
int rc = SBI_SUCCESS;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
rc = sbi_clk_set_rate(clock_names, val * clk_granularity);
break;
default:
rc = SBI_ERR_NOT_SUPPORTED;
}
return rc;
}
static int sg2044_cppc_probe(unsigned long reg)
{
int rc;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
rc = CPPC_REGISTER_WIDTH;
break;
default:
rc = CPPC_REGISTER_NOT_IMPLEMENTED;
}
return rc;
}
static struct sbi_cppc_device sbi_sg2044_cppc = {
.name = "sg2044-cppc",
.cppc_read = sg2044_cppc_read,
.cppc_write = sg2044_cppc_write,
.cppc_probe = sg2044_cppc_probe,
};
static int sg2044_cppc_cold_init(const void *fdt, int nodeoff,
const struct fdt_match *match)
{
const struct sbi_clk_device *clk;
const fdt32_t *val;
const char *name;
int len;
clk = sbi_clk_get_device(fdt);
if (!clk)
return SBI_ENODEV;
val = fdt_getprop(fdt, nodeoff, "step", &len);
if (!val)
return SBI_EINVAL;
clk_granularity = fdt32_to_cpu(val[0]);
clk_granularity = (clk_granularity << 32) | fdt32_to_cpu(val[1]);
name = fdt_getprop(fdt, nodeoff, "clock-names", &len);
if (!name)
return SBI_EINVAL;
sbi_strncpy(clock_names, name, MIN(sizeof(clock_names), len));
sbi_cppc_set_device(&sbi_sg2044_cppc);
return 0;
}
static const struct fdt_match sg2044_cppc_match[] = {
{ .compatible = "sophgo,sg2044-cppc" },
{},
};
struct fdt_driver fdt_cppc_sg2044 = {
.match_table = sg2044_cppc_match,
.init = sg2044_cppc_cold_init,
};

View File

@@ -12,3 +12,6 @@ libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc_drivers.carray.o
carray-fdt_cppc_drivers-$(CONFIG_FDT_CPPC_RPMI) += fdt_cppc_rpmi
libsbiutils-objs-$(CONFIG_FDT_CPPC_RPMI) += cppc/fdt_cppc_rpmi.o
carray-fdt_cppc_drivers-$(CONFIG_FDT_CPPC_SG2044) += fdt_cppc_sg2044
libsbiutils-objs-$(CONFIG_FDT_CPPC_SG2044) += cppc/fdt_cppc_sg2044.o

View File

@@ -56,6 +56,7 @@ static const struct fdt_match ipi_mswi_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },
{ .compatible = "sifive,clint0", .data = &clint_offset },
{ .compatible = "thead,c900-clint", .data = &clint_offset },
{ .compatible = "thead,c900-clint-mswi", .data = &clint_offset },
{ .compatible = "thead,c900-aclint-mswi" },
{ .compatible = "riscv,aclint-mswi" },
{ },

View File

@@ -14,9 +14,6 @@
#include <sbi_utils/reset/fdt_reset.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#define MANGO_BOARD_TYPE_MASK 0x80
#define REG_BOARD_TYPE 0x00
#define REG_CMD 0x03
#define CMD_POWEROFF 0x02
@@ -60,22 +57,6 @@ static struct sbi_system_reset_device sg2042_mcu_reset_device = {
.system_reset = sg2042_mcu_reset
};
static int sg2042_mcu_reset_check_board(struct i2c_adapter *adap, uint32_t reg)
{
static uint8_t val;
int ret;
/* check board type */
ret = i2c_adapter_reg_read(adap, reg, REG_BOARD_TYPE, &val);
if (ret)
return ret;
if (!(val & MANGO_BOARD_TYPE_MASK))
return SBI_ENODEV;
return 0;
}
static int sg2042_mcu_reset_init(const void *fdt, int nodeoff,
const struct fdt_match *match)
{
@@ -96,8 +77,6 @@ static int sg2042_mcu_reset_init(const void *fdt, int nodeoff,
if (ret)
return ret;
ret = sg2042_mcu_reset_check_board(mcu_adapter, mcu_reg);
sbi_system_reset_add_device(&sg2042_mcu_reset_device);
return 0;

View File

@@ -156,6 +156,8 @@ static const struct fdt_match timer_mtimer_match[] = {
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
{ .compatible = "thead,c900-clint", .data = &thead_clint_quirks },
{ .compatible = "thead,c900-clint-mtimer",
.data = &thead_clint_quirks },
{ .compatible = "thead,c900-aclint-mtimer",
.data = &thead_aclint_quirks },
{ .compatible = "riscv,aclint-mtimer" },

View File

@@ -58,6 +58,13 @@ config PLATFORM_SOPHGO_SG2042
select THEAD_C9XX_PMU
default n
config PLATFORM_SOPHGO_SG2044
bool "Sophgo sg2044 support"
select THEAD_C9XX_ERRATA
select THEAD_C9XX_ERRATA_JTLB
select THEAD_C9XX_PMU
default n
config PLATFORM_STARFIVE_JH7110
bool "StarFive JH7110 support"
default n

View File

@@ -4,10 +4,14 @@ CONFIG_PLATFORM_RENESAS_RZFIVE=y
CONFIG_PLATFORM_SIFIVE_FU540=y
CONFIG_PLATFORM_SIFIVE_FU740=y
CONFIG_PLATFORM_SOPHGO_SG2042=y
CONFIG_PLATFORM_SOPHGO_SG2044=y
CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_THEAD=y
CONFIG_FDT_CPPC=y
CONFIG_FDT_CPPC_RPMI=y
CONFIG_FDT_CPPC_SG2044=y
CONFIG_FDT_CLK=y
CONFIG_FDT_CLK_SG2044=y
CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_DESIGNWARE=y
CONFIG_FDT_GPIO_SIFIVE=y

View File

@@ -255,7 +255,7 @@ static int generic_early_init(bool cold_boot)
else
rc = fdt_serial_init(fdt);
if (rc)
return rc;
return (rc == SBI_ENODEV) ? 0 : rc;
fdt_cppc_init(fdt);
fdt_hsm_init(fdt);

View File

@@ -7,3 +7,7 @@ config THEAD_C9XX_PMU
config THEAD_C9XX_ERRATA
bool "T-HEAD c9xx errata support"
default n
config THEAD_C9XX_ERRATA_JTLB
bool "T-HEAD c9xx errata(JTLB) support"
default n

View File

@@ -45,21 +45,18 @@ static struct thead_generic_quirks thead_th1520_quirks = {
.errata = THEAD_QUIRK_ERRATA_TLB_FLUSH | THEAD_QUIRK_ERRATA_THEAD_PMU,
};
static struct thead_generic_quirks canaan_k230_quirks = {
.errata = THEAD_QUIRK_ERRATA_THEAD_PMU,
};
static struct thead_generic_quirks sophgo_cv1800_quirks = {
static struct thead_generic_quirks thead_pmu_quirks = {
.errata = THEAD_QUIRK_ERRATA_THEAD_PMU,
};
static const struct fdt_match thead_generic_match[] = {
{ .compatible = "sophgo,cv1800b", .data = &sophgo_cv1800_quirks },
{ .compatible = "sophgo,cv1812h", .data = &sophgo_cv1800_quirks },
{ .compatible = "sophgo,sg2000", .data = &sophgo_cv1800_quirks },
{ .compatible = "sophgo,sg2002", .data = &sophgo_cv1800_quirks },
{ .compatible = "canaan,kendryte-k230", .data = &thead_pmu_quirks },
{ .compatible = "sophgo,cv1800b", .data = &thead_pmu_quirks },
{ .compatible = "sophgo,cv1812h", .data = &thead_pmu_quirks },
{ .compatible = "sophgo,sg2000", .data = &thead_pmu_quirks },
{ .compatible = "sophgo,sg2002", .data = &thead_pmu_quirks },
{ .compatible = "sophgo,sg2044", .data = &thead_pmu_quirks },
{ .compatible = "thead,th1520", .data = &thead_th1520_quirks },
{ .compatible = "canaan,kendryte-k230", .data = &canaan_k230_quirks },
{ },
};