CI: https://source.denx.de/u-boot/custodians/u-boot-riscv/-/pipelines/24215

- RISC-V: Add "riscv,isa-extensions" and multi-letter extension parsing
  support
- RISC-V: Add default cache line size
- Board: Canaan: Add K230-CanMV support
- Board: VisionFive2: Split out target specific configuration
This commit is contained in:
Tom Rini
2025-01-17 08:27:40 -06:00
29 changed files with 1275 additions and 168 deletions

View File

@@ -52,7 +52,8 @@ config SYS_CACHELINE_SIZE
default 64 if SYS_CACHE_SHIFT_6
default 32 if SYS_CACHE_SHIFT_5
default 16 if SYS_CACHE_SHIFT_4
# Fall-back for MIPS
# Fall-back for MIPS and RISC-V
default 64 if RISCV
default 32 if MIPS
config LINKER_LIST_ALIGN

View File

@@ -14,6 +14,9 @@ config TARGET_ANDES_AE350
config TARGET_BANANAPI_F3
bool "Support BananaPi F3 Board"
config TARGET_K230_CANMV
bool "Support K230 CanMV Board"
config TARGET_LICHEERV_NANO
bool "Support LicheeRV Nano Board"
@@ -91,6 +94,7 @@ config SPL_ZERO_MEM_BEFORE_USE
# board-specific options below
source "board/andestech/ae350/Kconfig"
source "board/aspeed/ibex_ast2700/Kconfig"
source "board/canaan/k230_canmv/Kconfig"
source "board/emulation/qemu-riscv/Kconfig"
source "board/microchip/mpfs_icicle/Kconfig"
source "board/openpiton/riscv64/Kconfig"
@@ -113,6 +117,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/k230/Kconfig"
# architecture-specific options below

View File

