xref: /openbmc/u-boot/drivers/mtd/mtd_uboot.c (revision ff4afa8a981e22eef670c7c857cb87983346cc2c)
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 }
163