]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/common/mmc.c
karo: tx6: Finalize support for TX6Q-1020
[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
46         dd = get_dev(ifname, devno);
47         if (!dd || dd->type == DEV_TYPE_UNKNOWN) {
48                 printf("** Bad device %s %d **\n", ifname, devno);
49                 return -1;
50         }
51         init_part(dd);
52
53         /*
54          * No partition table on device,
55          * or user requested partition 0 (entire device).
56          */
57         if (dd->part_type == PART_TYPE_UNKNOWN) {
58                 printf("** No partition table on device %s %d **\n",
59                         ifname, devno);
60                 goto cleanup;
61         }
62
63         part = 0;
64         for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
65                 ret = get_partition_info(dd, p, info);
66                 if (ret)
67                         continue;
68
69                 if (fat_register_device(dd, p) == 0) {
70                         part = p;
71                         dd->log2blksz = LOG2(dd->blksz);
72                         break;
73                 }
74         }
75         if (!part) {
76                 printf("** No valid partition on device %s %d **\n",
77                         ifname, devno);
78                 ret = -1;
79                 goto cleanup;
80         }
81
82         ret = part;
83         *dev_desc = dd;
84
85 cleanup:
86         free(dup_str);
87         return ret;
88 }
89
90 static int karo_mmc_find_part(struct mmc *mmc, const char *part, int devno,
91                         disk_partition_t *part_info)
92 {
93         int ret;
94         block_dev_desc_t *mmc_dev;
95
96         if (strcmp(part, "dtb") == 0) {
97                 const int partnum = CONFIG_SYS_MMC_ENV_PART;
98
99                 part_info->blksz = mmc->read_bl_len;
100                 part_info->start = CONFIG_SYS_DTB_OFFSET / part_info->blksz;
101                 part_info->size = CONFIG_SYS_DTB_PART_SIZE / part_info->blksz;
102                 printf("Using virtual partition %s(%d) ["LBAF".."LBAF"]\n",
103                         part, partnum, part_info->start,
104                         part_info->start + part_info->size - 1);
105                 return partnum;
106         }
107
108         ret = find_partitions("mmc", devno, FS_TYPE_FAT, &mmc_dev, part_info);
109         if (ret < 0) {
110                 printf("No eMMC partition found: %d\n", ret);
111                 return ret;
112         }
113         return 0;
114 }
115
116 int karo_load_mmc_part(const char *part, void *addr, size_t len)
117 {
118         int ret;
119         struct mmc *mmc;
120         disk_partition_t part_info;
121         int devno = CONFIG_MMC_BOOT_DEV;
122         lbaint_t blk_cnt;
123         int partnum;
124
125         mmc = find_mmc_device(devno);
126         if (!mmc) {
127                 printf("Failed to find mmc%u\n", devno);
128                 return -ENODEV;
129         }
130
131         if (mmc_init(mmc)) {
132                 printf("Failed to init MMC device %d\n", devno);
133                 return -EIO;
134         }
135
136         blk_cnt = DIV_ROUND_UP(len, mmc->read_bl_len);
137
138         partnum = karo_mmc_find_part(mmc, part, devno, &part_info);
139         if (partnum > 0) {
140                 if (part_info.start + blk_cnt < part_info.start) {
141                         printf("%s: given length 0x%08x exceeds size of partition\n",
142                                 __func__, len);
143                         return -EINVAL;
144                 }
145                 if (part_info.start + blk_cnt > mmc->block_dev.lba)
146                         blk_cnt = mmc->block_dev.lba - part_info.start;
147
148                 mmc_switch_part(devno, partnum);
149
150                 memset(addr, 0xee, len);
151
152                 debug("Reading 0x"LBAF" blks from MMC partition %d offset 0x"LBAF" to %p\n",
153                         blk_cnt, partnum, part_info.start, addr);
154                 ret = mmc->block_dev.block_read(devno, part_info.start, blk_cnt, addr);
155                 if (ret == 0) {
156                         printf("Failed to read MMC partition %s\n", part);
157                         ret = -EIO;
158                         goto out;
159                 }
160                 debug("Read %u (%u) byte from partition '%s' @ offset 0x"LBAF"\n",
161                         ret * mmc->read_bl_len, len, part, part_info.start);
162         } else if (partnum == 0) {
163                 int len_read;
164
165                 printf("Reading file %s from mmc partition %d\n", part, 0);
166                 len_read = fs_read(part, (ulong)addr, 0, len);
167                 if (len_read < len) {
168                         printf("Read only %u of %u bytes\n", len_read, len);
169                 }
170         } else {
171                 ret = partnum;
172                 goto out;
173         }
174         ret = 0;
175 out:
176         if (partnum > 0)
177                 mmc_switch_part(devno, 0);
178         return ret < 0 ? ret : 0;
179 }