20230126使AIO-3568J开发板在原厂Android11下跑起来

news2024/12/26 23:14:51

20230126使AIO-3568J开发板在原厂Android11下跑起来
2023/1/26 18:22


1、前提
2、修改dts设备树
3、适配板子的dts
4、(修改uboot)编译系统烧入固件验证

前提
因源码是直接使用原厂的SDK,没有使用firefly配套的SDK源码,所以手上这块firefly aio-3568i板子在硬计上与原厂使用的板子会有些差异;
就是因为这些差异会导致新固件烧入后,debug串口 打印许多错息,可能的话,系统还会崩溃掉,跑不起来

主要差异在哪里呢?比如:
1、DDR类型和品牌多样性;
2、电源管理PMU: RK809 PMU芯片各路输出电压不同,需要修改dts配置
3、CPU,GPU电压配置或电压域配置问题
4、GPIO控制管脚分配控制的芯片器件不同这些问题只需我们到dts 设备树上进行修改,重新适配下我们手上的aio-3568i板子


1、【临时使用可以不用修改的!^_】修改dts设备树
找当前kernel使用的是哪个dts文件先配置Android分支:
/build/envsetup.sh
lunch rk3566_r-userdebug

查找方法:
查看编译脚本用的是哪个dts文件
查看build.sh脚本,找到kernel当前使用的dts名称:


Y:\rk3568_Android11.0_ToyBrick\device\rockchip\rk356x\rk3568_r\BoardConfig.mk
PRODUCT_KERNEL_DTS := rk3568-evb1-ddr4-v10
修改为:
PRODUCT_KERNEL_DTS := rk3568-evb2-lp4x-v10


# only save the version code
SDK_VERSION=`get_build_var CURRENT_SDK_VERSION`
UBOOT_DEFCONFIG=`get_build_var PRODUCT_UBOOT_CONFIG`
KERNEL_ARCH=`get_build_var PRODUCT_KERNEL_ARCH`
KERNEL_DEFCONFIG=`get_build_var PRODUCT_KERNEL_CONFIG`
if [ "$KERNEL_DTS" = "" ] ; then
KERNEL_DTS=`get_build_var PRODUCT_KERNEL_DTS`
fi
echo "-------------------KERNEL_DTS:$KERNEL_DTS"
PACK_TOOL_DIR=RKTools/linux/Linux_Pack_Firmware
IMAGE_PATH=rockdev/Image-$TARGET_PRODUCT
export PROJECT_TOP=`gettop`

lunch $TARGET_PRODUCT-$BUILD_VARIANT


服务器shell终端输入: get_build_var PRODUCT_KERNEL_DTS
ubuntu:~/rk356x/rk356x android11$ get build var PRODUCT KERNEL DTS68-evb1-ddr4-v10
从中可知道kernel是使用rk3568-evb1-ddr4-v10.dts


可以到源码中查找:
kernel/arch/arm64/boot/dts/rk3568-evb1-ddr4-v10.dts
替换dts文件
如如果需要替换为其他名称的dts,可以到这个文件下修改
device/rockchip/rk356x/rk3568_r/BoardConfig.mk


演示:因AIO-3568J的DDR是LPDDR4,所以替换个rk3568-evb2-p4x-v10.dts
修改: device/rockchip/rk356x/rk3568_r/BoardConfig.mk
PRODUCT_UBOOT_CONFIG := rk3568
PRODUCT_KERNEL_DTS := rk3568-evb2-lp4x-v10
BOARD_GSENSOR_MXC6655XA_SUPPORT := true
BOARD_CAMERA_SUPPORT_EXT := true
BOARD_HS_ETHERNET := true

再次执行: get build_var PRODUCT_KERNEL DTS
即可看到kernel使用的dts变为rk3568-evb2-lp4x-v10.dts

rootroot@rootroot-HP-ZHAN-66-Pro-A-14-G3:~/rk3568_Android11.0_ToyBrick$ 
rootroot@rootroot-HP-ZHAN-66-Pro-A-14-G3:~/rk3568_Android11.0_ToyBrick$ get_build_var PRODUCT_KERNEL_DTS
rk3568-evb2-lp4x-v10

rootroot@rootroot-HP-ZHAN-66-Pro-A-14-G3:~/rk3568_Android11.0_ToyBrick$ 