@@ -14,8 +14,12 @@
#include <log.h>
#include <asm/encoding.h>
#include <asm/system.h>
#include <asm/hwcap.h>
#include <asm/cpufeature.h>
#include <dm/uclass-internal.h>
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/ctype.h>
/*
* The variables here must be stored in the data section since they are used
@@ -33,60 +37,565 @@ u32 available_harts_lock = 1;
#endif
#endif
/* Host ISA bitmap */
static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __section(".data");
static unsigned int riscv_cbom_block_size __section(".data");
static unsigned int riscv_cboz_block_size __section(".data");
/**
* __riscv_isa_extension_available() - Check whether given extension
* is available or not
*
* @bit: bit position of the desired extension
* Return: true or false
*
*/
static bool __riscv_isa_extension_available(unsigned int bit)
{
if (bit >= RISCV_ISA_EXT_MAX)
return false;
return test_bit(bit, riscv_isa) ? true : false;
}
inline unsigned int riscv_get_cbom_block_size(void)
{
return riscv_cbom_block_size;
}
inline unsigned int riscv_get_cboz_block_size(void)
{
return riscv_cboz_block_size;
}
static int riscv_ext_zicbom_validate(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
{
struct udevice *dev;
if (!CONFIG_IS_ENABLED(RISCV_ISA_ZICBOM) || riscv_cbom_block_size)
return 0;
uclass_first_device(UCLASS_CPU, &dev);
if (!dev) {
log_info("Failed to get cpu device!\n");
return -ENXIO;
}
if (!dev_read_u32(dev, "riscv,cbom-block-size",
&riscv_cbom_block_size)) {
if (!riscv_cbom_block_size) {
log_err("Zicbom detected in ISA string, disabling as no cbom-block-size found\n");
return -EINVAL;
}
if (!is_power_of_2(riscv_cbom_block_size)) {
log_err("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n");
return -EINVAL;
}
return 0;
} else {
return -EINVAL;
}
}
static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
{
struct udevice *dev;
if (!CONFIG_IS_ENABLED(RISCV_ISA_ZICBOM) || riscv_cboz_block_size)
return 0;
uclass_first_device(UCLASS_CPU, &dev);
if (!dev) {
log_debug("Failed to get cpu device!\n");
return -ENXIO;
}
if (!dev_read_u32(dev, "riscv,cboz-block-size",
&riscv_cboz_block_size)) {
if (!riscv_cboz_block_size) {
log_err("Zicboz detected in ISA string, disabling as no cboz-block-size found\n");
return -EINVAL;
}
if (!is_power_of_2(riscv_cboz_block_size)) {
log_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n");
return -EINVAL;
}
return 0;
} else {
return -EINVAL;
}
}
static int riscv_ext_zca_depends(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
{
if (__riscv_isa_extension_available(RISCV_ISA_EXT_ZCA))
return 0;
return -EINVAL;
}
static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
{
if (__riscv_isa_extension_available(RISCV_ISA_EXT_ZCA) &&
__riscv_isa_extension_available(RISCV_ISA_EXT_d))
return 0;
return -EINVAL;
}
static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
{
if (IS_ENABLED(CONFIG_64BIT))
return -EINVAL;
if (__riscv_isa_extension_available(RISCV_ISA_EXT_ZCA) &&
__riscv_isa_extension_available(RISCV_ISA_EXT_f))
return 0;
return -EINVAL;
}
static const unsigned int riscv_zk_bundled_exts[] = {
RISCV_ISA_EXT_ZBKB,
RISCV_ISA_EXT_ZBKC,
RISCV_ISA_EXT_ZBKX,
RISCV_ISA_EXT_ZKND,
RISCV_ISA_EXT_ZKNE,
RISCV_ISA_EXT_ZKR,
RISCV_ISA_EXT_ZKT,
};
static const unsigned int riscv_zkn_bundled_exts[] = {
RISCV_ISA_EXT_ZBKB,
RISCV_ISA_EXT_ZBKC,
RISCV_ISA_EXT_ZBKX,
RISCV_ISA_EXT_ZKND,
RISCV_ISA_EXT_ZKNE,
RISCV_ISA_EXT_ZKNH,
};
static const unsigned int riscv_zks_bundled_exts[] = {
RISCV_ISA_EXT_ZBKB,
RISCV_ISA_EXT_ZBKC,
RISCV_ISA_EXT_ZKSED,
RISCV_ISA_EXT_ZKSH
};
#define RISCV_ISA_EXT_ZVKN \
RISCV_ISA_EXT_ZVKNED, \
RISCV_ISA_EXT_ZVKNHB, \
RISCV_ISA_EXT_ZVKB, \
RISCV_ISA_EXT_ZVKT
static const unsigned int riscv_zvkn_bundled_exts[] = {
RISCV_ISA_EXT_ZVKN
};
static const unsigned int riscv_zvknc_bundled_exts[] = {
RISCV_ISA_EXT_ZVKN,
RISCV_ISA_EXT_ZVBC
};
static const unsigned int riscv_zvkng_bundled_exts[] = {
RISCV_ISA_EXT_ZVKN,
RISCV_ISA_EXT_ZVKG
};
#define RISCV_ISA_EXT_ZVKS \
RISCV_ISA_EXT_ZVKSED, \
RISCV_ISA_EXT_ZVKSH, \
RISCV_ISA_EXT_ZVKB, \
RISCV_ISA_EXT_ZVKT
static const unsigned int riscv_zvks_bundled_exts[] = {
RISCV_ISA_EXT_ZVKS
};
static const unsigned int riscv_zvksc_bundled_exts[] = {
RISCV_ISA_EXT_ZVKS,
RISCV_ISA_EXT_ZVBC
};
static const unsigned int riscv_zvksg_bundled_exts[] = {
RISCV_ISA_EXT_ZVKS,
RISCV_ISA_EXT_ZVKG
};
static const unsigned int riscv_zvbb_exts[] = {
RISCV_ISA_EXT_ZVKB
};
#define RISCV_ISA_EXT_ZVE64F_IMPLY_LIST \
RISCV_ISA_EXT_ZVE64X, \
RISCV_ISA_EXT_ZVE32F, \
RISCV_ISA_EXT_ZVE32X
#define RISCV_ISA_EXT_ZVE64D_IMPLY_LIST \
RISCV_ISA_EXT_ZVE64F, \
RISCV_ISA_EXT_ZVE64F_IMPLY_LIST
#define RISCV_ISA_EXT_V_IMPLY_LIST \
RISCV_ISA_EXT_ZVE64D, \
RISCV_ISA_EXT_ZVE64D_IMPLY_LIST
static const unsigned int riscv_zve32f_exts[] = {
RISCV_ISA_EXT_ZVE32X
};
static const unsigned int riscv_zve64f_exts[] = {
RISCV_ISA_EXT_ZVE64F_IMPLY_LIST
};
static const unsigned int riscv_zve64d_exts[] = {
RISCV_ISA_EXT_ZVE64D_IMPLY_LIST
};
static const unsigned int riscv_v_exts[] = {
RISCV_ISA_EXT_V_IMPLY_LIST
};
static const unsigned int riscv_zve64x_exts[] = {
RISCV_ISA_EXT_ZVE32X,
RISCV_ISA_EXT_ZVE64X
};
/*
* While the [ms]envcfg CSRs were not defined until version 1.12 of the RISC-V
* privileged ISA, the existence of the CSRs is implied by any extension which
* specifies [ms]envcfg bit(s). Hence, we define a custom ISA extension for the
* existence of the CSR, and treat it as a subset of those other extensions.
*/
static const unsigned int riscv_xlinuxenvcfg_exts[] = {
RISCV_ISA_EXT_XLINUXENVCFG
};
/*
* Zc* spec states that:
* - C always implies Zca
* - C+F implies Zcf (RV32 only)
* - C+D implies Zcd
*
* These extensions will be enabled and then validated depending on the
* availability of F/D RV32.
*/
static const unsigned int riscv_c_exts[] = {
RISCV_ISA_EXT_ZCA,
RISCV_ISA_EXT_ZCF,
RISCV_ISA_EXT_ZCD,
};
/*
* The canonical order of ISA extension names in the ISA string is defined in
* chapter 27 of the unprivileged specification.
*
* Ordinarily, for in-kernel data structures, this order is unimportant but
* isa_ext_arr defines the order of the ISA string in /proc/cpuinfo.
*
* The specification uses vague wording, such as should, when it comes to
* ordering, so for our purposes the following rules apply:
*
* 1. All multi-letter extensions must be separated from other extensions by an
* underscore.
*
* 2. Additional standard extensions (starting with 'Z') must be sorted after
* single-letter extensions and before any higher-privileged extensions.
*
* 3. The first letter following the 'Z' conventionally indicates the most
* closely related alphabetical extension category, IMAFDQLCBKJTPVH.
* If multiple 'Z' extensions are named, they must be ordered first by
* category, then alphabetically within a category.
*
* 3. Standard supervisor-level extensions (starting with 'S') must be listed
* after standard unprivileged extensions. If multiple supervisor-level
* extensions are listed, they must be ordered alphabetically.
*
* 4. Standard machine-level extensions (starting with 'Zxm') must be listed
* after any lower-privileged, standard extensions. If multiple
* machine-level extensions are listed, they must be ordered
* alphabetically.
*
* 5. Non-standard extensions (starting with 'X') must be listed after all
* standard extensions. If multiple non-standard extensions are listed, they
* must be ordered alphabetically.
*
* An example string following the order is:
* rv64imadc_zifoo_zigoo_zafoo_sbar_scar_zxmbaz_xqux_xrux
*
* New entries to this struct should follow the ordering rules described above.
*/
const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i),
__RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m),
__RISCV_ISA_EXT_DATA(a, RISCV_ISA_EXT_a),
__RISCV_ISA_EXT_DATA(f, RISCV_ISA_EXT_f),
__RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d),
__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
__RISCV_ISA_EXT_SUPERSET(v, RISCV_ISA_EXT_v, riscv_v_exts),
__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts,
riscv_ext_zicbom_validate),
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts,
riscv_ext_zicboz_validate),
__RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
__RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
__RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
__RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
__RISCV_ISA_EXT_DATA(zihintntl, RISCV_ISA_EXT_ZIHINTNTL),
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
__RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP),
__RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
__RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
__RISCV_ISA_EXT_DATA(zfa, RISCV_ISA_EXT_ZFA),
__RISCV_ISA_EXT_DATA(zfh, RISCV_ISA_EXT_ZFH),
__RISCV_ISA_EXT_DATA(zfhmin, RISCV_ISA_EXT_ZFHMIN),
__RISCV_ISA_EXT_DATA(zca, RISCV_ISA_EXT_ZCA),
__RISCV_ISA_EXT_DATA_VALIDATE(zcb, RISCV_ISA_EXT_ZCB, riscv_ext_zca_depends),
__RISCV_ISA_EXT_DATA_VALIDATE(zcd, RISCV_ISA_EXT_ZCD, riscv_ext_zcd_validate),
__RISCV_ISA_EXT_DATA_VALIDATE(zcf, RISCV_ISA_EXT_ZCF, riscv_ext_zcf_validate),
__RISCV_ISA_EXT_DATA_VALIDATE(zcmop, RISCV_ISA_EXT_ZCMOP, riscv_ext_zca_depends),
__RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA),
__RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
__RISCV_ISA_EXT_DATA(zbc, RISCV_ISA_EXT_ZBC),
__RISCV_ISA_EXT_DATA(zbkb, RISCV_ISA_EXT_ZBKB),
__RISCV_ISA_EXT_DATA(zbkc, RISCV_ISA_EXT_ZBKC),
__RISCV_ISA_EXT_DATA(zbkx, RISCV_ISA_EXT_ZBKX),
__RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
__RISCV_ISA_EXT_BUNDLE(zk, riscv_zk_bundled_exts),
__RISCV_ISA_EXT_BUNDLE(zkn, riscv_zkn_bundled_exts),
__RISCV_ISA_EXT_DATA(zknd, RISCV_ISA_EXT_ZKND),
__RISCV_ISA_EXT_DATA(zkne, RISCV_ISA_EXT_ZKNE),
__RISCV_ISA_EXT_DATA(zknh, RISCV_ISA_EXT_ZKNH),
__RISCV_ISA_EXT_DATA(zkr, RISCV_ISA_EXT_ZKR),
__RISCV_ISA_EXT_BUNDLE(zks, riscv_zks_bundled_exts),
__RISCV_ISA_EXT_DATA(zkt, RISCV_ISA_EXT_ZKT),
__RISCV_ISA_EXT_DATA(zksed, RISCV_ISA_EXT_ZKSED),
__RISCV_ISA_EXT_DATA(zksh, RISCV_ISA_EXT_ZKSH),
__RISCV_ISA_EXT_DATA(ztso, RISCV_ISA_EXT_ZTSO),
__RISCV_ISA_EXT_SUPERSET(zvbb, RISCV_ISA_EXT_ZVBB, riscv_zvbb_exts),
__RISCV_ISA_EXT_DATA(zvbc, RISCV_ISA_EXT_ZVBC),
__RISCV_ISA_EXT_SUPERSET(zve32f, RISCV_ISA_EXT_ZVE32F, riscv_zve32f_exts),
__RISCV_ISA_EXT_DATA(zve32x, RISCV_ISA_EXT_ZVE32X),
__RISCV_ISA_EXT_SUPERSET(zve64d, RISCV_ISA_EXT_ZVE64D, riscv_zve64d_exts),
__RISCV_ISA_EXT_SUPERSET(zve64f, RISCV_ISA_EXT_ZVE64F, riscv_zve64f_exts),
__RISCV_ISA_EXT_SUPERSET(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts),
__RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH),
__RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN),
__RISCV_ISA_EXT_DATA(zvkb, RISCV_ISA_EXT_ZVKB),
__RISCV_ISA_EXT_DATA(zvkg, RISCV_ISA_EXT_ZVKG),
__RISCV_ISA_EXT_BUNDLE(zvkn, riscv_zvkn_bundled_exts),
__RISCV_ISA_EXT_BUNDLE(zvknc, riscv_zvknc_bundled_exts),
__RISCV_ISA_EXT_DATA(zvkned, RISCV_ISA_EXT_ZVKNED),
__RISCV_ISA_EXT_BUNDLE(zvkng, riscv_zvkng_bundled_exts),
__RISCV_ISA_EXT_DATA(zvknha, RISCV_ISA_EXT_ZVKNHA),
__RISCV_ISA_EXT_DATA(zvknhb, RISCV_ISA_EXT_ZVKNHB),
__RISCV_ISA_EXT_BUNDLE(zvks, riscv_zvks_bundled_exts),
__RISCV_ISA_EXT_BUNDLE(zvksc, riscv_zvksc_bundled_exts),
__RISCV_ISA_EXT_DATA(zvksed, RISCV_ISA_EXT_ZVKSED),
__RISCV_ISA_EXT_DATA(zvksh, RISCV_ISA_EXT_ZVKSH),
__RISCV_ISA_EXT_BUNDLE(zvksg, riscv_zvksg_bundled_exts),
__RISCV_ISA_EXT_DATA(zvkt, RISCV_ISA_EXT_ZVKT),
__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
__RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM),
__RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts),
__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
__RISCV_ISA_EXT_DATA(svvptc, RISCV_ISA_EXT_SVVPTC),
};
const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
static void riscv_isa_set_ext(const struct riscv_isa_ext_data *ext, unsigned long *bitmap)
{
if (ext->id != RISCV_ISA_EXT_INVALID)
__set_bit(ext->id, bitmap);
for (int i = 0; i < ext->subset_ext_size; i++) {
if (ext->subset_ext_ids[i] != RISCV_ISA_EXT_INVALID)
__set_bit(ext->subset_ext_ids[i], bitmap);
}
}
static void match_isa_ext(const char *name, const char *name_end)
{
for (int i = 0; i < riscv_isa_ext_count; i++) {
const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i];
if ((name_end - name == strlen(ext->name)) &&
!strncasecmp(name, ext->name, name_end - name)) {
if (ext->validate && !ext->validate(ext, riscv_isa))
riscv_isa_set_ext(ext, riscv_isa);
break;
}
}
}
static void riscv_parse_isa_string(const char *isa)
{
/*
* For all possible cpus, we have already validated in
* the boot process that they at least contain "rv" and
* whichever of "32"/"64" this kernel supports, and so this
* section can be skipped.
*/
isa += 4;
while (*isa) {
const char *ext = isa++;
const char *ext_end = isa;
bool ext_err = false;
switch (*ext) {
case 'x':
case 'X':
log_warning("Vendor extensions are ignored in riscv,isa. Use riscv,isa-extensions instead.");
/*
* To skip an extension, we find its end.
* As multi-letter extensions must be split from other multi-letter
* extensions with an "_", the end of a multi-letter extension will
* either be the null character or the "_" at the start of the next
* multi-letter extension.
*/
for (; *isa && *isa != '_'; ++isa)
;
ext_err = true;
break;
case 's':
/*
* Workaround for invalid single-letter 's' & 'u' (QEMU).
* No need to set the bit in riscv_isa as 's' & 'u' are
* not valid ISA extensions. It works unless the first
* multi-letter extension in the ISA string begins with
* "Su" and is not prefixed with an underscore.
*/
if (ext[-1] != '_' && ext[1] == 'u') {
++isa;
ext_err = true;
break;
}
fallthrough;
case 'S':
case 'z':
case 'Z':
/*
* Before attempting to parse the extension itself, we find its end.
* As multi-letter extensions must be split from other multi-letter
* extensions with an "_", the end of a multi-letter extension will
* either be the null character or the "_" at the start of the next
* multi-letter extension.
*
* Next, as the extensions version is currently ignored, we
* eliminate that portion. This is done by parsing backwards from
* the end of the extension, removing any numbers. This may be a
* major or minor number however, so the process is repeated if a
* minor number was found.
*
* ext_end is intended to represent the first character *after* the
* name portion of an extension, but will be decremented to the last
* character itself while eliminating the extensions version number.
* A simple re-increment solves this problem.
*/
for (; *isa && *isa != '_'; ++isa)
if (unlikely(!isalnum(*isa)))
ext_err = true;
ext_end = isa;
if (unlikely(ext_err))
break;
if (!isdigit(ext_end[-1]))
break;
while (isdigit(*--ext_end))
;
if (tolower(ext_end[0]) != 'p' || !isdigit(ext_end[-1])) {
++ext_end;
break;
}
while (isdigit(*--ext_end))
;
++ext_end;
break;
default:
/*
* Things are a little easier for single-letter extensions, as they
* are parsed forwards.
*
* After checking that our starting position is valid, we need to
* ensure that, when isa was incremented at the start of the loop,
* that it arrived at the start of the next extension.
*
* If we are already on a non-digit, there is nothing to do. Either
* we have a multi-letter extension's _, or the start of an
* extension.
*
* Otherwise we have found the current extension's major version
* number. Parse past it, and a subsequent p/minor version number
* if present. The `p` extension must not appear immediately after
* a number, so there is no fear of missing it.
*
*/
if (unlikely(!isalpha(*ext))) {
ext_err = true;
break;
}
if (!isdigit(*isa))
break;
while (isdigit(*++isa))
;
if (tolower(*isa) != 'p')
break;
if (!isdigit(*++isa)) {
--isa;
break;
}
while (isdigit(*++isa))
;
break;
}
/*
* The parser expects that at the start of an iteration isa points to the
* first character of the next extension. As we stop parsing an extension
* on meeting a non-alphanumeric character, an extra increment is needed
* where the succeeding extension is a multi-letter prefixed with an "_".
*/
if (*isa == '_')
++isa;
if (unlikely(ext_err))
continue;
match_isa_ext(ext, ext_end);
}
}
static inline bool supports_extension(char ext)
{
#if CONFIG_IS_ENABLED(RISCV_MMODE)
return csr_read(CSR_MISA) & (1 << (ext - 'a'));
#elif CONFIG_CPU
char sext[2] = {ext};
struct udevice *dev;
const char *isa;
int ret, i;
uclass_find_first_device(UCLASS_CPU, &dev);
if (!dev) {
debug("unable to find the RISC-V cpu device\n");
return false;
}
ret = dev_read_stringlist_search(dev, "riscv,isa-extensions", sext);
if (ret >= 0)
return true;
/*
* Only if the property is not found (ENODATA) is the fallback to
* riscv,isa used, otherwise the extension is not present in this
* CPU.
*/
if (ret != -ENODATA)
return false;
isa = dev_read_string(dev, "riscv,isa");
if (!isa)
return false;
/*
* Skip the first 4 characters (rv32|rv64).
*/
for (i = 4; i < sizeof(isa); i++) {
switch (isa[i]) {
case 's':
case 'x':
case 'z':
case '_':
case '\0':
/*
* Any of these characters mean the single
* letter extensions have all been consumed.
*/
return false;
default:
if (isa[i] == ext)
return true;
}
}
return false;
return __riscv_isa_extension_available(ext);
#else /* !CONFIG_CPU */
#warning "There is no way to determine the available extensions in S-mode."
#warning "Please convert your board to use the RISC-V CPU driver."
@@ -122,7 +631,26 @@ static void dummy_pending_ipi_clear(ulong hart, ulong arg0, ulong arg1)
int riscv_cpu_setup(void)
{
int __maybe_unused ret;
int ret = -ENODEV, ext_count, i;
const char *isa, **exts;
struct udevice *dev;
uclass_find_first_device(UCLASS_CPU, &dev);
if (!dev) {
debug("unable to find the RISC-V cpu device\n");
return ret;
}
ext_count = dev_read_string_list(dev, "riscv,isa-extensions", &exts);
if (ext_count > 0) {
for (i = 0; i < ext_count; i++)
match_isa_ext(exts[i], exts[i] + strlen(exts[i]));
} else {
isa = dev_read_string(dev, "riscv,isa");
if (!isa)
return ret;
riscv_parse_isa_string(isa);
}
/* Enable FPU */
if (supports_extension('d') || supports_extension('f')) {

View File

@@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2025, Junhui Liu <junhui.liu@pigmoral.tech>
config CANAAN_K230
bool
select ARCH_EARLY_INIT_R
select BINMAN
imply CPU
imply CPU_RISCV
imply RISCV_TIMER
imply CMD_CPU
imply SYSRESET
imply SYSRESET_SYSCON

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2025, Junhui Liu <junhui.liu@pigmoral.tech>
obj-y += dram.o
obj-y += cpu.o

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025, Junhui Liu <junhui.liu@pigmoral.tech>
*/
int cleanup_before_linux(void)
{
return 0;
}

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <asm/global_data.h>
#include <fdtdec.h>
#include <init.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
return fdtdec_setup_mem_size_base();
}
int dram_init_banksize(void)
{
return fdtdec_setup_memory_banksize();
}

View File

@@ -2,6 +2,7 @@
dtb-$(CONFIG_TARGET_ANDES_AE350) += ae350_32.dtb ae350_64.dtb
dtb-$(CONFIG_TARGET_BANANAPI_F3) += k1-bananapi-f3.dtb
dtb-$(CONFIG_TARGET_K230_CANMV) += k230-canmv.dtb
dtb-$(CONFIG_TARGET_MICROCHIP_ICICLE) += mpfs-icicle-kit.dtb
dtb-$(CONFIG_TARGET_MILKV_DUO) += cv1800b-milkv-duo.dtb
dtb-$(CONFIG_TARGET_LICHEERV_NANO) += sg2002-licheerv-nano-b.dtb

View File

@@ -3,7 +3,6 @@
* Copyright (C) 2023 StarFive Technology Co., Ltd.
*/
#include "binman.dtsi"
#include "jh7110-u-boot.dtsi"
/ {
aliases {
@@ -19,11 +18,6 @@
bootph-pre-ram;
};
config {
bootph-pre-ram;
u-boot,spl-payload-offset = <0x100000>;
};
memory@40000000 {
bootph-pre-ram;
};
@@ -104,92 +98,3 @@
pagesize = <16>;
};
};
&binman {
itb {
fit {
images {
fdt-jh7110-milkv-mars {
description = "jh7110-milkv-mars";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-milkv-mars.dtb";
};
};
fdt-jh7110-pine64-star64 {
description = "jh7110-pine64-star64";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-pine64-star64.dtb";
};
};
fdt-jh7110-starfive-visionfive-2-v1.2a {
description = "jh7110-starfive-visionfive-2-v1.2a";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb";
};
};
fdt-jh7110-starfive-visionfive-2-v1.3b {
description = "jh7110-starfive-visionfive-2-v1.3b";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb";
};
};
};
configurations {
conf-jh7110-milkv-mars {
description = "jh7110-milkv-mars";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-milkv-mars";
};
conf-jh7110-pine64-star64 {
description = "jh7110-pine64-star64";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-pine64-star64";
};
conf-jh7110-starfive-visionfive-2-v1.2a {
description = "jh7110-starfive-visionfive-2-v1.2a";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-starfive-visionfive-2-v1.2a";
};
conf-jh7110-starfive-visionfive-2-v1.3b {
description = "jh7110-starfive-visionfive-2-v1.3b";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-starfive-visionfive-2-v1.3b";
};
};
};
};
spl-img {
filename = "spl/u-boot-spl.bin.normal.out";
mkimage {
args = "-T sfspl";
u-boot-spl {
};
};
};
};

