浅浅

浅浅

0个粉丝

9

问答

0

专栏

0

资料

浅浅  发布于  2019-07-22 16:20:17
采纳率 0%
9个问答
1817

auto_update.c

 
海思的例子是使用spi nor flash ,怎么样改成spi nand flash啊,板子是3531d做U盘升级。谢谢大佬们了,比较需要思路,从哪离开始改。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#ifdef CONFIG_AUTO_UPDATE  /* cover the whole file 覆盖整个文件*/

#ifdef CONFIG_AUTO_SD_UPDATE
#ifndef CONFIG_MMC
#error "should have defined CONFIG_MMC"
#endif
#include
#include "mmc_init.c"
#endif

#if defined CONFIG_AUTO_USB_UPDATE
#if !defined CONFIG_USB_OHCI && !defined CONFIG_USB_XHCI
#error "should have defined CONFIG_USB_OHCI or CONFIG_USB_XHCI"
#endif
#ifndef CONFIG_USB_STORAGE
#error "should have defined CONFIG_USB_STORAGE"
#endif
#include
#include "usb_init.c"
#endif

#undef AU_DEBUG
#undef debug
#ifdef        AU_DEBUG
#define debug(fmt, args...)        printf(fmt, ##args)
#else
#define debug(fmt, args...)
#endif        /* AU_DEBUG */

/* possible names of files on the medium.介质上文件的可能名称 */
#define AU_FIRMWARE        "u-boot"
#define AU_KERNEL        "kernel"
#define AU_ROOTFS        "rootfs"

struct flash_layout {
        long start;
        long end;
};
static struct spi_flash *flash;

struct medium_interface {
        char name[20];
        int (*init) (void);
        void (*exit) (void);
};

#define MAX_UPDATE_INTF        3
static struct medium_interface s_intf[MAX_UPDATE_INTF] = {
#ifdef CONFIG_AUTO_SD_UPDATE
        {.name = "mmc",        .init = mmc_stor_init,        .exit = mmc_stor_exit,},
#endif
#ifdef CONFIG_AUTO_USB_UPDATE
        {.name = "usb",        .init = usb_stor_init,        .exit = usb_stor_exit,},
#endif
};

/* layout of the FLASH. ST = start address, ND = end address. FLASH的布局。ST =开始地址,ND =结束地址。*/
#define AU_FL_FIRMWARE_ST        0x0
#define AU_FL_FIRMWARE_ND        0x7FFFF
#define AU_FL_KERNEL_ST                0x100000
#define AU_FL_KERNEL_ND                0x5FFFFF
#define AU_FL_ROOTFS_ST                0x600000
#define AU_FL_ROOTFS_ND                0xbFFFFF

static int au_stor_curr_dev; /* current device目前的设备*/

/* index of each file in the following arrays 以下数组中每个文件的索引 */
#define IDX_FIRMWARE        0
#define IDX_KERNEL        1
#define IDX_ROOTFS        2

/* max. number of files which could interest us 我们感兴趣的文件数量 */
#define AU_MAXFILES 3

/* pointers to file names 指向文件名的指针 */
char *aufile[AU_MAXFILES] = {
        AU_FIRMWARE,
        AU_KERNEL,
        AU_ROOTFS
};

