ARM64: dts: rk3368-android: enable vpu_combo default
[firefly-linux-kernel-4.4.55.git] / block / partitions / rk.c
1 #include <linux/kernel.h>
2 #include <linux/slab.h>
3 #include <linux/bootmem.h>
4 #include "check.h"
5 #include "rk.h"
6
7 /* rkpart_setup() parses into here */
8 static struct cmdline_rk_partition *partitions;
9 /* the command line passed to mtdpart_setupd() */
10 static char *cmdline;
11 static int cmdline_parsed;
12
13 /*
14  * Parse one partition definition for an rkpart. Since there can be many
15  * comma separated partition definitions, this function calls itself
16  * recursively until no more partition definitions are found. Nice side
17  * effect: the memory to keep the rk_partition structs and the names
18  * is allocated upon the last definition being found. At that point the
19  * syntax has been verified ok.
20  */
21 static struct rk_partition *newpart(char *s,
22                                         char **retptr,
23                                         int *num_parts,
24                                         int this_part,
25                                         unsigned char **extra_mem_ptr,
26                                         int extra_mem_size)
27 {
28         struct rk_partition *parts;
29         sector_t size;
30         sector_t from = OFFSET_CONTINUOUS;
31         char *name;
32         int name_len;
33         unsigned char *extra_mem;
34         char delim;
35
36         /* fetch the partition size */
37         if (*s == '-')
38         {       /* assign all remaining space to this partition */
39                 size = SIZE_REMAINING;
40                 s++;
41         }
42         else
43         {
44                 size = memparse(s, &s);
45                 /* No sense support partition less than 8B */
46                 if (size < ((PAGE_SIZE) >> 9))
47                 {
48                         printk(KERN_ERR ERRP "partition size too small (%llx)\n", (u64)size);
49                         return NULL;
50                 }
51         }
52
53         /* fetch partition name */
54         delim = 0;
55         /* check for from */
56         if (*s == '@')
57         {
58                 s++;
59                 from = memparse(s, &s);
60         }
61         /* now look for name */
62         if (*s == '(')
63         {
64                 delim = ')';
65         }
66
67         if (delim)
68         {
69                 char *p;
70
71                 name = ++s;
72                 p = strchr(name, delim);
73                 if (!p)
74                 {
75                         printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
76                         return NULL;
77                 }
78                 name_len = p - name;
79                 s = p + 1;
80         }
81         else
82         {
83                 name = NULL;
84                 name_len = 13; /* Partition_000 */
85         }
86
87         /* record name length for memory allocation later */
88         extra_mem_size += name_len + 1;
89
90         /* test if more partitions are following */
91         if (*s == ',')
92         {
93                 if (size == SIZE_REMAINING)
94                 {
95                         printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
96                         return NULL;
97                 }
98                 /* more partitions follow, parse them */
99                 parts = newpart(s + 1, &s, num_parts, this_part + 1,
100                                 &extra_mem, extra_mem_size);
101                 if (!parts)
102                         return NULL;
103         }
104         else
105         {       /* this is the last partition: allocate space for all */
106                 int alloc_size;
107
108                 *num_parts = this_part + 1;
109                 alloc_size = *num_parts * sizeof(struct rk_partition) +
110                              extra_mem_size;
111                 parts = kzalloc(alloc_size, GFP_KERNEL);
112                 if (!parts)
113                 {
114                         printk(KERN_ERR ERRP "out of memory\n");
115                         return NULL;
116                 }
117                 extra_mem = (unsigned char *)(parts + *num_parts);
118         }
119         /* enter this partition (from will be calculated later if it is zero at this point) */
120         parts[this_part].size = size;
121         parts[this_part].from = from;
122         if (name)
123         {
124                 strlcpy(extra_mem, name, name_len + 1);
125         }
126         else
127         {
128                 sprintf(extra_mem, "Partition_%03d", this_part);
129         }
130         parts[this_part].name = extra_mem;
131         extra_mem += name_len + 1;
132
133         dbg(("partition %d: name <%s>, from %llx, size %llx\n",
134              this_part,
135              parts[this_part].name,
136              parts[this_part].from,
137              parts[this_part].size));
138
139         /* return (updated) pointer to extra_mem memory */
140         if (extra_mem_ptr)
141           *extra_mem_ptr = extra_mem;
142
143         /* return (updated) pointer command line string */
144         *retptr = s;
145
146         /* return partition table */
147         return parts;
148 }
149
150 /*
151  * Parse the command line.
152  */
153 static int rkpart_setup_real(char *s)
154 {
155         cmdline_parsed = 1;
156
157         for( ; s != NULL; )
158         {
159                 struct cmdline_rk_partition *this_rk;
160                 struct rk_partition *parts;
161                 int rk_id_len;
162                 int num_parts;
163                 char *p, *rk_id;
164
165                 rk_id = s;
166                 /* fetch <rk-id> */
167                 if (!(p = strchr(s, ':')))
168                 {
169                         dbg(( "no rk-id\n"));
170                         return 0;
171                 }
172                 rk_id_len = p - rk_id;
173
174                 dbg(("parsing <%s>\n", p + 1));
175
176                 /*
177                  * parse one mtd. have it reserve memory for the
178                  * struct cmdline_mtd_partition and the mtd-id string.
179                  */
180                 parts = newpart(p + 1,          /* cmdline */
181                                 &s,             /* out: updated cmdline ptr */
182                                 &num_parts,     /* out: number of parts */
183                                 0,              /* first partition */
184                                 (unsigned char**)&this_rk, /* out: extra mem */
185                                 rk_id_len + 1 + sizeof(*this_rk) +
186                                 sizeof(void*)-1 /*alignment*/);
187                 if(!parts)
188                 {
189                         /*
190                          * An error occurred. We're either:
191                          * a) out of memory, or
192                          * b) in the middle of the partition spec
193                          * Either way, this mtd is hosed and we're
194                          * unlikely to succeed in parsing any more
195                          */
196                          return 0;
197                  }
198
199                 /* align this_rk */
200                 this_rk = (struct cmdline_rk_partition *)
201                         ALIGN((unsigned long)this_rk, sizeof(void*));
202                 /* enter results */
203                 this_rk->parts = parts;
204                 this_rk->num_parts = num_parts;
205                 this_rk->rk_id = (char*)(this_rk + 1);
206                 strlcpy(this_rk->rk_id, rk_id, rk_id_len + 1);
207
208                 /* link into chain */
209                 this_rk->next = partitions;
210                 partitions = this_rk;
211
212                 dbg(("rkid=<%s> num_parts=<%d>\n",
213                      this_rk->mtd_id, this_rk->num_parts));
214
215                 /* EOS - we're done */
216                 if (*s == 0)
217                         break;
218                 s++;
219         }
220         return 1;
221 }
222
223 /*
224  * Main function to be called from the MTD mapping driver/device to
225  * obtain the partitioning information. At this point the command line
226  * arguments will actually be parsed and turned to struct mtd_partition
227  * information. It returns partitions for the requested mtd device, or
228  * the first one in the chain if a NULL mtd_id is passed in.
229  */
230 static int parse_cmdline_partitions(sector_t n,
231                                     struct rk_partition **pparts,
232                                     unsigned long origin)
233 {
234         unsigned long from;
235         int i;
236         struct cmdline_rk_partition *part;
237         /* Fixme: parameter should be coherence with part table id */
238         const char *rk_id = "rk29xxnand";
239
240         /* parse command line */
241         if (!cmdline_parsed)
242                 rkpart_setup_real(cmdline);
243
244         for(part = partitions; part; part = part->next)
245         {
246                 if ((!rk_id) || (!strcmp(part->rk_id, rk_id)))
247                 {
248                         for(i = 0, from = 0; i < part->num_parts; i++)
249                         {
250                                 if (part->parts[i].from == OFFSET_CONTINUOUS)
251                                   part->parts[i].from = from;
252                                 else
253                                   from = part->parts[i].from;
254                                 if (part->parts[i].size == SIZE_REMAINING)
255                                   part->parts[i].size = n - from - FROM_OFFSET;
256                                 if (from + part->parts[i].size > n)
257                                 {
258                                         printk(KERN_WARNING ERRP
259                                                "%s: partitioning exceeds flash size, truncating\n",
260                                                part->rk_id);
261                                         part->parts[i].size = n - from;
262                                         part->num_parts = i;
263                                 }
264                                 from += part->parts[i].size;
265                         }
266                         *pparts = kmemdup(part->parts,
267                                         sizeof(*part->parts) * part->num_parts,
268                                         GFP_KERNEL);
269                         if (!*pparts)
270                                 return -ENOMEM;
271                         return part->num_parts;
272                 }
273         }
274         return 0;
275 }
276
277 static void rkpart_bootmode_fixup(void)
278 {
279         const char mode_emmc[] = " androidboot.mode=emmc";
280         const char mode_nvme[] = " androidboot.mode=nvme";
281         const char charger[] = " androidboot.charger.emmc=1";
282         char *new_command_line;
283         size_t saved_command_line_len = strlen(saved_command_line);
284
285         if (strstr(saved_command_line, "androidboot.mode=charger")) {
286                 new_command_line = kzalloc(saved_command_line_len +
287                                 strlen(charger) + 1, GFP_KERNEL);
288                 sprintf(new_command_line, "%s%s",
289                         saved_command_line, charger);
290         } else {
291                 new_command_line = kzalloc(saved_command_line_len +
292                                 strlen(mode_emmc) + 1, GFP_KERNEL);
293                 if (strstr(saved_command_line, "storagemedia=nvme"))
294                         sprintf(new_command_line, "%s%s",
295                                 saved_command_line, mode_nvme);
296                 else
297                         sprintf(new_command_line, "%s%s",
298                                 saved_command_line, mode_emmc);
299         }
300         saved_command_line = new_command_line;
301 }
302
303 int rkpart_partition(struct parsed_partitions *state)
304 {
305         int num_parts = 0, i;
306         sector_t n = get_capacity(state->bdev->bd_disk);
307         struct rk_partition *parts = NULL;
308
309         if (n < SECTOR_1G)
310                 return 0;
311
312         if (!state->bdev->bd_disk->is_rk_disk)
313                 return 0;
314
315         /* Fixme: parameter should be coherence with part table */
316         cmdline = strstr(saved_command_line, "mtdparts=");
317         if (!cmdline)
318                 return 0;
319         cmdline += 9;
320         cmdline_parsed = 0;
321
322         num_parts = parse_cmdline_partitions(n, &parts, 0);
323         if (num_parts < 0)
324                 return num_parts;
325
326         for (i = 0; i < num_parts; i++) {
327                 put_partition(  state,
328                                 i+1,
329                                 parts[i].from + FROM_OFFSET,
330                                 parts[i].size);
331                 strcpy(state->parts[i+1].info.volname, parts[i].name);
332                 printk(KERN_INFO "%10s: 0x%09llx -- 0x%09llx (%llu MB)\n", 
333                                 parts[i].name,
334                                 (u64)parts[i].from * 512,
335                                 (u64)(parts[i].from + parts[i].size) * 512,
336                                 (u64)parts[i].size / 2048);
337         }
338
339         rkpart_bootmode_fixup();
340
341         return 1;
342 }
343
344