View File

@@ -4,3 +4,4 @@
*/
#include "jh7110-common-u-boot.dtsi"
#include "starfive-visionfive2-binman.dtsi"

View File

@@ -4,3 +4,4 @@
*/
#include "jh7110-common-u-boot.dtsi"
#include "starfive-visionfive2-binman.dtsi"

View File

@@ -4,3 +4,4 @@
*/
#include "jh7110-common-u-boot.dtsi"
#include "starfive-visionfive2-binman.dtsi"

View File

@@ -4,3 +4,4 @@
*/
#include "jh7110-common-u-boot.dtsi"
#include "starfive-visionfive2-binman.dtsi"

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2024 Yangyu Chen <cyy@cyyself.name>
* Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech>
*/
/dts-v1/;
#include "k230.dtsi"
/ {
model = "Canaan CanMV-K230";
compatible = "canaan,canmv-k230", "canaan,kendryte-k230";
chosen {
stdout-path = "serial0:115200n8";
};
memory@0 {
device_type = "memory";
reg = <0x0 0x0 0x0 0x20000000>;
};
};
&uart0 {
status = "okay";
};
/* onboard RTL8152 */
&usb1 {
status = "okay";
};

View File

@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech>
*/
#include <linux/stringify.h>
/ {
binman: binman {
};
};
&binman {
mkimage {
filename = "u-boot-gz.img";
args = "-A", "riscv", "-T", "firmware", "-O", "u-boot",
"-C", "gzip", "-n", "uboot",
"-a", __stringify(CONFIG_TEXT_BASE),
"-e", __stringify(CONFIG_TEXT_BASE);
blob {
filename = "u-boot.bin";
compress = "gzip";
};
};
};

