fs/fs.c: correctly interpret the '(max)len' parameter to fs_read()
[karo-tx-uboot.git] / board / karo / common / mmc.c
1 /*
2  * (C) Copyright 2014 Lothar WaƟmann <LW@KARO-electronics.de>
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <common.h>
19 #include <errno.h>
20 #include <libfdt.h>
21 #include <fdt_support.h>
22 #include <mmc.h>
23 #include <mxcfb.h>
24 #include <fs.h>
25 #include <fat.h>
26 #include <malloc.h>
27 #include <linux/list.h>
28 #include <linux/fb.h>
29 #include <jffs2/load_kernel.h>
30
31 #include "karo.h"
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 #define MAX_SEARCH_PARTITIONS 16
36
37 static int find_partitions(const char *ifname, int devno, int fstype,
38                         block_dev_desc_t **dev_desc, disk_partition_t *info)
39 {
40         int ret = -1;
41         char *dup_str = NULL;
42         int p;
43         int part;
44         block_dev_desc_t *dd;
45         char dev_part_str[16];
46
47         dd = get_dev(ifname, devno);
48         if (!dd || dd->type == DEV_TYPE_UNKNOWN) {
49                 printf("** Bad device %s %d **\n", ifname, devno);
50                 return -1;
51         }
52         init_part(dd);
53
54         /*
55          * No partition table on device,
56          * or user requested partition 0 (entire device).
57          */
58         if (dd->part_type == PART_TYPE_UNKNOWN) {
59                 printf("** No partition table on device %s %d **\n",
60                         ifname, devno);
61                 goto cleanup;
62         }
63
64         part = 0;
65         for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
66                 ret = get_partition_info(dd, p, info);
67                 if (ret)
68                         continue;
69
70                 if (fat_register_device(dd, p) == 0) {
71                         part = p;
72                         dd->log2blksz = LOG2(dd->blksz);
73                         break;
74                 }
75         }
76         if (!part) {
77                 printf("** No valid partition on device %s %d **\n",
78                         ifname, devno);
79                 ret = -1;
80                 goto cleanup;
81         }
82         snprintf(dev_part_str, sizeof(dev_part_str), "%d:%d", devno, part);
83         fs_set_blk_dev(ifname, dev_part_str, fstype);
84         ret = part;
85         *dev_desc = dd;
86
87 cleanup:
88         free(dup_str);
89         return ret;
90 }
91
92 static int karo_mmc_find_part(struct mmc *mmc, const char *part, int devno,
93                         disk_partition_t *part_info)
94 {
95         int ret;
96         block_dev_desc_t *mmc_dev;
97
98 #if defined(CONFIG_SYS_DTB_OFFSET) && defined(CONFIG_SYS_MMC_ENV_PART)
99         if (strcmp(part, "dtb") == 0) {
100                 const int partnum = CONFIG_SYS_MMC_ENV_PART;
101
102                 part_info->blksz = mmc->read_bl_len;
103                 part_info->start = CONFIG_SYS_DTB_OFFSET / part_info->blksz;
104                 part_info->size = CONFIG_SYS_DTB_PART_SIZE / part_info->blksz;
105                 printf("Using virtual partition %s(%d) ["LBAF".."LBAF"]\n",
106                         part, partnum, part_info->start,
107                         part_info->start + part_info->size - 1);
108                 return partnum;
109         }
110 #endif
111         ret = find_partitions("mmc", devno, FS_TYPE_FAT, &mmc_dev, part_info);
112         if (ret < 0) {
113                 printf("No (e)MMC partition found: %d\n", ret);
114                 return ret;
115         }
116         return 0;
117 }
118
119 int karo_load_mmc_part(const char *part, void *addr, size_t len)
120 {
121         int ret;
122         struct mmc *mmc;
123         disk_partition_t part_info;
124         int devno = CONFIG_SYS_MMC_ENV_DEV;
125         lbaint_t blk_cnt;
126         int partnum;
127
128         mmc = find_mmc_device(devno);
129         if (!mmc) {
130                 printf("Failed to find mmc%u\n", devno);
131                 return -ENODEV;
132         }
133
134         if (mmc_init(mmc)) {
135                 printf("Failed to init MMC device %d\n", devno);
136                 return -EIO;
137         }
138
139         blk_cnt = DIV_ROUND_UP(len, mmc->read_bl_len);
140
141         partnum = karo_mmc_find_part(mmc, part, devno, &part_info);
142         if (partnum > 0) {
143                 if (part_info.start + blk_cnt < part_info.start) {
144                         printf("%s: given length 0x%08x exceeds size of partition\n",
145                                 __func__, len);
146                         return -EINVAL;
147                 }
148                 if (part_info.start + blk_cnt > mmc->block_dev.lba)
149                         blk_cnt = mmc->block_dev.lba - part_info.start;
150
151                 mmc_switch_part(devno, partnum);
152
153                 memset(addr, 0xee, len);
154
155                 debug("Reading 0x"LBAF" blks from MMC partition %d offset 0x"LBAF" to %p\n",
156                         blk_cnt, partnum, part_info.start, addr);
157                 ret = mmc->block_dev.block_read(devno, part_info.start, blk_cnt, addr);
158                 if (ret == 0) {
159                         printf("Failed to read MMC partition %s\n", part);
160                         ret = -EIO;
161                         goto out;
162                 }
163                 debug("Read %u (%u) byte from partition '%s' @ offset 0x"LBAF"\n",
164                         ret * mmc->read_bl_len, len, part, part_info.start);
165         } else if (partnum == 0) {
166                 loff_t len_read;
167
168                 debug("Trying to read (%u) byte from file '%s' in mmc partition %d\n",
169                         len, part, partnum);
170                 ret = fs_read(part, (ulong)addr, 0, len, &len_read);
171                 if (ret < 0) {
172                         printf("Failed to read %u byte from %s in mmc partition %d; err: %d\n",
173                                 len, part, partnum, ret);
174                         goto out;
175                 }
176                 debug("Read %llu bytes from %s\n", len_read, part);
177         } else {
178                 ret = partnum;
179                 goto out;
180         }
181         ret = 0;
182 out:
183         if (partnum > 0)
184                 mmc_switch_part(devno, 0);
185         return ret < 0 ? ret : 0;
186 }