aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2010-05-18 10:43:04 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-05-31 00:11:47 -0400
commit8a768952ca8cb5cad98cfa343e6fb131e3bbdc3e (patch)
tree4e79a49469e6035946aa76d0168cd8c234768283
parent487d9fc5016529d7d77dfe35b666fd3a090e2953 (diff)
sh: add boot code to MMCIF driver header
This patch adds a set of MMCIF functions for the romImage boot loader that allows the kernel to be booted directly from an MMC card. Thanks to Jeremy Baker for the initial prototype. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--include/linux/mmc/sh_mmcif.h129
1 files changed, 129 insertions, 0 deletions
diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h
index e079c6beeb98..d4a2ebbdab4b 100644
--- a/include/linux/mmc/sh_mmcif.h
+++ b/include/linux/mmc/sh_mmcif.h
@@ -68,4 +68,133 @@ extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
68 writel(val, addr + reg); 68 writel(val, addr + reg);
69} 69}
70 70
71#define SH_MMCIF_BBS 512 /* boot block size */
72
73extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
74 unsigned long cmd, unsigned long arg)
75{
76 sh_mmcif_writel(base, MMCIF_CE_INT, 0);
77 sh_mmcif_writel(base, MMCIF_CE_ARG, arg);
78 sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd);
79}
80
81extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
82{
83 unsigned long tmp;
84 int cnt;
85
86 for (cnt = 0; cnt < 1000000; cnt++) {
87 tmp = sh_mmcif_readl(base, MMCIF_CE_INT);
88 if (tmp & mask) {
89 sh_mmcif_writel(base, MMCIF_CE_INT, tmp & ~mask);
90 return 0;
91 }
92 }
93
94 return -1;
95}
96
97extern inline int sh_mmcif_boot_cmd(void __iomem *base,
98 unsigned long cmd, unsigned long arg)
99{
100 sh_mmcif_boot_cmd_send(base, cmd, arg);
101 return sh_mmcif_boot_cmd_poll(base, 0x00010000);
102}
103
104extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
105 unsigned int block_nr,
106 unsigned long *buf)
107{
108 int k;
109
110 /* CMD13 - Status */
111 sh_mmcif_boot_cmd(base, 0x0d400000, 0x00010000);
112
113 if (sh_mmcif_readl(base, MMCIF_CE_RESP0) != 0x0900)
114 return -1;
115
116 /* CMD17 - Read */
117 sh_mmcif_boot_cmd(base, 0x11480000, block_nr * SH_MMCIF_BBS);
118 if (sh_mmcif_boot_cmd_poll(base, 0x00100000) < 0)
119 return -1;
120
121 for (k = 0; k < (SH_MMCIF_BBS / 4); k++)
122 buf[k] = sh_mmcif_readl(base, MMCIF_CE_DATA);
123
124 return 0;
125}
126
127extern inline int sh_mmcif_boot_do_read(void __iomem *base,
128 unsigned long first_block,
129 unsigned long nr_blocks,
130 void *buf)
131{
132 unsigned long k;
133 int ret = 0;
134
135 /* CMD16 - Set the block size */
136 sh_mmcif_boot_cmd(base, 0x10400000, SH_MMCIF_BBS);
137
138 for (k = 0; !ret && k < nr_blocks; k++)
139 ret = sh_mmcif_boot_do_read_single(base, first_block + k,
140 buf + (k * SH_MMCIF_BBS));
141
142 return ret;
143}
144
145extern inline void sh_mmcif_boot_init(void __iomem *base)
146{
147 unsigned long tmp;
148
149 /* reset */
150 tmp = sh_mmcif_readl(base, MMCIF_CE_VERSION);
151 sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp | 0x80000000);
152 sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp & ~0x80000000);
153
154 /* byte swap */
155 sh_mmcif_writel(base, MMCIF_CE_BUF_ACC, 0x00010000);
156
157 /* Set block size in MMCIF hardware */
158 sh_mmcif_writel(base, MMCIF_CE_BLOCK_SET, SH_MMCIF_BBS);
159
160 /* Enable the clock, set it to Bus clock/256 (about 325Khz)*/
161 sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01072fff);
162
163 /* CMD0 */
164 sh_mmcif_boot_cmd(base, 0x00000040, 0);
165
166 /* CMD1 - Get OCR */
167 do {
168 sh_mmcif_boot_cmd(base, 0x01405040, 0x40300000); /* CMD1 */
169 } while ((sh_mmcif_readl(base, MMCIF_CE_RESP0) & 0x80000000)
170 != 0x80000000);
171
172 /* CMD2 - Get CID */
173 sh_mmcif_boot_cmd(base, 0x02806040, 0);
174
175 /* CMD3 - Set card relative address */
176 sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000);
177}
178
179extern inline void sh_mmcif_boot_slurp(void __iomem *base,
180 unsigned char *buf,
181 unsigned long no_bytes)
182{
183 unsigned long tmp;
184
185 /* In data transfer mode: Set clock to Bus clock/4 (about 20Mhz) */
186 sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01012fff);
187
188 /* CMD9 - Get CSD */
189 sh_mmcif_boot_cmd(base, 0x09806000, 0x00010000);
190
191 /* CMD7 - Select the card */
192 sh_mmcif_boot_cmd(base, 0x07400000, 0x00010000);
193
194 tmp = no_bytes / SH_MMCIF_BBS;
195 tmp += (no_bytes % SH_MMCIF_BBS) ? 1 : 0;
196
197 sh_mmcif_boot_do_read(base, 512, tmp, buf);
198}
199
71#endif /* __SH_MMCIF_H__ */ 200#endif /* __SH_MMCIF_H__ */