drivers: dfu: add DFU to read and write to MTD base storage
Add DFU to read and write to MTD base storage. Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com> Change-Id: I84cb160b182c31d7f84ed700896a4970845a3ca8
This commit is contained in:
parent
ca42250799
commit
0bcaecc8ee
|
|
@ -23,6 +23,12 @@ config DFU_NAND
|
||||||
This option enables using DFU to read and write to NAND based
|
This option enables using DFU to read and write to NAND based
|
||||||
storage.
|
storage.
|
||||||
|
|
||||||
|
config DFU_MTD
|
||||||
|
bool "MTD back end for DFU"
|
||||||
|
help
|
||||||
|
This option enables using DFU to read and write to MTD based
|
||||||
|
storage.
|
||||||
|
|
||||||
config DFU_RAM
|
config DFU_RAM
|
||||||
bool "RAM back end for DFU"
|
bool "RAM back end for DFU"
|
||||||
help
|
help
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
obj-$(CONFIG_USB_FUNCTION_DFU) += dfu.o
|
obj-$(CONFIG_USB_FUNCTION_DFU) += dfu.o
|
||||||
obj-$(CONFIG_DFU_MMC) += dfu_mmc.o
|
obj-$(CONFIG_DFU_MMC) += dfu_mmc.o
|
||||||
|
obj-$(CONFIG_DFU_MTD) += dfu_mtd.o
|
||||||
obj-$(CONFIG_DFU_NAND) += dfu_nand.o
|
obj-$(CONFIG_DFU_NAND) += dfu_nand.o
|
||||||
obj-$(CONFIG_DFU_RAM) += dfu_ram.o
|
obj-$(CONFIG_DFU_RAM) += dfu_ram.o
|
||||||
obj-$(CONFIG_DFU_SF) += dfu_sf.o
|
obj-$(CONFIG_DFU_SF) += dfu_sf.o
|
||||||
|
|
|
||||||
|
|
@ -400,6 +400,9 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt,
|
||||||
if (strcmp(interface, "mmc") == 0) {
|
if (strcmp(interface, "mmc") == 0) {
|
||||||
if (dfu_fill_entity_mmc(dfu, devstr, s))
|
if (dfu_fill_entity_mmc(dfu, devstr, s))
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (strcmp(interface, "mtd") == 0) {
|
||||||
|
if (dfu_fill_entity_mtd(dfu, devstr, s))
|
||||||
|
return -1;
|
||||||
} else if (strcmp(interface, "nand") == 0) {
|
} else if (strcmp(interface, "nand") == 0) {
|
||||||
if (dfu_fill_entity_nand(dfu, devstr, s))
|
if (dfu_fill_entity_nand(dfu, devstr, s))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2021 Rockchip Electronics Co., Ltd
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
*/
|
||||||
|
#include <common.h>
|
||||||
|
#include <boot_rkimg.h>
|
||||||
|
#include <div64.h>
|
||||||
|
#include <dfu.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <part.h>
|
||||||
|
|
||||||
|
static int dfu_write_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
|
||||||
|
{
|
||||||
|
struct blk_desc *dev_desc;
|
||||||
|
u64 block_start, block_len;
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
switch (dfu->layout) {
|
||||||
|
case DFU_RAW_ADDR:
|
||||||
|
/* if buf == NULL return total size of the area */
|
||||||
|
if (!buf) {
|
||||||
|
*len = dfu->data.nand.size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_desc = rockchip_get_bootdev();
|
||||||
|
if (!dev_desc) {
|
||||||
|
printf("%s: dev_desc is NULL!\n", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in case of ubi partition, erase rest of the partition */
|
||||||
|
if (dfu->data.mtd.ubi && !offset) {
|
||||||
|
block_start = dfu->data.mtd.start >> 9;
|
||||||
|
block_len = dfu->data.mtd.size >> 9;
|
||||||
|
|
||||||
|
ret = blk_derase(dev_desc, block_start, block_len);
|
||||||
|
if (ret != 0)
|
||||||
|
printf("Failure erase: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
block_start = (dfu->data.mtd.start + offset) >> 9;
|
||||||
|
block_len = (*len) >> 9;
|
||||||
|
|
||||||
|
ret = blk_dwrite(dev_desc, block_start, block_len, buf);
|
||||||
|
if (ret == block_len)
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
|
||||||
|
dfu_get_layout(dfu->layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size)
|
||||||
|
{
|
||||||
|
*size = dfu->data.mtd.size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
|
||||||
|
{
|
||||||
|
struct blk_desc *dev_desc;
|
||||||
|
u64 block_start, block_len;
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
switch (dfu->layout) {
|
||||||
|
case DFU_RAW_ADDR:
|
||||||
|
/* if buf == NULL return total size of the area */
|
||||||
|
if (!buf) {
|
||||||
|
*len = dfu->data.nand.size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_desc = rockchip_get_bootdev();
|
||||||
|
if (!dev_desc) {
|
||||||
|
printf("%s: dev_desc is NULL!\n", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_start = (dfu->data.mtd.start + offset) >> 9;
|
||||||
|
block_len = (*len) >> 9;
|
||||||
|
|
||||||
|
ret = blk_dread(dev_desc, block_start, block_len, buf);
|
||||||
|
if (ret == block_len)
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
|
||||||
|
dfu_get_layout(dfu->layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfu_flush_medium_mtd(struct dfu_entity *dfu)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Currently, Poll Timeout != 0 is only needed on nand
|
||||||
|
* ubi partition, as the not used sectors need an erase
|
||||||
|
*/
|
||||||
|
if (dfu->data.mtd.ubi)
|
||||||
|
return DFU_MANIFEST_POLL_TIMEOUT;
|
||||||
|
|
||||||
|
return DFU_DEFAULT_POLL_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s)
|
||||||
|
{
|
||||||
|
struct blk_desc *dev_desc;
|
||||||
|
disk_partition_t dfu_part;
|
||||||
|
char *st;
|
||||||
|
|
||||||
|
dfu->data.mtd.ubi = 0;
|
||||||
|
dfu->dev_type = DFU_DEV_MTD;
|
||||||
|
st = strsep(&s, " ");
|
||||||
|
|
||||||
|
if (!strcmp(st, "raw")) {
|
||||||
|
dfu->layout = DFU_RAW_ADDR;
|
||||||
|
dfu->data.mtd.start = simple_strtoul(s, &s, 16);
|
||||||
|
s++;
|
||||||
|
dfu->data.mtd.size = simple_strtoul(s, &s, 16);
|
||||||
|
} else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
|
||||||
|
dev_desc = rockchip_get_bootdev();
|
||||||
|
if (!dev_desc) {
|
||||||
|
printf("%s: dev_desc is NULL!\n", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
dfu->layout = DFU_RAW_ADDR;
|
||||||
|
if (part_get_info_by_name(dev_desc, s, &dfu_part) < 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
dfu->data.mtd.start = dfu_part.start << 9;
|
||||||
|
dfu->data.mtd.size = dfu_part.size << 9;
|
||||||
|
if (!strcmp(st, "partubi"))
|
||||||
|
dfu->data.mtd.ubi = 1;
|
||||||
|
} else {
|
||||||
|
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfu->get_medium_size = dfu_get_medium_size_mtd;
|
||||||
|
dfu->read_medium = dfu_read_medium_mtd;
|
||||||
|
dfu->write_medium = dfu_write_medium_mtd;
|
||||||
|
dfu->flush_medium = dfu_flush_medium_mtd;
|
||||||
|
dfu->poll_timeout = dfu_polltimeout_mtd;
|
||||||
|
|
||||||
|
/* initial state */
|
||||||
|
dfu->inited = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ enum dfu_device_type {
|
||||||
DFU_DEV_NAND,
|
DFU_DEV_NAND,
|
||||||
DFU_DEV_RAM,
|
DFU_DEV_RAM,
|
||||||
DFU_DEV_SF,
|
DFU_DEV_SF,
|
||||||
|
DFU_DEV_MTD,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dfu_layout {
|
enum dfu_layout {
|
||||||
|
|
@ -67,6 +68,17 @@ struct nand_internal_data {
|
||||||
unsigned int ubi;
|
unsigned int ubi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mtd_internal_data {
|
||||||
|
/* RAW programming */
|
||||||
|
u64 start;
|
||||||
|
u64 size;
|
||||||
|
|
||||||
|
unsigned int dev;
|
||||||
|
unsigned int part;
|
||||||
|
/* for nand/ubi use */
|
||||||
|
unsigned int ubi;
|
||||||
|
};
|
||||||
|
|
||||||
struct ram_internal_data {
|
struct ram_internal_data {
|
||||||
void *start;
|
void *start;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
|
@ -108,6 +120,7 @@ struct dfu_entity {
|
||||||
struct nand_internal_data nand;
|
struct nand_internal_data nand;
|
||||||
struct ram_internal_data ram;
|
struct ram_internal_data ram;
|
||||||
struct sf_internal_data sf;
|
struct sf_internal_data sf;
|
||||||
|
struct mtd_internal_data mtd;
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
int (*get_medium_size)(struct dfu_entity *dfu, u64 *size);
|
int (*get_medium_size)(struct dfu_entity *dfu, u64 *size);
|
||||||
|
|
@ -214,6 +227,17 @@ static inline int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_DFU_MTD
|
||||||
|
extern int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s);
|
||||||
|
#else
|
||||||
|
static inline int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr,
|
||||||
|
char *s)
|
||||||
|
{
|
||||||
|
puts("MTD support not available!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DFU_NAND
|
#ifdef CONFIG_DFU_NAND
|
||||||
extern int dfu_fill_entity_nand(struct dfu_entity *dfu, char *devstr, char *s);
|
extern int dfu_fill_entity_nand(struct dfu_entity *dfu, char *devstr, char *s);
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue