1 /* 2 * (C) Copyright 2021 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <boot_rkimg.h> 8 #include <div64.h> 9 #include <dfu.h> 10 #include <errno.h> 11 #include <linux/mtd/mtd.h> 12 #include <malloc.h> 13 #include <part.h> 14 15 static int dfu_write_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len) 16 { 17 struct blk_desc *dev_desc; 18 u64 block_start, block_len; 19 int ret = -ENODEV; 20 21 switch (dfu->layout) { 22 case DFU_RAW_ADDR: 23 /* if buf == NULL return total size of the area */ 24 if (!buf) { 25 *len = dfu->data.nand.size; 26 return 0; 27 } 28 29 dev_desc = rockchip_get_bootdev(); 30 if (!dev_desc) { 31 printf("%s: dev_desc is NULL!\n", __func__); 32 return -ENODEV; 33 } 34 35 /* in case of ubi partition, erase rest of the partition */ 36 if (dfu->data.mtd.ubi && !offset) { 37 block_start = dfu->data.mtd.start >> 9; 38 block_len = dfu->data.mtd.size >> 9; 39 40 ret = blk_derase(dev_desc, block_start, block_len); 41 if (ret != 0) 42 printf("Failure erase: %d\n", ret); 43 } 44 45 block_start = (dfu->data.mtd.start + offset) >> 9; 46 block_len = (*len) >> 9; 47 48 ret = blk_dwrite(dev_desc, block_start, block_len, buf); 49 if (ret == block_len) 50 ret = 0; 51 break; 52 default: 53 printf("%s: Layout (%s) not (yet) supported!\n", __func__, 54 dfu_get_layout(dfu->layout)); 55 } 56 57 return ret; 58 } 59 60 static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size) 61 { 62 *size = dfu->data.mtd.size; 63 64 return 0; 65 } 66 67 static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len) 68 { 69 struct blk_desc *dev_desc; 70 u64 block_start, block_len; 71 int ret = -ENODEV; 72 73 switch (dfu->layout) { 74 case DFU_RAW_ADDR: 75 /* if buf == NULL return total size of the area */ 76 if (!buf) { 77 *len = dfu->data.nand.size; 78 return 0; 79 } 80 81 dev_desc = rockchip_get_bootdev(); 82 if (!dev_desc) { 83 printf("%s: dev_desc is NULL!\n", __func__); 84 return -ENODEV; 85 } 86 87 block_start = (dfu->data.mtd.start + offset) >> 9; 88 block_len = (*len) >> 9; 89 90 ret = blk_dread(dev_desc, block_start, block_len, buf); 91 if (ret == block_len) 92 ret = 0; 93 break; 94 default: 95 printf("%s: Layout (%s) not (yet) supported!\n", __func__, 96 dfu_get_layout(dfu->layout)); 97 } 98 99 return ret; 100 } 101 102 static int dfu_flush_medium_mtd(struct dfu_entity *dfu) 103 { 104 return 0; 105 } 106 107 unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu) 108 { 109 /* 110 * Currently, Poll Timeout != 0 is only needed on nand 111 * ubi partition, as the not used sectors need an erase 112 */ 113 if (dfu->data.mtd.ubi) 114 return DFU_MANIFEST_POLL_TIMEOUT; 115 116 return DFU_DEFAULT_POLL_TIMEOUT; 117 } 118 119 int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s) 120 { 121 struct blk_desc *dev_desc; 122 disk_partition_t dfu_part; 123 char *st; 124 125 dfu->data.mtd.ubi = 0; 126 dfu->dev_type = DFU_DEV_MTD; 127 st = strsep(&s, " "); 128 129 if (!strcmp(st, "raw") || !strcmp(st, "rawubi")) { 130 dfu->layout = DFU_RAW_ADDR; 131 dfu->data.mtd.start = simple_strtoul(s, &s, 16); 132 s++; 133 dfu->data.mtd.size = simple_strtoul(s, &s, 16); 134 if (!strcmp(st, "rawubi")) 135 dfu->data.mtd.ubi = 1; 136 } else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) { 137 dev_desc = rockchip_get_bootdev(); 138 if (!dev_desc) { 139 printf("%s: dev_desc is NULL!\n", __func__); 140 return -ENODEV; 141 } 142 dfu->layout = DFU_RAW_ADDR; 143 if (part_get_info_by_name(dev_desc, s, &dfu_part) < 0) 144 return -EIO; 145 146 dfu->data.mtd.start = dfu_part.start << 9; 147 dfu->data.mtd.size = dfu_part.size << 9; 148 if (!strcmp(st, "partubi")) 149 dfu->data.mtd.ubi = 1; 150 } else { 151 printf("%s: Memory layout (%s) not supported!\n", __func__, st); 152 return -1; 153 } 154 155 dfu->get_medium_size = dfu_get_medium_size_mtd; 156 dfu->read_medium = dfu_read_medium_mtd; 157 dfu->write_medium = dfu_write_medium_mtd; 158 dfu->flush_medium = dfu_flush_medium_mtd; 159 dfu->poll_timeout = dfu_polltimeout_mtd; 160 161 /* initial state */ 162 dfu->inited = 0; 163 164 return 0; 165 } 166