/* sizes of flash areas for each file 每个文件的flash区域大小*/
long ausize[AU_MAXFILES] = {
        (AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST,
        (AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST,
        (AU_FL_ROOTFS_ND + 1) - AU_FL_ROOTFS_ST,
};

/* array of flash areas start and end addresses flash区域开始和结束地址的数组*/
struct flash_layout aufl_layout[AU_MAXFILES] = {
        { AU_FL_FIRMWARE_ST,        AU_FL_FIRMWARE_ND, },
        { AU_FL_KERNEL_ST,        AU_FL_KERNEL_ND,   },
        { AU_FL_ROOTFS_ST,        AU_FL_ROOTFS_ND,   },
};

/* where to load files into memory 哪里加载文件到内存*/
#if defined(CONFIG_HI3536) || defined(CONFIG_HI3531A) || defined(CONFIG_HI3531D)
#define LOAD_ADDR ((unsigned char *)0x42000000)
#else
#define LOAD_ADDR ((unsigned char *)0x82000000)
#endif
/* the app is the largest image应用程序是最大的图像 */
#define MAX_LOADSZ ausize[IDX_ROOTFS]

/*获取当前文件的总大小,把它与 image_header 中记录的总大小比较,如果不匹配
则返回错误,并中止升级*/
static int au_check_cksum_valid(int idx, long nbytes)
{
        image_header_t *hdr;
        unsigned long checksum;

        hdr = (image_header_t *)LOAD_ADDR;

        if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
                printf("Image %s bad total SIZE\n", aufile[idx]);
                return -1;
        }
        /* check the data CRC 检查数据CRC*/
        checksum = ntohl(hdr->ih_dcrc);

        if (crc32(0, (unsigned char const *)(LOAD_ADDR + sizeof(*hdr)),
                        ntohl(hdr->ih_size)) != checksum) {
                printf("Image %s bad data checksum\n", aufile[idx]);
                return -1;
        }

        return 0;
}

/*这个函数的主要功能就是校验镜像文件的 image_header 信息,如果校验不通过
则不会进行升级。
− 如果校验通过,这个函数还有一个重要的功能就是对比 ih_time 这个时间戳信
息,用它来判断镜像文件的版本。如果镜像文件的生成时间小于已记录的时间
之前,那么该镜像就不会被 down 到 flash 上。当满足信息的镜像更新到 flash
上之后就会在 boot 的环境变量中保存当前镜像的时间戳信息用于下一次比较。*/
static int au_check_header_valid(int idx, long nbytes)
{
        image_header_t *hdr;
        unsigned long checksum;

        char env[20] = {0};
        char auversion[20] = {0};

        hdr = (image_header_t *)LOAD_ADDR;
        /* check the easy ones first 先检查一下*/
#if 0
        #define CHECK_VALID_DEBUG
#else
        #undef CHECK_VALID_DEBUG
#endif

#ifdef CHECK_VALID_DEBUG
        printf("\nmagic %#x %#x\n", ntohl(hdr->ih_magic), IH_MAGIC);
        printf("arch %#x %#x\n", hdr->ih_arch, IH_ARCH_ARM);
        printf("size %#x %#lx\n", ntohl(hdr->ih_size), nbytes);
        printf("type %#x %#x\n", hdr->ih_type, IH_TYPE_KERNEL);
#endif
        if (nbytes < sizeof(*hdr)) {
                printf("Image %s bad header SIZE\n", aufile[idx]);
                return -1;
        }
        if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_ARCH_ARM) {
                printf("Image %s bad MAGIC or ARCH\n", aufile[idx]);
                return -1;
        }
        /* check the hdr CRC 检查hdr CRC*/
        checksum = ntohl(hdr->ih_hcrc);
        hdr->ih_hcrc = 0;

        if (crc32(0, (unsigned char const *)hdr, sizeof(*hdr)) != checksum) {
                printf("Image %s bad header checksum\n", aufile[idx]);
                return -1;
        }
        hdr->ih_hcrc = htonl(checksum);
        /* check the type - could do this all in one gigantic if() 检查类型-可以在一个巨大的if()中完成所有这些*/
        if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
                printf("Image %s wrong type\n", aufile[idx]);
                return -1;
        }
        if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) {
                printf("Image %s wrong type\n", aufile[idx]);
                return -1;
        }
        if ((idx == IDX_ROOTFS) &&
                        (hdr->ih_type != IH_TYPE_RAMDISK) &&
                        (hdr->ih_type != IH_TYPE_FILESYSTEM)) {
                printf("Image %s wrong type\n", aufile[idx]);
                ausize[idx] = 0;
                return -1;
        }

        /* recycle checksum 循环校验和*/
        checksum = ntohl(hdr->ih_size);
        /* for kernel and app the image header must also fit into flash 对于内核和应用程序,图像头部也必须适应flash*/
        if ((idx == IDX_KERNEL) || (hdr->ih_type == IH_TYPE_RAMDISK))
                checksum += sizeof(*hdr);

        /* check the size does not exceed space in flash. HUSH scripts 检查大小不超过flash中的空间。嘘的脚本*/
        /* all have ausize[] set to 0 都将ausize[]设置为0*/
        if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
                printf("Image %s is bigger than FLASH\n", aufile[idx]);
                return -1;
        }

        sprintf(env, "%lx", (unsigned long)ntohl(hdr->ih_time));
        setenv(auversion, env);

        return 0;
}
//时间进度通知
static void schedule_notify(unsigned long offset, unsigned long len,
                unsigned long off_start)
{
        int percent_complete = -1;

        do {
                unsigned long long n = (unsigned long long)
                        (offset - off_start) * 100;
                int percent;

                do_div(n, len);
                percent = (int)n;

                /* output progress message only at whole percent
                 * steps to reduce the number of messages
                 * printed on (slow) serial consoles
                 仅以整个百分比的步骤输出进度消息,以减少(缓慢的)串行控制台上打印的消息数量*/
                if (percent != percent_complete) {
                        percent_complete = percent;

                        printf("\rOperation at 0x%lx -- %3d%% complete.",
                                        offset, percent);
                }
        } while (0);
}
//spi_flash擦除函数
static int spi_flash_erase_op(struct spi_flash *flash, unsigned long offset,
                unsigned long len)
{
        int ret;
        struct mtd_info_ex *spiflash_info = get_spiflash_info();
        unsigned long erase_start, erase_len, erase_step;

        erase_start = offset;
        erase_len   = len;
        erase_step  = spiflash_info->erasesize;

        while (len > 0) {
                if (len < erase_step)
                        erase_step = len;

                ret = flash->erase(flash, (u32)offset, erase_step);
                if (ret)
                        return 1;

                len -= erase_step;
                offset += erase_step;
                /* notify real time schedule 实时通知时间表*/
                schedule_notify(offset, erase_len, erase_start);
        }
        return ret;
}
//spi_flash写入函数
static int spi_flash_write_op(struct spi_flash *flash, unsigned long offset,
                unsigned long len, void *buf)
{
        int ret = 0;
        unsigned long write_start, write_len, write_step;
        char *pbuf = buf;
        struct mtd_info_ex *spiflash_info = get_spiflash_info();

        write_start = offset;
        write_len   = len;
        write_step  = spiflash_info->erasesize;

        while (len > 0) {
                if (len < write_step)
                        write_step = len;

                ret = flash->write(flash, offset, write_step, pbuf);
                if (ret)
                        break;

                offset += write_step;
                pbuf   += write_step;
                len    -= write_step;
                /* notify real time schedule 实时通知时间表*/
                schedule_notify(offset, write_len, write_start);
        }

        return ret;
}

