Commit 6ace153d130f528b88117b1edcfe017ea1852d67
Committed by
Pantelis Antoniou
1 parent
dae0f5c644
Exists in
v2017.01-smarct4x
and in
37 other branches
mmc/dw_mmc: Fix clock divider calculation error for bypass mode
To fix the clock divider calculation error when the controller clock same as the operating frequency. This is known as bypass mode. In this mode, the divider should be 0. Signed-off-by: Chin Liang See <clsee@altera.com> Cc: Pantelis Antoniou <panto@antoniou-consulting.com> Cc: Rajeshwari Shinde <rajeshwari.s@samsung.com> Cc: Jaehoon Chung <jh80.chung@samsung.com> Cc: Mischa Jonker <mjonker@synopsys.com>
Showing 1 changed file with 4 additions and 1 deletions Inline Diff
drivers/mmc/dw_mmc.c
1 | /* | 1 | /* |
2 | * (C) Copyright 2012 SAMSUNG Electronics | 2 | * (C) Copyright 2012 SAMSUNG Electronics |
3 | * Jaehoon Chung <jh80.chung@samsung.com> | 3 | * Jaehoon Chung <jh80.chung@samsung.com> |
4 | * Rajeshawari Shinde <rajeshwari.s@samsung.com> | 4 | * Rajeshawari Shinde <rajeshwari.s@samsung.com> |
5 | * | 5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <bouncebuf.h> | 9 | #include <bouncebuf.h> |
10 | #include <common.h> | 10 | #include <common.h> |
11 | #include <malloc.h> | 11 | #include <malloc.h> |
12 | #include <mmc.h> | 12 | #include <mmc.h> |
13 | #include <dwmmc.h> | 13 | #include <dwmmc.h> |
14 | #include <asm-generic/errno.h> | 14 | #include <asm-generic/errno.h> |
15 | 15 | ||
16 | #define PAGE_SIZE 4096 | 16 | #define PAGE_SIZE 4096 |
17 | 17 | ||
18 | static int dwmci_wait_reset(struct dwmci_host *host, u32 value) | 18 | static int dwmci_wait_reset(struct dwmci_host *host, u32 value) |
19 | { | 19 | { |
20 | unsigned long timeout = 1000; | 20 | unsigned long timeout = 1000; |
21 | u32 ctrl; | 21 | u32 ctrl; |
22 | 22 | ||
23 | dwmci_writel(host, DWMCI_CTRL, value); | 23 | dwmci_writel(host, DWMCI_CTRL, value); |
24 | 24 | ||
25 | while (timeout--) { | 25 | while (timeout--) { |
26 | ctrl = dwmci_readl(host, DWMCI_CTRL); | 26 | ctrl = dwmci_readl(host, DWMCI_CTRL); |
27 | if (!(ctrl & DWMCI_RESET_ALL)) | 27 | if (!(ctrl & DWMCI_RESET_ALL)) |
28 | return 1; | 28 | return 1; |
29 | } | 29 | } |
30 | return 0; | 30 | return 0; |
31 | } | 31 | } |
32 | 32 | ||
33 | static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, | 33 | static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, |
34 | u32 desc0, u32 desc1, u32 desc2) | 34 | u32 desc0, u32 desc1, u32 desc2) |
35 | { | 35 | { |
36 | struct dwmci_idmac *desc = idmac; | 36 | struct dwmci_idmac *desc = idmac; |
37 | 37 | ||
38 | desc->flags = desc0; | 38 | desc->flags = desc0; |
39 | desc->cnt = desc1; | 39 | desc->cnt = desc1; |
40 | desc->addr = desc2; | 40 | desc->addr = desc2; |
41 | desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); | 41 | desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); |
42 | } | 42 | } |
43 | 43 | ||
44 | static void dwmci_prepare_data(struct dwmci_host *host, | 44 | static void dwmci_prepare_data(struct dwmci_host *host, |
45 | struct mmc_data *data, | 45 | struct mmc_data *data, |
46 | struct dwmci_idmac *cur_idmac, | 46 | struct dwmci_idmac *cur_idmac, |
47 | void *bounce_buffer) | 47 | void *bounce_buffer) |
48 | { | 48 | { |
49 | unsigned long ctrl; | 49 | unsigned long ctrl; |
50 | unsigned int i = 0, flags, cnt, blk_cnt; | 50 | unsigned int i = 0, flags, cnt, blk_cnt; |
51 | ulong data_start, data_end; | 51 | ulong data_start, data_end; |
52 | 52 | ||
53 | 53 | ||
54 | blk_cnt = data->blocks; | 54 | blk_cnt = data->blocks; |
55 | 55 | ||
56 | dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); | 56 | dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); |
57 | 57 | ||
58 | data_start = (ulong)cur_idmac; | 58 | data_start = (ulong)cur_idmac; |
59 | dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); | 59 | dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); |
60 | 60 | ||
61 | do { | 61 | do { |
62 | flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; | 62 | flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; |
63 | flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; | 63 | flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; |
64 | if (blk_cnt <= 8) { | 64 | if (blk_cnt <= 8) { |
65 | flags |= DWMCI_IDMAC_LD; | 65 | flags |= DWMCI_IDMAC_LD; |
66 | cnt = data->blocksize * blk_cnt; | 66 | cnt = data->blocksize * blk_cnt; |
67 | } else | 67 | } else |
68 | cnt = data->blocksize * 8; | 68 | cnt = data->blocksize * 8; |
69 | 69 | ||
70 | dwmci_set_idma_desc(cur_idmac, flags, cnt, | 70 | dwmci_set_idma_desc(cur_idmac, flags, cnt, |
71 | (u32)bounce_buffer + (i * PAGE_SIZE)); | 71 | (u32)bounce_buffer + (i * PAGE_SIZE)); |
72 | 72 | ||
73 | if (blk_cnt <= 8) | 73 | if (blk_cnt <= 8) |
74 | break; | 74 | break; |
75 | blk_cnt -= 8; | 75 | blk_cnt -= 8; |
76 | cur_idmac++; | 76 | cur_idmac++; |
77 | i++; | 77 | i++; |
78 | } while(1); | 78 | } while(1); |
79 | 79 | ||
80 | data_end = (ulong)cur_idmac; | 80 | data_end = (ulong)cur_idmac; |
81 | flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); | 81 | flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); |
82 | 82 | ||
83 | ctrl = dwmci_readl(host, DWMCI_CTRL); | 83 | ctrl = dwmci_readl(host, DWMCI_CTRL); |
84 | ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; | 84 | ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; |
85 | dwmci_writel(host, DWMCI_CTRL, ctrl); | 85 | dwmci_writel(host, DWMCI_CTRL, ctrl); |
86 | 86 | ||
87 | ctrl = dwmci_readl(host, DWMCI_BMOD); | 87 | ctrl = dwmci_readl(host, DWMCI_BMOD); |
88 | ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; | 88 | ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; |
89 | dwmci_writel(host, DWMCI_BMOD, ctrl); | 89 | dwmci_writel(host, DWMCI_BMOD, ctrl); |
90 | 90 | ||
91 | dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); | 91 | dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); |
92 | dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); | 92 | dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); |
93 | } | 93 | } |
94 | 94 | ||
95 | static int dwmci_set_transfer_mode(struct dwmci_host *host, | 95 | static int dwmci_set_transfer_mode(struct dwmci_host *host, |
96 | struct mmc_data *data) | 96 | struct mmc_data *data) |
97 | { | 97 | { |
98 | unsigned long mode; | 98 | unsigned long mode; |
99 | 99 | ||
100 | mode = DWMCI_CMD_DATA_EXP; | 100 | mode = DWMCI_CMD_DATA_EXP; |
101 | if (data->flags & MMC_DATA_WRITE) | 101 | if (data->flags & MMC_DATA_WRITE) |
102 | mode |= DWMCI_CMD_RW; | 102 | mode |= DWMCI_CMD_RW; |
103 | 103 | ||
104 | return mode; | 104 | return mode; |
105 | } | 105 | } |
106 | 106 | ||
107 | static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | 107 | static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
108 | struct mmc_data *data) | 108 | struct mmc_data *data) |
109 | { | 109 | { |
110 | struct dwmci_host *host = mmc->priv; | 110 | struct dwmci_host *host = mmc->priv; |
111 | ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, | 111 | ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, |
112 | data ? DIV_ROUND_UP(data->blocks, 8) : 0); | 112 | data ? DIV_ROUND_UP(data->blocks, 8) : 0); |
113 | int flags = 0, i; | 113 | int flags = 0, i; |
114 | unsigned int timeout = 100000; | 114 | unsigned int timeout = 100000; |
115 | u32 retry = 10000; | 115 | u32 retry = 10000; |
116 | u32 mask, ctrl; | 116 | u32 mask, ctrl; |
117 | ulong start = get_timer(0); | 117 | ulong start = get_timer(0); |
118 | struct bounce_buffer bbstate; | 118 | struct bounce_buffer bbstate; |
119 | 119 | ||
120 | while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { | 120 | while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { |
121 | if (get_timer(start) > timeout) { | 121 | if (get_timer(start) > timeout) { |
122 | printf("Timeout on data busy\n"); | 122 | printf("Timeout on data busy\n"); |
123 | return TIMEOUT; | 123 | return TIMEOUT; |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); | 127 | dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); |
128 | 128 | ||
129 | if (data) { | 129 | if (data) { |
130 | if (data->flags == MMC_DATA_READ) { | 130 | if (data->flags == MMC_DATA_READ) { |
131 | bounce_buffer_start(&bbstate, (void*)data->dest, | 131 | bounce_buffer_start(&bbstate, (void*)data->dest, |
132 | data->blocksize * | 132 | data->blocksize * |
133 | data->blocks, GEN_BB_WRITE); | 133 | data->blocks, GEN_BB_WRITE); |
134 | } else { | 134 | } else { |
135 | bounce_buffer_start(&bbstate, (void*)data->src, | 135 | bounce_buffer_start(&bbstate, (void*)data->src, |
136 | data->blocksize * | 136 | data->blocksize * |
137 | data->blocks, GEN_BB_READ); | 137 | data->blocks, GEN_BB_READ); |
138 | } | 138 | } |
139 | dwmci_prepare_data(host, data, cur_idmac, | 139 | dwmci_prepare_data(host, data, cur_idmac, |
140 | bbstate.bounce_buffer); | 140 | bbstate.bounce_buffer); |
141 | } | 141 | } |
142 | 142 | ||
143 | dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); | 143 | dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); |
144 | 144 | ||
145 | if (data) | 145 | if (data) |
146 | flags = dwmci_set_transfer_mode(host, data); | 146 | flags = dwmci_set_transfer_mode(host, data); |
147 | 147 | ||
148 | if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) | 148 | if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) |
149 | return -1; | 149 | return -1; |
150 | 150 | ||
151 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) | 151 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) |
152 | flags |= DWMCI_CMD_ABORT_STOP; | 152 | flags |= DWMCI_CMD_ABORT_STOP; |
153 | else | 153 | else |
154 | flags |= DWMCI_CMD_PRV_DAT_WAIT; | 154 | flags |= DWMCI_CMD_PRV_DAT_WAIT; |
155 | 155 | ||
156 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 156 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
157 | flags |= DWMCI_CMD_RESP_EXP; | 157 | flags |= DWMCI_CMD_RESP_EXP; |
158 | if (cmd->resp_type & MMC_RSP_136) | 158 | if (cmd->resp_type & MMC_RSP_136) |
159 | flags |= DWMCI_CMD_RESP_LENGTH; | 159 | flags |= DWMCI_CMD_RESP_LENGTH; |
160 | } | 160 | } |
161 | 161 | ||
162 | if (cmd->resp_type & MMC_RSP_CRC) | 162 | if (cmd->resp_type & MMC_RSP_CRC) |
163 | flags |= DWMCI_CMD_CHECK_CRC; | 163 | flags |= DWMCI_CMD_CHECK_CRC; |
164 | 164 | ||
165 | flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); | 165 | flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); |
166 | 166 | ||
167 | debug("Sending CMD%d\n",cmd->cmdidx); | 167 | debug("Sending CMD%d\n",cmd->cmdidx); |
168 | 168 | ||
169 | dwmci_writel(host, DWMCI_CMD, flags); | 169 | dwmci_writel(host, DWMCI_CMD, flags); |
170 | 170 | ||
171 | for (i = 0; i < retry; i++) { | 171 | for (i = 0; i < retry; i++) { |
172 | mask = dwmci_readl(host, DWMCI_RINTSTS); | 172 | mask = dwmci_readl(host, DWMCI_RINTSTS); |
173 | if (mask & DWMCI_INTMSK_CDONE) { | 173 | if (mask & DWMCI_INTMSK_CDONE) { |
174 | if (!data) | 174 | if (!data) |
175 | dwmci_writel(host, DWMCI_RINTSTS, mask); | 175 | dwmci_writel(host, DWMCI_RINTSTS, mask); |
176 | break; | 176 | break; |
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
180 | if (i == retry) | 180 | if (i == retry) |
181 | return TIMEOUT; | 181 | return TIMEOUT; |
182 | 182 | ||
183 | if (mask & DWMCI_INTMSK_RTO) { | 183 | if (mask & DWMCI_INTMSK_RTO) { |
184 | debug("Response Timeout..\n"); | 184 | debug("Response Timeout..\n"); |
185 | return TIMEOUT; | 185 | return TIMEOUT; |
186 | } else if (mask & DWMCI_INTMSK_RE) { | 186 | } else if (mask & DWMCI_INTMSK_RE) { |
187 | debug("Response Error..\n"); | 187 | debug("Response Error..\n"); |
188 | return -1; | 188 | return -1; |
189 | } | 189 | } |
190 | 190 | ||
191 | 191 | ||
192 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 192 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
193 | if (cmd->resp_type & MMC_RSP_136) { | 193 | if (cmd->resp_type & MMC_RSP_136) { |
194 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); | 194 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); |
195 | cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); | 195 | cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); |
196 | cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); | 196 | cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); |
197 | cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); | 197 | cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); |
198 | } else { | 198 | } else { |
199 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); | 199 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); |
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | if (data) { | 203 | if (data) { |
204 | do { | 204 | do { |
205 | mask = dwmci_readl(host, DWMCI_RINTSTS); | 205 | mask = dwmci_readl(host, DWMCI_RINTSTS); |
206 | if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { | 206 | if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { |
207 | debug("DATA ERROR!\n"); | 207 | debug("DATA ERROR!\n"); |
208 | return -1; | 208 | return -1; |
209 | } | 209 | } |
210 | } while (!(mask & DWMCI_INTMSK_DTO)); | 210 | } while (!(mask & DWMCI_INTMSK_DTO)); |
211 | 211 | ||
212 | dwmci_writel(host, DWMCI_RINTSTS, mask); | 212 | dwmci_writel(host, DWMCI_RINTSTS, mask); |
213 | 213 | ||
214 | ctrl = dwmci_readl(host, DWMCI_CTRL); | 214 | ctrl = dwmci_readl(host, DWMCI_CTRL); |
215 | ctrl &= ~(DWMCI_DMA_EN); | 215 | ctrl &= ~(DWMCI_DMA_EN); |
216 | dwmci_writel(host, DWMCI_CTRL, ctrl); | 216 | dwmci_writel(host, DWMCI_CTRL, ctrl); |
217 | 217 | ||
218 | bounce_buffer_stop(&bbstate); | 218 | bounce_buffer_stop(&bbstate); |
219 | } | 219 | } |
220 | 220 | ||
221 | udelay(100); | 221 | udelay(100); |
222 | 222 | ||
223 | return 0; | 223 | return 0; |
224 | } | 224 | } |
225 | 225 | ||
226 | static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) | 226 | static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) |
227 | { | 227 | { |
228 | u32 div, status; | 228 | u32 div, status; |
229 | int timeout = 10000; | 229 | int timeout = 10000; |
230 | unsigned long sclk; | 230 | unsigned long sclk; |
231 | 231 | ||
232 | if ((freq == host->clock) || (freq == 0)) | 232 | if ((freq == host->clock) || (freq == 0)) |
233 | return 0; | 233 | return 0; |
234 | /* | 234 | /* |
235 | * If host->get_mmc_clk didn't define, | 235 | * If host->get_mmc_clk didn't define, |
236 | * then assume that host->bus_hz is source clock value. | 236 | * then assume that host->bus_hz is source clock value. |
237 | * host->bus_hz should be set from user. | 237 | * host->bus_hz should be set from user. |
238 | */ | 238 | */ |
239 | if (host->get_mmc_clk) | 239 | if (host->get_mmc_clk) |
240 | sclk = host->get_mmc_clk(host); | 240 | sclk = host->get_mmc_clk(host); |
241 | else if (host->bus_hz) | 241 | else if (host->bus_hz) |
242 | sclk = host->bus_hz; | 242 | sclk = host->bus_hz; |
243 | else { | 243 | else { |
244 | printf("Didn't get source clock value..\n"); | 244 | printf("Didn't get source clock value..\n"); |
245 | return -EINVAL; | 245 | return -EINVAL; |
246 | } | 246 | } |
247 | 247 | ||
248 | div = DIV_ROUND_UP(sclk, 2 * freq); | 248 | if (sclk == freq) |
249 | div = 0; /* bypass mode */ | ||
250 | else | ||
251 | div = DIV_ROUND_UP(sclk, 2 * freq); | ||
249 | 252 | ||
250 | dwmci_writel(host, DWMCI_CLKENA, 0); | 253 | dwmci_writel(host, DWMCI_CLKENA, 0); |
251 | dwmci_writel(host, DWMCI_CLKSRC, 0); | 254 | dwmci_writel(host, DWMCI_CLKSRC, 0); |
252 | 255 | ||
253 | dwmci_writel(host, DWMCI_CLKDIV, div); | 256 | dwmci_writel(host, DWMCI_CLKDIV, div); |
254 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | | 257 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
255 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); | 258 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
256 | 259 | ||
257 | do { | 260 | do { |
258 | status = dwmci_readl(host, DWMCI_CMD); | 261 | status = dwmci_readl(host, DWMCI_CMD); |
259 | if (timeout-- < 0) { | 262 | if (timeout-- < 0) { |
260 | printf("TIMEOUT error!!\n"); | 263 | printf("TIMEOUT error!!\n"); |
261 | return -ETIMEDOUT; | 264 | return -ETIMEDOUT; |
262 | } | 265 | } |
263 | } while (status & DWMCI_CMD_START); | 266 | } while (status & DWMCI_CMD_START); |
264 | 267 | ||
265 | dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | | 268 | dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | |
266 | DWMCI_CLKEN_LOW_PWR); | 269 | DWMCI_CLKEN_LOW_PWR); |
267 | 270 | ||
268 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | | 271 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
269 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); | 272 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
270 | 273 | ||
271 | timeout = 10000; | 274 | timeout = 10000; |
272 | do { | 275 | do { |
273 | status = dwmci_readl(host, DWMCI_CMD); | 276 | status = dwmci_readl(host, DWMCI_CMD); |
274 | if (timeout-- < 0) { | 277 | if (timeout-- < 0) { |
275 | printf("TIMEOUT error!!\n"); | 278 | printf("TIMEOUT error!!\n"); |
276 | return -ETIMEDOUT; | 279 | return -ETIMEDOUT; |
277 | } | 280 | } |
278 | } while (status & DWMCI_CMD_START); | 281 | } while (status & DWMCI_CMD_START); |
279 | 282 | ||
280 | host->clock = freq; | 283 | host->clock = freq; |
281 | 284 | ||
282 | return 0; | 285 | return 0; |
283 | } | 286 | } |
284 | 287 | ||
285 | static void dwmci_set_ios(struct mmc *mmc) | 288 | static void dwmci_set_ios(struct mmc *mmc) |
286 | { | 289 | { |
287 | struct dwmci_host *host = (struct dwmci_host *)mmc->priv; | 290 | struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
288 | u32 ctype, regs; | 291 | u32 ctype, regs; |
289 | 292 | ||
290 | debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); | 293 | debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); |
291 | 294 | ||
292 | dwmci_setup_bus(host, mmc->clock); | 295 | dwmci_setup_bus(host, mmc->clock); |
293 | switch (mmc->bus_width) { | 296 | switch (mmc->bus_width) { |
294 | case 8: | 297 | case 8: |
295 | ctype = DWMCI_CTYPE_8BIT; | 298 | ctype = DWMCI_CTYPE_8BIT; |
296 | break; | 299 | break; |
297 | case 4: | 300 | case 4: |
298 | ctype = DWMCI_CTYPE_4BIT; | 301 | ctype = DWMCI_CTYPE_4BIT; |
299 | break; | 302 | break; |
300 | default: | 303 | default: |
301 | ctype = DWMCI_CTYPE_1BIT; | 304 | ctype = DWMCI_CTYPE_1BIT; |
302 | break; | 305 | break; |
303 | } | 306 | } |
304 | 307 | ||
305 | dwmci_writel(host, DWMCI_CTYPE, ctype); | 308 | dwmci_writel(host, DWMCI_CTYPE, ctype); |
306 | 309 | ||
307 | regs = dwmci_readl(host, DWMCI_UHS_REG); | 310 | regs = dwmci_readl(host, DWMCI_UHS_REG); |
308 | if (mmc->card_caps & MMC_MODE_DDR_52MHz) | 311 | if (mmc->card_caps & MMC_MODE_DDR_52MHz) |
309 | regs |= DWMCI_DDR_MODE; | 312 | regs |= DWMCI_DDR_MODE; |
310 | else | 313 | else |
311 | regs &= DWMCI_DDR_MODE; | 314 | regs &= DWMCI_DDR_MODE; |
312 | 315 | ||
313 | dwmci_writel(host, DWMCI_UHS_REG, regs); | 316 | dwmci_writel(host, DWMCI_UHS_REG, regs); |
314 | 317 | ||
315 | if (host->clksel) | 318 | if (host->clksel) |
316 | host->clksel(host); | 319 | host->clksel(host); |
317 | } | 320 | } |
318 | 321 | ||
319 | static int dwmci_init(struct mmc *mmc) | 322 | static int dwmci_init(struct mmc *mmc) |
320 | { | 323 | { |
321 | struct dwmci_host *host = mmc->priv; | 324 | struct dwmci_host *host = mmc->priv; |
322 | 325 | ||
323 | if (host->board_init) | 326 | if (host->board_init) |
324 | host->board_init(host); | 327 | host->board_init(host); |
325 | 328 | ||
326 | dwmci_writel(host, DWMCI_PWREN, 1); | 329 | dwmci_writel(host, DWMCI_PWREN, 1); |
327 | 330 | ||
328 | if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { | 331 | if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { |
329 | debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); | 332 | debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); |
330 | return -1; | 333 | return -1; |
331 | } | 334 | } |
332 | 335 | ||
333 | /* Enumerate at 400KHz */ | 336 | /* Enumerate at 400KHz */ |
334 | dwmci_setup_bus(host, mmc->cfg->f_min); | 337 | dwmci_setup_bus(host, mmc->cfg->f_min); |
335 | 338 | ||
336 | dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); | 339 | dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); |
337 | dwmci_writel(host, DWMCI_INTMASK, 0); | 340 | dwmci_writel(host, DWMCI_INTMASK, 0); |
338 | 341 | ||
339 | dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); | 342 | dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); |
340 | 343 | ||
341 | dwmci_writel(host, DWMCI_IDINTEN, 0); | 344 | dwmci_writel(host, DWMCI_IDINTEN, 0); |
342 | dwmci_writel(host, DWMCI_BMOD, 1); | 345 | dwmci_writel(host, DWMCI_BMOD, 1); |
343 | 346 | ||
344 | if (host->fifoth_val) { | 347 | if (host->fifoth_val) { |
345 | dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); | 348 | dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); |
346 | } | 349 | } |
347 | 350 | ||
348 | dwmci_writel(host, DWMCI_CLKENA, 0); | 351 | dwmci_writel(host, DWMCI_CLKENA, 0); |
349 | dwmci_writel(host, DWMCI_CLKSRC, 0); | 352 | dwmci_writel(host, DWMCI_CLKSRC, 0); |
350 | 353 | ||
351 | return 0; | 354 | return 0; |
352 | } | 355 | } |
353 | 356 | ||
354 | static const struct mmc_ops dwmci_ops = { | 357 | static const struct mmc_ops dwmci_ops = { |
355 | .send_cmd = dwmci_send_cmd, | 358 | .send_cmd = dwmci_send_cmd, |
356 | .set_ios = dwmci_set_ios, | 359 | .set_ios = dwmci_set_ios, |
357 | .init = dwmci_init, | 360 | .init = dwmci_init, |
358 | }; | 361 | }; |
359 | 362 | ||
360 | int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) | 363 | int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) |
361 | { | 364 | { |
362 | host->cfg.name = host->name; | 365 | host->cfg.name = host->name; |
363 | host->cfg.ops = &dwmci_ops; | 366 | host->cfg.ops = &dwmci_ops; |
364 | host->cfg.f_min = min_clk; | 367 | host->cfg.f_min = min_clk; |
365 | host->cfg.f_max = max_clk; | 368 | host->cfg.f_max = max_clk; |
366 | 369 | ||
367 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | 370 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
368 | 371 | ||
369 | host->cfg.host_caps = host->caps; | 372 | host->cfg.host_caps = host->caps; |
370 | 373 | ||
371 | if (host->buswidth == 8) { | 374 | if (host->buswidth == 8) { |
372 | host->cfg.host_caps |= MMC_MODE_8BIT; | 375 | host->cfg.host_caps |= MMC_MODE_8BIT; |
373 | host->cfg.host_caps &= ~MMC_MODE_4BIT; | 376 | host->cfg.host_caps &= ~MMC_MODE_4BIT; |
374 | } else { | 377 | } else { |
375 | host->cfg.host_caps |= MMC_MODE_4BIT; | 378 | host->cfg.host_caps |= MMC_MODE_4BIT; |
376 | host->cfg.host_caps &= ~MMC_MODE_8BIT; | 379 | host->cfg.host_caps &= ~MMC_MODE_8BIT; |
377 | } | 380 | } |
378 | host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; | 381 | host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; |
379 | 382 | ||
380 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 383 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
381 | 384 | ||
382 | host->mmc = mmc_create(&host->cfg, host); | 385 | host->mmc = mmc_create(&host->cfg, host); |
383 | if (host->mmc == NULL) | 386 | if (host->mmc == NULL) |
384 | return -1; | 387 | return -1; |
385 | 388 | ||
386 | return 0; | 389 | return 0; |
387 | } | 390 | } |
388 | 391 |