175
arch/riscv/dts/k230.dtsi Normal file
View File

@@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2024 Yangyu Chen <cyy@cyyself.name>
* Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech>
*/
#include <dt-bindings/interrupt-controller/irq.h>
/ {
#address-cells = <2>;
#size-cells = <2>;
compatible = "canaan,kendryte-k230";
aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
serial3 = &uart3;
serial4 = &uart4;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <27000000>;
cpu@0 {
compatible = "thead,c908", "riscv";
device_type = "cpu";
reg = <0>;
riscv,isa = "rv64imafdcv_zicbom_zicbop_zicboz_zfh_zba_zbb_zbc_zbs_zvfh_svpbmt";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "zicbom",
"zicbop", "zicboz", "zicntr", "zicsr", "zifencei",
"zihpm", "zfh", "zba", "zbb", "zbc", "zbs", "zvfh",
"svpbmt";
riscv,cbom-block-size = <64>;
riscv,cbop-block-size = <64>;
riscv,cboz-block-size = <64>;
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
};
apb_clk: apb-clk-clock {
compatible = "fixed-clock";
clock-frequency = <50000000>;
clock-output-names = "apb_clk";
#clock-cells = <0>;
};
clk_dummy: clock-dummy {
compatible = "fixed-clock";
clock-frequency = <0>;
clock-output-names = "clk_dummy";
#clock-cells = <0>;
};
reboot: syscon-reboot {
compatible = "syscon-reboot";
regmap = <&bootctl>;
offset = <0x60>;
mask = <0x10001>;
value = <0x10001>;
};
soc {
compatible = "simple-bus";
interrupt-parent = <&plic>;
#address-cells = <2>;
#size-cells = <2>;
dma-noncoherent;
ranges;
bootctl: syscon@0x91102000 {
compatible = "syscon";
reg = <0x0 0x91102000 0x0 0x1000>;
};
plic: interrupt-controller@f00000000 {
compatible = "canaan,k230-plic" ,"thead,c900-plic";
reg = <0xf 0x00000000 0x0 0x04000000>;
interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>;
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
riscv,ndev = <208>;
};
clint: timer@f04000000 {
compatible = "canaan,k230-clint", "thead,c900-clint";
reg = <0xf 0x04000000 0x0 0x00010000>;
interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>;
};
uart0: serial@91400000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x91400000 0x0 0x1000>;
clocks = <&apb_clk>;
interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
reg-io-width = <4>;
reg-shift = <2>;
status = "disabled";
};
uart1: serial@91401000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x91401000 0x0 0x1000>;
clocks = <&apb_clk>;
interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
reg-io-width = <4>;
reg-shift = <2>;
status = "disabled";
};
uart2: serial@91402000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x91402000 0x0 0x1000>;
clocks = <&apb_clk>;
interrupts = <18 IRQ_TYPE_LEVEL_HIGH>;
reg-io-width = <4>;
reg-shift = <2>;
status = "disabled";
};
uart3: serial@91403000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x91403000 0x0 0x1000>;
clocks = <&apb_clk>;
interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
reg-io-width = <4>;
reg-shift = <2>;
status = "disabled";
};
uart4: serial@91404000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x91404000 0x0 0x1000>;
clocks = <&apb_clk>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
reg-io-width = <4>;
reg-shift = <2>;
status = "disabled";
};
usb0: usb@91500000 {
compatible = "canaan,k230-otg", "snps,dwc2";
reg = <0x0 0x91500000 0x0 0x40000>;
interrupts = <173 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_dummy>;
clock-names = "otg";
g-rx-fifo-size = <512>;
g-np-tx-fifo-size = <64>;
g-tx-fifo-size = <512 1024 64 64 64 64>;
status = "disabled";
};
usb1: usb@91540000 {
compatible = "canaan,k230-otg", "snps,dwc2";
reg = <0x0 0x91540000 0x0 0x40000>;
interrupts = <174 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_dummy>;
clock-names = "otg";
g-rx-fifo-size = <512>;
g-np-tx-fifo-size = <64>;
g-tx-fifo-size = <512 1024 64 64 64 64>;
status = "disabled";
};
};
};