/*这个函数的主要功能就是写 flash,当所有的校验通过之后,就会通过这个函数
把镜像写到 flash 上。 */
static int au_do_update(int idx, long sz)
{
        image_header_t *hdr;
        unsigned long start, len;
        unsigned long write_len;
        int rc;
        void *buf;
        char *pbuf;

        hdr = (image_header_t *)LOAD_ADDR;

        start = aufl_layout[idx].start;
        len = aufl_layout[idx].end - aufl_layout[idx].start + 1;

        /*
         * erase the address range.
         删除地址范围*/
        printf("flash erase...\n");
        rc = spi_flash_erase_op(flash, start, len);
        if (rc) {
                printf("SPI flash sector erase failed\n");
                return 1;
        }

        buf = map_physmem((unsigned long)LOAD_ADDR, len, MAP_WRBACK);
        if (!buf) {
                puts("Failed to map physical memory\n");
                return 1;
        }

        /* strip the header - except for the kernel and ramdisk 除去内核和ramdisk之外的头 */
        if (hdr->ih_type == IH_TYPE_KERNEL || hdr->ih_type == IH_TYPE_RAMDISK) {
                pbuf = buf;
                write_len = sizeof(*hdr) + ntohl(hdr->ih_size);
        } else {
                pbuf = (buf + sizeof(*hdr));
                write_len = ntohl(hdr->ih_size);
        }

        /* copy the data from RAM to FLASH 将数据从RAM复制到FLASH*/
        printf("\nflash write...\n");
        rc = spi_flash_write_op(flash, start, write_len, pbuf);
        if (rc) {
                printf("SPI flash write failed, return %d\n", rc);
                return 1;
        }

        /* check the dcrc of the copy 检查副本的dcrc*/
        if (crc32(0, (unsigned char const *)(buf + sizeof(*hdr)),
                ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) {
                printf("Image %s Bad Data Checksum After COPY\n", aufile[idx]);
                return -1;
        }

        unmap_physmem(buf, len);

        return 0;
}
//得到更新的环境变量
static void get_update_env(char *img_start, char *img_end)
{
        long start = -1, end = 0;
        char *env;

        /*
         * check whether start and end are defined in environment
         * variables.
        检查start和end是否在环境变量中定义。 */
        env = getenv(img_start);
        if (env != NULL)
                start = simple_strtoul(env, NULL, 16);

        env = getenv(img_end);
        if (env != NULL)
                end = simple_strtoul(env, NULL, 16);

        if (start >= 0 && end && end > start) {
                ausize[IDX_FIRMWARE] = (end + 1) - start;
                aufl_layout[0].start = start;
                aufl_layout[0].end = end;
        }
}

/*
* If none of the update file(u-boot, kernel or rootfs) was found
* in the medium, return -1;
* If u-boot has been updated, return 1;
* Others, return 0;
如果没有找到任何更新文件(u-boot、内核或rootfs)
*在介质中,返回-1;
*如果u-boot已更新,返回1;
*其他,返回0;
*/
static int update_to_flash(void)
{
        int i = 0;
        long sz;
        int res, cnt;
        int uboot_updated = 0;
        int image_found = 0;

        /* just loop thru all the possible files 循环遍历所有可能的文件*/
        for (i = 0; i < AU_MAXFILES; i++) {
                /* just read the header 读一下标题*/
                sz = file_fat_read(aufile, LOAD_ADDR,
                        sizeof(image_header_t));
                debug("read %s sz %ld hdr %d\n",
                        aufile, sz, sizeof(image_header_t));
                if (sz <= 0 || sz < sizeof(image_header_t)) {
                        debug("%s not found\n", aufile);
                        continue;
                }

                image_found = 1;
         //au_check_header_valid()返回值小于0效验头不通过不升级
                if (au_check_header_valid(i, sz) < 0) {
                        debug("%s header not valid\n", aufile);
                        continue;
                }

                sz = file_fat_read(aufile, LOAD_ADDR, MAX_LOADSZ);
                debug("read %s sz %ld hdr %d\n",
                        aufile, sz, sizeof(image_header_t));
                if (sz <= 0 || sz <= sizeof(image_header_t)) {
                        debug("%s not found\n", aufile);
                        continue;
                }
         //au_check_cksum_valid返回值小于0效验和不通过不升级
                if (au_check_cksum_valid(i, sz) < 0) {
                        debug("%s checksum not valid\n", aufile);
                        continue;
                }

                /* If u-boot had been updated, we need to
                 * save current env to flash 如果u-boot已经更新,我们需要将当前环境保存为flash*/
                if (0 == strcmp((char *)AU_FIRMWARE, aufile))
                        uboot_updated = 1;

                /* this is really not a good idea, but it's what the */
                /* customer wants. 这确实不是一个好主意,但这是客户想要的。*/
                cnt = 0;
                do {
                        res = au_do_update(i, sz);//写 flash
                        /* let the user break out of the loop让用户跳出循环 */
                        if (ctrlc() || had_ctrlc()) {
                                clear_ctrlc();

                                break;
                        }
                        cnt++;
#ifdef AU_TEST_ONLY
                } while (res < 0 && cnt < 3);
                if (cnt < 3)
#else
                } while (res < 0);
#endif
        }

        if (1 == uboot_updated)
                return 1;
        if (1 == image_found)
                return 0;

        return -1;
}

