8d7e7890b71b06e268a0d07be8c76cf5b4678e53
[oweals/u-boot.git] / drivers / mtd / mtd_uboot.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2014
4  * Heiko Schocher, DENX Software Engineering, hs@denx.de.
5  */
6 #include <common.h>
7 #include <linux/mtd/mtd.h>
8 #include <jffs2/jffs2.h> /* Legacy */
9
10 /**
11  * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
12  *                             the mtdids legacy environment variable.
13  *
14  * The mtdids string is a list of comma-separated 'dev_id=mtd_id' tupples.
15  * Check if one of the mtd_id matches mtdname, in this case save dev_id in
16  * altname.
17  *
18  * @mtdname: Current MTD device name
19  * @altname: Alternate name to return
20  * @max_len: Length of the alternate name buffer
21  *
22  * @return 0 on success, an error otherwise.
23  */
24 int mtd_search_alternate_name(const char *mtdname, char *altname,
25                               unsigned int max_len)
26 {
27         const char *mtdids, *equal, *comma, *dev_id, *mtd_id;
28         int dev_id_len, mtd_id_len;
29
30         mtdids = env_get("mtdids");
31         if (!mtdids)
32                 return -EINVAL;
33
34         do {
35                 /* Find the '=' sign */
36                 dev_id = mtdids;
37                 equal = strchr(dev_id, '=');
38                 if (!equal)
39                         break;
40                 dev_id_len = equal - mtdids;
41                 mtd_id = equal + 1;
42
43                 /* Find the end of the tupple */
44                 comma = strchr(mtdids, ',');
45                 if (comma)
46                         mtd_id_len = comma - mtd_id;
47                 else
48                         mtd_id_len = &mtdids[strlen(mtdids)] - mtd_id + 1;
49
50                 if (!dev_id_len || !mtd_id_len)
51                         return -EINVAL;
52
53                 if (dev_id_len + 1 > max_len)
54                         continue;
55
56                 /* Compare the name we search with the current mtd_id */
57                 if (!strncmp(mtdname, mtd_id, mtd_id_len)) {
58                         strncpy(altname, dev_id, dev_id_len);
59                         altname[dev_id_len] = 0;
60
61                         return 0;
62                 }
63
64                 /* Go to the next tupple */
65                 mtdids = comma + 1;
66         } while (comma);
67
68         return -EINVAL;
69 }
70
71 /* Legacy */
72
73 static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
74                 loff_t *maxsize, int devtype)
75 {
76 #ifdef CONFIG_CMD_MTDPARTS
77         struct mtd_device *dev;
78         struct part_info *part;
79         u8 pnum;
80         int ret;
81
82         ret = mtdparts_init();
83         if (ret)
84                 return ret;
85
86         ret = find_dev_and_part(partname, &dev, &pnum, &part);
87         if (ret)
88                 return ret;
89
90         if (dev->id->type != devtype) {
91                 printf("not same typ %d != %d\n", dev->id->type, devtype);
92                 return -1;
93         }
94
95         *off = part->offset;
96         *size = part->size;
97         *maxsize = part->size;
98         *idx = dev->id->num;
99
100         return 0;
101 #else
102         puts("mtdparts support missing.\n");
103         return -1;
104 #endif
105 }
106
107 int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
108                 loff_t *maxsize, int devtype, uint64_t chipsize)
109 {
110         if (!str2off(arg, off))
111                 return get_part(arg, idx, off, size, maxsize, devtype);
112
113         if (*off >= chipsize) {
114                 puts("Offset exceeds device limit\n");
115                 return -1;
116         }
117
118         *maxsize = chipsize - *off;
119         *size = *maxsize;
120         return 0;
121 }
122
123 int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
124                      loff_t *size, loff_t *maxsize, int devtype,
125                      uint64_t chipsize)
126 {
127         int ret;
128
129         if (argc == 0) {
130                 *off = 0;
131                 *size = chipsize;
132                 *maxsize = *size;
133                 goto print;
134         }
135
136         ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype,
137                           chipsize);
138         if (ret)
139                 return ret;
140
141         if (argc == 1)
142                 goto print;
143
144         if (!str2off(argv[1], size)) {
145                 printf("'%s' is not a number\n", argv[1]);
146                 return -1;
147         }
148
149         if (*size > *maxsize) {
150                 puts("Size exceeds partition or device limit\n");
151                 return -1;
152         }
153
154 print:
155         printf("device %d ", *idx);
156         if (*size == chipsize)
157                 puts("whole chip\n");
158         else
159                 printf("offset 0x%llx, size 0x%llx\n",
160                        (unsigned long long)*off, (unsigned long long)*size);
161         return 0;
162 }