10bcaecc8SYifeng Zhao /*
20bcaecc8SYifeng Zhao * (C) Copyright 2021 Rockchip Electronics Co., Ltd
30bcaecc8SYifeng Zhao *
40bcaecc8SYifeng Zhao * SPDX-License-Identifier: GPL-2.0+
50bcaecc8SYifeng Zhao */
60bcaecc8SYifeng Zhao #include <common.h>
70bcaecc8SYifeng Zhao #include <boot_rkimg.h>
80bcaecc8SYifeng Zhao #include <div64.h>
90bcaecc8SYifeng Zhao #include <dfu.h>
100bcaecc8SYifeng Zhao #include <errno.h>
110bcaecc8SYifeng Zhao #include <linux/mtd/mtd.h>
120bcaecc8SYifeng Zhao #include <malloc.h>
130bcaecc8SYifeng Zhao #include <part.h>
140bcaecc8SYifeng Zhao
dfu_write_medium_mtd(struct dfu_entity * dfu,u64 offset,void * buf,long * len)150bcaecc8SYifeng Zhao static int dfu_write_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
160bcaecc8SYifeng Zhao {
170bcaecc8SYifeng Zhao struct blk_desc *dev_desc;
180bcaecc8SYifeng Zhao u64 block_start, block_len;
190bcaecc8SYifeng Zhao int ret = -ENODEV;
200bcaecc8SYifeng Zhao
210bcaecc8SYifeng Zhao switch (dfu->layout) {
220bcaecc8SYifeng Zhao case DFU_RAW_ADDR:
230bcaecc8SYifeng Zhao /* if buf == NULL return total size of the area */
240bcaecc8SYifeng Zhao if (!buf) {
250bcaecc8SYifeng Zhao *len = dfu->data.nand.size;
260bcaecc8SYifeng Zhao return 0;
270bcaecc8SYifeng Zhao }
280bcaecc8SYifeng Zhao
290bcaecc8SYifeng Zhao dev_desc = rockchip_get_bootdev();
300bcaecc8SYifeng Zhao if (!dev_desc) {
310bcaecc8SYifeng Zhao printf("%s: dev_desc is NULL!\n", __func__);
320bcaecc8SYifeng Zhao return -ENODEV;
330bcaecc8SYifeng Zhao }
340bcaecc8SYifeng Zhao
350bcaecc8SYifeng Zhao /* in case of ubi partition, erase rest of the partition */
360bcaecc8SYifeng Zhao if (dfu->data.mtd.ubi && !offset) {
370bcaecc8SYifeng Zhao block_start = dfu->data.mtd.start >> 9;
380bcaecc8SYifeng Zhao block_len = dfu->data.mtd.size >> 9;
390bcaecc8SYifeng Zhao
400bcaecc8SYifeng Zhao ret = blk_derase(dev_desc, block_start, block_len);
410bcaecc8SYifeng Zhao if (ret != 0)
420bcaecc8SYifeng Zhao printf("Failure erase: %d\n", ret);
430bcaecc8SYifeng Zhao }
440bcaecc8SYifeng Zhao
450bcaecc8SYifeng Zhao block_start = (dfu->data.mtd.start + offset) >> 9;
460bcaecc8SYifeng Zhao block_len = (*len) >> 9;
470bcaecc8SYifeng Zhao
480bcaecc8SYifeng Zhao ret = blk_dwrite(dev_desc, block_start, block_len, buf);
490bcaecc8SYifeng Zhao if (ret == block_len)
500bcaecc8SYifeng Zhao ret = 0;
510bcaecc8SYifeng Zhao break;
520bcaecc8SYifeng Zhao default:
530bcaecc8SYifeng Zhao printf("%s: Layout (%s) not (yet) supported!\n", __func__,
540bcaecc8SYifeng Zhao dfu_get_layout(dfu->layout));
550bcaecc8SYifeng Zhao }
560bcaecc8SYifeng Zhao
570bcaecc8SYifeng Zhao return ret;
580bcaecc8SYifeng Zhao }
590bcaecc8SYifeng Zhao
dfu_get_medium_size_mtd(struct dfu_entity * dfu,u64 * size)600bcaecc8SYifeng Zhao static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size)
610bcaecc8SYifeng Zhao {
620bcaecc8SYifeng Zhao *size = dfu->data.mtd.size;
630bcaecc8SYifeng Zhao
640bcaecc8SYifeng Zhao return 0;
650bcaecc8SYifeng Zhao }
660bcaecc8SYifeng Zhao
dfu_read_medium_mtd(struct dfu_entity * dfu,u64 offset,void * buf,long * len)670bcaecc8SYifeng Zhao static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
680bcaecc8SYifeng Zhao {
690bcaecc8SYifeng Zhao struct blk_desc *dev_desc;
700bcaecc8SYifeng Zhao u64 block_start, block_len;
710bcaecc8SYifeng Zhao int ret = -ENODEV;
720bcaecc8SYifeng Zhao
730bcaecc8SYifeng Zhao switch (dfu->layout) {
740bcaecc8SYifeng Zhao case DFU_RAW_ADDR:
750bcaecc8SYifeng Zhao /* if buf == NULL return total size of the area */
760bcaecc8SYifeng Zhao if (!buf) {
770bcaecc8SYifeng Zhao *len = dfu->data.nand.size;
780bcaecc8SYifeng Zhao return 0;
790bcaecc8SYifeng Zhao }
800bcaecc8SYifeng Zhao
810bcaecc8SYifeng Zhao dev_desc = rockchip_get_bootdev();
820bcaecc8SYifeng Zhao if (!dev_desc) {
830bcaecc8SYifeng Zhao printf("%s: dev_desc is NULL!\n", __func__);
840bcaecc8SYifeng Zhao return -ENODEV;
850bcaecc8SYifeng Zhao }
860bcaecc8SYifeng Zhao
870bcaecc8SYifeng Zhao block_start = (dfu->data.mtd.start + offset) >> 9;
880bcaecc8SYifeng Zhao block_len = (*len) >> 9;
890bcaecc8SYifeng Zhao
900bcaecc8SYifeng Zhao ret = blk_dread(dev_desc, block_start, block_len, buf);
910bcaecc8SYifeng Zhao if (ret == block_len)
920bcaecc8SYifeng Zhao ret = 0;
930bcaecc8SYifeng Zhao break;
940bcaecc8SYifeng Zhao default:
950bcaecc8SYifeng Zhao printf("%s: Layout (%s) not (yet) supported!\n", __func__,
960bcaecc8SYifeng Zhao dfu_get_layout(dfu->layout));
970bcaecc8SYifeng Zhao }
980bcaecc8SYifeng Zhao
990bcaecc8SYifeng Zhao return ret;
1000bcaecc8SYifeng Zhao }
1010bcaecc8SYifeng Zhao
dfu_flush_medium_mtd(struct dfu_entity * dfu)1020bcaecc8SYifeng Zhao static int dfu_flush_medium_mtd(struct dfu_entity *dfu)
1030bcaecc8SYifeng Zhao {
1040bcaecc8SYifeng Zhao return 0;
1050bcaecc8SYifeng Zhao }
1060bcaecc8SYifeng Zhao
dfu_polltimeout_mtd(struct dfu_entity * dfu)1070bcaecc8SYifeng Zhao unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
1080bcaecc8SYifeng Zhao {
1090bcaecc8SYifeng Zhao /*
1100bcaecc8SYifeng Zhao * Currently, Poll Timeout != 0 is only needed on nand
1110bcaecc8SYifeng Zhao * ubi partition, as the not used sectors need an erase
1120bcaecc8SYifeng Zhao */
1130bcaecc8SYifeng Zhao if (dfu->data.mtd.ubi)
1140bcaecc8SYifeng Zhao return DFU_MANIFEST_POLL_TIMEOUT;
1150bcaecc8SYifeng Zhao
1160bcaecc8SYifeng Zhao return DFU_DEFAULT_POLL_TIMEOUT;
1170bcaecc8SYifeng Zhao }
1180bcaecc8SYifeng Zhao
dfu_fill_entity_mtd(struct dfu_entity * dfu,char * devstr,char * s)1190bcaecc8SYifeng Zhao int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s)
1200bcaecc8SYifeng Zhao {
1210bcaecc8SYifeng Zhao struct blk_desc *dev_desc;
1220bcaecc8SYifeng Zhao disk_partition_t dfu_part;
1230bcaecc8SYifeng Zhao char *st;
1240bcaecc8SYifeng Zhao
1250bcaecc8SYifeng Zhao dfu->data.mtd.ubi = 0;
1260bcaecc8SYifeng Zhao dfu->dev_type = DFU_DEV_MTD;
1270bcaecc8SYifeng Zhao st = strsep(&s, " ");
1280bcaecc8SYifeng Zhao
129*42bb6aacSTony Xu if (!strcmp(st, "raw") || !strcmp(st, "rawubi")) {
1300bcaecc8SYifeng Zhao dfu->layout = DFU_RAW_ADDR;
1310bcaecc8SYifeng Zhao dfu->data.mtd.start = simple_strtoul(s, &s, 16);
1320bcaecc8SYifeng Zhao s++;
1330bcaecc8SYifeng Zhao dfu->data.mtd.size = simple_strtoul(s, &s, 16);
134*42bb6aacSTony Xu if (!strcmp(st, "rawubi"))
135*42bb6aacSTony Xu dfu->data.mtd.ubi = 1;
1360bcaecc8SYifeng Zhao } else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
1370bcaecc8SYifeng Zhao dev_desc = rockchip_get_bootdev();
1380bcaecc8SYifeng Zhao if (!dev_desc) {
1390bcaecc8SYifeng Zhao printf("%s: dev_desc is NULL!\n", __func__);
1400bcaecc8SYifeng Zhao return -ENODEV;
1410bcaecc8SYifeng Zhao }
1420bcaecc8SYifeng Zhao dfu->layout = DFU_RAW_ADDR;
1430bcaecc8SYifeng Zhao if (part_get_info_by_name(dev_desc, s, &dfu_part) < 0)
1440bcaecc8SYifeng Zhao return -EIO;
1450bcaecc8SYifeng Zhao
1460bcaecc8SYifeng Zhao dfu->data.mtd.start = dfu_part.start << 9;
1470bcaecc8SYifeng Zhao dfu->data.mtd.size = dfu_part.size << 9;
1480bcaecc8SYifeng Zhao if (!strcmp(st, "partubi"))
1490bcaecc8SYifeng Zhao dfu->data.mtd.ubi = 1;
1500bcaecc8SYifeng Zhao } else {
1510bcaecc8SYifeng Zhao printf("%s: Memory layout (%s) not supported!\n", __func__, st);
1520bcaecc8SYifeng Zhao return -1;
1530bcaecc8SYifeng Zhao }
1540bcaecc8SYifeng Zhao
1550bcaecc8SYifeng Zhao dfu->get_medium_size = dfu_get_medium_size_mtd;
1560bcaecc8SYifeng Zhao dfu->read_medium = dfu_read_medium_mtd;
1570bcaecc8SYifeng Zhao dfu->write_medium = dfu_write_medium_mtd;
1580bcaecc8SYifeng Zhao dfu->flush_medium = dfu_flush_medium_mtd;
1590bcaecc8SYifeng Zhao dfu->poll_timeout = dfu_polltimeout_mtd;
1600bcaecc8SYifeng Zhao
1610bcaecc8SYifeng Zhao /* initial state */
1620bcaecc8SYifeng Zhao dfu->inited = 0;
1630bcaecc8SYifeng Zhao
1640bcaecc8SYifeng Zhao return 0;
1650bcaecc8SYifeng Zhao }
166