/*
* This is called by board_init() after the hardware has been set up
* and is usable. Only if SPI flash initialization failed will this function
* return -1, otherwise it will return 0;
*在硬件设置好并可用之后,board_init()调用这个函数。只有SPI flash初始化失败时,该函数才返回-1,否则返回0;
*提供给外部的函数接口,是 auto update 的主函数。*/
int do_auto_update(void)
{
        block_dev_desc_t *stor_dev;
        int old_ctrlc;
        int j;
        int state = -1;
        int dev;

        au_stor_curr_dev = -1;
        for (j = 0; j < MAX_UPDATE_INTF; j++) {
                if (0 != (unsigned int)s_intf[j].name[0]) {
                        au_stor_curr_dev = s_intf[j].init();
                        if (-1 == au_stor_curr_dev) {
                                debug("No %s storage device found!\n",
                                                s_intf[j].name);
                                continue;
                        }

                        dev = 0;

#if (defined CONFIG_HI3516CV300 || defined CONFIG_ARCH_HI3519 || \
                defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3516AV200)
                        if (strncmp("mmc", s_intf[j].name, sizeof("mmc")) == 0)
                                dev = 2;
#endif
                        debug("device name %s!\n", s_intf[j].name);
                        stor_dev = get_dev(s_intf[j].name, dev);
                        if (NULL == stor_dev) {
                                debug("Unknow device type!\n");
                                continue;
                        }

                        if (fat_register_device(stor_dev, 1) != 0) {
                                debug("Unable to use %s %d:%d for fatls\n",
                                                s_intf[j].name,
                                                au_stor_curr_dev,
                                                1);
                                continue;
                        }

                        if (file_fat_detectfs() != 0) {
                                debug("file_fat_detectfs failed\n");
                                continue;
                        }

                        /*
                         * Get image layout from environment.
                         * If the start address and the end address
                         * were not definedin environment virables,
                         * use the default value
                         从环境中获取图像布局。如果环境virables中没有定义开始地址和结束地址,请使用默认值
                         */
                        get_update_env("firmware_st", "firmware_nd");
                        get_update_env("kernel_st", "kernel_nd");
                        get_update_env("rootfs_st", "rootfs_nd");

                        /*
                         * make sure that we see CTRL-C
                         * and save the old state
                         确保我们看到CTRL-C并保存旧状态
                         */
                        old_ctrlc = disable_ctrlc(0);

                        /*
                         * CONFIG_SF_DEFAULT_SPEED=1000000,
                         * CONFIG_SF_DEFAULT_MODE=0x3
                         */
                        flash = spi_flash_probe(0, 0, 1000000, 0x3);
                        if (!flash) {
                                printf("Failed to initialize SPI flash\n");
                                return -1;
                        }

                        state = update_to_flash();//功能更新flash;函数里面调用au_do_update();功能写flash
                        //调用au_check_header_valid()校验函数

                        /* restore the old state 恢复旧状态*/
                        disable_ctrlc(old_ctrlc);

                        s_intf[j].exit();

                        /*
                         * no update file found没有找到更新文件
                         */
                        if (-1 == state)
                                continue;
                        /*
                         * update files have been found on current medium,
                         * so just break here
                         更新文件已在当前媒体上找到,因此请在此中断
                         */
                        break;
                }
        }

        /*
         * If u-boot has been updated, it's better to save environment to flash
         如果u-boot已经更新,最好将环境保存到flash中
         */
        if (1 == state) {
                env_crc_update();
                saveenv();
        }

        return 0;
}
#endif /* CONFIG_AUTO_UPDATE */
我来回答
回答2个
时间排序
认可量排序

浅浅

0个粉丝

9

问答

0

专栏

0

资料

浅浅 2019-07-22 16:23:08
认可0
主要改 spi_flash_erase_op和spi_flash_write_op吗,那对应的spi nand的函数是在那些头文件

浅浅

0个粉丝

9

问答

0

专栏

0

资料

浅浅 2019-07-22 16:25:38
认可0
需要写一个类似于spi_flash.c的spi_nand_flash.c吗以及对应的头文件
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区