View File

@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
*/
#include "binman.dtsi"
/ {
config {
bootph-pre-ram;
u-boot,spl-payload-offset = <0x100000>;
};
};
&binman {
itb {
fit {
images {
fdt-jh7110-milkv-mars {
description = "jh7110-milkv-mars";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-milkv-mars.dtb";
};
};
fdt-jh7110-pine64-star64 {
description = "jh7110-pine64-star64";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-pine64-star64.dtb";
};
};
fdt-jh7110-starfive-visionfive-2-v1.2a {
description = "jh7110-starfive-visionfive-2-v1.2a";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb";
};
};
fdt-jh7110-starfive-visionfive-2-v1.3b {
description = "jh7110-starfive-visionfive-2-v1.3b";
load = <0x40400000>;
compression = "none";
blob-ext {
filename = "dts/upstream/src/riscv/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb";
};
};
};
configurations {
conf-jh7110-milkv-mars {
description = "jh7110-milkv-mars";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-milkv-mars";
};
conf-jh7110-pine64-star64 {
description = "jh7110-pine64-star64";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-pine64-star64";
};
conf-jh7110-starfive-visionfive-2-v1.2a {
description = "jh7110-starfive-visionfive-2-v1.2a";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-starfive-visionfive-2-v1.2a";
};
conf-jh7110-starfive-visionfive-2-v1.3b {
description = "jh7110-starfive-visionfive-2-v1.3b";
firmware = "opensbi";
loadables = "uboot";
fdt = "fdt-jh7110-starfive-visionfive-2-v1.3b";
};
};
};
};
spl-img {
filename = "spl/u-boot-spl.bin.normal.out";
mkimage {
args = "-T sfspl";
u-boot-spl {
};
};
};
};