适配板子的dts
先打开板子的原理图和位置图
嵌入式开发和学习,板子硬件的原理图和位置图PDF图纸是不可或少的哈aio-3568i-位置图背面pdf          2021/8/6 23:56
aio-3568j-位置图正面pdf          2021/8/6 23:57
MB-JM3-RK3568-V12-20210616pdf    2021/8/7 8:25


【临时使用可以不用修改的!^_但是是给WIFI和以太网RJ45供电的,长期使用可能会损害相关器件!^_】
2、因AIO-3568J板子是核心板+底板形式,firefly官方并没有开放核心板的原理图,所以dts的配置需要参考发布的Android11源码;
主要参考:IO电源域和RK809配置部分;
可看下此篇文章IO电源域和RK809知识点:
https://blog.csdn.net/soar999999/article/details/120102934

[[RK3568 Android11] 教程之IO电源域和rk809 DTS讲解
两套SDK源码对比最终的dts配置如下:
lIO电源域配置 (rk3568-evbd.tsi) :

Y:\rk3568_Android11.0_ToyBrick\kernel\arch\arm64\boot\dts\rockchip\rk3568-evb.dtsi
 /*
  * There are 10 independent IO domains in RK3566/RK3568, including PMUIO[0:2] and VCCIO[1:7].
  * 1/ PMUIO0 and PMUIO1 are fixed-level power domains which cannot be configured;
  * 2/ PMUIO2 and VCCIO1,VCCIO[3:7] domains require that their hardware power supply voltages
  *    must be consistent with the software configuration correspondingly
  *    a/ When the hardware IO level is connected to 1.8V, the software voltage configuration
  *       should also be configured to 1.8V accordingly;
  *    b/ When the hardware IO level is connected to 3.3V, the software voltage configuration
  *       should also be configured to 3.3V accordingly;
  * 3/ VCCIO2 voltage control selection (0xFDC20140)
  *    BIT[0]: 0x0: from GPIO_0A7 (default)
  *    BIT[0]: 0x1: from GRF
  *    Default is determined by Pin FLASH_VOL_SEL/GPIO0_A7:
  *    L:VCCIO2 must supply 3.3V
  *    H:VCCIO2 must supply 1.8V
  */
&pmu_io_domains {
    status = "okay";
    pmuio1-supply = <&vcc3v3_pmu>;
    pmuio2-supply = <&vcc3v3_pmu>;
    vccio1-supply = <&vccio_acodec>;
    vccio3-supply = <&vccio_sd>;
    vccio4-supply = <&vcc_1v8>;
    vccio5-supply = <&vcc_3v3>;
    vccio6-supply = <&vcc_1v8>;
    vccio7-supply = <&vcc_3v3>;
};

&pwm4 {
    status = "okay";
};

【以下完全相同:就不上源码了!】
RK809各路输出电压配置 (rk3568-evb.dtsi) :

P:\AIO-3568J\rk3568_Android11.0_ToyBrick\kernel\arch\arm64\boot\dts\rockchip\rk3568-firefly-core.dtsi


3、【经过确认:可以不用修改。虽然Firefly的rbin的版本比ToyBrick的新!^_】


编译系统烧入固件验证
DTS里IO电源域和RK809都配置好后,编译固件,烧录到板子上验证烧录后,AIO-3568J板子会大概率崩溃重启,偶尔能进入Android系统桌面

用使比较软件对比了原厂的SDK包和firefly发布的SDK包,uboot和kernel部分没看出哪里有区别;然后对firefly固件和原厂SDK编译出来的固件开机log; 发现使用的DDR配置版本不同,firely使用的的版本比较新,所以尝试更新下DDR版本:路径: 
sdk/rkbin

比较目录后,果真是有区别;
解决办法: 把firefly的rkbin目录有差异的地方都拷贝过来;
重新编译固件: ./build.sh -UKAu
修改过后,AIO-3568J板子每次开机都能稳定的运行,没有出现崩溃和重启现象;老化了一段时间,系统正常;

Y:\rk3568_Android11.0_ToyBrick\rkbin\RKBOOT\RK3566MINIALL.ini
[CHIP_NAME]
NAME=RK3568
[VERSION]
MAJOR=1
MINOR=1
[CODE471_OPTION]
NUM=1
Path1=bin/rk35/rk3566_ddr_1056MHz_v1.08.bin
Sleep=1
[CODE472_OPTION]
NUM=1
Path1=bin/rk35/rk356x_usbplug_v1.09.bin
[LOADER_OPTION]
NUM=2
LOADER1=FlashData
LOADER2=FlashBoot
FlashData=bin/rk35/rk3566_ddr_1056MHz_v1.08.bin
FlashBoot=bin/rk35/rk356x_spl_v1.11.bin
[OUTPUT]
PATH=rk356x_spl_loader_v1.08.111.bin
[SYSTEM]
NEWIDB=true
[FLAG]
471_RC4_OFF=true
RC4_OFF=true


新版本:
[CHIP_NAME]
NAME=RK3568
[VERSION]
MAJOR=1
MINOR=1
[CODE471_OPTION]
NUM=1
Path1=bin/rk35/rk3566_ddr_1056MHz_v1.09.bin
Sleep=1
[CODE472_OPTION]
NUM=1
Path1=bin/rk35/rk356x_usbplug_v1.10.bin
[LOADER_OPTION]
NUM=2
LOADER1=FlashData
LOADER2=FlashBoot
FlashData=bin/rk35/rk3566_ddr_1056MHz_v1.09.bin
FlashBoot=bin/rk35/rk356x_spl_v1.11.bin
[OUTPUT]
PATH=rk356x_spl_loader_v1.09.111.bin
[SYSTEM]
NEWIDB=true
[FLAG]
471_RC4_OFF=true
RC4_OFF=true


4、替换uboot的三个文件,重新编译uboot。刷机就可以进去了!
Y:\rk3568_Android11.0_ToyBrick\u-boot\arch\arm\mach-rockchip\board.c

#include <asm/arch/param.h>
#ifdef CONFIG_DM_CHARGE_DISPLAY
#include <power/charge_display.h>
#endif
#ifdef CONFIG_DM_DVFS
#include <dvfs.h>
#endif
#ifdef CONFIG_ROCKCHIP_IO_DOMAIN
#include <io-domain.h>
#endif
#ifdef CONFIG_DM_REGULATOR
#include <power/regulator.h>
#endif
#ifdef CONFIG_DRM_ROCKCHIP
#include <video_rockchip.h>
#endif
#ifdef CONFIG_ROCKCHIP_DEBUGGER
#include <rockchip_debugger.h>
#endif
#include <of_live.h>
#include <dm/root.h>
#include <console.h>
#include <boot_rkimg.h>

#define BLK_OFFSET_31K    62
#define ABNORMAL_BOOT_COUNT    2
static long abnormal_boot_detect(void)
{
#ifdef CONFIG_ABNORMAL_BOOT_DETECT
    long ret;
    char *buf;
    struct blk_desc *dev_desc;
    char flag;
    dev_desc = rockchip_get_bootdev();
    lbaint_t start = BLK_OFFSET_31K;

    buf = (char *)memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
    if(!buf) {
        printf("%s: out of memory!\n", __func__);
        return -ENOMEM;
    }

    ret = blk_dread(dev_desc, start, 1, buf);
    if(ret < 0) {
        printf("%s: failed to get abnormal boot flag, ret=%lu\n",
                __func__, ret);
        return ret;
    }

    flag = buf[0];
    if(flag < ABNORMAL_BOOT_COUNT) {
        printf("Abnormal boot count: %d\n", flag);
        flag++;
        buf[0] = flag;
        ret = blk_dwrite(dev_desc, start, 1, buf); 
    } else {
        buf[0] = 0;
        ret = blk_dwrite(dev_desc, start, 1, buf); 
        printf("Enter bootrom download...");
        mdelay(100);
        writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
        do_reset(NULL, 0, 0, NULL);
        printf("failed!\n");
    }

    return ret;
#else
    return 0;
#endif
}

static void board_debug_init(void)
{
    if (!gd->serial.using_pre_serial &&
        !(gd->flags & GD_FLG_DISABLE_CONSOLE))
        debug_uart_init();

    if (tstc()) {
        gd->console_evt = getc();
        if (gd->console_evt <= 0x1a) /* 'z' */
            printf("Hotkey: ctrl+%c\n", gd->console_evt + 'a' - 1);
    }

    if (IS_ENABLED(CONFIG_CONSOLE_DISABLE_CLI))
        printf("Cmd interface: disabled\n");
}

#ifdef CONFIG_MTD_BLK
static void board_mtd_blk_map_partitions(void)
{
    struct blk_desc *dev_desc;

    dev_desc = rockchip_get_bootdev();
    if (dev_desc)
        mtd_blk_map_partitions(dev_desc);
}
#endif

int board_init(void)
{
    board_debug_init();
    abnormal_boot_detect();

#ifdef DEBUG
    soc_clk_dump();
#endif

Y:\rk3568_Android11.0_ToyBrick\u-boot\arch\arm\mach-rockchip\boot_mode.c

#include <asm/arch/toybrick.h>
#include <optee_include/OpteeClientInterface.h>
#include <u-boot/sha256.h>
 

static int load_SnMacAc_from_vendor(char *sn, char *mac, char *actcode)
{
    int ret;

    memset(sn, 0, TOYBRICK_SN_LEN + 1);
    memset(mac, 0, TOYBRICK_MAC_LEN + 1);
    memset(actcode, 0, TOYBRICK_ACTCODE_LEN + 1);

    ret = toybrick_get_sn(sn);
    if (ret <= 0) {
        printf("Load sn form vendor failed\n");
        return -EIO;
    }

    ret = toybrick_get_mac(mac);
    if (ret != TOYBRICK_MAC_LEN) {
        printf("Load mac form vendor failed\n");
        return -EIO;
    }

    ret = toybrick_get_actcode(actcode);
    if (ret != TOYBRICK_ACTCODE_LEN) {
        printf("Load actcode form vendor failed\n");
        return -EIO;
    }

    printf("Load SnMacAc from vendor: sn %s, mac %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
            sn, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    return 0;
}

static int save_SnMacAc_to_vendor(char *sn, char *mac, char *actcode)
{
    int ret;

    ret = toybrick_set_sn(sn);
    if (ret <= 0) {
        printf("Save sn to vendor failed\n");
        return -EIO;
    }

    ret = toybrick_set_mac(mac);
    if (ret != TOYBRICK_MAC_LEN) {
        printf("Save mac to vendor failed\n");
        return -EIO;
    }

    ret = toybrick_set_actcode(actcode);
    if (ret != TOYBRICK_ACTCODE_LEN) {
        printf("Save actcode to vendor failed\n");
        return -EIO;
    }

    return 0;
}

static int load_SnMacAc_from_rpmb(char *sn, char *mac, char *actcode)
{
    int ret;
    sha256_context ctx;
    uint8_t digest[SHA256_SUM_LEN + 1] = {0};
    uint8_t hash_pre[SHA256_SUM_LEN + 1] = {0};
    uint8_t data_sha256[TOYBRICK_SHA_LEN + 1]={0};

    memset(sn, 0, TOYBRICK_SN_LEN + 1);
    memset(mac, 0, TOYBRICK_MAC_LEN + 1);
    memset(actcode, 0, TOYBRICK_ACTCODE_LEN + 1);
    ret = trusty_read_toybrick_SnMacAc(data_sha256, TOYBRICK_SHA_LEN);
    if (ret != 0) {
        printf("Load SnMacAc from rpmb failed\n");
        return -EIO;
    }
    memcpy(hash_pre, data_sha256, SHA256_SUM_LEN);
    sha256_starts(&ctx);
    sha256_update(&ctx,(const uint8_t *)(data_sha256 + SHA256_SUM_LEN), TOYBRICK_DATA_LEN);
    sha256_finish(&ctx, digest);
    if (memcmp(digest, hash_pre, SHA256_SUM_LEN) != 0) {
        printf("SnMacAc from rpmb is invalid\n");
        return -EINVAL;
    }
    memcpy(sn, data_sha256 + SHA256_SUM_LEN, TOYBRICK_SN_LEN);
    memcpy(mac, data_sha256 + SHA256_SUM_LEN + TOYBRICK_SN_LEN, TOYBRICK_MAC_LEN);
    memcpy(actcode, data_sha256 + SHA256_SUM_LEN + TOYBRICK_SN_LEN + TOYBRICK_MAC_LEN, TOYBRICK_ACTCODE_LEN);

    if (strlen(sn) == 0) {
        printf("SnMacAc from rpmb is empty\n");
        return -EINVAL;
    }

    printf("Load SnMacAc from rpmb: sn %s, mac %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
            sn, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    return 0;
}

static int save_SnMacAc_to_rpmb(char *sn, char *mac, char *actcode)
{
    int ret;
    sha256_context ctx;
    uint8_t digest[SHA256_SUM_LEN + 1] = {0};
    uint8_t data[TOYBRICK_DATA_LEN + 1]={0};
    uint8_t data_sha256[TOYBRICK_SHA_LEN + 1]={0};

    memset(&data, 0, sizeof(data));
    memset(&data_sha256, 0, sizeof(data_sha256));
    memcpy(data, sn, TOYBRICK_SN_LEN);
    memcpy(data + TOYBRICK_SN_LEN, mac, TOYBRICK_MAC_LEN);
    memcpy(data + TOYBRICK_SN_LEN + TOYBRICK_MAC_LEN, actcode, TOYBRICK_ACTCODE_LEN);

    sha256_starts(&ctx);
    sha256_update(&ctx,(const uint8_t *)data, TOYBRICK_DATA_LEN);
    sha256_finish(&ctx, digest);
    memcpy(data_sha256, digest, SHA256_SUM_LEN);
    memcpy(data_sha256 + SHA256_SUM_LEN, data, TOYBRICK_DATA_LEN);
    
    ret = trusty_write_toybrick_SnMacAc(data_sha256, TOYBRICK_SHA_LEN);
    if (ret != 0) {
        printf("Save SnMacAc to rpmb failed\n");
        return -EIO;
    }

    return 0;
}

static int toybrick_check_SnMacAc(void)
{
    int ret = 0;
    int ret_vendor, ret_rpmb;
    char vendor_sn[TOYBRICK_SN_LEN + 1];
    char vendor_mac[TOYBRICK_MAC_LEN + 1];
    char vendor_actcode[TOYBRICK_ACTCODE_LEN + 1];
    char rpmb_sn[TOYBRICK_SN_LEN + 1];
    char rpmb_mac[TOYBRICK_MAC_LEN + 1];
    char rpmb_actcode[TOYBRICK_ACTCODE_LEN + 1];

    ret_vendor = load_SnMacAc_from_vendor(vendor_sn, vendor_mac, vendor_actcode);
    ret_rpmb = load_SnMacAc_from_rpmb(rpmb_sn, rpmb_mac, rpmb_actcode);

    if (ret_vendor < 0 && ret_rpmb < 0) {
        printf("No SnMacAc found in vendor and rpmb, goto loader ...\n");
        run_command_list("rockusb 0 ${devtype} ${devnum}", -1, 0);
        //set_back_to_bootrom_dnl_flag();
        do_reset(NULL, 0, 0, NULL);
    } else if (ret_vendor < 0) {
        printf("No SnMacAc found in vendor, load from rpmb and save to vendor\n");
        ret = save_SnMacAc_to_vendor(rpmb_sn, rpmb_mac, rpmb_actcode);
        do_reset(NULL, 0, 0, NULL);
    } else if (ret_rpmb < 0) {
        printf("No SnMacAc found in rpmb, load from vendor and save to rpmb\n");
        ret = save_SnMacAc_to_rpmb(vendor_sn, vendor_mac, vendor_actcode);
    } else if (memcmp(vendor_sn, rpmb_sn, TOYBRICK_SN_LEN) != 0){
        printf("Warn: SN(%s %s) form vendor and rpmb is different!\n",
                vendor_sn, rpmb_sn);
        ret = save_SnMacAc_to_vendor(rpmb_sn, rpmb_mac, rpmb_actcode);
        do_reset(NULL, 0, 0, NULL);
    } else if (memcmp(vendor_mac, rpmb_mac, TOYBRICK_MAC_LEN) != 0){
        printf("Warn: MAC form vendor and rpmb is different!\n");
        ret = save_SnMacAc_to_vendor(rpmb_sn, rpmb_mac, rpmb_actcode);
        do_reset(NULL, 0, 0, NULL);
    } else if (memcmp(vendor_actcode, rpmb_actcode, TOYBRICK_ACTCODE_LEN) != 0){
        printf("Warn: Actcode form vendor and rpmb is different!\n");
        ret = save_SnMacAc_to_vendor(rpmb_sn, rpmb_mac, rpmb_actcode);
        do_reset(NULL, 0, 0, NULL);
    } else {
        printf("Toybrick check SnMacAc OK, sn %s\n", vendor_sn);
        ret = 0;
    }

    return ret;
}

int setup_boot_mode(void)
{
    char env_preboot[256] = {0};
#ifndef CONFIG_ROCKCHIP_RK3288
    toybrick_check_SnMacAc();
#endif
    switch (rockchip_get_boot_mode()) {
    case BOOT_MODE_BOOTLOADER:
        printf("enter fastboot!\n");
#if defined(CONFIG_FASTBOOT_FLASH_MMC_DEV)
        snprintf(env_preboot, 256,
                "setenv preboot; mmc dev %x; fastboot usb 0; ",
                CONFIG_FASTBOOT_FLASH_MMC_DEV);
#elif defined(CONFIG_FASTBOOT_FLASH_NAND_DEV)
        snprintf(env_preboot, 256,
                "setenv preboot; fastboot usb 0; ");
#endif

Y:\rk3568_Android11.0_ToyBrick\u-boot\arch\arm\mach-rockchip\boot_rkimg.c

#include <asm/arch/uimage.h>
#include <asm/arch/toybrick.h>
#include <dm/ofnode.h>

#define KEY_DOWN_MIN_VAL    0
#define KEY_DOWN_MAX_VAL    30

__weak int rockchip_dnl_key_pressed(void)
{
#if defined(CONFIG_DM_KEY)
#ifdef CONFIG_CMD_ROCKUSB
    return key_is_pressed(key_read(KEY_VOLUMEUP));
#else
    return key_is_pressed(key_read(KEY_MENU));
#endif

#elif defined(CONFIG_ADC)
    const void *blob = gd->fdt_blob;
    int node, ret, channel = 1;
    u32 val, chns[2];

    node = fdt_node_offset_by_compatible(blob, 0, "adc-keys");
    if (node >= 0) {
        if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2))
            channel = chns[1];
    }

    ret = adc_channel_single_shot("saradc", channel, &val);
    if (ret) {
        printf("%s: Failed to read saradc, ret=%d\n", __func__, ret);
        return 0;
    }

    return ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL));
#endif

    return 0;
}


#if defined(CONFIG_ROCKCHIP_EARLY_DISTRO_DTB)
static int rockchip_read_distro_dtb(void *fdt_addr)
{
    const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
    char *devnum, *devtype, *devplist;
    char devnum_part[12];
    char fdt_hex_str[19];
    char *fs_argv[5];
    char flag[TOYBRICK_FLAG_LEN + 1];
    char dtb_path[128];
    int index = -1;
    //int size;
    //int ret;

    if (!rockchip_get_bootdev() || !fdt_addr)
        return -ENODEV;

    if (run_command_list(cmd, -1, 0)) {
        printf("Failed to find -bootable\n");
        return -EINVAL;
    }

    devplist = env_get("devplist");
    if (!devplist)
        return -ENODEV;

    devtype = env_get("devtype");
    devnum = env_get("devnum");
    sprintf(devnum_part, "%s:%s", devnum, devplist);
    sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);

    fs_argv[0] = "load";
    fs_argv[1] = devtype,
    fs_argv[2] = devnum_part;
    fs_argv[3] = fdt_hex_str;

    if(toybrick_get_flag(flag, &index) < 0)
        strcpy(dtb_path, CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
    else
        sprintf(dtb_path, "%s.%s", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH, flag);
    fs_argv[4] = dtb_path;

    if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
        return -EIO;

    if (fdt_check_header(fdt_addr))
        return -EBADF;

    printf("DTB(Distro): %s\n", dtb_path);

    return 0;
}
#endif


参考资料:
https://blog.csdn.net/soar999999/article/details/120102401
[RK3568 Android11] 教程之原厂SDK源码适配AIO-3568J板子跑起来

https://t.rock-chips.com/wiki.php
ToyBrick
前言
本站旨在高效地知识分享--所见即所得。
让Toybrick板用户能够快速上手,利用Toybrick系列开发板快速开发、评估以及产品化。

https://t.rock-chips.com/wiki.php?filename=%E6%9D%BF%E7%BA%A7%E6%8C%87%E5%8D%97/TB-RK3568X
TB-RK3568X

https://t.rock-chips.com/wiki.php?filename=%E8%B5%84%E6%96%99%E4%B8%8B%E8%BD%BD/%E8%B5%84%E6%96%99%E4%B8%8B%E8%BD%BD
Android源码下载
Android源码下载地址
https://eyun.baidu.com-s/3c2U4Y7A#sharelink/path=%2F

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/183064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux安装mongodb企业版集群(分片集群)

目录 一、mongodb分片集群三种角色 二、安装 1、准备工作 2、安装 configsvr配置 router配置 shard配置 三、测试 四、整合Springboot 一、mongodb分片集群三种角色 router角色&#xff1a; mongodb的路由&#xff0c;提供入口&#xff0c;使得分片集群对外透明&…

【目标检测论文解读复现NO.27】基于改进YOLOv5的螺纹钢表面缺陷检测

前言此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0c;…

【工程化之路】Node require 正解

require 实现原理 流程概述 步骤1&#xff1a;尝试执行代码require("./1"). 开始调用方法require.步骤2&#xff1a;此时会得到filename&#xff0c;根据filename 会判断缓存中是否已经加载模块&#xff0c;如果加载完毕直接返回&#xff0c;反之继续执行步骤3&…

python图像处理(laplacian算子)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 和之前的prewitt算子、sobel算子不同,laplacian算子更适合检测一些孤立点、短线段的边缘。因此,它对噪声比较敏感,输入的图像一定要做好噪声的处理工作。同时,laplacian算子设计…

Leetcode 03. 无重复字符的最长子串 [C语言]

目录题目思路1代码1结果1思路2代码2结果2该文章只是用于记录考研复试刷题题目 Leetcode 03: 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所…

尚医通-OAuth2-微信登录接口开发(三十一)

目录&#xff1a; &#xff08;1&#xff09;微信登录-OAuth2介绍 &#xff08;2&#xff09;前台用户系统-微信登录-准备工作 &#xff08;3&#xff09;微信登录-生成微信二维码-接口开发 &#xff08;4&#xff09;微信登录-生成验证码-前端整合 &#xff08;5&#xf…

Telerik DevCraft Ultimate R1 2023

Telerik DevCraft Ultimate R1 2023 Kendo UI R1 2023-添加新的Chip和ChipList组件。 KendoReact R1 2023&#xff08;v5.11.0&#xff09;-新的PDFViewer组件允许用户直接在应用程序中查看PDF文档。 Telerik JustLock R1 2023-Visual Studio快速操作菜单现在可以在创建通用…

蓝桥杯重点(C/C++)(随时更新,更新时间:2023.1.29)

点关注不迷路&#xff0c;欢迎推荐给更多人 目录 1 技巧 1.1 取消同步&#xff08;节约时间&#xff0c;甚至能多骗点分&#xff0c;最好每个程序都写上&#xff09; 1.2 万能库&#xff08;可能会耽误编译时间&#xff0c;但是省脑子&#xff09; 1.3 蓝桥杯return 0…

【数据库-通用知识系列-01】数据库规范化设计之范式,让数据库表看起来更专业

我们在设计数据库时考虑的因素包括读取性能&#xff0c;数据一致性&#xff0c;数据冗余度&#xff0c;可扩展性等&#xff0c;好好学习数据库规范化的知识&#xff0c;设计的数据库表看起来才专业。 范式一览 “键”理解&#xff1a; 超键&#xff1a;在关系中能唯一标识元组…

送什么礼物给小学生比较有纪念意义?适合送小学生的小礼物

送给小学生的礼物哪种比较有意义呢&#xff1f;送给学生的礼物&#xff0c;基本上是对学习有所帮助的&#xff0c;但是像送钢笔、练习册这些&#xff0c;有一部分学生是抗拒的&#xff0c;作为大人就是希望对视力、对成长有用的东西&#xff0c;我认为保护视力是现在许多家庭的…

isNotEmpty() 和 isNotBlank() 的区别,字符串判空, StringUtils工具包 StringUtil工具类,isEmpty() 和 isBlank() 的区别

目录1.StringUtils 和 StringUtilStringUtils 的依赖&#xff1a;StringUtils 的用法&#xff1a;StringUtil 工具类2. isNotEmpty() 和 isNotBlank()1.StringUtils 和 StringUtil 注&#xff1a;StringUtils 和 StringUtil 的区别&#xff08;StringUtil为自定义工具类&#…

以表达式作为template参数

目录 一.template参数的分类&#xff1a; 二.非类型参数与默认参数值一起使用 三.应用 一.template参数的分类&#xff1a; ①.某种类型&#xff1a; template<typename T>; ②.表达式(非类型)&#xff1a; template<int length,int position>; 其中length…

Liunx中shell命令行和权限的理解

文章目录前言1.shell外壳的理解2.关于权限理解1.Linux下的用户2.角色划分3.文件和目录的权限3.粘滞位3.总结前言 Linux中的操作都是通过在命令行上敲指令来实现的&#xff0c;本文将简单的介绍Linux中的外壳程序shell以及浅谈一下对Linux中的权限理解。 1.shell外壳的理解 Lin…

微信小程序开发(一)

1. 微信小程序的开发流程 2. 注册小程序 小程序注册页&#xff1a;https://mp.weixin.qq.com/wxopen/waregister?actionstep1 如已注册&#xff0c;直接登录 小程序后台 https://mp.weixin.qq.com/ 即可。 在小程序后台的 【开发管理】→ 【开发设置】下可以查看AppID&…

算法训练营DAY45|322. 零钱兑换、279.完全平方数

两道题思路上有相似之处&#xff0c;都是求得最少的种类方法&#xff0c;也就是说在完全背包里给定容量时&#xff0c;用最少的物品去装满背包。它和用最多的方法去装满背包也有一些相似&#xff0c;也就是说两者实际上是互通的。 322. 零钱兑换 - 力扣&#xff08;LeetCode&a…

HTML零散知识

1、代码规范与思路 参考凹凸实验室代码规范&#xff1a;Aotu.io - 前端代码规范 CSS编写顺序的思路 先确定盒子本身是如何布局 position: absolutefloat: left/rightdisplay: flex 盒子的特性和可见性 display: block/inline-block/inline/nonevisibility/opacity 盒子模型…

【Pytorch项目实战】之生成式模型:DeepDream、风格迁移、图像修复

文章目录生成式模型&#xff08;算法一&#xff09;深度梦境&#xff08;DeepDream&#xff09;&#xff08;算法二&#xff09;风格迁移&#xff08;Style Transfer&#xff09;&#xff08;算法三&#xff09;图像修复&#xff08;Image Inpainting&#xff09;&#xff08;一…

(13)工业界推荐系统-小红书推荐场景及内部实践【用户行为序列建模】

&#xff08;1&#xff09;工业界推荐系统-小红书推荐场景及内部实践【业务指标、链路、ItemCF】 &#xff08;2&#xff09;工业界推荐系统-小红书推荐场景及内部实践【UserCF、离线特征处理】 &#xff08;3&#xff09;工业界推荐系统-小红书推荐场景及内部实践【矩阵补充、…

Docker搭建LNMP+Wordpress

一、服务器环境 容器操作系统IP地址主要软件nginxCentOS 7172.18.0.10Docker-NginxmysqlCentOS 7172.18.0.20Docker-MysqlmysqlCentOS 7172.18.0.20Docker-Mysql 二、Linux系统基础镜像 systemctl stop firewalld setenforce 0 docker pull centos:7 #从公有仓库中下载cento…

cubeIDE开发, stm32人工智能开发应用实践(Cube.AI).篇三

一、cube.AI实际项目应用 接篇二&#xff0c;前文都是采用FP-AI-SENSING1案例和配套的B-L475E-IOT01A开发板来阐述的&#xff0c;而实际项目中&#xff0c;我们都是基于自身项目硬件平台来训练模型及部署模型的&#xff0c;我们仅仅需要cube.AI软件包&#xff08;作为可调用库&…