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