View File

@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_CPUFEATURE_H
#define _ASM_CPUFEATURE_H
struct riscv_isa_ext_data {
const unsigned int id;
const char *name;
const char *property;
const unsigned int *subset_ext_ids;
const unsigned int subset_ext_size;
int (*validate)(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap);
};
#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
.name = #_name, \
.property = #_name, \
.id = _id, \
.subset_ext_ids = _subset_exts, \
.subset_ext_size = _subset_exts_size, \
.validate = _validate \
}
#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL)
#define __RISCV_ISA_EXT_DATA_VALIDATE(_name, _id, _validate) \
_RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, _validate)
/* Used to declare pure "lasso" extension (Zk for instance) */
#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
_RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
ARRAY_SIZE(_bundled_exts), NULL)
/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL)
#define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
#endif

View File

@@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_RISCV_HWCAP_H
#define _ASM_RISCV_HWCAP_H
#define RISCV_ISA_EXT_a ('a' - 'a')
#define RISCV_ISA_EXT_c ('c' - 'a')
#define RISCV_ISA_EXT_d ('d' - 'a')
#define RISCV_ISA_EXT_f ('f' - 'a')
#define RISCV_ISA_EXT_h ('h' - 'a')
#define RISCV_ISA_EXT_i ('i' - 'a')
#define RISCV_ISA_EXT_m ('m' - 'a')
#define RISCV_ISA_EXT_q ('q' - 'a')
#define RISCV_ISA_EXT_v ('v' - 'a')
/*
* These macros represent the logical IDs of each multi-letter RISC-V ISA
* extension and are used in the ISA bitmap. The logical IDs start from
* RISCV_ISA_EXT_BASE, which allows the 0-25 range to be reserved for single
* letter extensions. The maximum, RISCV_ISA_EXT_MAX, is defined in order
* to allocate the bitmap and may be increased when necessary.
*
* New extensions should just be added to the bottom, rather than added
* alphabetically, in order to avoid unnecessary shuffling.
*/
#define RISCV_ISA_EXT_BASE 26
#define RISCV_ISA_EXT_SSCOFPMF 26
#define RISCV_ISA_EXT_SSTC 27
#define RISCV_ISA_EXT_SVINVAL 28
#define RISCV_ISA_EXT_SVPBMT 29
#define RISCV_ISA_EXT_ZBB 30
#define RISCV_ISA_EXT_ZICBOM 31
#define RISCV_ISA_EXT_ZIHINTPAUSE 32
#define RISCV_ISA_EXT_SVNAPOT 33
#define RISCV_ISA_EXT_ZICBOZ 34
#define RISCV_ISA_EXT_SMAIA 35
#define RISCV_ISA_EXT_SSAIA 36
#define RISCV_ISA_EXT_ZBA 37
#define RISCV_ISA_EXT_ZBS 38
#define RISCV_ISA_EXT_ZICNTR 39
#define RISCV_ISA_EXT_ZICSR 40
#define RISCV_ISA_EXT_ZIFENCEI 41
#define RISCV_ISA_EXT_ZIHPM 42
#define RISCV_ISA_EXT_SMSTATEEN 43
#define RISCV_ISA_EXT_ZICOND 44
#define RISCV_ISA_EXT_ZBC 45
#define RISCV_ISA_EXT_ZBKB 46
#define RISCV_ISA_EXT_ZBKC 47
#define RISCV_ISA_EXT_ZBKX 48
#define RISCV_ISA_EXT_ZKND 49
#define RISCV_ISA_EXT_ZKNE 50
#define RISCV_ISA_EXT_ZKNH 51
#define RISCV_ISA_EXT_ZKR 52
#define RISCV_ISA_EXT_ZKSED 53
#define RISCV_ISA_EXT_ZKSH 54
#define RISCV_ISA_EXT_ZKT 55
#define RISCV_ISA_EXT_ZVBB 56
#define RISCV_ISA_EXT_ZVBC 57
#define RISCV_ISA_EXT_ZVKB 58
#define RISCV_ISA_EXT_ZVKG 59
#define RISCV_ISA_EXT_ZVKNED 60
#define RISCV_ISA_EXT_ZVKNHA 61
#define RISCV_ISA_EXT_ZVKNHB 62
#define RISCV_ISA_EXT_ZVKSED 63
#define RISCV_ISA_EXT_ZVKSH 64
#define RISCV_ISA_EXT_ZVKT 65
#define RISCV_ISA_EXT_ZFH 66
#define RISCV_ISA_EXT_ZFHMIN 67
#define RISCV_ISA_EXT_ZIHINTNTL 68
#define RISCV_ISA_EXT_ZVFH 69
#define RISCV_ISA_EXT_ZVFHMIN 70
#define RISCV_ISA_EXT_ZFA 71
#define RISCV_ISA_EXT_ZTSO 72
#define RISCV_ISA_EXT_ZACAS 73
#define RISCV_ISA_EXT_ZVE32X 74
#define RISCV_ISA_EXT_ZVE32F 75
#define RISCV_ISA_EXT_ZVE64X 76
#define RISCV_ISA_EXT_ZVE64F 77
#define RISCV_ISA_EXT_ZVE64D 78
#define RISCV_ISA_EXT_ZIMOP 79
#define RISCV_ISA_EXT_ZCA 80
#define RISCV_ISA_EXT_ZCB 81
#define RISCV_ISA_EXT_ZCD 82
#define RISCV_ISA_EXT_ZCF 83
#define RISCV_ISA_EXT_ZCMOP 84
#define RISCV_ISA_EXT_ZAWRS 85
#define RISCV_ISA_EXT_SVVPTC 86
#define RISCV_ISA_EXT_SMMPM 87
#define RISCV_ISA_EXT_SMNPM 88
#define RISCV_ISA_EXT_SSNPM 89
#define RISCV_ISA_EXT_XLINUXENVCFG 127
#define RISCV_ISA_EXT_MAX 128
#define RISCV_ISA_EXT_INVALID U32_MAX
#ifdef CONFIG_RISCV_M_MODE
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA
#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SMNPM
#else
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SSAIA
#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SSNPM
#endif
#endif /* _ASM_RISCV_HWCAP_H */

