powerpc: mpc85xx: Support booting from SD Card with SPL
[platform/kernel/u-boot.git] / drivers / mmc / fsl_esdhc_spl.c
1 /*
2  * Copyright 2013 Freescale Semiconductor, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  *
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  * MA 02111-1307 USA
19  *
20  */
21
22 #include <common.h>
23 #include <mmc.h>
24 #include <malloc.h>
25
26 /*
27  * The environment variables are written to just after the u-boot image
28  * on SDCard, so we must read the MBR to get the start address and code
29  * length of the u-boot image, then calculate the address of the env.
30  */
31 #define ESDHC_BOOT_IMAGE_SIZE   0x48
32 #define ESDHC_BOOT_IMAGE_ADDR   0x50
33 #define MBRDBR_BOOT_SIG_55      0x1fe
34 #define MBRDBR_BOOT_SIG_AA      0x1ff
35 #define CONFIG_CFG_DATA_SECTOR  0
36
37 /*
38  * The main entry for mmc booting. It's necessary that SDRAM is already
39  * configured and available since this code loads the main U-Boot image
40  * from mmc into SDRAM and starts it from there.
41  */
42
43 void __noreturn mmc_boot(void)
44 {
45         __attribute__((noreturn)) void (*uboot)(void);
46         uint blk_start, blk_cnt, err;
47         u32 blklen;
48         uchar *tmp_buf;
49         uchar val;
50         uint i, byte_num;
51         u32 offset, code_len;
52         struct mmc *mmc;
53
54         mmc = find_mmc_device(0);
55         if (!mmc) {
56                 puts("spl: mmc device not found!!\n");
57                 hang();
58         }
59
60         blklen = mmc->read_bl_len;
61         tmp_buf = malloc(blklen);
62         if (!tmp_buf) {
63                 puts("spl: malloc memory failed!!\n");
64                 hang();
65         }
66         memset(tmp_buf, 0, blklen);
67
68         /*
69         * Read source addr from sd card
70         */
71         err = mmc->block_dev.block_read(0, CONFIG_CFG_DATA_SECTOR, 1, tmp_buf);
72         if (err != 1) {
73                 puts("spl: mmc read failed!!\n");
74                 free(tmp_buf);
75                 hang();
76         }
77
78         val = *(tmp_buf + MBRDBR_BOOT_SIG_55);
79         if (0x55 != val) {
80                 puts("spl: mmc signature is not valid!!\n");
81                 free(tmp_buf);
82                 hang();
83         }
84         val = *(tmp_buf + MBRDBR_BOOT_SIG_AA);
85         if (0xAA != val) {
86                 puts("spl: mmc signature is not valid!!\n");
87                 free(tmp_buf);
88                 hang();
89         }
90
91         byte_num = 4;
92         offset = 0;
93         for (i = 0; i < byte_num; i++) {
94                 val = *(tmp_buf + ESDHC_BOOT_IMAGE_ADDR + i);
95                 offset = (offset << 8) + val;
96         }
97         offset += CONFIG_SYS_MMC_U_BOOT_OFFS;
98         /* Get the code size from offset 0x48 */
99         byte_num = 4;
100         code_len = 0;
101         for (i = 0; i < byte_num; i++) {
102                 val = *(tmp_buf + ESDHC_BOOT_IMAGE_SIZE + i);
103                 code_len = (code_len << 8) + val;
104         }
105         code_len -= CONFIG_SYS_MMC_U_BOOT_OFFS;
106         /*
107         * Load U-Boot image from mmc into RAM
108         */
109         blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
110         blk_cnt = ALIGN(code_len, mmc->read_bl_len) / mmc->read_bl_len;
111         err = mmc->block_dev.block_read(0, blk_start, blk_cnt,
112                                         (uchar *)CONFIG_SYS_MMC_U_BOOT_DST);
113         if (err != blk_cnt) {
114                 puts("spl: mmc read failed!!\n");
115                 free(tmp_buf);
116                 hang();
117         }
118
119         /*
120         * Clean d-cache and invalidate i-cache, to
121         * make sure that no stale data is executed.
122         */
123         flush_cache(CONFIG_SYS_MMC_U_BOOT_DST, CONFIG_SYS_MMC_U_BOOT_SIZE);
124
125         /*
126         * Jump to U-Boot image
127         */
128         uboot = (void *)CONFIG_SYS_MMC_U_BOOT_START;
129         (*uboot)();
130 }