View File

@@ -24,7 +24,7 @@ enum {
CBO_INVAL
} riscv_cbo_ops;
static int zicbom_block_size;
extern unsigned int riscv_get_cbom_block_size(void);
static inline void do_cbo_clean(unsigned long base)
{
asm volatile ("add a0, %0, zero\n" CBO_CLEAN(%0) ::
@@ -79,25 +79,6 @@ void cbo_inval(unsigned long start, unsigned long end)
cbo_op(CBO_INVAL, start, end);
}
static int riscv_zicbom_init(void)
{
struct udevice *dev;
if (!CONFIG_IS_ENABLED(RISCV_ISA_ZICBOM) || zicbom_block_size)
return 1;
uclass_first_device(UCLASS_CPU, &dev);
if (!dev) {
log_debug("Failed to get cpu device!\n");
return 0;
}
if (dev_read_u32(dev, "riscv,cbom-block-size", &zicbom_block_size))
log_debug("riscv,cbom-block-size DT property not present\n");
return zicbom_block_size;
}
void invalidate_icache_all(void)
{
asm volatile ("fence.i" ::: "memory");
@@ -166,6 +147,7 @@ __weak int dcache_status(void)
__weak void enable_caches(void)
{
if (!riscv_zicbom_init())
log_info("Zicbom not initialized.\n");
zicbom_block_size = riscv_get_cbom_block_size();
if (!zicbom_block_size)
log_debug("Zicbom not initialized.\n");
}

View File

@@ -0,0 +1,19 @@
if TARGET_K230_CANMV
config SYS_BOARD
default "k230_canmv"
config SYS_VENDOR
default "canaan"
config SYS_CPU
default "k230"
config TEXT_BASE
default 0x0
config BOARD_SPECIFIC_OPTIONS
def_bool y
select CANAAN_K230
endif

View File

@@ -0,0 +1,6 @@
K230 CANMV
M: Junhui Liu <junhui.liu@pigmoral.tech>
S: Maintained
F: board/canaan/k230_canmv/
F: configs/k230_canmv_defconfig
F: doc/board/canaan/k230_canmv.rst

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2025, Junhui Liu <junhui.liu@pigmoral.tech>
obj-y += board.o

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025, Junhui Liu <junhui.liu@pigmoral.tech>
*/
int board_init(void)
{
return 0;
}

View File

@@ -0,0 +1,19 @@
CONFIG_RISCV=y
CONFIG_SYS_MALLOC_F_LEN=0x40000
CONFIG_NR_DRAM_BANKS=1
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80400000
CONFIG_DEFAULT_DEVICE_TREE="k230-canmv"
CONFIG_SYS_LOAD_ADDR=0xc000000
CONFIG_TARGET_K230_CANMV=y
CONFIG_ARCH_RV64I=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="K230# "
CONFIG_CMD_USB=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_SYS_NS16550=y
CONFIG_SYS_NS16550_MEM32=y
CONFIG_USB=y
CONFIG_USB_DWC2=y
CONFIG_USB_HOST_ETHER=y
CONFIG_USB_ETHER_RTL8152=y

View File

@@ -0,0 +1,8 @@
.. SPDX-License-Identifier: GPL-2.0+
Canaan
======
.. toctree::
:maxdepth: 1
k230_canmv

View File

@@ -0,0 +1,88 @@
.. SPDX-License-Identifier: GPL-2.0+
K230 CanMV
==========
K230 RISC-V SoC
------------------
The K230 chip is the latest generation SoC product in Canaan Technology's
Kendryte series of AIOT chips.
Mainline support
----------------
The support for following drivers are already enabled:
1. ns16550 UART
2. DWC2 OTG USB controller
Building
~~~~~~~~
1. Get the RISC-V toolchain.
2. Setup cross compilation environment variable:
3. Get the `firmware_gen.py`_ from vendor.
.. code-block:: console
export CROSS_COMPILE=riscv64-linux-gnu-
cd <U-Boot-dir>
make k230_canmv_defconfig
make
cp u-boot-gz.img u-boot-gz.img.tmp
pip install gmssl pycryptodome
python3 firmware_gen.py -i u-boot-gz.img.tmp -o u-boot-head.img -n
This will generate u-boot-head.img.
.. _firmware_gen.py: https://raw.githubusercontent.com/kendryte/k230_sdk/refs/tags/v1.8/src/little/uboot/tools/firmware_gen.py
Booting
~~~~~~~
Currently, we rely on vendor u-boot-spl to initialize the
ddr and load the u-boot image, then bootup from it.
1. Prepare a SD card with the `vendor image`_ burned on it.
2. Write the U-Boot image to the SD card at offset 2MB.
.. code-block:: console
dd if=u-boot-head.img of=/dev/sd[x] bs=1M seek=2
3. Insert the SD card into the board and power it on.
.. _vendor image: https://kendryte-download.canaan-creative.com/developer/k230/CanMV-K230_debian_sdcard_sdk_1.3.img.gz
Sample boot log from K230 CanMV board
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: none
U-Boot 2025.01-00645-g2d81c4788455 (Jan 14 2025 - 23:15:07 +0800)
DRAM: 512 MiB
Core: 15 devices, 11 uclasses, devicetree: separate
Loading Environment from nowhere... OK
In: serial@91400000
Out: serial@91400000
Err: serial@91400000
Net: No ethernet found.
K230# cpu list
0: cpu@0 thead,c908
K230# usb start
starting USB...
Bus usb@91540000: USB DWC2
scanning bus usb@91540000 for devices...
Warning: r8152_eth (eth0) using random MAC address - 1e:33:97:47:e6:32
2 USB Device(s) found
K230# usb tree
USB device tree:
1 Hub (480 Mb/s, 0mA)
| U-Boot Root Hub
|
+-2 Vendor specific (480 Mb/s, 100mA)
Realtek USB 10/100 LAN 000000000000
K230#

View File

@@ -21,6 +21,7 @@ Board-specific doc
beagle/index
broadcom/index
bsh/index
canaan/index
cloos/index
congatec/index
coolpi/index

View File

@@ -4,6 +4,7 @@ Platform DesignWare HS OTG USB 2.0 controller
Required properties:
- compatible : One of:
- brcm,bcm2835-usb: The DWC2 USB controller instance in the BCM2835 SoC.
- canaan,k230-otg: The DWC2 USB controller instance in the K230 SoC.
- hisilicon,hi6220-usb: The DWC2 USB controller instance in the hi6220 SoC.
- "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq ARX SoCs;
- "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs;