Commit 5a20397b007e9c1482997cf4418639e9ba3df5fe
Committed by
Pantelis Antoniou
1 parent
bd47c13583
Exists in
v2017.01-smarct4x
and in
37 other branches
mmc: remove the MMC_MODE_HC flag
High capacity support is not a host capability, but a device capability that is queried via the OCR. The flag in the operating conditions request argument can just be set unconditionally. This matches the Linux implementation. [panto] Hand merged and renumbering MMC_MODE_DDR_52MHz. Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> Cc: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
Showing 14 changed files with 12 additions and 22 deletions Inline Diff
- drivers/mmc/dw_mmc.c
- drivers/mmc/fsl_esdhc.c
- drivers/mmc/kona_sdhci.c
- drivers/mmc/mmc.c
- drivers/mmc/mvebu_mmc.c
- drivers/mmc/mxsmmc.c
- drivers/mmc/omap_hsmmc.c
- drivers/mmc/s3c_sdi.c
- drivers/mmc/s5p_sdhci.c
- drivers/mmc/sh_mmcif.c
- drivers/mmc/sunxi_mmc.c
- drivers/mmc/tegra_mmc.c
- drivers/mmc/zynq_sdhci.c
- include/mmc.h
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("%s: Timeout on data busy\n", __func__); | 122 | printf("%s: Timeout on data busy\n", __func__); |
| 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 | printf("%s: Timeout.\n", __func__); | 181 | printf("%s: Timeout.\n", __func__); |
| 182 | return TIMEOUT; | 182 | return TIMEOUT; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | if (mask & DWMCI_INTMSK_RTO) { | 185 | if (mask & DWMCI_INTMSK_RTO) { |
| 186 | /* | 186 | /* |
| 187 | * Timeout here is not necessarily fatal. (e)MMC cards | 187 | * Timeout here is not necessarily fatal. (e)MMC cards |
| 188 | * will splat here when they receive CMD55 as they do | 188 | * will splat here when they receive CMD55 as they do |
| 189 | * not support this command and that is exactly the way | 189 | * not support this command and that is exactly the way |
| 190 | * to tell them apart from SD cards. Thus, this output | 190 | * to tell them apart from SD cards. Thus, this output |
| 191 | * below shall be debug(). eMMC cards also do not favor | 191 | * below shall be debug(). eMMC cards also do not favor |
| 192 | * CMD8, please keep that in mind. | 192 | * CMD8, please keep that in mind. |
| 193 | */ | 193 | */ |
| 194 | debug("%s: Response Timeout.\n", __func__); | 194 | debug("%s: Response Timeout.\n", __func__); |
| 195 | return TIMEOUT; | 195 | return TIMEOUT; |
| 196 | } else if (mask & DWMCI_INTMSK_RE) { | 196 | } else if (mask & DWMCI_INTMSK_RE) { |
| 197 | printf("%s: Response Error.\n", __func__); | 197 | printf("%s: Response Error.\n", __func__); |
| 198 | return -1; | 198 | return -1; |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | 201 | ||
| 202 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 202 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 203 | if (cmd->resp_type & MMC_RSP_136) { | 203 | if (cmd->resp_type & MMC_RSP_136) { |
| 204 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); | 204 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); |
| 205 | cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); | 205 | cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); |
| 206 | cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); | 206 | cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); |
| 207 | cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); | 207 | cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); |
| 208 | } else { | 208 | } else { |
| 209 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); | 209 | cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | if (data) { | 213 | if (data) { |
| 214 | do { | 214 | do { |
| 215 | mask = dwmci_readl(host, DWMCI_RINTSTS); | 215 | mask = dwmci_readl(host, DWMCI_RINTSTS); |
| 216 | if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { | 216 | if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { |
| 217 | printf("%s: DATA ERROR!\n", __func__); | 217 | printf("%s: DATA ERROR!\n", __func__); |
| 218 | return -1; | 218 | return -1; |
| 219 | } | 219 | } |
| 220 | } while (!(mask & DWMCI_INTMSK_DTO)); | 220 | } while (!(mask & DWMCI_INTMSK_DTO)); |
| 221 | 221 | ||
| 222 | dwmci_writel(host, DWMCI_RINTSTS, mask); | 222 | dwmci_writel(host, DWMCI_RINTSTS, mask); |
| 223 | 223 | ||
| 224 | ctrl = dwmci_readl(host, DWMCI_CTRL); | 224 | ctrl = dwmci_readl(host, DWMCI_CTRL); |
| 225 | ctrl &= ~(DWMCI_DMA_EN); | 225 | ctrl &= ~(DWMCI_DMA_EN); |
| 226 | dwmci_writel(host, DWMCI_CTRL, ctrl); | 226 | dwmci_writel(host, DWMCI_CTRL, ctrl); |
| 227 | 227 | ||
| 228 | bounce_buffer_stop(&bbstate); | 228 | bounce_buffer_stop(&bbstate); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | udelay(100); | 231 | udelay(100); |
| 232 | 232 | ||
| 233 | return 0; | 233 | return 0; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) | 236 | static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) |
| 237 | { | 237 | { |
| 238 | u32 div, status; | 238 | u32 div, status; |
| 239 | int timeout = 10000; | 239 | int timeout = 10000; |
| 240 | unsigned long sclk; | 240 | unsigned long sclk; |
| 241 | 241 | ||
| 242 | if ((freq == host->clock) || (freq == 0)) | 242 | if ((freq == host->clock) || (freq == 0)) |
| 243 | return 0; | 243 | return 0; |
| 244 | /* | 244 | /* |
| 245 | * If host->get_mmc_clk isn't defined, | 245 | * If host->get_mmc_clk isn't defined, |
| 246 | * then assume that host->bus_hz is source clock value. | 246 | * then assume that host->bus_hz is source clock value. |
| 247 | * host->bus_hz should be set by user. | 247 | * host->bus_hz should be set by user. |
| 248 | */ | 248 | */ |
| 249 | if (host->get_mmc_clk) | 249 | if (host->get_mmc_clk) |
| 250 | sclk = host->get_mmc_clk(host); | 250 | sclk = host->get_mmc_clk(host); |
| 251 | else if (host->bus_hz) | 251 | else if (host->bus_hz) |
| 252 | sclk = host->bus_hz; | 252 | sclk = host->bus_hz; |
| 253 | else { | 253 | else { |
| 254 | printf("%s: Didn't get source clock value.\n", __func__); | 254 | printf("%s: Didn't get source clock value.\n", __func__); |
| 255 | return -EINVAL; | 255 | return -EINVAL; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | if (sclk == freq) | 258 | if (sclk == freq) |
| 259 | div = 0; /* bypass mode */ | 259 | div = 0; /* bypass mode */ |
| 260 | else | 260 | else |
| 261 | div = DIV_ROUND_UP(sclk, 2 * freq); | 261 | div = DIV_ROUND_UP(sclk, 2 * freq); |
| 262 | 262 | ||
| 263 | dwmci_writel(host, DWMCI_CLKENA, 0); | 263 | dwmci_writel(host, DWMCI_CLKENA, 0); |
| 264 | dwmci_writel(host, DWMCI_CLKSRC, 0); | 264 | dwmci_writel(host, DWMCI_CLKSRC, 0); |
| 265 | 265 | ||
| 266 | dwmci_writel(host, DWMCI_CLKDIV, div); | 266 | dwmci_writel(host, DWMCI_CLKDIV, div); |
| 267 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | | 267 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
| 268 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); | 268 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
| 269 | 269 | ||
| 270 | do { | 270 | do { |
| 271 | status = dwmci_readl(host, DWMCI_CMD); | 271 | status = dwmci_readl(host, DWMCI_CMD); |
| 272 | if (timeout-- < 0) { | 272 | if (timeout-- < 0) { |
| 273 | printf("%s: Timeout!\n", __func__); | 273 | printf("%s: Timeout!\n", __func__); |
| 274 | return -ETIMEDOUT; | 274 | return -ETIMEDOUT; |
| 275 | } | 275 | } |
| 276 | } while (status & DWMCI_CMD_START); | 276 | } while (status & DWMCI_CMD_START); |
| 277 | 277 | ||
| 278 | dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | | 278 | dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | |
| 279 | DWMCI_CLKEN_LOW_PWR); | 279 | DWMCI_CLKEN_LOW_PWR); |
| 280 | 280 | ||
| 281 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | | 281 | dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | |
| 282 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); | 282 | DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); |
| 283 | 283 | ||
| 284 | timeout = 10000; | 284 | timeout = 10000; |
| 285 | do { | 285 | do { |
| 286 | status = dwmci_readl(host, DWMCI_CMD); | 286 | status = dwmci_readl(host, DWMCI_CMD); |
| 287 | if (timeout-- < 0) { | 287 | if (timeout-- < 0) { |
| 288 | printf("%s: Timeout!\n", __func__); | 288 | printf("%s: Timeout!\n", __func__); |
| 289 | return -ETIMEDOUT; | 289 | return -ETIMEDOUT; |
| 290 | } | 290 | } |
| 291 | } while (status & DWMCI_CMD_START); | 291 | } while (status & DWMCI_CMD_START); |
| 292 | 292 | ||
| 293 | host->clock = freq; | 293 | host->clock = freq; |
| 294 | 294 | ||
| 295 | return 0; | 295 | return 0; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static void dwmci_set_ios(struct mmc *mmc) | 298 | static void dwmci_set_ios(struct mmc *mmc) |
| 299 | { | 299 | { |
| 300 | struct dwmci_host *host = (struct dwmci_host *)mmc->priv; | 300 | struct dwmci_host *host = (struct dwmci_host *)mmc->priv; |
| 301 | u32 ctype, regs; | 301 | u32 ctype, regs; |
| 302 | 302 | ||
| 303 | debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); | 303 | debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); |
| 304 | 304 | ||
| 305 | dwmci_setup_bus(host, mmc->clock); | 305 | dwmci_setup_bus(host, mmc->clock); |
| 306 | switch (mmc->bus_width) { | 306 | switch (mmc->bus_width) { |
| 307 | case 8: | 307 | case 8: |
| 308 | ctype = DWMCI_CTYPE_8BIT; | 308 | ctype = DWMCI_CTYPE_8BIT; |
| 309 | break; | 309 | break; |
| 310 | case 4: | 310 | case 4: |
| 311 | ctype = DWMCI_CTYPE_4BIT; | 311 | ctype = DWMCI_CTYPE_4BIT; |
| 312 | break; | 312 | break; |
| 313 | default: | 313 | default: |
| 314 | ctype = DWMCI_CTYPE_1BIT; | 314 | ctype = DWMCI_CTYPE_1BIT; |
| 315 | break; | 315 | break; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | dwmci_writel(host, DWMCI_CTYPE, ctype); | 318 | dwmci_writel(host, DWMCI_CTYPE, ctype); |
| 319 | 319 | ||
| 320 | regs = dwmci_readl(host, DWMCI_UHS_REG); | 320 | regs = dwmci_readl(host, DWMCI_UHS_REG); |
| 321 | if (mmc->ddr_mode) | 321 | if (mmc->ddr_mode) |
| 322 | regs |= DWMCI_DDR_MODE; | 322 | regs |= DWMCI_DDR_MODE; |
| 323 | else | 323 | else |
| 324 | regs &= ~DWMCI_DDR_MODE; | 324 | regs &= ~DWMCI_DDR_MODE; |
| 325 | 325 | ||
| 326 | dwmci_writel(host, DWMCI_UHS_REG, regs); | 326 | dwmci_writel(host, DWMCI_UHS_REG, regs); |
| 327 | 327 | ||
| 328 | if (host->clksel) | 328 | if (host->clksel) |
| 329 | host->clksel(host); | 329 | host->clksel(host); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | static int dwmci_init(struct mmc *mmc) | 332 | static int dwmci_init(struct mmc *mmc) |
| 333 | { | 333 | { |
| 334 | struct dwmci_host *host = mmc->priv; | 334 | struct dwmci_host *host = mmc->priv; |
| 335 | 335 | ||
| 336 | if (host->board_init) | 336 | if (host->board_init) |
| 337 | host->board_init(host); | 337 | host->board_init(host); |
| 338 | 338 | ||
| 339 | dwmci_writel(host, DWMCI_PWREN, 1); | 339 | dwmci_writel(host, DWMCI_PWREN, 1); |
| 340 | 340 | ||
| 341 | if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { | 341 | if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { |
| 342 | printf("%s[%d] Fail-reset!!\n", __func__, __LINE__); | 342 | printf("%s[%d] Fail-reset!!\n", __func__, __LINE__); |
| 343 | return -1; | 343 | return -1; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | /* Enumerate at 400KHz */ | 346 | /* Enumerate at 400KHz */ |
| 347 | dwmci_setup_bus(host, mmc->cfg->f_min); | 347 | dwmci_setup_bus(host, mmc->cfg->f_min); |
| 348 | 348 | ||
| 349 | dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); | 349 | dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); |
| 350 | dwmci_writel(host, DWMCI_INTMASK, 0); | 350 | dwmci_writel(host, DWMCI_INTMASK, 0); |
| 351 | 351 | ||
| 352 | dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); | 352 | dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); |
| 353 | 353 | ||
| 354 | dwmci_writel(host, DWMCI_IDINTEN, 0); | 354 | dwmci_writel(host, DWMCI_IDINTEN, 0); |
| 355 | dwmci_writel(host, DWMCI_BMOD, 1); | 355 | dwmci_writel(host, DWMCI_BMOD, 1); |
| 356 | 356 | ||
| 357 | if (host->fifoth_val) { | 357 | if (host->fifoth_val) { |
| 358 | dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); | 358 | dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | dwmci_writel(host, DWMCI_CLKENA, 0); | 361 | dwmci_writel(host, DWMCI_CLKENA, 0); |
| 362 | dwmci_writel(host, DWMCI_CLKSRC, 0); | 362 | dwmci_writel(host, DWMCI_CLKSRC, 0); |
| 363 | 363 | ||
| 364 | return 0; | 364 | return 0; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | static const struct mmc_ops dwmci_ops = { | 367 | static const struct mmc_ops dwmci_ops = { |
| 368 | .send_cmd = dwmci_send_cmd, | 368 | .send_cmd = dwmci_send_cmd, |
| 369 | .set_ios = dwmci_set_ios, | 369 | .set_ios = dwmci_set_ios, |
| 370 | .init = dwmci_init, | 370 | .init = dwmci_init, |
| 371 | }; | 371 | }; |
| 372 | 372 | ||
| 373 | int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) | 373 | int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) |
| 374 | { | 374 | { |
| 375 | host->cfg.name = host->name; | 375 | host->cfg.name = host->name; |
| 376 | host->cfg.ops = &dwmci_ops; | 376 | host->cfg.ops = &dwmci_ops; |
| 377 | host->cfg.f_min = min_clk; | 377 | host->cfg.f_min = min_clk; |
| 378 | host->cfg.f_max = max_clk; | 378 | host->cfg.f_max = max_clk; |
| 379 | 379 | ||
| 380 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | 380 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
| 381 | 381 | ||
| 382 | host->cfg.host_caps = host->caps; | 382 | host->cfg.host_caps = host->caps; |
| 383 | 383 | ||
| 384 | if (host->buswidth == 8) { | 384 | if (host->buswidth == 8) { |
| 385 | host->cfg.host_caps |= MMC_MODE_8BIT; | 385 | host->cfg.host_caps |= MMC_MODE_8BIT; |
| 386 | host->cfg.host_caps &= ~MMC_MODE_4BIT; | 386 | host->cfg.host_caps &= ~MMC_MODE_4BIT; |
| 387 | } else { | 387 | } else { |
| 388 | host->cfg.host_caps |= MMC_MODE_4BIT; | 388 | host->cfg.host_caps |= MMC_MODE_4BIT; |
| 389 | host->cfg.host_caps &= ~MMC_MODE_8BIT; | 389 | host->cfg.host_caps &= ~MMC_MODE_8BIT; |
| 390 | } | 390 | } |
| 391 | host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; | 391 | host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; |
| 392 | 392 | ||
| 393 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 393 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
| 394 | 394 | ||
| 395 | host->mmc = mmc_create(&host->cfg, host); | 395 | host->mmc = mmc_create(&host->cfg, host); |
| 396 | if (host->mmc == NULL) | 396 | if (host->mmc == NULL) |
| 397 | return -1; | 397 | return -1; |
| 398 | 398 | ||
| 399 | return 0; | 399 | return 0; |
| 400 | } | 400 | } |
| 401 | 401 |
drivers/mmc/fsl_esdhc.c
| 1 | /* | 1 | /* |
| 2 | * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc | 2 | * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc |
| 3 | * Andy Fleming | 3 | * Andy Fleming |
| 4 | * | 4 | * |
| 5 | * Based vaguely on the pxa mmc code: | 5 | * Based vaguely on the pxa mmc code: |
| 6 | * (C) Copyright 2003 | 6 | * (C) Copyright 2003 |
| 7 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net | 7 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net |
| 8 | * | 8 | * |
| 9 | * SPDX-License-Identifier: GPL-2.0+ | 9 | * SPDX-License-Identifier: GPL-2.0+ |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <config.h> | 12 | #include <config.h> |
| 13 | #include <common.h> | 13 | #include <common.h> |
| 14 | #include <command.h> | 14 | #include <command.h> |
| 15 | #include <hwconfig.h> | 15 | #include <hwconfig.h> |
| 16 | #include <mmc.h> | 16 | #include <mmc.h> |
| 17 | #include <part.h> | 17 | #include <part.h> |
| 18 | #include <malloc.h> | 18 | #include <malloc.h> |
| 19 | #include <mmc.h> | 19 | #include <mmc.h> |
| 20 | #include <fsl_esdhc.h> | 20 | #include <fsl_esdhc.h> |
| 21 | #include <fdt_support.h> | 21 | #include <fdt_support.h> |
| 22 | #include <asm/io.h> | 22 | #include <asm/io.h> |
| 23 | 23 | ||
| 24 | DECLARE_GLOBAL_DATA_PTR; | 24 | DECLARE_GLOBAL_DATA_PTR; |
| 25 | 25 | ||
| 26 | #define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ | 26 | #define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \ |
| 27 | IRQSTATEN_CINT | \ | 27 | IRQSTATEN_CINT | \ |
| 28 | IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ | 28 | IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \ |
| 29 | IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ | 29 | IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \ |
| 30 | IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ | 30 | IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \ |
| 31 | IRQSTATEN_DINT) | 31 | IRQSTATEN_DINT) |
| 32 | 32 | ||
| 33 | struct fsl_esdhc { | 33 | struct fsl_esdhc { |
| 34 | uint dsaddr; /* SDMA system address register */ | 34 | uint dsaddr; /* SDMA system address register */ |
| 35 | uint blkattr; /* Block attributes register */ | 35 | uint blkattr; /* Block attributes register */ |
| 36 | uint cmdarg; /* Command argument register */ | 36 | uint cmdarg; /* Command argument register */ |
| 37 | uint xfertyp; /* Transfer type register */ | 37 | uint xfertyp; /* Transfer type register */ |
| 38 | uint cmdrsp0; /* Command response 0 register */ | 38 | uint cmdrsp0; /* Command response 0 register */ |
| 39 | uint cmdrsp1; /* Command response 1 register */ | 39 | uint cmdrsp1; /* Command response 1 register */ |
| 40 | uint cmdrsp2; /* Command response 2 register */ | 40 | uint cmdrsp2; /* Command response 2 register */ |
| 41 | uint cmdrsp3; /* Command response 3 register */ | 41 | uint cmdrsp3; /* Command response 3 register */ |
| 42 | uint datport; /* Buffer data port register */ | 42 | uint datport; /* Buffer data port register */ |
| 43 | uint prsstat; /* Present state register */ | 43 | uint prsstat; /* Present state register */ |
| 44 | uint proctl; /* Protocol control register */ | 44 | uint proctl; /* Protocol control register */ |
| 45 | uint sysctl; /* System Control Register */ | 45 | uint sysctl; /* System Control Register */ |
| 46 | uint irqstat; /* Interrupt status register */ | 46 | uint irqstat; /* Interrupt status register */ |
| 47 | uint irqstaten; /* Interrupt status enable register */ | 47 | uint irqstaten; /* Interrupt status enable register */ |
| 48 | uint irqsigen; /* Interrupt signal enable register */ | 48 | uint irqsigen; /* Interrupt signal enable register */ |
| 49 | uint autoc12err; /* Auto CMD error status register */ | 49 | uint autoc12err; /* Auto CMD error status register */ |
| 50 | uint hostcapblt; /* Host controller capabilities register */ | 50 | uint hostcapblt; /* Host controller capabilities register */ |
| 51 | uint wml; /* Watermark level register */ | 51 | uint wml; /* Watermark level register */ |
| 52 | uint mixctrl; /* For USDHC */ | 52 | uint mixctrl; /* For USDHC */ |
| 53 | char reserved1[4]; /* reserved */ | 53 | char reserved1[4]; /* reserved */ |
| 54 | uint fevt; /* Force event register */ | 54 | uint fevt; /* Force event register */ |
| 55 | uint admaes; /* ADMA error status register */ | 55 | uint admaes; /* ADMA error status register */ |
| 56 | uint adsaddr; /* ADMA system address register */ | 56 | uint adsaddr; /* ADMA system address register */ |
| 57 | char reserved2[100]; /* reserved */ | 57 | char reserved2[100]; /* reserved */ |
| 58 | uint vendorspec; /* Vendor Specific register */ | 58 | uint vendorspec; /* Vendor Specific register */ |
| 59 | char reserved3[56]; /* reserved */ | 59 | char reserved3[56]; /* reserved */ |
| 60 | uint hostver; /* Host controller version register */ | 60 | uint hostver; /* Host controller version register */ |
| 61 | char reserved4[4]; /* reserved */ | 61 | char reserved4[4]; /* reserved */ |
| 62 | uint dmaerraddr; /* DMA error address register */ | 62 | uint dmaerraddr; /* DMA error address register */ |
| 63 | char reserved5[4]; /* reserved */ | 63 | char reserved5[4]; /* reserved */ |
| 64 | uint dmaerrattr; /* DMA error attribute register */ | 64 | uint dmaerrattr; /* DMA error attribute register */ |
| 65 | char reserved6[4]; /* reserved */ | 65 | char reserved6[4]; /* reserved */ |
| 66 | uint hostcapblt2; /* Host controller capabilities register 2 */ | 66 | uint hostcapblt2; /* Host controller capabilities register 2 */ |
| 67 | char reserved7[8]; /* reserved */ | 67 | char reserved7[8]; /* reserved */ |
| 68 | uint tcr; /* Tuning control register */ | 68 | uint tcr; /* Tuning control register */ |
| 69 | char reserved8[28]; /* reserved */ | 69 | char reserved8[28]; /* reserved */ |
| 70 | uint sddirctl; /* SD direction control register */ | 70 | uint sddirctl; /* SD direction control register */ |
| 71 | char reserved9[712]; /* reserved */ | 71 | char reserved9[712]; /* reserved */ |
| 72 | uint scr; /* eSDHC control register */ | 72 | uint scr; /* eSDHC control register */ |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | /* Return the XFERTYP flags for a given command and data packet */ | 75 | /* Return the XFERTYP flags for a given command and data packet */ |
| 76 | static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) | 76 | static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) |
| 77 | { | 77 | { |
| 78 | uint xfertyp = 0; | 78 | uint xfertyp = 0; |
| 79 | 79 | ||
| 80 | if (data) { | 80 | if (data) { |
| 81 | xfertyp |= XFERTYP_DPSEL; | 81 | xfertyp |= XFERTYP_DPSEL; |
| 82 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | 82 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 83 | xfertyp |= XFERTYP_DMAEN; | 83 | xfertyp |= XFERTYP_DMAEN; |
| 84 | #endif | 84 | #endif |
| 85 | if (data->blocks > 1) { | 85 | if (data->blocks > 1) { |
| 86 | xfertyp |= XFERTYP_MSBSEL; | 86 | xfertyp |= XFERTYP_MSBSEL; |
| 87 | xfertyp |= XFERTYP_BCEN; | 87 | xfertyp |= XFERTYP_BCEN; |
| 88 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 | 88 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 |
| 89 | xfertyp |= XFERTYP_AC12EN; | 89 | xfertyp |= XFERTYP_AC12EN; |
| 90 | #endif | 90 | #endif |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | if (data->flags & MMC_DATA_READ) | 93 | if (data->flags & MMC_DATA_READ) |
| 94 | xfertyp |= XFERTYP_DTDSEL; | 94 | xfertyp |= XFERTYP_DTDSEL; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | if (cmd->resp_type & MMC_RSP_CRC) | 97 | if (cmd->resp_type & MMC_RSP_CRC) |
| 98 | xfertyp |= XFERTYP_CCCEN; | 98 | xfertyp |= XFERTYP_CCCEN; |
| 99 | if (cmd->resp_type & MMC_RSP_OPCODE) | 99 | if (cmd->resp_type & MMC_RSP_OPCODE) |
| 100 | xfertyp |= XFERTYP_CICEN; | 100 | xfertyp |= XFERTYP_CICEN; |
| 101 | if (cmd->resp_type & MMC_RSP_136) | 101 | if (cmd->resp_type & MMC_RSP_136) |
| 102 | xfertyp |= XFERTYP_RSPTYP_136; | 102 | xfertyp |= XFERTYP_RSPTYP_136; |
| 103 | else if (cmd->resp_type & MMC_RSP_BUSY) | 103 | else if (cmd->resp_type & MMC_RSP_BUSY) |
| 104 | xfertyp |= XFERTYP_RSPTYP_48_BUSY; | 104 | xfertyp |= XFERTYP_RSPTYP_48_BUSY; |
| 105 | else if (cmd->resp_type & MMC_RSP_PRESENT) | 105 | else if (cmd->resp_type & MMC_RSP_PRESENT) |
| 106 | xfertyp |= XFERTYP_RSPTYP_48; | 106 | xfertyp |= XFERTYP_RSPTYP_48; |
| 107 | 107 | ||
| 108 | #if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || \ | 108 | #if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || \ |
| 109 | defined(CONFIG_LS102XA) || defined(CONFIG_LS2085A) | 109 | defined(CONFIG_LS102XA) || defined(CONFIG_LS2085A) |
| 110 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) | 110 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) |
| 111 | xfertyp |= XFERTYP_CMDTYP_ABORT; | 111 | xfertyp |= XFERTYP_CMDTYP_ABORT; |
| 112 | #endif | 112 | #endif |
| 113 | return XFERTYP_CMD(cmd->cmdidx) | xfertyp; | 113 | return XFERTYP_CMD(cmd->cmdidx) | xfertyp; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO | 116 | #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 117 | /* | 117 | /* |
| 118 | * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. | 118 | * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. |
| 119 | */ | 119 | */ |
| 120 | static void | 120 | static void |
| 121 | esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) | 121 | esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) |
| 122 | { | 122 | { |
| 123 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 123 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 124 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 124 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 125 | uint blocks; | 125 | uint blocks; |
| 126 | char *buffer; | 126 | char *buffer; |
| 127 | uint databuf; | 127 | uint databuf; |
| 128 | uint size; | 128 | uint size; |
| 129 | uint irqstat; | 129 | uint irqstat; |
| 130 | uint timeout; | 130 | uint timeout; |
| 131 | 131 | ||
| 132 | if (data->flags & MMC_DATA_READ) { | 132 | if (data->flags & MMC_DATA_READ) { |
| 133 | blocks = data->blocks; | 133 | blocks = data->blocks; |
| 134 | buffer = data->dest; | 134 | buffer = data->dest; |
| 135 | while (blocks) { | 135 | while (blocks) { |
| 136 | timeout = PIO_TIMEOUT; | 136 | timeout = PIO_TIMEOUT; |
| 137 | size = data->blocksize; | 137 | size = data->blocksize; |
| 138 | irqstat = esdhc_read32(®s->irqstat); | 138 | irqstat = esdhc_read32(®s->irqstat); |
| 139 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) | 139 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) |
| 140 | && --timeout); | 140 | && --timeout); |
| 141 | if (timeout <= 0) { | 141 | if (timeout <= 0) { |
| 142 | printf("\nData Read Failed in PIO Mode."); | 142 | printf("\nData Read Failed in PIO Mode."); |
| 143 | return; | 143 | return; |
| 144 | } | 144 | } |
| 145 | while (size && (!(irqstat & IRQSTAT_TC))) { | 145 | while (size && (!(irqstat & IRQSTAT_TC))) { |
| 146 | udelay(100); /* Wait before last byte transfer complete */ | 146 | udelay(100); /* Wait before last byte transfer complete */ |
| 147 | irqstat = esdhc_read32(®s->irqstat); | 147 | irqstat = esdhc_read32(®s->irqstat); |
| 148 | databuf = in_le32(®s->datport); | 148 | databuf = in_le32(®s->datport); |
| 149 | *((uint *)buffer) = databuf; | 149 | *((uint *)buffer) = databuf; |
| 150 | buffer += 4; | 150 | buffer += 4; |
| 151 | size -= 4; | 151 | size -= 4; |
| 152 | } | 152 | } |
| 153 | blocks--; | 153 | blocks--; |
| 154 | } | 154 | } |
| 155 | } else { | 155 | } else { |
| 156 | blocks = data->blocks; | 156 | blocks = data->blocks; |
| 157 | buffer = (char *)data->src; | 157 | buffer = (char *)data->src; |
| 158 | while (blocks) { | 158 | while (blocks) { |
| 159 | timeout = PIO_TIMEOUT; | 159 | timeout = PIO_TIMEOUT; |
| 160 | size = data->blocksize; | 160 | size = data->blocksize; |
| 161 | irqstat = esdhc_read32(®s->irqstat); | 161 | irqstat = esdhc_read32(®s->irqstat); |
| 162 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BWEN) | 162 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BWEN) |
| 163 | && --timeout); | 163 | && --timeout); |
| 164 | if (timeout <= 0) { | 164 | if (timeout <= 0) { |
| 165 | printf("\nData Write Failed in PIO Mode."); | 165 | printf("\nData Write Failed in PIO Mode."); |
| 166 | return; | 166 | return; |
| 167 | } | 167 | } |
| 168 | while (size && (!(irqstat & IRQSTAT_TC))) { | 168 | while (size && (!(irqstat & IRQSTAT_TC))) { |
| 169 | udelay(100); /* Wait before last byte transfer complete */ | 169 | udelay(100); /* Wait before last byte transfer complete */ |
| 170 | databuf = *((uint *)buffer); | 170 | databuf = *((uint *)buffer); |
| 171 | buffer += 4; | 171 | buffer += 4; |
| 172 | size -= 4; | 172 | size -= 4; |
| 173 | irqstat = esdhc_read32(®s->irqstat); | 173 | irqstat = esdhc_read32(®s->irqstat); |
| 174 | out_le32(®s->datport, databuf); | 174 | out_le32(®s->datport, databuf); |
| 175 | } | 175 | } |
| 176 | blocks--; | 176 | blocks--; |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | #endif | 180 | #endif |
| 181 | 181 | ||
| 182 | static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) | 182 | static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) |
| 183 | { | 183 | { |
| 184 | int timeout; | 184 | int timeout; |
| 185 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 185 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 186 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 186 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 187 | #ifdef CONFIG_LS2085A | 187 | #ifdef CONFIG_LS2085A |
| 188 | dma_addr_t addr; | 188 | dma_addr_t addr; |
| 189 | #endif | 189 | #endif |
| 190 | uint wml_value; | 190 | uint wml_value; |
| 191 | 191 | ||
| 192 | wml_value = data->blocksize/4; | 192 | wml_value = data->blocksize/4; |
| 193 | 193 | ||
| 194 | if (data->flags & MMC_DATA_READ) { | 194 | if (data->flags & MMC_DATA_READ) { |
| 195 | if (wml_value > WML_RD_WML_MAX) | 195 | if (wml_value > WML_RD_WML_MAX) |
| 196 | wml_value = WML_RD_WML_MAX_VAL; | 196 | wml_value = WML_RD_WML_MAX_VAL; |
| 197 | 197 | ||
| 198 | esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); | 198 | esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); |
| 199 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | 199 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 200 | #ifdef CONFIG_LS2085A | 200 | #ifdef CONFIG_LS2085A |
| 201 | addr = virt_to_phys((void *)(data->dest)); | 201 | addr = virt_to_phys((void *)(data->dest)); |
| 202 | if (upper_32_bits(addr)) | 202 | if (upper_32_bits(addr)) |
| 203 | printf("Error found for upper 32 bits\n"); | 203 | printf("Error found for upper 32 bits\n"); |
| 204 | else | 204 | else |
| 205 | esdhc_write32(®s->dsaddr, lower_32_bits(addr)); | 205 | esdhc_write32(®s->dsaddr, lower_32_bits(addr)); |
| 206 | #else | 206 | #else |
| 207 | esdhc_write32(®s->dsaddr, (u32)data->dest); | 207 | esdhc_write32(®s->dsaddr, (u32)data->dest); |
| 208 | #endif | 208 | #endif |
| 209 | #endif | 209 | #endif |
| 210 | } else { | 210 | } else { |
| 211 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | 211 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 212 | flush_dcache_range((ulong)data->src, | 212 | flush_dcache_range((ulong)data->src, |
| 213 | (ulong)data->src+data->blocks | 213 | (ulong)data->src+data->blocks |
| 214 | *data->blocksize); | 214 | *data->blocksize); |
| 215 | #endif | 215 | #endif |
| 216 | if (wml_value > WML_WR_WML_MAX) | 216 | if (wml_value > WML_WR_WML_MAX) |
| 217 | wml_value = WML_WR_WML_MAX_VAL; | 217 | wml_value = WML_WR_WML_MAX_VAL; |
| 218 | if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { | 218 | if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { |
| 219 | printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); | 219 | printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); |
| 220 | return TIMEOUT; | 220 | return TIMEOUT; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, | 223 | esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, |
| 224 | wml_value << 16); | 224 | wml_value << 16); |
| 225 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | 225 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 226 | #ifdef CONFIG_LS2085A | 226 | #ifdef CONFIG_LS2085A |
| 227 | addr = virt_to_phys((void *)(data->src)); | 227 | addr = virt_to_phys((void *)(data->src)); |
| 228 | if (upper_32_bits(addr)) | 228 | if (upper_32_bits(addr)) |
| 229 | printf("Error found for upper 32 bits\n"); | 229 | printf("Error found for upper 32 bits\n"); |
| 230 | else | 230 | else |
| 231 | esdhc_write32(®s->dsaddr, lower_32_bits(addr)); | 231 | esdhc_write32(®s->dsaddr, lower_32_bits(addr)); |
| 232 | #else | 232 | #else |
| 233 | esdhc_write32(®s->dsaddr, (u32)data->src); | 233 | esdhc_write32(®s->dsaddr, (u32)data->src); |
| 234 | #endif | 234 | #endif |
| 235 | #endif | 235 | #endif |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); | 238 | esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); |
| 239 | 239 | ||
| 240 | /* Calculate the timeout period for data transactions */ | 240 | /* Calculate the timeout period for data transactions */ |
| 241 | /* | 241 | /* |
| 242 | * 1)Timeout period = (2^(timeout+13)) SD Clock cycles | 242 | * 1)Timeout period = (2^(timeout+13)) SD Clock cycles |
| 243 | * 2)Timeout period should be minimum 0.250sec as per SD Card spec | 243 | * 2)Timeout period should be minimum 0.250sec as per SD Card spec |
| 244 | * So, Number of SD Clock cycles for 0.25sec should be minimum | 244 | * So, Number of SD Clock cycles for 0.25sec should be minimum |
| 245 | * (SD Clock/sec * 0.25 sec) SD Clock cycles | 245 | * (SD Clock/sec * 0.25 sec) SD Clock cycles |
| 246 | * = (mmc->clock * 1/4) SD Clock cycles | 246 | * = (mmc->clock * 1/4) SD Clock cycles |
| 247 | * As 1) >= 2) | 247 | * As 1) >= 2) |
| 248 | * => (2^(timeout+13)) >= mmc->clock * 1/4 | 248 | * => (2^(timeout+13)) >= mmc->clock * 1/4 |
| 249 | * Taking log2 both the sides | 249 | * Taking log2 both the sides |
| 250 | * => timeout + 13 >= log2(mmc->clock/4) | 250 | * => timeout + 13 >= log2(mmc->clock/4) |
| 251 | * Rounding up to next power of 2 | 251 | * Rounding up to next power of 2 |
| 252 | * => timeout + 13 = log2(mmc->clock/4) + 1 | 252 | * => timeout + 13 = log2(mmc->clock/4) + 1 |
| 253 | * => timeout + 13 = fls(mmc->clock/4) | 253 | * => timeout + 13 = fls(mmc->clock/4) |
| 254 | */ | 254 | */ |
| 255 | timeout = fls(mmc->clock/4); | 255 | timeout = fls(mmc->clock/4); |
| 256 | timeout -= 13; | 256 | timeout -= 13; |
| 257 | 257 | ||
| 258 | if (timeout > 14) | 258 | if (timeout > 14) |
| 259 | timeout = 14; | 259 | timeout = 14; |
| 260 | 260 | ||
| 261 | if (timeout < 0) | 261 | if (timeout < 0) |
| 262 | timeout = 0; | 262 | timeout = 0; |
| 263 | 263 | ||
| 264 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 | 264 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 |
| 265 | if ((timeout == 4) || (timeout == 8) || (timeout == 12)) | 265 | if ((timeout == 4) || (timeout == 8) || (timeout == 12)) |
| 266 | timeout++; | 266 | timeout++; |
| 267 | #endif | 267 | #endif |
| 268 | 268 | ||
| 269 | #ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE | 269 | #ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE |
| 270 | timeout = 0xE; | 270 | timeout = 0xE; |
| 271 | #endif | 271 | #endif |
| 272 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); | 272 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); |
| 273 | 273 | ||
| 274 | return 0; | 274 | return 0; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | 277 | #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 278 | static void check_and_invalidate_dcache_range | 278 | static void check_and_invalidate_dcache_range |
| 279 | (struct mmc_cmd *cmd, | 279 | (struct mmc_cmd *cmd, |
| 280 | struct mmc_data *data) { | 280 | struct mmc_data *data) { |
| 281 | #ifdef CONFIG_LS2085A | 281 | #ifdef CONFIG_LS2085A |
| 282 | unsigned start = 0; | 282 | unsigned start = 0; |
| 283 | #else | 283 | #else |
| 284 | unsigned start = (unsigned)data->dest ; | 284 | unsigned start = (unsigned)data->dest ; |
| 285 | #endif | 285 | #endif |
| 286 | unsigned size = roundup(ARCH_DMA_MINALIGN, | 286 | unsigned size = roundup(ARCH_DMA_MINALIGN, |
| 287 | data->blocks*data->blocksize); | 287 | data->blocks*data->blocksize); |
| 288 | unsigned end = start+size ; | 288 | unsigned end = start+size ; |
| 289 | #ifdef CONFIG_LS2085A | 289 | #ifdef CONFIG_LS2085A |
| 290 | dma_addr_t addr; | 290 | dma_addr_t addr; |
| 291 | 291 | ||
| 292 | addr = virt_to_phys((void *)(data->dest)); | 292 | addr = virt_to_phys((void *)(data->dest)); |
| 293 | if (upper_32_bits(addr)) | 293 | if (upper_32_bits(addr)) |
| 294 | printf("Error found for upper 32 bits\n"); | 294 | printf("Error found for upper 32 bits\n"); |
| 295 | else | 295 | else |
| 296 | start = lower_32_bits(addr); | 296 | start = lower_32_bits(addr); |
| 297 | #endif | 297 | #endif |
| 298 | invalidate_dcache_range(start, end); | 298 | invalidate_dcache_range(start, end); |
| 299 | } | 299 | } |
| 300 | #endif | 300 | #endif |
| 301 | 301 | ||
| 302 | /* | 302 | /* |
| 303 | * Sends a command out on the bus. Takes the mmc pointer, | 303 | * Sends a command out on the bus. Takes the mmc pointer, |
| 304 | * a command pointer, and an optional data pointer. | 304 | * a command pointer, and an optional data pointer. |
| 305 | */ | 305 | */ |
| 306 | static int | 306 | static int |
| 307 | esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | 307 | esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) |
| 308 | { | 308 | { |
| 309 | int err = 0; | 309 | int err = 0; |
| 310 | uint xfertyp; | 310 | uint xfertyp; |
| 311 | uint irqstat; | 311 | uint irqstat; |
| 312 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 312 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 313 | volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 313 | volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 314 | 314 | ||
| 315 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 | 315 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 |
| 316 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) | 316 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) |
| 317 | return 0; | 317 | return 0; |
| 318 | #endif | 318 | #endif |
| 319 | 319 | ||
| 320 | esdhc_write32(®s->irqstat, -1); | 320 | esdhc_write32(®s->irqstat, -1); |
| 321 | 321 | ||
| 322 | sync(); | 322 | sync(); |
| 323 | 323 | ||
| 324 | /* Wait for the bus to be idle */ | 324 | /* Wait for the bus to be idle */ |
| 325 | while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || | 325 | while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || |
| 326 | (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) | 326 | (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) |
| 327 | ; | 327 | ; |
| 328 | 328 | ||
| 329 | while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) | 329 | while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) |
| 330 | ; | 330 | ; |
| 331 | 331 | ||
| 332 | /* Wait at least 8 SD clock cycles before the next command */ | 332 | /* Wait at least 8 SD clock cycles before the next command */ |
| 333 | /* | 333 | /* |
| 334 | * Note: This is way more than 8 cycles, but 1ms seems to | 334 | * Note: This is way more than 8 cycles, but 1ms seems to |
| 335 | * resolve timing issues with some cards | 335 | * resolve timing issues with some cards |
| 336 | */ | 336 | */ |
| 337 | udelay(1000); | 337 | udelay(1000); |
| 338 | 338 | ||
| 339 | /* Set up for a data transfer if we have one */ | 339 | /* Set up for a data transfer if we have one */ |
| 340 | if (data) { | 340 | if (data) { |
| 341 | err = esdhc_setup_data(mmc, data); | 341 | err = esdhc_setup_data(mmc, data); |
| 342 | if(err) | 342 | if(err) |
| 343 | return err; | 343 | return err; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | /* Figure out the transfer arguments */ | 346 | /* Figure out the transfer arguments */ |
| 347 | xfertyp = esdhc_xfertyp(cmd, data); | 347 | xfertyp = esdhc_xfertyp(cmd, data); |
| 348 | 348 | ||
| 349 | /* Mask all irqs */ | 349 | /* Mask all irqs */ |
| 350 | esdhc_write32(®s->irqsigen, 0); | 350 | esdhc_write32(®s->irqsigen, 0); |
| 351 | 351 | ||
| 352 | /* Send the command */ | 352 | /* Send the command */ |
| 353 | esdhc_write32(®s->cmdarg, cmd->cmdarg); | 353 | esdhc_write32(®s->cmdarg, cmd->cmdarg); |
| 354 | #if defined(CONFIG_FSL_USDHC) | 354 | #if defined(CONFIG_FSL_USDHC) |
| 355 | esdhc_write32(®s->mixctrl, | 355 | esdhc_write32(®s->mixctrl, |
| 356 | (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F) | 356 | (esdhc_read32(®s->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F) |
| 357 | | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); | 357 | | (mmc->ddr_mode ? XFERTYP_DDREN : 0)); |
| 358 | esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); | 358 | esdhc_write32(®s->xfertyp, xfertyp & 0xFFFF0000); |
| 359 | #else | 359 | #else |
| 360 | esdhc_write32(®s->xfertyp, xfertyp); | 360 | esdhc_write32(®s->xfertyp, xfertyp); |
| 361 | #endif | 361 | #endif |
| 362 | 362 | ||
| 363 | /* Wait for the command to complete */ | 363 | /* Wait for the command to complete */ |
| 364 | while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) | 364 | while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) |
| 365 | ; | 365 | ; |
| 366 | 366 | ||
| 367 | irqstat = esdhc_read32(®s->irqstat); | 367 | irqstat = esdhc_read32(®s->irqstat); |
| 368 | 368 | ||
| 369 | if (irqstat & CMD_ERR) { | 369 | if (irqstat & CMD_ERR) { |
| 370 | err = COMM_ERR; | 370 | err = COMM_ERR; |
| 371 | goto out; | 371 | goto out; |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | if (irqstat & IRQSTAT_CTOE) { | 374 | if (irqstat & IRQSTAT_CTOE) { |
| 375 | err = TIMEOUT; | 375 | err = TIMEOUT; |
| 376 | goto out; | 376 | goto out; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | /* Switch voltage to 1.8V if CMD11 succeeded */ | 379 | /* Switch voltage to 1.8V if CMD11 succeeded */ |
| 380 | if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { | 380 | if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { |
| 381 | esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); | 381 | esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); |
| 382 | 382 | ||
| 383 | printf("Run CMD11 1.8V switch\n"); | 383 | printf("Run CMD11 1.8V switch\n"); |
| 384 | /* Sleep for 5 ms - max time for card to switch to 1.8V */ | 384 | /* Sleep for 5 ms - max time for card to switch to 1.8V */ |
| 385 | udelay(5000); | 385 | udelay(5000); |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | /* Workaround for ESDHC errata ENGcm03648 */ | 388 | /* Workaround for ESDHC errata ENGcm03648 */ |
| 389 | if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { | 389 | if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { |
| 390 | int timeout = 2500; | 390 | int timeout = 2500; |
| 391 | 391 | ||
| 392 | /* Poll on DATA0 line for cmd with busy signal for 250 ms */ | 392 | /* Poll on DATA0 line for cmd with busy signal for 250 ms */ |
| 393 | while (timeout > 0 && !(esdhc_read32(®s->prsstat) & | 393 | while (timeout > 0 && !(esdhc_read32(®s->prsstat) & |
| 394 | PRSSTAT_DAT0)) { | 394 | PRSSTAT_DAT0)) { |
| 395 | udelay(100); | 395 | udelay(100); |
| 396 | timeout--; | 396 | timeout--; |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | if (timeout <= 0) { | 399 | if (timeout <= 0) { |
| 400 | printf("Timeout waiting for DAT0 to go high!\n"); | 400 | printf("Timeout waiting for DAT0 to go high!\n"); |
| 401 | err = TIMEOUT; | 401 | err = TIMEOUT; |
| 402 | goto out; | 402 | goto out; |
| 403 | } | 403 | } |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | /* Copy the response to the response buffer */ | 406 | /* Copy the response to the response buffer */ |
| 407 | if (cmd->resp_type & MMC_RSP_136) { | 407 | if (cmd->resp_type & MMC_RSP_136) { |
| 408 | u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; | 408 | u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; |
| 409 | 409 | ||
| 410 | cmdrsp3 = esdhc_read32(®s->cmdrsp3); | 410 | cmdrsp3 = esdhc_read32(®s->cmdrsp3); |
| 411 | cmdrsp2 = esdhc_read32(®s->cmdrsp2); | 411 | cmdrsp2 = esdhc_read32(®s->cmdrsp2); |
| 412 | cmdrsp1 = esdhc_read32(®s->cmdrsp1); | 412 | cmdrsp1 = esdhc_read32(®s->cmdrsp1); |
| 413 | cmdrsp0 = esdhc_read32(®s->cmdrsp0); | 413 | cmdrsp0 = esdhc_read32(®s->cmdrsp0); |
| 414 | cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); | 414 | cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); |
| 415 | cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); | 415 | cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); |
| 416 | cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); | 416 | cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); |
| 417 | cmd->response[3] = (cmdrsp0 << 8); | 417 | cmd->response[3] = (cmdrsp0 << 8); |
| 418 | } else | 418 | } else |
| 419 | cmd->response[0] = esdhc_read32(®s->cmdrsp0); | 419 | cmd->response[0] = esdhc_read32(®s->cmdrsp0); |
| 420 | 420 | ||
| 421 | /* Wait until all of the blocks are transferred */ | 421 | /* Wait until all of the blocks are transferred */ |
| 422 | if (data) { | 422 | if (data) { |
| 423 | #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO | 423 | #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO |
| 424 | esdhc_pio_read_write(mmc, data); | 424 | esdhc_pio_read_write(mmc, data); |
| 425 | #else | 425 | #else |
| 426 | do { | 426 | do { |
| 427 | irqstat = esdhc_read32(®s->irqstat); | 427 | irqstat = esdhc_read32(®s->irqstat); |
| 428 | 428 | ||
| 429 | if (irqstat & IRQSTAT_DTOE) { | 429 | if (irqstat & IRQSTAT_DTOE) { |
| 430 | err = TIMEOUT; | 430 | err = TIMEOUT; |
| 431 | goto out; | 431 | goto out; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | if (irqstat & DATA_ERR) { | 434 | if (irqstat & DATA_ERR) { |
| 435 | err = COMM_ERR; | 435 | err = COMM_ERR; |
| 436 | goto out; | 436 | goto out; |
| 437 | } | 437 | } |
| 438 | } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); | 438 | } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); |
| 439 | 439 | ||
| 440 | if (data->flags & MMC_DATA_READ) | 440 | if (data->flags & MMC_DATA_READ) |
| 441 | check_and_invalidate_dcache_range(cmd, data); | 441 | check_and_invalidate_dcache_range(cmd, data); |
| 442 | #endif | 442 | #endif |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | out: | 445 | out: |
| 446 | /* Reset CMD and DATA portions on error */ | 446 | /* Reset CMD and DATA portions on error */ |
| 447 | if (err) { | 447 | if (err) { |
| 448 | esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | | 448 | esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | |
| 449 | SYSCTL_RSTC); | 449 | SYSCTL_RSTC); |
| 450 | while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) | 450 | while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) |
| 451 | ; | 451 | ; |
| 452 | 452 | ||
| 453 | if (data) { | 453 | if (data) { |
| 454 | esdhc_write32(®s->sysctl, | 454 | esdhc_write32(®s->sysctl, |
| 455 | esdhc_read32(®s->sysctl) | | 455 | esdhc_read32(®s->sysctl) | |
| 456 | SYSCTL_RSTD); | 456 | SYSCTL_RSTD); |
| 457 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) | 457 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) |
| 458 | ; | 458 | ; |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | /* If this was CMD11, then notify that power cycle is needed */ | 461 | /* If this was CMD11, then notify that power cycle is needed */ |
| 462 | if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) | 462 | if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) |
| 463 | printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); | 463 | printf("CMD11 to switch to 1.8V mode failed, card requires power cycle.\n"); |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | esdhc_write32(®s->irqstat, -1); | 466 | esdhc_write32(®s->irqstat, -1); |
| 467 | 467 | ||
| 468 | return err; | 468 | return err; |
| 469 | } | 469 | } |
| 470 | 470 | ||
| 471 | static void set_sysctl(struct mmc *mmc, uint clock) | 471 | static void set_sysctl(struct mmc *mmc, uint clock) |
| 472 | { | 472 | { |
| 473 | int div, pre_div; | 473 | int div, pre_div; |
| 474 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 474 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 475 | volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 475 | volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 476 | int sdhc_clk = cfg->sdhc_clk; | 476 | int sdhc_clk = cfg->sdhc_clk; |
| 477 | uint clk; | 477 | uint clk; |
| 478 | 478 | ||
| 479 | if (clock < mmc->cfg->f_min) | 479 | if (clock < mmc->cfg->f_min) |
| 480 | clock = mmc->cfg->f_min; | 480 | clock = mmc->cfg->f_min; |
| 481 | 481 | ||
| 482 | if (sdhc_clk / 16 > clock) { | 482 | if (sdhc_clk / 16 > clock) { |
| 483 | for (pre_div = 2; pre_div < 256; pre_div *= 2) | 483 | for (pre_div = 2; pre_div < 256; pre_div *= 2) |
| 484 | if ((sdhc_clk / pre_div) <= (clock * 16)) | 484 | if ((sdhc_clk / pre_div) <= (clock * 16)) |
| 485 | break; | 485 | break; |
| 486 | } else | 486 | } else |
| 487 | pre_div = 2; | 487 | pre_div = 2; |
| 488 | 488 | ||
| 489 | for (div = 1; div <= 16; div++) | 489 | for (div = 1; div <= 16; div++) |
| 490 | if ((sdhc_clk / (div * pre_div)) <= clock) | 490 | if ((sdhc_clk / (div * pre_div)) <= clock) |
| 491 | break; | 491 | break; |
| 492 | 492 | ||
| 493 | pre_div >>= mmc->ddr_mode ? 2 : 1; | 493 | pre_div >>= mmc->ddr_mode ? 2 : 1; |
| 494 | div -= 1; | 494 | div -= 1; |
| 495 | 495 | ||
| 496 | clk = (pre_div << 8) | (div << 4); | 496 | clk = (pre_div << 8) | (div << 4); |
| 497 | 497 | ||
| 498 | esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); | 498 | esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); |
| 499 | 499 | ||
| 500 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); | 500 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); |
| 501 | 501 | ||
| 502 | udelay(10000); | 502 | udelay(10000); |
| 503 | 503 | ||
| 504 | clk = SYSCTL_PEREN | SYSCTL_CKEN; | 504 | clk = SYSCTL_PEREN | SYSCTL_CKEN; |
| 505 | 505 | ||
| 506 | esdhc_setbits32(®s->sysctl, clk); | 506 | esdhc_setbits32(®s->sysctl, clk); |
| 507 | } | 507 | } |
| 508 | 508 | ||
| 509 | static void esdhc_set_ios(struct mmc *mmc) | 509 | static void esdhc_set_ios(struct mmc *mmc) |
| 510 | { | 510 | { |
| 511 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 511 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 512 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 512 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 513 | 513 | ||
| 514 | /* Set the clock speed */ | 514 | /* Set the clock speed */ |
| 515 | set_sysctl(mmc, mmc->clock); | 515 | set_sysctl(mmc, mmc->clock); |
| 516 | 516 | ||
| 517 | /* Set the bus width */ | 517 | /* Set the bus width */ |
| 518 | esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); | 518 | esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); |
| 519 | 519 | ||
| 520 | if (mmc->bus_width == 4) | 520 | if (mmc->bus_width == 4) |
| 521 | esdhc_setbits32(®s->proctl, PROCTL_DTW_4); | 521 | esdhc_setbits32(®s->proctl, PROCTL_DTW_4); |
| 522 | else if (mmc->bus_width == 8) | 522 | else if (mmc->bus_width == 8) |
| 523 | esdhc_setbits32(®s->proctl, PROCTL_DTW_8); | 523 | esdhc_setbits32(®s->proctl, PROCTL_DTW_8); |
| 524 | 524 | ||
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | static int esdhc_init(struct mmc *mmc) | 527 | static int esdhc_init(struct mmc *mmc) |
| 528 | { | 528 | { |
| 529 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 529 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 530 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 530 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 531 | int timeout = 1000; | 531 | int timeout = 1000; |
| 532 | 532 | ||
| 533 | /* Reset the entire host controller */ | 533 | /* Reset the entire host controller */ |
| 534 | esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); | 534 | esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); |
| 535 | 535 | ||
| 536 | /* Wait until the controller is available */ | 536 | /* Wait until the controller is available */ |
| 537 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) | 537 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) |
| 538 | udelay(1000); | 538 | udelay(1000); |
| 539 | 539 | ||
| 540 | #ifndef ARCH_MXC | 540 | #ifndef ARCH_MXC |
| 541 | /* Enable cache snooping */ | 541 | /* Enable cache snooping */ |
| 542 | esdhc_write32(®s->scr, 0x00000040); | 542 | esdhc_write32(®s->scr, 0x00000040); |
| 543 | #endif | 543 | #endif |
| 544 | 544 | ||
| 545 | esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); | 545 | esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); |
| 546 | 546 | ||
| 547 | /* Set the initial clock speed */ | 547 | /* Set the initial clock speed */ |
| 548 | mmc_set_clock(mmc, 400000); | 548 | mmc_set_clock(mmc, 400000); |
| 549 | 549 | ||
| 550 | /* Disable the BRR and BWR bits in IRQSTAT */ | 550 | /* Disable the BRR and BWR bits in IRQSTAT */ |
| 551 | esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); | 551 | esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); |
| 552 | 552 | ||
| 553 | /* Put the PROCTL reg back to the default */ | 553 | /* Put the PROCTL reg back to the default */ |
| 554 | esdhc_write32(®s->proctl, PROCTL_INIT); | 554 | esdhc_write32(®s->proctl, PROCTL_INIT); |
| 555 | 555 | ||
| 556 | /* Set timout to the maximum value */ | 556 | /* Set timout to the maximum value */ |
| 557 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); | 557 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); |
| 558 | 558 | ||
| 559 | #ifdef CONFIG_SYS_FSL_ESDHC_FORCE_VSELECT | 559 | #ifdef CONFIG_SYS_FSL_ESDHC_FORCE_VSELECT |
| 560 | esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); | 560 | esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); |
| 561 | #endif | 561 | #endif |
| 562 | 562 | ||
| 563 | return 0; | 563 | return 0; |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | static int esdhc_getcd(struct mmc *mmc) | 566 | static int esdhc_getcd(struct mmc *mmc) |
| 567 | { | 567 | { |
| 568 | struct fsl_esdhc_cfg *cfg = mmc->priv; | 568 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
| 569 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; | 569 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 570 | int timeout = 1000; | 570 | int timeout = 1000; |
| 571 | 571 | ||
| 572 | #ifdef CONFIG_ESDHC_DETECT_QUIRK | 572 | #ifdef CONFIG_ESDHC_DETECT_QUIRK |
| 573 | if (CONFIG_ESDHC_DETECT_QUIRK) | 573 | if (CONFIG_ESDHC_DETECT_QUIRK) |
| 574 | return 1; | 574 | return 1; |
| 575 | #endif | 575 | #endif |
| 576 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) | 576 | while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) |
| 577 | udelay(1000); | 577 | udelay(1000); |
| 578 | 578 | ||
| 579 | return timeout > 0; | 579 | return timeout > 0; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | static void esdhc_reset(struct fsl_esdhc *regs) | 582 | static void esdhc_reset(struct fsl_esdhc *regs) |
| 583 | { | 583 | { |
| 584 | unsigned long timeout = 100; /* wait max 100 ms */ | 584 | unsigned long timeout = 100; /* wait max 100 ms */ |
| 585 | 585 | ||
| 586 | /* reset the controller */ | 586 | /* reset the controller */ |
| 587 | esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); | 587 | esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); |
| 588 | 588 | ||
| 589 | /* hardware clears the bit when it is done */ | 589 | /* hardware clears the bit when it is done */ |
| 590 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) | 590 | while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) |
| 591 | udelay(1000); | 591 | udelay(1000); |
| 592 | if (!timeout) | 592 | if (!timeout) |
| 593 | printf("MMC/SD: Reset never completed.\n"); | 593 | printf("MMC/SD: Reset never completed.\n"); |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | static const struct mmc_ops esdhc_ops = { | 596 | static const struct mmc_ops esdhc_ops = { |
| 597 | .send_cmd = esdhc_send_cmd, | 597 | .send_cmd = esdhc_send_cmd, |
| 598 | .set_ios = esdhc_set_ios, | 598 | .set_ios = esdhc_set_ios, |
| 599 | .init = esdhc_init, | 599 | .init = esdhc_init, |
| 600 | .getcd = esdhc_getcd, | 600 | .getcd = esdhc_getcd, |
| 601 | }; | 601 | }; |
| 602 | 602 | ||
| 603 | int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) | 603 | int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) |
| 604 | { | 604 | { |
| 605 | struct fsl_esdhc *regs; | 605 | struct fsl_esdhc *regs; |
| 606 | struct mmc *mmc; | 606 | struct mmc *mmc; |
| 607 | u32 caps, voltage_caps; | 607 | u32 caps, voltage_caps; |
| 608 | 608 | ||
| 609 | if (!cfg) | 609 | if (!cfg) |
| 610 | return -1; | 610 | return -1; |
| 611 | 611 | ||
| 612 | regs = (struct fsl_esdhc *)cfg->esdhc_base; | 612 | regs = (struct fsl_esdhc *)cfg->esdhc_base; |
| 613 | 613 | ||
| 614 | /* First reset the eSDHC controller */ | 614 | /* First reset the eSDHC controller */ |
| 615 | esdhc_reset(regs); | 615 | esdhc_reset(regs); |
| 616 | 616 | ||
| 617 | esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | 617 | esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN |
| 618 | | SYSCTL_IPGEN | SYSCTL_CKEN); | 618 | | SYSCTL_IPGEN | SYSCTL_CKEN); |
| 619 | 619 | ||
| 620 | writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); | 620 | writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); |
| 621 | memset(&cfg->cfg, 0, sizeof(cfg->cfg)); | 621 | memset(&cfg->cfg, 0, sizeof(cfg->cfg)); |
| 622 | 622 | ||
| 623 | voltage_caps = 0; | 623 | voltage_caps = 0; |
| 624 | caps = esdhc_read32(®s->hostcapblt); | 624 | caps = esdhc_read32(®s->hostcapblt); |
| 625 | 625 | ||
| 626 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 | 626 | #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 |
| 627 | caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | | 627 | caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | |
| 628 | ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); | 628 | ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); |
| 629 | #endif | 629 | #endif |
| 630 | 630 | ||
| 631 | /* T4240 host controller capabilities register should have VS33 bit */ | 631 | /* T4240 host controller capabilities register should have VS33 bit */ |
| 632 | #ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 | 632 | #ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 |
| 633 | caps = caps | ESDHC_HOSTCAPBLT_VS33; | 633 | caps = caps | ESDHC_HOSTCAPBLT_VS33; |
| 634 | #endif | 634 | #endif |
| 635 | 635 | ||
| 636 | if (caps & ESDHC_HOSTCAPBLT_VS18) | 636 | if (caps & ESDHC_HOSTCAPBLT_VS18) |
| 637 | voltage_caps |= MMC_VDD_165_195; | 637 | voltage_caps |= MMC_VDD_165_195; |
| 638 | if (caps & ESDHC_HOSTCAPBLT_VS30) | 638 | if (caps & ESDHC_HOSTCAPBLT_VS30) |
| 639 | voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31; | 639 | voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31; |
| 640 | if (caps & ESDHC_HOSTCAPBLT_VS33) | 640 | if (caps & ESDHC_HOSTCAPBLT_VS33) |
| 641 | voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; | 641 | voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; |
| 642 | 642 | ||
| 643 | cfg->cfg.name = "FSL_SDHC"; | 643 | cfg->cfg.name = "FSL_SDHC"; |
| 644 | cfg->cfg.ops = &esdhc_ops; | 644 | cfg->cfg.ops = &esdhc_ops; |
| 645 | #ifdef CONFIG_SYS_SD_VOLTAGE | 645 | #ifdef CONFIG_SYS_SD_VOLTAGE |
| 646 | cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE; | 646 | cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE; |
| 647 | #else | 647 | #else |
| 648 | cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; | 648 | cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
| 649 | #endif | 649 | #endif |
| 650 | if ((cfg->cfg.voltages & voltage_caps) == 0) { | 650 | if ((cfg->cfg.voltages & voltage_caps) == 0) { |
| 651 | printf("voltage not supported by controller\n"); | 651 | printf("voltage not supported by controller\n"); |
| 652 | return -1; | 652 | return -1; |
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; | 655 | cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; |
| 656 | #ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE | 656 | #ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE |
| 657 | cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; | 657 | cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz; |
| 658 | #endif | 658 | #endif |
| 659 | 659 | ||
| 660 | if (cfg->max_bus_width > 0) { | 660 | if (cfg->max_bus_width > 0) { |
| 661 | if (cfg->max_bus_width < 8) | 661 | if (cfg->max_bus_width < 8) |
| 662 | cfg->cfg.host_caps &= ~MMC_MODE_8BIT; | 662 | cfg->cfg.host_caps &= ~MMC_MODE_8BIT; |
| 663 | if (cfg->max_bus_width < 4) | 663 | if (cfg->max_bus_width < 4) |
| 664 | cfg->cfg.host_caps &= ~MMC_MODE_4BIT; | 664 | cfg->cfg.host_caps &= ~MMC_MODE_4BIT; |
| 665 | } | 665 | } |
| 666 | 666 | ||
| 667 | if (caps & ESDHC_HOSTCAPBLT_HSS) | 667 | if (caps & ESDHC_HOSTCAPBLT_HSS) |
| 668 | cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; | 668 | cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 669 | 669 | ||
| 670 | #ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK | 670 | #ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK |
| 671 | if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) | 671 | if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) |
| 672 | cfg->cfg.host_caps &= ~MMC_MODE_8BIT; | 672 | cfg->cfg.host_caps &= ~MMC_MODE_8BIT; |
| 673 | #endif | 673 | #endif |
| 674 | 674 | ||
| 675 | cfg->cfg.f_min = 400000; | 675 | cfg->cfg.f_min = 400000; |
| 676 | cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000); | 676 | cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000); |
| 677 | 677 | ||
| 678 | cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 678 | cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
| 679 | 679 | ||
| 680 | mmc = mmc_create(&cfg->cfg, cfg); | 680 | mmc = mmc_create(&cfg->cfg, cfg); |
| 681 | if (mmc == NULL) | 681 | if (mmc == NULL) |
| 682 | return -1; | 682 | return -1; |
| 683 | 683 | ||
| 684 | return 0; | 684 | return 0; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | int fsl_esdhc_mmc_init(bd_t *bis) | 687 | int fsl_esdhc_mmc_init(bd_t *bis) |
| 688 | { | 688 | { |
| 689 | struct fsl_esdhc_cfg *cfg; | 689 | struct fsl_esdhc_cfg *cfg; |
| 690 | 690 | ||
| 691 | cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1); | 691 | cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1); |
| 692 | cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; | 692 | cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; |
| 693 | cfg->sdhc_clk = gd->arch.sdhc_clk; | 693 | cfg->sdhc_clk = gd->arch.sdhc_clk; |
| 694 | return fsl_esdhc_initialize(bis, cfg); | 694 | return fsl_esdhc_initialize(bis, cfg); |
| 695 | } | 695 | } |
| 696 | 696 | ||
| 697 | #ifdef CONFIG_OF_LIBFDT | 697 | #ifdef CONFIG_OF_LIBFDT |
| 698 | void fdt_fixup_esdhc(void *blob, bd_t *bd) | 698 | void fdt_fixup_esdhc(void *blob, bd_t *bd) |
| 699 | { | 699 | { |
| 700 | const char *compat = "fsl,esdhc"; | 700 | const char *compat = "fsl,esdhc"; |
| 701 | 701 | ||
| 702 | #ifdef CONFIG_FSL_ESDHC_PIN_MUX | 702 | #ifdef CONFIG_FSL_ESDHC_PIN_MUX |
| 703 | if (!hwconfig("esdhc")) { | 703 | if (!hwconfig("esdhc")) { |
| 704 | do_fixup_by_compat(blob, compat, "status", "disabled", | 704 | do_fixup_by_compat(blob, compat, "status", "disabled", |
| 705 | 8 + 1, 1); | 705 | 8 + 1, 1); |
| 706 | return; | 706 | return; |
| 707 | } | 707 | } |
| 708 | #endif | 708 | #endif |
| 709 | 709 | ||
| 710 | do_fixup_by_compat_u32(blob, compat, "clock-frequency", | 710 | do_fixup_by_compat_u32(blob, compat, "clock-frequency", |
| 711 | gd->arch.sdhc_clk, 1); | 711 | gd->arch.sdhc_clk, 1); |
| 712 | 712 | ||
| 713 | do_fixup_by_compat(blob, compat, "status", "okay", | 713 | do_fixup_by_compat(blob, compat, "status", "okay", |
| 714 | 4 + 1, 1); | 714 | 4 + 1, 1); |
| 715 | } | 715 | } |
| 716 | #endif | 716 | #endif |
| 717 | 717 |
drivers/mmc/kona_sdhci.c
| 1 | /* | 1 | /* |
| 2 | * Copyright 2013 Broadcom Corporation. | 2 | * Copyright 2013 Broadcom Corporation. |
| 3 | * | 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0+ | 4 | * SPDX-License-Identifier: GPL-2.0+ |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <common.h> | 7 | #include <common.h> |
| 8 | #include <malloc.h> | 8 | #include <malloc.h> |
| 9 | #include <sdhci.h> | 9 | #include <sdhci.h> |
| 10 | #include <asm/errno.h> | 10 | #include <asm/errno.h> |
| 11 | #include <asm/kona-common/clk.h> | 11 | #include <asm/kona-common/clk.h> |
| 12 | 12 | ||
| 13 | #define SDHCI_CORECTRL_OFFSET 0x00008000 | 13 | #define SDHCI_CORECTRL_OFFSET 0x00008000 |
| 14 | #define SDHCI_CORECTRL_EN 0x01 | 14 | #define SDHCI_CORECTRL_EN 0x01 |
| 15 | #define SDHCI_CORECTRL_RESET 0x02 | 15 | #define SDHCI_CORECTRL_RESET 0x02 |
| 16 | 16 | ||
| 17 | #define SDHCI_CORESTAT_OFFSET 0x00008004 | 17 | #define SDHCI_CORESTAT_OFFSET 0x00008004 |
| 18 | #define SDHCI_CORESTAT_CD_SW 0x01 | 18 | #define SDHCI_CORESTAT_CD_SW 0x01 |
| 19 | 19 | ||
| 20 | #define SDHCI_COREIMR_OFFSET 0x00008008 | 20 | #define SDHCI_COREIMR_OFFSET 0x00008008 |
| 21 | #define SDHCI_COREIMR_IP 0x01 | 21 | #define SDHCI_COREIMR_IP 0x01 |
| 22 | 22 | ||
| 23 | static int init_kona_mmc_core(struct sdhci_host *host) | 23 | static int init_kona_mmc_core(struct sdhci_host *host) |
| 24 | { | 24 | { |
| 25 | unsigned int mask; | 25 | unsigned int mask; |
| 26 | unsigned int timeout; | 26 | unsigned int timeout; |
| 27 | 27 | ||
| 28 | if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) { | 28 | if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) { |
| 29 | printf("%s: sd host controller reset error\n", __func__); | 29 | printf("%s: sd host controller reset error\n", __func__); |
| 30 | return 1; | 30 | return 1; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | /* For kona a hardware reset before anything else. */ | 33 | /* For kona a hardware reset before anything else. */ |
| 34 | mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET; | 34 | mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET; |
| 35 | sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); | 35 | sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); |
| 36 | 36 | ||
| 37 | /* Wait max 100 ms */ | 37 | /* Wait max 100 ms */ |
| 38 | timeout = 1000; | 38 | timeout = 1000; |
| 39 | do { | 39 | do { |
| 40 | if (timeout == 0) { | 40 | if (timeout == 0) { |
| 41 | printf("%s: reset timeout error\n", __func__); | 41 | printf("%s: reset timeout error\n", __func__); |
| 42 | return 1; | 42 | return 1; |
| 43 | } | 43 | } |
| 44 | timeout--; | 44 | timeout--; |
| 45 | udelay(100); | 45 | udelay(100); |
| 46 | } while (0 == | 46 | } while (0 == |
| 47 | (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) & | 47 | (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) & |
| 48 | SDHCI_CORECTRL_RESET)); | 48 | SDHCI_CORECTRL_RESET)); |
| 49 | 49 | ||
| 50 | /* Clear the reset bit. */ | 50 | /* Clear the reset bit. */ |
| 51 | mask = mask & ~SDHCI_CORECTRL_RESET; | 51 | mask = mask & ~SDHCI_CORECTRL_RESET; |
| 52 | sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); | 52 | sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET); |
| 53 | 53 | ||
| 54 | /* Enable AHB clock */ | 54 | /* Enable AHB clock */ |
| 55 | mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET); | 55 | mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET); |
| 56 | sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET); | 56 | sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET); |
| 57 | 57 | ||
| 58 | /* Enable interrupts */ | 58 | /* Enable interrupts */ |
| 59 | sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET); | 59 | sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET); |
| 60 | 60 | ||
| 61 | /* Make sure Card is detected in controller */ | 61 | /* Make sure Card is detected in controller */ |
| 62 | mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET); | 62 | mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET); |
| 63 | sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET); | 63 | sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET); |
| 64 | 64 | ||
| 65 | /* Wait max 100 ms */ | 65 | /* Wait max 100 ms */ |
| 66 | timeout = 1000; | 66 | timeout = 1000; |
| 67 | while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { | 67 | while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { |
| 68 | if (timeout == 0) { | 68 | if (timeout == 0) { |
| 69 | printf("%s: CARD DETECT timeout error\n", __func__); | 69 | printf("%s: CARD DETECT timeout error\n", __func__); |
| 70 | return 1; | 70 | return 1; |
| 71 | } | 71 | } |
| 72 | timeout--; | 72 | timeout--; |
| 73 | udelay(100); | 73 | udelay(100); |
| 74 | } | 74 | } |
| 75 | return 0; | 75 | return 0; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks) | 78 | int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks) |
| 79 | { | 79 | { |
| 80 | int ret = 0; | 80 | int ret = 0; |
| 81 | u32 max_clk; | 81 | u32 max_clk; |
| 82 | void *reg_base; | 82 | void *reg_base; |
| 83 | struct sdhci_host *host = NULL; | 83 | struct sdhci_host *host = NULL; |
| 84 | 84 | ||
| 85 | host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); | 85 | host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); |
| 86 | if (!host) { | 86 | if (!host) { |
| 87 | printf("%s: sdhci host malloc fail!\n", __func__); | 87 | printf("%s: sdhci host malloc fail!\n", __func__); |
| 88 | return -ENOMEM; | 88 | return -ENOMEM; |
| 89 | } | 89 | } |
| 90 | switch (dev_index) { | 90 | switch (dev_index) { |
| 91 | case 0: | 91 | case 0: |
| 92 | reg_base = (void *)CONFIG_SYS_SDIO_BASE0; | 92 | reg_base = (void *)CONFIG_SYS_SDIO_BASE0; |
| 93 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK, | 93 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK, |
| 94 | &max_clk); | 94 | &max_clk); |
| 95 | break; | 95 | break; |
| 96 | case 1: | 96 | case 1: |
| 97 | reg_base = (void *)CONFIG_SYS_SDIO_BASE1; | 97 | reg_base = (void *)CONFIG_SYS_SDIO_BASE1; |
| 98 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK, | 98 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK, |
| 99 | &max_clk); | 99 | &max_clk); |
| 100 | break; | 100 | break; |
| 101 | case 2: | 101 | case 2: |
| 102 | reg_base = (void *)CONFIG_SYS_SDIO_BASE2; | 102 | reg_base = (void *)CONFIG_SYS_SDIO_BASE2; |
| 103 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK, | 103 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK, |
| 104 | &max_clk); | 104 | &max_clk); |
| 105 | break; | 105 | break; |
| 106 | case 3: | 106 | case 3: |
| 107 | reg_base = (void *)CONFIG_SYS_SDIO_BASE3; | 107 | reg_base = (void *)CONFIG_SYS_SDIO_BASE3; |
| 108 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK, | 108 | ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK, |
| 109 | &max_clk); | 109 | &max_clk); |
| 110 | break; | 110 | break; |
| 111 | default: | 111 | default: |
| 112 | printf("%s: sdio dev index %d not supported\n", | 112 | printf("%s: sdio dev index %d not supported\n", |
| 113 | __func__, dev_index); | 113 | __func__, dev_index); |
| 114 | ret = -EINVAL; | 114 | ret = -EINVAL; |
| 115 | } | 115 | } |
| 116 | if (ret) { | 116 | if (ret) { |
| 117 | free(host); | 117 | free(host); |
| 118 | return ret; | 118 | return ret; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | host->name = "kona-sdhci"; | 121 | host->name = "kona-sdhci"; |
| 122 | host->ioaddr = reg_base; | 122 | host->ioaddr = reg_base; |
| 123 | host->quirks = quirks; | 123 | host->quirks = quirks; |
| 124 | host->host_caps = MMC_MODE_HC; | ||
| 125 | 124 | ||
| 126 | if (init_kona_mmc_core(host)) { | 125 | if (init_kona_mmc_core(host)) { |
| 127 | free(host); | 126 | free(host); |
| 128 | return -EINVAL; | 127 | return -EINVAL; |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | if (quirks & SDHCI_QUIRK_REG32_RW) | 130 | if (quirks & SDHCI_QUIRK_REG32_RW) |
| 132 | host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; | 131 | host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; |
| 133 | else | 132 | else |
| 134 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); | 133 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); |
| 135 | 134 | ||
| 136 | add_sdhci(host, max_clk, min_clk); | 135 | add_sdhci(host, max_clk, min_clk); |
| 137 | return ret; | 136 | return ret; |
| 138 | } | 137 | } |
| 139 | 138 |
drivers/mmc/mmc.c
| 1 | /* | 1 | /* |
| 2 | * Copyright 2008, Freescale Semiconductor, Inc | 2 | * Copyright 2008, Freescale Semiconductor, Inc |
| 3 | * Andy Fleming | 3 | * Andy Fleming |
| 4 | * | 4 | * |
| 5 | * Based vaguely on the Linux code | 5 | * Based vaguely on the Linux code |
| 6 | * | 6 | * |
| 7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <config.h> | 10 | #include <config.h> |
| 11 | #include <common.h> | 11 | #include <common.h> |
| 12 | #include <command.h> | 12 | #include <command.h> |
| 13 | #include <errno.h> | 13 | #include <errno.h> |
| 14 | #include <mmc.h> | 14 | #include <mmc.h> |
| 15 | #include <part.h> | 15 | #include <part.h> |
| 16 | #include <malloc.h> | 16 | #include <malloc.h> |
| 17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
| 18 | #include <div64.h> | 18 | #include <div64.h> |
| 19 | #include "mmc_private.h" | 19 | #include "mmc_private.h" |
| 20 | 20 | ||
| 21 | static struct list_head mmc_devices; | 21 | static struct list_head mmc_devices; |
| 22 | static int cur_dev_num = -1; | 22 | static int cur_dev_num = -1; |
| 23 | 23 | ||
| 24 | __weak int board_mmc_getwp(struct mmc *mmc) | 24 | __weak int board_mmc_getwp(struct mmc *mmc) |
| 25 | { | 25 | { |
| 26 | return -1; | 26 | return -1; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | int mmc_getwp(struct mmc *mmc) | 29 | int mmc_getwp(struct mmc *mmc) |
| 30 | { | 30 | { |
| 31 | int wp; | 31 | int wp; |
| 32 | 32 | ||
| 33 | wp = board_mmc_getwp(mmc); | 33 | wp = board_mmc_getwp(mmc); |
| 34 | 34 | ||
| 35 | if (wp < 0) { | 35 | if (wp < 0) { |
| 36 | if (mmc->cfg->ops->getwp) | 36 | if (mmc->cfg->ops->getwp) |
| 37 | wp = mmc->cfg->ops->getwp(mmc); | 37 | wp = mmc->cfg->ops->getwp(mmc); |
| 38 | else | 38 | else |
| 39 | wp = 0; | 39 | wp = 0; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | return wp; | 42 | return wp; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | __weak int board_mmc_getcd(struct mmc *mmc) | 45 | __weak int board_mmc_getcd(struct mmc *mmc) |
| 46 | { | 46 | { |
| 47 | return -1; | 47 | return -1; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | 50 | int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) |
| 51 | { | 51 | { |
| 52 | int ret; | 52 | int ret; |
| 53 | 53 | ||
| 54 | #ifdef CONFIG_MMC_TRACE | 54 | #ifdef CONFIG_MMC_TRACE |
| 55 | int i; | 55 | int i; |
| 56 | u8 *ptr; | 56 | u8 *ptr; |
| 57 | 57 | ||
| 58 | printf("CMD_SEND:%d\n", cmd->cmdidx); | 58 | printf("CMD_SEND:%d\n", cmd->cmdidx); |
| 59 | printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); | 59 | printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); |
| 60 | ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); | 60 | ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); |
| 61 | switch (cmd->resp_type) { | 61 | switch (cmd->resp_type) { |
| 62 | case MMC_RSP_NONE: | 62 | case MMC_RSP_NONE: |
| 63 | printf("\t\tMMC_RSP_NONE\n"); | 63 | printf("\t\tMMC_RSP_NONE\n"); |
| 64 | break; | 64 | break; |
| 65 | case MMC_RSP_R1: | 65 | case MMC_RSP_R1: |
| 66 | printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", | 66 | printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", |
| 67 | cmd->response[0]); | 67 | cmd->response[0]); |
| 68 | break; | 68 | break; |
| 69 | case MMC_RSP_R1b: | 69 | case MMC_RSP_R1b: |
| 70 | printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", | 70 | printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", |
| 71 | cmd->response[0]); | 71 | cmd->response[0]); |
| 72 | break; | 72 | break; |
| 73 | case MMC_RSP_R2: | 73 | case MMC_RSP_R2: |
| 74 | printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", | 74 | printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", |
| 75 | cmd->response[0]); | 75 | cmd->response[0]); |
| 76 | printf("\t\t \t\t 0x%08X \n", | 76 | printf("\t\t \t\t 0x%08X \n", |
| 77 | cmd->response[1]); | 77 | cmd->response[1]); |
| 78 | printf("\t\t \t\t 0x%08X \n", | 78 | printf("\t\t \t\t 0x%08X \n", |
| 79 | cmd->response[2]); | 79 | cmd->response[2]); |
| 80 | printf("\t\t \t\t 0x%08X \n", | 80 | printf("\t\t \t\t 0x%08X \n", |
| 81 | cmd->response[3]); | 81 | cmd->response[3]); |
| 82 | printf("\n"); | 82 | printf("\n"); |
| 83 | printf("\t\t\t\t\tDUMPING DATA\n"); | 83 | printf("\t\t\t\t\tDUMPING DATA\n"); |
| 84 | for (i = 0; i < 4; i++) { | 84 | for (i = 0; i < 4; i++) { |
| 85 | int j; | 85 | int j; |
| 86 | printf("\t\t\t\t\t%03d - ", i*4); | 86 | printf("\t\t\t\t\t%03d - ", i*4); |
| 87 | ptr = (u8 *)&cmd->response[i]; | 87 | ptr = (u8 *)&cmd->response[i]; |
| 88 | ptr += 3; | 88 | ptr += 3; |
| 89 | for (j = 0; j < 4; j++) | 89 | for (j = 0; j < 4; j++) |
| 90 | printf("%02X ", *ptr--); | 90 | printf("%02X ", *ptr--); |
| 91 | printf("\n"); | 91 | printf("\n"); |
| 92 | } | 92 | } |
| 93 | break; | 93 | break; |
| 94 | case MMC_RSP_R3: | 94 | case MMC_RSP_R3: |
| 95 | printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", | 95 | printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", |
| 96 | cmd->response[0]); | 96 | cmd->response[0]); |
| 97 | break; | 97 | break; |
| 98 | default: | 98 | default: |
| 99 | printf("\t\tERROR MMC rsp not supported\n"); | 99 | printf("\t\tERROR MMC rsp not supported\n"); |
| 100 | break; | 100 | break; |
| 101 | } | 101 | } |
| 102 | #else | 102 | #else |
| 103 | ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); | 103 | ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); |
| 104 | #endif | 104 | #endif |
| 105 | return ret; | 105 | return ret; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | int mmc_send_status(struct mmc *mmc, int timeout) | 108 | int mmc_send_status(struct mmc *mmc, int timeout) |
| 109 | { | 109 | { |
| 110 | struct mmc_cmd cmd; | 110 | struct mmc_cmd cmd; |
| 111 | int err, retries = 5; | 111 | int err, retries = 5; |
| 112 | #ifdef CONFIG_MMC_TRACE | 112 | #ifdef CONFIG_MMC_TRACE |
| 113 | int status; | 113 | int status; |
| 114 | #endif | 114 | #endif |
| 115 | 115 | ||
| 116 | cmd.cmdidx = MMC_CMD_SEND_STATUS; | 116 | cmd.cmdidx = MMC_CMD_SEND_STATUS; |
| 117 | cmd.resp_type = MMC_RSP_R1; | 117 | cmd.resp_type = MMC_RSP_R1; |
| 118 | if (!mmc_host_is_spi(mmc)) | 118 | if (!mmc_host_is_spi(mmc)) |
| 119 | cmd.cmdarg = mmc->rca << 16; | 119 | cmd.cmdarg = mmc->rca << 16; |
| 120 | 120 | ||
| 121 | while (1) { | 121 | while (1) { |
| 122 | err = mmc_send_cmd(mmc, &cmd, NULL); | 122 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 123 | if (!err) { | 123 | if (!err) { |
| 124 | if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && | 124 | if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && |
| 125 | (cmd.response[0] & MMC_STATUS_CURR_STATE) != | 125 | (cmd.response[0] & MMC_STATUS_CURR_STATE) != |
| 126 | MMC_STATE_PRG) | 126 | MMC_STATE_PRG) |
| 127 | break; | 127 | break; |
| 128 | else if (cmd.response[0] & MMC_STATUS_MASK) { | 128 | else if (cmd.response[0] & MMC_STATUS_MASK) { |
| 129 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 129 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 130 | printf("Status Error: 0x%08X\n", | 130 | printf("Status Error: 0x%08X\n", |
| 131 | cmd.response[0]); | 131 | cmd.response[0]); |
| 132 | #endif | 132 | #endif |
| 133 | return COMM_ERR; | 133 | return COMM_ERR; |
| 134 | } | 134 | } |
| 135 | } else if (--retries < 0) | 135 | } else if (--retries < 0) |
| 136 | return err; | 136 | return err; |
| 137 | 137 | ||
| 138 | if (timeout-- <= 0) | 138 | if (timeout-- <= 0) |
| 139 | break; | 139 | break; |
| 140 | 140 | ||
| 141 | udelay(1000); | 141 | udelay(1000); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | #ifdef CONFIG_MMC_TRACE | 144 | #ifdef CONFIG_MMC_TRACE |
| 145 | status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; | 145 | status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; |
| 146 | printf("CURR STATE:%d\n", status); | 146 | printf("CURR STATE:%d\n", status); |
| 147 | #endif | 147 | #endif |
| 148 | if (timeout <= 0) { | 148 | if (timeout <= 0) { |
| 149 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 149 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 150 | printf("Timeout waiting card ready\n"); | 150 | printf("Timeout waiting card ready\n"); |
| 151 | #endif | 151 | #endif |
| 152 | return TIMEOUT; | 152 | return TIMEOUT; |
| 153 | } | 153 | } |
| 154 | if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) | 154 | if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) |
| 155 | return SWITCH_ERR; | 155 | return SWITCH_ERR; |
| 156 | 156 | ||
| 157 | return 0; | 157 | return 0; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | int mmc_set_blocklen(struct mmc *mmc, int len) | 160 | int mmc_set_blocklen(struct mmc *mmc, int len) |
| 161 | { | 161 | { |
| 162 | struct mmc_cmd cmd; | 162 | struct mmc_cmd cmd; |
| 163 | 163 | ||
| 164 | if (mmc->ddr_mode) | 164 | if (mmc->ddr_mode) |
| 165 | return 0; | 165 | return 0; |
| 166 | 166 | ||
| 167 | cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; | 167 | cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; |
| 168 | cmd.resp_type = MMC_RSP_R1; | 168 | cmd.resp_type = MMC_RSP_R1; |
| 169 | cmd.cmdarg = len; | 169 | cmd.cmdarg = len; |
| 170 | 170 | ||
| 171 | return mmc_send_cmd(mmc, &cmd, NULL); | 171 | return mmc_send_cmd(mmc, &cmd, NULL); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | struct mmc *find_mmc_device(int dev_num) | 174 | struct mmc *find_mmc_device(int dev_num) |
| 175 | { | 175 | { |
| 176 | struct mmc *m; | 176 | struct mmc *m; |
| 177 | struct list_head *entry; | 177 | struct list_head *entry; |
| 178 | 178 | ||
| 179 | list_for_each(entry, &mmc_devices) { | 179 | list_for_each(entry, &mmc_devices) { |
| 180 | m = list_entry(entry, struct mmc, link); | 180 | m = list_entry(entry, struct mmc, link); |
| 181 | 181 | ||
| 182 | if (m->block_dev.dev == dev_num) | 182 | if (m->block_dev.dev == dev_num) |
| 183 | return m; | 183 | return m; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 186 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 187 | printf("MMC Device %d not found\n", dev_num); | 187 | printf("MMC Device %d not found\n", dev_num); |
| 188 | #endif | 188 | #endif |
| 189 | 189 | ||
| 190 | return NULL; | 190 | return NULL; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, | 193 | static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, |
| 194 | lbaint_t blkcnt) | 194 | lbaint_t blkcnt) |
| 195 | { | 195 | { |
| 196 | struct mmc_cmd cmd; | 196 | struct mmc_cmd cmd; |
| 197 | struct mmc_data data; | 197 | struct mmc_data data; |
| 198 | 198 | ||
| 199 | if (blkcnt > 1) | 199 | if (blkcnt > 1) |
| 200 | cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; | 200 | cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; |
| 201 | else | 201 | else |
| 202 | cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; | 202 | cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; |
| 203 | 203 | ||
| 204 | if (mmc->high_capacity) | 204 | if (mmc->high_capacity) |
| 205 | cmd.cmdarg = start; | 205 | cmd.cmdarg = start; |
| 206 | else | 206 | else |
| 207 | cmd.cmdarg = start * mmc->read_bl_len; | 207 | cmd.cmdarg = start * mmc->read_bl_len; |
| 208 | 208 | ||
| 209 | cmd.resp_type = MMC_RSP_R1; | 209 | cmd.resp_type = MMC_RSP_R1; |
| 210 | 210 | ||
| 211 | data.dest = dst; | 211 | data.dest = dst; |
| 212 | data.blocks = blkcnt; | 212 | data.blocks = blkcnt; |
| 213 | data.blocksize = mmc->read_bl_len; | 213 | data.blocksize = mmc->read_bl_len; |
| 214 | data.flags = MMC_DATA_READ; | 214 | data.flags = MMC_DATA_READ; |
| 215 | 215 | ||
| 216 | if (mmc_send_cmd(mmc, &cmd, &data)) | 216 | if (mmc_send_cmd(mmc, &cmd, &data)) |
| 217 | return 0; | 217 | return 0; |
| 218 | 218 | ||
| 219 | if (blkcnt > 1) { | 219 | if (blkcnt > 1) { |
| 220 | cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; | 220 | cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; |
| 221 | cmd.cmdarg = 0; | 221 | cmd.cmdarg = 0; |
| 222 | cmd.resp_type = MMC_RSP_R1b; | 222 | cmd.resp_type = MMC_RSP_R1b; |
| 223 | if (mmc_send_cmd(mmc, &cmd, NULL)) { | 223 | if (mmc_send_cmd(mmc, &cmd, NULL)) { |
| 224 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 224 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 225 | printf("mmc fail to send stop cmd\n"); | 225 | printf("mmc fail to send stop cmd\n"); |
| 226 | #endif | 226 | #endif |
| 227 | return 0; | 227 | return 0; |
| 228 | } | 228 | } |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | return blkcnt; | 231 | return blkcnt; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) | 234 | static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) |
| 235 | { | 235 | { |
| 236 | lbaint_t cur, blocks_todo = blkcnt; | 236 | lbaint_t cur, blocks_todo = blkcnt; |
| 237 | 237 | ||
| 238 | if (blkcnt == 0) | 238 | if (blkcnt == 0) |
| 239 | return 0; | 239 | return 0; |
| 240 | 240 | ||
| 241 | struct mmc *mmc = find_mmc_device(dev_num); | 241 | struct mmc *mmc = find_mmc_device(dev_num); |
| 242 | if (!mmc) | 242 | if (!mmc) |
| 243 | return 0; | 243 | return 0; |
| 244 | 244 | ||
| 245 | if ((start + blkcnt) > mmc->block_dev.lba) { | 245 | if ((start + blkcnt) > mmc->block_dev.lba) { |
| 246 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 246 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 247 | printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", | 247 | printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", |
| 248 | start + blkcnt, mmc->block_dev.lba); | 248 | start + blkcnt, mmc->block_dev.lba); |
| 249 | #endif | 249 | #endif |
| 250 | return 0; | 250 | return 0; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | if (mmc_set_blocklen(mmc, mmc->read_bl_len)) | 253 | if (mmc_set_blocklen(mmc, mmc->read_bl_len)) |
| 254 | return 0; | 254 | return 0; |
| 255 | 255 | ||
| 256 | do { | 256 | do { |
| 257 | cur = (blocks_todo > mmc->cfg->b_max) ? | 257 | cur = (blocks_todo > mmc->cfg->b_max) ? |
| 258 | mmc->cfg->b_max : blocks_todo; | 258 | mmc->cfg->b_max : blocks_todo; |
| 259 | if(mmc_read_blocks(mmc, dst, start, cur) != cur) | 259 | if(mmc_read_blocks(mmc, dst, start, cur) != cur) |
| 260 | return 0; | 260 | return 0; |
| 261 | blocks_todo -= cur; | 261 | blocks_todo -= cur; |
| 262 | start += cur; | 262 | start += cur; |
| 263 | dst += cur * mmc->read_bl_len; | 263 | dst += cur * mmc->read_bl_len; |
| 264 | } while (blocks_todo > 0); | 264 | } while (blocks_todo > 0); |
| 265 | 265 | ||
| 266 | return blkcnt; | 266 | return blkcnt; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | static int mmc_go_idle(struct mmc *mmc) | 269 | static int mmc_go_idle(struct mmc *mmc) |
| 270 | { | 270 | { |
| 271 | struct mmc_cmd cmd; | 271 | struct mmc_cmd cmd; |
| 272 | int err; | 272 | int err; |
| 273 | 273 | ||
| 274 | udelay(1000); | 274 | udelay(1000); |
| 275 | 275 | ||
| 276 | cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; | 276 | cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; |
| 277 | cmd.cmdarg = 0; | 277 | cmd.cmdarg = 0; |
| 278 | cmd.resp_type = MMC_RSP_NONE; | 278 | cmd.resp_type = MMC_RSP_NONE; |
| 279 | 279 | ||
| 280 | err = mmc_send_cmd(mmc, &cmd, NULL); | 280 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 281 | 281 | ||
| 282 | if (err) | 282 | if (err) |
| 283 | return err; | 283 | return err; |
| 284 | 284 | ||
| 285 | udelay(2000); | 285 | udelay(2000); |
| 286 | 286 | ||
| 287 | return 0; | 287 | return 0; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | static int sd_send_op_cond(struct mmc *mmc) | 290 | static int sd_send_op_cond(struct mmc *mmc) |
| 291 | { | 291 | { |
| 292 | int timeout = 1000; | 292 | int timeout = 1000; |
| 293 | int err; | 293 | int err; |
| 294 | struct mmc_cmd cmd; | 294 | struct mmc_cmd cmd; |
| 295 | 295 | ||
| 296 | while (1) { | 296 | while (1) { |
| 297 | cmd.cmdidx = MMC_CMD_APP_CMD; | 297 | cmd.cmdidx = MMC_CMD_APP_CMD; |
| 298 | cmd.resp_type = MMC_RSP_R1; | 298 | cmd.resp_type = MMC_RSP_R1; |
| 299 | cmd.cmdarg = 0; | 299 | cmd.cmdarg = 0; |
| 300 | 300 | ||
| 301 | err = mmc_send_cmd(mmc, &cmd, NULL); | 301 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 302 | 302 | ||
| 303 | if (err) | 303 | if (err) |
| 304 | return err; | 304 | return err; |
| 305 | 305 | ||
| 306 | cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; | 306 | cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; |
| 307 | cmd.resp_type = MMC_RSP_R3; | 307 | cmd.resp_type = MMC_RSP_R3; |
| 308 | 308 | ||
| 309 | /* | 309 | /* |
| 310 | * Most cards do not answer if some reserved bits | 310 | * Most cards do not answer if some reserved bits |
| 311 | * in the ocr are set. However, Some controller | 311 | * in the ocr are set. However, Some controller |
| 312 | * can set bit 7 (reserved for low voltages), but | 312 | * can set bit 7 (reserved for low voltages), but |
| 313 | * how to manage low voltages SD card is not yet | 313 | * how to manage low voltages SD card is not yet |
| 314 | * specified. | 314 | * specified. |
| 315 | */ | 315 | */ |
| 316 | cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : | 316 | cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : |
| 317 | (mmc->cfg->voltages & 0xff8000); | 317 | (mmc->cfg->voltages & 0xff8000); |
| 318 | 318 | ||
| 319 | if (mmc->version == SD_VERSION_2) | 319 | if (mmc->version == SD_VERSION_2) |
| 320 | cmd.cmdarg |= OCR_HCS; | 320 | cmd.cmdarg |= OCR_HCS; |
| 321 | 321 | ||
| 322 | err = mmc_send_cmd(mmc, &cmd, NULL); | 322 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 323 | 323 | ||
| 324 | if (err) | 324 | if (err) |
| 325 | return err; | 325 | return err; |
| 326 | 326 | ||
| 327 | if (cmd.response[0] & OCR_BUSY) | 327 | if (cmd.response[0] & OCR_BUSY) |
| 328 | break; | 328 | break; |
| 329 | 329 | ||
| 330 | if (timeout-- <= 0) | 330 | if (timeout-- <= 0) |
| 331 | return UNUSABLE_ERR; | 331 | return UNUSABLE_ERR; |
| 332 | 332 | ||
| 333 | udelay(1000); | 333 | udelay(1000); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | if (mmc->version != SD_VERSION_2) | 336 | if (mmc->version != SD_VERSION_2) |
| 337 | mmc->version = SD_VERSION_1_0; | 337 | mmc->version = SD_VERSION_1_0; |
| 338 | 338 | ||
| 339 | if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ | 339 | if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ |
| 340 | cmd.cmdidx = MMC_CMD_SPI_READ_OCR; | 340 | cmd.cmdidx = MMC_CMD_SPI_READ_OCR; |
| 341 | cmd.resp_type = MMC_RSP_R3; | 341 | cmd.resp_type = MMC_RSP_R3; |
| 342 | cmd.cmdarg = 0; | 342 | cmd.cmdarg = 0; |
| 343 | 343 | ||
| 344 | err = mmc_send_cmd(mmc, &cmd, NULL); | 344 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 345 | 345 | ||
| 346 | if (err) | 346 | if (err) |
| 347 | return err; | 347 | return err; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | mmc->ocr = cmd.response[0]; | 350 | mmc->ocr = cmd.response[0]; |
| 351 | 351 | ||
| 352 | mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); | 352 | mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); |
| 353 | mmc->rca = 0; | 353 | mmc->rca = 0; |
| 354 | 354 | ||
| 355 | return 0; | 355 | return 0; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) | 358 | static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) |
| 359 | { | 359 | { |
| 360 | struct mmc_cmd cmd; | 360 | struct mmc_cmd cmd; |
| 361 | int err; | 361 | int err; |
| 362 | 362 | ||
| 363 | cmd.cmdidx = MMC_CMD_SEND_OP_COND; | 363 | cmd.cmdidx = MMC_CMD_SEND_OP_COND; |
| 364 | cmd.resp_type = MMC_RSP_R3; | 364 | cmd.resp_type = MMC_RSP_R3; |
| 365 | cmd.cmdarg = 0; | 365 | cmd.cmdarg = 0; |
| 366 | if (use_arg && !mmc_host_is_spi(mmc)) { | 366 | if (use_arg && !mmc_host_is_spi(mmc)) |
| 367 | cmd.cmdarg = | 367 | cmd.cmdarg = OCR_HCS | |
| 368 | (mmc->cfg->voltages & | 368 | (mmc->cfg->voltages & |
| 369 | (mmc->ocr & OCR_VOLTAGE_MASK)) | | 369 | (mmc->ocr & OCR_VOLTAGE_MASK)) | |
| 370 | (mmc->ocr & OCR_ACCESS_MODE); | 370 | (mmc->ocr & OCR_ACCESS_MODE); |
| 371 | 371 | ||
| 372 | if (mmc->cfg->host_caps & MMC_MODE_HC) | ||
| 373 | cmd.cmdarg |= OCR_HCS; | ||
| 374 | } | ||
| 375 | err = mmc_send_cmd(mmc, &cmd, NULL); | 372 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 376 | if (err) | 373 | if (err) |
| 377 | return err; | 374 | return err; |
| 378 | mmc->ocr = cmd.response[0]; | 375 | mmc->ocr = cmd.response[0]; |
| 379 | return 0; | 376 | return 0; |
| 380 | } | 377 | } |
| 381 | 378 | ||
| 382 | static int mmc_send_op_cond(struct mmc *mmc) | 379 | static int mmc_send_op_cond(struct mmc *mmc) |
| 383 | { | 380 | { |
| 384 | int err, i; | 381 | int err, i; |
| 385 | 382 | ||
| 386 | /* Some cards seem to need this */ | 383 | /* Some cards seem to need this */ |
| 387 | mmc_go_idle(mmc); | 384 | mmc_go_idle(mmc); |
| 388 | 385 | ||
| 389 | /* Asking to the card its capabilities */ | 386 | /* Asking to the card its capabilities */ |
| 390 | for (i = 0; i < 2; i++) { | 387 | for (i = 0; i < 2; i++) { |
| 391 | err = mmc_send_op_cond_iter(mmc, i != 0); | 388 | err = mmc_send_op_cond_iter(mmc, i != 0); |
| 392 | if (err) | 389 | if (err) |
| 393 | return err; | 390 | return err; |
| 394 | 391 | ||
| 395 | /* exit if not busy (flag seems to be inverted) */ | 392 | /* exit if not busy (flag seems to be inverted) */ |
| 396 | if (mmc->ocr & OCR_BUSY) | 393 | if (mmc->ocr & OCR_BUSY) |
| 397 | break; | 394 | break; |
| 398 | } | 395 | } |
| 399 | mmc->op_cond_pending = 1; | 396 | mmc->op_cond_pending = 1; |
| 400 | return 0; | 397 | return 0; |
| 401 | } | 398 | } |
| 402 | 399 | ||
| 403 | static int mmc_complete_op_cond(struct mmc *mmc) | 400 | static int mmc_complete_op_cond(struct mmc *mmc) |
| 404 | { | 401 | { |
| 405 | struct mmc_cmd cmd; | 402 | struct mmc_cmd cmd; |
| 406 | int timeout = 1000; | 403 | int timeout = 1000; |
| 407 | uint start; | 404 | uint start; |
| 408 | int err; | 405 | int err; |
| 409 | 406 | ||
| 410 | mmc->op_cond_pending = 0; | 407 | mmc->op_cond_pending = 0; |
| 411 | if (!(mmc->ocr & OCR_BUSY)) { | 408 | if (!(mmc->ocr & OCR_BUSY)) { |
| 412 | start = get_timer(0); | 409 | start = get_timer(0); |
| 413 | while (1) { | 410 | while (1) { |
| 414 | err = mmc_send_op_cond_iter(mmc, 1); | 411 | err = mmc_send_op_cond_iter(mmc, 1); |
| 415 | if (err) | 412 | if (err) |
| 416 | return err; | 413 | return err; |
| 417 | if (mmc->ocr & OCR_BUSY) | 414 | if (mmc->ocr & OCR_BUSY) |
| 418 | break; | 415 | break; |
| 419 | if (get_timer(start) > timeout) | 416 | if (get_timer(start) > timeout) |
| 420 | return UNUSABLE_ERR; | 417 | return UNUSABLE_ERR; |
| 421 | udelay(100); | 418 | udelay(100); |
| 422 | } | 419 | } |
| 423 | } | 420 | } |
| 424 | 421 | ||
| 425 | if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ | 422 | if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ |
| 426 | cmd.cmdidx = MMC_CMD_SPI_READ_OCR; | 423 | cmd.cmdidx = MMC_CMD_SPI_READ_OCR; |
| 427 | cmd.resp_type = MMC_RSP_R3; | 424 | cmd.resp_type = MMC_RSP_R3; |
| 428 | cmd.cmdarg = 0; | 425 | cmd.cmdarg = 0; |
| 429 | 426 | ||
| 430 | err = mmc_send_cmd(mmc, &cmd, NULL); | 427 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 431 | 428 | ||
| 432 | if (err) | 429 | if (err) |
| 433 | return err; | 430 | return err; |
| 434 | 431 | ||
| 435 | mmc->ocr = cmd.response[0]; | 432 | mmc->ocr = cmd.response[0]; |
| 436 | } | 433 | } |
| 437 | 434 | ||
| 438 | mmc->version = MMC_VERSION_UNKNOWN; | 435 | mmc->version = MMC_VERSION_UNKNOWN; |
| 439 | 436 | ||
| 440 | mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); | 437 | mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); |
| 441 | mmc->rca = 1; | 438 | mmc->rca = 1; |
| 442 | 439 | ||
| 443 | return 0; | 440 | return 0; |
| 444 | } | 441 | } |
| 445 | 442 | ||
| 446 | 443 | ||
| 447 | static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) | 444 | static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) |
| 448 | { | 445 | { |
| 449 | struct mmc_cmd cmd; | 446 | struct mmc_cmd cmd; |
| 450 | struct mmc_data data; | 447 | struct mmc_data data; |
| 451 | int err; | 448 | int err; |
| 452 | 449 | ||
| 453 | /* Get the Card Status Register */ | 450 | /* Get the Card Status Register */ |
| 454 | cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; | 451 | cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; |
| 455 | cmd.resp_type = MMC_RSP_R1; | 452 | cmd.resp_type = MMC_RSP_R1; |
| 456 | cmd.cmdarg = 0; | 453 | cmd.cmdarg = 0; |
| 457 | 454 | ||
| 458 | data.dest = (char *)ext_csd; | 455 | data.dest = (char *)ext_csd; |
| 459 | data.blocks = 1; | 456 | data.blocks = 1; |
| 460 | data.blocksize = MMC_MAX_BLOCK_LEN; | 457 | data.blocksize = MMC_MAX_BLOCK_LEN; |
| 461 | data.flags = MMC_DATA_READ; | 458 | data.flags = MMC_DATA_READ; |
| 462 | 459 | ||
| 463 | err = mmc_send_cmd(mmc, &cmd, &data); | 460 | err = mmc_send_cmd(mmc, &cmd, &data); |
| 464 | 461 | ||
| 465 | return err; | 462 | return err; |
| 466 | } | 463 | } |
| 467 | 464 | ||
| 468 | 465 | ||
| 469 | static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) | 466 | static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) |
| 470 | { | 467 | { |
| 471 | struct mmc_cmd cmd; | 468 | struct mmc_cmd cmd; |
| 472 | int timeout = 1000; | 469 | int timeout = 1000; |
| 473 | int ret; | 470 | int ret; |
| 474 | 471 | ||
| 475 | cmd.cmdidx = MMC_CMD_SWITCH; | 472 | cmd.cmdidx = MMC_CMD_SWITCH; |
| 476 | cmd.resp_type = MMC_RSP_R1b; | 473 | cmd.resp_type = MMC_RSP_R1b; |
| 477 | cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | 474 | cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | |
| 478 | (index << 16) | | 475 | (index << 16) | |
| 479 | (value << 8); | 476 | (value << 8); |
| 480 | 477 | ||
| 481 | ret = mmc_send_cmd(mmc, &cmd, NULL); | 478 | ret = mmc_send_cmd(mmc, &cmd, NULL); |
| 482 | 479 | ||
| 483 | /* Waiting for the ready status */ | 480 | /* Waiting for the ready status */ |
| 484 | if (!ret) | 481 | if (!ret) |
| 485 | ret = mmc_send_status(mmc, timeout); | 482 | ret = mmc_send_status(mmc, timeout); |
| 486 | 483 | ||
| 487 | return ret; | 484 | return ret; |
| 488 | 485 | ||
| 489 | } | 486 | } |
| 490 | 487 | ||
| 491 | static int mmc_change_freq(struct mmc *mmc) | 488 | static int mmc_change_freq(struct mmc *mmc) |
| 492 | { | 489 | { |
| 493 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); | 490 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); |
| 494 | char cardtype; | 491 | char cardtype; |
| 495 | int err; | 492 | int err; |
| 496 | 493 | ||
| 497 | mmc->card_caps = 0; | 494 | mmc->card_caps = 0; |
| 498 | 495 | ||
| 499 | if (mmc_host_is_spi(mmc)) | 496 | if (mmc_host_is_spi(mmc)) |
| 500 | return 0; | 497 | return 0; |
| 501 | 498 | ||
| 502 | /* Only version 4 supports high-speed */ | 499 | /* Only version 4 supports high-speed */ |
| 503 | if (mmc->version < MMC_VERSION_4) | 500 | if (mmc->version < MMC_VERSION_4) |
| 504 | return 0; | 501 | return 0; |
| 505 | 502 | ||
| 506 | mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; | 503 | mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; |
| 507 | 504 | ||
| 508 | err = mmc_send_ext_csd(mmc, ext_csd); | 505 | err = mmc_send_ext_csd(mmc, ext_csd); |
| 509 | 506 | ||
| 510 | if (err) | 507 | if (err) |
| 511 | return err; | 508 | return err; |
| 512 | 509 | ||
| 513 | cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; | 510 | cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; |
| 514 | 511 | ||
| 515 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); | 512 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); |
| 516 | 513 | ||
| 517 | if (err) | 514 | if (err) |
| 518 | return err == SWITCH_ERR ? 0 : err; | 515 | return err == SWITCH_ERR ? 0 : err; |
| 519 | 516 | ||
| 520 | /* Now check to see that it worked */ | 517 | /* Now check to see that it worked */ |
| 521 | err = mmc_send_ext_csd(mmc, ext_csd); | 518 | err = mmc_send_ext_csd(mmc, ext_csd); |
| 522 | 519 | ||
| 523 | if (err) | 520 | if (err) |
| 524 | return err; | 521 | return err; |
| 525 | 522 | ||
| 526 | /* No high-speed support */ | 523 | /* No high-speed support */ |
| 527 | if (!ext_csd[EXT_CSD_HS_TIMING]) | 524 | if (!ext_csd[EXT_CSD_HS_TIMING]) |
| 528 | return 0; | 525 | return 0; |
| 529 | 526 | ||
| 530 | /* High Speed is set, there are two types: 52MHz and 26MHz */ | 527 | /* High Speed is set, there are two types: 52MHz and 26MHz */ |
| 531 | if (cardtype & EXT_CSD_CARD_TYPE_52) { | 528 | if (cardtype & EXT_CSD_CARD_TYPE_52) { |
| 532 | if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) | 529 | if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) |
| 533 | mmc->card_caps |= MMC_MODE_DDR_52MHz; | 530 | mmc->card_caps |= MMC_MODE_DDR_52MHz; |
| 534 | mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; | 531 | mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 535 | } else { | 532 | } else { |
| 536 | mmc->card_caps |= MMC_MODE_HS; | 533 | mmc->card_caps |= MMC_MODE_HS; |
| 537 | } | 534 | } |
| 538 | 535 | ||
| 539 | return 0; | 536 | return 0; |
| 540 | } | 537 | } |
| 541 | 538 | ||
| 542 | static int mmc_set_capacity(struct mmc *mmc, int part_num) | 539 | static int mmc_set_capacity(struct mmc *mmc, int part_num) |
| 543 | { | 540 | { |
| 544 | switch (part_num) { | 541 | switch (part_num) { |
| 545 | case 0: | 542 | case 0: |
| 546 | mmc->capacity = mmc->capacity_user; | 543 | mmc->capacity = mmc->capacity_user; |
| 547 | break; | 544 | break; |
| 548 | case 1: | 545 | case 1: |
| 549 | case 2: | 546 | case 2: |
| 550 | mmc->capacity = mmc->capacity_boot; | 547 | mmc->capacity = mmc->capacity_boot; |
| 551 | break; | 548 | break; |
| 552 | case 3: | 549 | case 3: |
| 553 | mmc->capacity = mmc->capacity_rpmb; | 550 | mmc->capacity = mmc->capacity_rpmb; |
| 554 | break; | 551 | break; |
| 555 | case 4: | 552 | case 4: |
| 556 | case 5: | 553 | case 5: |
| 557 | case 6: | 554 | case 6: |
| 558 | case 7: | 555 | case 7: |
| 559 | mmc->capacity = mmc->capacity_gp[part_num - 4]; | 556 | mmc->capacity = mmc->capacity_gp[part_num - 4]; |
| 560 | break; | 557 | break; |
| 561 | default: | 558 | default: |
| 562 | return -1; | 559 | return -1; |
| 563 | } | 560 | } |
| 564 | 561 | ||
| 565 | mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); | 562 | mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); |
| 566 | 563 | ||
| 567 | return 0; | 564 | return 0; |
| 568 | } | 565 | } |
| 569 | 566 | ||
| 570 | int mmc_select_hwpart(int dev_num, int hwpart) | 567 | int mmc_select_hwpart(int dev_num, int hwpart) |
| 571 | { | 568 | { |
| 572 | struct mmc *mmc = find_mmc_device(dev_num); | 569 | struct mmc *mmc = find_mmc_device(dev_num); |
| 573 | int ret; | 570 | int ret; |
| 574 | 571 | ||
| 575 | if (!mmc) | 572 | if (!mmc) |
| 576 | return -ENODEV; | 573 | return -ENODEV; |
| 577 | 574 | ||
| 578 | if (mmc->part_num == hwpart) | 575 | if (mmc->part_num == hwpart) |
| 579 | return 0; | 576 | return 0; |
| 580 | 577 | ||
| 581 | if (mmc->part_config == MMCPART_NOAVAILABLE) { | 578 | if (mmc->part_config == MMCPART_NOAVAILABLE) { |
| 582 | printf("Card doesn't support part_switch\n"); | 579 | printf("Card doesn't support part_switch\n"); |
| 583 | return -EMEDIUMTYPE; | 580 | return -EMEDIUMTYPE; |
| 584 | } | 581 | } |
| 585 | 582 | ||
| 586 | ret = mmc_switch_part(dev_num, hwpart); | 583 | ret = mmc_switch_part(dev_num, hwpart); |
| 587 | if (ret) | 584 | if (ret) |
| 588 | return ret; | 585 | return ret; |
| 589 | 586 | ||
| 590 | mmc->part_num = hwpart; | 587 | mmc->part_num = hwpart; |
| 591 | 588 | ||
| 592 | return 0; | 589 | return 0; |
| 593 | } | 590 | } |
| 594 | 591 | ||
| 595 | 592 | ||
| 596 | int mmc_switch_part(int dev_num, unsigned int part_num) | 593 | int mmc_switch_part(int dev_num, unsigned int part_num) |
| 597 | { | 594 | { |
| 598 | struct mmc *mmc = find_mmc_device(dev_num); | 595 | struct mmc *mmc = find_mmc_device(dev_num); |
| 599 | int ret; | 596 | int ret; |
| 600 | 597 | ||
| 601 | if (!mmc) | 598 | if (!mmc) |
| 602 | return -1; | 599 | return -1; |
| 603 | 600 | ||
| 604 | ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, | 601 | ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, |
| 605 | (mmc->part_config & ~PART_ACCESS_MASK) | 602 | (mmc->part_config & ~PART_ACCESS_MASK) |
| 606 | | (part_num & PART_ACCESS_MASK)); | 603 | | (part_num & PART_ACCESS_MASK)); |
| 607 | 604 | ||
| 608 | /* | 605 | /* |
| 609 | * Set the capacity if the switch succeeded or was intended | 606 | * Set the capacity if the switch succeeded or was intended |
| 610 | * to return to representing the raw device. | 607 | * to return to representing the raw device. |
| 611 | */ | 608 | */ |
| 612 | if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) | 609 | if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) |
| 613 | ret = mmc_set_capacity(mmc, part_num); | 610 | ret = mmc_set_capacity(mmc, part_num); |
| 614 | 611 | ||
| 615 | return ret; | 612 | return ret; |
| 616 | } | 613 | } |
| 617 | 614 | ||
| 618 | int mmc_hwpart_config(struct mmc *mmc, | 615 | int mmc_hwpart_config(struct mmc *mmc, |
| 619 | const struct mmc_hwpart_conf *conf, | 616 | const struct mmc_hwpart_conf *conf, |
| 620 | enum mmc_hwpart_conf_mode mode) | 617 | enum mmc_hwpart_conf_mode mode) |
| 621 | { | 618 | { |
| 622 | u8 part_attrs = 0; | 619 | u8 part_attrs = 0; |
| 623 | u32 enh_size_mult; | 620 | u32 enh_size_mult; |
| 624 | u32 enh_start_addr; | 621 | u32 enh_start_addr; |
| 625 | u32 gp_size_mult[4]; | 622 | u32 gp_size_mult[4]; |
| 626 | u32 max_enh_size_mult; | 623 | u32 max_enh_size_mult; |
| 627 | u32 tot_enh_size_mult = 0; | 624 | u32 tot_enh_size_mult = 0; |
| 628 | u8 wr_rel_set; | 625 | u8 wr_rel_set; |
| 629 | int i, pidx, err; | 626 | int i, pidx, err; |
| 630 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); | 627 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); |
| 631 | 628 | ||
| 632 | if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) | 629 | if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) |
| 633 | return -EINVAL; | 630 | return -EINVAL; |
| 634 | 631 | ||
| 635 | if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { | 632 | if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { |
| 636 | printf("eMMC >= 4.4 required for enhanced user data area\n"); | 633 | printf("eMMC >= 4.4 required for enhanced user data area\n"); |
| 637 | return -EMEDIUMTYPE; | 634 | return -EMEDIUMTYPE; |
| 638 | } | 635 | } |
| 639 | 636 | ||
| 640 | if (!(mmc->part_support & PART_SUPPORT)) { | 637 | if (!(mmc->part_support & PART_SUPPORT)) { |
| 641 | printf("Card does not support partitioning\n"); | 638 | printf("Card does not support partitioning\n"); |
| 642 | return -EMEDIUMTYPE; | 639 | return -EMEDIUMTYPE; |
| 643 | } | 640 | } |
| 644 | 641 | ||
| 645 | if (!mmc->hc_wp_grp_size) { | 642 | if (!mmc->hc_wp_grp_size) { |
| 646 | printf("Card does not define HC WP group size\n"); | 643 | printf("Card does not define HC WP group size\n"); |
| 647 | return -EMEDIUMTYPE; | 644 | return -EMEDIUMTYPE; |
| 648 | } | 645 | } |
| 649 | 646 | ||
| 650 | /* check partition alignment and total enhanced size */ | 647 | /* check partition alignment and total enhanced size */ |
| 651 | if (conf->user.enh_size) { | 648 | if (conf->user.enh_size) { |
| 652 | if (conf->user.enh_size % mmc->hc_wp_grp_size || | 649 | if (conf->user.enh_size % mmc->hc_wp_grp_size || |
| 653 | conf->user.enh_start % mmc->hc_wp_grp_size) { | 650 | conf->user.enh_start % mmc->hc_wp_grp_size) { |
| 654 | printf("User data enhanced area not HC WP group " | 651 | printf("User data enhanced area not HC WP group " |
| 655 | "size aligned\n"); | 652 | "size aligned\n"); |
| 656 | return -EINVAL; | 653 | return -EINVAL; |
| 657 | } | 654 | } |
| 658 | part_attrs |= EXT_CSD_ENH_USR; | 655 | part_attrs |= EXT_CSD_ENH_USR; |
| 659 | enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; | 656 | enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; |
| 660 | if (mmc->high_capacity) { | 657 | if (mmc->high_capacity) { |
| 661 | enh_start_addr = conf->user.enh_start; | 658 | enh_start_addr = conf->user.enh_start; |
| 662 | } else { | 659 | } else { |
| 663 | enh_start_addr = (conf->user.enh_start << 9); | 660 | enh_start_addr = (conf->user.enh_start << 9); |
| 664 | } | 661 | } |
| 665 | } else { | 662 | } else { |
| 666 | enh_size_mult = 0; | 663 | enh_size_mult = 0; |
| 667 | enh_start_addr = 0; | 664 | enh_start_addr = 0; |
| 668 | } | 665 | } |
| 669 | tot_enh_size_mult += enh_size_mult; | 666 | tot_enh_size_mult += enh_size_mult; |
| 670 | 667 | ||
| 671 | for (pidx = 0; pidx < 4; pidx++) { | 668 | for (pidx = 0; pidx < 4; pidx++) { |
| 672 | if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { | 669 | if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { |
| 673 | printf("GP%i partition not HC WP group size " | 670 | printf("GP%i partition not HC WP group size " |
| 674 | "aligned\n", pidx+1); | 671 | "aligned\n", pidx+1); |
| 675 | return -EINVAL; | 672 | return -EINVAL; |
| 676 | } | 673 | } |
| 677 | gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; | 674 | gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; |
| 678 | if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { | 675 | if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { |
| 679 | part_attrs |= EXT_CSD_ENH_GP(pidx); | 676 | part_attrs |= EXT_CSD_ENH_GP(pidx); |
| 680 | tot_enh_size_mult += gp_size_mult[pidx]; | 677 | tot_enh_size_mult += gp_size_mult[pidx]; |
| 681 | } | 678 | } |
| 682 | } | 679 | } |
| 683 | 680 | ||
| 684 | if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { | 681 | if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { |
| 685 | printf("Card does not support enhanced attribute\n"); | 682 | printf("Card does not support enhanced attribute\n"); |
| 686 | return -EMEDIUMTYPE; | 683 | return -EMEDIUMTYPE; |
| 687 | } | 684 | } |
| 688 | 685 | ||
| 689 | err = mmc_send_ext_csd(mmc, ext_csd); | 686 | err = mmc_send_ext_csd(mmc, ext_csd); |
| 690 | if (err) | 687 | if (err) |
| 691 | return err; | 688 | return err; |
| 692 | 689 | ||
| 693 | max_enh_size_mult = | 690 | max_enh_size_mult = |
| 694 | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + | 691 | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + |
| 695 | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + | 692 | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + |
| 696 | ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; | 693 | ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; |
| 697 | if (tot_enh_size_mult > max_enh_size_mult) { | 694 | if (tot_enh_size_mult > max_enh_size_mult) { |
| 698 | printf("Total enhanced size exceeds maximum (%u > %u)\n", | 695 | printf("Total enhanced size exceeds maximum (%u > %u)\n", |
| 699 | tot_enh_size_mult, max_enh_size_mult); | 696 | tot_enh_size_mult, max_enh_size_mult); |
| 700 | return -EMEDIUMTYPE; | 697 | return -EMEDIUMTYPE; |
| 701 | } | 698 | } |
| 702 | 699 | ||
| 703 | /* The default value of EXT_CSD_WR_REL_SET is device | 700 | /* The default value of EXT_CSD_WR_REL_SET is device |
| 704 | * dependent, the values can only be changed if the | 701 | * dependent, the values can only be changed if the |
| 705 | * EXT_CSD_HS_CTRL_REL bit is set. The values can be | 702 | * EXT_CSD_HS_CTRL_REL bit is set. The values can be |
| 706 | * changed only once and before partitioning is completed. */ | 703 | * changed only once and before partitioning is completed. */ |
| 707 | wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; | 704 | wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; |
| 708 | if (conf->user.wr_rel_change) { | 705 | if (conf->user.wr_rel_change) { |
| 709 | if (conf->user.wr_rel_set) | 706 | if (conf->user.wr_rel_set) |
| 710 | wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; | 707 | wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; |
| 711 | else | 708 | else |
| 712 | wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; | 709 | wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; |
| 713 | } | 710 | } |
| 714 | for (pidx = 0; pidx < 4; pidx++) { | 711 | for (pidx = 0; pidx < 4; pidx++) { |
| 715 | if (conf->gp_part[pidx].wr_rel_change) { | 712 | if (conf->gp_part[pidx].wr_rel_change) { |
| 716 | if (conf->gp_part[pidx].wr_rel_set) | 713 | if (conf->gp_part[pidx].wr_rel_set) |
| 717 | wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); | 714 | wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); |
| 718 | else | 715 | else |
| 719 | wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); | 716 | wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); |
| 720 | } | 717 | } |
| 721 | } | 718 | } |
| 722 | 719 | ||
| 723 | if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && | 720 | if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && |
| 724 | !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { | 721 | !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { |
| 725 | puts("Card does not support host controlled partition write " | 722 | puts("Card does not support host controlled partition write " |
| 726 | "reliability settings\n"); | 723 | "reliability settings\n"); |
| 727 | return -EMEDIUMTYPE; | 724 | return -EMEDIUMTYPE; |
| 728 | } | 725 | } |
| 729 | 726 | ||
| 730 | if (ext_csd[EXT_CSD_PARTITION_SETTING] & | 727 | if (ext_csd[EXT_CSD_PARTITION_SETTING] & |
| 731 | EXT_CSD_PARTITION_SETTING_COMPLETED) { | 728 | EXT_CSD_PARTITION_SETTING_COMPLETED) { |
| 732 | printf("Card already partitioned\n"); | 729 | printf("Card already partitioned\n"); |
| 733 | return -EPERM; | 730 | return -EPERM; |
| 734 | } | 731 | } |
| 735 | 732 | ||
| 736 | if (mode == MMC_HWPART_CONF_CHECK) | 733 | if (mode == MMC_HWPART_CONF_CHECK) |
| 737 | return 0; | 734 | return 0; |
| 738 | 735 | ||
| 739 | /* Partitioning requires high-capacity size definitions */ | 736 | /* Partitioning requires high-capacity size definitions */ |
| 740 | if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { | 737 | if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { |
| 741 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 738 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 742 | EXT_CSD_ERASE_GROUP_DEF, 1); | 739 | EXT_CSD_ERASE_GROUP_DEF, 1); |
| 743 | 740 | ||
| 744 | if (err) | 741 | if (err) |
| 745 | return err; | 742 | return err; |
| 746 | 743 | ||
| 747 | ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; | 744 | ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; |
| 748 | 745 | ||
| 749 | /* update erase group size to be high-capacity */ | 746 | /* update erase group size to be high-capacity */ |
| 750 | mmc->erase_grp_size = | 747 | mmc->erase_grp_size = |
| 751 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; | 748 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; |
| 752 | 749 | ||
| 753 | } | 750 | } |
| 754 | 751 | ||
| 755 | /* all OK, write the configuration */ | 752 | /* all OK, write the configuration */ |
| 756 | for (i = 0; i < 4; i++) { | 753 | for (i = 0; i < 4; i++) { |
| 757 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 754 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 758 | EXT_CSD_ENH_START_ADDR+i, | 755 | EXT_CSD_ENH_START_ADDR+i, |
| 759 | (enh_start_addr >> (i*8)) & 0xFF); | 756 | (enh_start_addr >> (i*8)) & 0xFF); |
| 760 | if (err) | 757 | if (err) |
| 761 | return err; | 758 | return err; |
| 762 | } | 759 | } |
| 763 | for (i = 0; i < 3; i++) { | 760 | for (i = 0; i < 3; i++) { |
| 764 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 761 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 765 | EXT_CSD_ENH_SIZE_MULT+i, | 762 | EXT_CSD_ENH_SIZE_MULT+i, |
| 766 | (enh_size_mult >> (i*8)) & 0xFF); | 763 | (enh_size_mult >> (i*8)) & 0xFF); |
| 767 | if (err) | 764 | if (err) |
| 768 | return err; | 765 | return err; |
| 769 | } | 766 | } |
| 770 | for (pidx = 0; pidx < 4; pidx++) { | 767 | for (pidx = 0; pidx < 4; pidx++) { |
| 771 | for (i = 0; i < 3; i++) { | 768 | for (i = 0; i < 3; i++) { |
| 772 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 769 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 773 | EXT_CSD_GP_SIZE_MULT+pidx*3+i, | 770 | EXT_CSD_GP_SIZE_MULT+pidx*3+i, |
| 774 | (gp_size_mult[pidx] >> (i*8)) & 0xFF); | 771 | (gp_size_mult[pidx] >> (i*8)) & 0xFF); |
| 775 | if (err) | 772 | if (err) |
| 776 | return err; | 773 | return err; |
| 777 | } | 774 | } |
| 778 | } | 775 | } |
| 779 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 776 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 780 | EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); | 777 | EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); |
| 781 | if (err) | 778 | if (err) |
| 782 | return err; | 779 | return err; |
| 783 | 780 | ||
| 784 | if (mode == MMC_HWPART_CONF_SET) | 781 | if (mode == MMC_HWPART_CONF_SET) |
| 785 | return 0; | 782 | return 0; |
| 786 | 783 | ||
| 787 | /* The WR_REL_SET is a write-once register but shall be | 784 | /* The WR_REL_SET is a write-once register but shall be |
| 788 | * written before setting PART_SETTING_COMPLETED. As it is | 785 | * written before setting PART_SETTING_COMPLETED. As it is |
| 789 | * write-once we can only write it when completing the | 786 | * write-once we can only write it when completing the |
| 790 | * partitioning. */ | 787 | * partitioning. */ |
| 791 | if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { | 788 | if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { |
| 792 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 789 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 793 | EXT_CSD_WR_REL_SET, wr_rel_set); | 790 | EXT_CSD_WR_REL_SET, wr_rel_set); |
| 794 | if (err) | 791 | if (err) |
| 795 | return err; | 792 | return err; |
| 796 | } | 793 | } |
| 797 | 794 | ||
| 798 | /* Setting PART_SETTING_COMPLETED confirms the partition | 795 | /* Setting PART_SETTING_COMPLETED confirms the partition |
| 799 | * configuration but it only becomes effective after power | 796 | * configuration but it only becomes effective after power |
| 800 | * cycle, so we do not adjust the partition related settings | 797 | * cycle, so we do not adjust the partition related settings |
| 801 | * in the mmc struct. */ | 798 | * in the mmc struct. */ |
| 802 | 799 | ||
| 803 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 800 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 804 | EXT_CSD_PARTITION_SETTING, | 801 | EXT_CSD_PARTITION_SETTING, |
| 805 | EXT_CSD_PARTITION_SETTING_COMPLETED); | 802 | EXT_CSD_PARTITION_SETTING_COMPLETED); |
| 806 | if (err) | 803 | if (err) |
| 807 | return err; | 804 | return err; |
| 808 | 805 | ||
| 809 | return 0; | 806 | return 0; |
| 810 | } | 807 | } |
| 811 | 808 | ||
| 812 | int mmc_getcd(struct mmc *mmc) | 809 | int mmc_getcd(struct mmc *mmc) |
| 813 | { | 810 | { |
| 814 | int cd; | 811 | int cd; |
| 815 | 812 | ||
| 816 | cd = board_mmc_getcd(mmc); | 813 | cd = board_mmc_getcd(mmc); |
| 817 | 814 | ||
| 818 | if (cd < 0) { | 815 | if (cd < 0) { |
| 819 | if (mmc->cfg->ops->getcd) | 816 | if (mmc->cfg->ops->getcd) |
| 820 | cd = mmc->cfg->ops->getcd(mmc); | 817 | cd = mmc->cfg->ops->getcd(mmc); |
| 821 | else | 818 | else |
| 822 | cd = 1; | 819 | cd = 1; |
| 823 | } | 820 | } |
| 824 | 821 | ||
| 825 | return cd; | 822 | return cd; |
| 826 | } | 823 | } |
| 827 | 824 | ||
| 828 | static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) | 825 | static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) |
| 829 | { | 826 | { |
| 830 | struct mmc_cmd cmd; | 827 | struct mmc_cmd cmd; |
| 831 | struct mmc_data data; | 828 | struct mmc_data data; |
| 832 | 829 | ||
| 833 | /* Switch the frequency */ | 830 | /* Switch the frequency */ |
| 834 | cmd.cmdidx = SD_CMD_SWITCH_FUNC; | 831 | cmd.cmdidx = SD_CMD_SWITCH_FUNC; |
| 835 | cmd.resp_type = MMC_RSP_R1; | 832 | cmd.resp_type = MMC_RSP_R1; |
| 836 | cmd.cmdarg = (mode << 31) | 0xffffff; | 833 | cmd.cmdarg = (mode << 31) | 0xffffff; |
| 837 | cmd.cmdarg &= ~(0xf << (group * 4)); | 834 | cmd.cmdarg &= ~(0xf << (group * 4)); |
| 838 | cmd.cmdarg |= value << (group * 4); | 835 | cmd.cmdarg |= value << (group * 4); |
| 839 | 836 | ||
| 840 | data.dest = (char *)resp; | 837 | data.dest = (char *)resp; |
| 841 | data.blocksize = 64; | 838 | data.blocksize = 64; |
| 842 | data.blocks = 1; | 839 | data.blocks = 1; |
| 843 | data.flags = MMC_DATA_READ; | 840 | data.flags = MMC_DATA_READ; |
| 844 | 841 | ||
| 845 | return mmc_send_cmd(mmc, &cmd, &data); | 842 | return mmc_send_cmd(mmc, &cmd, &data); |
| 846 | } | 843 | } |
| 847 | 844 | ||
| 848 | 845 | ||
| 849 | static int sd_change_freq(struct mmc *mmc) | 846 | static int sd_change_freq(struct mmc *mmc) |
| 850 | { | 847 | { |
| 851 | int err; | 848 | int err; |
| 852 | struct mmc_cmd cmd; | 849 | struct mmc_cmd cmd; |
| 853 | ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); | 850 | ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); |
| 854 | ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); | 851 | ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); |
| 855 | struct mmc_data data; | 852 | struct mmc_data data; |
| 856 | int timeout; | 853 | int timeout; |
| 857 | 854 | ||
| 858 | mmc->card_caps = 0; | 855 | mmc->card_caps = 0; |
| 859 | 856 | ||
| 860 | if (mmc_host_is_spi(mmc)) | 857 | if (mmc_host_is_spi(mmc)) |
| 861 | return 0; | 858 | return 0; |
| 862 | 859 | ||
| 863 | /* Read the SCR to find out if this card supports higher speeds */ | 860 | /* Read the SCR to find out if this card supports higher speeds */ |
| 864 | cmd.cmdidx = MMC_CMD_APP_CMD; | 861 | cmd.cmdidx = MMC_CMD_APP_CMD; |
| 865 | cmd.resp_type = MMC_RSP_R1; | 862 | cmd.resp_type = MMC_RSP_R1; |
| 866 | cmd.cmdarg = mmc->rca << 16; | 863 | cmd.cmdarg = mmc->rca << 16; |
| 867 | 864 | ||
| 868 | err = mmc_send_cmd(mmc, &cmd, NULL); | 865 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 869 | 866 | ||
| 870 | if (err) | 867 | if (err) |
| 871 | return err; | 868 | return err; |
| 872 | 869 | ||
| 873 | cmd.cmdidx = SD_CMD_APP_SEND_SCR; | 870 | cmd.cmdidx = SD_CMD_APP_SEND_SCR; |
| 874 | cmd.resp_type = MMC_RSP_R1; | 871 | cmd.resp_type = MMC_RSP_R1; |
| 875 | cmd.cmdarg = 0; | 872 | cmd.cmdarg = 0; |
| 876 | 873 | ||
| 877 | timeout = 3; | 874 | timeout = 3; |
| 878 | 875 | ||
| 879 | retry_scr: | 876 | retry_scr: |
| 880 | data.dest = (char *)scr; | 877 | data.dest = (char *)scr; |
| 881 | data.blocksize = 8; | 878 | data.blocksize = 8; |
| 882 | data.blocks = 1; | 879 | data.blocks = 1; |
| 883 | data.flags = MMC_DATA_READ; | 880 | data.flags = MMC_DATA_READ; |
| 884 | 881 | ||
| 885 | err = mmc_send_cmd(mmc, &cmd, &data); | 882 | err = mmc_send_cmd(mmc, &cmd, &data); |
| 886 | 883 | ||
| 887 | if (err) { | 884 | if (err) { |
| 888 | if (timeout--) | 885 | if (timeout--) |
| 889 | goto retry_scr; | 886 | goto retry_scr; |
| 890 | 887 | ||
| 891 | return err; | 888 | return err; |
| 892 | } | 889 | } |
| 893 | 890 | ||
| 894 | mmc->scr[0] = __be32_to_cpu(scr[0]); | 891 | mmc->scr[0] = __be32_to_cpu(scr[0]); |
| 895 | mmc->scr[1] = __be32_to_cpu(scr[1]); | 892 | mmc->scr[1] = __be32_to_cpu(scr[1]); |
| 896 | 893 | ||
| 897 | switch ((mmc->scr[0] >> 24) & 0xf) { | 894 | switch ((mmc->scr[0] >> 24) & 0xf) { |
| 898 | case 0: | 895 | case 0: |
| 899 | mmc->version = SD_VERSION_1_0; | 896 | mmc->version = SD_VERSION_1_0; |
| 900 | break; | 897 | break; |
| 901 | case 1: | 898 | case 1: |
| 902 | mmc->version = SD_VERSION_1_10; | 899 | mmc->version = SD_VERSION_1_10; |
| 903 | break; | 900 | break; |
| 904 | case 2: | 901 | case 2: |
| 905 | mmc->version = SD_VERSION_2; | 902 | mmc->version = SD_VERSION_2; |
| 906 | if ((mmc->scr[0] >> 15) & 0x1) | 903 | if ((mmc->scr[0] >> 15) & 0x1) |
| 907 | mmc->version = SD_VERSION_3; | 904 | mmc->version = SD_VERSION_3; |
| 908 | break; | 905 | break; |
| 909 | default: | 906 | default: |
| 910 | mmc->version = SD_VERSION_1_0; | 907 | mmc->version = SD_VERSION_1_0; |
| 911 | break; | 908 | break; |
| 912 | } | 909 | } |
| 913 | 910 | ||
| 914 | if (mmc->scr[0] & SD_DATA_4BIT) | 911 | if (mmc->scr[0] & SD_DATA_4BIT) |
| 915 | mmc->card_caps |= MMC_MODE_4BIT; | 912 | mmc->card_caps |= MMC_MODE_4BIT; |
| 916 | 913 | ||
| 917 | /* Version 1.0 doesn't support switching */ | 914 | /* Version 1.0 doesn't support switching */ |
| 918 | if (mmc->version == SD_VERSION_1_0) | 915 | if (mmc->version == SD_VERSION_1_0) |
| 919 | return 0; | 916 | return 0; |
| 920 | 917 | ||
| 921 | timeout = 4; | 918 | timeout = 4; |
| 922 | while (timeout--) { | 919 | while (timeout--) { |
| 923 | err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, | 920 | err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, |
| 924 | (u8 *)switch_status); | 921 | (u8 *)switch_status); |
| 925 | 922 | ||
| 926 | if (err) | 923 | if (err) |
| 927 | return err; | 924 | return err; |
| 928 | 925 | ||
| 929 | /* The high-speed function is busy. Try again */ | 926 | /* The high-speed function is busy. Try again */ |
| 930 | if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) | 927 | if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) |
| 931 | break; | 928 | break; |
| 932 | } | 929 | } |
| 933 | 930 | ||
| 934 | /* If high-speed isn't supported, we return */ | 931 | /* If high-speed isn't supported, we return */ |
| 935 | if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) | 932 | if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) |
| 936 | return 0; | 933 | return 0; |
| 937 | 934 | ||
| 938 | /* | 935 | /* |
| 939 | * If the host doesn't support SD_HIGHSPEED, do not switch card to | 936 | * If the host doesn't support SD_HIGHSPEED, do not switch card to |
| 940 | * HIGHSPEED mode even if the card support SD_HIGHSPPED. | 937 | * HIGHSPEED mode even if the card support SD_HIGHSPPED. |
| 941 | * This can avoid furthur problem when the card runs in different | 938 | * This can avoid furthur problem when the card runs in different |
| 942 | * mode between the host. | 939 | * mode between the host. |
| 943 | */ | 940 | */ |
| 944 | if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && | 941 | if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && |
| 945 | (mmc->cfg->host_caps & MMC_MODE_HS))) | 942 | (mmc->cfg->host_caps & MMC_MODE_HS))) |
| 946 | return 0; | 943 | return 0; |
| 947 | 944 | ||
| 948 | err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); | 945 | err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); |
| 949 | 946 | ||
| 950 | if (err) | 947 | if (err) |
| 951 | return err; | 948 | return err; |
| 952 | 949 | ||
| 953 | if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) | 950 | if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) |
| 954 | mmc->card_caps |= MMC_MODE_HS; | 951 | mmc->card_caps |= MMC_MODE_HS; |
| 955 | 952 | ||
| 956 | return 0; | 953 | return 0; |
| 957 | } | 954 | } |
| 958 | 955 | ||
| 959 | /* frequency bases */ | 956 | /* frequency bases */ |
| 960 | /* divided by 10 to be nice to platforms without floating point */ | 957 | /* divided by 10 to be nice to platforms without floating point */ |
| 961 | static const int fbase[] = { | 958 | static const int fbase[] = { |
| 962 | 10000, | 959 | 10000, |
| 963 | 100000, | 960 | 100000, |
| 964 | 1000000, | 961 | 1000000, |
| 965 | 10000000, | 962 | 10000000, |
| 966 | }; | 963 | }; |
| 967 | 964 | ||
| 968 | /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice | 965 | /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice |
| 969 | * to platforms without floating point. | 966 | * to platforms without floating point. |
| 970 | */ | 967 | */ |
| 971 | static const int multipliers[] = { | 968 | static const int multipliers[] = { |
| 972 | 0, /* reserved */ | 969 | 0, /* reserved */ |
| 973 | 10, | 970 | 10, |
| 974 | 12, | 971 | 12, |
| 975 | 13, | 972 | 13, |
| 976 | 15, | 973 | 15, |
| 977 | 20, | 974 | 20, |
| 978 | 25, | 975 | 25, |
| 979 | 30, | 976 | 30, |
| 980 | 35, | 977 | 35, |
| 981 | 40, | 978 | 40, |
| 982 | 45, | 979 | 45, |
| 983 | 50, | 980 | 50, |
| 984 | 55, | 981 | 55, |
| 985 | 60, | 982 | 60, |
| 986 | 70, | 983 | 70, |
| 987 | 80, | 984 | 80, |
| 988 | }; | 985 | }; |
| 989 | 986 | ||
| 990 | static void mmc_set_ios(struct mmc *mmc) | 987 | static void mmc_set_ios(struct mmc *mmc) |
| 991 | { | 988 | { |
| 992 | if (mmc->cfg->ops->set_ios) | 989 | if (mmc->cfg->ops->set_ios) |
| 993 | mmc->cfg->ops->set_ios(mmc); | 990 | mmc->cfg->ops->set_ios(mmc); |
| 994 | } | 991 | } |
| 995 | 992 | ||
| 996 | void mmc_set_clock(struct mmc *mmc, uint clock) | 993 | void mmc_set_clock(struct mmc *mmc, uint clock) |
| 997 | { | 994 | { |
| 998 | if (clock > mmc->cfg->f_max) | 995 | if (clock > mmc->cfg->f_max) |
| 999 | clock = mmc->cfg->f_max; | 996 | clock = mmc->cfg->f_max; |
| 1000 | 997 | ||
| 1001 | if (clock < mmc->cfg->f_min) | 998 | if (clock < mmc->cfg->f_min) |
| 1002 | clock = mmc->cfg->f_min; | 999 | clock = mmc->cfg->f_min; |
| 1003 | 1000 | ||
| 1004 | mmc->clock = clock; | 1001 | mmc->clock = clock; |
| 1005 | 1002 | ||
| 1006 | mmc_set_ios(mmc); | 1003 | mmc_set_ios(mmc); |
| 1007 | } | 1004 | } |
| 1008 | 1005 | ||
| 1009 | static void mmc_set_bus_width(struct mmc *mmc, uint width) | 1006 | static void mmc_set_bus_width(struct mmc *mmc, uint width) |
| 1010 | { | 1007 | { |
| 1011 | mmc->bus_width = width; | 1008 | mmc->bus_width = width; |
| 1012 | 1009 | ||
| 1013 | mmc_set_ios(mmc); | 1010 | mmc_set_ios(mmc); |
| 1014 | } | 1011 | } |
| 1015 | 1012 | ||
| 1016 | static int mmc_startup(struct mmc *mmc) | 1013 | static int mmc_startup(struct mmc *mmc) |
| 1017 | { | 1014 | { |
| 1018 | int err, i; | 1015 | int err, i; |
| 1019 | uint mult, freq; | 1016 | uint mult, freq; |
| 1020 | u64 cmult, csize, capacity; | 1017 | u64 cmult, csize, capacity; |
| 1021 | struct mmc_cmd cmd; | 1018 | struct mmc_cmd cmd; |
| 1022 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); | 1019 | ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); |
| 1023 | ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); | 1020 | ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); |
| 1024 | int timeout = 1000; | 1021 | int timeout = 1000; |
| 1025 | bool has_parts = false; | 1022 | bool has_parts = false; |
| 1026 | bool part_completed; | 1023 | bool part_completed; |
| 1027 | 1024 | ||
| 1028 | #ifdef CONFIG_MMC_SPI_CRC_ON | 1025 | #ifdef CONFIG_MMC_SPI_CRC_ON |
| 1029 | if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ | 1026 | if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ |
| 1030 | cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; | 1027 | cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; |
| 1031 | cmd.resp_type = MMC_RSP_R1; | 1028 | cmd.resp_type = MMC_RSP_R1; |
| 1032 | cmd.cmdarg = 1; | 1029 | cmd.cmdarg = 1; |
| 1033 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1030 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1034 | 1031 | ||
| 1035 | if (err) | 1032 | if (err) |
| 1036 | return err; | 1033 | return err; |
| 1037 | } | 1034 | } |
| 1038 | #endif | 1035 | #endif |
| 1039 | 1036 | ||
| 1040 | /* Put the Card in Identify Mode */ | 1037 | /* Put the Card in Identify Mode */ |
| 1041 | cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : | 1038 | cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : |
| 1042 | MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ | 1039 | MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ |
| 1043 | cmd.resp_type = MMC_RSP_R2; | 1040 | cmd.resp_type = MMC_RSP_R2; |
| 1044 | cmd.cmdarg = 0; | 1041 | cmd.cmdarg = 0; |
| 1045 | 1042 | ||
| 1046 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1043 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1047 | 1044 | ||
| 1048 | if (err) | 1045 | if (err) |
| 1049 | return err; | 1046 | return err; |
| 1050 | 1047 | ||
| 1051 | memcpy(mmc->cid, cmd.response, 16); | 1048 | memcpy(mmc->cid, cmd.response, 16); |
| 1052 | 1049 | ||
| 1053 | /* | 1050 | /* |
| 1054 | * For MMC cards, set the Relative Address. | 1051 | * For MMC cards, set the Relative Address. |
| 1055 | * For SD cards, get the Relatvie Address. | 1052 | * For SD cards, get the Relatvie Address. |
| 1056 | * This also puts the cards into Standby State | 1053 | * This also puts the cards into Standby State |
| 1057 | */ | 1054 | */ |
| 1058 | if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ | 1055 | if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ |
| 1059 | cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; | 1056 | cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; |
| 1060 | cmd.cmdarg = mmc->rca << 16; | 1057 | cmd.cmdarg = mmc->rca << 16; |
| 1061 | cmd.resp_type = MMC_RSP_R6; | 1058 | cmd.resp_type = MMC_RSP_R6; |
| 1062 | 1059 | ||
| 1063 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1060 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1064 | 1061 | ||
| 1065 | if (err) | 1062 | if (err) |
| 1066 | return err; | 1063 | return err; |
| 1067 | 1064 | ||
| 1068 | if (IS_SD(mmc)) | 1065 | if (IS_SD(mmc)) |
| 1069 | mmc->rca = (cmd.response[0] >> 16) & 0xffff; | 1066 | mmc->rca = (cmd.response[0] >> 16) & 0xffff; |
| 1070 | } | 1067 | } |
| 1071 | 1068 | ||
| 1072 | /* Get the Card-Specific Data */ | 1069 | /* Get the Card-Specific Data */ |
| 1073 | cmd.cmdidx = MMC_CMD_SEND_CSD; | 1070 | cmd.cmdidx = MMC_CMD_SEND_CSD; |
| 1074 | cmd.resp_type = MMC_RSP_R2; | 1071 | cmd.resp_type = MMC_RSP_R2; |
| 1075 | cmd.cmdarg = mmc->rca << 16; | 1072 | cmd.cmdarg = mmc->rca << 16; |
| 1076 | 1073 | ||
| 1077 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1074 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1078 | 1075 | ||
| 1079 | /* Waiting for the ready status */ | 1076 | /* Waiting for the ready status */ |
| 1080 | mmc_send_status(mmc, timeout); | 1077 | mmc_send_status(mmc, timeout); |
| 1081 | 1078 | ||
| 1082 | if (err) | 1079 | if (err) |
| 1083 | return err; | 1080 | return err; |
| 1084 | 1081 | ||
| 1085 | mmc->csd[0] = cmd.response[0]; | 1082 | mmc->csd[0] = cmd.response[0]; |
| 1086 | mmc->csd[1] = cmd.response[1]; | 1083 | mmc->csd[1] = cmd.response[1]; |
| 1087 | mmc->csd[2] = cmd.response[2]; | 1084 | mmc->csd[2] = cmd.response[2]; |
| 1088 | mmc->csd[3] = cmd.response[3]; | 1085 | mmc->csd[3] = cmd.response[3]; |
| 1089 | 1086 | ||
| 1090 | if (mmc->version == MMC_VERSION_UNKNOWN) { | 1087 | if (mmc->version == MMC_VERSION_UNKNOWN) { |
| 1091 | int version = (cmd.response[0] >> 26) & 0xf; | 1088 | int version = (cmd.response[0] >> 26) & 0xf; |
| 1092 | 1089 | ||
| 1093 | switch (version) { | 1090 | switch (version) { |
| 1094 | case 0: | 1091 | case 0: |
| 1095 | mmc->version = MMC_VERSION_1_2; | 1092 | mmc->version = MMC_VERSION_1_2; |
| 1096 | break; | 1093 | break; |
| 1097 | case 1: | 1094 | case 1: |
| 1098 | mmc->version = MMC_VERSION_1_4; | 1095 | mmc->version = MMC_VERSION_1_4; |
| 1099 | break; | 1096 | break; |
| 1100 | case 2: | 1097 | case 2: |
| 1101 | mmc->version = MMC_VERSION_2_2; | 1098 | mmc->version = MMC_VERSION_2_2; |
| 1102 | break; | 1099 | break; |
| 1103 | case 3: | 1100 | case 3: |
| 1104 | mmc->version = MMC_VERSION_3; | 1101 | mmc->version = MMC_VERSION_3; |
| 1105 | break; | 1102 | break; |
| 1106 | case 4: | 1103 | case 4: |
| 1107 | mmc->version = MMC_VERSION_4; | 1104 | mmc->version = MMC_VERSION_4; |
| 1108 | break; | 1105 | break; |
| 1109 | default: | 1106 | default: |
| 1110 | mmc->version = MMC_VERSION_1_2; | 1107 | mmc->version = MMC_VERSION_1_2; |
| 1111 | break; | 1108 | break; |
| 1112 | } | 1109 | } |
| 1113 | } | 1110 | } |
| 1114 | 1111 | ||
| 1115 | /* divide frequency by 10, since the mults are 10x bigger */ | 1112 | /* divide frequency by 10, since the mults are 10x bigger */ |
| 1116 | freq = fbase[(cmd.response[0] & 0x7)]; | 1113 | freq = fbase[(cmd.response[0] & 0x7)]; |
| 1117 | mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; | 1114 | mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; |
| 1118 | 1115 | ||
| 1119 | mmc->tran_speed = freq * mult; | 1116 | mmc->tran_speed = freq * mult; |
| 1120 | 1117 | ||
| 1121 | mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); | 1118 | mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); |
| 1122 | mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); | 1119 | mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); |
| 1123 | 1120 | ||
| 1124 | if (IS_SD(mmc)) | 1121 | if (IS_SD(mmc)) |
| 1125 | mmc->write_bl_len = mmc->read_bl_len; | 1122 | mmc->write_bl_len = mmc->read_bl_len; |
| 1126 | else | 1123 | else |
| 1127 | mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); | 1124 | mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); |
| 1128 | 1125 | ||
| 1129 | if (mmc->high_capacity) { | 1126 | if (mmc->high_capacity) { |
| 1130 | csize = (mmc->csd[1] & 0x3f) << 16 | 1127 | csize = (mmc->csd[1] & 0x3f) << 16 |
| 1131 | | (mmc->csd[2] & 0xffff0000) >> 16; | 1128 | | (mmc->csd[2] & 0xffff0000) >> 16; |
| 1132 | cmult = 8; | 1129 | cmult = 8; |
| 1133 | } else { | 1130 | } else { |
| 1134 | csize = (mmc->csd[1] & 0x3ff) << 2 | 1131 | csize = (mmc->csd[1] & 0x3ff) << 2 |
| 1135 | | (mmc->csd[2] & 0xc0000000) >> 30; | 1132 | | (mmc->csd[2] & 0xc0000000) >> 30; |
| 1136 | cmult = (mmc->csd[2] & 0x00038000) >> 15; | 1133 | cmult = (mmc->csd[2] & 0x00038000) >> 15; |
| 1137 | } | 1134 | } |
| 1138 | 1135 | ||
| 1139 | mmc->capacity_user = (csize + 1) << (cmult + 2); | 1136 | mmc->capacity_user = (csize + 1) << (cmult + 2); |
| 1140 | mmc->capacity_user *= mmc->read_bl_len; | 1137 | mmc->capacity_user *= mmc->read_bl_len; |
| 1141 | mmc->capacity_boot = 0; | 1138 | mmc->capacity_boot = 0; |
| 1142 | mmc->capacity_rpmb = 0; | 1139 | mmc->capacity_rpmb = 0; |
| 1143 | for (i = 0; i < 4; i++) | 1140 | for (i = 0; i < 4; i++) |
| 1144 | mmc->capacity_gp[i] = 0; | 1141 | mmc->capacity_gp[i] = 0; |
| 1145 | 1142 | ||
| 1146 | if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) | 1143 | if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) |
| 1147 | mmc->read_bl_len = MMC_MAX_BLOCK_LEN; | 1144 | mmc->read_bl_len = MMC_MAX_BLOCK_LEN; |
| 1148 | 1145 | ||
| 1149 | if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) | 1146 | if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) |
| 1150 | mmc->write_bl_len = MMC_MAX_BLOCK_LEN; | 1147 | mmc->write_bl_len = MMC_MAX_BLOCK_LEN; |
| 1151 | 1148 | ||
| 1152 | if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { | 1149 | if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { |
| 1153 | cmd.cmdidx = MMC_CMD_SET_DSR; | 1150 | cmd.cmdidx = MMC_CMD_SET_DSR; |
| 1154 | cmd.cmdarg = (mmc->dsr & 0xffff) << 16; | 1151 | cmd.cmdarg = (mmc->dsr & 0xffff) << 16; |
| 1155 | cmd.resp_type = MMC_RSP_NONE; | 1152 | cmd.resp_type = MMC_RSP_NONE; |
| 1156 | if (mmc_send_cmd(mmc, &cmd, NULL)) | 1153 | if (mmc_send_cmd(mmc, &cmd, NULL)) |
| 1157 | printf("MMC: SET_DSR failed\n"); | 1154 | printf("MMC: SET_DSR failed\n"); |
| 1158 | } | 1155 | } |
| 1159 | 1156 | ||
| 1160 | /* Select the card, and put it into Transfer Mode */ | 1157 | /* Select the card, and put it into Transfer Mode */ |
| 1161 | if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ | 1158 | if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ |
| 1162 | cmd.cmdidx = MMC_CMD_SELECT_CARD; | 1159 | cmd.cmdidx = MMC_CMD_SELECT_CARD; |
| 1163 | cmd.resp_type = MMC_RSP_R1; | 1160 | cmd.resp_type = MMC_RSP_R1; |
| 1164 | cmd.cmdarg = mmc->rca << 16; | 1161 | cmd.cmdarg = mmc->rca << 16; |
| 1165 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1162 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1166 | 1163 | ||
| 1167 | if (err) | 1164 | if (err) |
| 1168 | return err; | 1165 | return err; |
| 1169 | } | 1166 | } |
| 1170 | 1167 | ||
| 1171 | /* | 1168 | /* |
| 1172 | * For SD, its erase group is always one sector | 1169 | * For SD, its erase group is always one sector |
| 1173 | */ | 1170 | */ |
| 1174 | mmc->erase_grp_size = 1; | 1171 | mmc->erase_grp_size = 1; |
| 1175 | mmc->part_config = MMCPART_NOAVAILABLE; | 1172 | mmc->part_config = MMCPART_NOAVAILABLE; |
| 1176 | if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { | 1173 | if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { |
| 1177 | /* check ext_csd version and capacity */ | 1174 | /* check ext_csd version and capacity */ |
| 1178 | err = mmc_send_ext_csd(mmc, ext_csd); | 1175 | err = mmc_send_ext_csd(mmc, ext_csd); |
| 1179 | if (err) | 1176 | if (err) |
| 1180 | return err; | 1177 | return err; |
| 1181 | if (ext_csd[EXT_CSD_REV] >= 2) { | 1178 | if (ext_csd[EXT_CSD_REV] >= 2) { |
| 1182 | /* | 1179 | /* |
| 1183 | * According to the JEDEC Standard, the value of | 1180 | * According to the JEDEC Standard, the value of |
| 1184 | * ext_csd's capacity is valid if the value is more | 1181 | * ext_csd's capacity is valid if the value is more |
| 1185 | * than 2GB | 1182 | * than 2GB |
| 1186 | */ | 1183 | */ |
| 1187 | capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 | 1184 | capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 |
| 1188 | | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | 1185 | | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
| 1189 | | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | 1186 | | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
| 1190 | | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; | 1187 | | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; |
| 1191 | capacity *= MMC_MAX_BLOCK_LEN; | 1188 | capacity *= MMC_MAX_BLOCK_LEN; |
| 1192 | if ((capacity >> 20) > 2 * 1024) | 1189 | if ((capacity >> 20) > 2 * 1024) |
| 1193 | mmc->capacity_user = capacity; | 1190 | mmc->capacity_user = capacity; |
| 1194 | } | 1191 | } |
| 1195 | 1192 | ||
| 1196 | switch (ext_csd[EXT_CSD_REV]) { | 1193 | switch (ext_csd[EXT_CSD_REV]) { |
| 1197 | case 1: | 1194 | case 1: |
| 1198 | mmc->version = MMC_VERSION_4_1; | 1195 | mmc->version = MMC_VERSION_4_1; |
| 1199 | break; | 1196 | break; |
| 1200 | case 2: | 1197 | case 2: |
| 1201 | mmc->version = MMC_VERSION_4_2; | 1198 | mmc->version = MMC_VERSION_4_2; |
| 1202 | break; | 1199 | break; |
| 1203 | case 3: | 1200 | case 3: |
| 1204 | mmc->version = MMC_VERSION_4_3; | 1201 | mmc->version = MMC_VERSION_4_3; |
| 1205 | break; | 1202 | break; |
| 1206 | case 5: | 1203 | case 5: |
| 1207 | mmc->version = MMC_VERSION_4_41; | 1204 | mmc->version = MMC_VERSION_4_41; |
| 1208 | break; | 1205 | break; |
| 1209 | case 6: | 1206 | case 6: |
| 1210 | mmc->version = MMC_VERSION_4_5; | 1207 | mmc->version = MMC_VERSION_4_5; |
| 1211 | break; | 1208 | break; |
| 1212 | case 7: | 1209 | case 7: |
| 1213 | mmc->version = MMC_VERSION_5_0; | 1210 | mmc->version = MMC_VERSION_5_0; |
| 1214 | break; | 1211 | break; |
| 1215 | } | 1212 | } |
| 1216 | 1213 | ||
| 1217 | /* The partition data may be non-zero but it is only | 1214 | /* The partition data may be non-zero but it is only |
| 1218 | * effective if PARTITION_SETTING_COMPLETED is set in | 1215 | * effective if PARTITION_SETTING_COMPLETED is set in |
| 1219 | * EXT_CSD, so ignore any data if this bit is not set, | 1216 | * EXT_CSD, so ignore any data if this bit is not set, |
| 1220 | * except for enabling the high-capacity group size | 1217 | * except for enabling the high-capacity group size |
| 1221 | * definition (see below). */ | 1218 | * definition (see below). */ |
| 1222 | part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & | 1219 | part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & |
| 1223 | EXT_CSD_PARTITION_SETTING_COMPLETED); | 1220 | EXT_CSD_PARTITION_SETTING_COMPLETED); |
| 1224 | 1221 | ||
| 1225 | /* store the partition info of emmc */ | 1222 | /* store the partition info of emmc */ |
| 1226 | mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; | 1223 | mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; |
| 1227 | if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || | 1224 | if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || |
| 1228 | ext_csd[EXT_CSD_BOOT_MULT]) | 1225 | ext_csd[EXT_CSD_BOOT_MULT]) |
| 1229 | mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; | 1226 | mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; |
| 1230 | if (part_completed && | 1227 | if (part_completed && |
| 1231 | (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) | 1228 | (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) |
| 1232 | mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; | 1229 | mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; |
| 1233 | 1230 | ||
| 1234 | mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; | 1231 | mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; |
| 1235 | 1232 | ||
| 1236 | mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; | 1233 | mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; |
| 1237 | 1234 | ||
| 1238 | for (i = 0; i < 4; i++) { | 1235 | for (i = 0; i < 4; i++) { |
| 1239 | int idx = EXT_CSD_GP_SIZE_MULT + i * 3; | 1236 | int idx = EXT_CSD_GP_SIZE_MULT + i * 3; |
| 1240 | uint mult = (ext_csd[idx + 2] << 16) + | 1237 | uint mult = (ext_csd[idx + 2] << 16) + |
| 1241 | (ext_csd[idx + 1] << 8) + ext_csd[idx]; | 1238 | (ext_csd[idx + 1] << 8) + ext_csd[idx]; |
| 1242 | if (mult) | 1239 | if (mult) |
| 1243 | has_parts = true; | 1240 | has_parts = true; |
| 1244 | if (!part_completed) | 1241 | if (!part_completed) |
| 1245 | continue; | 1242 | continue; |
| 1246 | mmc->capacity_gp[i] = mult; | 1243 | mmc->capacity_gp[i] = mult; |
| 1247 | mmc->capacity_gp[i] *= | 1244 | mmc->capacity_gp[i] *= |
| 1248 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; | 1245 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; |
| 1249 | mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; | 1246 | mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; |
| 1250 | mmc->capacity_gp[i] <<= 19; | 1247 | mmc->capacity_gp[i] <<= 19; |
| 1251 | } | 1248 | } |
| 1252 | 1249 | ||
| 1253 | if (part_completed) { | 1250 | if (part_completed) { |
| 1254 | mmc->enh_user_size = | 1251 | mmc->enh_user_size = |
| 1255 | (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + | 1252 | (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + |
| 1256 | (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + | 1253 | (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + |
| 1257 | ext_csd[EXT_CSD_ENH_SIZE_MULT]; | 1254 | ext_csd[EXT_CSD_ENH_SIZE_MULT]; |
| 1258 | mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; | 1255 | mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; |
| 1259 | mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; | 1256 | mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; |
| 1260 | mmc->enh_user_size <<= 19; | 1257 | mmc->enh_user_size <<= 19; |
| 1261 | mmc->enh_user_start = | 1258 | mmc->enh_user_start = |
| 1262 | (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + | 1259 | (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + |
| 1263 | (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + | 1260 | (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + |
| 1264 | (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + | 1261 | (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + |
| 1265 | ext_csd[EXT_CSD_ENH_START_ADDR]; | 1262 | ext_csd[EXT_CSD_ENH_START_ADDR]; |
| 1266 | if (mmc->high_capacity) | 1263 | if (mmc->high_capacity) |
| 1267 | mmc->enh_user_start <<= 9; | 1264 | mmc->enh_user_start <<= 9; |
| 1268 | } | 1265 | } |
| 1269 | 1266 | ||
| 1270 | /* | 1267 | /* |
| 1271 | * Host needs to enable ERASE_GRP_DEF bit if device is | 1268 | * Host needs to enable ERASE_GRP_DEF bit if device is |
| 1272 | * partitioned. This bit will be lost every time after a reset | 1269 | * partitioned. This bit will be lost every time after a reset |
| 1273 | * or power off. This will affect erase size. | 1270 | * or power off. This will affect erase size. |
| 1274 | */ | 1271 | */ |
| 1275 | if (part_completed) | 1272 | if (part_completed) |
| 1276 | has_parts = true; | 1273 | has_parts = true; |
| 1277 | if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && | 1274 | if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && |
| 1278 | (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) | 1275 | (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) |
| 1279 | has_parts = true; | 1276 | has_parts = true; |
| 1280 | if (has_parts) { | 1277 | if (has_parts) { |
| 1281 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 1278 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 1282 | EXT_CSD_ERASE_GROUP_DEF, 1); | 1279 | EXT_CSD_ERASE_GROUP_DEF, 1); |
| 1283 | 1280 | ||
| 1284 | if (err) | 1281 | if (err) |
| 1285 | return err; | 1282 | return err; |
| 1286 | else | 1283 | else |
| 1287 | ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; | 1284 | ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; |
| 1288 | } | 1285 | } |
| 1289 | 1286 | ||
| 1290 | if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { | 1287 | if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { |
| 1291 | /* Read out group size from ext_csd */ | 1288 | /* Read out group size from ext_csd */ |
| 1292 | mmc->erase_grp_size = | 1289 | mmc->erase_grp_size = |
| 1293 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; | 1290 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; |
| 1294 | /* | 1291 | /* |
| 1295 | * if high capacity and partition setting completed | 1292 | * if high capacity and partition setting completed |
| 1296 | * SEC_COUNT is valid even if it is smaller than 2 GiB | 1293 | * SEC_COUNT is valid even if it is smaller than 2 GiB |
| 1297 | * JEDEC Standard JESD84-B45, 6.2.4 | 1294 | * JEDEC Standard JESD84-B45, 6.2.4 |
| 1298 | */ | 1295 | */ |
| 1299 | if (mmc->high_capacity && part_completed) { | 1296 | if (mmc->high_capacity && part_completed) { |
| 1300 | capacity = (ext_csd[EXT_CSD_SEC_CNT]) | | 1297 | capacity = (ext_csd[EXT_CSD_SEC_CNT]) | |
| 1301 | (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | | 1298 | (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | |
| 1302 | (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | | 1299 | (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | |
| 1303 | (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); | 1300 | (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); |
| 1304 | capacity *= MMC_MAX_BLOCK_LEN; | 1301 | capacity *= MMC_MAX_BLOCK_LEN; |
| 1305 | mmc->capacity_user = capacity; | 1302 | mmc->capacity_user = capacity; |
| 1306 | } | 1303 | } |
| 1307 | } else { | 1304 | } else { |
| 1308 | /* Calculate the group size from the csd value. */ | 1305 | /* Calculate the group size from the csd value. */ |
| 1309 | int erase_gsz, erase_gmul; | 1306 | int erase_gsz, erase_gmul; |
| 1310 | erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; | 1307 | erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; |
| 1311 | erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; | 1308 | erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; |
| 1312 | mmc->erase_grp_size = (erase_gsz + 1) | 1309 | mmc->erase_grp_size = (erase_gsz + 1) |
| 1313 | * (erase_gmul + 1); | 1310 | * (erase_gmul + 1); |
| 1314 | } | 1311 | } |
| 1315 | 1312 | ||
| 1316 | mmc->hc_wp_grp_size = 1024 | 1313 | mmc->hc_wp_grp_size = 1024 |
| 1317 | * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] | 1314 | * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] |
| 1318 | * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; | 1315 | * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; |
| 1319 | 1316 | ||
| 1320 | mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; | 1317 | mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; |
| 1321 | } | 1318 | } |
| 1322 | 1319 | ||
| 1323 | err = mmc_set_capacity(mmc, mmc->part_num); | 1320 | err = mmc_set_capacity(mmc, mmc->part_num); |
| 1324 | if (err) | 1321 | if (err) |
| 1325 | return err; | 1322 | return err; |
| 1326 | 1323 | ||
| 1327 | if (IS_SD(mmc)) | 1324 | if (IS_SD(mmc)) |
| 1328 | err = sd_change_freq(mmc); | 1325 | err = sd_change_freq(mmc); |
| 1329 | else | 1326 | else |
| 1330 | err = mmc_change_freq(mmc); | 1327 | err = mmc_change_freq(mmc); |
| 1331 | 1328 | ||
| 1332 | if (err) | 1329 | if (err) |
| 1333 | return err; | 1330 | return err; |
| 1334 | 1331 | ||
| 1335 | /* Restrict card's capabilities by what the host can do */ | 1332 | /* Restrict card's capabilities by what the host can do */ |
| 1336 | mmc->card_caps &= mmc->cfg->host_caps; | 1333 | mmc->card_caps &= mmc->cfg->host_caps; |
| 1337 | 1334 | ||
| 1338 | if (IS_SD(mmc)) { | 1335 | if (IS_SD(mmc)) { |
| 1339 | if (mmc->card_caps & MMC_MODE_4BIT) { | 1336 | if (mmc->card_caps & MMC_MODE_4BIT) { |
| 1340 | cmd.cmdidx = MMC_CMD_APP_CMD; | 1337 | cmd.cmdidx = MMC_CMD_APP_CMD; |
| 1341 | cmd.resp_type = MMC_RSP_R1; | 1338 | cmd.resp_type = MMC_RSP_R1; |
| 1342 | cmd.cmdarg = mmc->rca << 16; | 1339 | cmd.cmdarg = mmc->rca << 16; |
| 1343 | 1340 | ||
| 1344 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1341 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1345 | if (err) | 1342 | if (err) |
| 1346 | return err; | 1343 | return err; |
| 1347 | 1344 | ||
| 1348 | cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; | 1345 | cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; |
| 1349 | cmd.resp_type = MMC_RSP_R1; | 1346 | cmd.resp_type = MMC_RSP_R1; |
| 1350 | cmd.cmdarg = 2; | 1347 | cmd.cmdarg = 2; |
| 1351 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1348 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1352 | if (err) | 1349 | if (err) |
| 1353 | return err; | 1350 | return err; |
| 1354 | 1351 | ||
| 1355 | mmc_set_bus_width(mmc, 4); | 1352 | mmc_set_bus_width(mmc, 4); |
| 1356 | } | 1353 | } |
| 1357 | 1354 | ||
| 1358 | if (mmc->card_caps & MMC_MODE_HS) | 1355 | if (mmc->card_caps & MMC_MODE_HS) |
| 1359 | mmc->tran_speed = 50000000; | 1356 | mmc->tran_speed = 50000000; |
| 1360 | else | 1357 | else |
| 1361 | mmc->tran_speed = 25000000; | 1358 | mmc->tran_speed = 25000000; |
| 1362 | } else if (mmc->version >= MMC_VERSION_4) { | 1359 | } else if (mmc->version >= MMC_VERSION_4) { |
| 1363 | /* Only version 4 of MMC supports wider bus widths */ | 1360 | /* Only version 4 of MMC supports wider bus widths */ |
| 1364 | int idx; | 1361 | int idx; |
| 1365 | 1362 | ||
| 1366 | /* An array of possible bus widths in order of preference */ | 1363 | /* An array of possible bus widths in order of preference */ |
| 1367 | static unsigned ext_csd_bits[] = { | 1364 | static unsigned ext_csd_bits[] = { |
| 1368 | EXT_CSD_DDR_BUS_WIDTH_8, | 1365 | EXT_CSD_DDR_BUS_WIDTH_8, |
| 1369 | EXT_CSD_DDR_BUS_WIDTH_4, | 1366 | EXT_CSD_DDR_BUS_WIDTH_4, |
| 1370 | EXT_CSD_BUS_WIDTH_8, | 1367 | EXT_CSD_BUS_WIDTH_8, |
| 1371 | EXT_CSD_BUS_WIDTH_4, | 1368 | EXT_CSD_BUS_WIDTH_4, |
| 1372 | EXT_CSD_BUS_WIDTH_1, | 1369 | EXT_CSD_BUS_WIDTH_1, |
| 1373 | }; | 1370 | }; |
| 1374 | 1371 | ||
| 1375 | /* An array to map CSD bus widths to host cap bits */ | 1372 | /* An array to map CSD bus widths to host cap bits */ |
| 1376 | static unsigned ext_to_hostcaps[] = { | 1373 | static unsigned ext_to_hostcaps[] = { |
| 1377 | [EXT_CSD_DDR_BUS_WIDTH_4] = | 1374 | [EXT_CSD_DDR_BUS_WIDTH_4] = |
| 1378 | MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, | 1375 | MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, |
| 1379 | [EXT_CSD_DDR_BUS_WIDTH_8] = | 1376 | [EXT_CSD_DDR_BUS_WIDTH_8] = |
| 1380 | MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, | 1377 | MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, |
| 1381 | [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, | 1378 | [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, |
| 1382 | [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, | 1379 | [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, |
| 1383 | }; | 1380 | }; |
| 1384 | 1381 | ||
| 1385 | /* An array to map chosen bus width to an integer */ | 1382 | /* An array to map chosen bus width to an integer */ |
| 1386 | static unsigned widths[] = { | 1383 | static unsigned widths[] = { |
| 1387 | 8, 4, 8, 4, 1, | 1384 | 8, 4, 8, 4, 1, |
| 1388 | }; | 1385 | }; |
| 1389 | 1386 | ||
| 1390 | for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { | 1387 | for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { |
| 1391 | unsigned int extw = ext_csd_bits[idx]; | 1388 | unsigned int extw = ext_csd_bits[idx]; |
| 1392 | unsigned int caps = ext_to_hostcaps[extw]; | 1389 | unsigned int caps = ext_to_hostcaps[extw]; |
| 1393 | 1390 | ||
| 1394 | /* | 1391 | /* |
| 1395 | * If the bus width is still not changed, | 1392 | * If the bus width is still not changed, |
| 1396 | * don't try to set the default again. | 1393 | * don't try to set the default again. |
| 1397 | * Otherwise, recover from switch attempts | 1394 | * Otherwise, recover from switch attempts |
| 1398 | * by switching to 1-bit bus width. | 1395 | * by switching to 1-bit bus width. |
| 1399 | */ | 1396 | */ |
| 1400 | if (extw == EXT_CSD_BUS_WIDTH_1 && | 1397 | if (extw == EXT_CSD_BUS_WIDTH_1 && |
| 1401 | mmc->bus_width == 1) { | 1398 | mmc->bus_width == 1) { |
| 1402 | err = 0; | 1399 | err = 0; |
| 1403 | break; | 1400 | break; |
| 1404 | } | 1401 | } |
| 1405 | 1402 | ||
| 1406 | /* | 1403 | /* |
| 1407 | * Check to make sure the card and controller support | 1404 | * Check to make sure the card and controller support |
| 1408 | * these capabilities | 1405 | * these capabilities |
| 1409 | */ | 1406 | */ |
| 1410 | if ((mmc->card_caps & caps) != caps) | 1407 | if ((mmc->card_caps & caps) != caps) |
| 1411 | continue; | 1408 | continue; |
| 1412 | 1409 | ||
| 1413 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, | 1410 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, |
| 1414 | EXT_CSD_BUS_WIDTH, extw); | 1411 | EXT_CSD_BUS_WIDTH, extw); |
| 1415 | 1412 | ||
| 1416 | if (err) | 1413 | if (err) |
| 1417 | continue; | 1414 | continue; |
| 1418 | 1415 | ||
| 1419 | mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; | 1416 | mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; |
| 1420 | mmc_set_bus_width(mmc, widths[idx]); | 1417 | mmc_set_bus_width(mmc, widths[idx]); |
| 1421 | 1418 | ||
| 1422 | err = mmc_send_ext_csd(mmc, test_csd); | 1419 | err = mmc_send_ext_csd(mmc, test_csd); |
| 1423 | 1420 | ||
| 1424 | if (err) | 1421 | if (err) |
| 1425 | continue; | 1422 | continue; |
| 1426 | 1423 | ||
| 1427 | /* Only compare read only fields */ | 1424 | /* Only compare read only fields */ |
| 1428 | if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] | 1425 | if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] |
| 1429 | == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && | 1426 | == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && |
| 1430 | ext_csd[EXT_CSD_HC_WP_GRP_SIZE] | 1427 | ext_csd[EXT_CSD_HC_WP_GRP_SIZE] |
| 1431 | == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && | 1428 | == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && |
| 1432 | ext_csd[EXT_CSD_REV] | 1429 | ext_csd[EXT_CSD_REV] |
| 1433 | == test_csd[EXT_CSD_REV] && | 1430 | == test_csd[EXT_CSD_REV] && |
| 1434 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] | 1431 | ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] |
| 1435 | == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && | 1432 | == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && |
| 1436 | memcmp(&ext_csd[EXT_CSD_SEC_CNT], | 1433 | memcmp(&ext_csd[EXT_CSD_SEC_CNT], |
| 1437 | &test_csd[EXT_CSD_SEC_CNT], 4) == 0) | 1434 | &test_csd[EXT_CSD_SEC_CNT], 4) == 0) |
| 1438 | break; | 1435 | break; |
| 1439 | else | 1436 | else |
| 1440 | err = SWITCH_ERR; | 1437 | err = SWITCH_ERR; |
| 1441 | } | 1438 | } |
| 1442 | 1439 | ||
| 1443 | if (err) | 1440 | if (err) |
| 1444 | return err; | 1441 | return err; |
| 1445 | 1442 | ||
| 1446 | if (mmc->card_caps & MMC_MODE_HS) { | 1443 | if (mmc->card_caps & MMC_MODE_HS) { |
| 1447 | if (mmc->card_caps & MMC_MODE_HS_52MHz) | 1444 | if (mmc->card_caps & MMC_MODE_HS_52MHz) |
| 1448 | mmc->tran_speed = 52000000; | 1445 | mmc->tran_speed = 52000000; |
| 1449 | else | 1446 | else |
| 1450 | mmc->tran_speed = 26000000; | 1447 | mmc->tran_speed = 26000000; |
| 1451 | } | 1448 | } |
| 1452 | } | 1449 | } |
| 1453 | 1450 | ||
| 1454 | mmc_set_clock(mmc, mmc->tran_speed); | 1451 | mmc_set_clock(mmc, mmc->tran_speed); |
| 1455 | 1452 | ||
| 1456 | /* Fix the block length for DDR mode */ | 1453 | /* Fix the block length for DDR mode */ |
| 1457 | if (mmc->ddr_mode) { | 1454 | if (mmc->ddr_mode) { |
| 1458 | mmc->read_bl_len = MMC_MAX_BLOCK_LEN; | 1455 | mmc->read_bl_len = MMC_MAX_BLOCK_LEN; |
| 1459 | mmc->write_bl_len = MMC_MAX_BLOCK_LEN; | 1456 | mmc->write_bl_len = MMC_MAX_BLOCK_LEN; |
| 1460 | } | 1457 | } |
| 1461 | 1458 | ||
| 1462 | /* fill in device description */ | 1459 | /* fill in device description */ |
| 1463 | mmc->block_dev.lun = 0; | 1460 | mmc->block_dev.lun = 0; |
| 1464 | mmc->block_dev.type = 0; | 1461 | mmc->block_dev.type = 0; |
| 1465 | mmc->block_dev.blksz = mmc->read_bl_len; | 1462 | mmc->block_dev.blksz = mmc->read_bl_len; |
| 1466 | mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); | 1463 | mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); |
| 1467 | mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); | 1464 | mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); |
| 1468 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 1465 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 1469 | sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", | 1466 | sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", |
| 1470 | mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), | 1467 | mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), |
| 1471 | (mmc->cid[3] >> 16) & 0xffff); | 1468 | (mmc->cid[3] >> 16) & 0xffff); |
| 1472 | sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, | 1469 | sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, |
| 1473 | (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, | 1470 | (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, |
| 1474 | (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, | 1471 | (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, |
| 1475 | (mmc->cid[2] >> 24) & 0xff); | 1472 | (mmc->cid[2] >> 24) & 0xff); |
| 1476 | sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, | 1473 | sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, |
| 1477 | (mmc->cid[2] >> 16) & 0xf); | 1474 | (mmc->cid[2] >> 16) & 0xf); |
| 1478 | #else | 1475 | #else |
| 1479 | mmc->block_dev.vendor[0] = 0; | 1476 | mmc->block_dev.vendor[0] = 0; |
| 1480 | mmc->block_dev.product[0] = 0; | 1477 | mmc->block_dev.product[0] = 0; |
| 1481 | mmc->block_dev.revision[0] = 0; | 1478 | mmc->block_dev.revision[0] = 0; |
| 1482 | #endif | 1479 | #endif |
| 1483 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) | 1480 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) |
| 1484 | init_part(&mmc->block_dev); | 1481 | init_part(&mmc->block_dev); |
| 1485 | #endif | 1482 | #endif |
| 1486 | 1483 | ||
| 1487 | return 0; | 1484 | return 0; |
| 1488 | } | 1485 | } |
| 1489 | 1486 | ||
| 1490 | static int mmc_send_if_cond(struct mmc *mmc) | 1487 | static int mmc_send_if_cond(struct mmc *mmc) |
| 1491 | { | 1488 | { |
| 1492 | struct mmc_cmd cmd; | 1489 | struct mmc_cmd cmd; |
| 1493 | int err; | 1490 | int err; |
| 1494 | 1491 | ||
| 1495 | cmd.cmdidx = SD_CMD_SEND_IF_COND; | 1492 | cmd.cmdidx = SD_CMD_SEND_IF_COND; |
| 1496 | /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ | 1493 | /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ |
| 1497 | cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; | 1494 | cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; |
| 1498 | cmd.resp_type = MMC_RSP_R7; | 1495 | cmd.resp_type = MMC_RSP_R7; |
| 1499 | 1496 | ||
| 1500 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1497 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1501 | 1498 | ||
| 1502 | if (err) | 1499 | if (err) |
| 1503 | return err; | 1500 | return err; |
| 1504 | 1501 | ||
| 1505 | if ((cmd.response[0] & 0xff) != 0xaa) | 1502 | if ((cmd.response[0] & 0xff) != 0xaa) |
| 1506 | return UNUSABLE_ERR; | 1503 | return UNUSABLE_ERR; |
| 1507 | else | 1504 | else |
| 1508 | mmc->version = SD_VERSION_2; | 1505 | mmc->version = SD_VERSION_2; |
| 1509 | 1506 | ||
| 1510 | return 0; | 1507 | return 0; |
| 1511 | } | 1508 | } |
| 1512 | 1509 | ||
| 1513 | /* not used any more */ | 1510 | /* not used any more */ |
| 1514 | int __deprecated mmc_register(struct mmc *mmc) | 1511 | int __deprecated mmc_register(struct mmc *mmc) |
| 1515 | { | 1512 | { |
| 1516 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 1513 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 1517 | printf("%s is deprecated! use mmc_create() instead.\n", __func__); | 1514 | printf("%s is deprecated! use mmc_create() instead.\n", __func__); |
| 1518 | #endif | 1515 | #endif |
| 1519 | return -1; | 1516 | return -1; |
| 1520 | } | 1517 | } |
| 1521 | 1518 | ||
| 1522 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) | 1519 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) |
| 1523 | { | 1520 | { |
| 1524 | struct mmc *mmc; | 1521 | struct mmc *mmc; |
| 1525 | 1522 | ||
| 1526 | /* quick validation */ | 1523 | /* quick validation */ |
| 1527 | if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || | 1524 | if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || |
| 1528 | cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) | 1525 | cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) |
| 1529 | return NULL; | 1526 | return NULL; |
| 1530 | 1527 | ||
| 1531 | mmc = calloc(1, sizeof(*mmc)); | 1528 | mmc = calloc(1, sizeof(*mmc)); |
| 1532 | if (mmc == NULL) | 1529 | if (mmc == NULL) |
| 1533 | return NULL; | 1530 | return NULL; |
| 1534 | 1531 | ||
| 1535 | mmc->cfg = cfg; | 1532 | mmc->cfg = cfg; |
| 1536 | mmc->priv = priv; | 1533 | mmc->priv = priv; |
| 1537 | 1534 | ||
| 1538 | /* the following chunk was mmc_register() */ | 1535 | /* the following chunk was mmc_register() */ |
| 1539 | 1536 | ||
| 1540 | /* Setup dsr related values */ | 1537 | /* Setup dsr related values */ |
| 1541 | mmc->dsr_imp = 0; | 1538 | mmc->dsr_imp = 0; |
| 1542 | mmc->dsr = 0xffffffff; | 1539 | mmc->dsr = 0xffffffff; |
| 1543 | /* Setup the universal parts of the block interface just once */ | 1540 | /* Setup the universal parts of the block interface just once */ |
| 1544 | mmc->block_dev.if_type = IF_TYPE_MMC; | 1541 | mmc->block_dev.if_type = IF_TYPE_MMC; |
| 1545 | mmc->block_dev.dev = cur_dev_num++; | 1542 | mmc->block_dev.dev = cur_dev_num++; |
| 1546 | mmc->block_dev.removable = 1; | 1543 | mmc->block_dev.removable = 1; |
| 1547 | mmc->block_dev.block_read = mmc_bread; | 1544 | mmc->block_dev.block_read = mmc_bread; |
| 1548 | mmc->block_dev.block_write = mmc_bwrite; | 1545 | mmc->block_dev.block_write = mmc_bwrite; |
| 1549 | mmc->block_dev.block_erase = mmc_berase; | 1546 | mmc->block_dev.block_erase = mmc_berase; |
| 1550 | 1547 | ||
| 1551 | /* setup initial part type */ | 1548 | /* setup initial part type */ |
| 1552 | mmc->block_dev.part_type = mmc->cfg->part_type; | 1549 | mmc->block_dev.part_type = mmc->cfg->part_type; |
| 1553 | 1550 | ||
| 1554 | INIT_LIST_HEAD(&mmc->link); | 1551 | INIT_LIST_HEAD(&mmc->link); |
| 1555 | 1552 | ||
| 1556 | list_add_tail(&mmc->link, &mmc_devices); | 1553 | list_add_tail(&mmc->link, &mmc_devices); |
| 1557 | 1554 | ||
| 1558 | return mmc; | 1555 | return mmc; |
| 1559 | } | 1556 | } |
| 1560 | 1557 | ||
| 1561 | void mmc_destroy(struct mmc *mmc) | 1558 | void mmc_destroy(struct mmc *mmc) |
| 1562 | { | 1559 | { |
| 1563 | /* only freeing memory for now */ | 1560 | /* only freeing memory for now */ |
| 1564 | free(mmc); | 1561 | free(mmc); |
| 1565 | } | 1562 | } |
| 1566 | 1563 | ||
| 1567 | #ifdef CONFIG_PARTITIONS | 1564 | #ifdef CONFIG_PARTITIONS |
| 1568 | block_dev_desc_t *mmc_get_dev(int dev) | 1565 | block_dev_desc_t *mmc_get_dev(int dev) |
| 1569 | { | 1566 | { |
| 1570 | struct mmc *mmc = find_mmc_device(dev); | 1567 | struct mmc *mmc = find_mmc_device(dev); |
| 1571 | if (!mmc || mmc_init(mmc)) | 1568 | if (!mmc || mmc_init(mmc)) |
| 1572 | return NULL; | 1569 | return NULL; |
| 1573 | 1570 | ||
| 1574 | return &mmc->block_dev; | 1571 | return &mmc->block_dev; |
| 1575 | } | 1572 | } |
| 1576 | #endif | 1573 | #endif |
| 1577 | 1574 | ||
| 1578 | /* board-specific MMC power initializations. */ | 1575 | /* board-specific MMC power initializations. */ |
| 1579 | __weak void board_mmc_power_init(void) | 1576 | __weak void board_mmc_power_init(void) |
| 1580 | { | 1577 | { |
| 1581 | } | 1578 | } |
| 1582 | 1579 | ||
| 1583 | int mmc_start_init(struct mmc *mmc) | 1580 | int mmc_start_init(struct mmc *mmc) |
| 1584 | { | 1581 | { |
| 1585 | int err; | 1582 | int err; |
| 1586 | 1583 | ||
| 1587 | /* we pretend there's no card when init is NULL */ | 1584 | /* we pretend there's no card when init is NULL */ |
| 1588 | if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { | 1585 | if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { |
| 1589 | mmc->has_init = 0; | 1586 | mmc->has_init = 0; |
| 1590 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 1587 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 1591 | printf("MMC: no card present\n"); | 1588 | printf("MMC: no card present\n"); |
| 1592 | #endif | 1589 | #endif |
| 1593 | return NO_CARD_ERR; | 1590 | return NO_CARD_ERR; |
| 1594 | } | 1591 | } |
| 1595 | 1592 | ||
| 1596 | if (mmc->has_init) | 1593 | if (mmc->has_init) |
| 1597 | return 0; | 1594 | return 0; |
| 1598 | 1595 | ||
| 1599 | board_mmc_power_init(); | 1596 | board_mmc_power_init(); |
| 1600 | 1597 | ||
| 1601 | /* made sure it's not NULL earlier */ | 1598 | /* made sure it's not NULL earlier */ |
| 1602 | err = mmc->cfg->ops->init(mmc); | 1599 | err = mmc->cfg->ops->init(mmc); |
| 1603 | 1600 | ||
| 1604 | if (err) | 1601 | if (err) |
| 1605 | return err; | 1602 | return err; |
| 1606 | 1603 | ||
| 1607 | mmc->ddr_mode = 0; | 1604 | mmc->ddr_mode = 0; |
| 1608 | mmc_set_bus_width(mmc, 1); | 1605 | mmc_set_bus_width(mmc, 1); |
| 1609 | mmc_set_clock(mmc, 1); | 1606 | mmc_set_clock(mmc, 1); |
| 1610 | 1607 | ||
| 1611 | /* Reset the Card */ | 1608 | /* Reset the Card */ |
| 1612 | err = mmc_go_idle(mmc); | 1609 | err = mmc_go_idle(mmc); |
| 1613 | 1610 | ||
| 1614 | if (err) | 1611 | if (err) |
| 1615 | return err; | 1612 | return err; |
| 1616 | 1613 | ||
| 1617 | /* The internal partition reset to user partition(0) at every CMD0*/ | 1614 | /* The internal partition reset to user partition(0) at every CMD0*/ |
| 1618 | mmc->part_num = 0; | 1615 | mmc->part_num = 0; |
| 1619 | 1616 | ||
| 1620 | /* Test for SD version 2 */ | 1617 | /* Test for SD version 2 */ |
| 1621 | err = mmc_send_if_cond(mmc); | 1618 | err = mmc_send_if_cond(mmc); |
| 1622 | 1619 | ||
| 1623 | /* Now try to get the SD card's operating condition */ | 1620 | /* Now try to get the SD card's operating condition */ |
| 1624 | err = sd_send_op_cond(mmc); | 1621 | err = sd_send_op_cond(mmc); |
| 1625 | 1622 | ||
| 1626 | /* If the command timed out, we check for an MMC card */ | 1623 | /* If the command timed out, we check for an MMC card */ |
| 1627 | if (err == TIMEOUT) { | 1624 | if (err == TIMEOUT) { |
| 1628 | err = mmc_send_op_cond(mmc); | 1625 | err = mmc_send_op_cond(mmc); |
| 1629 | 1626 | ||
| 1630 | if (err) { | 1627 | if (err) { |
| 1631 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 1628 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 1632 | printf("Card did not respond to voltage select!\n"); | 1629 | printf("Card did not respond to voltage select!\n"); |
| 1633 | #endif | 1630 | #endif |
| 1634 | return UNUSABLE_ERR; | 1631 | return UNUSABLE_ERR; |
| 1635 | } | 1632 | } |
| 1636 | } | 1633 | } |
| 1637 | 1634 | ||
| 1638 | if (!err) | 1635 | if (!err) |
| 1639 | mmc->init_in_progress = 1; | 1636 | mmc->init_in_progress = 1; |
| 1640 | 1637 | ||
| 1641 | return err; | 1638 | return err; |
| 1642 | } | 1639 | } |
| 1643 | 1640 | ||
| 1644 | static int mmc_complete_init(struct mmc *mmc) | 1641 | static int mmc_complete_init(struct mmc *mmc) |
| 1645 | { | 1642 | { |
| 1646 | int err = 0; | 1643 | int err = 0; |
| 1647 | 1644 | ||
| 1648 | mmc->init_in_progress = 0; | 1645 | mmc->init_in_progress = 0; |
| 1649 | if (mmc->op_cond_pending) | 1646 | if (mmc->op_cond_pending) |
| 1650 | err = mmc_complete_op_cond(mmc); | 1647 | err = mmc_complete_op_cond(mmc); |
| 1651 | 1648 | ||
| 1652 | if (!err) | 1649 | if (!err) |
| 1653 | err = mmc_startup(mmc); | 1650 | err = mmc_startup(mmc); |
| 1654 | if (err) | 1651 | if (err) |
| 1655 | mmc->has_init = 0; | 1652 | mmc->has_init = 0; |
| 1656 | else | 1653 | else |
| 1657 | mmc->has_init = 1; | 1654 | mmc->has_init = 1; |
| 1658 | return err; | 1655 | return err; |
| 1659 | } | 1656 | } |
| 1660 | 1657 | ||
| 1661 | int mmc_init(struct mmc *mmc) | 1658 | int mmc_init(struct mmc *mmc) |
| 1662 | { | 1659 | { |
| 1663 | int err = 0; | 1660 | int err = 0; |
| 1664 | unsigned start; | 1661 | unsigned start; |
| 1665 | 1662 | ||
| 1666 | if (mmc->has_init) | 1663 | if (mmc->has_init) |
| 1667 | return 0; | 1664 | return 0; |
| 1668 | 1665 | ||
| 1669 | start = get_timer(0); | 1666 | start = get_timer(0); |
| 1670 | 1667 | ||
| 1671 | if (!mmc->init_in_progress) | 1668 | if (!mmc->init_in_progress) |
| 1672 | err = mmc_start_init(mmc); | 1669 | err = mmc_start_init(mmc); |
| 1673 | 1670 | ||
| 1674 | if (!err) | 1671 | if (!err) |
| 1675 | err = mmc_complete_init(mmc); | 1672 | err = mmc_complete_init(mmc); |
| 1676 | debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); | 1673 | debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); |
| 1677 | return err; | 1674 | return err; |
| 1678 | } | 1675 | } |
| 1679 | 1676 | ||
| 1680 | int mmc_set_dsr(struct mmc *mmc, u16 val) | 1677 | int mmc_set_dsr(struct mmc *mmc, u16 val) |
| 1681 | { | 1678 | { |
| 1682 | mmc->dsr = val; | 1679 | mmc->dsr = val; |
| 1683 | return 0; | 1680 | return 0; |
| 1684 | } | 1681 | } |
| 1685 | 1682 | ||
| 1686 | /* CPU-specific MMC initializations */ | 1683 | /* CPU-specific MMC initializations */ |
| 1687 | __weak int cpu_mmc_init(bd_t *bis) | 1684 | __weak int cpu_mmc_init(bd_t *bis) |
| 1688 | { | 1685 | { |
| 1689 | return -1; | 1686 | return -1; |
| 1690 | } | 1687 | } |
| 1691 | 1688 | ||
| 1692 | /* board-specific MMC initializations. */ | 1689 | /* board-specific MMC initializations. */ |
| 1693 | __weak int board_mmc_init(bd_t *bis) | 1690 | __weak int board_mmc_init(bd_t *bis) |
| 1694 | { | 1691 | { |
| 1695 | return -1; | 1692 | return -1; |
| 1696 | } | 1693 | } |
| 1697 | 1694 | ||
| 1698 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | 1695 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) |
| 1699 | 1696 | ||
| 1700 | void print_mmc_devices(char separator) | 1697 | void print_mmc_devices(char separator) |
| 1701 | { | 1698 | { |
| 1702 | struct mmc *m; | 1699 | struct mmc *m; |
| 1703 | struct list_head *entry; | 1700 | struct list_head *entry; |
| 1704 | char *mmc_type; | 1701 | char *mmc_type; |
| 1705 | 1702 | ||
| 1706 | list_for_each(entry, &mmc_devices) { | 1703 | list_for_each(entry, &mmc_devices) { |
| 1707 | m = list_entry(entry, struct mmc, link); | 1704 | m = list_entry(entry, struct mmc, link); |
| 1708 | 1705 | ||
| 1709 | if (m->has_init) | 1706 | if (m->has_init) |
| 1710 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | 1707 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; |
| 1711 | else | 1708 | else |
| 1712 | mmc_type = NULL; | 1709 | mmc_type = NULL; |
| 1713 | 1710 | ||
| 1714 | printf("%s: %d", m->cfg->name, m->block_dev.dev); | 1711 | printf("%s: %d", m->cfg->name, m->block_dev.dev); |
| 1715 | if (mmc_type) | 1712 | if (mmc_type) |
| 1716 | printf(" (%s)", mmc_type); | 1713 | printf(" (%s)", mmc_type); |
| 1717 | 1714 | ||
| 1718 | if (entry->next != &mmc_devices) { | 1715 | if (entry->next != &mmc_devices) { |
| 1719 | printf("%c", separator); | 1716 | printf("%c", separator); |
| 1720 | if (separator != '\n') | 1717 | if (separator != '\n') |
| 1721 | puts (" "); | 1718 | puts (" "); |
| 1722 | } | 1719 | } |
| 1723 | } | 1720 | } |
| 1724 | 1721 | ||
| 1725 | printf("\n"); | 1722 | printf("\n"); |
| 1726 | } | 1723 | } |
| 1727 | 1724 | ||
| 1728 | #else | 1725 | #else |
| 1729 | void print_mmc_devices(char separator) { } | 1726 | void print_mmc_devices(char separator) { } |
| 1730 | #endif | 1727 | #endif |
| 1731 | 1728 | ||
| 1732 | int get_mmc_num(void) | 1729 | int get_mmc_num(void) |
| 1733 | { | 1730 | { |
| 1734 | return cur_dev_num; | 1731 | return cur_dev_num; |
| 1735 | } | 1732 | } |
| 1736 | 1733 | ||
| 1737 | void mmc_set_preinit(struct mmc *mmc, int preinit) | 1734 | void mmc_set_preinit(struct mmc *mmc, int preinit) |
| 1738 | { | 1735 | { |
| 1739 | mmc->preinit = preinit; | 1736 | mmc->preinit = preinit; |
| 1740 | } | 1737 | } |
| 1741 | 1738 | ||
| 1742 | static void do_preinit(void) | 1739 | static void do_preinit(void) |
| 1743 | { | 1740 | { |
| 1744 | struct mmc *m; | 1741 | struct mmc *m; |
| 1745 | struct list_head *entry; | 1742 | struct list_head *entry; |
| 1746 | 1743 | ||
| 1747 | list_for_each(entry, &mmc_devices) { | 1744 | list_for_each(entry, &mmc_devices) { |
| 1748 | m = list_entry(entry, struct mmc, link); | 1745 | m = list_entry(entry, struct mmc, link); |
| 1749 | 1746 | ||
| 1750 | if (m->preinit) | 1747 | if (m->preinit) |
| 1751 | mmc_start_init(m); | 1748 | mmc_start_init(m); |
| 1752 | } | 1749 | } |
| 1753 | } | 1750 | } |
| 1754 | 1751 | ||
| 1755 | 1752 | ||
| 1756 | int mmc_initialize(bd_t *bis) | 1753 | int mmc_initialize(bd_t *bis) |
| 1757 | { | 1754 | { |
| 1758 | INIT_LIST_HEAD (&mmc_devices); | 1755 | INIT_LIST_HEAD (&mmc_devices); |
| 1759 | cur_dev_num = 0; | 1756 | cur_dev_num = 0; |
| 1760 | 1757 | ||
| 1761 | if (board_mmc_init(bis) < 0) | 1758 | if (board_mmc_init(bis) < 0) |
| 1762 | cpu_mmc_init(bis); | 1759 | cpu_mmc_init(bis); |
| 1763 | 1760 | ||
| 1764 | #ifndef CONFIG_SPL_BUILD | 1761 | #ifndef CONFIG_SPL_BUILD |
| 1765 | print_mmc_devices(','); | 1762 | print_mmc_devices(','); |
| 1766 | #endif | 1763 | #endif |
| 1767 | 1764 | ||
| 1768 | do_preinit(); | 1765 | do_preinit(); |
| 1769 | return 0; | 1766 | return 0; |
| 1770 | } | 1767 | } |
| 1771 | 1768 | ||
| 1772 | #ifdef CONFIG_SUPPORT_EMMC_BOOT | 1769 | #ifdef CONFIG_SUPPORT_EMMC_BOOT |
| 1773 | /* | 1770 | /* |
| 1774 | * This function changes the size of boot partition and the size of rpmb | 1771 | * This function changes the size of boot partition and the size of rpmb |
| 1775 | * partition present on EMMC devices. | 1772 | * partition present on EMMC devices. |
| 1776 | * | 1773 | * |
| 1777 | * Input Parameters: | 1774 | * Input Parameters: |
| 1778 | * struct *mmc: pointer for the mmc device strcuture | 1775 | * struct *mmc: pointer for the mmc device strcuture |
| 1779 | * bootsize: size of boot partition | 1776 | * bootsize: size of boot partition |
| 1780 | * rpmbsize: size of rpmb partition | 1777 | * rpmbsize: size of rpmb partition |
| 1781 | * | 1778 | * |
| 1782 | * Returns 0 on success. | 1779 | * Returns 0 on success. |
| 1783 | */ | 1780 | */ |
| 1784 | 1781 | ||
| 1785 | int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, | 1782 | int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, |
| 1786 | unsigned long rpmbsize) | 1783 | unsigned long rpmbsize) |
| 1787 | { | 1784 | { |
| 1788 | int err; | 1785 | int err; |
| 1789 | struct mmc_cmd cmd; | 1786 | struct mmc_cmd cmd; |
| 1790 | 1787 | ||
| 1791 | /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ | 1788 | /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ |
| 1792 | cmd.cmdidx = MMC_CMD_RES_MAN; | 1789 | cmd.cmdidx = MMC_CMD_RES_MAN; |
| 1793 | cmd.resp_type = MMC_RSP_R1b; | 1790 | cmd.resp_type = MMC_RSP_R1b; |
| 1794 | cmd.cmdarg = MMC_CMD62_ARG1; | 1791 | cmd.cmdarg = MMC_CMD62_ARG1; |
| 1795 | 1792 | ||
| 1796 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1793 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1797 | if (err) { | 1794 | if (err) { |
| 1798 | debug("mmc_boot_partition_size_change: Error1 = %d\n", err); | 1795 | debug("mmc_boot_partition_size_change: Error1 = %d\n", err); |
| 1799 | return err; | 1796 | return err; |
| 1800 | } | 1797 | } |
| 1801 | 1798 | ||
| 1802 | /* Boot partition changing mode */ | 1799 | /* Boot partition changing mode */ |
| 1803 | cmd.cmdidx = MMC_CMD_RES_MAN; | 1800 | cmd.cmdidx = MMC_CMD_RES_MAN; |
| 1804 | cmd.resp_type = MMC_RSP_R1b; | 1801 | cmd.resp_type = MMC_RSP_R1b; |
| 1805 | cmd.cmdarg = MMC_CMD62_ARG2; | 1802 | cmd.cmdarg = MMC_CMD62_ARG2; |
| 1806 | 1803 | ||
| 1807 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1804 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1808 | if (err) { | 1805 | if (err) { |
| 1809 | debug("mmc_boot_partition_size_change: Error2 = %d\n", err); | 1806 | debug("mmc_boot_partition_size_change: Error2 = %d\n", err); |
| 1810 | return err; | 1807 | return err; |
| 1811 | } | 1808 | } |
| 1812 | /* boot partition size is multiple of 128KB */ | 1809 | /* boot partition size is multiple of 128KB */ |
| 1813 | bootsize = (bootsize * 1024) / 128; | 1810 | bootsize = (bootsize * 1024) / 128; |
| 1814 | 1811 | ||
| 1815 | /* Arg: boot partition size */ | 1812 | /* Arg: boot partition size */ |
| 1816 | cmd.cmdidx = MMC_CMD_RES_MAN; | 1813 | cmd.cmdidx = MMC_CMD_RES_MAN; |
| 1817 | cmd.resp_type = MMC_RSP_R1b; | 1814 | cmd.resp_type = MMC_RSP_R1b; |
| 1818 | cmd.cmdarg = bootsize; | 1815 | cmd.cmdarg = bootsize; |
| 1819 | 1816 | ||
| 1820 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1817 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1821 | if (err) { | 1818 | if (err) { |
| 1822 | debug("mmc_boot_partition_size_change: Error3 = %d\n", err); | 1819 | debug("mmc_boot_partition_size_change: Error3 = %d\n", err); |
| 1823 | return err; | 1820 | return err; |
| 1824 | } | 1821 | } |
| 1825 | /* RPMB partition size is multiple of 128KB */ | 1822 | /* RPMB partition size is multiple of 128KB */ |
| 1826 | rpmbsize = (rpmbsize * 1024) / 128; | 1823 | rpmbsize = (rpmbsize * 1024) / 128; |
| 1827 | /* Arg: RPMB partition size */ | 1824 | /* Arg: RPMB partition size */ |
| 1828 | cmd.cmdidx = MMC_CMD_RES_MAN; | 1825 | cmd.cmdidx = MMC_CMD_RES_MAN; |
| 1829 | cmd.resp_type = MMC_RSP_R1b; | 1826 | cmd.resp_type = MMC_RSP_R1b; |
| 1830 | cmd.cmdarg = rpmbsize; | 1827 | cmd.cmdarg = rpmbsize; |
| 1831 | 1828 | ||
| 1832 | err = mmc_send_cmd(mmc, &cmd, NULL); | 1829 | err = mmc_send_cmd(mmc, &cmd, NULL); |
| 1833 | if (err) { | 1830 | if (err) { |
| 1834 | debug("mmc_boot_partition_size_change: Error4 = %d\n", err); | 1831 | debug("mmc_boot_partition_size_change: Error4 = %d\n", err); |
| 1835 | return err; | 1832 | return err; |
| 1836 | } | 1833 | } |
| 1837 | return 0; | 1834 | return 0; |
| 1838 | } | 1835 | } |
| 1839 | 1836 | ||
| 1840 | /* | 1837 | /* |
| 1841 | * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH | 1838 | * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH |
| 1842 | * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH | 1839 | * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH |
| 1843 | * and BOOT_MODE. | 1840 | * and BOOT_MODE. |
| 1844 | * | 1841 | * |
| 1845 | * Returns 0 on success. | 1842 | * Returns 0 on success. |
| 1846 | */ | 1843 | */ |
| 1847 | int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) | 1844 | int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) |
| 1848 | { | 1845 | { |
| 1849 | int err; | 1846 | int err; |
| 1850 | 1847 | ||
| 1851 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, | 1848 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, |
| 1852 | EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | | 1849 | EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | |
| 1853 | EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | | 1850 | EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | |
| 1854 | EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); | 1851 | EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); |
| 1855 | 1852 | ||
| 1856 | if (err) | 1853 | if (err) |
| 1857 | return err; | 1854 | return err; |
| 1858 | return 0; | 1855 | return 0; |
| 1859 | } | 1856 | } |
| 1860 | 1857 | ||
| 1861 | /* | 1858 | /* |
| 1862 | * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) | 1859 | * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) |
| 1863 | * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and | 1860 | * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and |
| 1864 | * PARTITION_ACCESS. | 1861 | * PARTITION_ACCESS. |
| 1865 | * | 1862 | * |
| 1866 | * Returns 0 on success. | 1863 | * Returns 0 on success. |
| 1867 | */ | 1864 | */ |
| 1868 | int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) | 1865 | int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) |
| 1869 | { | 1866 | { |
| 1870 | int err; | 1867 | int err; |
| 1871 | 1868 | ||
| 1872 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, | 1869 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, |
| 1873 | EXT_CSD_BOOT_ACK(ack) | | 1870 | EXT_CSD_BOOT_ACK(ack) | |
| 1874 | EXT_CSD_BOOT_PART_NUM(part_num) | | 1871 | EXT_CSD_BOOT_PART_NUM(part_num) | |
| 1875 | EXT_CSD_PARTITION_ACCESS(access)); | 1872 | EXT_CSD_PARTITION_ACCESS(access)); |
| 1876 | 1873 | ||
| 1877 | if (err) | 1874 | if (err) |
| 1878 | return err; | 1875 | return err; |
| 1879 | return 0; | 1876 | return 0; |
| 1880 | } | 1877 | } |
| 1881 | 1878 | ||
| 1882 | /* | 1879 | /* |
| 1883 | * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value | 1880 | * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value |
| 1884 | * for enable. Note that this is a write-once field for non-zero values. | 1881 | * for enable. Note that this is a write-once field for non-zero values. |
| 1885 | * | 1882 | * |
| 1886 | * Returns 0 on success. | 1883 | * Returns 0 on success. |
| 1887 | */ | 1884 | */ |
| 1888 | int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) | 1885 | int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) |
| 1889 | { | 1886 | { |
| 1890 | return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, | 1887 | return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, |
| 1891 | enable); | 1888 | enable); |
| 1892 | } | 1889 | } |
| 1893 | #endif | 1890 | #endif |
| 1894 | 1891 |
drivers/mmc/mvebu_mmc.c
| 1 | /* | 1 | /* |
| 2 | * Marvell MMC/SD/SDIO driver | 2 | * Marvell MMC/SD/SDIO driver |
| 3 | * | 3 | * |
| 4 | * (C) Copyright 2012-2014 | 4 | * (C) Copyright 2012-2014 |
| 5 | * Marvell Semiconductor <www.marvell.com> | 5 | * Marvell Semiconductor <www.marvell.com> |
| 6 | * Written-by: Maen Suleiman, Gerald Kerma | 6 | * Written-by: Maen Suleiman, Gerald Kerma |
| 7 | * | 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <common.h> | 11 | #include <common.h> |
| 12 | #include <malloc.h> | 12 | #include <malloc.h> |
| 13 | #include <part.h> | 13 | #include <part.h> |
| 14 | #include <mmc.h> | 14 | #include <mmc.h> |
| 15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
| 16 | #include <asm/arch/cpu.h> | 16 | #include <asm/arch/cpu.h> |
| 17 | #include <asm/arch/soc.h> | 17 | #include <asm/arch/soc.h> |
| 18 | #include <mvebu_mmc.h> | 18 | #include <mvebu_mmc.h> |
| 19 | 19 | ||
| 20 | DECLARE_GLOBAL_DATA_PTR; | 20 | DECLARE_GLOBAL_DATA_PTR; |
| 21 | 21 | ||
| 22 | #define DRIVER_NAME "MVEBU_MMC" | 22 | #define DRIVER_NAME "MVEBU_MMC" |
| 23 | 23 | ||
| 24 | #define MVEBU_TARGET_DRAM 0 | 24 | #define MVEBU_TARGET_DRAM 0 |
| 25 | 25 | ||
| 26 | #define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */ | 26 | #define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */ |
| 27 | 27 | ||
| 28 | static void mvebu_mmc_write(u32 offs, u32 val) | 28 | static void mvebu_mmc_write(u32 offs, u32 val) |
| 29 | { | 29 | { |
| 30 | writel(val, CONFIG_SYS_MMC_BASE + (offs)); | 30 | writel(val, CONFIG_SYS_MMC_BASE + (offs)); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static u32 mvebu_mmc_read(u32 offs) | 33 | static u32 mvebu_mmc_read(u32 offs) |
| 34 | { | 34 | { |
| 35 | return readl(CONFIG_SYS_MMC_BASE + (offs)); | 35 | return readl(CONFIG_SYS_MMC_BASE + (offs)); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | static int mvebu_mmc_setup_data(struct mmc_data *data) | 38 | static int mvebu_mmc_setup_data(struct mmc_data *data) |
| 39 | { | 39 | { |
| 40 | u32 ctrl_reg; | 40 | u32 ctrl_reg; |
| 41 | 41 | ||
| 42 | debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME, | 42 | debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME, |
| 43 | (data->flags & MMC_DATA_READ) ? "read" : "write", | 43 | (data->flags & MMC_DATA_READ) ? "read" : "write", |
| 44 | data->blocks, data->blocksize); | 44 | data->blocks, data->blocksize); |
| 45 | 45 | ||
| 46 | /* default to maximum timeout */ | 46 | /* default to maximum timeout */ |
| 47 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); | 47 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); |
| 48 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); | 48 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); |
| 49 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); | 49 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); |
| 50 | 50 | ||
| 51 | if (data->flags & MMC_DATA_READ) { | 51 | if (data->flags & MMC_DATA_READ) { |
| 52 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff); | 52 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff); |
| 53 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16); | 53 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16); |
| 54 | } else { | 54 | } else { |
| 55 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff); | 55 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff); |
| 56 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16); | 56 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks); | 59 | mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks); |
| 60 | mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize); | 60 | mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize); |
| 61 | 61 | ||
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | 65 | static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
| 66 | struct mmc_data *data) | 66 | struct mmc_data *data) |
| 67 | { | 67 | { |
| 68 | ulong start; | 68 | ulong start; |
| 69 | ushort waittype = 0; | 69 | ushort waittype = 0; |
| 70 | ushort resptype = 0; | 70 | ushort resptype = 0; |
| 71 | ushort xfertype = 0; | 71 | ushort xfertype = 0; |
| 72 | ushort resp_indx = 0; | 72 | ushort resp_indx = 0; |
| 73 | 73 | ||
| 74 | debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", | 74 | debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", |
| 75 | DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg); | 75 | DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg); |
| 76 | 76 | ||
| 77 | debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, | 77 | debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, |
| 78 | cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); | 78 | cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); |
| 79 | 79 | ||
| 80 | /* | 80 | /* |
| 81 | * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE | 81 | * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE |
| 82 | * register is sometimes not set before a while when some | 82 | * register is sometimes not set before a while when some |
| 83 | * "unusual" data block sizes are used (such as with the SWITCH | 83 | * "unusual" data block sizes are used (such as with the SWITCH |
| 84 | * command), even despite the fact that the XFER_DONE interrupt | 84 | * command), even despite the fact that the XFER_DONE interrupt |
| 85 | * was raised. And if another data transfer starts before | 85 | * was raised. And if another data transfer starts before |
| 86 | * this bit comes to good sense (which eventually happens by | 86 | * this bit comes to good sense (which eventually happens by |
| 87 | * itself) then the new transfer simply fails with a timeout. | 87 | * itself) then the new transfer simply fails with a timeout. |
| 88 | */ | 88 | */ |
| 89 | if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { | 89 | if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { |
| 90 | ushort hw_state, count = 0; | 90 | ushort hw_state, count = 0; |
| 91 | 91 | ||
| 92 | start = get_timer(0); | 92 | start = get_timer(0); |
| 93 | do { | 93 | do { |
| 94 | hw_state = mvebu_mmc_read(SDIO_HW_STATE); | 94 | hw_state = mvebu_mmc_read(SDIO_HW_STATE); |
| 95 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { | 95 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { |
| 96 | printf("%s : FIFO_EMPTY bit missing\n", | 96 | printf("%s : FIFO_EMPTY bit missing\n", |
| 97 | DRIVER_NAME); | 97 | DRIVER_NAME); |
| 98 | break; | 98 | break; |
| 99 | } | 99 | } |
| 100 | count++; | 100 | count++; |
| 101 | } while (!(hw_state & CMD_FIFO_EMPTY)); | 101 | } while (!(hw_state & CMD_FIFO_EMPTY)); |
| 102 | debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", | 102 | debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", |
| 103 | DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); | 103 | DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | /* Clear status */ | 106 | /* Clear status */ |
| 107 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); | 107 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); |
| 108 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); | 108 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); |
| 109 | 109 | ||
| 110 | resptype = SDIO_CMD_INDEX(cmd->cmdidx); | 110 | resptype = SDIO_CMD_INDEX(cmd->cmdidx); |
| 111 | 111 | ||
| 112 | /* Analyzing resptype/xfertype/waittype for the command */ | 112 | /* Analyzing resptype/xfertype/waittype for the command */ |
| 113 | if (cmd->resp_type & MMC_RSP_BUSY) | 113 | if (cmd->resp_type & MMC_RSP_BUSY) |
| 114 | resptype |= SDIO_CMD_RSP_48BUSY; | 114 | resptype |= SDIO_CMD_RSP_48BUSY; |
| 115 | else if (cmd->resp_type & MMC_RSP_136) | 115 | else if (cmd->resp_type & MMC_RSP_136) |
| 116 | resptype |= SDIO_CMD_RSP_136; | 116 | resptype |= SDIO_CMD_RSP_136; |
| 117 | else if (cmd->resp_type & MMC_RSP_PRESENT) | 117 | else if (cmd->resp_type & MMC_RSP_PRESENT) |
| 118 | resptype |= SDIO_CMD_RSP_48; | 118 | resptype |= SDIO_CMD_RSP_48; |
| 119 | else | 119 | else |
| 120 | resptype |= SDIO_CMD_RSP_NONE; | 120 | resptype |= SDIO_CMD_RSP_NONE; |
| 121 | 121 | ||
| 122 | if (cmd->resp_type & MMC_RSP_CRC) | 122 | if (cmd->resp_type & MMC_RSP_CRC) |
| 123 | resptype |= SDIO_CMD_CHECK_CMDCRC; | 123 | resptype |= SDIO_CMD_CHECK_CMDCRC; |
| 124 | 124 | ||
| 125 | if (cmd->resp_type & MMC_RSP_OPCODE) | 125 | if (cmd->resp_type & MMC_RSP_OPCODE) |
| 126 | resptype |= SDIO_CMD_INDX_CHECK; | 126 | resptype |= SDIO_CMD_INDX_CHECK; |
| 127 | 127 | ||
| 128 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 128 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 129 | resptype |= SDIO_UNEXPECTED_RESP; | 129 | resptype |= SDIO_UNEXPECTED_RESP; |
| 130 | waittype |= SDIO_NOR_UNEXP_RSP; | 130 | waittype |= SDIO_NOR_UNEXP_RSP; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | if (data) { | 133 | if (data) { |
| 134 | int err = mvebu_mmc_setup_data(data); | 134 | int err = mvebu_mmc_setup_data(data); |
| 135 | 135 | ||
| 136 | if (err) { | 136 | if (err) { |
| 137 | debug("%s: command DATA error :%x\n", | 137 | debug("%s: command DATA error :%x\n", |
| 138 | DRIVER_NAME, err); | 138 | DRIVER_NAME, err); |
| 139 | return err; | 139 | return err; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16; | 142 | resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16; |
| 143 | xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN; | 143 | xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN; |
| 144 | if (data->flags & MMC_DATA_READ) { | 144 | if (data->flags & MMC_DATA_READ) { |
| 145 | xfertype |= SDIO_XFER_MODE_TO_HOST; | 145 | xfertype |= SDIO_XFER_MODE_TO_HOST; |
| 146 | waittype = SDIO_NOR_DMA_INI; | 146 | waittype = SDIO_NOR_DMA_INI; |
| 147 | } else { | 147 | } else { |
| 148 | waittype |= SDIO_NOR_XFER_DONE; | 148 | waittype |= SDIO_NOR_XFER_DONE; |
| 149 | } | 149 | } |
| 150 | } else { | 150 | } else { |
| 151 | waittype |= SDIO_NOR_CMD_DONE; | 151 | waittype |= SDIO_NOR_CMD_DONE; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | /* Setting cmd arguments */ | 154 | /* Setting cmd arguments */ |
| 155 | mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff); | 155 | mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff); |
| 156 | mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16); | 156 | mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16); |
| 157 | 157 | ||
| 158 | /* Setting Xfer mode */ | 158 | /* Setting Xfer mode */ |
| 159 | mvebu_mmc_write(SDIO_XFER_MODE, xfertype); | 159 | mvebu_mmc_write(SDIO_XFER_MODE, xfertype); |
| 160 | 160 | ||
| 161 | /* Sending command */ | 161 | /* Sending command */ |
| 162 | mvebu_mmc_write(SDIO_CMD, resptype); | 162 | mvebu_mmc_write(SDIO_CMD, resptype); |
| 163 | 163 | ||
| 164 | start = get_timer(0); | 164 | start = get_timer(0); |
| 165 | 165 | ||
| 166 | while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { | 166 | while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { |
| 167 | if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { | 167 | if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { |
| 168 | debug("%s: error! cmdidx : %d, err reg: %04x\n", | 168 | debug("%s: error! cmdidx : %d, err reg: %04x\n", |
| 169 | DRIVER_NAME, cmd->cmdidx, | 169 | DRIVER_NAME, cmd->cmdidx, |
| 170 | mvebu_mmc_read(SDIO_ERR_INTR_STATUS)); | 170 | mvebu_mmc_read(SDIO_ERR_INTR_STATUS)); |
| 171 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & | 171 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & |
| 172 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) { | 172 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) { |
| 173 | debug("%s: command READ timed out\n", | 173 | debug("%s: command READ timed out\n", |
| 174 | DRIVER_NAME); | 174 | DRIVER_NAME); |
| 175 | return TIMEOUT; | 175 | return TIMEOUT; |
| 176 | } | 176 | } |
| 177 | debug("%s: command READ error\n", DRIVER_NAME); | 177 | debug("%s: command READ error\n", DRIVER_NAME); |
| 178 | return COMM_ERR; | 178 | return COMM_ERR; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { | 181 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { |
| 182 | debug("%s: command timed out\n", DRIVER_NAME); | 182 | debug("%s: command timed out\n", DRIVER_NAME); |
| 183 | return TIMEOUT; | 183 | return TIMEOUT; |
| 184 | } | 184 | } |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | /* Handling response */ | 187 | /* Handling response */ |
| 188 | if (cmd->resp_type & MMC_RSP_136) { | 188 | if (cmd->resp_type & MMC_RSP_136) { |
| 189 | uint response[8]; | 189 | uint response[8]; |
| 190 | 190 | ||
| 191 | for (resp_indx = 0; resp_indx < 8; resp_indx++) | 191 | for (resp_indx = 0; resp_indx < 8; resp_indx++) |
| 192 | response[resp_indx] | 192 | response[resp_indx] |
| 193 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); | 193 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); |
| 194 | 194 | ||
| 195 | cmd->response[0] = ((response[0] & 0x03ff) << 22) | | 195 | cmd->response[0] = ((response[0] & 0x03ff) << 22) | |
| 196 | ((response[1] & 0xffff) << 6) | | 196 | ((response[1] & 0xffff) << 6) | |
| 197 | ((response[2] & 0xfc00) >> 10); | 197 | ((response[2] & 0xfc00) >> 10); |
| 198 | cmd->response[1] = ((response[2] & 0x03ff) << 22) | | 198 | cmd->response[1] = ((response[2] & 0x03ff) << 22) | |
| 199 | ((response[3] & 0xffff) << 6) | | 199 | ((response[3] & 0xffff) << 6) | |
| 200 | ((response[4] & 0xfc00) >> 10); | 200 | ((response[4] & 0xfc00) >> 10); |
| 201 | cmd->response[2] = ((response[4] & 0x03ff) << 22) | | 201 | cmd->response[2] = ((response[4] & 0x03ff) << 22) | |
| 202 | ((response[5] & 0xffff) << 6) | | 202 | ((response[5] & 0xffff) << 6) | |
| 203 | ((response[6] & 0xfc00) >> 10); | 203 | ((response[6] & 0xfc00) >> 10); |
| 204 | cmd->response[3] = ((response[6] & 0x03ff) << 22) | | 204 | cmd->response[3] = ((response[6] & 0x03ff) << 22) | |
| 205 | ((response[7] & 0x3fff) << 8); | 205 | ((response[7] & 0x3fff) << 8); |
| 206 | } else if (cmd->resp_type & MMC_RSP_PRESENT) { | 206 | } else if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 207 | uint response[3]; | 207 | uint response[3]; |
| 208 | 208 | ||
| 209 | for (resp_indx = 0; resp_indx < 3; resp_indx++) | 209 | for (resp_indx = 0; resp_indx < 3; resp_indx++) |
| 210 | response[resp_indx] | 210 | response[resp_indx] |
| 211 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); | 211 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); |
| 212 | 212 | ||
| 213 | cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) | | 213 | cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) | |
| 214 | ((response[1] & 0xffff) << (14 - 8)) | | 214 | ((response[1] & 0xffff) << (14 - 8)) | |
| 215 | ((response[0] & 0x03ff) << (30 - 8)); | 215 | ((response[0] & 0x03ff) << (30 - 8)); |
| 216 | cmd->response[1] = ((response[0] & 0xfc00) >> 10); | 216 | cmd->response[1] = ((response[0] & 0xfc00) >> 10); |
| 217 | cmd->response[2] = 0; | 217 | cmd->response[2] = 0; |
| 218 | cmd->response[3] = 0; | 218 | cmd->response[3] = 0; |
| 219 | } else { | 219 | } else { |
| 220 | cmd->response[0] = 0; | 220 | cmd->response[0] = 0; |
| 221 | cmd->response[1] = 0; | 221 | cmd->response[1] = 0; |
| 222 | cmd->response[2] = 0; | 222 | cmd->response[2] = 0; |
| 223 | cmd->response[3] = 0; | 223 | cmd->response[3] = 0; |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type); | 226 | debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type); |
| 227 | debug("[0x%x] ", cmd->response[0]); | 227 | debug("[0x%x] ", cmd->response[0]); |
| 228 | debug("[0x%x] ", cmd->response[1]); | 228 | debug("[0x%x] ", cmd->response[1]); |
| 229 | debug("[0x%x] ", cmd->response[2]); | 229 | debug("[0x%x] ", cmd->response[2]); |
| 230 | debug("[0x%x] ", cmd->response[3]); | 230 | debug("[0x%x] ", cmd->response[3]); |
| 231 | debug("\n"); | 231 | debug("\n"); |
| 232 | 232 | ||
| 233 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & | 233 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & |
| 234 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) | 234 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) |
| 235 | return TIMEOUT; | 235 | return TIMEOUT; |
| 236 | 236 | ||
| 237 | return 0; | 237 | return 0; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static void mvebu_mmc_power_up(void) | 240 | static void mvebu_mmc_power_up(void) |
| 241 | { | 241 | { |
| 242 | debug("%s: power up\n", DRIVER_NAME); | 242 | debug("%s: power up\n", DRIVER_NAME); |
| 243 | 243 | ||
| 244 | /* disable interrupts */ | 244 | /* disable interrupts */ |
| 245 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); | 245 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); |
| 246 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); | 246 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); |
| 247 | 247 | ||
| 248 | /* SW reset */ | 248 | /* SW reset */ |
| 249 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); | 249 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); |
| 250 | 250 | ||
| 251 | mvebu_mmc_write(SDIO_XFER_MODE, 0); | 251 | mvebu_mmc_write(SDIO_XFER_MODE, 0); |
| 252 | 252 | ||
| 253 | /* enable status */ | 253 | /* enable status */ |
| 254 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); | 254 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); |
| 255 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); | 255 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); |
| 256 | 256 | ||
| 257 | /* enable interrupts status */ | 257 | /* enable interrupts status */ |
| 258 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); | 258 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); |
| 259 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); | 259 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | static void mvebu_mmc_set_clk(unsigned int clock) | 262 | static void mvebu_mmc_set_clk(unsigned int clock) |
| 263 | { | 263 | { |
| 264 | unsigned int m; | 264 | unsigned int m; |
| 265 | 265 | ||
| 266 | if (clock == 0) { | 266 | if (clock == 0) { |
| 267 | debug("%s: clock off\n", DRIVER_NAME); | 267 | debug("%s: clock off\n", DRIVER_NAME); |
| 268 | mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); | 268 | mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); |
| 269 | mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); | 269 | mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); |
| 270 | } else { | 270 | } else { |
| 271 | m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1; | 271 | m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1; |
| 272 | if (m > MVEBU_MMC_BASE_DIV_MAX) | 272 | if (m > MVEBU_MMC_BASE_DIV_MAX) |
| 273 | m = MVEBU_MMC_BASE_DIV_MAX; | 273 | m = MVEBU_MMC_BASE_DIV_MAX; |
| 274 | mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); | 274 | mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); |
| 275 | debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); | 275 | debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); |
| 276 | } | 276 | } |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | static void mvebu_mmc_set_bus(unsigned int bus) | 279 | static void mvebu_mmc_set_bus(unsigned int bus) |
| 280 | { | 280 | { |
| 281 | u32 ctrl_reg = 0; | 281 | u32 ctrl_reg = 0; |
| 282 | 282 | ||
| 283 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); | 283 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); |
| 284 | ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; | 284 | ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; |
| 285 | 285 | ||
| 286 | switch (bus) { | 286 | switch (bus) { |
| 287 | case 4: | 287 | case 4: |
| 288 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; | 288 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; |
| 289 | break; | 289 | break; |
| 290 | case 1: | 290 | case 1: |
| 291 | default: | 291 | default: |
| 292 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT; | 292 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT; |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | /* default transfer mode */ | 295 | /* default transfer mode */ |
| 296 | ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN; | 296 | ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN; |
| 297 | ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST; | 297 | ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST; |
| 298 | 298 | ||
| 299 | /* default to maximum timeout */ | 299 | /* default to maximum timeout */ |
| 300 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); | 300 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); |
| 301 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN; | 301 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN; |
| 302 | 302 | ||
| 303 | ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN; | 303 | ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN; |
| 304 | 304 | ||
| 305 | ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY; | 305 | ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY; |
| 306 | 306 | ||
| 307 | debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg, | 307 | debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg, |
| 308 | (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ? | 308 | (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ? |
| 309 | "push-pull" : "open-drain", | 309 | "push-pull" : "open-drain", |
| 310 | (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ? | 310 | (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ? |
| 311 | "4bit-width" : "1bit-width", | 311 | "4bit-width" : "1bit-width", |
| 312 | (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ? | 312 | (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ? |
| 313 | "high-speed" : ""); | 313 | "high-speed" : ""); |
| 314 | 314 | ||
| 315 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); | 315 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | static void mvebu_mmc_set_ios(struct mmc *mmc) | 318 | static void mvebu_mmc_set_ios(struct mmc *mmc) |
| 319 | { | 319 | { |
| 320 | debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME, | 320 | debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME, |
| 321 | mmc->bus_width, mmc->clock); | 321 | mmc->bus_width, mmc->clock); |
| 322 | mvebu_mmc_set_bus(mmc->bus_width); | 322 | mvebu_mmc_set_bus(mmc->bus_width); |
| 323 | mvebu_mmc_set_clk(mmc->clock); | 323 | mvebu_mmc_set_clk(mmc->clock); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | /* | 326 | /* |
| 327 | * Set window register. | 327 | * Set window register. |
| 328 | */ | 328 | */ |
| 329 | static void mvebu_window_setup(void) | 329 | static void mvebu_window_setup(void) |
| 330 | { | 330 | { |
| 331 | int i; | 331 | int i; |
| 332 | 332 | ||
| 333 | for (i = 0; i < 4; i++) { | 333 | for (i = 0; i < 4; i++) { |
| 334 | mvebu_mmc_write(WINDOW_CTRL(i), 0); | 334 | mvebu_mmc_write(WINDOW_CTRL(i), 0); |
| 335 | mvebu_mmc_write(WINDOW_BASE(i), 0); | 335 | mvebu_mmc_write(WINDOW_BASE(i), 0); |
| 336 | } | 336 | } |
| 337 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { | 337 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { |
| 338 | u32 size, base, attrib; | 338 | u32 size, base, attrib; |
| 339 | 339 | ||
| 340 | /* Enable DRAM bank */ | 340 | /* Enable DRAM bank */ |
| 341 | switch (i) { | 341 | switch (i) { |
| 342 | case 0: | 342 | case 0: |
| 343 | attrib = KWCPU_ATTR_DRAM_CS0; | 343 | attrib = KWCPU_ATTR_DRAM_CS0; |
| 344 | break; | 344 | break; |
| 345 | case 1: | 345 | case 1: |
| 346 | attrib = KWCPU_ATTR_DRAM_CS1; | 346 | attrib = KWCPU_ATTR_DRAM_CS1; |
| 347 | break; | 347 | break; |
| 348 | case 2: | 348 | case 2: |
| 349 | attrib = KWCPU_ATTR_DRAM_CS2; | 349 | attrib = KWCPU_ATTR_DRAM_CS2; |
| 350 | break; | 350 | break; |
| 351 | case 3: | 351 | case 3: |
| 352 | attrib = KWCPU_ATTR_DRAM_CS3; | 352 | attrib = KWCPU_ATTR_DRAM_CS3; |
| 353 | break; | 353 | break; |
| 354 | default: | 354 | default: |
| 355 | /* invalide bank, disable access */ | 355 | /* invalide bank, disable access */ |
| 356 | attrib = 0; | 356 | attrib = 0; |
| 357 | break; | 357 | break; |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | size = gd->bd->bi_dram[i].size; | 360 | size = gd->bd->bi_dram[i].size; |
| 361 | base = gd->bd->bi_dram[i].start; | 361 | base = gd->bd->bi_dram[i].start; |
| 362 | if (size && attrib) { | 362 | if (size && attrib) { |
| 363 | mvebu_mmc_write(WINDOW_CTRL(i), | 363 | mvebu_mmc_write(WINDOW_CTRL(i), |
| 364 | MVCPU_WIN_CTRL_DATA(size, | 364 | MVCPU_WIN_CTRL_DATA(size, |
| 365 | MVEBU_TARGET_DRAM, | 365 | MVEBU_TARGET_DRAM, |
| 366 | attrib, | 366 | attrib, |
| 367 | MVCPU_WIN_ENABLE)); | 367 | MVCPU_WIN_ENABLE)); |
| 368 | } else { | 368 | } else { |
| 369 | mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE); | 369 | mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE); |
| 370 | } | 370 | } |
| 371 | mvebu_mmc_write(WINDOW_BASE(i), base); | 371 | mvebu_mmc_write(WINDOW_BASE(i), base); |
| 372 | } | 372 | } |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | static int mvebu_mmc_initialize(struct mmc *mmc) | 375 | static int mvebu_mmc_initialize(struct mmc *mmc) |
| 376 | { | 376 | { |
| 377 | debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME); | 377 | debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME); |
| 378 | 378 | ||
| 379 | /* | 379 | /* |
| 380 | * Setting host parameters | 380 | * Setting host parameters |
| 381 | * Initial Host Ctrl : Timeout : max , Normal Speed mode, | 381 | * Initial Host Ctrl : Timeout : max , Normal Speed mode, |
| 382 | * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line | 382 | * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line |
| 383 | */ | 383 | */ |
| 384 | mvebu_mmc_write(SDIO_HOST_CTRL, | 384 | mvebu_mmc_write(SDIO_HOST_CTRL, |
| 385 | SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) | | 385 | SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) | |
| 386 | SDIO_HOST_CTRL_DATA_WIDTH_4_BITS | | 386 | SDIO_HOST_CTRL_DATA_WIDTH_4_BITS | |
| 387 | SDIO_HOST_CTRL_BIG_ENDIAN | | 387 | SDIO_HOST_CTRL_BIG_ENDIAN | |
| 388 | SDIO_HOST_CTRL_PUSH_PULL_EN | | 388 | SDIO_HOST_CTRL_PUSH_PULL_EN | |
| 389 | SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY); | 389 | SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY); |
| 390 | 390 | ||
| 391 | mvebu_mmc_write(SDIO_CLK_CTRL, 0); | 391 | mvebu_mmc_write(SDIO_CLK_CTRL, 0); |
| 392 | 392 | ||
| 393 | /* enable status */ | 393 | /* enable status */ |
| 394 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); | 394 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); |
| 395 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); | 395 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); |
| 396 | 396 | ||
| 397 | /* disable interrupts */ | 397 | /* disable interrupts */ |
| 398 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); | 398 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); |
| 399 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); | 399 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); |
| 400 | 400 | ||
| 401 | mvebu_window_setup(); | 401 | mvebu_window_setup(); |
| 402 | 402 | ||
| 403 | /* SW reset */ | 403 | /* SW reset */ |
| 404 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); | 404 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); |
| 405 | 405 | ||
| 406 | return 0; | 406 | return 0; |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | static const struct mmc_ops mvebu_mmc_ops = { | 409 | static const struct mmc_ops mvebu_mmc_ops = { |
| 410 | .send_cmd = mvebu_mmc_send_cmd, | 410 | .send_cmd = mvebu_mmc_send_cmd, |
| 411 | .set_ios = mvebu_mmc_set_ios, | 411 | .set_ios = mvebu_mmc_set_ios, |
| 412 | .init = mvebu_mmc_initialize, | 412 | .init = mvebu_mmc_initialize, |
| 413 | }; | 413 | }; |
| 414 | 414 | ||
| 415 | static struct mmc_config mvebu_mmc_cfg = { | 415 | static struct mmc_config mvebu_mmc_cfg = { |
| 416 | .name = DRIVER_NAME, | 416 | .name = DRIVER_NAME, |
| 417 | .ops = &mvebu_mmc_ops, | 417 | .ops = &mvebu_mmc_ops, |
| 418 | .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX, | 418 | .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX, |
| 419 | .f_max = MVEBU_MMC_CLOCKRATE_MAX, | 419 | .f_max = MVEBU_MMC_CLOCKRATE_MAX, |
| 420 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, | 420 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, |
| 421 | .host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HC | | 421 | .host_caps = MMC_MODE_4BIT | MMC_MODE_HS | |
| 422 | MMC_MODE_HS_52MHz, | 422 | MMC_MODE_HS_52MHz, |
| 423 | .part_type = PART_TYPE_DOS, | 423 | .part_type = PART_TYPE_DOS, |
| 424 | .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, | 424 | .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, |
| 425 | }; | 425 | }; |
| 426 | 426 | ||
| 427 | int mvebu_mmc_init(bd_t *bis) | 427 | int mvebu_mmc_init(bd_t *bis) |
| 428 | { | 428 | { |
| 429 | struct mmc *mmc; | 429 | struct mmc *mmc; |
| 430 | 430 | ||
| 431 | mvebu_mmc_power_up(); | 431 | mvebu_mmc_power_up(); |
| 432 | 432 | ||
| 433 | mmc = mmc_create(&mvebu_mmc_cfg, bis); | 433 | mmc = mmc_create(&mvebu_mmc_cfg, bis); |
| 434 | if (mmc == NULL) | 434 | if (mmc == NULL) |
| 435 | return -1; | 435 | return -1; |
| 436 | 436 | ||
| 437 | return 0; | 437 | return 0; |
| 438 | } | 438 | } |
| 439 | 439 |
drivers/mmc/mxsmmc.c
| 1 | /* | 1 | /* |
| 2 | * Freescale i.MX28 SSP MMC driver | 2 | * Freescale i.MX28 SSP MMC driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | 4 | * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> |
| 5 | * on behalf of DENX Software Engineering GmbH | 5 | * on behalf of DENX Software Engineering GmbH |
| 6 | * | 6 | * |
| 7 | * Based on code from LTIB: | 7 | * Based on code from LTIB: |
| 8 | * (C) Copyright 2008-2010 Freescale Semiconductor, Inc. | 8 | * (C) Copyright 2008-2010 Freescale Semiconductor, Inc. |
| 9 | * Terry Lv | 9 | * Terry Lv |
| 10 | * | 10 | * |
| 11 | * Copyright 2007, Freescale Semiconductor, Inc | 11 | * Copyright 2007, Freescale Semiconductor, Inc |
| 12 | * Andy Fleming | 12 | * Andy Fleming |
| 13 | * | 13 | * |
| 14 | * Based vaguely on the pxa mmc code: | 14 | * Based vaguely on the pxa mmc code: |
| 15 | * (C) Copyright 2003 | 15 | * (C) Copyright 2003 |
| 16 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net | 16 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net |
| 17 | * | 17 | * |
| 18 | * SPDX-License-Identifier: GPL-2.0+ | 18 | * SPDX-License-Identifier: GPL-2.0+ |
| 19 | */ | 19 | */ |
| 20 | #include <common.h> | 20 | #include <common.h> |
| 21 | #include <malloc.h> | 21 | #include <malloc.h> |
| 22 | #include <mmc.h> | 22 | #include <mmc.h> |
| 23 | #include <asm/errno.h> | 23 | #include <asm/errno.h> |
| 24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
| 25 | #include <asm/arch/clock.h> | 25 | #include <asm/arch/clock.h> |
| 26 | #include <asm/arch/imx-regs.h> | 26 | #include <asm/arch/imx-regs.h> |
| 27 | #include <asm/arch/sys_proto.h> | 27 | #include <asm/arch/sys_proto.h> |
| 28 | #include <asm/imx-common/dma.h> | 28 | #include <asm/imx-common/dma.h> |
| 29 | #include <bouncebuf.h> | 29 | #include <bouncebuf.h> |
| 30 | 30 | ||
| 31 | struct mxsmmc_priv { | 31 | struct mxsmmc_priv { |
| 32 | int id; | 32 | int id; |
| 33 | struct mxs_ssp_regs *regs; | 33 | struct mxs_ssp_regs *regs; |
| 34 | uint32_t buswidth; | 34 | uint32_t buswidth; |
| 35 | int (*mmc_is_wp)(int); | 35 | int (*mmc_is_wp)(int); |
| 36 | int (*mmc_cd)(int); | 36 | int (*mmc_cd)(int); |
| 37 | struct mxs_dma_desc *desc; | 37 | struct mxs_dma_desc *desc; |
| 38 | struct mmc_config cfg; /* mmc configuration */ | 38 | struct mmc_config cfg; /* mmc configuration */ |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | #define MXSMMC_MAX_TIMEOUT 10000 | 41 | #define MXSMMC_MAX_TIMEOUT 10000 |
| 42 | #define MXSMMC_SMALL_TRANSFER 512 | 42 | #define MXSMMC_SMALL_TRANSFER 512 |
| 43 | 43 | ||
| 44 | static int mxsmmc_cd(struct mxsmmc_priv *priv) | 44 | static int mxsmmc_cd(struct mxsmmc_priv *priv) |
| 45 | { | 45 | { |
| 46 | struct mxs_ssp_regs *ssp_regs = priv->regs; | 46 | struct mxs_ssp_regs *ssp_regs = priv->regs; |
| 47 | 47 | ||
| 48 | if (priv->mmc_cd) | 48 | if (priv->mmc_cd) |
| 49 | return priv->mmc_cd(priv->id); | 49 | return priv->mmc_cd(priv->id); |
| 50 | 50 | ||
| 51 | return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT); | 51 | return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data) | 54 | static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data) |
| 55 | { | 55 | { |
| 56 | struct mxs_ssp_regs *ssp_regs = priv->regs; | 56 | struct mxs_ssp_regs *ssp_regs = priv->regs; |
| 57 | uint32_t *data_ptr; | 57 | uint32_t *data_ptr; |
| 58 | int timeout = MXSMMC_MAX_TIMEOUT; | 58 | int timeout = MXSMMC_MAX_TIMEOUT; |
| 59 | uint32_t reg; | 59 | uint32_t reg; |
| 60 | uint32_t data_count = data->blocksize * data->blocks; | 60 | uint32_t data_count = data->blocksize * data->blocks; |
| 61 | 61 | ||
| 62 | if (data->flags & MMC_DATA_READ) { | 62 | if (data->flags & MMC_DATA_READ) { |
| 63 | data_ptr = (uint32_t *)data->dest; | 63 | data_ptr = (uint32_t *)data->dest; |
| 64 | while (data_count && --timeout) { | 64 | while (data_count && --timeout) { |
| 65 | reg = readl(&ssp_regs->hw_ssp_status); | 65 | reg = readl(&ssp_regs->hw_ssp_status); |
| 66 | if (!(reg & SSP_STATUS_FIFO_EMPTY)) { | 66 | if (!(reg & SSP_STATUS_FIFO_EMPTY)) { |
| 67 | *data_ptr++ = readl(&ssp_regs->hw_ssp_data); | 67 | *data_ptr++ = readl(&ssp_regs->hw_ssp_data); |
| 68 | data_count -= 4; | 68 | data_count -= 4; |
| 69 | timeout = MXSMMC_MAX_TIMEOUT; | 69 | timeout = MXSMMC_MAX_TIMEOUT; |
| 70 | } else | 70 | } else |
| 71 | udelay(1000); | 71 | udelay(1000); |
| 72 | } | 72 | } |
| 73 | } else { | 73 | } else { |
| 74 | data_ptr = (uint32_t *)data->src; | 74 | data_ptr = (uint32_t *)data->src; |
| 75 | timeout *= 100; | 75 | timeout *= 100; |
| 76 | while (data_count && --timeout) { | 76 | while (data_count && --timeout) { |
| 77 | reg = readl(&ssp_regs->hw_ssp_status); | 77 | reg = readl(&ssp_regs->hw_ssp_status); |
| 78 | if (!(reg & SSP_STATUS_FIFO_FULL)) { | 78 | if (!(reg & SSP_STATUS_FIFO_FULL)) { |
| 79 | writel(*data_ptr++, &ssp_regs->hw_ssp_data); | 79 | writel(*data_ptr++, &ssp_regs->hw_ssp_data); |
| 80 | data_count -= 4; | 80 | data_count -= 4; |
| 81 | timeout = MXSMMC_MAX_TIMEOUT; | 81 | timeout = MXSMMC_MAX_TIMEOUT; |
| 82 | } else | 82 | } else |
| 83 | udelay(1000); | 83 | udelay(1000); |
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | return timeout ? 0 : COMM_ERR; | 87 | return timeout ? 0 : COMM_ERR; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) | 90 | static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) |
| 91 | { | 91 | { |
| 92 | uint32_t data_count = data->blocksize * data->blocks; | 92 | uint32_t data_count = data->blocksize * data->blocks; |
| 93 | int dmach; | 93 | int dmach; |
| 94 | struct mxs_dma_desc *desc = priv->desc; | 94 | struct mxs_dma_desc *desc = priv->desc; |
| 95 | void *addr; | 95 | void *addr; |
| 96 | unsigned int flags; | 96 | unsigned int flags; |
| 97 | struct bounce_buffer bbstate; | 97 | struct bounce_buffer bbstate; |
| 98 | 98 | ||
| 99 | memset(desc, 0, sizeof(struct mxs_dma_desc)); | 99 | memset(desc, 0, sizeof(struct mxs_dma_desc)); |
| 100 | desc->address = (dma_addr_t)desc; | 100 | desc->address = (dma_addr_t)desc; |
| 101 | 101 | ||
| 102 | if (data->flags & MMC_DATA_READ) { | 102 | if (data->flags & MMC_DATA_READ) { |
| 103 | priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; | 103 | priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; |
| 104 | addr = data->dest; | 104 | addr = data->dest; |
| 105 | flags = GEN_BB_WRITE; | 105 | flags = GEN_BB_WRITE; |
| 106 | } else { | 106 | } else { |
| 107 | priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; | 107 | priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; |
| 108 | addr = (void *)data->src; | 108 | addr = (void *)data->src; |
| 109 | flags = GEN_BB_READ; | 109 | flags = GEN_BB_READ; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | bounce_buffer_start(&bbstate, addr, data_count, flags); | 112 | bounce_buffer_start(&bbstate, addr, data_count, flags); |
| 113 | 113 | ||
| 114 | priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer; | 114 | priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer; |
| 115 | 115 | ||
| 116 | priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | | 116 | priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | |
| 117 | (data_count << MXS_DMA_DESC_BYTES_OFFSET); | 117 | (data_count << MXS_DMA_DESC_BYTES_OFFSET); |
| 118 | 118 | ||
| 119 | dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; | 119 | dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; |
| 120 | mxs_dma_desc_append(dmach, priv->desc); | 120 | mxs_dma_desc_append(dmach, priv->desc); |
| 121 | if (mxs_dma_go(dmach)) { | 121 | if (mxs_dma_go(dmach)) { |
| 122 | bounce_buffer_stop(&bbstate); | 122 | bounce_buffer_stop(&bbstate); |
| 123 | return COMM_ERR; | 123 | return COMM_ERR; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | bounce_buffer_stop(&bbstate); | 126 | bounce_buffer_stop(&bbstate); |
| 127 | 127 | ||
| 128 | return 0; | 128 | return 0; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /* | 131 | /* |
| 132 | * Sends a command out on the bus. Takes the mmc pointer, | 132 | * Sends a command out on the bus. Takes the mmc pointer, |
| 133 | * a command pointer, and an optional data pointer. | 133 | * a command pointer, and an optional data pointer. |
| 134 | */ | 134 | */ |
| 135 | static int | 135 | static int |
| 136 | mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | 136 | mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) |
| 137 | { | 137 | { |
| 138 | struct mxsmmc_priv *priv = mmc->priv; | 138 | struct mxsmmc_priv *priv = mmc->priv; |
| 139 | struct mxs_ssp_regs *ssp_regs = priv->regs; | 139 | struct mxs_ssp_regs *ssp_regs = priv->regs; |
| 140 | uint32_t reg; | 140 | uint32_t reg; |
| 141 | int timeout; | 141 | int timeout; |
| 142 | uint32_t ctrl0; | 142 | uint32_t ctrl0; |
| 143 | int ret; | 143 | int ret; |
| 144 | 144 | ||
| 145 | debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx); | 145 | debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx); |
| 146 | 146 | ||
| 147 | /* Check bus busy */ | 147 | /* Check bus busy */ |
| 148 | timeout = MXSMMC_MAX_TIMEOUT; | 148 | timeout = MXSMMC_MAX_TIMEOUT; |
| 149 | while (--timeout) { | 149 | while (--timeout) { |
| 150 | udelay(1000); | 150 | udelay(1000); |
| 151 | reg = readl(&ssp_regs->hw_ssp_status); | 151 | reg = readl(&ssp_regs->hw_ssp_status); |
| 152 | if (!(reg & | 152 | if (!(reg & |
| 153 | (SSP_STATUS_BUSY | SSP_STATUS_DATA_BUSY | | 153 | (SSP_STATUS_BUSY | SSP_STATUS_DATA_BUSY | |
| 154 | SSP_STATUS_CMD_BUSY))) { | 154 | SSP_STATUS_CMD_BUSY))) { |
| 155 | break; | 155 | break; |
| 156 | } | 156 | } |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | if (!timeout) { | 159 | if (!timeout) { |
| 160 | printf("MMC%d: Bus busy timeout!\n", mmc->block_dev.dev); | 160 | printf("MMC%d: Bus busy timeout!\n", mmc->block_dev.dev); |
| 161 | return TIMEOUT; | 161 | return TIMEOUT; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /* See if card is present */ | 164 | /* See if card is present */ |
| 165 | if (!mxsmmc_cd(priv)) { | 165 | if (!mxsmmc_cd(priv)) { |
| 166 | printf("MMC%d: No card detected!\n", mmc->block_dev.dev); | 166 | printf("MMC%d: No card detected!\n", mmc->block_dev.dev); |
| 167 | return NO_CARD_ERR; | 167 | return NO_CARD_ERR; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | /* Start building CTRL0 contents */ | 170 | /* Start building CTRL0 contents */ |
| 171 | ctrl0 = priv->buswidth; | 171 | ctrl0 = priv->buswidth; |
| 172 | 172 | ||
| 173 | /* Set up command */ | 173 | /* Set up command */ |
| 174 | if (!(cmd->resp_type & MMC_RSP_CRC)) | 174 | if (!(cmd->resp_type & MMC_RSP_CRC)) |
| 175 | ctrl0 |= SSP_CTRL0_IGNORE_CRC; | 175 | ctrl0 |= SSP_CTRL0_IGNORE_CRC; |
| 176 | if (cmd->resp_type & MMC_RSP_PRESENT) /* Need to get response */ | 176 | if (cmd->resp_type & MMC_RSP_PRESENT) /* Need to get response */ |
| 177 | ctrl0 |= SSP_CTRL0_GET_RESP; | 177 | ctrl0 |= SSP_CTRL0_GET_RESP; |
| 178 | if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */ | 178 | if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */ |
| 179 | ctrl0 |= SSP_CTRL0_LONG_RESP; | 179 | ctrl0 |= SSP_CTRL0_LONG_RESP; |
| 180 | 180 | ||
| 181 | if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER)) | 181 | if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER)) |
| 182 | writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr); | 182 | writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr); |
| 183 | else | 183 | else |
| 184 | writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set); | 184 | writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set); |
| 185 | 185 | ||
| 186 | /* Command index */ | 186 | /* Command index */ |
| 187 | reg = readl(&ssp_regs->hw_ssp_cmd0); | 187 | reg = readl(&ssp_regs->hw_ssp_cmd0); |
| 188 | reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC); | 188 | reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC); |
| 189 | reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET; | 189 | reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET; |
| 190 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) | 190 | if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) |
| 191 | reg |= SSP_CMD0_APPEND_8CYC; | 191 | reg |= SSP_CMD0_APPEND_8CYC; |
| 192 | writel(reg, &ssp_regs->hw_ssp_cmd0); | 192 | writel(reg, &ssp_regs->hw_ssp_cmd0); |
| 193 | 193 | ||
| 194 | /* Command argument */ | 194 | /* Command argument */ |
| 195 | writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1); | 195 | writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1); |
| 196 | 196 | ||
| 197 | /* Set up data */ | 197 | /* Set up data */ |
| 198 | if (data) { | 198 | if (data) { |
| 199 | /* READ or WRITE */ | 199 | /* READ or WRITE */ |
| 200 | if (data->flags & MMC_DATA_READ) { | 200 | if (data->flags & MMC_DATA_READ) { |
| 201 | ctrl0 |= SSP_CTRL0_READ; | 201 | ctrl0 |= SSP_CTRL0_READ; |
| 202 | } else if (priv->mmc_is_wp && | 202 | } else if (priv->mmc_is_wp && |
| 203 | priv->mmc_is_wp(mmc->block_dev.dev)) { | 203 | priv->mmc_is_wp(mmc->block_dev.dev)) { |
| 204 | printf("MMC%d: Can not write a locked card!\n", | 204 | printf("MMC%d: Can not write a locked card!\n", |
| 205 | mmc->block_dev.dev); | 205 | mmc->block_dev.dev); |
| 206 | return UNUSABLE_ERR; | 206 | return UNUSABLE_ERR; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | ctrl0 |= SSP_CTRL0_DATA_XFER; | 209 | ctrl0 |= SSP_CTRL0_DATA_XFER; |
| 210 | 210 | ||
| 211 | reg = data->blocksize * data->blocks; | 211 | reg = data->blocksize * data->blocks; |
| 212 | #if defined(CONFIG_MX23) | 212 | #if defined(CONFIG_MX23) |
| 213 | ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK; | 213 | ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK; |
| 214 | 214 | ||
| 215 | clrsetbits_le32(&ssp_regs->hw_ssp_cmd0, | 215 | clrsetbits_le32(&ssp_regs->hw_ssp_cmd0, |
| 216 | SSP_CMD0_BLOCK_SIZE_MASK | SSP_CMD0_BLOCK_COUNT_MASK, | 216 | SSP_CMD0_BLOCK_SIZE_MASK | SSP_CMD0_BLOCK_COUNT_MASK, |
| 217 | ((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) | | 217 | ((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) | |
| 218 | ((ffs(data->blocksize) - 1) << | 218 | ((ffs(data->blocksize) - 1) << |
| 219 | SSP_CMD0_BLOCK_SIZE_OFFSET)); | 219 | SSP_CMD0_BLOCK_SIZE_OFFSET)); |
| 220 | #elif defined(CONFIG_MX28) | 220 | #elif defined(CONFIG_MX28) |
| 221 | writel(reg, &ssp_regs->hw_ssp_xfer_size); | 221 | writel(reg, &ssp_regs->hw_ssp_xfer_size); |
| 222 | 222 | ||
| 223 | reg = ((data->blocks - 1) << | 223 | reg = ((data->blocks - 1) << |
| 224 | SSP_BLOCK_SIZE_BLOCK_COUNT_OFFSET) | | 224 | SSP_BLOCK_SIZE_BLOCK_COUNT_OFFSET) | |
| 225 | ((ffs(data->blocksize) - 1) << | 225 | ((ffs(data->blocksize) - 1) << |
| 226 | SSP_BLOCK_SIZE_BLOCK_SIZE_OFFSET); | 226 | SSP_BLOCK_SIZE_BLOCK_SIZE_OFFSET); |
| 227 | writel(reg, &ssp_regs->hw_ssp_block_size); | 227 | writel(reg, &ssp_regs->hw_ssp_block_size); |
| 228 | #endif | 228 | #endif |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | /* Kick off the command */ | 231 | /* Kick off the command */ |
| 232 | ctrl0 |= SSP_CTRL0_WAIT_FOR_IRQ | SSP_CTRL0_ENABLE | SSP_CTRL0_RUN; | 232 | ctrl0 |= SSP_CTRL0_WAIT_FOR_IRQ | SSP_CTRL0_ENABLE | SSP_CTRL0_RUN; |
| 233 | writel(ctrl0, &ssp_regs->hw_ssp_ctrl0); | 233 | writel(ctrl0, &ssp_regs->hw_ssp_ctrl0); |
| 234 | 234 | ||
| 235 | /* Wait for the command to complete */ | 235 | /* Wait for the command to complete */ |
| 236 | timeout = MXSMMC_MAX_TIMEOUT; | 236 | timeout = MXSMMC_MAX_TIMEOUT; |
| 237 | while (--timeout) { | 237 | while (--timeout) { |
| 238 | udelay(1000); | 238 | udelay(1000); |
| 239 | reg = readl(&ssp_regs->hw_ssp_status); | 239 | reg = readl(&ssp_regs->hw_ssp_status); |
| 240 | if (!(reg & SSP_STATUS_CMD_BUSY)) | 240 | if (!(reg & SSP_STATUS_CMD_BUSY)) |
| 241 | break; | 241 | break; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | if (!timeout) { | 244 | if (!timeout) { |
| 245 | printf("MMC%d: Command %d busy\n", | 245 | printf("MMC%d: Command %d busy\n", |
| 246 | mmc->block_dev.dev, cmd->cmdidx); | 246 | mmc->block_dev.dev, cmd->cmdidx); |
| 247 | return TIMEOUT; | 247 | return TIMEOUT; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | /* Check command timeout */ | 250 | /* Check command timeout */ |
| 251 | if (reg & SSP_STATUS_RESP_TIMEOUT) { | 251 | if (reg & SSP_STATUS_RESP_TIMEOUT) { |
| 252 | printf("MMC%d: Command %d timeout (status 0x%08x)\n", | 252 | printf("MMC%d: Command %d timeout (status 0x%08x)\n", |
| 253 | mmc->block_dev.dev, cmd->cmdidx, reg); | 253 | mmc->block_dev.dev, cmd->cmdidx, reg); |
| 254 | return TIMEOUT; | 254 | return TIMEOUT; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | /* Check command errors */ | 257 | /* Check command errors */ |
| 258 | if (reg & (SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR)) { | 258 | if (reg & (SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR)) { |
| 259 | printf("MMC%d: Command %d error (status 0x%08x)!\n", | 259 | printf("MMC%d: Command %d error (status 0x%08x)!\n", |
| 260 | mmc->block_dev.dev, cmd->cmdidx, reg); | 260 | mmc->block_dev.dev, cmd->cmdidx, reg); |
| 261 | return COMM_ERR; | 261 | return COMM_ERR; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | /* Copy response to response buffer */ | 264 | /* Copy response to response buffer */ |
| 265 | if (cmd->resp_type & MMC_RSP_136) { | 265 | if (cmd->resp_type & MMC_RSP_136) { |
| 266 | cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0); | 266 | cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0); |
| 267 | cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1); | 267 | cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1); |
| 268 | cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2); | 268 | cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2); |
| 269 | cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3); | 269 | cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3); |
| 270 | } else | 270 | } else |
| 271 | cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0); | 271 | cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0); |
| 272 | 272 | ||
| 273 | /* Return if no data to process */ | 273 | /* Return if no data to process */ |
| 274 | if (!data) | 274 | if (!data) |
| 275 | return 0; | 275 | return 0; |
| 276 | 276 | ||
| 277 | if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) { | 277 | if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) { |
| 278 | ret = mxsmmc_send_cmd_pio(priv, data); | 278 | ret = mxsmmc_send_cmd_pio(priv, data); |
| 279 | if (ret) { | 279 | if (ret) { |
| 280 | printf("MMC%d: Data timeout with command %d " | 280 | printf("MMC%d: Data timeout with command %d " |
| 281 | "(status 0x%08x)!\n", | 281 | "(status 0x%08x)!\n", |
| 282 | mmc->block_dev.dev, cmd->cmdidx, reg); | 282 | mmc->block_dev.dev, cmd->cmdidx, reg); |
| 283 | return ret; | 283 | return ret; |
| 284 | } | 284 | } |
| 285 | } else { | 285 | } else { |
| 286 | ret = mxsmmc_send_cmd_dma(priv, data); | 286 | ret = mxsmmc_send_cmd_dma(priv, data); |
| 287 | if (ret) { | 287 | if (ret) { |
| 288 | printf("MMC%d: DMA transfer failed\n", | 288 | printf("MMC%d: DMA transfer failed\n", |
| 289 | mmc->block_dev.dev); | 289 | mmc->block_dev.dev); |
| 290 | return ret; | 290 | return ret; |
| 291 | } | 291 | } |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | /* Check data errors */ | 294 | /* Check data errors */ |
| 295 | reg = readl(&ssp_regs->hw_ssp_status); | 295 | reg = readl(&ssp_regs->hw_ssp_status); |
| 296 | if (reg & | 296 | if (reg & |
| 297 | (SSP_STATUS_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | | 297 | (SSP_STATUS_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | |
| 298 | SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW)) { | 298 | SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW)) { |
| 299 | printf("MMC%d: Data error with command %d (status 0x%08x)!\n", | 299 | printf("MMC%d: Data error with command %d (status 0x%08x)!\n", |
| 300 | mmc->block_dev.dev, cmd->cmdidx, reg); | 300 | mmc->block_dev.dev, cmd->cmdidx, reg); |
| 301 | return COMM_ERR; | 301 | return COMM_ERR; |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | return 0; | 304 | return 0; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | static void mxsmmc_set_ios(struct mmc *mmc) | 307 | static void mxsmmc_set_ios(struct mmc *mmc) |
| 308 | { | 308 | { |
| 309 | struct mxsmmc_priv *priv = mmc->priv; | 309 | struct mxsmmc_priv *priv = mmc->priv; |
| 310 | struct mxs_ssp_regs *ssp_regs = priv->regs; | 310 | struct mxs_ssp_regs *ssp_regs = priv->regs; |
| 311 | 311 | ||
| 312 | /* Set the clock speed */ | 312 | /* Set the clock speed */ |
| 313 | if (mmc->clock) | 313 | if (mmc->clock) |
| 314 | mxs_set_ssp_busclock(priv->id, mmc->clock / 1000); | 314 | mxs_set_ssp_busclock(priv->id, mmc->clock / 1000); |
| 315 | 315 | ||
| 316 | switch (mmc->bus_width) { | 316 | switch (mmc->bus_width) { |
| 317 | case 1: | 317 | case 1: |
| 318 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT; | 318 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT; |
| 319 | break; | 319 | break; |
| 320 | case 4: | 320 | case 4: |
| 321 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT; | 321 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT; |
| 322 | break; | 322 | break; |
| 323 | case 8: | 323 | case 8: |
| 324 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT; | 324 | priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT; |
| 325 | break; | 325 | break; |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | /* Set the bus width */ | 328 | /* Set the bus width */ |
| 329 | clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0, | 329 | clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0, |
| 330 | SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth); | 330 | SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth); |
| 331 | 331 | ||
| 332 | debug("MMC%d: Set %d bits bus width\n", | 332 | debug("MMC%d: Set %d bits bus width\n", |
| 333 | mmc->block_dev.dev, mmc->bus_width); | 333 | mmc->block_dev.dev, mmc->bus_width); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | static int mxsmmc_init(struct mmc *mmc) | 336 | static int mxsmmc_init(struct mmc *mmc) |
| 337 | { | 337 | { |
| 338 | struct mxsmmc_priv *priv = mmc->priv; | 338 | struct mxsmmc_priv *priv = mmc->priv; |
| 339 | struct mxs_ssp_regs *ssp_regs = priv->regs; | 339 | struct mxs_ssp_regs *ssp_regs = priv->regs; |
| 340 | 340 | ||
| 341 | /* Reset SSP */ | 341 | /* Reset SSP */ |
| 342 | mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); | 342 | mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); |
| 343 | 343 | ||
| 344 | /* Reconfigure the SSP block for MMC operation */ | 344 | /* Reconfigure the SSP block for MMC operation */ |
| 345 | writel(SSP_CTRL1_SSP_MODE_SD_MMC | | 345 | writel(SSP_CTRL1_SSP_MODE_SD_MMC | |
| 346 | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS | | 346 | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS | |
| 347 | SSP_CTRL1_DMA_ENABLE | | 347 | SSP_CTRL1_DMA_ENABLE | |
| 348 | SSP_CTRL1_POLARITY | | 348 | SSP_CTRL1_POLARITY | |
| 349 | SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | | 349 | SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | |
| 350 | SSP_CTRL1_DATA_CRC_IRQ_EN | | 350 | SSP_CTRL1_DATA_CRC_IRQ_EN | |
| 351 | SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | | 351 | SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | |
| 352 | SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | | 352 | SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | |
| 353 | SSP_CTRL1_RESP_ERR_IRQ_EN, | 353 | SSP_CTRL1_RESP_ERR_IRQ_EN, |
| 354 | &ssp_regs->hw_ssp_ctrl1_set); | 354 | &ssp_regs->hw_ssp_ctrl1_set); |
| 355 | 355 | ||
| 356 | /* Set initial bit clock 400 KHz */ | 356 | /* Set initial bit clock 400 KHz */ |
| 357 | mxs_set_ssp_busclock(priv->id, 400); | 357 | mxs_set_ssp_busclock(priv->id, 400); |
| 358 | 358 | ||
| 359 | /* Send initial 74 clock cycles (185 us @ 400 KHz)*/ | 359 | /* Send initial 74 clock cycles (185 us @ 400 KHz)*/ |
| 360 | writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set); | 360 | writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set); |
| 361 | udelay(200); | 361 | udelay(200); |
| 362 | writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr); | 362 | writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr); |
| 363 | 363 | ||
| 364 | return 0; | 364 | return 0; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | static const struct mmc_ops mxsmmc_ops = { | 367 | static const struct mmc_ops mxsmmc_ops = { |
| 368 | .send_cmd = mxsmmc_send_cmd, | 368 | .send_cmd = mxsmmc_send_cmd, |
| 369 | .set_ios = mxsmmc_set_ios, | 369 | .set_ios = mxsmmc_set_ios, |
| 370 | .init = mxsmmc_init, | 370 | .init = mxsmmc_init, |
| 371 | }; | 371 | }; |
| 372 | 372 | ||
| 373 | int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int)) | 373 | int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int)) |
| 374 | { | 374 | { |
| 375 | struct mmc *mmc = NULL; | 375 | struct mmc *mmc = NULL; |
| 376 | struct mxsmmc_priv *priv = NULL; | 376 | struct mxsmmc_priv *priv = NULL; |
| 377 | int ret; | 377 | int ret; |
| 378 | const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id); | 378 | const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id); |
| 379 | 379 | ||
| 380 | if (!mxs_ssp_bus_id_valid(id)) | 380 | if (!mxs_ssp_bus_id_valid(id)) |
| 381 | return -ENODEV; | 381 | return -ENODEV; |
| 382 | 382 | ||
| 383 | priv = malloc(sizeof(struct mxsmmc_priv)); | 383 | priv = malloc(sizeof(struct mxsmmc_priv)); |
| 384 | if (!priv) | 384 | if (!priv) |
| 385 | return -ENOMEM; | 385 | return -ENOMEM; |
| 386 | 386 | ||
| 387 | priv->desc = mxs_dma_desc_alloc(); | 387 | priv->desc = mxs_dma_desc_alloc(); |
| 388 | if (!priv->desc) { | 388 | if (!priv->desc) { |
| 389 | free(priv); | 389 | free(priv); |
| 390 | return -ENOMEM; | 390 | return -ENOMEM; |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id); | 393 | ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id); |
| 394 | if (ret) | 394 | if (ret) |
| 395 | return ret; | 395 | return ret; |
| 396 | 396 | ||
| 397 | priv->mmc_is_wp = wp; | 397 | priv->mmc_is_wp = wp; |
| 398 | priv->mmc_cd = cd; | 398 | priv->mmc_cd = cd; |
| 399 | priv->id = id; | 399 | priv->id = id; |
| 400 | priv->regs = mxs_ssp_regs_by_bus(id); | 400 | priv->regs = mxs_ssp_regs_by_bus(id); |
| 401 | 401 | ||
| 402 | priv->cfg.name = "MXS MMC"; | 402 | priv->cfg.name = "MXS MMC"; |
| 403 | priv->cfg.ops = &mxsmmc_ops; | 403 | priv->cfg.ops = &mxsmmc_ops; |
| 404 | 404 | ||
| 405 | priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; | 405 | priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
| 406 | 406 | ||
| 407 | priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | | 407 | priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | |
| 408 | MMC_MODE_HS_52MHz | MMC_MODE_HS | | 408 | MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 409 | MMC_MODE_HC; | ||
| 410 | 409 | ||
| 411 | /* | 410 | /* |
| 412 | * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz | 411 | * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz |
| 413 | * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), | 412 | * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), |
| 414 | * CLOCK_DIVIDE has to be an even value from 2 to 254, and | 413 | * CLOCK_DIVIDE has to be an even value from 2 to 254, and |
| 415 | * CLOCK_RATE could be any integer from 0 to 255. | 414 | * CLOCK_RATE could be any integer from 0 to 255. |
| 416 | */ | 415 | */ |
| 417 | priv->cfg.f_min = 400000; | 416 | priv->cfg.f_min = 400000; |
| 418 | priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2; | 417 | priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2; |
| 419 | priv->cfg.b_max = 0x20; | 418 | priv->cfg.b_max = 0x20; |
| 420 | 419 | ||
| 421 | mmc = mmc_create(&priv->cfg, priv); | 420 | mmc = mmc_create(&priv->cfg, priv); |
| 422 | if (mmc == NULL) { | 421 | if (mmc == NULL) { |
| 423 | mxs_dma_desc_free(priv->desc); | 422 | mxs_dma_desc_free(priv->desc); |
| 424 | free(priv); | 423 | free(priv); |
| 425 | return -ENOMEM; | 424 | return -ENOMEM; |
| 426 | } | 425 | } |
| 427 | return 0; | 426 | return 0; |
| 428 | } | 427 | } |
| 429 | 428 |
drivers/mmc/omap_hsmmc.c
| 1 | /* | 1 | /* |
| 2 | * (C) Copyright 2008 | 2 | * (C) Copyright 2008 |
| 3 | * Texas Instruments, <www.ti.com> | 3 | * Texas Instruments, <www.ti.com> |
| 4 | * Sukumar Ghorai <s-ghorai@ti.com> | 4 | * Sukumar Ghorai <s-ghorai@ti.com> |
| 5 | * | 5 | * |
| 6 | * See file CREDITS for list of people who contributed to this | 6 | * See file CREDITS for list of people who contributed to this |
| 7 | * project. | 7 | * project. |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License as | 10 | * modify it under the terms of the GNU General Public License as |
| 11 | * published by the Free Software Foundation's version 2 of | 11 | * published by the Free Software Foundation's version 2 of |
| 12 | * the License. | 12 | * the License. |
| 13 | * | 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, | 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
| 18 | * | 18 | * |
| 19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 22 | * MA 02111-1307 USA | 22 | * MA 02111-1307 USA |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <config.h> | 25 | #include <config.h> |
| 26 | #include <common.h> | 26 | #include <common.h> |
| 27 | #include <malloc.h> | 27 | #include <malloc.h> |
| 28 | #include <mmc.h> | 28 | #include <mmc.h> |
| 29 | #include <part.h> | 29 | #include <part.h> |
| 30 | #include <i2c.h> | 30 | #include <i2c.h> |
| 31 | #include <twl4030.h> | 31 | #include <twl4030.h> |
| 32 | #include <twl6030.h> | 32 | #include <twl6030.h> |
| 33 | #include <palmas.h> | 33 | #include <palmas.h> |
| 34 | #include <asm/gpio.h> | 34 | #include <asm/gpio.h> |
| 35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
| 36 | #include <asm/arch/mmc_host_def.h> | 36 | #include <asm/arch/mmc_host_def.h> |
| 37 | #include <asm/arch/sys_proto.h> | 37 | #include <asm/arch/sys_proto.h> |
| 38 | 38 | ||
| 39 | /* simplify defines to OMAP_HSMMC_USE_GPIO */ | 39 | /* simplify defines to OMAP_HSMMC_USE_GPIO */ |
| 40 | #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \ | 40 | #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \ |
| 41 | (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT)) | 41 | (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT)) |
| 42 | #define OMAP_HSMMC_USE_GPIO | 42 | #define OMAP_HSMMC_USE_GPIO |
| 43 | #else | 43 | #else |
| 44 | #undef OMAP_HSMMC_USE_GPIO | 44 | #undef OMAP_HSMMC_USE_GPIO |
| 45 | #endif | 45 | #endif |
| 46 | 46 | ||
| 47 | /* common definitions for all OMAPs */ | 47 | /* common definitions for all OMAPs */ |
| 48 | #define SYSCTL_SRC (1 << 25) | 48 | #define SYSCTL_SRC (1 << 25) |
| 49 | #define SYSCTL_SRD (1 << 26) | 49 | #define SYSCTL_SRD (1 << 26) |
| 50 | 50 | ||
| 51 | struct omap_hsmmc_data { | 51 | struct omap_hsmmc_data { |
| 52 | struct hsmmc *base_addr; | 52 | struct hsmmc *base_addr; |
| 53 | struct mmc_config cfg; | 53 | struct mmc_config cfg; |
| 54 | #ifdef OMAP_HSMMC_USE_GPIO | 54 | #ifdef OMAP_HSMMC_USE_GPIO |
| 55 | int cd_gpio; | 55 | int cd_gpio; |
| 56 | int wp_gpio; | 56 | int wp_gpio; |
| 57 | #endif | 57 | #endif |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | /* If we fail after 1 second wait, something is really bad */ | 60 | /* If we fail after 1 second wait, something is really bad */ |
| 61 | #define MAX_RETRY_MS 1000 | 61 | #define MAX_RETRY_MS 1000 |
| 62 | 62 | ||
| 63 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size); | 63 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size); |
| 64 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, | 64 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, |
| 65 | unsigned int siz); | 65 | unsigned int siz); |
| 66 | 66 | ||
| 67 | #ifdef OMAP_HSMMC_USE_GPIO | 67 | #ifdef OMAP_HSMMC_USE_GPIO |
| 68 | static int omap_mmc_setup_gpio_in(int gpio, const char *label) | 68 | static int omap_mmc_setup_gpio_in(int gpio, const char *label) |
| 69 | { | 69 | { |
| 70 | int ret; | 70 | int ret; |
| 71 | 71 | ||
| 72 | #ifndef CONFIG_DM_GPIO | 72 | #ifndef CONFIG_DM_GPIO |
| 73 | if (!gpio_is_valid(gpio)) | 73 | if (!gpio_is_valid(gpio)) |
| 74 | return -1; | 74 | return -1; |
| 75 | #endif | 75 | #endif |
| 76 | ret = gpio_request(gpio, label); | 76 | ret = gpio_request(gpio, label); |
| 77 | if (ret) | 77 | if (ret) |
| 78 | return ret; | 78 | return ret; |
| 79 | 79 | ||
| 80 | ret = gpio_direction_input(gpio); | 80 | ret = gpio_direction_input(gpio); |
| 81 | if (ret) | 81 | if (ret) |
| 82 | return ret; | 82 | return ret; |
| 83 | 83 | ||
| 84 | return gpio; | 84 | return gpio; |
| 85 | } | 85 | } |
| 86 | #endif | 86 | #endif |
| 87 | 87 | ||
| 88 | #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER) | 88 | #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER) |
| 89 | static void omap4_vmmc_pbias_config(struct mmc *mmc) | 89 | static void omap4_vmmc_pbias_config(struct mmc *mmc) |
| 90 | { | 90 | { |
| 91 | u32 value = 0; | 91 | u32 value = 0; |
| 92 | 92 | ||
| 93 | value = readl((*ctrl)->control_pbiaslite); | 93 | value = readl((*ctrl)->control_pbiaslite); |
| 94 | value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ); | 94 | value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ); |
| 95 | writel(value, (*ctrl)->control_pbiaslite); | 95 | writel(value, (*ctrl)->control_pbiaslite); |
| 96 | /* set VMMC to 3V */ | 96 | /* set VMMC to 3V */ |
| 97 | twl6030_power_mmc_init(); | 97 | twl6030_power_mmc_init(); |
| 98 | value = readl((*ctrl)->control_pbiaslite); | 98 | value = readl((*ctrl)->control_pbiaslite); |
| 99 | value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ; | 99 | value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ; |
| 100 | writel(value, (*ctrl)->control_pbiaslite); | 100 | writel(value, (*ctrl)->control_pbiaslite); |
| 101 | } | 101 | } |
| 102 | #endif | 102 | #endif |
| 103 | 103 | ||
| 104 | #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER) | 104 | #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER) |
| 105 | static void omap5_pbias_config(struct mmc *mmc) | 105 | static void omap5_pbias_config(struct mmc *mmc) |
| 106 | { | 106 | { |
| 107 | u32 value = 0; | 107 | u32 value = 0; |
| 108 | 108 | ||
| 109 | value = readl((*ctrl)->control_pbias); | 109 | value = readl((*ctrl)->control_pbias); |
| 110 | value &= ~SDCARD_PWRDNZ; | 110 | value &= ~SDCARD_PWRDNZ; |
| 111 | writel(value, (*ctrl)->control_pbias); | 111 | writel(value, (*ctrl)->control_pbias); |
| 112 | udelay(10); /* wait 10 us */ | 112 | udelay(10); /* wait 10 us */ |
| 113 | value &= ~SDCARD_BIAS_PWRDNZ; | 113 | value &= ~SDCARD_BIAS_PWRDNZ; |
| 114 | writel(value, (*ctrl)->control_pbias); | 114 | writel(value, (*ctrl)->control_pbias); |
| 115 | 115 | ||
| 116 | palmas_mmc1_poweron_ldo(); | 116 | palmas_mmc1_poweron_ldo(); |
| 117 | 117 | ||
| 118 | value = readl((*ctrl)->control_pbias); | 118 | value = readl((*ctrl)->control_pbias); |
| 119 | value |= SDCARD_BIAS_PWRDNZ; | 119 | value |= SDCARD_BIAS_PWRDNZ; |
| 120 | writel(value, (*ctrl)->control_pbias); | 120 | writel(value, (*ctrl)->control_pbias); |
| 121 | udelay(150); /* wait 150 us */ | 121 | udelay(150); /* wait 150 us */ |
| 122 | value |= SDCARD_PWRDNZ; | 122 | value |= SDCARD_PWRDNZ; |
| 123 | writel(value, (*ctrl)->control_pbias); | 123 | writel(value, (*ctrl)->control_pbias); |
| 124 | udelay(150); /* wait 150 us */ | 124 | udelay(150); /* wait 150 us */ |
| 125 | } | 125 | } |
| 126 | #endif | 126 | #endif |
| 127 | 127 | ||
| 128 | static unsigned char mmc_board_init(struct mmc *mmc) | 128 | static unsigned char mmc_board_init(struct mmc *mmc) |
| 129 | { | 129 | { |
| 130 | #if defined(CONFIG_OMAP34XX) | 130 | #if defined(CONFIG_OMAP34XX) |
| 131 | t2_t *t2_base = (t2_t *)T2_BASE; | 131 | t2_t *t2_base = (t2_t *)T2_BASE; |
| 132 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; | 132 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; |
| 133 | u32 pbias_lite; | 133 | u32 pbias_lite; |
| 134 | 134 | ||
| 135 | pbias_lite = readl(&t2_base->pbias_lite); | 135 | pbias_lite = readl(&t2_base->pbias_lite); |
| 136 | pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0); | 136 | pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0); |
| 137 | #ifdef CONFIG_TARGET_OMAP3_CAIRO | 137 | #ifdef CONFIG_TARGET_OMAP3_CAIRO |
| 138 | /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */ | 138 | /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */ |
| 139 | pbias_lite &= ~PBIASLITEVMODE0; | 139 | pbias_lite &= ~PBIASLITEVMODE0; |
| 140 | #endif | 140 | #endif |
| 141 | writel(pbias_lite, &t2_base->pbias_lite); | 141 | writel(pbias_lite, &t2_base->pbias_lite); |
| 142 | 142 | ||
| 143 | writel(pbias_lite | PBIASLITEPWRDNZ1 | | 143 | writel(pbias_lite | PBIASLITEPWRDNZ1 | |
| 144 | PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0, | 144 | PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0, |
| 145 | &t2_base->pbias_lite); | 145 | &t2_base->pbias_lite); |
| 146 | 146 | ||
| 147 | writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL, | 147 | writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL, |
| 148 | &t2_base->devconf0); | 148 | &t2_base->devconf0); |
| 149 | 149 | ||
| 150 | writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL, | 150 | writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL, |
| 151 | &t2_base->devconf1); | 151 | &t2_base->devconf1); |
| 152 | 152 | ||
| 153 | /* Change from default of 52MHz to 26MHz if necessary */ | 153 | /* Change from default of 52MHz to 26MHz if necessary */ |
| 154 | if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz)) | 154 | if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz)) |
| 155 | writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL, | 155 | writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL, |
| 156 | &t2_base->ctl_prog_io1); | 156 | &t2_base->ctl_prog_io1); |
| 157 | 157 | ||
| 158 | writel(readl(&prcm_base->fclken1_core) | | 158 | writel(readl(&prcm_base->fclken1_core) | |
| 159 | EN_MMC1 | EN_MMC2 | EN_MMC3, | 159 | EN_MMC1 | EN_MMC2 | EN_MMC3, |
| 160 | &prcm_base->fclken1_core); | 160 | &prcm_base->fclken1_core); |
| 161 | 161 | ||
| 162 | writel(readl(&prcm_base->iclken1_core) | | 162 | writel(readl(&prcm_base->iclken1_core) | |
| 163 | EN_MMC1 | EN_MMC2 | EN_MMC3, | 163 | EN_MMC1 | EN_MMC2 | EN_MMC3, |
| 164 | &prcm_base->iclken1_core); | 164 | &prcm_base->iclken1_core); |
| 165 | #endif | 165 | #endif |
| 166 | 166 | ||
| 167 | #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER) | 167 | #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER) |
| 168 | /* PBIAS config needed for MMC1 only */ | 168 | /* PBIAS config needed for MMC1 only */ |
| 169 | if (mmc->block_dev.dev == 0) | 169 | if (mmc->block_dev.dev == 0) |
| 170 | omap4_vmmc_pbias_config(mmc); | 170 | omap4_vmmc_pbias_config(mmc); |
| 171 | #endif | 171 | #endif |
| 172 | #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER) | 172 | #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER) |
| 173 | if (mmc->block_dev.dev == 0) | 173 | if (mmc->block_dev.dev == 0) |
| 174 | omap5_pbias_config(mmc); | 174 | omap5_pbias_config(mmc); |
| 175 | #endif | 175 | #endif |
| 176 | 176 | ||
| 177 | return 0; | 177 | return 0; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | void mmc_init_stream(struct hsmmc *mmc_base) | 180 | void mmc_init_stream(struct hsmmc *mmc_base) |
| 181 | { | 181 | { |
| 182 | ulong start; | 182 | ulong start; |
| 183 | 183 | ||
| 184 | writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con); | 184 | writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con); |
| 185 | 185 | ||
| 186 | writel(MMC_CMD0, &mmc_base->cmd); | 186 | writel(MMC_CMD0, &mmc_base->cmd); |
| 187 | start = get_timer(0); | 187 | start = get_timer(0); |
| 188 | while (!(readl(&mmc_base->stat) & CC_MASK)) { | 188 | while (!(readl(&mmc_base->stat) & CC_MASK)) { |
| 189 | if (get_timer(0) - start > MAX_RETRY_MS) { | 189 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 190 | printf("%s: timedout waiting for cc!\n", __func__); | 190 | printf("%s: timedout waiting for cc!\n", __func__); |
| 191 | return; | 191 | return; |
| 192 | } | 192 | } |
| 193 | } | 193 | } |
| 194 | writel(CC_MASK, &mmc_base->stat) | 194 | writel(CC_MASK, &mmc_base->stat) |
| 195 | ; | 195 | ; |
| 196 | writel(MMC_CMD0, &mmc_base->cmd) | 196 | writel(MMC_CMD0, &mmc_base->cmd) |
| 197 | ; | 197 | ; |
| 198 | start = get_timer(0); | 198 | start = get_timer(0); |
| 199 | while (!(readl(&mmc_base->stat) & CC_MASK)) { | 199 | while (!(readl(&mmc_base->stat) & CC_MASK)) { |
| 200 | if (get_timer(0) - start > MAX_RETRY_MS) { | 200 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 201 | printf("%s: timedout waiting for cc2!\n", __func__); | 201 | printf("%s: timedout waiting for cc2!\n", __func__); |
| 202 | return; | 202 | return; |
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| 205 | writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con); | 205 | writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | 208 | ||
| 209 | static int omap_hsmmc_init_setup(struct mmc *mmc) | 209 | static int omap_hsmmc_init_setup(struct mmc *mmc) |
| 210 | { | 210 | { |
| 211 | struct hsmmc *mmc_base; | 211 | struct hsmmc *mmc_base; |
| 212 | unsigned int reg_val; | 212 | unsigned int reg_val; |
| 213 | unsigned int dsor; | 213 | unsigned int dsor; |
| 214 | ulong start; | 214 | ulong start; |
| 215 | 215 | ||
| 216 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; | 216 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; |
| 217 | mmc_board_init(mmc); | 217 | mmc_board_init(mmc); |
| 218 | 218 | ||
| 219 | writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET, | 219 | writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET, |
| 220 | &mmc_base->sysconfig); | 220 | &mmc_base->sysconfig); |
| 221 | start = get_timer(0); | 221 | start = get_timer(0); |
| 222 | while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) { | 222 | while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) { |
| 223 | if (get_timer(0) - start > MAX_RETRY_MS) { | 223 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 224 | printf("%s: timedout waiting for cc2!\n", __func__); | 224 | printf("%s: timedout waiting for cc2!\n", __func__); |
| 225 | return TIMEOUT; | 225 | return TIMEOUT; |
| 226 | } | 226 | } |
| 227 | } | 227 | } |
| 228 | writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl); | 228 | writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl); |
| 229 | start = get_timer(0); | 229 | start = get_timer(0); |
| 230 | while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) { | 230 | while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) { |
| 231 | if (get_timer(0) - start > MAX_RETRY_MS) { | 231 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 232 | printf("%s: timedout waiting for softresetall!\n", | 232 | printf("%s: timedout waiting for softresetall!\n", |
| 233 | __func__); | 233 | __func__); |
| 234 | return TIMEOUT; | 234 | return TIMEOUT; |
| 235 | } | 235 | } |
| 236 | } | 236 | } |
| 237 | writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl); | 237 | writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl); |
| 238 | writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP, | 238 | writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP, |
| 239 | &mmc_base->capa); | 239 | &mmc_base->capa); |
| 240 | 240 | ||
| 241 | reg_val = readl(&mmc_base->con) & RESERVED_MASK; | 241 | reg_val = readl(&mmc_base->con) & RESERVED_MASK; |
| 242 | 242 | ||
| 243 | writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH | | 243 | writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH | |
| 244 | MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK | | 244 | MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK | |
| 245 | HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con); | 245 | HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con); |
| 246 | 246 | ||
| 247 | dsor = 240; | 247 | dsor = 240; |
| 248 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), | 248 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), |
| 249 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); | 249 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); |
| 250 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, | 250 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, |
| 251 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); | 251 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); |
| 252 | start = get_timer(0); | 252 | start = get_timer(0); |
| 253 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { | 253 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { |
| 254 | if (get_timer(0) - start > MAX_RETRY_MS) { | 254 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 255 | printf("%s: timedout waiting for ics!\n", __func__); | 255 | printf("%s: timedout waiting for ics!\n", __func__); |
| 256 | return TIMEOUT; | 256 | return TIMEOUT; |
| 257 | } | 257 | } |
| 258 | } | 258 | } |
| 259 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); | 259 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); |
| 260 | 260 | ||
| 261 | writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl); | 261 | writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl); |
| 262 | 262 | ||
| 263 | writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE | | 263 | writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE | |
| 264 | IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC, | 264 | IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC, |
| 265 | &mmc_base->ie); | 265 | &mmc_base->ie); |
| 266 | 266 | ||
| 267 | mmc_init_stream(mmc_base); | 267 | mmc_init_stream(mmc_base); |
| 268 | 268 | ||
| 269 | return 0; | 269 | return 0; |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | /* | 272 | /* |
| 273 | * MMC controller internal finite state machine reset | 273 | * MMC controller internal finite state machine reset |
| 274 | * | 274 | * |
| 275 | * Used to reset command or data internal state machines, using respectively | 275 | * Used to reset command or data internal state machines, using respectively |
| 276 | * SRC or SRD bit of SYSCTL register | 276 | * SRC or SRD bit of SYSCTL register |
| 277 | */ | 277 | */ |
| 278 | static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit) | 278 | static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit) |
| 279 | { | 279 | { |
| 280 | ulong start; | 280 | ulong start; |
| 281 | 281 | ||
| 282 | mmc_reg_out(&mmc_base->sysctl, bit, bit); | 282 | mmc_reg_out(&mmc_base->sysctl, bit, bit); |
| 283 | 283 | ||
| 284 | /* | 284 | /* |
| 285 | * CMD(DAT) lines reset procedures are slightly different | 285 | * CMD(DAT) lines reset procedures are slightly different |
| 286 | * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx). | 286 | * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx). |
| 287 | * According to OMAP3 TRM: | 287 | * According to OMAP3 TRM: |
| 288 | * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it | 288 | * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it |
| 289 | * returns to 0x0. | 289 | * returns to 0x0. |
| 290 | * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset | 290 | * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset |
| 291 | * procedure steps must be as follows: | 291 | * procedure steps must be as follows: |
| 292 | * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in | 292 | * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in |
| 293 | * MMCHS_SYSCTL register (SD_SYSCTL for AM335x). | 293 | * MMCHS_SYSCTL register (SD_SYSCTL for AM335x). |
| 294 | * 2. Poll the SRC(SRD) bit until it is set to 0x1. | 294 | * 2. Poll the SRC(SRD) bit until it is set to 0x1. |
| 295 | * 3. Wait until the SRC (SRD) bit returns to 0x0 | 295 | * 3. Wait until the SRC (SRD) bit returns to 0x0 |
| 296 | * (reset procedure is completed). | 296 | * (reset procedure is completed). |
| 297 | */ | 297 | */ |
| 298 | #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ | 298 | #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ |
| 299 | defined(CONFIG_AM33XX) | 299 | defined(CONFIG_AM33XX) |
| 300 | if (!(readl(&mmc_base->sysctl) & bit)) { | 300 | if (!(readl(&mmc_base->sysctl) & bit)) { |
| 301 | start = get_timer(0); | 301 | start = get_timer(0); |
| 302 | while (!(readl(&mmc_base->sysctl) & bit)) { | 302 | while (!(readl(&mmc_base->sysctl) & bit)) { |
| 303 | if (get_timer(0) - start > MAX_RETRY_MS) | 303 | if (get_timer(0) - start > MAX_RETRY_MS) |
| 304 | return; | 304 | return; |
| 305 | } | 305 | } |
| 306 | } | 306 | } |
| 307 | #endif | 307 | #endif |
| 308 | start = get_timer(0); | 308 | start = get_timer(0); |
| 309 | while ((readl(&mmc_base->sysctl) & bit) != 0) { | 309 | while ((readl(&mmc_base->sysctl) & bit) != 0) { |
| 310 | if (get_timer(0) - start > MAX_RETRY_MS) { | 310 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 311 | printf("%s: timedout waiting for sysctl %x to clear\n", | 311 | printf("%s: timedout waiting for sysctl %x to clear\n", |
| 312 | __func__, bit); | 312 | __func__, bit); |
| 313 | return; | 313 | return; |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | 318 | static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
| 319 | struct mmc_data *data) | 319 | struct mmc_data *data) |
| 320 | { | 320 | { |
| 321 | struct hsmmc *mmc_base; | 321 | struct hsmmc *mmc_base; |
| 322 | unsigned int flags, mmc_stat; | 322 | unsigned int flags, mmc_stat; |
| 323 | ulong start; | 323 | ulong start; |
| 324 | 324 | ||
| 325 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; | 325 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; |
| 326 | start = get_timer(0); | 326 | start = get_timer(0); |
| 327 | while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) { | 327 | while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) { |
| 328 | if (get_timer(0) - start > MAX_RETRY_MS) { | 328 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 329 | printf("%s: timedout waiting on cmd inhibit to clear\n", | 329 | printf("%s: timedout waiting on cmd inhibit to clear\n", |
| 330 | __func__); | 330 | __func__); |
| 331 | return TIMEOUT; | 331 | return TIMEOUT; |
| 332 | } | 332 | } |
| 333 | } | 333 | } |
| 334 | writel(0xFFFFFFFF, &mmc_base->stat); | 334 | writel(0xFFFFFFFF, &mmc_base->stat); |
| 335 | start = get_timer(0); | 335 | start = get_timer(0); |
| 336 | while (readl(&mmc_base->stat)) { | 336 | while (readl(&mmc_base->stat)) { |
| 337 | if (get_timer(0) - start > MAX_RETRY_MS) { | 337 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 338 | printf("%s: timedout waiting for STAT (%x) to clear\n", | 338 | printf("%s: timedout waiting for STAT (%x) to clear\n", |
| 339 | __func__, readl(&mmc_base->stat)); | 339 | __func__, readl(&mmc_base->stat)); |
| 340 | return TIMEOUT; | 340 | return TIMEOUT; |
| 341 | } | 341 | } |
| 342 | } | 342 | } |
| 343 | /* | 343 | /* |
| 344 | * CMDREG | 344 | * CMDREG |
| 345 | * CMDIDX[13:8] : Command index | 345 | * CMDIDX[13:8] : Command index |
| 346 | * DATAPRNT[5] : Data Present Select | 346 | * DATAPRNT[5] : Data Present Select |
| 347 | * ENCMDIDX[4] : Command Index Check Enable | 347 | * ENCMDIDX[4] : Command Index Check Enable |
| 348 | * ENCMDCRC[3] : Command CRC Check Enable | 348 | * ENCMDCRC[3] : Command CRC Check Enable |
| 349 | * RSPTYP[1:0] | 349 | * RSPTYP[1:0] |
| 350 | * 00 = No Response | 350 | * 00 = No Response |
| 351 | * 01 = Length 136 | 351 | * 01 = Length 136 |
| 352 | * 10 = Length 48 | 352 | * 10 = Length 48 |
| 353 | * 11 = Length 48 Check busy after response | 353 | * 11 = Length 48 Check busy after response |
| 354 | */ | 354 | */ |
| 355 | /* Delay added before checking the status of frq change | 355 | /* Delay added before checking the status of frq change |
| 356 | * retry not supported by mmc.c(core file) | 356 | * retry not supported by mmc.c(core file) |
| 357 | */ | 357 | */ |
| 358 | if (cmd->cmdidx == SD_CMD_APP_SEND_SCR) | 358 | if (cmd->cmdidx == SD_CMD_APP_SEND_SCR) |
| 359 | udelay(50000); /* wait 50 ms */ | 359 | udelay(50000); /* wait 50 ms */ |
| 360 | 360 | ||
| 361 | if (!(cmd->resp_type & MMC_RSP_PRESENT)) | 361 | if (!(cmd->resp_type & MMC_RSP_PRESENT)) |
| 362 | flags = 0; | 362 | flags = 0; |
| 363 | else if (cmd->resp_type & MMC_RSP_136) | 363 | else if (cmd->resp_type & MMC_RSP_136) |
| 364 | flags = RSP_TYPE_LGHT136 | CICE_NOCHECK; | 364 | flags = RSP_TYPE_LGHT136 | CICE_NOCHECK; |
| 365 | else if (cmd->resp_type & MMC_RSP_BUSY) | 365 | else if (cmd->resp_type & MMC_RSP_BUSY) |
| 366 | flags = RSP_TYPE_LGHT48B; | 366 | flags = RSP_TYPE_LGHT48B; |
| 367 | else | 367 | else |
| 368 | flags = RSP_TYPE_LGHT48; | 368 | flags = RSP_TYPE_LGHT48; |
| 369 | 369 | ||
| 370 | /* enable default flags */ | 370 | /* enable default flags */ |
| 371 | flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK | | 371 | flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK | |
| 372 | MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE); | 372 | MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE); |
| 373 | 373 | ||
| 374 | if (cmd->resp_type & MMC_RSP_CRC) | 374 | if (cmd->resp_type & MMC_RSP_CRC) |
| 375 | flags |= CCCE_CHECK; | 375 | flags |= CCCE_CHECK; |
| 376 | if (cmd->resp_type & MMC_RSP_OPCODE) | 376 | if (cmd->resp_type & MMC_RSP_OPCODE) |
| 377 | flags |= CICE_CHECK; | 377 | flags |= CICE_CHECK; |
| 378 | 378 | ||
| 379 | if (data) { | 379 | if (data) { |
| 380 | if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) || | 380 | if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) || |
| 381 | (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) { | 381 | (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) { |
| 382 | flags |= (MSBS_MULTIBLK | BCE_ENABLE); | 382 | flags |= (MSBS_MULTIBLK | BCE_ENABLE); |
| 383 | data->blocksize = 512; | 383 | data->blocksize = 512; |
| 384 | writel(data->blocksize | (data->blocks << 16), | 384 | writel(data->blocksize | (data->blocks << 16), |
| 385 | &mmc_base->blk); | 385 | &mmc_base->blk); |
| 386 | } else | 386 | } else |
| 387 | writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk); | 387 | writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk); |
| 388 | 388 | ||
| 389 | if (data->flags & MMC_DATA_READ) | 389 | if (data->flags & MMC_DATA_READ) |
| 390 | flags |= (DP_DATA | DDIR_READ); | 390 | flags |= (DP_DATA | DDIR_READ); |
| 391 | else | 391 | else |
| 392 | flags |= (DP_DATA | DDIR_WRITE); | 392 | flags |= (DP_DATA | DDIR_WRITE); |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | writel(cmd->cmdarg, &mmc_base->arg); | 395 | writel(cmd->cmdarg, &mmc_base->arg); |
| 396 | udelay(20); /* To fix "No status update" error on eMMC */ | 396 | udelay(20); /* To fix "No status update" error on eMMC */ |
| 397 | writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd); | 397 | writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd); |
| 398 | 398 | ||
| 399 | start = get_timer(0); | 399 | start = get_timer(0); |
| 400 | do { | 400 | do { |
| 401 | mmc_stat = readl(&mmc_base->stat); | 401 | mmc_stat = readl(&mmc_base->stat); |
| 402 | if (get_timer(0) - start > MAX_RETRY_MS) { | 402 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 403 | printf("%s : timeout: No status update\n", __func__); | 403 | printf("%s : timeout: No status update\n", __func__); |
| 404 | return TIMEOUT; | 404 | return TIMEOUT; |
| 405 | } | 405 | } |
| 406 | } while (!mmc_stat); | 406 | } while (!mmc_stat); |
| 407 | 407 | ||
| 408 | if ((mmc_stat & IE_CTO) != 0) { | 408 | if ((mmc_stat & IE_CTO) != 0) { |
| 409 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); | 409 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); |
| 410 | return TIMEOUT; | 410 | return TIMEOUT; |
| 411 | } else if ((mmc_stat & ERRI_MASK) != 0) | 411 | } else if ((mmc_stat & ERRI_MASK) != 0) |
| 412 | return -1; | 412 | return -1; |
| 413 | 413 | ||
| 414 | if (mmc_stat & CC_MASK) { | 414 | if (mmc_stat & CC_MASK) { |
| 415 | writel(CC_MASK, &mmc_base->stat); | 415 | writel(CC_MASK, &mmc_base->stat); |
| 416 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 416 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 417 | if (cmd->resp_type & MMC_RSP_136) { | 417 | if (cmd->resp_type & MMC_RSP_136) { |
| 418 | /* response type 2 */ | 418 | /* response type 2 */ |
| 419 | cmd->response[3] = readl(&mmc_base->rsp10); | 419 | cmd->response[3] = readl(&mmc_base->rsp10); |
| 420 | cmd->response[2] = readl(&mmc_base->rsp32); | 420 | cmd->response[2] = readl(&mmc_base->rsp32); |
| 421 | cmd->response[1] = readl(&mmc_base->rsp54); | 421 | cmd->response[1] = readl(&mmc_base->rsp54); |
| 422 | cmd->response[0] = readl(&mmc_base->rsp76); | 422 | cmd->response[0] = readl(&mmc_base->rsp76); |
| 423 | } else | 423 | } else |
| 424 | /* response types 1, 1b, 3, 4, 5, 6 */ | 424 | /* response types 1, 1b, 3, 4, 5, 6 */ |
| 425 | cmd->response[0] = readl(&mmc_base->rsp10); | 425 | cmd->response[0] = readl(&mmc_base->rsp10); |
| 426 | } | 426 | } |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | if (data && (data->flags & MMC_DATA_READ)) { | 429 | if (data && (data->flags & MMC_DATA_READ)) { |
| 430 | mmc_read_data(mmc_base, data->dest, | 430 | mmc_read_data(mmc_base, data->dest, |
| 431 | data->blocksize * data->blocks); | 431 | data->blocksize * data->blocks); |
| 432 | } else if (data && (data->flags & MMC_DATA_WRITE)) { | 432 | } else if (data && (data->flags & MMC_DATA_WRITE)) { |
| 433 | mmc_write_data(mmc_base, data->src, | 433 | mmc_write_data(mmc_base, data->src, |
| 434 | data->blocksize * data->blocks); | 434 | data->blocksize * data->blocks); |
| 435 | } | 435 | } |
| 436 | return 0; | 436 | return 0; |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size) | 439 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size) |
| 440 | { | 440 | { |
| 441 | unsigned int *output_buf = (unsigned int *)buf; | 441 | unsigned int *output_buf = (unsigned int *)buf; |
| 442 | unsigned int mmc_stat; | 442 | unsigned int mmc_stat; |
| 443 | unsigned int count; | 443 | unsigned int count; |
| 444 | 444 | ||
| 445 | /* | 445 | /* |
| 446 | * Start Polled Read | 446 | * Start Polled Read |
| 447 | */ | 447 | */ |
| 448 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; | 448 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; |
| 449 | count /= 4; | 449 | count /= 4; |
| 450 | 450 | ||
| 451 | while (size) { | 451 | while (size) { |
| 452 | ulong start = get_timer(0); | 452 | ulong start = get_timer(0); |
| 453 | do { | 453 | do { |
| 454 | mmc_stat = readl(&mmc_base->stat); | 454 | mmc_stat = readl(&mmc_base->stat); |
| 455 | if (get_timer(0) - start > MAX_RETRY_MS) { | 455 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 456 | printf("%s: timedout waiting for status!\n", | 456 | printf("%s: timedout waiting for status!\n", |
| 457 | __func__); | 457 | __func__); |
| 458 | return TIMEOUT; | 458 | return TIMEOUT; |
| 459 | } | 459 | } |
| 460 | } while (mmc_stat == 0); | 460 | } while (mmc_stat == 0); |
| 461 | 461 | ||
| 462 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) | 462 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) |
| 463 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); | 463 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); |
| 464 | 464 | ||
| 465 | if ((mmc_stat & ERRI_MASK) != 0) | 465 | if ((mmc_stat & ERRI_MASK) != 0) |
| 466 | return 1; | 466 | return 1; |
| 467 | 467 | ||
| 468 | if (mmc_stat & BRR_MASK) { | 468 | if (mmc_stat & BRR_MASK) { |
| 469 | unsigned int k; | 469 | unsigned int k; |
| 470 | 470 | ||
| 471 | writel(readl(&mmc_base->stat) | BRR_MASK, | 471 | writel(readl(&mmc_base->stat) | BRR_MASK, |
| 472 | &mmc_base->stat); | 472 | &mmc_base->stat); |
| 473 | for (k = 0; k < count; k++) { | 473 | for (k = 0; k < count; k++) { |
| 474 | *output_buf = readl(&mmc_base->data); | 474 | *output_buf = readl(&mmc_base->data); |
| 475 | output_buf++; | 475 | output_buf++; |
| 476 | } | 476 | } |
| 477 | size -= (count*4); | 477 | size -= (count*4); |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | if (mmc_stat & BWR_MASK) | 480 | if (mmc_stat & BWR_MASK) |
| 481 | writel(readl(&mmc_base->stat) | BWR_MASK, | 481 | writel(readl(&mmc_base->stat) | BWR_MASK, |
| 482 | &mmc_base->stat); | 482 | &mmc_base->stat); |
| 483 | 483 | ||
| 484 | if (mmc_stat & TC_MASK) { | 484 | if (mmc_stat & TC_MASK) { |
| 485 | writel(readl(&mmc_base->stat) | TC_MASK, | 485 | writel(readl(&mmc_base->stat) | TC_MASK, |
| 486 | &mmc_base->stat); | 486 | &mmc_base->stat); |
| 487 | break; | 487 | break; |
| 488 | } | 488 | } |
| 489 | } | 489 | } |
| 490 | return 0; | 490 | return 0; |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, | 493 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, |
| 494 | unsigned int size) | 494 | unsigned int size) |
| 495 | { | 495 | { |
| 496 | unsigned int *input_buf = (unsigned int *)buf; | 496 | unsigned int *input_buf = (unsigned int *)buf; |
| 497 | unsigned int mmc_stat; | 497 | unsigned int mmc_stat; |
| 498 | unsigned int count; | 498 | unsigned int count; |
| 499 | 499 | ||
| 500 | /* | 500 | /* |
| 501 | * Start Polled Write | 501 | * Start Polled Write |
| 502 | */ | 502 | */ |
| 503 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; | 503 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; |
| 504 | count /= 4; | 504 | count /= 4; |
| 505 | 505 | ||
| 506 | while (size) { | 506 | while (size) { |
| 507 | ulong start = get_timer(0); | 507 | ulong start = get_timer(0); |
| 508 | do { | 508 | do { |
| 509 | mmc_stat = readl(&mmc_base->stat); | 509 | mmc_stat = readl(&mmc_base->stat); |
| 510 | if (get_timer(0) - start > MAX_RETRY_MS) { | 510 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 511 | printf("%s: timedout waiting for status!\n", | 511 | printf("%s: timedout waiting for status!\n", |
| 512 | __func__); | 512 | __func__); |
| 513 | return TIMEOUT; | 513 | return TIMEOUT; |
| 514 | } | 514 | } |
| 515 | } while (mmc_stat == 0); | 515 | } while (mmc_stat == 0); |
| 516 | 516 | ||
| 517 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) | 517 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) |
| 518 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); | 518 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); |
| 519 | 519 | ||
| 520 | if ((mmc_stat & ERRI_MASK) != 0) | 520 | if ((mmc_stat & ERRI_MASK) != 0) |
| 521 | return 1; | 521 | return 1; |
| 522 | 522 | ||
| 523 | if (mmc_stat & BWR_MASK) { | 523 | if (mmc_stat & BWR_MASK) { |
| 524 | unsigned int k; | 524 | unsigned int k; |
| 525 | 525 | ||
| 526 | writel(readl(&mmc_base->stat) | BWR_MASK, | 526 | writel(readl(&mmc_base->stat) | BWR_MASK, |
| 527 | &mmc_base->stat); | 527 | &mmc_base->stat); |
| 528 | for (k = 0; k < count; k++) { | 528 | for (k = 0; k < count; k++) { |
| 529 | writel(*input_buf, &mmc_base->data); | 529 | writel(*input_buf, &mmc_base->data); |
| 530 | input_buf++; | 530 | input_buf++; |
| 531 | } | 531 | } |
| 532 | size -= (count*4); | 532 | size -= (count*4); |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | if (mmc_stat & BRR_MASK) | 535 | if (mmc_stat & BRR_MASK) |
| 536 | writel(readl(&mmc_base->stat) | BRR_MASK, | 536 | writel(readl(&mmc_base->stat) | BRR_MASK, |
| 537 | &mmc_base->stat); | 537 | &mmc_base->stat); |
| 538 | 538 | ||
| 539 | if (mmc_stat & TC_MASK) { | 539 | if (mmc_stat & TC_MASK) { |
| 540 | writel(readl(&mmc_base->stat) | TC_MASK, | 540 | writel(readl(&mmc_base->stat) | TC_MASK, |
| 541 | &mmc_base->stat); | 541 | &mmc_base->stat); |
| 542 | break; | 542 | break; |
| 543 | } | 543 | } |
| 544 | } | 544 | } |
| 545 | return 0; | 545 | return 0; |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | static void omap_hsmmc_set_ios(struct mmc *mmc) | 548 | static void omap_hsmmc_set_ios(struct mmc *mmc) |
| 549 | { | 549 | { |
| 550 | struct hsmmc *mmc_base; | 550 | struct hsmmc *mmc_base; |
| 551 | unsigned int dsor = 0; | 551 | unsigned int dsor = 0; |
| 552 | ulong start; | 552 | ulong start; |
| 553 | 553 | ||
| 554 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; | 554 | mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; |
| 555 | /* configue bus width */ | 555 | /* configue bus width */ |
| 556 | switch (mmc->bus_width) { | 556 | switch (mmc->bus_width) { |
| 557 | case 8: | 557 | case 8: |
| 558 | writel(readl(&mmc_base->con) | DTW_8_BITMODE, | 558 | writel(readl(&mmc_base->con) | DTW_8_BITMODE, |
| 559 | &mmc_base->con); | 559 | &mmc_base->con); |
| 560 | break; | 560 | break; |
| 561 | 561 | ||
| 562 | case 4: | 562 | case 4: |
| 563 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, | 563 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, |
| 564 | &mmc_base->con); | 564 | &mmc_base->con); |
| 565 | writel(readl(&mmc_base->hctl) | DTW_4_BITMODE, | 565 | writel(readl(&mmc_base->hctl) | DTW_4_BITMODE, |
| 566 | &mmc_base->hctl); | 566 | &mmc_base->hctl); |
| 567 | break; | 567 | break; |
| 568 | 568 | ||
| 569 | case 1: | 569 | case 1: |
| 570 | default: | 570 | default: |
| 571 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, | 571 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, |
| 572 | &mmc_base->con); | 572 | &mmc_base->con); |
| 573 | writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE, | 573 | writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE, |
| 574 | &mmc_base->hctl); | 574 | &mmc_base->hctl); |
| 575 | break; | 575 | break; |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | /* configure clock with 96Mhz system clock. | 578 | /* configure clock with 96Mhz system clock. |
| 579 | */ | 579 | */ |
| 580 | if (mmc->clock != 0) { | 580 | if (mmc->clock != 0) { |
| 581 | dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock); | 581 | dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock); |
| 582 | if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock) | 582 | if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock) |
| 583 | dsor++; | 583 | dsor++; |
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), | 586 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), |
| 587 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); | 587 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); |
| 588 | 588 | ||
| 589 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, | 589 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, |
| 590 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); | 590 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); |
| 591 | 591 | ||
| 592 | start = get_timer(0); | 592 | start = get_timer(0); |
| 593 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { | 593 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { |
| 594 | if (get_timer(0) - start > MAX_RETRY_MS) { | 594 | if (get_timer(0) - start > MAX_RETRY_MS) { |
| 595 | printf("%s: timedout waiting for ics!\n", __func__); | 595 | printf("%s: timedout waiting for ics!\n", __func__); |
| 596 | return; | 596 | return; |
| 597 | } | 597 | } |
| 598 | } | 598 | } |
| 599 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); | 599 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | #ifdef OMAP_HSMMC_USE_GPIO | 602 | #ifdef OMAP_HSMMC_USE_GPIO |
| 603 | static int omap_hsmmc_getcd(struct mmc *mmc) | 603 | static int omap_hsmmc_getcd(struct mmc *mmc) |
| 604 | { | 604 | { |
| 605 | struct omap_hsmmc_data *priv_data = mmc->priv; | 605 | struct omap_hsmmc_data *priv_data = mmc->priv; |
| 606 | int cd_gpio; | 606 | int cd_gpio; |
| 607 | 607 | ||
| 608 | /* if no CD return as 1 */ | 608 | /* if no CD return as 1 */ |
| 609 | cd_gpio = priv_data->cd_gpio; | 609 | cd_gpio = priv_data->cd_gpio; |
| 610 | if (cd_gpio < 0) | 610 | if (cd_gpio < 0) |
| 611 | return 1; | 611 | return 1; |
| 612 | 612 | ||
| 613 | /* NOTE: assumes card detect signal is active-low */ | 613 | /* NOTE: assumes card detect signal is active-low */ |
| 614 | return !gpio_get_value(cd_gpio); | 614 | return !gpio_get_value(cd_gpio); |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | static int omap_hsmmc_getwp(struct mmc *mmc) | 617 | static int omap_hsmmc_getwp(struct mmc *mmc) |
| 618 | { | 618 | { |
| 619 | struct omap_hsmmc_data *priv_data = mmc->priv; | 619 | struct omap_hsmmc_data *priv_data = mmc->priv; |
| 620 | int wp_gpio; | 620 | int wp_gpio; |
| 621 | 621 | ||
| 622 | /* if no WP return as 0 */ | 622 | /* if no WP return as 0 */ |
| 623 | wp_gpio = priv_data->wp_gpio; | 623 | wp_gpio = priv_data->wp_gpio; |
| 624 | if (wp_gpio < 0) | 624 | if (wp_gpio < 0) |
| 625 | return 0; | 625 | return 0; |
| 626 | 626 | ||
| 627 | /* NOTE: assumes write protect signal is active-high */ | 627 | /* NOTE: assumes write protect signal is active-high */ |
| 628 | return gpio_get_value(wp_gpio); | 628 | return gpio_get_value(wp_gpio); |
| 629 | } | 629 | } |
| 630 | #endif | 630 | #endif |
| 631 | 631 | ||
| 632 | static const struct mmc_ops omap_hsmmc_ops = { | 632 | static const struct mmc_ops omap_hsmmc_ops = { |
| 633 | .send_cmd = omap_hsmmc_send_cmd, | 633 | .send_cmd = omap_hsmmc_send_cmd, |
| 634 | .set_ios = omap_hsmmc_set_ios, | 634 | .set_ios = omap_hsmmc_set_ios, |
| 635 | .init = omap_hsmmc_init_setup, | 635 | .init = omap_hsmmc_init_setup, |
| 636 | #ifdef OMAP_HSMMC_USE_GPIO | 636 | #ifdef OMAP_HSMMC_USE_GPIO |
| 637 | .getcd = omap_hsmmc_getcd, | 637 | .getcd = omap_hsmmc_getcd, |
| 638 | .getwp = omap_hsmmc_getwp, | 638 | .getwp = omap_hsmmc_getwp, |
| 639 | #endif | 639 | #endif |
| 640 | }; | 640 | }; |
| 641 | 641 | ||
| 642 | int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, | 642 | int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, |
| 643 | int wp_gpio) | 643 | int wp_gpio) |
| 644 | { | 644 | { |
| 645 | struct mmc *mmc; | 645 | struct mmc *mmc; |
| 646 | struct omap_hsmmc_data *priv_data; | 646 | struct omap_hsmmc_data *priv_data; |
| 647 | struct mmc_config *cfg; | 647 | struct mmc_config *cfg; |
| 648 | uint host_caps_val; | 648 | uint host_caps_val; |
| 649 | 649 | ||
| 650 | priv_data = malloc(sizeof(*priv_data)); | 650 | priv_data = malloc(sizeof(*priv_data)); |
| 651 | if (priv_data == NULL) | 651 | if (priv_data == NULL) |
| 652 | return -1; | 652 | return -1; |
| 653 | 653 | ||
| 654 | host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS | | 654 | host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 655 | MMC_MODE_HC; | ||
| 656 | 655 | ||
| 657 | switch (dev_index) { | 656 | switch (dev_index) { |
| 658 | case 0: | 657 | case 0: |
| 659 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; | 658 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; |
| 660 | break; | 659 | break; |
| 661 | #ifdef OMAP_HSMMC2_BASE | 660 | #ifdef OMAP_HSMMC2_BASE |
| 662 | case 1: | 661 | case 1: |
| 663 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; | 662 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; |
| 664 | #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ | 663 | #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ |
| 665 | defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && \ | 664 | defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && \ |
| 666 | defined(CONFIG_HSMMC2_8BIT) | 665 | defined(CONFIG_HSMMC2_8BIT) |
| 667 | /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */ | 666 | /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */ |
| 668 | host_caps_val |= MMC_MODE_8BIT; | 667 | host_caps_val |= MMC_MODE_8BIT; |
| 669 | #endif | 668 | #endif |
| 670 | break; | 669 | break; |
| 671 | #endif | 670 | #endif |
| 672 | #ifdef OMAP_HSMMC3_BASE | 671 | #ifdef OMAP_HSMMC3_BASE |
| 673 | case 2: | 672 | case 2: |
| 674 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE; | 673 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE; |
| 675 | #if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT) | 674 | #if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT) |
| 676 | /* Enable 8-bit interface for eMMC on DRA7XX */ | 675 | /* Enable 8-bit interface for eMMC on DRA7XX */ |
| 677 | host_caps_val |= MMC_MODE_8BIT; | 676 | host_caps_val |= MMC_MODE_8BIT; |
| 678 | #endif | 677 | #endif |
| 679 | break; | 678 | break; |
| 680 | #endif | 679 | #endif |
| 681 | default: | 680 | default: |
| 682 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; | 681 | priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; |
| 683 | return 1; | 682 | return 1; |
| 684 | } | 683 | } |
| 685 | #ifdef OMAP_HSMMC_USE_GPIO | 684 | #ifdef OMAP_HSMMC_USE_GPIO |
| 686 | /* on error gpio values are set to -1, which is what we want */ | 685 | /* on error gpio values are set to -1, which is what we want */ |
| 687 | priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd"); | 686 | priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd"); |
| 688 | priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp"); | 687 | priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp"); |
| 689 | #endif | 688 | #endif |
| 690 | 689 | ||
| 691 | cfg = &priv_data->cfg; | 690 | cfg = &priv_data->cfg; |
| 692 | 691 | ||
| 693 | cfg->name = "OMAP SD/MMC"; | 692 | cfg->name = "OMAP SD/MMC"; |
| 694 | cfg->ops = &omap_hsmmc_ops; | 693 | cfg->ops = &omap_hsmmc_ops; |
| 695 | 694 | ||
| 696 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | 695 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
| 697 | cfg->host_caps = host_caps_val & ~host_caps_mask; | 696 | cfg->host_caps = host_caps_val & ~host_caps_mask; |
| 698 | 697 | ||
| 699 | cfg->f_min = 400000; | 698 | cfg->f_min = 400000; |
| 700 | 699 | ||
| 701 | if (f_max != 0) | 700 | if (f_max != 0) |
| 702 | cfg->f_max = f_max; | 701 | cfg->f_max = f_max; |
| 703 | else { | 702 | else { |
| 704 | if (cfg->host_caps & MMC_MODE_HS) { | 703 | if (cfg->host_caps & MMC_MODE_HS) { |
| 705 | if (cfg->host_caps & MMC_MODE_HS_52MHz) | 704 | if (cfg->host_caps & MMC_MODE_HS_52MHz) |
| 706 | cfg->f_max = 52000000; | 705 | cfg->f_max = 52000000; |
| 707 | else | 706 | else |
| 708 | cfg->f_max = 26000000; | 707 | cfg->f_max = 26000000; |
| 709 | } else | 708 | } else |
| 710 | cfg->f_max = 20000000; | 709 | cfg->f_max = 20000000; |
| 711 | } | 710 | } |
| 712 | 711 | ||
| 713 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 712 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
| 714 | 713 | ||
| 715 | #if defined(CONFIG_OMAP34XX) | 714 | #if defined(CONFIG_OMAP34XX) |
| 716 | /* | 715 | /* |
| 717 | * Silicon revs 2.1 and older do not support multiblock transfers. | 716 | * Silicon revs 2.1 and older do not support multiblock transfers. |
| 718 | */ | 717 | */ |
| 719 | if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21)) | 718 | if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21)) |
| 720 | cfg->b_max = 1; | 719 | cfg->b_max = 1; |
| 721 | #endif | 720 | #endif |
| 722 | mmc = mmc_create(cfg, priv_data); | 721 | mmc = mmc_create(cfg, priv_data); |
| 723 | if (mmc == NULL) | 722 | if (mmc == NULL) |
| 724 | return -1; | 723 | return -1; |
| 725 | 724 | ||
| 726 | return 0; | 725 | return 0; |
| 727 | } | 726 | } |
| 728 | 727 |
drivers/mmc/s3c_sdi.c
| 1 | /* | 1 | /* |
| 2 | * S3C24xx SD/MMC driver | 2 | * S3C24xx SD/MMC driver |
| 3 | * | 3 | * |
| 4 | * Based on OpenMoko S3C24xx driver by Harald Welte <laforge@openmoko.org> | 4 | * Based on OpenMoko S3C24xx driver by Harald Welte <laforge@openmoko.org> |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2014 Marek Vasut <marex@denx.de> | 6 | * Copyright (C) 2014 Marek Vasut <marex@denx.de> |
| 7 | * | 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <common.h> | 11 | #include <common.h> |
| 12 | #include <malloc.h> | 12 | #include <malloc.h> |
| 13 | #include <mmc.h> | 13 | #include <mmc.h> |
| 14 | #include <errno.h> | 14 | #include <errno.h> |
| 15 | #include <asm/arch/s3c24x0_cpu.h> | 15 | #include <asm/arch/s3c24x0_cpu.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | #include <asm/unaligned.h> | 17 | #include <asm/unaligned.h> |
| 18 | 18 | ||
| 19 | #define S3C2440_SDICON_SDRESET (1 << 8) | 19 | #define S3C2440_SDICON_SDRESET (1 << 8) |
| 20 | #define S3C2410_SDICON_FIFORESET (1 << 1) | 20 | #define S3C2410_SDICON_FIFORESET (1 << 1) |
| 21 | #define S3C2410_SDICON_CLOCKTYPE (1 << 0) | 21 | #define S3C2410_SDICON_CLOCKTYPE (1 << 0) |
| 22 | 22 | ||
| 23 | #define S3C2410_SDICMDCON_LONGRSP (1 << 10) | 23 | #define S3C2410_SDICMDCON_LONGRSP (1 << 10) |
| 24 | #define S3C2410_SDICMDCON_WAITRSP (1 << 9) | 24 | #define S3C2410_SDICMDCON_WAITRSP (1 << 9) |
| 25 | #define S3C2410_SDICMDCON_CMDSTART (1 << 8) | 25 | #define S3C2410_SDICMDCON_CMDSTART (1 << 8) |
| 26 | #define S3C2410_SDICMDCON_SENDERHOST (1 << 6) | 26 | #define S3C2410_SDICMDCON_SENDERHOST (1 << 6) |
| 27 | #define S3C2410_SDICMDCON_INDEX 0x3f | 27 | #define S3C2410_SDICMDCON_INDEX 0x3f |
| 28 | 28 | ||
| 29 | #define S3C2410_SDICMDSTAT_CRCFAIL (1 << 12) | 29 | #define S3C2410_SDICMDSTAT_CRCFAIL (1 << 12) |
| 30 | #define S3C2410_SDICMDSTAT_CMDSENT (1 << 11) | 30 | #define S3C2410_SDICMDSTAT_CMDSENT (1 << 11) |
| 31 | #define S3C2410_SDICMDSTAT_CMDTIMEOUT (1 << 10) | 31 | #define S3C2410_SDICMDSTAT_CMDTIMEOUT (1 << 10) |
| 32 | #define S3C2410_SDICMDSTAT_RSPFIN (1 << 9) | 32 | #define S3C2410_SDICMDSTAT_RSPFIN (1 << 9) |
| 33 | 33 | ||
| 34 | #define S3C2440_SDIDCON_DS_WORD (2 << 22) | 34 | #define S3C2440_SDIDCON_DS_WORD (2 << 22) |
| 35 | #define S3C2410_SDIDCON_TXAFTERRESP (1 << 20) | 35 | #define S3C2410_SDIDCON_TXAFTERRESP (1 << 20) |
| 36 | #define S3C2410_SDIDCON_RXAFTERCMD (1 << 19) | 36 | #define S3C2410_SDIDCON_RXAFTERCMD (1 << 19) |
| 37 | #define S3C2410_SDIDCON_BLOCKMODE (1 << 17) | 37 | #define S3C2410_SDIDCON_BLOCKMODE (1 << 17) |
| 38 | #define S3C2410_SDIDCON_WIDEBUS (1 << 16) | 38 | #define S3C2410_SDIDCON_WIDEBUS (1 << 16) |
| 39 | #define S3C2440_SDIDCON_DATSTART (1 << 14) | 39 | #define S3C2440_SDIDCON_DATSTART (1 << 14) |
| 40 | #define S3C2410_SDIDCON_XFER_RXSTART (2 << 12) | 40 | #define S3C2410_SDIDCON_XFER_RXSTART (2 << 12) |
| 41 | #define S3C2410_SDIDCON_XFER_TXSTART (3 << 12) | 41 | #define S3C2410_SDIDCON_XFER_TXSTART (3 << 12) |
| 42 | #define S3C2410_SDIDCON_BLKNUM 0x7ff | 42 | #define S3C2410_SDIDCON_BLKNUM 0x7ff |
| 43 | 43 | ||
| 44 | #define S3C2410_SDIDSTA_FIFOFAIL (1 << 8) | 44 | #define S3C2410_SDIDSTA_FIFOFAIL (1 << 8) |
| 45 | #define S3C2410_SDIDSTA_CRCFAIL (1 << 7) | 45 | #define S3C2410_SDIDSTA_CRCFAIL (1 << 7) |
| 46 | #define S3C2410_SDIDSTA_RXCRCFAIL (1 << 6) | 46 | #define S3C2410_SDIDSTA_RXCRCFAIL (1 << 6) |
| 47 | #define S3C2410_SDIDSTA_DATATIMEOUT (1 << 5) | 47 | #define S3C2410_SDIDSTA_DATATIMEOUT (1 << 5) |
| 48 | #define S3C2410_SDIDSTA_XFERFINISH (1 << 4) | 48 | #define S3C2410_SDIDSTA_XFERFINISH (1 << 4) |
| 49 | 49 | ||
| 50 | #define S3C2410_SDIFSTA_TFHALF (1 << 11) | 50 | #define S3C2410_SDIFSTA_TFHALF (1 << 11) |
| 51 | #define S3C2410_SDIFSTA_COUNTMASK 0x7f | 51 | #define S3C2410_SDIFSTA_COUNTMASK 0x7f |
| 52 | 52 | ||
| 53 | /* | 53 | /* |
| 54 | * WARNING: We only support one SD IP block. | 54 | * WARNING: We only support one SD IP block. |
| 55 | * NOTE: It's not likely there will ever exist an S3C24xx with two, | 55 | * NOTE: It's not likely there will ever exist an S3C24xx with two, |
| 56 | * at least not in this universe all right. | 56 | * at least not in this universe all right. |
| 57 | */ | 57 | */ |
| 58 | static int wide_bus; | 58 | static int wide_bus; |
| 59 | 59 | ||
| 60 | static int | 60 | static int |
| 61 | s3cmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | 61 | s3cmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) |
| 62 | { | 62 | { |
| 63 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); | 63 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); |
| 64 | uint32_t sdiccon, sdicsta, sdidcon, sdidsta, sdidat, sdifsta; | 64 | uint32_t sdiccon, sdicsta, sdidcon, sdidsta, sdidat, sdifsta; |
| 65 | uint32_t sdicsta_wait_bit = S3C2410_SDICMDSTAT_CMDSENT; | 65 | uint32_t sdicsta_wait_bit = S3C2410_SDICMDSTAT_CMDSENT; |
| 66 | unsigned int timeout = 100000; | 66 | unsigned int timeout = 100000; |
| 67 | int ret = 0, xfer_len, data_offset = 0; | 67 | int ret = 0, xfer_len, data_offset = 0; |
| 68 | const uint32_t sdidsta_err_mask = S3C2410_SDIDSTA_FIFOFAIL | | 68 | const uint32_t sdidsta_err_mask = S3C2410_SDIDSTA_FIFOFAIL | |
| 69 | S3C2410_SDIDSTA_CRCFAIL | S3C2410_SDIDSTA_RXCRCFAIL | | 69 | S3C2410_SDIDSTA_CRCFAIL | S3C2410_SDIDSTA_RXCRCFAIL | |
| 70 | S3C2410_SDIDSTA_DATATIMEOUT; | 70 | S3C2410_SDIDSTA_DATATIMEOUT; |
| 71 | 71 | ||
| 72 | 72 | ||
| 73 | writel(0xffffffff, &sdi_regs->sdicsta); | 73 | writel(0xffffffff, &sdi_regs->sdicsta); |
| 74 | writel(0xffffffff, &sdi_regs->sdidsta); | 74 | writel(0xffffffff, &sdi_regs->sdidsta); |
| 75 | writel(0xffffffff, &sdi_regs->sdifsta); | 75 | writel(0xffffffff, &sdi_regs->sdifsta); |
| 76 | 76 | ||
| 77 | /* Set up data transfer (if applicable). */ | 77 | /* Set up data transfer (if applicable). */ |
| 78 | if (data) { | 78 | if (data) { |
| 79 | writel(data->blocksize, &sdi_regs->sdibsize); | 79 | writel(data->blocksize, &sdi_regs->sdibsize); |
| 80 | 80 | ||
| 81 | sdidcon = data->blocks & S3C2410_SDIDCON_BLKNUM; | 81 | sdidcon = data->blocks & S3C2410_SDIDCON_BLKNUM; |
| 82 | sdidcon |= S3C2410_SDIDCON_BLOCKMODE; | 82 | sdidcon |= S3C2410_SDIDCON_BLOCKMODE; |
| 83 | #if defined(CONFIG_S3C2440) | 83 | #if defined(CONFIG_S3C2440) |
| 84 | sdidcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART; | 84 | sdidcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART; |
| 85 | #endif | 85 | #endif |
| 86 | if (wide_bus) | 86 | if (wide_bus) |
| 87 | sdidcon |= S3C2410_SDIDCON_WIDEBUS; | 87 | sdidcon |= S3C2410_SDIDCON_WIDEBUS; |
| 88 | 88 | ||
| 89 | if (data->flags & MMC_DATA_READ) { | 89 | if (data->flags & MMC_DATA_READ) { |
| 90 | sdidcon |= S3C2410_SDIDCON_RXAFTERCMD; | 90 | sdidcon |= S3C2410_SDIDCON_RXAFTERCMD; |
| 91 | sdidcon |= S3C2410_SDIDCON_XFER_RXSTART; | 91 | sdidcon |= S3C2410_SDIDCON_XFER_RXSTART; |
| 92 | } else { | 92 | } else { |
| 93 | sdidcon |= S3C2410_SDIDCON_TXAFTERRESP; | 93 | sdidcon |= S3C2410_SDIDCON_TXAFTERRESP; |
| 94 | sdidcon |= S3C2410_SDIDCON_XFER_TXSTART; | 94 | sdidcon |= S3C2410_SDIDCON_XFER_TXSTART; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | writel(sdidcon, &sdi_regs->sdidcon); | 97 | writel(sdidcon, &sdi_regs->sdidcon); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /* Write CMD arg. */ | 100 | /* Write CMD arg. */ |
| 101 | writel(cmd->cmdarg, &sdi_regs->sdicarg); | 101 | writel(cmd->cmdarg, &sdi_regs->sdicarg); |
| 102 | 102 | ||
| 103 | /* Write CMD index. */ | 103 | /* Write CMD index. */ |
| 104 | sdiccon = cmd->cmdidx & S3C2410_SDICMDCON_INDEX; | 104 | sdiccon = cmd->cmdidx & S3C2410_SDICMDCON_INDEX; |
| 105 | sdiccon |= S3C2410_SDICMDCON_SENDERHOST; | 105 | sdiccon |= S3C2410_SDICMDCON_SENDERHOST; |
| 106 | sdiccon |= S3C2410_SDICMDCON_CMDSTART; | 106 | sdiccon |= S3C2410_SDICMDCON_CMDSTART; |
| 107 | 107 | ||
| 108 | /* Command with short response. */ | 108 | /* Command with short response. */ |
| 109 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 109 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 110 | sdiccon |= S3C2410_SDICMDCON_WAITRSP; | 110 | sdiccon |= S3C2410_SDICMDCON_WAITRSP; |
| 111 | sdicsta_wait_bit = S3C2410_SDICMDSTAT_RSPFIN; | 111 | sdicsta_wait_bit = S3C2410_SDICMDSTAT_RSPFIN; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | /* Command with long response. */ | 114 | /* Command with long response. */ |
| 115 | if (cmd->resp_type & MMC_RSP_136) | 115 | if (cmd->resp_type & MMC_RSP_136) |
| 116 | sdiccon |= S3C2410_SDICMDCON_LONGRSP; | 116 | sdiccon |= S3C2410_SDICMDCON_LONGRSP; |
| 117 | 117 | ||
| 118 | /* Start the command. */ | 118 | /* Start the command. */ |
| 119 | writel(sdiccon, &sdi_regs->sdiccon); | 119 | writel(sdiccon, &sdi_regs->sdiccon); |
| 120 | 120 | ||
| 121 | /* Wait for the command to complete or for response. */ | 121 | /* Wait for the command to complete or for response. */ |
| 122 | for (timeout = 100000; timeout; timeout--) { | 122 | for (timeout = 100000; timeout; timeout--) { |
| 123 | sdicsta = readl(&sdi_regs->sdicsta); | 123 | sdicsta = readl(&sdi_regs->sdicsta); |
| 124 | if (sdicsta & sdicsta_wait_bit) | 124 | if (sdicsta & sdicsta_wait_bit) |
| 125 | break; | 125 | break; |
| 126 | 126 | ||
| 127 | if (sdicsta & S3C2410_SDICMDSTAT_CMDTIMEOUT) | 127 | if (sdicsta & S3C2410_SDICMDSTAT_CMDTIMEOUT) |
| 128 | timeout = 1; | 128 | timeout = 1; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /* Clean the status bits. */ | 131 | /* Clean the status bits. */ |
| 132 | setbits_le32(&sdi_regs->sdicsta, 0xf << 9); | 132 | setbits_le32(&sdi_regs->sdicsta, 0xf << 9); |
| 133 | 133 | ||
| 134 | if (!timeout) { | 134 | if (!timeout) { |
| 135 | puts("S3C SDI: Command timed out!\n"); | 135 | puts("S3C SDI: Command timed out!\n"); |
| 136 | ret = TIMEOUT; | 136 | ret = TIMEOUT; |
| 137 | goto error; | 137 | goto error; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | /* Read out the response. */ | 140 | /* Read out the response. */ |
| 141 | if (cmd->resp_type & MMC_RSP_136) { | 141 | if (cmd->resp_type & MMC_RSP_136) { |
| 142 | cmd->response[0] = readl(&sdi_regs->sdirsp0); | 142 | cmd->response[0] = readl(&sdi_regs->sdirsp0); |
| 143 | cmd->response[1] = readl(&sdi_regs->sdirsp1); | 143 | cmd->response[1] = readl(&sdi_regs->sdirsp1); |
| 144 | cmd->response[2] = readl(&sdi_regs->sdirsp2); | 144 | cmd->response[2] = readl(&sdi_regs->sdirsp2); |
| 145 | cmd->response[3] = readl(&sdi_regs->sdirsp3); | 145 | cmd->response[3] = readl(&sdi_regs->sdirsp3); |
| 146 | } else { | 146 | } else { |
| 147 | cmd->response[0] = readl(&sdi_regs->sdirsp0); | 147 | cmd->response[0] = readl(&sdi_regs->sdirsp0); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | /* If there are no data, we're done. */ | 150 | /* If there are no data, we're done. */ |
| 151 | if (!data) | 151 | if (!data) |
| 152 | return 0; | 152 | return 0; |
| 153 | 153 | ||
| 154 | xfer_len = data->blocksize * data->blocks; | 154 | xfer_len = data->blocksize * data->blocks; |
| 155 | 155 | ||
| 156 | while (xfer_len > 0) { | 156 | while (xfer_len > 0) { |
| 157 | sdidsta = readl(&sdi_regs->sdidsta); | 157 | sdidsta = readl(&sdi_regs->sdidsta); |
| 158 | sdifsta = readl(&sdi_regs->sdifsta); | 158 | sdifsta = readl(&sdi_regs->sdifsta); |
| 159 | 159 | ||
| 160 | if (sdidsta & sdidsta_err_mask) { | 160 | if (sdidsta & sdidsta_err_mask) { |
| 161 | printf("S3C SDI: Data error (sdta=0x%08x)\n", sdidsta); | 161 | printf("S3C SDI: Data error (sdta=0x%08x)\n", sdidsta); |
| 162 | ret = -EIO; | 162 | ret = -EIO; |
| 163 | goto error; | 163 | goto error; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | if (data->flags & MMC_DATA_READ) { | 166 | if (data->flags & MMC_DATA_READ) { |
| 167 | if ((sdifsta & S3C2410_SDIFSTA_COUNTMASK) < 4) | 167 | if ((sdifsta & S3C2410_SDIFSTA_COUNTMASK) < 4) |
| 168 | continue; | 168 | continue; |
| 169 | sdidat = readl(&sdi_regs->sdidat); | 169 | sdidat = readl(&sdi_regs->sdidat); |
| 170 | put_unaligned_le32(sdidat, data->dest + data_offset); | 170 | put_unaligned_le32(sdidat, data->dest + data_offset); |
| 171 | } else { /* Write */ | 171 | } else { /* Write */ |
| 172 | /* TX FIFO half full. */ | 172 | /* TX FIFO half full. */ |
| 173 | if (!(sdifsta & S3C2410_SDIFSTA_TFHALF)) | 173 | if (!(sdifsta & S3C2410_SDIFSTA_TFHALF)) |
| 174 | continue; | 174 | continue; |
| 175 | 175 | ||
| 176 | /* TX FIFO is below 32b full, write. */ | 176 | /* TX FIFO is below 32b full, write. */ |
| 177 | sdidat = get_unaligned_le32(data->src + data_offset); | 177 | sdidat = get_unaligned_le32(data->src + data_offset); |
| 178 | writel(sdidat, &sdi_regs->sdidat); | 178 | writel(sdidat, &sdi_regs->sdidat); |
| 179 | } | 179 | } |
| 180 | data_offset += 4; | 180 | data_offset += 4; |
| 181 | xfer_len -= 4; | 181 | xfer_len -= 4; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /* Wait for the command to complete or for response. */ | 184 | /* Wait for the command to complete or for response. */ |
| 185 | for (timeout = 100000; timeout; timeout--) { | 185 | for (timeout = 100000; timeout; timeout--) { |
| 186 | sdidsta = readl(&sdi_regs->sdidsta); | 186 | sdidsta = readl(&sdi_regs->sdidsta); |
| 187 | if (sdidsta & S3C2410_SDIDSTA_XFERFINISH) | 187 | if (sdidsta & S3C2410_SDIDSTA_XFERFINISH) |
| 188 | break; | 188 | break; |
| 189 | 189 | ||
| 190 | if (sdidsta & S3C2410_SDIDSTA_DATATIMEOUT) | 190 | if (sdidsta & S3C2410_SDIDSTA_DATATIMEOUT) |
| 191 | timeout = 1; | 191 | timeout = 1; |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | /* Clear status bits. */ | 194 | /* Clear status bits. */ |
| 195 | writel(0x6f8, &sdi_regs->sdidsta); | 195 | writel(0x6f8, &sdi_regs->sdidsta); |
| 196 | 196 | ||
| 197 | if (!timeout) { | 197 | if (!timeout) { |
| 198 | puts("S3C SDI: Command timed out!\n"); | 198 | puts("S3C SDI: Command timed out!\n"); |
| 199 | ret = TIMEOUT; | 199 | ret = TIMEOUT; |
| 200 | goto error; | 200 | goto error; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | writel(0, &sdi_regs->sdidcon); | 203 | writel(0, &sdi_regs->sdidcon); |
| 204 | 204 | ||
| 205 | return 0; | 205 | return 0; |
| 206 | error: | 206 | error: |
| 207 | return ret; | 207 | return ret; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static void s3cmmc_set_ios(struct mmc *mmc) | 210 | static void s3cmmc_set_ios(struct mmc *mmc) |
| 211 | { | 211 | { |
| 212 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); | 212 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); |
| 213 | uint32_t divider = 0; | 213 | uint32_t divider = 0; |
| 214 | 214 | ||
| 215 | wide_bus = (mmc->bus_width == 4); | 215 | wide_bus = (mmc->bus_width == 4); |
| 216 | 216 | ||
| 217 | if (!mmc->clock) | 217 | if (!mmc->clock) |
| 218 | return; | 218 | return; |
| 219 | 219 | ||
| 220 | divider = DIV_ROUND_UP(get_PCLK(), mmc->clock); | 220 | divider = DIV_ROUND_UP(get_PCLK(), mmc->clock); |
| 221 | if (divider) | 221 | if (divider) |
| 222 | divider--; | 222 | divider--; |
| 223 | 223 | ||
| 224 | writel(divider, &sdi_regs->sdipre); | 224 | writel(divider, &sdi_regs->sdipre); |
| 225 | mdelay(125); | 225 | mdelay(125); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | static int s3cmmc_init(struct mmc *mmc) | 228 | static int s3cmmc_init(struct mmc *mmc) |
| 229 | { | 229 | { |
| 230 | struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); | 230 | struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); |
| 231 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); | 231 | struct s3c24x0_sdi *sdi_regs = s3c24x0_get_base_sdi(); |
| 232 | 232 | ||
| 233 | /* Start the clock. */ | 233 | /* Start the clock. */ |
| 234 | setbits_le32(&clk_power->clkcon, 1 << 9); | 234 | setbits_le32(&clk_power->clkcon, 1 << 9); |
| 235 | 235 | ||
| 236 | #if defined(CONFIG_S3C2440) | 236 | #if defined(CONFIG_S3C2440) |
| 237 | writel(S3C2440_SDICON_SDRESET, &sdi_regs->sdicon); | 237 | writel(S3C2440_SDICON_SDRESET, &sdi_regs->sdicon); |
| 238 | mdelay(10); | 238 | mdelay(10); |
| 239 | writel(0x7fffff, &sdi_regs->sdidtimer); | 239 | writel(0x7fffff, &sdi_regs->sdidtimer); |
| 240 | #else | 240 | #else |
| 241 | writel(0xffff, &sdi_regs->sdidtimer); | 241 | writel(0xffff, &sdi_regs->sdidtimer); |
| 242 | #endif | 242 | #endif |
| 243 | writel(MMC_MAX_BLOCK_LEN, &sdi_regs->sdibsize); | 243 | writel(MMC_MAX_BLOCK_LEN, &sdi_regs->sdibsize); |
| 244 | writel(0x0, &sdi_regs->sdiimsk); | 244 | writel(0x0, &sdi_regs->sdiimsk); |
| 245 | 245 | ||
| 246 | writel(S3C2410_SDICON_FIFORESET | S3C2410_SDICON_CLOCKTYPE, | 246 | writel(S3C2410_SDICON_FIFORESET | S3C2410_SDICON_CLOCKTYPE, |
| 247 | &sdi_regs->sdicon); | 247 | &sdi_regs->sdicon); |
| 248 | 248 | ||
| 249 | mdelay(125); | 249 | mdelay(125); |
| 250 | 250 | ||
| 251 | return 0; | 251 | return 0; |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | struct s3cmmc_priv { | 254 | struct s3cmmc_priv { |
| 255 | struct mmc_config cfg; | 255 | struct mmc_config cfg; |
| 256 | int (*getcd)(struct mmc *); | 256 | int (*getcd)(struct mmc *); |
| 257 | int (*getwp)(struct mmc *); | 257 | int (*getwp)(struct mmc *); |
| 258 | }; | 258 | }; |
| 259 | 259 | ||
| 260 | static int s3cmmc_getcd(struct mmc *mmc) | 260 | static int s3cmmc_getcd(struct mmc *mmc) |
| 261 | { | 261 | { |
| 262 | struct s3cmmc_priv *priv = mmc->priv; | 262 | struct s3cmmc_priv *priv = mmc->priv; |
| 263 | if (priv->getcd) | 263 | if (priv->getcd) |
| 264 | return priv->getcd(mmc); | 264 | return priv->getcd(mmc); |
| 265 | else | 265 | else |
| 266 | return 0; | 266 | return 0; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | static int s3cmmc_getwp(struct mmc *mmc) | 269 | static int s3cmmc_getwp(struct mmc *mmc) |
| 270 | { | 270 | { |
| 271 | struct s3cmmc_priv *priv = mmc->priv; | 271 | struct s3cmmc_priv *priv = mmc->priv; |
| 272 | if (priv->getwp) | 272 | if (priv->getwp) |
| 273 | return priv->getwp(mmc); | 273 | return priv->getwp(mmc); |
| 274 | else | 274 | else |
| 275 | return 0; | 275 | return 0; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | static const struct mmc_ops s3cmmc_ops = { | 278 | static const struct mmc_ops s3cmmc_ops = { |
| 279 | .send_cmd = s3cmmc_send_cmd, | 279 | .send_cmd = s3cmmc_send_cmd, |
| 280 | .set_ios = s3cmmc_set_ios, | 280 | .set_ios = s3cmmc_set_ios, |
| 281 | .init = s3cmmc_init, | 281 | .init = s3cmmc_init, |
| 282 | .getcd = s3cmmc_getcd, | 282 | .getcd = s3cmmc_getcd, |
| 283 | .getwp = s3cmmc_getwp, | 283 | .getwp = s3cmmc_getwp, |
| 284 | }; | 284 | }; |
| 285 | 285 | ||
| 286 | int s3cmmc_initialize(bd_t *bis, int (*getcd)(struct mmc *), | 286 | int s3cmmc_initialize(bd_t *bis, int (*getcd)(struct mmc *), |
| 287 | int (*getwp)(struct mmc *)) | 287 | int (*getwp)(struct mmc *)) |
| 288 | { | 288 | { |
| 289 | struct s3cmmc_priv *priv; | 289 | struct s3cmmc_priv *priv; |
| 290 | struct mmc *mmc; | 290 | struct mmc *mmc; |
| 291 | struct mmc_config *cfg; | 291 | struct mmc_config *cfg; |
| 292 | 292 | ||
| 293 | priv = calloc(1, sizeof(*priv)); | 293 | priv = calloc(1, sizeof(*priv)); |
| 294 | if (!priv) | 294 | if (!priv) |
| 295 | return -ENOMEM; | 295 | return -ENOMEM; |
| 296 | cfg = &priv->cfg; | 296 | cfg = &priv->cfg; |
| 297 | 297 | ||
| 298 | cfg->name = "S3C MMC"; | 298 | cfg->name = "S3C MMC"; |
| 299 | cfg->ops = &s3cmmc_ops; | 299 | cfg->ops = &s3cmmc_ops; |
| 300 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; | 300 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
| 301 | cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HC | MMC_MODE_HS; | 301 | cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS; |
| 302 | cfg->f_min = 400000; | 302 | cfg->f_min = 400000; |
| 303 | cfg->f_max = get_PCLK() / 2; | 303 | cfg->f_max = get_PCLK() / 2; |
| 304 | cfg->b_max = 0x80; | 304 | cfg->b_max = 0x80; |
| 305 | 305 | ||
| 306 | #if defined(CONFIG_S3C2410) | 306 | #if defined(CONFIG_S3C2410) |
| 307 | /* | 307 | /* |
| 308 | * S3C2410 has some bug that prevents reliable | 308 | * S3C2410 has some bug that prevents reliable |
| 309 | * operation at higher speed | 309 | * operation at higher speed |
| 310 | */ | 310 | */ |
| 311 | cfg->f_max /= 2; | 311 | cfg->f_max /= 2; |
| 312 | #endif | 312 | #endif |
| 313 | 313 | ||
| 314 | mmc = mmc_create(cfg, priv); | 314 | mmc = mmc_create(cfg, priv); |
| 315 | if (!mmc) { | 315 | if (!mmc) { |
| 316 | free(priv); | 316 | free(priv); |
| 317 | return -ENOMEM; | 317 | return -ENOMEM; |
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | return 0; | 320 | return 0; |
| 321 | } | 321 | } |
| 322 | 322 |
drivers/mmc/s5p_sdhci.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 | * | 4 | * |
| 5 | * SPDX-License-Identifier: GPL-2.0+ | 5 | * SPDX-License-Identifier: GPL-2.0+ |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <common.h> | 8 | #include <common.h> |
| 9 | #include <malloc.h> | 9 | #include <malloc.h> |
| 10 | #include <sdhci.h> | 10 | #include <sdhci.h> |
| 11 | #include <fdtdec.h> | 11 | #include <fdtdec.h> |
| 12 | #include <libfdt.h> | 12 | #include <libfdt.h> |
| 13 | #include <asm/gpio.h> | 13 | #include <asm/gpio.h> |
| 14 | #include <asm/arch/mmc.h> | 14 | #include <asm/arch/mmc.h> |
| 15 | #include <asm/arch/clk.h> | 15 | #include <asm/arch/clk.h> |
| 16 | #include <errno.h> | 16 | #include <errno.h> |
| 17 | #include <asm/arch/pinmux.h> | 17 | #include <asm/arch/pinmux.h> |
| 18 | 18 | ||
| 19 | static char *S5P_NAME = "SAMSUNG SDHCI"; | 19 | static char *S5P_NAME = "SAMSUNG SDHCI"; |
| 20 | static void s5p_sdhci_set_control_reg(struct sdhci_host *host) | 20 | static void s5p_sdhci_set_control_reg(struct sdhci_host *host) |
| 21 | { | 21 | { |
| 22 | unsigned long val, ctrl; | 22 | unsigned long val, ctrl; |
| 23 | /* | 23 | /* |
| 24 | * SELCLKPADDS[17:16] | 24 | * SELCLKPADDS[17:16] |
| 25 | * 00 = 2mA | 25 | * 00 = 2mA |
| 26 | * 01 = 4mA | 26 | * 01 = 4mA |
| 27 | * 10 = 7mA | 27 | * 10 = 7mA |
| 28 | * 11 = 9mA | 28 | * 11 = 9mA |
| 29 | */ | 29 | */ |
| 30 | sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4); | 30 | sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4); |
| 31 | 31 | ||
| 32 | val = sdhci_readl(host, SDHCI_CONTROL2); | 32 | val = sdhci_readl(host, SDHCI_CONTROL2); |
| 33 | val &= SDHCI_CTRL2_SELBASECLK_MASK(3); | 33 | val &= SDHCI_CTRL2_SELBASECLK_MASK(3); |
| 34 | 34 | ||
| 35 | val |= SDHCI_CTRL2_ENSTAASYNCCLR | | 35 | val |= SDHCI_CTRL2_ENSTAASYNCCLR | |
| 36 | SDHCI_CTRL2_ENCMDCNFMSK | | 36 | SDHCI_CTRL2_ENCMDCNFMSK | |
| 37 | SDHCI_CTRL2_ENFBCLKRX | | 37 | SDHCI_CTRL2_ENFBCLKRX | |
| 38 | SDHCI_CTRL2_ENCLKOUTHOLD; | 38 | SDHCI_CTRL2_ENCLKOUTHOLD; |
| 39 | 39 | ||
| 40 | sdhci_writel(host, val, SDHCI_CONTROL2); | 40 | sdhci_writel(host, val, SDHCI_CONTROL2); |
| 41 | 41 | ||
| 42 | /* | 42 | /* |
| 43 | * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] | 43 | * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] |
| 44 | * FCSel[1:0] : Rx Feedback Clock Delay Control | 44 | * FCSel[1:0] : Rx Feedback Clock Delay Control |
| 45 | * Inverter delay means10ns delay if SDCLK 50MHz setting | 45 | * Inverter delay means10ns delay if SDCLK 50MHz setting |
| 46 | * 01 = Delay1 (basic delay) | 46 | * 01 = Delay1 (basic delay) |
| 47 | * 11 = Delay2 (basic delay + 2ns) | 47 | * 11 = Delay2 (basic delay + 2ns) |
| 48 | * 00 = Delay3 (inverter delay) | 48 | * 00 = Delay3 (inverter delay) |
| 49 | * 10 = Delay4 (inverter delay + 2ns) | 49 | * 10 = Delay4 (inverter delay + 2ns) |
| 50 | */ | 50 | */ |
| 51 | val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1; | 51 | val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1; |
| 52 | sdhci_writel(host, val, SDHCI_CONTROL3); | 52 | sdhci_writel(host, val, SDHCI_CONTROL3); |
| 53 | 53 | ||
| 54 | /* | 54 | /* |
| 55 | * SELBASECLK[5:4] | 55 | * SELBASECLK[5:4] |
| 56 | * 00/01 = HCLK | 56 | * 00/01 = HCLK |
| 57 | * 10 = EPLL | 57 | * 10 = EPLL |
| 58 | * 11 = XTI or XEXTCLK | 58 | * 11 = XTI or XEXTCLK |
| 59 | */ | 59 | */ |
| 60 | ctrl = sdhci_readl(host, SDHCI_CONTROL2); | 60 | ctrl = sdhci_readl(host, SDHCI_CONTROL2); |
| 61 | ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3); | 61 | ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3); |
| 62 | ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2); | 62 | ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2); |
| 63 | sdhci_writel(host, ctrl, SDHCI_CONTROL2); | 63 | sdhci_writel(host, ctrl, SDHCI_CONTROL2); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static int s5p_sdhci_core_init(struct sdhci_host *host) | 66 | static int s5p_sdhci_core_init(struct sdhci_host *host) |
| 67 | { | 67 | { |
| 68 | host->name = S5P_NAME; | 68 | host->name = S5P_NAME; |
| 69 | 69 | ||
| 70 | host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | | 70 | host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | |
| 71 | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | | 71 | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | |
| 72 | SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8; | 72 | SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8; |
| 73 | host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | 73 | host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
| 74 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); | 74 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); |
| 75 | 75 | ||
| 76 | host->set_control_reg = &s5p_sdhci_set_control_reg; | 76 | host->set_control_reg = &s5p_sdhci_set_control_reg; |
| 77 | host->set_clock = set_mmc_clk; | 77 | host->set_clock = set_mmc_clk; |
| 78 | 78 | ||
| 79 | host->host_caps = MMC_MODE_HC; | ||
| 80 | if (host->bus_width == 8) | 79 | if (host->bus_width == 8) |
| 81 | host->host_caps |= MMC_MODE_8BIT; | 80 | host->host_caps |= MMC_MODE_8BIT; |
| 82 | 81 | ||
| 83 | return add_sdhci(host, 52000000, 400000); | 82 | return add_sdhci(host, 52000000, 400000); |
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | int s5p_sdhci_init(u32 regbase, int index, int bus_width) | 85 | int s5p_sdhci_init(u32 regbase, int index, int bus_width) |
| 87 | { | 86 | { |
| 88 | struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); | 87 | struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); |
| 89 | if (!host) { | 88 | if (!host) { |
| 90 | printf("sdhci__host malloc fail!\n"); | 89 | printf("sdhci__host malloc fail!\n"); |
| 91 | return 1; | 90 | return 1; |
| 92 | } | 91 | } |
| 93 | host->ioaddr = (void *)regbase; | 92 | host->ioaddr = (void *)regbase; |
| 94 | host->index = index; | 93 | host->index = index; |
| 95 | host->bus_width = bus_width; | 94 | host->bus_width = bus_width; |
| 96 | 95 | ||
| 97 | return s5p_sdhci_core_init(host); | 96 | return s5p_sdhci_core_init(host); |
| 98 | } | 97 | } |
| 99 | 98 | ||
| 100 | #ifdef CONFIG_OF_CONTROL | 99 | #ifdef CONFIG_OF_CONTROL |
| 101 | struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; | 100 | struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; |
| 102 | 101 | ||
| 103 | static int do_sdhci_init(struct sdhci_host *host) | 102 | static int do_sdhci_init(struct sdhci_host *host) |
| 104 | { | 103 | { |
| 105 | int dev_id, flag; | 104 | int dev_id, flag; |
| 106 | int err = 0; | 105 | int err = 0; |
| 107 | 106 | ||
| 108 | flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; | 107 | flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; |
| 109 | dev_id = host->index + PERIPH_ID_SDMMC0; | 108 | dev_id = host->index + PERIPH_ID_SDMMC0; |
| 110 | 109 | ||
| 111 | if (dm_gpio_is_valid(&host->pwr_gpio)) { | 110 | if (dm_gpio_is_valid(&host->pwr_gpio)) { |
| 112 | dm_gpio_set_value(&host->pwr_gpio, 1); | 111 | dm_gpio_set_value(&host->pwr_gpio, 1); |
| 113 | err = exynos_pinmux_config(dev_id, flag); | 112 | err = exynos_pinmux_config(dev_id, flag); |
| 114 | if (err) { | 113 | if (err) { |
| 115 | debug("MMC not configured\n"); | 114 | debug("MMC not configured\n"); |
| 116 | return err; | 115 | return err; |
| 117 | } | 116 | } |
| 118 | } | 117 | } |
| 119 | 118 | ||
| 120 | if (dm_gpio_is_valid(&host->cd_gpio)) { | 119 | if (dm_gpio_is_valid(&host->cd_gpio)) { |
| 121 | if (dm_gpio_get_value(&host->cd_gpio)) | 120 | if (dm_gpio_get_value(&host->cd_gpio)) |
| 122 | return -ENODEV; | 121 | return -ENODEV; |
| 123 | 122 | ||
| 124 | err = exynos_pinmux_config(dev_id, flag); | 123 | err = exynos_pinmux_config(dev_id, flag); |
| 125 | if (err) { | 124 | if (err) { |
| 126 | printf("external SD not configured\n"); | 125 | printf("external SD not configured\n"); |
| 127 | return err; | 126 | return err; |
| 128 | } | 127 | } |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | return s5p_sdhci_core_init(host); | 130 | return s5p_sdhci_core_init(host); |
| 132 | } | 131 | } |
| 133 | 132 | ||
| 134 | static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) | 133 | static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) |
| 135 | { | 134 | { |
| 136 | int bus_width, dev_id; | 135 | int bus_width, dev_id; |
| 137 | unsigned int base; | 136 | unsigned int base; |
| 138 | 137 | ||
| 139 | /* Get device id */ | 138 | /* Get device id */ |
| 140 | dev_id = pinmux_decode_periph_id(blob, node); | 139 | dev_id = pinmux_decode_periph_id(blob, node); |
| 141 | if (dev_id < PERIPH_ID_SDMMC0 && dev_id > PERIPH_ID_SDMMC3) { | 140 | if (dev_id < PERIPH_ID_SDMMC0 && dev_id > PERIPH_ID_SDMMC3) { |
| 142 | debug("MMC: Can't get device id\n"); | 141 | debug("MMC: Can't get device id\n"); |
| 143 | return -1; | 142 | return -1; |
| 144 | } | 143 | } |
| 145 | host->index = dev_id - PERIPH_ID_SDMMC0; | 144 | host->index = dev_id - PERIPH_ID_SDMMC0; |
| 146 | 145 | ||
| 147 | /* Get bus width */ | 146 | /* Get bus width */ |
| 148 | bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); | 147 | bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); |
| 149 | if (bus_width <= 0) { | 148 | if (bus_width <= 0) { |
| 150 | debug("MMC: Can't get bus-width\n"); | 149 | debug("MMC: Can't get bus-width\n"); |
| 151 | return -1; | 150 | return -1; |
| 152 | } | 151 | } |
| 153 | host->bus_width = bus_width; | 152 | host->bus_width = bus_width; |
| 154 | 153 | ||
| 155 | /* Get the base address from the device node */ | 154 | /* Get the base address from the device node */ |
| 156 | base = fdtdec_get_addr(blob, node, "reg"); | 155 | base = fdtdec_get_addr(blob, node, "reg"); |
| 157 | if (!base) { | 156 | if (!base) { |
| 158 | debug("MMC: Can't get base address\n"); | 157 | debug("MMC: Can't get base address\n"); |
| 159 | return -1; | 158 | return -1; |
| 160 | } | 159 | } |
| 161 | host->ioaddr = (void *)base; | 160 | host->ioaddr = (void *)base; |
| 162 | 161 | ||
| 163 | gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio, | 162 | gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio, |
| 164 | GPIOD_IS_OUT); | 163 | GPIOD_IS_OUT); |
| 165 | gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, | 164 | gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, |
| 166 | GPIOD_IS_IN); | 165 | GPIOD_IS_IN); |
| 167 | 166 | ||
| 168 | return 0; | 167 | return 0; |
| 169 | } | 168 | } |
| 170 | 169 | ||
| 171 | static int process_nodes(const void *blob, int node_list[], int count) | 170 | static int process_nodes(const void *blob, int node_list[], int count) |
| 172 | { | 171 | { |
| 173 | struct sdhci_host *host; | 172 | struct sdhci_host *host; |
| 174 | int i, node; | 173 | int i, node; |
| 175 | 174 | ||
| 176 | debug("%s: count = %d\n", __func__, count); | 175 | debug("%s: count = %d\n", __func__, count); |
| 177 | 176 | ||
| 178 | /* build sdhci_host[] for each controller */ | 177 | /* build sdhci_host[] for each controller */ |
| 179 | for (i = 0; i < count; i++) { | 178 | for (i = 0; i < count; i++) { |
| 180 | node = node_list[i]; | 179 | node = node_list[i]; |
| 181 | if (node <= 0) | 180 | if (node <= 0) |
| 182 | continue; | 181 | continue; |
| 183 | 182 | ||
| 184 | host = &sdhci_host[i]; | 183 | host = &sdhci_host[i]; |
| 185 | 184 | ||
| 186 | if (sdhci_get_config(blob, node, host)) { | 185 | if (sdhci_get_config(blob, node, host)) { |
| 187 | printf("%s: failed to decode dev %d\n", __func__, i); | 186 | printf("%s: failed to decode dev %d\n", __func__, i); |
| 188 | return -1; | 187 | return -1; |
| 189 | } | 188 | } |
| 190 | do_sdhci_init(host); | 189 | do_sdhci_init(host); |
| 191 | } | 190 | } |
| 192 | return 0; | 191 | return 0; |
| 193 | } | 192 | } |
| 194 | 193 | ||
| 195 | int exynos_mmc_init(const void *blob) | 194 | int exynos_mmc_init(const void *blob) |
| 196 | { | 195 | { |
| 197 | int count; | 196 | int count; |
| 198 | int node_list[SDHCI_MAX_HOSTS]; | 197 | int node_list[SDHCI_MAX_HOSTS]; |
| 199 | 198 | ||
| 200 | count = fdtdec_find_aliases_for_id(blob, "mmc", | 199 | count = fdtdec_find_aliases_for_id(blob, "mmc", |
| 201 | COMPAT_SAMSUNG_EXYNOS_MMC, node_list, | 200 | COMPAT_SAMSUNG_EXYNOS_MMC, node_list, |
| 202 | SDHCI_MAX_HOSTS); | 201 | SDHCI_MAX_HOSTS); |
| 203 | 202 | ||
| 204 | process_nodes(blob, node_list, count); | 203 | process_nodes(blob, node_list, count); |
| 205 | 204 | ||
| 206 | return 1; | 205 | return 1; |
| 207 | } | 206 | } |
| 208 | #endif | 207 | #endif |
| 209 | 208 |
drivers/mmc/sh_mmcif.c
| 1 | /* | 1 | /* |
| 2 | * MMCIF driver. | 2 | * MMCIF driver. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Renesas Solutions Corp. | 4 | * Copyright (C) 2011 Renesas Solutions Corp. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License. | 8 | * the Free Software Foundation; either version 2 of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <config.h> | 11 | #include <config.h> |
| 12 | #include <common.h> | 12 | #include <common.h> |
| 13 | #include <watchdog.h> | 13 | #include <watchdog.h> |
| 14 | #include <command.h> | 14 | #include <command.h> |
| 15 | #include <mmc.h> | 15 | #include <mmc.h> |
| 16 | #include <malloc.h> | 16 | #include <malloc.h> |
| 17 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
| 18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
| 19 | #include "sh_mmcif.h" | 19 | #include "sh_mmcif.h" |
| 20 | 20 | ||
| 21 | #define DRIVER_NAME "sh_mmcif" | 21 | #define DRIVER_NAME "sh_mmcif" |
| 22 | 22 | ||
| 23 | static int sh_mmcif_intr(void *dev_id) | 23 | static int sh_mmcif_intr(void *dev_id) |
| 24 | { | 24 | { |
| 25 | struct sh_mmcif_host *host = dev_id; | 25 | struct sh_mmcif_host *host = dev_id; |
| 26 | u32 state = 0; | 26 | u32 state = 0; |
| 27 | 27 | ||
| 28 | state = sh_mmcif_read(&host->regs->ce_int); | 28 | state = sh_mmcif_read(&host->regs->ce_int); |
| 29 | state &= sh_mmcif_read(&host->regs->ce_int_mask); | 29 | state &= sh_mmcif_read(&host->regs->ce_int_mask); |
| 30 | 30 | ||
| 31 | if (state & INT_RBSYE) { | 31 | if (state & INT_RBSYE) { |
| 32 | sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int); | 32 | sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int); |
| 33 | sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask); | 33 | sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask); |
| 34 | goto end; | 34 | goto end; |
| 35 | } else if (state & INT_CRSPE) { | 35 | } else if (state & INT_CRSPE) { |
| 36 | sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int); | 36 | sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int); |
| 37 | sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask); | 37 | sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask); |
| 38 | /* one more interrupt (INT_RBSYE) */ | 38 | /* one more interrupt (INT_RBSYE) */ |
| 39 | if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY) | 39 | if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY) |
| 40 | return -EAGAIN; | 40 | return -EAGAIN; |
| 41 | goto end; | 41 | goto end; |
| 42 | } else if (state & INT_BUFREN) { | 42 | } else if (state & INT_BUFREN) { |
| 43 | sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int); | 43 | sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int); |
| 44 | sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask); | 44 | sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask); |
| 45 | goto end; | 45 | goto end; |
| 46 | } else if (state & INT_BUFWEN) { | 46 | } else if (state & INT_BUFWEN) { |
| 47 | sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int); | 47 | sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int); |
| 48 | sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask); | 48 | sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask); |
| 49 | goto end; | 49 | goto end; |
| 50 | } else if (state & INT_CMD12DRE) { | 50 | } else if (state & INT_CMD12DRE) { |
| 51 | sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | | 51 | sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | |
| 52 | INT_BUFRE), &host->regs->ce_int); | 52 | INT_BUFRE), &host->regs->ce_int); |
| 53 | sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask); | 53 | sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask); |
| 54 | goto end; | 54 | goto end; |
| 55 | } else if (state & INT_BUFRE) { | 55 | } else if (state & INT_BUFRE) { |
| 56 | sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int); | 56 | sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int); |
| 57 | sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask); | 57 | sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask); |
| 58 | goto end; | 58 | goto end; |
| 59 | } else if (state & INT_DTRANE) { | 59 | } else if (state & INT_DTRANE) { |
| 60 | sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int); | 60 | sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int); |
| 61 | sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask); | 61 | sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask); |
| 62 | goto end; | 62 | goto end; |
| 63 | } else if (state & INT_CMD12RBE) { | 63 | } else if (state & INT_CMD12RBE) { |
| 64 | sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE), | 64 | sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE), |
| 65 | &host->regs->ce_int); | 65 | &host->regs->ce_int); |
| 66 | sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask); | 66 | sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask); |
| 67 | goto end; | 67 | goto end; |
| 68 | } else if (state & INT_ERR_STS) { | 68 | } else if (state & INT_ERR_STS) { |
| 69 | /* err interrupts */ | 69 | /* err interrupts */ |
| 70 | sh_mmcif_write(~state, &host->regs->ce_int); | 70 | sh_mmcif_write(~state, &host->regs->ce_int); |
| 71 | sh_mmcif_bitclr(state, &host->regs->ce_int_mask); | 71 | sh_mmcif_bitclr(state, &host->regs->ce_int_mask); |
| 72 | goto err; | 72 | goto err; |
| 73 | } else | 73 | } else |
| 74 | return -EAGAIN; | 74 | return -EAGAIN; |
| 75 | 75 | ||
| 76 | err: | 76 | err: |
| 77 | host->sd_error = 1; | 77 | host->sd_error = 1; |
| 78 | debug("%s: int err state = %08x\n", DRIVER_NAME, state); | 78 | debug("%s: int err state = %08x\n", DRIVER_NAME, state); |
| 79 | end: | 79 | end: |
| 80 | host->wait_int = 1; | 80 | host->wait_int = 1; |
| 81 | return 0; | 81 | return 0; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host) | 84 | static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host) |
| 85 | { | 85 | { |
| 86 | int timeout = 10000000; | 86 | int timeout = 10000000; |
| 87 | 87 | ||
| 88 | while (1) { | 88 | while (1) { |
| 89 | timeout--; | 89 | timeout--; |
| 90 | if (timeout < 0) { | 90 | if (timeout < 0) { |
| 91 | printf("timeout\n"); | 91 | printf("timeout\n"); |
| 92 | return 0; | 92 | return 0; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | if (!sh_mmcif_intr(host)) | 95 | if (!sh_mmcif_intr(host)) |
| 96 | break; | 96 | break; |
| 97 | 97 | ||
| 98 | udelay(1); /* 1 usec */ | 98 | udelay(1); /* 1 usec */ |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | return 1; /* Return value: NOT 0 = complete waiting */ | 101 | return 1; /* Return value: NOT 0 = complete waiting */ |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) | 104 | static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) |
| 105 | { | 105 | { |
| 106 | sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl); | 106 | sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl); |
| 107 | sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl); | 107 | sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl); |
| 108 | 108 | ||
| 109 | if (!clk) | 109 | if (!clk) |
| 110 | return; | 110 | return; |
| 111 | 111 | ||
| 112 | if (clk == CLKDEV_EMMC_DATA) | 112 | if (clk == CLKDEV_EMMC_DATA) |
| 113 | sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl); | 113 | sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl); |
| 114 | else | 114 | else |
| 115 | sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk, | 115 | sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk, |
| 116 | clk) - 1) - 1) << 16, | 116 | clk) - 1) - 1) << 16, |
| 117 | &host->regs->ce_clk_ctrl); | 117 | &host->regs->ce_clk_ctrl); |
| 118 | sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl); | 118 | sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) | 121 | static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) |
| 122 | { | 122 | { |
| 123 | u32 tmp; | 123 | u32 tmp; |
| 124 | 124 | ||
| 125 | tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE | | 125 | tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE | |
| 126 | CLK_CLEAR); | 126 | CLK_CLEAR); |
| 127 | 127 | ||
| 128 | sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version); | 128 | sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version); |
| 129 | sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version); | 129 | sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version); |
| 130 | sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29, | 130 | sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29, |
| 131 | &host->regs->ce_clk_ctrl); | 131 | &host->regs->ce_clk_ctrl); |
| 132 | /* byte swap on */ | 132 | /* byte swap on */ |
| 133 | sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc); | 133 | sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | static int sh_mmcif_error_manage(struct sh_mmcif_host *host) | 136 | static int sh_mmcif_error_manage(struct sh_mmcif_host *host) |
| 137 | { | 137 | { |
| 138 | u32 state1, state2; | 138 | u32 state1, state2; |
| 139 | int ret, timeout = 10000000; | 139 | int ret, timeout = 10000000; |
| 140 | 140 | ||
| 141 | host->sd_error = 0; | 141 | host->sd_error = 0; |
| 142 | host->wait_int = 0; | 142 | host->wait_int = 0; |
| 143 | 143 | ||
| 144 | state1 = sh_mmcif_read(&host->regs->ce_host_sts1); | 144 | state1 = sh_mmcif_read(&host->regs->ce_host_sts1); |
| 145 | state2 = sh_mmcif_read(&host->regs->ce_host_sts2); | 145 | state2 = sh_mmcif_read(&host->regs->ce_host_sts2); |
| 146 | debug("%s: ERR HOST_STS1 = %08x\n", \ | 146 | debug("%s: ERR HOST_STS1 = %08x\n", \ |
| 147 | DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1)); | 147 | DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1)); |
| 148 | debug("%s: ERR HOST_STS2 = %08x\n", \ | 148 | debug("%s: ERR HOST_STS2 = %08x\n", \ |
| 149 | DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2)); | 149 | DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2)); |
| 150 | 150 | ||
| 151 | if (state1 & STS1_CMDSEQ) { | 151 | if (state1 & STS1_CMDSEQ) { |
| 152 | debug("%s: Forced end of command sequence\n", DRIVER_NAME); | 152 | debug("%s: Forced end of command sequence\n", DRIVER_NAME); |
| 153 | sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); | 153 | sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); |
| 154 | sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); | 154 | sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); |
| 155 | while (1) { | 155 | while (1) { |
| 156 | timeout--; | 156 | timeout--; |
| 157 | if (timeout < 0) { | 157 | if (timeout < 0) { |
| 158 | printf(DRIVER_NAME": Forceed end of " \ | 158 | printf(DRIVER_NAME": Forceed end of " \ |
| 159 | "command sequence timeout err\n"); | 159 | "command sequence timeout err\n"); |
| 160 | return -EILSEQ; | 160 | return -EILSEQ; |
| 161 | } | 161 | } |
| 162 | if (!(sh_mmcif_read(&host->regs->ce_host_sts1) | 162 | if (!(sh_mmcif_read(&host->regs->ce_host_sts1) |
| 163 | & STS1_CMDSEQ)) | 163 | & STS1_CMDSEQ)) |
| 164 | break; | 164 | break; |
| 165 | } | 165 | } |
| 166 | sh_mmcif_sync_reset(host); | 166 | sh_mmcif_sync_reset(host); |
| 167 | return -EILSEQ; | 167 | return -EILSEQ; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | if (state2 & STS2_CRC_ERR) | 170 | if (state2 & STS2_CRC_ERR) |
| 171 | ret = -EILSEQ; | 171 | ret = -EILSEQ; |
| 172 | else if (state2 & STS2_TIMEOUT_ERR) | 172 | else if (state2 & STS2_TIMEOUT_ERR) |
| 173 | ret = TIMEOUT; | 173 | ret = TIMEOUT; |
| 174 | else | 174 | else |
| 175 | ret = -EILSEQ; | 175 | ret = -EILSEQ; |
| 176 | return ret; | 176 | return ret; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static int sh_mmcif_single_read(struct sh_mmcif_host *host, | 179 | static int sh_mmcif_single_read(struct sh_mmcif_host *host, |
| 180 | struct mmc_data *data) | 180 | struct mmc_data *data) |
| 181 | { | 181 | { |
| 182 | long time; | 182 | long time; |
| 183 | u32 blocksize, i; | 183 | u32 blocksize, i; |
| 184 | unsigned long *p = (unsigned long *)data->dest; | 184 | unsigned long *p = (unsigned long *)data->dest; |
| 185 | 185 | ||
| 186 | if ((unsigned long)p & 0x00000001) { | 186 | if ((unsigned long)p & 0x00000001) { |
| 187 | printf("%s: The data pointer is unaligned.", __func__); | 187 | printf("%s: The data pointer is unaligned.", __func__); |
| 188 | return -EIO; | 188 | return -EIO; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | host->wait_int = 0; | 191 | host->wait_int = 0; |
| 192 | 192 | ||
| 193 | /* buf read enable */ | 193 | /* buf read enable */ |
| 194 | sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); | 194 | sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); |
| 195 | time = mmcif_wait_interrupt_flag(host); | 195 | time = mmcif_wait_interrupt_flag(host); |
| 196 | if (time == 0 || host->sd_error != 0) | 196 | if (time == 0 || host->sd_error != 0) |
| 197 | return sh_mmcif_error_manage(host); | 197 | return sh_mmcif_error_manage(host); |
| 198 | 198 | ||
| 199 | host->wait_int = 0; | 199 | host->wait_int = 0; |
| 200 | blocksize = (BLOCK_SIZE_MASK & | 200 | blocksize = (BLOCK_SIZE_MASK & |
| 201 | sh_mmcif_read(&host->regs->ce_block_set)) + 3; | 201 | sh_mmcif_read(&host->regs->ce_block_set)) + 3; |
| 202 | for (i = 0; i < blocksize / 4; i++) | 202 | for (i = 0; i < blocksize / 4; i++) |
| 203 | *p++ = sh_mmcif_read(&host->regs->ce_data); | 203 | *p++ = sh_mmcif_read(&host->regs->ce_data); |
| 204 | 204 | ||
| 205 | /* buffer read end */ | 205 | /* buffer read end */ |
| 206 | sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask); | 206 | sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask); |
| 207 | time = mmcif_wait_interrupt_flag(host); | 207 | time = mmcif_wait_interrupt_flag(host); |
| 208 | if (time == 0 || host->sd_error != 0) | 208 | if (time == 0 || host->sd_error != 0) |
| 209 | return sh_mmcif_error_manage(host); | 209 | return sh_mmcif_error_manage(host); |
| 210 | 210 | ||
| 211 | host->wait_int = 0; | 211 | host->wait_int = 0; |
| 212 | return 0; | 212 | return 0; |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | static int sh_mmcif_multi_read(struct sh_mmcif_host *host, | 215 | static int sh_mmcif_multi_read(struct sh_mmcif_host *host, |
| 216 | struct mmc_data *data) | 216 | struct mmc_data *data) |
| 217 | { | 217 | { |
| 218 | long time; | 218 | long time; |
| 219 | u32 blocksize, i, j; | 219 | u32 blocksize, i, j; |
| 220 | unsigned long *p = (unsigned long *)data->dest; | 220 | unsigned long *p = (unsigned long *)data->dest; |
| 221 | 221 | ||
| 222 | if ((unsigned long)p & 0x00000001) { | 222 | if ((unsigned long)p & 0x00000001) { |
| 223 | printf("%s: The data pointer is unaligned.", __func__); | 223 | printf("%s: The data pointer is unaligned.", __func__); |
| 224 | return -EIO; | 224 | return -EIO; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | host->wait_int = 0; | 227 | host->wait_int = 0; |
| 228 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); | 228 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); |
| 229 | for (j = 0; j < data->blocks; j++) { | 229 | for (j = 0; j < data->blocks; j++) { |
| 230 | sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); | 230 | sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); |
| 231 | time = mmcif_wait_interrupt_flag(host); | 231 | time = mmcif_wait_interrupt_flag(host); |
| 232 | if (time == 0 || host->sd_error != 0) | 232 | if (time == 0 || host->sd_error != 0) |
| 233 | return sh_mmcif_error_manage(host); | 233 | return sh_mmcif_error_manage(host); |
| 234 | 234 | ||
| 235 | host->wait_int = 0; | 235 | host->wait_int = 0; |
| 236 | for (i = 0; i < blocksize / 4; i++) | 236 | for (i = 0; i < blocksize / 4; i++) |
| 237 | *p++ = sh_mmcif_read(&host->regs->ce_data); | 237 | *p++ = sh_mmcif_read(&host->regs->ce_data); |
| 238 | 238 | ||
| 239 | WATCHDOG_RESET(); | 239 | WATCHDOG_RESET(); |
| 240 | } | 240 | } |
| 241 | return 0; | 241 | return 0; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | static int sh_mmcif_single_write(struct sh_mmcif_host *host, | 244 | static int sh_mmcif_single_write(struct sh_mmcif_host *host, |
| 245 | struct mmc_data *data) | 245 | struct mmc_data *data) |
| 246 | { | 246 | { |
| 247 | long time; | 247 | long time; |
| 248 | u32 blocksize, i; | 248 | u32 blocksize, i; |
| 249 | const unsigned long *p = (unsigned long *)data->dest; | 249 | const unsigned long *p = (unsigned long *)data->dest; |
| 250 | 250 | ||
| 251 | if ((unsigned long)p & 0x00000001) { | 251 | if ((unsigned long)p & 0x00000001) { |
| 252 | printf("%s: The data pointer is unaligned.", __func__); | 252 | printf("%s: The data pointer is unaligned.", __func__); |
| 253 | return -EIO; | 253 | return -EIO; |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | host->wait_int = 0; | 256 | host->wait_int = 0; |
| 257 | sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); | 257 | sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); |
| 258 | 258 | ||
| 259 | time = mmcif_wait_interrupt_flag(host); | 259 | time = mmcif_wait_interrupt_flag(host); |
| 260 | if (time == 0 || host->sd_error != 0) | 260 | if (time == 0 || host->sd_error != 0) |
| 261 | return sh_mmcif_error_manage(host); | 261 | return sh_mmcif_error_manage(host); |
| 262 | 262 | ||
| 263 | host->wait_int = 0; | 263 | host->wait_int = 0; |
| 264 | blocksize = (BLOCK_SIZE_MASK & | 264 | blocksize = (BLOCK_SIZE_MASK & |
| 265 | sh_mmcif_read(&host->regs->ce_block_set)) + 3; | 265 | sh_mmcif_read(&host->regs->ce_block_set)) + 3; |
| 266 | for (i = 0; i < blocksize / 4; i++) | 266 | for (i = 0; i < blocksize / 4; i++) |
| 267 | sh_mmcif_write(*p++, &host->regs->ce_data); | 267 | sh_mmcif_write(*p++, &host->regs->ce_data); |
| 268 | 268 | ||
| 269 | /* buffer write end */ | 269 | /* buffer write end */ |
| 270 | sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask); | 270 | sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask); |
| 271 | 271 | ||
| 272 | time = mmcif_wait_interrupt_flag(host); | 272 | time = mmcif_wait_interrupt_flag(host); |
| 273 | if (time == 0 || host->sd_error != 0) | 273 | if (time == 0 || host->sd_error != 0) |
| 274 | return sh_mmcif_error_manage(host); | 274 | return sh_mmcif_error_manage(host); |
| 275 | 275 | ||
| 276 | host->wait_int = 0; | 276 | host->wait_int = 0; |
| 277 | return 0; | 277 | return 0; |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | static int sh_mmcif_multi_write(struct sh_mmcif_host *host, | 280 | static int sh_mmcif_multi_write(struct sh_mmcif_host *host, |
| 281 | struct mmc_data *data) | 281 | struct mmc_data *data) |
| 282 | { | 282 | { |
| 283 | long time; | 283 | long time; |
| 284 | u32 i, j, blocksize; | 284 | u32 i, j, blocksize; |
| 285 | const unsigned long *p = (unsigned long *)data->dest; | 285 | const unsigned long *p = (unsigned long *)data->dest; |
| 286 | 286 | ||
| 287 | if ((unsigned long)p & 0x00000001) { | 287 | if ((unsigned long)p & 0x00000001) { |
| 288 | printf("%s: The data pointer is unaligned.", __func__); | 288 | printf("%s: The data pointer is unaligned.", __func__); |
| 289 | return -EIO; | 289 | return -EIO; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | host->wait_int = 0; | 292 | host->wait_int = 0; |
| 293 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); | 293 | blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); |
| 294 | for (j = 0; j < data->blocks; j++) { | 294 | for (j = 0; j < data->blocks; j++) { |
| 295 | sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); | 295 | sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); |
| 296 | 296 | ||
| 297 | time = mmcif_wait_interrupt_flag(host); | 297 | time = mmcif_wait_interrupt_flag(host); |
| 298 | 298 | ||
| 299 | if (time == 0 || host->sd_error != 0) | 299 | if (time == 0 || host->sd_error != 0) |
| 300 | return sh_mmcif_error_manage(host); | 300 | return sh_mmcif_error_manage(host); |
| 301 | 301 | ||
| 302 | host->wait_int = 0; | 302 | host->wait_int = 0; |
| 303 | for (i = 0; i < blocksize / 4; i++) | 303 | for (i = 0; i < blocksize / 4; i++) |
| 304 | sh_mmcif_write(*p++, &host->regs->ce_data); | 304 | sh_mmcif_write(*p++, &host->regs->ce_data); |
| 305 | 305 | ||
| 306 | WATCHDOG_RESET(); | 306 | WATCHDOG_RESET(); |
| 307 | } | 307 | } |
| 308 | return 0; | 308 | return 0; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | static void sh_mmcif_get_response(struct sh_mmcif_host *host, | 311 | static void sh_mmcif_get_response(struct sh_mmcif_host *host, |
| 312 | struct mmc_cmd *cmd) | 312 | struct mmc_cmd *cmd) |
| 313 | { | 313 | { |
| 314 | if (cmd->resp_type & MMC_RSP_136) { | 314 | if (cmd->resp_type & MMC_RSP_136) { |
| 315 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3); | 315 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3); |
| 316 | cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2); | 316 | cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2); |
| 317 | cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1); | 317 | cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1); |
| 318 | cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0); | 318 | cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0); |
| 319 | debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0], | 319 | debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0], |
| 320 | cmd->response[1], cmd->response[2], cmd->response[3]); | 320 | cmd->response[1], cmd->response[2], cmd->response[3]); |
| 321 | } else { | 321 | } else { |
| 322 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0); | 322 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0); |
| 323 | } | 323 | } |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, | 326 | static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, |
| 327 | struct mmc_cmd *cmd) | 327 | struct mmc_cmd *cmd) |
| 328 | { | 328 | { |
| 329 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12); | 329 | cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, | 332 | static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, |
| 333 | struct mmc_data *data, struct mmc_cmd *cmd) | 333 | struct mmc_data *data, struct mmc_cmd *cmd) |
| 334 | { | 334 | { |
| 335 | u32 tmp = 0; | 335 | u32 tmp = 0; |
| 336 | u32 opc = cmd->cmdidx; | 336 | u32 opc = cmd->cmdidx; |
| 337 | 337 | ||
| 338 | /* Response Type check */ | 338 | /* Response Type check */ |
| 339 | switch (cmd->resp_type) { | 339 | switch (cmd->resp_type) { |
| 340 | case MMC_RSP_NONE: | 340 | case MMC_RSP_NONE: |
| 341 | tmp |= CMD_SET_RTYP_NO; | 341 | tmp |= CMD_SET_RTYP_NO; |
| 342 | break; | 342 | break; |
| 343 | case MMC_RSP_R1: | 343 | case MMC_RSP_R1: |
| 344 | case MMC_RSP_R1b: | 344 | case MMC_RSP_R1b: |
| 345 | case MMC_RSP_R3: | 345 | case MMC_RSP_R3: |
| 346 | tmp |= CMD_SET_RTYP_6B; | 346 | tmp |= CMD_SET_RTYP_6B; |
| 347 | break; | 347 | break; |
| 348 | case MMC_RSP_R2: | 348 | case MMC_RSP_R2: |
| 349 | tmp |= CMD_SET_RTYP_17B; | 349 | tmp |= CMD_SET_RTYP_17B; |
| 350 | break; | 350 | break; |
| 351 | default: | 351 | default: |
| 352 | printf(DRIVER_NAME": Not support type response.\n"); | 352 | printf(DRIVER_NAME": Not support type response.\n"); |
| 353 | break; | 353 | break; |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | /* RBSY */ | 356 | /* RBSY */ |
| 357 | if (opc == MMC_CMD_SWITCH) | 357 | if (opc == MMC_CMD_SWITCH) |
| 358 | tmp |= CMD_SET_RBSY; | 358 | tmp |= CMD_SET_RBSY; |
| 359 | 359 | ||
| 360 | /* WDAT / DATW */ | 360 | /* WDAT / DATW */ |
| 361 | if (host->data) { | 361 | if (host->data) { |
| 362 | tmp |= CMD_SET_WDAT; | 362 | tmp |= CMD_SET_WDAT; |
| 363 | switch (host->bus_width) { | 363 | switch (host->bus_width) { |
| 364 | case MMC_BUS_WIDTH_1: | 364 | case MMC_BUS_WIDTH_1: |
| 365 | tmp |= CMD_SET_DATW_1; | 365 | tmp |= CMD_SET_DATW_1; |
| 366 | break; | 366 | break; |
| 367 | case MMC_BUS_WIDTH_4: | 367 | case MMC_BUS_WIDTH_4: |
| 368 | tmp |= CMD_SET_DATW_4; | 368 | tmp |= CMD_SET_DATW_4; |
| 369 | break; | 369 | break; |
| 370 | case MMC_BUS_WIDTH_8: | 370 | case MMC_BUS_WIDTH_8: |
| 371 | tmp |= CMD_SET_DATW_8; | 371 | tmp |= CMD_SET_DATW_8; |
| 372 | break; | 372 | break; |
| 373 | default: | 373 | default: |
| 374 | printf(DRIVER_NAME": Not support bus width.\n"); | 374 | printf(DRIVER_NAME": Not support bus width.\n"); |
| 375 | break; | 375 | break; |
| 376 | } | 376 | } |
| 377 | } | 377 | } |
| 378 | /* DWEN */ | 378 | /* DWEN */ |
| 379 | if (opc == MMC_CMD_WRITE_SINGLE_BLOCK || | 379 | if (opc == MMC_CMD_WRITE_SINGLE_BLOCK || |
| 380 | opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) | 380 | opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) |
| 381 | tmp |= CMD_SET_DWEN; | 381 | tmp |= CMD_SET_DWEN; |
| 382 | /* CMLTE/CMD12EN */ | 382 | /* CMLTE/CMD12EN */ |
| 383 | if (opc == MMC_CMD_READ_MULTIPLE_BLOCK || | 383 | if (opc == MMC_CMD_READ_MULTIPLE_BLOCK || |
| 384 | opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) { | 384 | opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) { |
| 385 | tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; | 385 | tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; |
| 386 | sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set); | 386 | sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set); |
| 387 | } | 387 | } |
| 388 | /* RIDXC[1:0] check bits */ | 388 | /* RIDXC[1:0] check bits */ |
| 389 | if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID || | 389 | if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID || |
| 390 | opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) | 390 | opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) |
| 391 | tmp |= CMD_SET_RIDXC_BITS; | 391 | tmp |= CMD_SET_RIDXC_BITS; |
| 392 | /* RCRC7C[1:0] check bits */ | 392 | /* RCRC7C[1:0] check bits */ |
| 393 | if (opc == MMC_CMD_SEND_OP_COND) | 393 | if (opc == MMC_CMD_SEND_OP_COND) |
| 394 | tmp |= CMD_SET_CRC7C_BITS; | 394 | tmp |= CMD_SET_CRC7C_BITS; |
| 395 | /* RCRC7C[1:0] internal CRC7 */ | 395 | /* RCRC7C[1:0] internal CRC7 */ |
| 396 | if (opc == MMC_CMD_ALL_SEND_CID || | 396 | if (opc == MMC_CMD_ALL_SEND_CID || |
| 397 | opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) | 397 | opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) |
| 398 | tmp |= CMD_SET_CRC7C_INTERNAL; | 398 | tmp |= CMD_SET_CRC7C_INTERNAL; |
| 399 | 399 | ||
| 400 | return opc = ((opc << 24) | tmp); | 400 | return opc = ((opc << 24) | tmp); |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, | 403 | static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, |
| 404 | struct mmc_data *data, u16 opc) | 404 | struct mmc_data *data, u16 opc) |
| 405 | { | 405 | { |
| 406 | u32 ret; | 406 | u32 ret; |
| 407 | 407 | ||
| 408 | switch (opc) { | 408 | switch (opc) { |
| 409 | case MMC_CMD_READ_MULTIPLE_BLOCK: | 409 | case MMC_CMD_READ_MULTIPLE_BLOCK: |
| 410 | ret = sh_mmcif_multi_read(host, data); | 410 | ret = sh_mmcif_multi_read(host, data); |
| 411 | break; | 411 | break; |
| 412 | case MMC_CMD_WRITE_MULTIPLE_BLOCK: | 412 | case MMC_CMD_WRITE_MULTIPLE_BLOCK: |
| 413 | ret = sh_mmcif_multi_write(host, data); | 413 | ret = sh_mmcif_multi_write(host, data); |
| 414 | break; | 414 | break; |
| 415 | case MMC_CMD_WRITE_SINGLE_BLOCK: | 415 | case MMC_CMD_WRITE_SINGLE_BLOCK: |
| 416 | ret = sh_mmcif_single_write(host, data); | 416 | ret = sh_mmcif_single_write(host, data); |
| 417 | break; | 417 | break; |
| 418 | case MMC_CMD_READ_SINGLE_BLOCK: | 418 | case MMC_CMD_READ_SINGLE_BLOCK: |
| 419 | case MMC_CMD_SEND_EXT_CSD: | 419 | case MMC_CMD_SEND_EXT_CSD: |
| 420 | ret = sh_mmcif_single_read(host, data); | 420 | ret = sh_mmcif_single_read(host, data); |
| 421 | break; | 421 | break; |
| 422 | default: | 422 | default: |
| 423 | printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); | 423 | printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); |
| 424 | ret = -EINVAL; | 424 | ret = -EINVAL; |
| 425 | break; | 425 | break; |
| 426 | } | 426 | } |
| 427 | return ret; | 427 | return ret; |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | static int sh_mmcif_start_cmd(struct sh_mmcif_host *host, | 430 | static int sh_mmcif_start_cmd(struct sh_mmcif_host *host, |
| 431 | struct mmc_data *data, struct mmc_cmd *cmd) | 431 | struct mmc_data *data, struct mmc_cmd *cmd) |
| 432 | { | 432 | { |
| 433 | long time; | 433 | long time; |
| 434 | int ret = 0, mask = 0; | 434 | int ret = 0, mask = 0; |
| 435 | u32 opc = cmd->cmdidx; | 435 | u32 opc = cmd->cmdidx; |
| 436 | 436 | ||
| 437 | if (opc == MMC_CMD_STOP_TRANSMISSION) { | 437 | if (opc == MMC_CMD_STOP_TRANSMISSION) { |
| 438 | /* MMCIF sends the STOP command automatically */ | 438 | /* MMCIF sends the STOP command automatically */ |
| 439 | if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK) | 439 | if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK) |
| 440 | sh_mmcif_bitset(MASK_MCMD12DRE, | 440 | sh_mmcif_bitset(MASK_MCMD12DRE, |
| 441 | &host->regs->ce_int_mask); | 441 | &host->regs->ce_int_mask); |
| 442 | else | 442 | else |
| 443 | sh_mmcif_bitset(MASK_MCMD12RBE, | 443 | sh_mmcif_bitset(MASK_MCMD12RBE, |
| 444 | &host->regs->ce_int_mask); | 444 | &host->regs->ce_int_mask); |
| 445 | 445 | ||
| 446 | time = mmcif_wait_interrupt_flag(host); | 446 | time = mmcif_wait_interrupt_flag(host); |
| 447 | if (time == 0 || host->sd_error != 0) | 447 | if (time == 0 || host->sd_error != 0) |
| 448 | return sh_mmcif_error_manage(host); | 448 | return sh_mmcif_error_manage(host); |
| 449 | 449 | ||
| 450 | sh_mmcif_get_cmd12response(host, cmd); | 450 | sh_mmcif_get_cmd12response(host, cmd); |
| 451 | return 0; | 451 | return 0; |
| 452 | } | 452 | } |
| 453 | if (opc == MMC_CMD_SWITCH) | 453 | if (opc == MMC_CMD_SWITCH) |
| 454 | mask = MASK_MRBSYE; | 454 | mask = MASK_MRBSYE; |
| 455 | else | 455 | else |
| 456 | mask = MASK_MCRSPE; | 456 | mask = MASK_MCRSPE; |
| 457 | 457 | ||
| 458 | mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | | 458 | mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | |
| 459 | MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | | 459 | MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | |
| 460 | MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | | 460 | MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | |
| 461 | MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; | 461 | MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; |
| 462 | 462 | ||
| 463 | if (host->data) { | 463 | if (host->data) { |
| 464 | sh_mmcif_write(0, &host->regs->ce_block_set); | 464 | sh_mmcif_write(0, &host->regs->ce_block_set); |
| 465 | sh_mmcif_write(data->blocksize, &host->regs->ce_block_set); | 465 | sh_mmcif_write(data->blocksize, &host->regs->ce_block_set); |
| 466 | } | 466 | } |
| 467 | opc = sh_mmcif_set_cmd(host, data, cmd); | 467 | opc = sh_mmcif_set_cmd(host, data, cmd); |
| 468 | 468 | ||
| 469 | sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int); | 469 | sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int); |
| 470 | sh_mmcif_write(mask, &host->regs->ce_int_mask); | 470 | sh_mmcif_write(mask, &host->regs->ce_int_mask); |
| 471 | 471 | ||
| 472 | debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg); | 472 | debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg); |
| 473 | /* set arg */ | 473 | /* set arg */ |
| 474 | sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg); | 474 | sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg); |
| 475 | host->wait_int = 0; | 475 | host->wait_int = 0; |
| 476 | /* set cmd */ | 476 | /* set cmd */ |
| 477 | sh_mmcif_write(opc, &host->regs->ce_cmd_set); | 477 | sh_mmcif_write(opc, &host->regs->ce_cmd_set); |
| 478 | 478 | ||
| 479 | time = mmcif_wait_interrupt_flag(host); | 479 | time = mmcif_wait_interrupt_flag(host); |
| 480 | if (time == 0) | 480 | if (time == 0) |
| 481 | return sh_mmcif_error_manage(host); | 481 | return sh_mmcif_error_manage(host); |
| 482 | 482 | ||
| 483 | if (host->sd_error) { | 483 | if (host->sd_error) { |
| 484 | switch (cmd->cmdidx) { | 484 | switch (cmd->cmdidx) { |
| 485 | case MMC_CMD_ALL_SEND_CID: | 485 | case MMC_CMD_ALL_SEND_CID: |
| 486 | case MMC_CMD_SELECT_CARD: | 486 | case MMC_CMD_SELECT_CARD: |
| 487 | case MMC_CMD_APP_CMD: | 487 | case MMC_CMD_APP_CMD: |
| 488 | ret = TIMEOUT; | 488 | ret = TIMEOUT; |
| 489 | break; | 489 | break; |
| 490 | default: | 490 | default: |
| 491 | printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx); | 491 | printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx); |
| 492 | ret = sh_mmcif_error_manage(host); | 492 | ret = sh_mmcif_error_manage(host); |
| 493 | break; | 493 | break; |
| 494 | } | 494 | } |
| 495 | host->sd_error = 0; | 495 | host->sd_error = 0; |
| 496 | host->wait_int = 0; | 496 | host->wait_int = 0; |
| 497 | return ret; | 497 | return ret; |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /* if no response */ | 500 | /* if no response */ |
| 501 | if (!(opc & 0x00C00000)) | 501 | if (!(opc & 0x00C00000)) |
| 502 | return 0; | 502 | return 0; |
| 503 | 503 | ||
| 504 | if (host->wait_int == 1) { | 504 | if (host->wait_int == 1) { |
| 505 | sh_mmcif_get_response(host, cmd); | 505 | sh_mmcif_get_response(host, cmd); |
| 506 | host->wait_int = 0; | 506 | host->wait_int = 0; |
| 507 | } | 507 | } |
| 508 | if (host->data) | 508 | if (host->data) |
| 509 | ret = sh_mmcif_data_trans(host, data, cmd->cmdidx); | 509 | ret = sh_mmcif_data_trans(host, data, cmd->cmdidx); |
| 510 | host->last_cmd = cmd->cmdidx; | 510 | host->last_cmd = cmd->cmdidx; |
| 511 | 511 | ||
| 512 | return ret; | 512 | return ret; |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd, | 515 | static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd, |
| 516 | struct mmc_data *data) | 516 | struct mmc_data *data) |
| 517 | { | 517 | { |
| 518 | struct sh_mmcif_host *host = mmc->priv; | 518 | struct sh_mmcif_host *host = mmc->priv; |
| 519 | int ret; | 519 | int ret; |
| 520 | 520 | ||
| 521 | WATCHDOG_RESET(); | 521 | WATCHDOG_RESET(); |
| 522 | 522 | ||
| 523 | switch (cmd->cmdidx) { | 523 | switch (cmd->cmdidx) { |
| 524 | case MMC_CMD_APP_CMD: | 524 | case MMC_CMD_APP_CMD: |
| 525 | return TIMEOUT; | 525 | return TIMEOUT; |
| 526 | case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ | 526 | case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ |
| 527 | if (data) | 527 | if (data) |
| 528 | /* ext_csd */ | 528 | /* ext_csd */ |
| 529 | break; | 529 | break; |
| 530 | else | 530 | else |
| 531 | /* send_if_cond cmd (not support) */ | 531 | /* send_if_cond cmd (not support) */ |
| 532 | return TIMEOUT; | 532 | return TIMEOUT; |
| 533 | default: | 533 | default: |
| 534 | break; | 534 | break; |
| 535 | } | 535 | } |
| 536 | host->sd_error = 0; | 536 | host->sd_error = 0; |
| 537 | host->data = data; | 537 | host->data = data; |
| 538 | ret = sh_mmcif_start_cmd(host, data, cmd); | 538 | ret = sh_mmcif_start_cmd(host, data, cmd); |
| 539 | host->data = NULL; | 539 | host->data = NULL; |
| 540 | 540 | ||
| 541 | return ret; | 541 | return ret; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | static void sh_mmcif_set_ios(struct mmc *mmc) | 544 | static void sh_mmcif_set_ios(struct mmc *mmc) |
| 545 | { | 545 | { |
| 546 | struct sh_mmcif_host *host = mmc->priv; | 546 | struct sh_mmcif_host *host = mmc->priv; |
| 547 | 547 | ||
| 548 | if (mmc->clock) | 548 | if (mmc->clock) |
| 549 | sh_mmcif_clock_control(host, mmc->clock); | 549 | sh_mmcif_clock_control(host, mmc->clock); |
| 550 | 550 | ||
| 551 | if (mmc->bus_width == 8) | 551 | if (mmc->bus_width == 8) |
| 552 | host->bus_width = MMC_BUS_WIDTH_8; | 552 | host->bus_width = MMC_BUS_WIDTH_8; |
| 553 | else if (mmc->bus_width == 4) | 553 | else if (mmc->bus_width == 4) |
| 554 | host->bus_width = MMC_BUS_WIDTH_4; | 554 | host->bus_width = MMC_BUS_WIDTH_4; |
| 555 | else | 555 | else |
| 556 | host->bus_width = MMC_BUS_WIDTH_1; | 556 | host->bus_width = MMC_BUS_WIDTH_1; |
| 557 | 557 | ||
| 558 | debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width); | 558 | debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width); |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | static int sh_mmcif_init(struct mmc *mmc) | 561 | static int sh_mmcif_init(struct mmc *mmc) |
| 562 | { | 562 | { |
| 563 | struct sh_mmcif_host *host = mmc->priv; | 563 | struct sh_mmcif_host *host = mmc->priv; |
| 564 | 564 | ||
| 565 | sh_mmcif_sync_reset(host); | 565 | sh_mmcif_sync_reset(host); |
| 566 | sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask); | 566 | sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask); |
| 567 | return 0; | 567 | return 0; |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | static const struct mmc_ops sh_mmcif_ops = { | 570 | static const struct mmc_ops sh_mmcif_ops = { |
| 571 | .send_cmd = sh_mmcif_request, | 571 | .send_cmd = sh_mmcif_request, |
| 572 | .set_ios = sh_mmcif_set_ios, | 572 | .set_ios = sh_mmcif_set_ios, |
| 573 | .init = sh_mmcif_init, | 573 | .init = sh_mmcif_init, |
| 574 | }; | 574 | }; |
| 575 | 575 | ||
| 576 | static struct mmc_config sh_mmcif_cfg = { | 576 | static struct mmc_config sh_mmcif_cfg = { |
| 577 | .name = DRIVER_NAME, | 577 | .name = DRIVER_NAME, |
| 578 | .ops = &sh_mmcif_ops, | 578 | .ops = &sh_mmcif_ops, |
| 579 | .host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | | 579 | .host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | |
| 580 | MMC_MODE_8BIT | MMC_MODE_HC, | 580 | MMC_MODE_8BIT, |
| 581 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, | 581 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, |
| 582 | .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, | 582 | .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, |
| 583 | }; | 583 | }; |
| 584 | 584 | ||
| 585 | int mmcif_mmc_init(void) | 585 | int mmcif_mmc_init(void) |
| 586 | { | 586 | { |
| 587 | struct mmc *mmc; | 587 | struct mmc *mmc; |
| 588 | struct sh_mmcif_host *host = NULL; | 588 | struct sh_mmcif_host *host = NULL; |
| 589 | 589 | ||
| 590 | host = malloc(sizeof(struct sh_mmcif_host)); | 590 | host = malloc(sizeof(struct sh_mmcif_host)); |
| 591 | if (!host) | 591 | if (!host) |
| 592 | return -ENOMEM; | 592 | return -ENOMEM; |
| 593 | memset(host, 0, sizeof(*host)); | 593 | memset(host, 0, sizeof(*host)); |
| 594 | 594 | ||
| 595 | host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR; | 595 | host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR; |
| 596 | host->clk = CONFIG_SH_MMCIF_CLK; | 596 | host->clk = CONFIG_SH_MMCIF_CLK; |
| 597 | 597 | ||
| 598 | sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk); | 598 | sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk); |
| 599 | sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk); | 599 | sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk); |
| 600 | 600 | ||
| 601 | mmc = mmc_create(&sh_mmcif_cfg, host); | 601 | mmc = mmc_create(&sh_mmcif_cfg, host); |
| 602 | if (mmc == NULL) { | 602 | if (mmc == NULL) { |
| 603 | free(host); | 603 | free(host); |
| 604 | return -ENOMEM; | 604 | return -ENOMEM; |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | return 0; | 607 | return 0; |
| 608 | } | 608 | } |
| 609 | 609 |
drivers/mmc/sunxi_mmc.c
| 1 | /* | 1 | /* |
| 2 | * (C) Copyright 2007-2011 | 2 | * (C) Copyright 2007-2011 |
| 3 | * Allwinner Technology Co., Ltd. <www.allwinnertech.com> | 3 | * Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
| 4 | * Aaron <leafy.myeh@allwinnertech.com> | 4 | * Aaron <leafy.myeh@allwinnertech.com> |
| 5 | * | 5 | * |
| 6 | * MMC driver for allwinner sunxi platform. | 6 | * MMC driver for allwinner sunxi platform. |
| 7 | * | 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <common.h> | 11 | #include <common.h> |
| 12 | #include <malloc.h> | 12 | #include <malloc.h> |
| 13 | #include <mmc.h> | 13 | #include <mmc.h> |
| 14 | #include <asm/io.h> | 14 | #include <asm/io.h> |
| 15 | #include <asm/arch/clock.h> | 15 | #include <asm/arch/clock.h> |
| 16 | #include <asm/arch/cpu.h> | 16 | #include <asm/arch/cpu.h> |
| 17 | #include <asm/arch/gpio.h> | 17 | #include <asm/arch/gpio.h> |
| 18 | #include <asm/arch/mmc.h> | 18 | #include <asm/arch/mmc.h> |
| 19 | #include <asm-generic/gpio.h> | 19 | #include <asm-generic/gpio.h> |
| 20 | 20 | ||
| 21 | struct sunxi_mmc_host { | 21 | struct sunxi_mmc_host { |
| 22 | unsigned mmc_no; | 22 | unsigned mmc_no; |
| 23 | uint32_t *mclkreg; | 23 | uint32_t *mclkreg; |
| 24 | unsigned fatal_err; | 24 | unsigned fatal_err; |
| 25 | struct sunxi_mmc *reg; | 25 | struct sunxi_mmc *reg; |
| 26 | struct mmc_config cfg; | 26 | struct mmc_config cfg; |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | /* support 4 mmc hosts */ | 29 | /* support 4 mmc hosts */ |
| 30 | struct sunxi_mmc_host mmc_host[4]; | 30 | struct sunxi_mmc_host mmc_host[4]; |
| 31 | 31 | ||
| 32 | static int sunxi_mmc_getcd_gpio(int sdc_no) | 32 | static int sunxi_mmc_getcd_gpio(int sdc_no) |
| 33 | { | 33 | { |
| 34 | switch (sdc_no) { | 34 | switch (sdc_no) { |
| 35 | case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); | 35 | case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); |
| 36 | case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); | 36 | case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); |
| 37 | case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); | 37 | case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); |
| 38 | case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); | 38 | case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); |
| 39 | } | 39 | } |
| 40 | return -1; | 40 | return -1; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static int mmc_resource_init(int sdc_no) | 43 | static int mmc_resource_init(int sdc_no) |
| 44 | { | 44 | { |
| 45 | struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; | 45 | struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; |
| 46 | struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; | 46 | struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
| 47 | int cd_pin, ret = 0; | 47 | int cd_pin, ret = 0; |
| 48 | 48 | ||
| 49 | debug("init mmc %d resource\n", sdc_no); | 49 | debug("init mmc %d resource\n", sdc_no); |
| 50 | 50 | ||
| 51 | switch (sdc_no) { | 51 | switch (sdc_no) { |
| 52 | case 0: | 52 | case 0: |
| 53 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; | 53 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; |
| 54 | mmchost->mclkreg = &ccm->sd0_clk_cfg; | 54 | mmchost->mclkreg = &ccm->sd0_clk_cfg; |
| 55 | break; | 55 | break; |
| 56 | case 1: | 56 | case 1: |
| 57 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; | 57 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; |
| 58 | mmchost->mclkreg = &ccm->sd1_clk_cfg; | 58 | mmchost->mclkreg = &ccm->sd1_clk_cfg; |
| 59 | break; | 59 | break; |
| 60 | case 2: | 60 | case 2: |
| 61 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; | 61 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; |
| 62 | mmchost->mclkreg = &ccm->sd2_clk_cfg; | 62 | mmchost->mclkreg = &ccm->sd2_clk_cfg; |
| 63 | break; | 63 | break; |
| 64 | case 3: | 64 | case 3: |
| 65 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; | 65 | mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; |
| 66 | mmchost->mclkreg = &ccm->sd3_clk_cfg; | 66 | mmchost->mclkreg = &ccm->sd3_clk_cfg; |
| 67 | break; | 67 | break; |
| 68 | default: | 68 | default: |
| 69 | printf("Wrong mmc number %d\n", sdc_no); | 69 | printf("Wrong mmc number %d\n", sdc_no); |
| 70 | return -1; | 70 | return -1; |
| 71 | } | 71 | } |
| 72 | mmchost->mmc_no = sdc_no; | 72 | mmchost->mmc_no = sdc_no; |
| 73 | 73 | ||
| 74 | cd_pin = sunxi_mmc_getcd_gpio(sdc_no); | 74 | cd_pin = sunxi_mmc_getcd_gpio(sdc_no); |
| 75 | if (cd_pin != -1) { | 75 | if (cd_pin != -1) { |
| 76 | ret = gpio_request(cd_pin, "mmc_cd"); | 76 | ret = gpio_request(cd_pin, "mmc_cd"); |
| 77 | if (!ret) | 77 | if (!ret) |
| 78 | ret = gpio_direction_input(cd_pin); | 78 | ret = gpio_direction_input(cd_pin); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | return ret; | 81 | return ret; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz) | 84 | static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz) |
| 85 | { | 85 | { |
| 86 | unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; | 86 | unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; |
| 87 | 87 | ||
| 88 | if (hz <= 24000000) { | 88 | if (hz <= 24000000) { |
| 89 | pll = CCM_MMC_CTRL_OSCM24; | 89 | pll = CCM_MMC_CTRL_OSCM24; |
| 90 | pll_hz = 24000000; | 90 | pll_hz = 24000000; |
| 91 | } else { | 91 | } else { |
| 92 | #ifdef CONFIG_MACH_SUN9I | 92 | #ifdef CONFIG_MACH_SUN9I |
| 93 | pll = CCM_MMC_CTRL_PLL_PERIPH0; | 93 | pll = CCM_MMC_CTRL_PLL_PERIPH0; |
| 94 | pll_hz = clock_get_pll4_periph0(); | 94 | pll_hz = clock_get_pll4_periph0(); |
| 95 | #else | 95 | #else |
| 96 | pll = CCM_MMC_CTRL_PLL6; | 96 | pll = CCM_MMC_CTRL_PLL6; |
| 97 | pll_hz = clock_get_pll6(); | 97 | pll_hz = clock_get_pll6(); |
| 98 | #endif | 98 | #endif |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | div = pll_hz / hz; | 101 | div = pll_hz / hz; |
| 102 | if (pll_hz % hz) | 102 | if (pll_hz % hz) |
| 103 | div++; | 103 | div++; |
| 104 | 104 | ||
| 105 | n = 0; | 105 | n = 0; |
| 106 | while (div > 16) { | 106 | while (div > 16) { |
| 107 | n++; | 107 | n++; |
| 108 | div = (div + 1) / 2; | 108 | div = (div + 1) / 2; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | if (n > 3) { | 111 | if (n > 3) { |
| 112 | printf("mmc %u error cannot set clock to %u\n", | 112 | printf("mmc %u error cannot set clock to %u\n", |
| 113 | mmchost->mmc_no, hz); | 113 | mmchost->mmc_no, hz); |
| 114 | return -1; | 114 | return -1; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /* determine delays */ | 117 | /* determine delays */ |
| 118 | if (hz <= 400000) { | 118 | if (hz <= 400000) { |
| 119 | oclk_dly = 0; | 119 | oclk_dly = 0; |
| 120 | sclk_dly = 7; | 120 | sclk_dly = 7; |
| 121 | } else if (hz <= 25000000) { | 121 | } else if (hz <= 25000000) { |
| 122 | oclk_dly = 0; | 122 | oclk_dly = 0; |
| 123 | sclk_dly = 5; | 123 | sclk_dly = 5; |
| 124 | } else if (hz <= 50000000) { | 124 | } else if (hz <= 50000000) { |
| 125 | oclk_dly = 3; | 125 | oclk_dly = 3; |
| 126 | sclk_dly = 5; | 126 | sclk_dly = 5; |
| 127 | } else { | 127 | } else { |
| 128 | /* hz > 50000000 */ | 128 | /* hz > 50000000 */ |
| 129 | oclk_dly = 2; | 129 | oclk_dly = 2; |
| 130 | sclk_dly = 4; | 130 | sclk_dly = 4; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | writel(CCM_MMC_CTRL_ENABLE | pll | CCM_MMC_CTRL_SCLK_DLY(sclk_dly) | | 133 | writel(CCM_MMC_CTRL_ENABLE | pll | CCM_MMC_CTRL_SCLK_DLY(sclk_dly) | |
| 134 | CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_OCLK_DLY(oclk_dly) | | 134 | CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_OCLK_DLY(oclk_dly) | |
| 135 | CCM_MMC_CTRL_M(div), mmchost->mclkreg); | 135 | CCM_MMC_CTRL_M(div), mmchost->mclkreg); |
| 136 | 136 | ||
| 137 | debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n", | 137 | debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n", |
| 138 | mmchost->mmc_no, hz, pll_hz, 1u << n, div, | 138 | mmchost->mmc_no, hz, pll_hz, 1u << n, div, |
| 139 | pll_hz / (1u << n) / div); | 139 | pll_hz / (1u << n) / div); |
| 140 | 140 | ||
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static int mmc_clk_io_on(int sdc_no) | 144 | static int mmc_clk_io_on(int sdc_no) |
| 145 | { | 145 | { |
| 146 | struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; | 146 | struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; |
| 147 | struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; | 147 | struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
| 148 | 148 | ||
| 149 | debug("init mmc %d clock and io\n", sdc_no); | 149 | debug("init mmc %d clock and io\n", sdc_no); |
| 150 | 150 | ||
| 151 | /* config ahb clock */ | 151 | /* config ahb clock */ |
| 152 | setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); | 152 | setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); |
| 153 | 153 | ||
| 154 | #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \ | 154 | #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \ |
| 155 | defined(CONFIG_MACH_SUN9I) | 155 | defined(CONFIG_MACH_SUN9I) |
| 156 | /* unassert reset */ | 156 | /* unassert reset */ |
| 157 | setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); | 157 | setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); |
| 158 | #endif | 158 | #endif |
| 159 | #if defined(CONFIG_MACH_SUN9I) | 159 | #if defined(CONFIG_MACH_SUN9I) |
| 160 | /* sun9i has a mmc-common module, also set the gate and reset there */ | 160 | /* sun9i has a mmc-common module, also set the gate and reset there */ |
| 161 | writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, | 161 | writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, |
| 162 | SUNXI_MMC_COMMON_BASE + 4 * sdc_no); | 162 | SUNXI_MMC_COMMON_BASE + 4 * sdc_no); |
| 163 | #endif | 163 | #endif |
| 164 | 164 | ||
| 165 | return mmc_set_mod_clk(mmchost, 24000000); | 165 | return mmc_set_mod_clk(mmchost, 24000000); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | static int mmc_update_clk(struct mmc *mmc) | 168 | static int mmc_update_clk(struct mmc *mmc) |
| 169 | { | 169 | { |
| 170 | struct sunxi_mmc_host *mmchost = mmc->priv; | 170 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 171 | unsigned int cmd; | 171 | unsigned int cmd; |
| 172 | unsigned timeout_msecs = 2000; | 172 | unsigned timeout_msecs = 2000; |
| 173 | 173 | ||
| 174 | cmd = SUNXI_MMC_CMD_START | | 174 | cmd = SUNXI_MMC_CMD_START | |
| 175 | SUNXI_MMC_CMD_UPCLK_ONLY | | 175 | SUNXI_MMC_CMD_UPCLK_ONLY | |
| 176 | SUNXI_MMC_CMD_WAIT_PRE_OVER; | 176 | SUNXI_MMC_CMD_WAIT_PRE_OVER; |
| 177 | writel(cmd, &mmchost->reg->cmd); | 177 | writel(cmd, &mmchost->reg->cmd); |
| 178 | while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) { | 178 | while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) { |
| 179 | if (!timeout_msecs--) | 179 | if (!timeout_msecs--) |
| 180 | return -1; | 180 | return -1; |
| 181 | udelay(1000); | 181 | udelay(1000); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /* clock update sets various irq status bits, clear these */ | 184 | /* clock update sets various irq status bits, clear these */ |
| 185 | writel(readl(&mmchost->reg->rint), &mmchost->reg->rint); | 185 | writel(readl(&mmchost->reg->rint), &mmchost->reg->rint); |
| 186 | 186 | ||
| 187 | return 0; | 187 | return 0; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | static int mmc_config_clock(struct mmc *mmc) | 190 | static int mmc_config_clock(struct mmc *mmc) |
| 191 | { | 191 | { |
| 192 | struct sunxi_mmc_host *mmchost = mmc->priv; | 192 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 193 | unsigned rval = readl(&mmchost->reg->clkcr); | 193 | unsigned rval = readl(&mmchost->reg->clkcr); |
| 194 | 194 | ||
| 195 | /* Disable Clock */ | 195 | /* Disable Clock */ |
| 196 | rval &= ~SUNXI_MMC_CLK_ENABLE; | 196 | rval &= ~SUNXI_MMC_CLK_ENABLE; |
| 197 | writel(rval, &mmchost->reg->clkcr); | 197 | writel(rval, &mmchost->reg->clkcr); |
| 198 | if (mmc_update_clk(mmc)) | 198 | if (mmc_update_clk(mmc)) |
| 199 | return -1; | 199 | return -1; |
| 200 | 200 | ||
| 201 | /* Set mod_clk to new rate */ | 201 | /* Set mod_clk to new rate */ |
| 202 | if (mmc_set_mod_clk(mmchost, mmc->clock)) | 202 | if (mmc_set_mod_clk(mmchost, mmc->clock)) |
| 203 | return -1; | 203 | return -1; |
| 204 | 204 | ||
| 205 | /* Clear internal divider */ | 205 | /* Clear internal divider */ |
| 206 | rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; | 206 | rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; |
| 207 | writel(rval, &mmchost->reg->clkcr); | 207 | writel(rval, &mmchost->reg->clkcr); |
| 208 | 208 | ||
| 209 | /* Re-enable Clock */ | 209 | /* Re-enable Clock */ |
| 210 | rval |= SUNXI_MMC_CLK_ENABLE; | 210 | rval |= SUNXI_MMC_CLK_ENABLE; |
| 211 | writel(rval, &mmchost->reg->clkcr); | 211 | writel(rval, &mmchost->reg->clkcr); |
| 212 | if (mmc_update_clk(mmc)) | 212 | if (mmc_update_clk(mmc)) |
| 213 | return -1; | 213 | return -1; |
| 214 | 214 | ||
| 215 | return 0; | 215 | return 0; |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static void sunxi_mmc_set_ios(struct mmc *mmc) | 218 | static void sunxi_mmc_set_ios(struct mmc *mmc) |
| 219 | { | 219 | { |
| 220 | struct sunxi_mmc_host *mmchost = mmc->priv; | 220 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 221 | 221 | ||
| 222 | debug("set ios: bus_width: %x, clock: %d\n", | 222 | debug("set ios: bus_width: %x, clock: %d\n", |
| 223 | mmc->bus_width, mmc->clock); | 223 | mmc->bus_width, mmc->clock); |
| 224 | 224 | ||
| 225 | /* Change clock first */ | 225 | /* Change clock first */ |
| 226 | if (mmc->clock && mmc_config_clock(mmc) != 0) { | 226 | if (mmc->clock && mmc_config_clock(mmc) != 0) { |
| 227 | mmchost->fatal_err = 1; | 227 | mmchost->fatal_err = 1; |
| 228 | return; | 228 | return; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | /* Change bus width */ | 231 | /* Change bus width */ |
| 232 | if (mmc->bus_width == 8) | 232 | if (mmc->bus_width == 8) |
| 233 | writel(0x2, &mmchost->reg->width); | 233 | writel(0x2, &mmchost->reg->width); |
| 234 | else if (mmc->bus_width == 4) | 234 | else if (mmc->bus_width == 4) |
| 235 | writel(0x1, &mmchost->reg->width); | 235 | writel(0x1, &mmchost->reg->width); |
| 236 | else | 236 | else |
| 237 | writel(0x0, &mmchost->reg->width); | 237 | writel(0x0, &mmchost->reg->width); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static int sunxi_mmc_core_init(struct mmc *mmc) | 240 | static int sunxi_mmc_core_init(struct mmc *mmc) |
| 241 | { | 241 | { |
| 242 | struct sunxi_mmc_host *mmchost = mmc->priv; | 242 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 243 | 243 | ||
| 244 | /* Reset controller */ | 244 | /* Reset controller */ |
| 245 | writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); | 245 | writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); |
| 246 | udelay(1000); | 246 | udelay(1000); |
| 247 | 247 | ||
| 248 | return 0; | 248 | return 0; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) | 251 | static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) |
| 252 | { | 252 | { |
| 253 | struct sunxi_mmc_host *mmchost = mmc->priv; | 253 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 254 | const int reading = !!(data->flags & MMC_DATA_READ); | 254 | const int reading = !!(data->flags & MMC_DATA_READ); |
| 255 | const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY : | 255 | const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY : |
| 256 | SUNXI_MMC_STATUS_FIFO_FULL; | 256 | SUNXI_MMC_STATUS_FIFO_FULL; |
| 257 | unsigned i; | 257 | unsigned i; |
| 258 | unsigned byte_cnt = data->blocksize * data->blocks; | 258 | unsigned byte_cnt = data->blocksize * data->blocks; |
| 259 | unsigned timeout_msecs = 2000; | 259 | unsigned timeout_msecs = 2000; |
| 260 | unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); | 260 | unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); |
| 261 | 261 | ||
| 262 | /* Always read / write data through the CPU */ | 262 | /* Always read / write data through the CPU */ |
| 263 | setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); | 263 | setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); |
| 264 | 264 | ||
| 265 | for (i = 0; i < (byte_cnt >> 2); i++) { | 265 | for (i = 0; i < (byte_cnt >> 2); i++) { |
| 266 | while (readl(&mmchost->reg->status) & status_bit) { | 266 | while (readl(&mmchost->reg->status) & status_bit) { |
| 267 | if (!timeout_msecs--) | 267 | if (!timeout_msecs--) |
| 268 | return -1; | 268 | return -1; |
| 269 | udelay(1000); | 269 | udelay(1000); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | if (reading) | 272 | if (reading) |
| 273 | buff[i] = readl(&mmchost->reg->fifo); | 273 | buff[i] = readl(&mmchost->reg->fifo); |
| 274 | else | 274 | else |
| 275 | writel(buff[i], &mmchost->reg->fifo); | 275 | writel(buff[i], &mmchost->reg->fifo); |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | return 0; | 278 | return 0; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs, | 281 | static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs, |
| 282 | unsigned int done_bit, const char *what) | 282 | unsigned int done_bit, const char *what) |
| 283 | { | 283 | { |
| 284 | struct sunxi_mmc_host *mmchost = mmc->priv; | 284 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 285 | unsigned int status; | 285 | unsigned int status; |
| 286 | 286 | ||
| 287 | do { | 287 | do { |
| 288 | status = readl(&mmchost->reg->rint); | 288 | status = readl(&mmchost->reg->rint); |
| 289 | if (!timeout_msecs-- || | 289 | if (!timeout_msecs-- || |
| 290 | (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { | 290 | (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { |
| 291 | debug("%s timeout %x\n", what, | 291 | debug("%s timeout %x\n", what, |
| 292 | status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); | 292 | status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); |
| 293 | return TIMEOUT; | 293 | return TIMEOUT; |
| 294 | } | 294 | } |
| 295 | udelay(1000); | 295 | udelay(1000); |
| 296 | } while (!(status & done_bit)); | 296 | } while (!(status & done_bit)); |
| 297 | 297 | ||
| 298 | return 0; | 298 | return 0; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | static int sunxi_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | 301 | static int sunxi_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
| 302 | struct mmc_data *data) | 302 | struct mmc_data *data) |
| 303 | { | 303 | { |
| 304 | struct sunxi_mmc_host *mmchost = mmc->priv; | 304 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 305 | unsigned int cmdval = SUNXI_MMC_CMD_START; | 305 | unsigned int cmdval = SUNXI_MMC_CMD_START; |
| 306 | unsigned int timeout_msecs; | 306 | unsigned int timeout_msecs; |
| 307 | int error = 0; | 307 | int error = 0; |
| 308 | unsigned int status = 0; | 308 | unsigned int status = 0; |
| 309 | unsigned int bytecnt = 0; | 309 | unsigned int bytecnt = 0; |
| 310 | 310 | ||
| 311 | if (mmchost->fatal_err) | 311 | if (mmchost->fatal_err) |
| 312 | return -1; | 312 | return -1; |
| 313 | if (cmd->resp_type & MMC_RSP_BUSY) | 313 | if (cmd->resp_type & MMC_RSP_BUSY) |
| 314 | debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); | 314 | debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); |
| 315 | if (cmd->cmdidx == 12) | 315 | if (cmd->cmdidx == 12) |
| 316 | return 0; | 316 | return 0; |
| 317 | 317 | ||
| 318 | if (!cmd->cmdidx) | 318 | if (!cmd->cmdidx) |
| 319 | cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; | 319 | cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; |
| 320 | if (cmd->resp_type & MMC_RSP_PRESENT) | 320 | if (cmd->resp_type & MMC_RSP_PRESENT) |
| 321 | cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; | 321 | cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; |
| 322 | if (cmd->resp_type & MMC_RSP_136) | 322 | if (cmd->resp_type & MMC_RSP_136) |
| 323 | cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; | 323 | cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; |
| 324 | if (cmd->resp_type & MMC_RSP_CRC) | 324 | if (cmd->resp_type & MMC_RSP_CRC) |
| 325 | cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC; | 325 | cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC; |
| 326 | 326 | ||
| 327 | if (data) { | 327 | if (data) { |
| 328 | if ((u32) data->dest & 0x3) { | 328 | if ((u32) data->dest & 0x3) { |
| 329 | error = -1; | 329 | error = -1; |
| 330 | goto out; | 330 | goto out; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; | 333 | cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; |
| 334 | if (data->flags & MMC_DATA_WRITE) | 334 | if (data->flags & MMC_DATA_WRITE) |
| 335 | cmdval |= SUNXI_MMC_CMD_WRITE; | 335 | cmdval |= SUNXI_MMC_CMD_WRITE; |
| 336 | if (data->blocks > 1) | 336 | if (data->blocks > 1) |
| 337 | cmdval |= SUNXI_MMC_CMD_AUTO_STOP; | 337 | cmdval |= SUNXI_MMC_CMD_AUTO_STOP; |
| 338 | writel(data->blocksize, &mmchost->reg->blksz); | 338 | writel(data->blocksize, &mmchost->reg->blksz); |
| 339 | writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt); | 339 | writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no, | 342 | debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no, |
| 343 | cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); | 343 | cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); |
| 344 | writel(cmd->cmdarg, &mmchost->reg->arg); | 344 | writel(cmd->cmdarg, &mmchost->reg->arg); |
| 345 | 345 | ||
| 346 | if (!data) | 346 | if (!data) |
| 347 | writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); | 347 | writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); |
| 348 | 348 | ||
| 349 | /* | 349 | /* |
| 350 | * transfer data and check status | 350 | * transfer data and check status |
| 351 | * STATREG[2] : FIFO empty | 351 | * STATREG[2] : FIFO empty |
| 352 | * STATREG[3] : FIFO full | 352 | * STATREG[3] : FIFO full |
| 353 | */ | 353 | */ |
| 354 | if (data) { | 354 | if (data) { |
| 355 | int ret = 0; | 355 | int ret = 0; |
| 356 | 356 | ||
| 357 | bytecnt = data->blocksize * data->blocks; | 357 | bytecnt = data->blocksize * data->blocks; |
| 358 | debug("trans data %d bytes\n", bytecnt); | 358 | debug("trans data %d bytes\n", bytecnt); |
| 359 | writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); | 359 | writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); |
| 360 | ret = mmc_trans_data_by_cpu(mmc, data); | 360 | ret = mmc_trans_data_by_cpu(mmc, data); |
| 361 | if (ret) { | 361 | if (ret) { |
| 362 | error = readl(&mmchost->reg->rint) & \ | 362 | error = readl(&mmchost->reg->rint) & \ |
| 363 | SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; | 363 | SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; |
| 364 | error = TIMEOUT; | 364 | error = TIMEOUT; |
| 365 | goto out; | 365 | goto out; |
| 366 | } | 366 | } |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | error = mmc_rint_wait(mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, "cmd"); | 369 | error = mmc_rint_wait(mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, "cmd"); |
| 370 | if (error) | 370 | if (error) |
| 371 | goto out; | 371 | goto out; |
| 372 | 372 | ||
| 373 | if (data) { | 373 | if (data) { |
| 374 | timeout_msecs = 120; | 374 | timeout_msecs = 120; |
| 375 | debug("cacl timeout %x msec\n", timeout_msecs); | 375 | debug("cacl timeout %x msec\n", timeout_msecs); |
| 376 | error = mmc_rint_wait(mmc, timeout_msecs, | 376 | error = mmc_rint_wait(mmc, timeout_msecs, |
| 377 | data->blocks > 1 ? | 377 | data->blocks > 1 ? |
| 378 | SUNXI_MMC_RINT_AUTO_COMMAND_DONE : | 378 | SUNXI_MMC_RINT_AUTO_COMMAND_DONE : |
| 379 | SUNXI_MMC_RINT_DATA_OVER, | 379 | SUNXI_MMC_RINT_DATA_OVER, |
| 380 | "data"); | 380 | "data"); |
| 381 | if (error) | 381 | if (error) |
| 382 | goto out; | 382 | goto out; |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | if (cmd->resp_type & MMC_RSP_BUSY) { | 385 | if (cmd->resp_type & MMC_RSP_BUSY) { |
| 386 | timeout_msecs = 2000; | 386 | timeout_msecs = 2000; |
| 387 | do { | 387 | do { |
| 388 | status = readl(&mmchost->reg->status); | 388 | status = readl(&mmchost->reg->status); |
| 389 | if (!timeout_msecs--) { | 389 | if (!timeout_msecs--) { |
| 390 | debug("busy timeout\n"); | 390 | debug("busy timeout\n"); |
| 391 | error = TIMEOUT; | 391 | error = TIMEOUT; |
| 392 | goto out; | 392 | goto out; |
| 393 | } | 393 | } |
| 394 | udelay(1000); | 394 | udelay(1000); |
| 395 | } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); | 395 | } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | if (cmd->resp_type & MMC_RSP_136) { | 398 | if (cmd->resp_type & MMC_RSP_136) { |
| 399 | cmd->response[0] = readl(&mmchost->reg->resp3); | 399 | cmd->response[0] = readl(&mmchost->reg->resp3); |
| 400 | cmd->response[1] = readl(&mmchost->reg->resp2); | 400 | cmd->response[1] = readl(&mmchost->reg->resp2); |
| 401 | cmd->response[2] = readl(&mmchost->reg->resp1); | 401 | cmd->response[2] = readl(&mmchost->reg->resp1); |
| 402 | cmd->response[3] = readl(&mmchost->reg->resp0); | 402 | cmd->response[3] = readl(&mmchost->reg->resp0); |
| 403 | debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", | 403 | debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", |
| 404 | cmd->response[3], cmd->response[2], | 404 | cmd->response[3], cmd->response[2], |
| 405 | cmd->response[1], cmd->response[0]); | 405 | cmd->response[1], cmd->response[0]); |
| 406 | } else { | 406 | } else { |
| 407 | cmd->response[0] = readl(&mmchost->reg->resp0); | 407 | cmd->response[0] = readl(&mmchost->reg->resp0); |
| 408 | debug("mmc resp 0x%08x\n", cmd->response[0]); | 408 | debug("mmc resp 0x%08x\n", cmd->response[0]); |
| 409 | } | 409 | } |
| 410 | out: | 410 | out: |
| 411 | if (error < 0) { | 411 | if (error < 0) { |
| 412 | writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); | 412 | writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); |
| 413 | mmc_update_clk(mmc); | 413 | mmc_update_clk(mmc); |
| 414 | } | 414 | } |
| 415 | writel(0xffffffff, &mmchost->reg->rint); | 415 | writel(0xffffffff, &mmchost->reg->rint); |
| 416 | writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET, | 416 | writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET, |
| 417 | &mmchost->reg->gctrl); | 417 | &mmchost->reg->gctrl); |
| 418 | 418 | ||
| 419 | return error; | 419 | return error; |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | static int sunxi_mmc_getcd(struct mmc *mmc) | 422 | static int sunxi_mmc_getcd(struct mmc *mmc) |
| 423 | { | 423 | { |
| 424 | struct sunxi_mmc_host *mmchost = mmc->priv; | 424 | struct sunxi_mmc_host *mmchost = mmc->priv; |
| 425 | int cd_pin; | 425 | int cd_pin; |
| 426 | 426 | ||
| 427 | cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no); | 427 | cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no); |
| 428 | if (cd_pin == -1) | 428 | if (cd_pin == -1) |
| 429 | return 1; | 429 | return 1; |
| 430 | 430 | ||
| 431 | return !gpio_get_value(cd_pin); | 431 | return !gpio_get_value(cd_pin); |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | static const struct mmc_ops sunxi_mmc_ops = { | 434 | static const struct mmc_ops sunxi_mmc_ops = { |
| 435 | .send_cmd = sunxi_mmc_send_cmd, | 435 | .send_cmd = sunxi_mmc_send_cmd, |
| 436 | .set_ios = sunxi_mmc_set_ios, | 436 | .set_ios = sunxi_mmc_set_ios, |
| 437 | .init = sunxi_mmc_core_init, | 437 | .init = sunxi_mmc_core_init, |
| 438 | .getcd = sunxi_mmc_getcd, | 438 | .getcd = sunxi_mmc_getcd, |
| 439 | }; | 439 | }; |
| 440 | 440 | ||
| 441 | struct mmc *sunxi_mmc_init(int sdc_no) | 441 | struct mmc *sunxi_mmc_init(int sdc_no) |
| 442 | { | 442 | { |
| 443 | struct mmc_config *cfg = &mmc_host[sdc_no].cfg; | 443 | struct mmc_config *cfg = &mmc_host[sdc_no].cfg; |
| 444 | 444 | ||
| 445 | memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); | 445 | memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); |
| 446 | 446 | ||
| 447 | cfg->name = "SUNXI SD/MMC"; | 447 | cfg->name = "SUNXI SD/MMC"; |
| 448 | cfg->ops = &sunxi_mmc_ops; | 448 | cfg->ops = &sunxi_mmc_ops; |
| 449 | 449 | ||
| 450 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; | 450 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
| 451 | cfg->host_caps = MMC_MODE_4BIT; | 451 | cfg->host_caps = MMC_MODE_4BIT; |
| 452 | cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; | 452 | cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 453 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 453 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
| 454 | 454 | ||
| 455 | cfg->f_min = 400000; | 455 | cfg->f_min = 400000; |
| 456 | cfg->f_max = 52000000; | 456 | cfg->f_max = 52000000; |
| 457 | 457 | ||
| 458 | if (mmc_resource_init(sdc_no) != 0) | 458 | if (mmc_resource_init(sdc_no) != 0) |
| 459 | return NULL; | 459 | return NULL; |
| 460 | 460 | ||
| 461 | mmc_clk_io_on(sdc_no); | 461 | mmc_clk_io_on(sdc_no); |
| 462 | 462 | ||
| 463 | return mmc_create(cfg, &mmc_host[sdc_no]); | 463 | return mmc_create(cfg, &mmc_host[sdc_no]); |
| 464 | } | 464 | } |
| 465 | 465 |
drivers/mmc/tegra_mmc.c
| 1 | /* | 1 | /* |
| 2 | * (C) Copyright 2009 SAMSUNG Electronics | 2 | * (C) Copyright 2009 SAMSUNG Electronics |
| 3 | * Minkyu Kang <mk7.kang@samsung.com> | 3 | * Minkyu Kang <mk7.kang@samsung.com> |
| 4 | * Jaehoon Chung <jh80.chung@samsung.com> | 4 | * Jaehoon Chung <jh80.chung@samsung.com> |
| 5 | * Portions Copyright 2011-2013 NVIDIA Corporation | 5 | * Portions Copyright 2011-2013 NVIDIA Corporation |
| 6 | * | 6 | * |
| 7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <bouncebuf.h> | 10 | #include <bouncebuf.h> |
| 11 | #include <common.h> | 11 | #include <common.h> |
| 12 | #include <asm/gpio.h> | 12 | #include <asm/gpio.h> |
| 13 | #include <asm/io.h> | 13 | #include <asm/io.h> |
| 14 | #include <asm/arch/clock.h> | 14 | #include <asm/arch/clock.h> |
| 15 | #include <asm/arch-tegra/clk_rst.h> | 15 | #include <asm/arch-tegra/clk_rst.h> |
| 16 | #include <asm/arch-tegra/mmc.h> | 16 | #include <asm/arch-tegra/mmc.h> |
| 17 | #include <asm/arch-tegra/tegra_mmc.h> | 17 | #include <asm/arch-tegra/tegra_mmc.h> |
| 18 | #include <mmc.h> | 18 | #include <mmc.h> |
| 19 | 19 | ||
| 20 | DECLARE_GLOBAL_DATA_PTR; | 20 | DECLARE_GLOBAL_DATA_PTR; |
| 21 | 21 | ||
| 22 | struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE]; | 22 | struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE]; |
| 23 | 23 | ||
| 24 | #ifndef CONFIG_OF_CONTROL | 24 | #ifndef CONFIG_OF_CONTROL |
| 25 | #error "Please enable device tree support to use this driver" | 25 | #error "Please enable device tree support to use this driver" |
| 26 | #endif | 26 | #endif |
| 27 | 27 | ||
| 28 | static void mmc_set_power(struct mmc_host *host, unsigned short power) | 28 | static void mmc_set_power(struct mmc_host *host, unsigned short power) |
| 29 | { | 29 | { |
| 30 | u8 pwr = 0; | 30 | u8 pwr = 0; |
| 31 | debug("%s: power = %x\n", __func__, power); | 31 | debug("%s: power = %x\n", __func__, power); |
| 32 | 32 | ||
| 33 | if (power != (unsigned short)-1) { | 33 | if (power != (unsigned short)-1) { |
| 34 | switch (1 << power) { | 34 | switch (1 << power) { |
| 35 | case MMC_VDD_165_195: | 35 | case MMC_VDD_165_195: |
| 36 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; | 36 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; |
| 37 | break; | 37 | break; |
| 38 | case MMC_VDD_29_30: | 38 | case MMC_VDD_29_30: |
| 39 | case MMC_VDD_30_31: | 39 | case MMC_VDD_30_31: |
| 40 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0; | 40 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0; |
| 41 | break; | 41 | break; |
| 42 | case MMC_VDD_32_33: | 42 | case MMC_VDD_32_33: |
| 43 | case MMC_VDD_33_34: | 43 | case MMC_VDD_33_34: |
| 44 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; | 44 | pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; |
| 45 | break; | 45 | break; |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | debug("%s: pwr = %X\n", __func__, pwr); | 48 | debug("%s: pwr = %X\n", __func__, pwr); |
| 49 | 49 | ||
| 50 | /* Set the bus voltage first (if any) */ | 50 | /* Set the bus voltage first (if any) */ |
| 51 | writeb(pwr, &host->reg->pwrcon); | 51 | writeb(pwr, &host->reg->pwrcon); |
| 52 | if (pwr == 0) | 52 | if (pwr == 0) |
| 53 | return; | 53 | return; |
| 54 | 54 | ||
| 55 | /* Now enable bus power */ | 55 | /* Now enable bus power */ |
| 56 | pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; | 56 | pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER; |
| 57 | writeb(pwr, &host->reg->pwrcon); | 57 | writeb(pwr, &host->reg->pwrcon); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data, | 60 | static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data, |
| 61 | struct bounce_buffer *bbstate) | 61 | struct bounce_buffer *bbstate) |
| 62 | { | 62 | { |
| 63 | unsigned char ctrl; | 63 | unsigned char ctrl; |
| 64 | 64 | ||
| 65 | 65 | ||
| 66 | debug("buf: %p (%p), data->blocks: %u, data->blocksize: %u\n", | 66 | debug("buf: %p (%p), data->blocks: %u, data->blocksize: %u\n", |
| 67 | bbstate->bounce_buffer, bbstate->user_buffer, data->blocks, | 67 | bbstate->bounce_buffer, bbstate->user_buffer, data->blocks, |
| 68 | data->blocksize); | 68 | data->blocksize); |
| 69 | 69 | ||
| 70 | writel((u32)bbstate->bounce_buffer, &host->reg->sysad); | 70 | writel((u32)bbstate->bounce_buffer, &host->reg->sysad); |
| 71 | /* | 71 | /* |
| 72 | * DMASEL[4:3] | 72 | * DMASEL[4:3] |
| 73 | * 00 = Selects SDMA | 73 | * 00 = Selects SDMA |
| 74 | * 01 = Reserved | 74 | * 01 = Reserved |
| 75 | * 10 = Selects 32-bit Address ADMA2 | 75 | * 10 = Selects 32-bit Address ADMA2 |
| 76 | * 11 = Selects 64-bit Address ADMA2 | 76 | * 11 = Selects 64-bit Address ADMA2 |
| 77 | */ | 77 | */ |
| 78 | ctrl = readb(&host->reg->hostctl); | 78 | ctrl = readb(&host->reg->hostctl); |
| 79 | ctrl &= ~TEGRA_MMC_HOSTCTL_DMASEL_MASK; | 79 | ctrl &= ~TEGRA_MMC_HOSTCTL_DMASEL_MASK; |
| 80 | ctrl |= TEGRA_MMC_HOSTCTL_DMASEL_SDMA; | 80 | ctrl |= TEGRA_MMC_HOSTCTL_DMASEL_SDMA; |
| 81 | writeb(ctrl, &host->reg->hostctl); | 81 | writeb(ctrl, &host->reg->hostctl); |
| 82 | 82 | ||
| 83 | /* We do not handle DMA boundaries, so set it to max (512 KiB) */ | 83 | /* We do not handle DMA boundaries, so set it to max (512 KiB) */ |
| 84 | writew((7 << 12) | (data->blocksize & 0xFFF), &host->reg->blksize); | 84 | writew((7 << 12) | (data->blocksize & 0xFFF), &host->reg->blksize); |
| 85 | writew(data->blocks, &host->reg->blkcnt); | 85 | writew(data->blocks, &host->reg->blkcnt); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data) | 88 | static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data) |
| 89 | { | 89 | { |
| 90 | unsigned short mode; | 90 | unsigned short mode; |
| 91 | debug(" mmc_set_transfer_mode called\n"); | 91 | debug(" mmc_set_transfer_mode called\n"); |
| 92 | /* | 92 | /* |
| 93 | * TRNMOD | 93 | * TRNMOD |
| 94 | * MUL1SIN0[5] : Multi/Single Block Select | 94 | * MUL1SIN0[5] : Multi/Single Block Select |
| 95 | * RD1WT0[4] : Data Transfer Direction Select | 95 | * RD1WT0[4] : Data Transfer Direction Select |
| 96 | * 1 = read | 96 | * 1 = read |
| 97 | * 0 = write | 97 | * 0 = write |
| 98 | * ENACMD12[2] : Auto CMD12 Enable | 98 | * ENACMD12[2] : Auto CMD12 Enable |
| 99 | * ENBLKCNT[1] : Block Count Enable | 99 | * ENBLKCNT[1] : Block Count Enable |
| 100 | * ENDMA[0] : DMA Enable | 100 | * ENDMA[0] : DMA Enable |
| 101 | */ | 101 | */ |
| 102 | mode = (TEGRA_MMC_TRNMOD_DMA_ENABLE | | 102 | mode = (TEGRA_MMC_TRNMOD_DMA_ENABLE | |
| 103 | TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE); | 103 | TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE); |
| 104 | 104 | ||
| 105 | if (data->blocks > 1) | 105 | if (data->blocks > 1) |
| 106 | mode |= TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT; | 106 | mode |= TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT; |
| 107 | 107 | ||
| 108 | if (data->flags & MMC_DATA_READ) | 108 | if (data->flags & MMC_DATA_READ) |
| 109 | mode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; | 109 | mode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; |
| 110 | 110 | ||
| 111 | writew(mode, &host->reg->trnmod); | 111 | writew(mode, &host->reg->trnmod); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | static int mmc_wait_inhibit(struct mmc_host *host, | 114 | static int mmc_wait_inhibit(struct mmc_host *host, |
| 115 | struct mmc_cmd *cmd, | 115 | struct mmc_cmd *cmd, |
| 116 | struct mmc_data *data, | 116 | struct mmc_data *data, |
| 117 | unsigned int timeout) | 117 | unsigned int timeout) |
| 118 | { | 118 | { |
| 119 | /* | 119 | /* |
| 120 | * PRNSTS | 120 | * PRNSTS |
| 121 | * CMDINHDAT[1] : Command Inhibit (DAT) | 121 | * CMDINHDAT[1] : Command Inhibit (DAT) |
| 122 | * CMDINHCMD[0] : Command Inhibit (CMD) | 122 | * CMDINHCMD[0] : Command Inhibit (CMD) |
| 123 | */ | 123 | */ |
| 124 | unsigned int mask = TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD; | 124 | unsigned int mask = TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD; |
| 125 | 125 | ||
| 126 | /* | 126 | /* |
| 127 | * We shouldn't wait for data inhibit for stop commands, even | 127 | * We shouldn't wait for data inhibit for stop commands, even |
| 128 | * though they might use busy signaling | 128 | * though they might use busy signaling |
| 129 | */ | 129 | */ |
| 130 | if ((data == NULL) && (cmd->resp_type & MMC_RSP_BUSY)) | 130 | if ((data == NULL) && (cmd->resp_type & MMC_RSP_BUSY)) |
| 131 | mask |= TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT; | 131 | mask |= TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT; |
| 132 | 132 | ||
| 133 | while (readl(&host->reg->prnsts) & mask) { | 133 | while (readl(&host->reg->prnsts) & mask) { |
| 134 | if (timeout == 0) { | 134 | if (timeout == 0) { |
| 135 | printf("%s: timeout error\n", __func__); | 135 | printf("%s: timeout error\n", __func__); |
| 136 | return -1; | 136 | return -1; |
| 137 | } | 137 | } |
| 138 | timeout--; | 138 | timeout--; |
| 139 | udelay(1000); | 139 | udelay(1000); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | return 0; | 142 | return 0; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, | 145 | static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, |
| 146 | struct mmc_data *data, struct bounce_buffer *bbstate) | 146 | struct mmc_data *data, struct bounce_buffer *bbstate) |
| 147 | { | 147 | { |
| 148 | struct mmc_host *host = mmc->priv; | 148 | struct mmc_host *host = mmc->priv; |
| 149 | int flags, i; | 149 | int flags, i; |
| 150 | int result; | 150 | int result; |
| 151 | unsigned int mask = 0; | 151 | unsigned int mask = 0; |
| 152 | unsigned int retry = 0x100000; | 152 | unsigned int retry = 0x100000; |
| 153 | debug(" mmc_send_cmd called\n"); | 153 | debug(" mmc_send_cmd called\n"); |
| 154 | 154 | ||
| 155 | result = mmc_wait_inhibit(host, cmd, data, 10 /* ms */); | 155 | result = mmc_wait_inhibit(host, cmd, data, 10 /* ms */); |
| 156 | 156 | ||
| 157 | if (result < 0) | 157 | if (result < 0) |
| 158 | return result; | 158 | return result; |
| 159 | 159 | ||
| 160 | if (data) | 160 | if (data) |
| 161 | mmc_prepare_data(host, data, bbstate); | 161 | mmc_prepare_data(host, data, bbstate); |
| 162 | 162 | ||
| 163 | debug("cmd->arg: %08x\n", cmd->cmdarg); | 163 | debug("cmd->arg: %08x\n", cmd->cmdarg); |
| 164 | writel(cmd->cmdarg, &host->reg->argument); | 164 | writel(cmd->cmdarg, &host->reg->argument); |
| 165 | 165 | ||
| 166 | if (data) | 166 | if (data) |
| 167 | mmc_set_transfer_mode(host, data); | 167 | mmc_set_transfer_mode(host, data); |
| 168 | 168 | ||
| 169 | if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) | 169 | if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) |
| 170 | return -1; | 170 | return -1; |
| 171 | 171 | ||
| 172 | /* | 172 | /* |
| 173 | * CMDREG | 173 | * CMDREG |
| 174 | * CMDIDX[13:8] : Command index | 174 | * CMDIDX[13:8] : Command index |
| 175 | * DATAPRNT[5] : Data Present Select | 175 | * DATAPRNT[5] : Data Present Select |
| 176 | * ENCMDIDX[4] : Command Index Check Enable | 176 | * ENCMDIDX[4] : Command Index Check Enable |
| 177 | * ENCMDCRC[3] : Command CRC Check Enable | 177 | * ENCMDCRC[3] : Command CRC Check Enable |
| 178 | * RSPTYP[1:0] | 178 | * RSPTYP[1:0] |
| 179 | * 00 = No Response | 179 | * 00 = No Response |
| 180 | * 01 = Length 136 | 180 | * 01 = Length 136 |
| 181 | * 10 = Length 48 | 181 | * 10 = Length 48 |
| 182 | * 11 = Length 48 Check busy after response | 182 | * 11 = Length 48 Check busy after response |
| 183 | */ | 183 | */ |
| 184 | if (!(cmd->resp_type & MMC_RSP_PRESENT)) | 184 | if (!(cmd->resp_type & MMC_RSP_PRESENT)) |
| 185 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE; | 185 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE; |
| 186 | else if (cmd->resp_type & MMC_RSP_136) | 186 | else if (cmd->resp_type & MMC_RSP_136) |
| 187 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136; | 187 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136; |
| 188 | else if (cmd->resp_type & MMC_RSP_BUSY) | 188 | else if (cmd->resp_type & MMC_RSP_BUSY) |
| 189 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY; | 189 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY; |
| 190 | else | 190 | else |
| 191 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48; | 191 | flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48; |
| 192 | 192 | ||
| 193 | if (cmd->resp_type & MMC_RSP_CRC) | 193 | if (cmd->resp_type & MMC_RSP_CRC) |
| 194 | flags |= TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; | 194 | flags |= TEGRA_MMC_TRNMOD_CMD_CRC_CHECK; |
| 195 | if (cmd->resp_type & MMC_RSP_OPCODE) | 195 | if (cmd->resp_type & MMC_RSP_OPCODE) |
| 196 | flags |= TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK; | 196 | flags |= TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK; |
| 197 | if (data) | 197 | if (data) |
| 198 | flags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER; | 198 | flags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER; |
| 199 | 199 | ||
| 200 | debug("cmd: %d\n", cmd->cmdidx); | 200 | debug("cmd: %d\n", cmd->cmdidx); |
| 201 | 201 | ||
| 202 | writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg); | 202 | writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg); |
| 203 | 203 | ||
| 204 | for (i = 0; i < retry; i++) { | 204 | for (i = 0; i < retry; i++) { |
| 205 | mask = readl(&host->reg->norintsts); | 205 | mask = readl(&host->reg->norintsts); |
| 206 | /* Command Complete */ | 206 | /* Command Complete */ |
| 207 | if (mask & TEGRA_MMC_NORINTSTS_CMD_COMPLETE) { | 207 | if (mask & TEGRA_MMC_NORINTSTS_CMD_COMPLETE) { |
| 208 | if (!data) | 208 | if (!data) |
| 209 | writel(mask, &host->reg->norintsts); | 209 | writel(mask, &host->reg->norintsts); |
| 210 | break; | 210 | break; |
| 211 | } | 211 | } |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | if (i == retry) { | 214 | if (i == retry) { |
| 215 | printf("%s: waiting for status update\n", __func__); | 215 | printf("%s: waiting for status update\n", __func__); |
| 216 | writel(mask, &host->reg->norintsts); | 216 | writel(mask, &host->reg->norintsts); |
| 217 | return TIMEOUT; | 217 | return TIMEOUT; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) { | 220 | if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) { |
| 221 | /* Timeout Error */ | 221 | /* Timeout Error */ |
| 222 | debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); | 222 | debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); |
| 223 | writel(mask, &host->reg->norintsts); | 223 | writel(mask, &host->reg->norintsts); |
| 224 | return TIMEOUT; | 224 | return TIMEOUT; |
| 225 | } else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { | 225 | } else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { |
| 226 | /* Error Interrupt */ | 226 | /* Error Interrupt */ |
| 227 | debug("error: %08x cmd %d\n", mask, cmd->cmdidx); | 227 | debug("error: %08x cmd %d\n", mask, cmd->cmdidx); |
| 228 | writel(mask, &host->reg->norintsts); | 228 | writel(mask, &host->reg->norintsts); |
| 229 | return -1; | 229 | return -1; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | if (cmd->resp_type & MMC_RSP_PRESENT) { | 232 | if (cmd->resp_type & MMC_RSP_PRESENT) { |
| 233 | if (cmd->resp_type & MMC_RSP_136) { | 233 | if (cmd->resp_type & MMC_RSP_136) { |
| 234 | /* CRC is stripped so we need to do some shifting. */ | 234 | /* CRC is stripped so we need to do some shifting. */ |
| 235 | for (i = 0; i < 4; i++) { | 235 | for (i = 0; i < 4; i++) { |
| 236 | unsigned int offset = | 236 | unsigned int offset = |
| 237 | (unsigned int)(&host->reg->rspreg3 - i); | 237 | (unsigned int)(&host->reg->rspreg3 - i); |
| 238 | cmd->response[i] = readl(offset) << 8; | 238 | cmd->response[i] = readl(offset) << 8; |
| 239 | 239 | ||
| 240 | if (i != 3) { | 240 | if (i != 3) { |
| 241 | cmd->response[i] |= | 241 | cmd->response[i] |= |
| 242 | readb(offset - 1); | 242 | readb(offset - 1); |
| 243 | } | 243 | } |
| 244 | debug("cmd->resp[%d]: %08x\n", | 244 | debug("cmd->resp[%d]: %08x\n", |
| 245 | i, cmd->response[i]); | 245 | i, cmd->response[i]); |
| 246 | } | 246 | } |
| 247 | } else if (cmd->resp_type & MMC_RSP_BUSY) { | 247 | } else if (cmd->resp_type & MMC_RSP_BUSY) { |
| 248 | for (i = 0; i < retry; i++) { | 248 | for (i = 0; i < retry; i++) { |
| 249 | /* PRNTDATA[23:20] : DAT[3:0] Line Signal */ | 249 | /* PRNTDATA[23:20] : DAT[3:0] Line Signal */ |
| 250 | if (readl(&host->reg->prnsts) | 250 | if (readl(&host->reg->prnsts) |
| 251 | & (1 << 20)) /* DAT[0] */ | 251 | & (1 << 20)) /* DAT[0] */ |
| 252 | break; | 252 | break; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | if (i == retry) { | 255 | if (i == retry) { |
| 256 | printf("%s: card is still busy\n", __func__); | 256 | printf("%s: card is still busy\n", __func__); |
| 257 | writel(mask, &host->reg->norintsts); | 257 | writel(mask, &host->reg->norintsts); |
| 258 | return TIMEOUT; | 258 | return TIMEOUT; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | cmd->response[0] = readl(&host->reg->rspreg0); | 261 | cmd->response[0] = readl(&host->reg->rspreg0); |
| 262 | debug("cmd->resp[0]: %08x\n", cmd->response[0]); | 262 | debug("cmd->resp[0]: %08x\n", cmd->response[0]); |
| 263 | } else { | 263 | } else { |
| 264 | cmd->response[0] = readl(&host->reg->rspreg0); | 264 | cmd->response[0] = readl(&host->reg->rspreg0); |
| 265 | debug("cmd->resp[0]: %08x\n", cmd->response[0]); | 265 | debug("cmd->resp[0]: %08x\n", cmd->response[0]); |
| 266 | } | 266 | } |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | if (data) { | 269 | if (data) { |
| 270 | unsigned long start = get_timer(0); | 270 | unsigned long start = get_timer(0); |
| 271 | 271 | ||
| 272 | while (1) { | 272 | while (1) { |
| 273 | mask = readl(&host->reg->norintsts); | 273 | mask = readl(&host->reg->norintsts); |
| 274 | 274 | ||
| 275 | if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { | 275 | if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { |
| 276 | /* Error Interrupt */ | 276 | /* Error Interrupt */ |
| 277 | writel(mask, &host->reg->norintsts); | 277 | writel(mask, &host->reg->norintsts); |
| 278 | printf("%s: error during transfer: 0x%08x\n", | 278 | printf("%s: error during transfer: 0x%08x\n", |
| 279 | __func__, mask); | 279 | __func__, mask); |
| 280 | return -1; | 280 | return -1; |
| 281 | } else if (mask & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) { | 281 | } else if (mask & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) { |
| 282 | /* | 282 | /* |
| 283 | * DMA Interrupt, restart the transfer where | 283 | * DMA Interrupt, restart the transfer where |
| 284 | * it was interrupted. | 284 | * it was interrupted. |
| 285 | */ | 285 | */ |
| 286 | unsigned int address = readl(&host->reg->sysad); | 286 | unsigned int address = readl(&host->reg->sysad); |
| 287 | 287 | ||
| 288 | debug("DMA end\n"); | 288 | debug("DMA end\n"); |
| 289 | writel(TEGRA_MMC_NORINTSTS_DMA_INTERRUPT, | 289 | writel(TEGRA_MMC_NORINTSTS_DMA_INTERRUPT, |
| 290 | &host->reg->norintsts); | 290 | &host->reg->norintsts); |
| 291 | writel(address, &host->reg->sysad); | 291 | writel(address, &host->reg->sysad); |
| 292 | } else if (mask & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) { | 292 | } else if (mask & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) { |
| 293 | /* Transfer Complete */ | 293 | /* Transfer Complete */ |
| 294 | debug("r/w is done\n"); | 294 | debug("r/w is done\n"); |
| 295 | break; | 295 | break; |
| 296 | } else if (get_timer(start) > 8000UL) { | 296 | } else if (get_timer(start) > 8000UL) { |
| 297 | writel(mask, &host->reg->norintsts); | 297 | writel(mask, &host->reg->norintsts); |
| 298 | printf("%s: MMC Timeout\n" | 298 | printf("%s: MMC Timeout\n" |
| 299 | " Interrupt status 0x%08x\n" | 299 | " Interrupt status 0x%08x\n" |
| 300 | " Interrupt status enable 0x%08x\n" | 300 | " Interrupt status enable 0x%08x\n" |
| 301 | " Interrupt signal enable 0x%08x\n" | 301 | " Interrupt signal enable 0x%08x\n" |
| 302 | " Present status 0x%08x\n", | 302 | " Present status 0x%08x\n", |
| 303 | __func__, mask, | 303 | __func__, mask, |
| 304 | readl(&host->reg->norintstsen), | 304 | readl(&host->reg->norintstsen), |
| 305 | readl(&host->reg->norintsigen), | 305 | readl(&host->reg->norintsigen), |
| 306 | readl(&host->reg->prnsts)); | 306 | readl(&host->reg->prnsts)); |
| 307 | return -1; | 307 | return -1; |
| 308 | } | 308 | } |
| 309 | } | 309 | } |
| 310 | writel(mask, &host->reg->norintsts); | 310 | writel(mask, &host->reg->norintsts); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | udelay(1000); | 313 | udelay(1000); |
| 314 | return 0; | 314 | return 0; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | 317 | static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
| 318 | struct mmc_data *data) | 318 | struct mmc_data *data) |
| 319 | { | 319 | { |
| 320 | void *buf; | 320 | void *buf; |
| 321 | unsigned int bbflags; | 321 | unsigned int bbflags; |
| 322 | size_t len; | 322 | size_t len; |
| 323 | struct bounce_buffer bbstate; | 323 | struct bounce_buffer bbstate; |
| 324 | int ret; | 324 | int ret; |
| 325 | 325 | ||
| 326 | if (data) { | 326 | if (data) { |
| 327 | if (data->flags & MMC_DATA_READ) { | 327 | if (data->flags & MMC_DATA_READ) { |
| 328 | buf = data->dest; | 328 | buf = data->dest; |
| 329 | bbflags = GEN_BB_WRITE; | 329 | bbflags = GEN_BB_WRITE; |
| 330 | } else { | 330 | } else { |
| 331 | buf = (void *)data->src; | 331 | buf = (void *)data->src; |
| 332 | bbflags = GEN_BB_READ; | 332 | bbflags = GEN_BB_READ; |
| 333 | } | 333 | } |
| 334 | len = data->blocks * data->blocksize; | 334 | len = data->blocks * data->blocksize; |
| 335 | 335 | ||
| 336 | bounce_buffer_start(&bbstate, buf, len, bbflags); | 336 | bounce_buffer_start(&bbstate, buf, len, bbflags); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | ret = mmc_send_cmd_bounced(mmc, cmd, data, &bbstate); | 339 | ret = mmc_send_cmd_bounced(mmc, cmd, data, &bbstate); |
| 340 | 340 | ||
| 341 | if (data) | 341 | if (data) |
| 342 | bounce_buffer_stop(&bbstate); | 342 | bounce_buffer_stop(&bbstate); |
| 343 | 343 | ||
| 344 | return ret; | 344 | return ret; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | static void mmc_change_clock(struct mmc_host *host, uint clock) | 347 | static void mmc_change_clock(struct mmc_host *host, uint clock) |
| 348 | { | 348 | { |
| 349 | int div; | 349 | int div; |
| 350 | unsigned short clk; | 350 | unsigned short clk; |
| 351 | unsigned long timeout; | 351 | unsigned long timeout; |
| 352 | 352 | ||
| 353 | debug(" mmc_change_clock called\n"); | 353 | debug(" mmc_change_clock called\n"); |
| 354 | 354 | ||
| 355 | /* | 355 | /* |
| 356 | * Change Tegra SDMMCx clock divisor here. Source is PLLP_OUT0 | 356 | * Change Tegra SDMMCx clock divisor here. Source is PLLP_OUT0 |
| 357 | */ | 357 | */ |
| 358 | if (clock == 0) | 358 | if (clock == 0) |
| 359 | goto out; | 359 | goto out; |
| 360 | clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, | 360 | clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, |
| 361 | &div); | 361 | &div); |
| 362 | debug("div = %d\n", div); | 362 | debug("div = %d\n", div); |
| 363 | 363 | ||
| 364 | writew(0, &host->reg->clkcon); | 364 | writew(0, &host->reg->clkcon); |
| 365 | 365 | ||
| 366 | /* | 366 | /* |
| 367 | * CLKCON | 367 | * CLKCON |
| 368 | * SELFREQ[15:8] : base clock divided by value | 368 | * SELFREQ[15:8] : base clock divided by value |
| 369 | * ENSDCLK[2] : SD Clock Enable | 369 | * ENSDCLK[2] : SD Clock Enable |
| 370 | * STBLINTCLK[1] : Internal Clock Stable | 370 | * STBLINTCLK[1] : Internal Clock Stable |
| 371 | * ENINTCLK[0] : Internal Clock Enable | 371 | * ENINTCLK[0] : Internal Clock Enable |
| 372 | */ | 372 | */ |
| 373 | div >>= 1; | 373 | div >>= 1; |
| 374 | clk = ((div << TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT) | | 374 | clk = ((div << TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT) | |
| 375 | TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE); | 375 | TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE); |
| 376 | writew(clk, &host->reg->clkcon); | 376 | writew(clk, &host->reg->clkcon); |
| 377 | 377 | ||
| 378 | /* Wait max 10 ms */ | 378 | /* Wait max 10 ms */ |
| 379 | timeout = 10; | 379 | timeout = 10; |
| 380 | while (!(readw(&host->reg->clkcon) & | 380 | while (!(readw(&host->reg->clkcon) & |
| 381 | TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) { | 381 | TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) { |
| 382 | if (timeout == 0) { | 382 | if (timeout == 0) { |
| 383 | printf("%s: timeout error\n", __func__); | 383 | printf("%s: timeout error\n", __func__); |
| 384 | return; | 384 | return; |
| 385 | } | 385 | } |
| 386 | timeout--; | 386 | timeout--; |
| 387 | udelay(1000); | 387 | udelay(1000); |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | clk |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; | 390 | clk |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; |
| 391 | writew(clk, &host->reg->clkcon); | 391 | writew(clk, &host->reg->clkcon); |
| 392 | 392 | ||
| 393 | debug("mmc_change_clock: clkcon = %08X\n", clk); | 393 | debug("mmc_change_clock: clkcon = %08X\n", clk); |
| 394 | 394 | ||
| 395 | out: | 395 | out: |
| 396 | host->clock = clock; | 396 | host->clock = clock; |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | static void tegra_mmc_set_ios(struct mmc *mmc) | 399 | static void tegra_mmc_set_ios(struct mmc *mmc) |
| 400 | { | 400 | { |
| 401 | struct mmc_host *host = mmc->priv; | 401 | struct mmc_host *host = mmc->priv; |
| 402 | unsigned char ctrl; | 402 | unsigned char ctrl; |
| 403 | debug(" mmc_set_ios called\n"); | 403 | debug(" mmc_set_ios called\n"); |
| 404 | 404 | ||
| 405 | debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); | 405 | debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); |
| 406 | 406 | ||
| 407 | /* Change clock first */ | 407 | /* Change clock first */ |
| 408 | mmc_change_clock(host, mmc->clock); | 408 | mmc_change_clock(host, mmc->clock); |
| 409 | 409 | ||
| 410 | ctrl = readb(&host->reg->hostctl); | 410 | ctrl = readb(&host->reg->hostctl); |
| 411 | 411 | ||
| 412 | /* | 412 | /* |
| 413 | * WIDE8[5] | 413 | * WIDE8[5] |
| 414 | * 0 = Depend on WIDE4 | 414 | * 0 = Depend on WIDE4 |
| 415 | * 1 = 8-bit mode | 415 | * 1 = 8-bit mode |
| 416 | * WIDE4[1] | 416 | * WIDE4[1] |
| 417 | * 1 = 4-bit mode | 417 | * 1 = 4-bit mode |
| 418 | * 0 = 1-bit mode | 418 | * 0 = 1-bit mode |
| 419 | */ | 419 | */ |
| 420 | if (mmc->bus_width == 8) | 420 | if (mmc->bus_width == 8) |
| 421 | ctrl |= (1 << 5); | 421 | ctrl |= (1 << 5); |
| 422 | else if (mmc->bus_width == 4) | 422 | else if (mmc->bus_width == 4) |
| 423 | ctrl |= (1 << 1); | 423 | ctrl |= (1 << 1); |
| 424 | else | 424 | else |
| 425 | ctrl &= ~(1 << 1); | 425 | ctrl &= ~(1 << 1); |
| 426 | 426 | ||
| 427 | writeb(ctrl, &host->reg->hostctl); | 427 | writeb(ctrl, &host->reg->hostctl); |
| 428 | debug("mmc_set_ios: hostctl = %08X\n", ctrl); | 428 | debug("mmc_set_ios: hostctl = %08X\n", ctrl); |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | static void mmc_reset(struct mmc_host *host, struct mmc *mmc) | 431 | static void mmc_reset(struct mmc_host *host, struct mmc *mmc) |
| 432 | { | 432 | { |
| 433 | unsigned int timeout; | 433 | unsigned int timeout; |
| 434 | debug(" mmc_reset called\n"); | 434 | debug(" mmc_reset called\n"); |
| 435 | 435 | ||
| 436 | /* | 436 | /* |
| 437 | * RSTALL[0] : Software reset for all | 437 | * RSTALL[0] : Software reset for all |
| 438 | * 1 = reset | 438 | * 1 = reset |
| 439 | * 0 = work | 439 | * 0 = work |
| 440 | */ | 440 | */ |
| 441 | writeb(TEGRA_MMC_SWRST_SW_RESET_FOR_ALL, &host->reg->swrst); | 441 | writeb(TEGRA_MMC_SWRST_SW_RESET_FOR_ALL, &host->reg->swrst); |
| 442 | 442 | ||
| 443 | host->clock = 0; | 443 | host->clock = 0; |
| 444 | 444 | ||
| 445 | /* Wait max 100 ms */ | 445 | /* Wait max 100 ms */ |
| 446 | timeout = 100; | 446 | timeout = 100; |
| 447 | 447 | ||
| 448 | /* hw clears the bit when it's done */ | 448 | /* hw clears the bit when it's done */ |
| 449 | while (readb(&host->reg->swrst) & TEGRA_MMC_SWRST_SW_RESET_FOR_ALL) { | 449 | while (readb(&host->reg->swrst) & TEGRA_MMC_SWRST_SW_RESET_FOR_ALL) { |
| 450 | if (timeout == 0) { | 450 | if (timeout == 0) { |
| 451 | printf("%s: timeout error\n", __func__); | 451 | printf("%s: timeout error\n", __func__); |
| 452 | return; | 452 | return; |
| 453 | } | 453 | } |
| 454 | timeout--; | 454 | timeout--; |
| 455 | udelay(1000); | 455 | udelay(1000); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | /* Set SD bus voltage & enable bus power */ | 458 | /* Set SD bus voltage & enable bus power */ |
| 459 | mmc_set_power(host, fls(mmc->cfg->voltages) - 1); | 459 | mmc_set_power(host, fls(mmc->cfg->voltages) - 1); |
| 460 | debug("%s: power control = %02X, host control = %02X\n", __func__, | 460 | debug("%s: power control = %02X, host control = %02X\n", __func__, |
| 461 | readb(&host->reg->pwrcon), readb(&host->reg->hostctl)); | 461 | readb(&host->reg->pwrcon), readb(&host->reg->hostctl)); |
| 462 | 462 | ||
| 463 | /* Make sure SDIO pads are set up */ | 463 | /* Make sure SDIO pads are set up */ |
| 464 | pad_init_mmc(host); | 464 | pad_init_mmc(host); |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | static int tegra_mmc_core_init(struct mmc *mmc) | 467 | static int tegra_mmc_core_init(struct mmc *mmc) |
| 468 | { | 468 | { |
| 469 | struct mmc_host *host = mmc->priv; | 469 | struct mmc_host *host = mmc->priv; |
| 470 | unsigned int mask; | 470 | unsigned int mask; |
| 471 | debug(" mmc_core_init called\n"); | 471 | debug(" mmc_core_init called\n"); |
| 472 | 472 | ||
| 473 | mmc_reset(host, mmc); | 473 | mmc_reset(host, mmc); |
| 474 | 474 | ||
| 475 | host->version = readw(&host->reg->hcver); | 475 | host->version = readw(&host->reg->hcver); |
| 476 | debug("host version = %x\n", host->version); | 476 | debug("host version = %x\n", host->version); |
| 477 | 477 | ||
| 478 | /* mask all */ | 478 | /* mask all */ |
| 479 | writel(0xffffffff, &host->reg->norintstsen); | 479 | writel(0xffffffff, &host->reg->norintstsen); |
| 480 | writel(0xffffffff, &host->reg->norintsigen); | 480 | writel(0xffffffff, &host->reg->norintsigen); |
| 481 | 481 | ||
| 482 | writeb(0xe, &host->reg->timeoutcon); /* TMCLK * 2^27 */ | 482 | writeb(0xe, &host->reg->timeoutcon); /* TMCLK * 2^27 */ |
| 483 | /* | 483 | /* |
| 484 | * NORMAL Interrupt Status Enable Register init | 484 | * NORMAL Interrupt Status Enable Register init |
| 485 | * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable | 485 | * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable |
| 486 | * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable | 486 | * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable |
| 487 | * [3] ENSTADMAINT : DMA boundary interrupt | 487 | * [3] ENSTADMAINT : DMA boundary interrupt |
| 488 | * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable | 488 | * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable |
| 489 | * [0] ENSTACMDCMPLT : Command Complete Status Enable | 489 | * [0] ENSTACMDCMPLT : Command Complete Status Enable |
| 490 | */ | 490 | */ |
| 491 | mask = readl(&host->reg->norintstsen); | 491 | mask = readl(&host->reg->norintstsen); |
| 492 | mask &= ~(0xffff); | 492 | mask &= ~(0xffff); |
| 493 | mask |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | | 493 | mask |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | |
| 494 | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | | 494 | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | |
| 495 | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT | | 495 | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT | |
| 496 | TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY | | 496 | TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY | |
| 497 | TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY); | 497 | TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY); |
| 498 | writel(mask, &host->reg->norintstsen); | 498 | writel(mask, &host->reg->norintstsen); |
| 499 | 499 | ||
| 500 | /* | 500 | /* |
| 501 | * NORMAL Interrupt Signal Enable Register init | 501 | * NORMAL Interrupt Signal Enable Register init |
| 502 | * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable | 502 | * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable |
| 503 | */ | 503 | */ |
| 504 | mask = readl(&host->reg->norintsigen); | 504 | mask = readl(&host->reg->norintsigen); |
| 505 | mask &= ~(0xffff); | 505 | mask &= ~(0xffff); |
| 506 | mask |= TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE; | 506 | mask |= TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE; |
| 507 | writel(mask, &host->reg->norintsigen); | 507 | writel(mask, &host->reg->norintsigen); |
| 508 | 508 | ||
| 509 | return 0; | 509 | return 0; |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | static int tegra_mmc_getcd(struct mmc *mmc) | 512 | static int tegra_mmc_getcd(struct mmc *mmc) |
| 513 | { | 513 | { |
| 514 | struct mmc_host *host = mmc->priv; | 514 | struct mmc_host *host = mmc->priv; |
| 515 | 515 | ||
| 516 | debug("tegra_mmc_getcd called\n"); | 516 | debug("tegra_mmc_getcd called\n"); |
| 517 | 517 | ||
| 518 | if (dm_gpio_is_valid(&host->cd_gpio)) | 518 | if (dm_gpio_is_valid(&host->cd_gpio)) |
| 519 | return dm_gpio_get_value(&host->cd_gpio); | 519 | return dm_gpio_get_value(&host->cd_gpio); |
| 520 | 520 | ||
| 521 | return 1; | 521 | return 1; |
| 522 | } | 522 | } |
| 523 | 523 | ||
| 524 | static const struct mmc_ops tegra_mmc_ops = { | 524 | static const struct mmc_ops tegra_mmc_ops = { |
| 525 | .send_cmd = tegra_mmc_send_cmd, | 525 | .send_cmd = tegra_mmc_send_cmd, |
| 526 | .set_ios = tegra_mmc_set_ios, | 526 | .set_ios = tegra_mmc_set_ios, |
| 527 | .init = tegra_mmc_core_init, | 527 | .init = tegra_mmc_core_init, |
| 528 | .getcd = tegra_mmc_getcd, | 528 | .getcd = tegra_mmc_getcd, |
| 529 | }; | 529 | }; |
| 530 | 530 | ||
| 531 | static int do_mmc_init(int dev_index) | 531 | static int do_mmc_init(int dev_index) |
| 532 | { | 532 | { |
| 533 | struct mmc_host *host; | 533 | struct mmc_host *host; |
| 534 | struct mmc *mmc; | 534 | struct mmc *mmc; |
| 535 | 535 | ||
| 536 | /* DT should have been read & host config filled in */ | 536 | /* DT should have been read & host config filled in */ |
| 537 | host = &mmc_host[dev_index]; | 537 | host = &mmc_host[dev_index]; |
| 538 | if (!host->enabled) | 538 | if (!host->enabled) |
| 539 | return -1; | 539 | return -1; |
| 540 | 540 | ||
| 541 | debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n", | 541 | debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n", |
| 542 | dev_index, host->width, gpio_get_number(&host->pwr_gpio), | 542 | dev_index, host->width, gpio_get_number(&host->pwr_gpio), |
| 543 | gpio_get_number(&host->cd_gpio)); | 543 | gpio_get_number(&host->cd_gpio)); |
| 544 | 544 | ||
| 545 | host->clock = 0; | 545 | host->clock = 0; |
| 546 | clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); | 546 | clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); |
| 547 | 547 | ||
| 548 | if (dm_gpio_is_valid(&host->pwr_gpio)) | 548 | if (dm_gpio_is_valid(&host->pwr_gpio)) |
| 549 | dm_gpio_set_value(&host->pwr_gpio, 1); | 549 | dm_gpio_set_value(&host->pwr_gpio, 1); |
| 550 | 550 | ||
| 551 | memset(&host->cfg, 0, sizeof(host->cfg)); | 551 | memset(&host->cfg, 0, sizeof(host->cfg)); |
| 552 | 552 | ||
| 553 | host->cfg.name = "Tegra SD/MMC"; | 553 | host->cfg.name = "Tegra SD/MMC"; |
| 554 | host->cfg.ops = &tegra_mmc_ops; | 554 | host->cfg.ops = &tegra_mmc_ops; |
| 555 | 555 | ||
| 556 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | 556 | host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
| 557 | host->cfg.host_caps = 0; | 557 | host->cfg.host_caps = 0; |
| 558 | if (host->width == 8) | 558 | if (host->width == 8) |
| 559 | host->cfg.host_caps |= MMC_MODE_8BIT; | 559 | host->cfg.host_caps |= MMC_MODE_8BIT; |
| 560 | if (host->width >= 4) | 560 | if (host->width >= 4) |
| 561 | host->cfg.host_caps |= MMC_MODE_4BIT; | 561 | host->cfg.host_caps |= MMC_MODE_4BIT; |
| 562 | host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; | 562 | host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; |
| 563 | 563 | ||
| 564 | /* | 564 | /* |
| 565 | * min freq is for card identification, and is the highest | 565 | * min freq is for card identification, and is the highest |
| 566 | * low-speed SDIO card frequency (actually 400KHz) | 566 | * low-speed SDIO card frequency (actually 400KHz) |
| 567 | * max freq is highest HS eMMC clock as per the SD/MMC spec | 567 | * max freq is highest HS eMMC clock as per the SD/MMC spec |
| 568 | * (actually 52MHz) | 568 | * (actually 52MHz) |
| 569 | */ | 569 | */ |
| 570 | host->cfg.f_min = 375000; | 570 | host->cfg.f_min = 375000; |
| 571 | host->cfg.f_max = 48000000; | 571 | host->cfg.f_max = 48000000; |
| 572 | 572 | ||
| 573 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | 573 | host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
| 574 | 574 | ||
| 575 | mmc = mmc_create(&host->cfg, host); | 575 | mmc = mmc_create(&host->cfg, host); |
| 576 | if (mmc == NULL) | 576 | if (mmc == NULL) |
| 577 | return -1; | 577 | return -1; |
| 578 | 578 | ||
| 579 | return 0; | 579 | return 0; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | /** | 582 | /** |
| 583 | * Get the host address and peripheral ID for a node. | 583 | * Get the host address and peripheral ID for a node. |
| 584 | * | 584 | * |
| 585 | * @param blob fdt blob | 585 | * @param blob fdt blob |
| 586 | * @param node Device index (0-3) | 586 | * @param node Device index (0-3) |
| 587 | * @param host Structure to fill in (reg, width, mmc_id) | 587 | * @param host Structure to fill in (reg, width, mmc_id) |
| 588 | */ | 588 | */ |
| 589 | static int mmc_get_config(const void *blob, int node, struct mmc_host *host) | 589 | static int mmc_get_config(const void *blob, int node, struct mmc_host *host) |
| 590 | { | 590 | { |
| 591 | debug("%s: node = %d\n", __func__, node); | 591 | debug("%s: node = %d\n", __func__, node); |
| 592 | 592 | ||
| 593 | host->enabled = fdtdec_get_is_enabled(blob, node); | 593 | host->enabled = fdtdec_get_is_enabled(blob, node); |
| 594 | 594 | ||
| 595 | host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg"); | 595 | host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg"); |
| 596 | if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) { | 596 | if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) { |
| 597 | debug("%s: no sdmmc base reg info found\n", __func__); | 597 | debug("%s: no sdmmc base reg info found\n", __func__); |
| 598 | return -FDT_ERR_NOTFOUND; | 598 | return -FDT_ERR_NOTFOUND; |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | host->mmc_id = clock_decode_periph_id(blob, node); | 601 | host->mmc_id = clock_decode_periph_id(blob, node); |
| 602 | if (host->mmc_id == PERIPH_ID_NONE) { | 602 | if (host->mmc_id == PERIPH_ID_NONE) { |
| 603 | debug("%s: could not decode periph id\n", __func__); | 603 | debug("%s: could not decode periph id\n", __func__); |
| 604 | return -FDT_ERR_NOTFOUND; | 604 | return -FDT_ERR_NOTFOUND; |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | /* | 607 | /* |
| 608 | * NOTE: mmc->bus_width is determined by mmc.c dynamically. | 608 | * NOTE: mmc->bus_width is determined by mmc.c dynamically. |
| 609 | * TBD: Override it with this value? | 609 | * TBD: Override it with this value? |
| 610 | */ | 610 | */ |
| 611 | host->width = fdtdec_get_int(blob, node, "bus-width", 0); | 611 | host->width = fdtdec_get_int(blob, node, "bus-width", 0); |
| 612 | if (!host->width) | 612 | if (!host->width) |
| 613 | debug("%s: no sdmmc width found\n", __func__); | 613 | debug("%s: no sdmmc width found\n", __func__); |
| 614 | 614 | ||
| 615 | /* These GPIOs are optional */ | 615 | /* These GPIOs are optional */ |
| 616 | gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, | 616 | gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, |
| 617 | GPIOD_IS_IN); | 617 | GPIOD_IS_IN); |
| 618 | gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio, | 618 | gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio, |
| 619 | GPIOD_IS_IN); | 619 | GPIOD_IS_IN); |
| 620 | gpio_request_by_name_nodev(blob, node, "power-gpios", 0, | 620 | gpio_request_by_name_nodev(blob, node, "power-gpios", 0, |
| 621 | &host->pwr_gpio, GPIOD_IS_OUT); | 621 | &host->pwr_gpio, GPIOD_IS_OUT); |
| 622 | 622 | ||
| 623 | debug("%s: found controller at %p, width = %d, periph_id = %d\n", | 623 | debug("%s: found controller at %p, width = %d, periph_id = %d\n", |
| 624 | __func__, host->reg, host->width, host->mmc_id); | 624 | __func__, host->reg, host->width, host->mmc_id); |
| 625 | return 0; | 625 | return 0; |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | /* | 628 | /* |
| 629 | * Process a list of nodes, adding them to our list of SDMMC ports. | 629 | * Process a list of nodes, adding them to our list of SDMMC ports. |
| 630 | * | 630 | * |
| 631 | * @param blob fdt blob | 631 | * @param blob fdt blob |
| 632 | * @param node_list list of nodes to process (any <=0 are ignored) | 632 | * @param node_list list of nodes to process (any <=0 are ignored) |
| 633 | * @param count number of nodes to process | 633 | * @param count number of nodes to process |
| 634 | * @return 0 if ok, -1 on error | 634 | * @return 0 if ok, -1 on error |
| 635 | */ | 635 | */ |
| 636 | static int process_nodes(const void *blob, int node_list[], int count) | 636 | static int process_nodes(const void *blob, int node_list[], int count) |
| 637 | { | 637 | { |
| 638 | struct mmc_host *host; | 638 | struct mmc_host *host; |
| 639 | int i, node; | 639 | int i, node; |
| 640 | 640 | ||
| 641 | debug("%s: count = %d\n", __func__, count); | 641 | debug("%s: count = %d\n", __func__, count); |
| 642 | 642 | ||
| 643 | /* build mmc_host[] for each controller */ | 643 | /* build mmc_host[] for each controller */ |
| 644 | for (i = 0; i < count; i++) { | 644 | for (i = 0; i < count; i++) { |
| 645 | node = node_list[i]; | 645 | node = node_list[i]; |
| 646 | if (node <= 0) | 646 | if (node <= 0) |
| 647 | continue; | 647 | continue; |
| 648 | 648 | ||
| 649 | host = &mmc_host[i]; | 649 | host = &mmc_host[i]; |
| 650 | host->id = i; | 650 | host->id = i; |
| 651 | 651 | ||
| 652 | if (mmc_get_config(blob, node, host)) { | 652 | if (mmc_get_config(blob, node, host)) { |
| 653 | printf("%s: failed to decode dev %d\n", __func__, i); | 653 | printf("%s: failed to decode dev %d\n", __func__, i); |
| 654 | return -1; | 654 | return -1; |
| 655 | } | 655 | } |
| 656 | do_mmc_init(i); | 656 | do_mmc_init(i); |
| 657 | } | 657 | } |
| 658 | return 0; | 658 | return 0; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | void tegra_mmc_init(void) | 661 | void tegra_mmc_init(void) |
| 662 | { | 662 | { |
| 663 | int node_list[CONFIG_SYS_MMC_MAX_DEVICE], count; | 663 | int node_list[CONFIG_SYS_MMC_MAX_DEVICE], count; |
| 664 | const void *blob = gd->fdt_blob; | 664 | const void *blob = gd->fdt_blob; |
| 665 | debug("%s entry\n", __func__); | 665 | debug("%s entry\n", __func__); |
| 666 | 666 | ||
| 667 | /* See if any Tegra124 MMC controllers are present */ | 667 | /* See if any Tegra124 MMC controllers are present */ |
| 668 | count = fdtdec_find_aliases_for_id(blob, "sdhci", | 668 | count = fdtdec_find_aliases_for_id(blob, "sdhci", |
| 669 | COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, | 669 | COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, |
| 670 | CONFIG_SYS_MMC_MAX_DEVICE); | 670 | CONFIG_SYS_MMC_MAX_DEVICE); |
| 671 | debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); | 671 | debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); |
| 672 | if (process_nodes(blob, node_list, count)) { | 672 | if (process_nodes(blob, node_list, count)) { |
| 673 | printf("%s: Error processing T30 mmc node(s)!\n", __func__); | 673 | printf("%s: Error processing T30 mmc node(s)!\n", __func__); |
| 674 | return; | 674 | return; |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | /* See if any Tegra30 MMC controllers are present */ | 677 | /* See if any Tegra30 MMC controllers are present */ |
| 678 | count = fdtdec_find_aliases_for_id(blob, "sdhci", | 678 | count = fdtdec_find_aliases_for_id(blob, "sdhci", |
| 679 | COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, | 679 | COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, |
| 680 | CONFIG_SYS_MMC_MAX_DEVICE); | 680 | CONFIG_SYS_MMC_MAX_DEVICE); |
| 681 | debug("%s: count of T30 sdhci nodes is %d\n", __func__, count); | 681 | debug("%s: count of T30 sdhci nodes is %d\n", __func__, count); |
| 682 | if (process_nodes(blob, node_list, count)) { | 682 | if (process_nodes(blob, node_list, count)) { |
| 683 | printf("%s: Error processing T30 mmc node(s)!\n", __func__); | 683 | printf("%s: Error processing T30 mmc node(s)!\n", __func__); |
| 684 | return; | 684 | return; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | /* Now look for any Tegra20 MMC controllers */ | 687 | /* Now look for any Tegra20 MMC controllers */ |
| 688 | count = fdtdec_find_aliases_for_id(blob, "sdhci", | 688 | count = fdtdec_find_aliases_for_id(blob, "sdhci", |
| 689 | COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, | 689 | COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, |
| 690 | CONFIG_SYS_MMC_MAX_DEVICE); | 690 | CONFIG_SYS_MMC_MAX_DEVICE); |
| 691 | debug("%s: count of T20 sdhci nodes is %d\n", __func__, count); | 691 | debug("%s: count of T20 sdhci nodes is %d\n", __func__, count); |
| 692 | if (process_nodes(blob, node_list, count)) { | 692 | if (process_nodes(blob, node_list, count)) { |
| 693 | printf("%s: Error processing T20 mmc node(s)!\n", __func__); | 693 | printf("%s: Error processing T20 mmc node(s)!\n", __func__); |
| 694 | return; | 694 | return; |
| 695 | } | 695 | } |
| 696 | } | 696 | } |
| 697 | 697 |
drivers/mmc/zynq_sdhci.c
| 1 | /* | 1 | /* |
| 2 | * (C) Copyright 2013 Inc. | 2 | * (C) Copyright 2013 Inc. |
| 3 | * | 3 | * |
| 4 | * Xilinx Zynq SD Host Controller Interface | 4 | * Xilinx Zynq SD Host Controller Interface |
| 5 | * | 5 | * |
| 6 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <common.h> | 9 | #include <common.h> |
| 10 | #include <fdtdec.h> | 10 | #include <fdtdec.h> |
| 11 | #include <libfdt.h> | 11 | #include <libfdt.h> |
| 12 | #include <malloc.h> | 12 | #include <malloc.h> |
| 13 | #include <sdhci.h> | 13 | #include <sdhci.h> |
| 14 | #include <asm/arch/sys_proto.h> | 14 | #include <asm/arch/sys_proto.h> |
| 15 | 15 | ||
| 16 | int zynq_sdhci_init(phys_addr_t regbase) | 16 | int zynq_sdhci_init(phys_addr_t regbase) |
| 17 | { | 17 | { |
| 18 | struct sdhci_host *host = NULL; | 18 | struct sdhci_host *host = NULL; |
| 19 | 19 | ||
| 20 | host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); | 20 | host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); |
| 21 | if (!host) { | 21 | if (!host) { |
| 22 | printf("zynq_sdhci_init: sdhci_host malloc fail\n"); | 22 | printf("zynq_sdhci_init: sdhci_host malloc fail\n"); |
| 23 | return 1; | 23 | return 1; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | host->name = "zynq_sdhci"; | 26 | host->name = "zynq_sdhci"; |
| 27 | host->ioaddr = (void *)regbase; | 27 | host->ioaddr = (void *)regbase; |
| 28 | host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | | 28 | host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | |
| 29 | SDHCI_QUIRK_BROKEN_R1B; | 29 | SDHCI_QUIRK_BROKEN_R1B; |
| 30 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); | 30 | host->version = sdhci_readw(host, SDHCI_HOST_VERSION); |
| 31 | 31 | ||
| 32 | host->host_caps = MMC_MODE_HC; | ||
| 33 | |||
| 34 | add_sdhci(host, 52000000, 52000000 >> 9); | 32 | add_sdhci(host, 52000000, 52000000 >> 9); |
| 35 | return 0; | 33 | return 0; |
| 36 | } | 34 | } |
| 37 | 35 | ||
| 38 | #ifdef CONFIG_OF_CONTROL | 36 | #ifdef CONFIG_OF_CONTROL |
| 39 | int zynq_sdhci_of_init(const void *blob) | 37 | int zynq_sdhci_of_init(const void *blob) |
| 40 | { | 38 | { |
| 41 | int offset = 0; | 39 | int offset = 0; |
| 42 | u32 ret = 0; | 40 | u32 ret = 0; |
| 43 | phys_addr_t reg; | 41 | phys_addr_t reg; |
| 44 | 42 | ||
| 45 | debug("ZYNQ SDHCI: Initialization\n"); | 43 | debug("ZYNQ SDHCI: Initialization\n"); |
| 46 | 44 | ||
| 47 | do { | 45 | do { |
| 48 | offset = fdt_node_offset_by_compatible(blob, offset, | 46 | offset = fdt_node_offset_by_compatible(blob, offset, |
| 49 | "arasan,sdhci-8.9a"); | 47 | "arasan,sdhci-8.9a"); |
| 50 | if (offset != -1) { | 48 | if (offset != -1) { |
| 51 | reg = fdtdec_get_addr(blob, offset, "reg"); | 49 | reg = fdtdec_get_addr(blob, offset, "reg"); |
| 52 | if (reg != FDT_ADDR_T_NONE) { | 50 | if (reg != FDT_ADDR_T_NONE) { |
| 53 | ret |= zynq_sdhci_init(reg); | 51 | ret |= zynq_sdhci_init(reg); |
| 54 | } else { | 52 | } else { |
| 55 | debug("ZYNQ SDHCI: Can't get base address\n"); | 53 | debug("ZYNQ SDHCI: Can't get base address\n"); |
| 56 | return -1; | 54 | return -1; |
| 57 | } | 55 | } |
| 58 | } | 56 | } |
| 59 | } while (offset != -1); | 57 | } while (offset != -1); |
| 60 | 58 | ||
| 61 | return ret; | 59 | return ret; |
| 62 | } | 60 | } |
| 63 | #endif | 61 | #endif |
| 64 | 62 |
include/mmc.h
| 1 | /* | 1 | /* |
| 2 | * Copyright 2008,2010 Freescale Semiconductor, Inc | 2 | * Copyright 2008,2010 Freescale Semiconductor, Inc |
| 3 | * Andy Fleming | 3 | * Andy Fleming |
| 4 | * | 4 | * |
| 5 | * Based (loosely) on the Linux code | 5 | * Based (loosely) on the Linux code |
| 6 | * | 6 | * |
| 7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #ifndef _MMC_H_ | 10 | #ifndef _MMC_H_ |
| 11 | #define _MMC_H_ | 11 | #define _MMC_H_ |
| 12 | 12 | ||
| 13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
| 14 | #include <linux/compiler.h> | 14 | #include <linux/compiler.h> |
| 15 | #include <part.h> | 15 | #include <part.h> |
| 16 | 16 | ||
| 17 | /* SD/MMC version bits; 8 flags, 8 major, 8 minor, 8 change */ | 17 | /* SD/MMC version bits; 8 flags, 8 major, 8 minor, 8 change */ |
| 18 | #define SD_VERSION_SD (1U << 31) | 18 | #define SD_VERSION_SD (1U << 31) |
| 19 | #define MMC_VERSION_MMC (1U << 30) | 19 | #define MMC_VERSION_MMC (1U << 30) |
| 20 | 20 | ||
| 21 | #define MAKE_SDMMC_VERSION(a, b, c) \ | 21 | #define MAKE_SDMMC_VERSION(a, b, c) \ |
| 22 | ((((u32)(a)) << 16) | ((u32)(b) << 8) | (u32)(c)) | 22 | ((((u32)(a)) << 16) | ((u32)(b) << 8) | (u32)(c)) |
| 23 | #define MAKE_SD_VERSION(a, b, c) \ | 23 | #define MAKE_SD_VERSION(a, b, c) \ |
| 24 | (SD_VERSION_SD | MAKE_SDMMC_VERSION(a, b, c)) | 24 | (SD_VERSION_SD | MAKE_SDMMC_VERSION(a, b, c)) |
| 25 | #define MAKE_MMC_VERSION(a, b, c) \ | 25 | #define MAKE_MMC_VERSION(a, b, c) \ |
| 26 | (MMC_VERSION_MMC | MAKE_SDMMC_VERSION(a, b, c)) | 26 | (MMC_VERSION_MMC | MAKE_SDMMC_VERSION(a, b, c)) |
| 27 | 27 | ||
| 28 | #define EXTRACT_SDMMC_MAJOR_VERSION(x) \ | 28 | #define EXTRACT_SDMMC_MAJOR_VERSION(x) \ |
| 29 | (((u32)(x) >> 16) & 0xff) | 29 | (((u32)(x) >> 16) & 0xff) |
| 30 | #define EXTRACT_SDMMC_MINOR_VERSION(x) \ | 30 | #define EXTRACT_SDMMC_MINOR_VERSION(x) \ |
| 31 | (((u32)(x) >> 8) & 0xff) | 31 | (((u32)(x) >> 8) & 0xff) |
| 32 | #define EXTRACT_SDMMC_CHANGE_VERSION(x) \ | 32 | #define EXTRACT_SDMMC_CHANGE_VERSION(x) \ |
| 33 | ((u32)(x) & 0xff) | 33 | ((u32)(x) & 0xff) |
| 34 | 34 | ||
| 35 | #define SD_VERSION_3 MAKE_SD_VERSION(3, 0, 0) | 35 | #define SD_VERSION_3 MAKE_SD_VERSION(3, 0, 0) |
| 36 | #define SD_VERSION_2 MAKE_SD_VERSION(2, 0, 0) | 36 | #define SD_VERSION_2 MAKE_SD_VERSION(2, 0, 0) |
| 37 | #define SD_VERSION_1_0 MAKE_SD_VERSION(1, 0, 0) | 37 | #define SD_VERSION_1_0 MAKE_SD_VERSION(1, 0, 0) |
| 38 | #define SD_VERSION_1_10 MAKE_SD_VERSION(1, 10, 0) | 38 | #define SD_VERSION_1_10 MAKE_SD_VERSION(1, 10, 0) |
| 39 | 39 | ||
| 40 | #define MMC_VERSION_UNKNOWN MAKE_MMC_VERSION(0, 0, 0) | 40 | #define MMC_VERSION_UNKNOWN MAKE_MMC_VERSION(0, 0, 0) |
| 41 | #define MMC_VERSION_1_2 MAKE_MMC_VERSION(1, 2, 0) | 41 | #define MMC_VERSION_1_2 MAKE_MMC_VERSION(1, 2, 0) |
| 42 | #define MMC_VERSION_1_4 MAKE_MMC_VERSION(1, 4, 0) | 42 | #define MMC_VERSION_1_4 MAKE_MMC_VERSION(1, 4, 0) |
| 43 | #define MMC_VERSION_2_2 MAKE_MMC_VERSION(2, 2, 0) | 43 | #define MMC_VERSION_2_2 MAKE_MMC_VERSION(2, 2, 0) |
| 44 | #define MMC_VERSION_3 MAKE_MMC_VERSION(3, 0, 0) | 44 | #define MMC_VERSION_3 MAKE_MMC_VERSION(3, 0, 0) |
| 45 | #define MMC_VERSION_4 MAKE_MMC_VERSION(4, 0, 0) | 45 | #define MMC_VERSION_4 MAKE_MMC_VERSION(4, 0, 0) |
| 46 | #define MMC_VERSION_4_1 MAKE_MMC_VERSION(4, 1, 0) | 46 | #define MMC_VERSION_4_1 MAKE_MMC_VERSION(4, 1, 0) |
| 47 | #define MMC_VERSION_4_2 MAKE_MMC_VERSION(4, 2, 0) | 47 | #define MMC_VERSION_4_2 MAKE_MMC_VERSION(4, 2, 0) |
| 48 | #define MMC_VERSION_4_3 MAKE_MMC_VERSION(4, 3, 0) | 48 | #define MMC_VERSION_4_3 MAKE_MMC_VERSION(4, 3, 0) |
| 49 | #define MMC_VERSION_4_41 MAKE_MMC_VERSION(4, 4, 1) | 49 | #define MMC_VERSION_4_41 MAKE_MMC_VERSION(4, 4, 1) |
| 50 | #define MMC_VERSION_4_5 MAKE_MMC_VERSION(4, 5, 0) | 50 | #define MMC_VERSION_4_5 MAKE_MMC_VERSION(4, 5, 0) |
| 51 | #define MMC_VERSION_5_0 MAKE_MMC_VERSION(5, 0, 0) | 51 | #define MMC_VERSION_5_0 MAKE_MMC_VERSION(5, 0, 0) |
| 52 | 52 | ||
| 53 | #define MMC_MODE_HS (1 << 0) | 53 | #define MMC_MODE_HS (1 << 0) |
| 54 | #define MMC_MODE_HS_52MHz (1 << 1) | 54 | #define MMC_MODE_HS_52MHz (1 << 1) |
| 55 | #define MMC_MODE_4BIT (1 << 2) | 55 | #define MMC_MODE_4BIT (1 << 2) |
| 56 | #define MMC_MODE_8BIT (1 << 3) | 56 | #define MMC_MODE_8BIT (1 << 3) |
| 57 | #define MMC_MODE_SPI (1 << 4) | 57 | #define MMC_MODE_SPI (1 << 4) |
| 58 | #define MMC_MODE_HC (1 << 5) | 58 | #define MMC_MODE_DDR_52MHz (1 << 5) |
| 59 | #define MMC_MODE_DDR_52MHz (1 << 6) | ||
| 60 | 59 | ||
| 61 | #define SD_DATA_4BIT 0x00040000 | 60 | #define SD_DATA_4BIT 0x00040000 |
| 62 | 61 | ||
| 63 | #define IS_SD(x) ((x)->version & SD_VERSION_SD) | 62 | #define IS_SD(x) ((x)->version & SD_VERSION_SD) |
| 64 | #define IS_MMC(x) ((x)->version & MMC_VERSION_MMC) | 63 | #define IS_MMC(x) ((x)->version & MMC_VERSION_MMC) |
| 65 | 64 | ||
| 66 | #define MMC_DATA_READ 1 | 65 | #define MMC_DATA_READ 1 |
| 67 | #define MMC_DATA_WRITE 2 | 66 | #define MMC_DATA_WRITE 2 |
| 68 | 67 | ||
| 69 | #define NO_CARD_ERR -16 /* No SD/MMC card inserted */ | 68 | #define NO_CARD_ERR -16 /* No SD/MMC card inserted */ |
| 70 | #define UNUSABLE_ERR -17 /* Unusable Card */ | 69 | #define UNUSABLE_ERR -17 /* Unusable Card */ |
| 71 | #define COMM_ERR -18 /* Communications Error */ | 70 | #define COMM_ERR -18 /* Communications Error */ |
| 72 | #define TIMEOUT -19 | 71 | #define TIMEOUT -19 |
| 73 | #define SWITCH_ERR -20 /* Card reports failure to switch mode */ | 72 | #define SWITCH_ERR -20 /* Card reports failure to switch mode */ |
| 74 | 73 | ||
| 75 | #define MMC_CMD_GO_IDLE_STATE 0 | 74 | #define MMC_CMD_GO_IDLE_STATE 0 |
| 76 | #define MMC_CMD_SEND_OP_COND 1 | 75 | #define MMC_CMD_SEND_OP_COND 1 |
| 77 | #define MMC_CMD_ALL_SEND_CID 2 | 76 | #define MMC_CMD_ALL_SEND_CID 2 |
| 78 | #define MMC_CMD_SET_RELATIVE_ADDR 3 | 77 | #define MMC_CMD_SET_RELATIVE_ADDR 3 |
| 79 | #define MMC_CMD_SET_DSR 4 | 78 | #define MMC_CMD_SET_DSR 4 |
| 80 | #define MMC_CMD_SWITCH 6 | 79 | #define MMC_CMD_SWITCH 6 |
| 81 | #define MMC_CMD_SELECT_CARD 7 | 80 | #define MMC_CMD_SELECT_CARD 7 |
| 82 | #define MMC_CMD_SEND_EXT_CSD 8 | 81 | #define MMC_CMD_SEND_EXT_CSD 8 |
| 83 | #define MMC_CMD_SEND_CSD 9 | 82 | #define MMC_CMD_SEND_CSD 9 |
| 84 | #define MMC_CMD_SEND_CID 10 | 83 | #define MMC_CMD_SEND_CID 10 |
| 85 | #define MMC_CMD_STOP_TRANSMISSION 12 | 84 | #define MMC_CMD_STOP_TRANSMISSION 12 |
| 86 | #define MMC_CMD_SEND_STATUS 13 | 85 | #define MMC_CMD_SEND_STATUS 13 |
| 87 | #define MMC_CMD_SET_BLOCKLEN 16 | 86 | #define MMC_CMD_SET_BLOCKLEN 16 |
| 88 | #define MMC_CMD_READ_SINGLE_BLOCK 17 | 87 | #define MMC_CMD_READ_SINGLE_BLOCK 17 |
| 89 | #define MMC_CMD_READ_MULTIPLE_BLOCK 18 | 88 | #define MMC_CMD_READ_MULTIPLE_BLOCK 18 |
| 90 | #define MMC_CMD_SET_BLOCK_COUNT 23 | 89 | #define MMC_CMD_SET_BLOCK_COUNT 23 |
| 91 | #define MMC_CMD_WRITE_SINGLE_BLOCK 24 | 90 | #define MMC_CMD_WRITE_SINGLE_BLOCK 24 |
| 92 | #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 | 91 | #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 |
| 93 | #define MMC_CMD_ERASE_GROUP_START 35 | 92 | #define MMC_CMD_ERASE_GROUP_START 35 |
| 94 | #define MMC_CMD_ERASE_GROUP_END 36 | 93 | #define MMC_CMD_ERASE_GROUP_END 36 |
| 95 | #define MMC_CMD_ERASE 38 | 94 | #define MMC_CMD_ERASE 38 |
| 96 | #define MMC_CMD_APP_CMD 55 | 95 | #define MMC_CMD_APP_CMD 55 |
| 97 | #define MMC_CMD_SPI_READ_OCR 58 | 96 | #define MMC_CMD_SPI_READ_OCR 58 |
| 98 | #define MMC_CMD_SPI_CRC_ON_OFF 59 | 97 | #define MMC_CMD_SPI_CRC_ON_OFF 59 |
| 99 | #define MMC_CMD_RES_MAN 62 | 98 | #define MMC_CMD_RES_MAN 62 |
| 100 | 99 | ||
| 101 | #define MMC_CMD62_ARG1 0xefac62ec | 100 | #define MMC_CMD62_ARG1 0xefac62ec |
| 102 | #define MMC_CMD62_ARG2 0xcbaea7 | 101 | #define MMC_CMD62_ARG2 0xcbaea7 |
| 103 | 102 | ||
| 104 | 103 | ||
| 105 | #define SD_CMD_SEND_RELATIVE_ADDR 3 | 104 | #define SD_CMD_SEND_RELATIVE_ADDR 3 |
| 106 | #define SD_CMD_SWITCH_FUNC 6 | 105 | #define SD_CMD_SWITCH_FUNC 6 |
| 107 | #define SD_CMD_SEND_IF_COND 8 | 106 | #define SD_CMD_SEND_IF_COND 8 |
| 108 | #define SD_CMD_SWITCH_UHS18V 11 | 107 | #define SD_CMD_SWITCH_UHS18V 11 |
| 109 | 108 | ||
| 110 | #define SD_CMD_APP_SET_BUS_WIDTH 6 | 109 | #define SD_CMD_APP_SET_BUS_WIDTH 6 |
| 111 | #define SD_CMD_ERASE_WR_BLK_START 32 | 110 | #define SD_CMD_ERASE_WR_BLK_START 32 |
| 112 | #define SD_CMD_ERASE_WR_BLK_END 33 | 111 | #define SD_CMD_ERASE_WR_BLK_END 33 |
| 113 | #define SD_CMD_APP_SEND_OP_COND 41 | 112 | #define SD_CMD_APP_SEND_OP_COND 41 |
| 114 | #define SD_CMD_APP_SEND_SCR 51 | 113 | #define SD_CMD_APP_SEND_SCR 51 |
| 115 | 114 | ||
| 116 | /* SCR definitions in different words */ | 115 | /* SCR definitions in different words */ |
| 117 | #define SD_HIGHSPEED_BUSY 0x00020000 | 116 | #define SD_HIGHSPEED_BUSY 0x00020000 |
| 118 | #define SD_HIGHSPEED_SUPPORTED 0x00020000 | 117 | #define SD_HIGHSPEED_SUPPORTED 0x00020000 |
| 119 | 118 | ||
| 120 | #define OCR_BUSY 0x80000000 | 119 | #define OCR_BUSY 0x80000000 |
| 121 | #define OCR_HCS 0x40000000 | 120 | #define OCR_HCS 0x40000000 |
| 122 | #define OCR_VOLTAGE_MASK 0x007FFF80 | 121 | #define OCR_VOLTAGE_MASK 0x007FFF80 |
| 123 | #define OCR_ACCESS_MODE 0x60000000 | 122 | #define OCR_ACCESS_MODE 0x60000000 |
| 124 | 123 | ||
| 125 | #define SECURE_ERASE 0x80000000 | 124 | #define SECURE_ERASE 0x80000000 |
| 126 | 125 | ||
| 127 | #define MMC_STATUS_MASK (~0x0206BF7F) | 126 | #define MMC_STATUS_MASK (~0x0206BF7F) |
| 128 | #define MMC_STATUS_SWITCH_ERROR (1 << 7) | 127 | #define MMC_STATUS_SWITCH_ERROR (1 << 7) |
| 129 | #define MMC_STATUS_RDY_FOR_DATA (1 << 8) | 128 | #define MMC_STATUS_RDY_FOR_DATA (1 << 8) |
| 130 | #define MMC_STATUS_CURR_STATE (0xf << 9) | 129 | #define MMC_STATUS_CURR_STATE (0xf << 9) |
| 131 | #define MMC_STATUS_ERROR (1 << 19) | 130 | #define MMC_STATUS_ERROR (1 << 19) |
| 132 | 131 | ||
| 133 | #define MMC_STATE_PRG (7 << 9) | 132 | #define MMC_STATE_PRG (7 << 9) |
| 134 | 133 | ||
| 135 | #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ | 134 | #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ |
| 136 | #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ | 135 | #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ |
| 137 | #define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ | 136 | #define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ |
| 138 | #define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ | 137 | #define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ |
| 139 | #define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ | 138 | #define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ |
| 140 | #define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ | 139 | #define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ |
| 141 | #define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ | 140 | #define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ |
| 142 | #define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ | 141 | #define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ |
| 143 | #define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ | 142 | #define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ |
| 144 | #define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ | 143 | #define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ |
| 145 | #define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ | 144 | #define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ |
| 146 | #define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ | 145 | #define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ |
| 147 | #define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ | 146 | #define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ |
| 148 | #define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ | 147 | #define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ |
| 149 | #define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ | 148 | #define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ |
| 150 | #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ | 149 | #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ |
| 151 | #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ | 150 | #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ |
| 152 | 151 | ||
| 153 | #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ | 152 | #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ |
| 154 | #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte | 153 | #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte |
| 155 | addressed by index which are | 154 | addressed by index which are |
| 156 | 1 in value field */ | 155 | 1 in value field */ |
| 157 | #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte | 156 | #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte |
| 158 | addressed by index, which are | 157 | addressed by index, which are |
| 159 | 1 in value field */ | 158 | 1 in value field */ |
| 160 | #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */ | 159 | #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */ |
| 161 | 160 | ||
| 162 | #define SD_SWITCH_CHECK 0 | 161 | #define SD_SWITCH_CHECK 0 |
| 163 | #define SD_SWITCH_SWITCH 1 | 162 | #define SD_SWITCH_SWITCH 1 |
| 164 | 163 | ||
| 165 | /* | 164 | /* |
| 166 | * EXT_CSD fields | 165 | * EXT_CSD fields |
| 167 | */ | 166 | */ |
| 168 | #define EXT_CSD_ENH_START_ADDR 136 /* R/W */ | 167 | #define EXT_CSD_ENH_START_ADDR 136 /* R/W */ |
| 169 | #define EXT_CSD_ENH_SIZE_MULT 140 /* R/W */ | 168 | #define EXT_CSD_ENH_SIZE_MULT 140 /* R/W */ |
| 170 | #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ | 169 | #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ |
| 171 | #define EXT_CSD_PARTITION_SETTING 155 /* R/W */ | 170 | #define EXT_CSD_PARTITION_SETTING 155 /* R/W */ |
| 172 | #define EXT_CSD_PARTITIONS_ATTRIBUTE 156 /* R/W */ | 171 | #define EXT_CSD_PARTITIONS_ATTRIBUTE 156 /* R/W */ |
| 173 | #define EXT_CSD_MAX_ENH_SIZE_MULT 157 /* R */ | 172 | #define EXT_CSD_MAX_ENH_SIZE_MULT 157 /* R */ |
| 174 | #define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */ | 173 | #define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */ |
| 175 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ | 174 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ |
| 176 | #define EXT_CSD_WR_REL_PARAM 166 /* R */ | 175 | #define EXT_CSD_WR_REL_PARAM 166 /* R */ |
| 177 | #define EXT_CSD_WR_REL_SET 167 /* R/W */ | 176 | #define EXT_CSD_WR_REL_SET 167 /* R/W */ |
| 178 | #define EXT_CSD_RPMB_MULT 168 /* RO */ | 177 | #define EXT_CSD_RPMB_MULT 168 /* RO */ |
| 179 | #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ | 178 | #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ |
| 180 | #define EXT_CSD_BOOT_BUS_WIDTH 177 | 179 | #define EXT_CSD_BOOT_BUS_WIDTH 177 |
| 181 | #define EXT_CSD_PART_CONF 179 /* R/W */ | 180 | #define EXT_CSD_PART_CONF 179 /* R/W */ |
| 182 | #define EXT_CSD_BUS_WIDTH 183 /* R/W */ | 181 | #define EXT_CSD_BUS_WIDTH 183 /* R/W */ |
| 183 | #define EXT_CSD_HS_TIMING 185 /* R/W */ | 182 | #define EXT_CSD_HS_TIMING 185 /* R/W */ |
| 184 | #define EXT_CSD_REV 192 /* RO */ | 183 | #define EXT_CSD_REV 192 /* RO */ |
| 185 | #define EXT_CSD_CARD_TYPE 196 /* RO */ | 184 | #define EXT_CSD_CARD_TYPE 196 /* RO */ |
| 186 | #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ | 185 | #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ |
| 187 | #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ | 186 | #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ |
| 188 | #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ | 187 | #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ |
| 189 | #define EXT_CSD_BOOT_MULT 226 /* RO */ | 188 | #define EXT_CSD_BOOT_MULT 226 /* RO */ |
| 190 | 189 | ||
| 191 | /* | 190 | /* |
| 192 | * EXT_CSD field definitions | 191 | * EXT_CSD field definitions |
| 193 | */ | 192 | */ |
| 194 | 193 | ||
| 195 | #define EXT_CSD_CMD_SET_NORMAL (1 << 0) | 194 | #define EXT_CSD_CMD_SET_NORMAL (1 << 0) |
| 196 | #define EXT_CSD_CMD_SET_SECURE (1 << 1) | 195 | #define EXT_CSD_CMD_SET_SECURE (1 << 1) |
| 197 | #define EXT_CSD_CMD_SET_CPSECURE (1 << 2) | 196 | #define EXT_CSD_CMD_SET_CPSECURE (1 << 2) |
| 198 | 197 | ||
| 199 | #define EXT_CSD_CARD_TYPE_26 (1 << 0) /* Card can run at 26MHz */ | 198 | #define EXT_CSD_CARD_TYPE_26 (1 << 0) /* Card can run at 26MHz */ |
| 200 | #define EXT_CSD_CARD_TYPE_52 (1 << 1) /* Card can run at 52MHz */ | 199 | #define EXT_CSD_CARD_TYPE_52 (1 << 1) /* Card can run at 52MHz */ |
| 201 | #define EXT_CSD_CARD_TYPE_DDR_1_8V (1 << 2) | 200 | #define EXT_CSD_CARD_TYPE_DDR_1_8V (1 << 2) |
| 202 | #define EXT_CSD_CARD_TYPE_DDR_1_2V (1 << 3) | 201 | #define EXT_CSD_CARD_TYPE_DDR_1_2V (1 << 3) |
| 203 | #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ | 202 | #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ |
| 204 | | EXT_CSD_CARD_TYPE_DDR_1_2V) | 203 | | EXT_CSD_CARD_TYPE_DDR_1_2V) |
| 205 | 204 | ||
| 206 | #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ | 205 | #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ |
| 207 | #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ | 206 | #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ |
| 208 | #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ | 207 | #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ |
| 209 | #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ | 208 | #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ |
| 210 | #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ | 209 | #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ |
| 211 | 210 | ||
| 212 | #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) | 211 | #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) |
| 213 | #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) | 212 | #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) |
| 214 | #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) | 213 | #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) |
| 215 | #define EXT_CSD_PARTITION_ACCESS_DISABLE (0 << 0) | 214 | #define EXT_CSD_PARTITION_ACCESS_DISABLE (0 << 0) |
| 216 | 215 | ||
| 217 | #define EXT_CSD_BOOT_ACK(x) (x << 6) | 216 | #define EXT_CSD_BOOT_ACK(x) (x << 6) |
| 218 | #define EXT_CSD_BOOT_PART_NUM(x) (x << 3) | 217 | #define EXT_CSD_BOOT_PART_NUM(x) (x << 3) |
| 219 | #define EXT_CSD_PARTITION_ACCESS(x) (x << 0) | 218 | #define EXT_CSD_PARTITION_ACCESS(x) (x << 0) |
| 220 | 219 | ||
| 221 | #define EXT_CSD_BOOT_BUS_WIDTH_MODE(x) (x << 3) | 220 | #define EXT_CSD_BOOT_BUS_WIDTH_MODE(x) (x << 3) |
| 222 | #define EXT_CSD_BOOT_BUS_WIDTH_RESET(x) (x << 2) | 221 | #define EXT_CSD_BOOT_BUS_WIDTH_RESET(x) (x << 2) |
| 223 | #define EXT_CSD_BOOT_BUS_WIDTH_WIDTH(x) (x) | 222 | #define EXT_CSD_BOOT_BUS_WIDTH_WIDTH(x) (x) |
| 224 | 223 | ||
| 225 | #define EXT_CSD_PARTITION_SETTING_COMPLETED (1 << 0) | 224 | #define EXT_CSD_PARTITION_SETTING_COMPLETED (1 << 0) |
| 226 | 225 | ||
| 227 | #define EXT_CSD_ENH_USR (1 << 0) /* user data area is enhanced */ | 226 | #define EXT_CSD_ENH_USR (1 << 0) /* user data area is enhanced */ |
| 228 | #define EXT_CSD_ENH_GP(x) (1 << ((x)+1)) /* GP part (x+1) is enhanced */ | 227 | #define EXT_CSD_ENH_GP(x) (1 << ((x)+1)) /* GP part (x+1) is enhanced */ |
| 229 | 228 | ||
| 230 | #define EXT_CSD_HS_CTRL_REL (1 << 0) /* host controlled WR_REL_SET */ | 229 | #define EXT_CSD_HS_CTRL_REL (1 << 0) /* host controlled WR_REL_SET */ |
| 231 | 230 | ||
| 232 | #define EXT_CSD_WR_DATA_REL_USR (1 << 0) /* user data area WR_REL */ | 231 | #define EXT_CSD_WR_DATA_REL_USR (1 << 0) /* user data area WR_REL */ |
| 233 | #define EXT_CSD_WR_DATA_REL_GP(x) (1 << ((x)+1)) /* GP part (x+1) WR_REL */ | 232 | #define EXT_CSD_WR_DATA_REL_GP(x) (1 << ((x)+1)) /* GP part (x+1) WR_REL */ |
| 234 | 233 | ||
| 235 | #define R1_ILLEGAL_COMMAND (1 << 22) | 234 | #define R1_ILLEGAL_COMMAND (1 << 22) |
| 236 | #define R1_APP_CMD (1 << 5) | 235 | #define R1_APP_CMD (1 << 5) |
| 237 | 236 | ||
| 238 | #define MMC_RSP_PRESENT (1 << 0) | 237 | #define MMC_RSP_PRESENT (1 << 0) |
| 239 | #define MMC_RSP_136 (1 << 1) /* 136 bit response */ | 238 | #define MMC_RSP_136 (1 << 1) /* 136 bit response */ |
| 240 | #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ | 239 | #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ |
| 241 | #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ | 240 | #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ |
| 242 | #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ | 241 | #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ |
| 243 | 242 | ||
| 244 | #define MMC_RSP_NONE (0) | 243 | #define MMC_RSP_NONE (0) |
| 245 | #define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) | 244 | #define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) |
| 246 | #define MMC_RSP_R1b (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \ | 245 | #define MMC_RSP_R1b (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \ |
| 247 | MMC_RSP_BUSY) | 246 | MMC_RSP_BUSY) |
| 248 | #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) | 247 | #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) |
| 249 | #define MMC_RSP_R3 (MMC_RSP_PRESENT) | 248 | #define MMC_RSP_R3 (MMC_RSP_PRESENT) |
| 250 | #define MMC_RSP_R4 (MMC_RSP_PRESENT) | 249 | #define MMC_RSP_R4 (MMC_RSP_PRESENT) |
| 251 | #define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) | 250 | #define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) |
| 252 | #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) | 251 | #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) |
| 253 | #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) | 252 | #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) |
| 254 | 253 | ||
| 255 | #define MMCPART_NOAVAILABLE (0xff) | 254 | #define MMCPART_NOAVAILABLE (0xff) |
| 256 | #define PART_ACCESS_MASK (0x7) | 255 | #define PART_ACCESS_MASK (0x7) |
| 257 | #define PART_SUPPORT (0x1) | 256 | #define PART_SUPPORT (0x1) |
| 258 | #define ENHNCD_SUPPORT (0x2) | 257 | #define ENHNCD_SUPPORT (0x2) |
| 259 | #define PART_ENH_ATTRIB (0x1f) | 258 | #define PART_ENH_ATTRIB (0x1f) |
| 260 | 259 | ||
| 261 | /* Maximum block size for MMC */ | 260 | /* Maximum block size for MMC */ |
| 262 | #define MMC_MAX_BLOCK_LEN 512 | 261 | #define MMC_MAX_BLOCK_LEN 512 |
| 263 | 262 | ||
| 264 | /* The number of MMC physical partitions. These consist of: | 263 | /* The number of MMC physical partitions. These consist of: |
| 265 | * boot partitions (2), general purpose partitions (4) in MMC v4.4. | 264 | * boot partitions (2), general purpose partitions (4) in MMC v4.4. |
| 266 | */ | 265 | */ |
| 267 | #define MMC_NUM_BOOT_PARTITION 2 | 266 | #define MMC_NUM_BOOT_PARTITION 2 |
| 268 | #define MMC_PART_RPMB 3 /* RPMB partition number */ | 267 | #define MMC_PART_RPMB 3 /* RPMB partition number */ |
| 269 | 268 | ||
| 270 | struct mmc_cid { | 269 | struct mmc_cid { |
| 271 | unsigned long psn; | 270 | unsigned long psn; |
| 272 | unsigned short oid; | 271 | unsigned short oid; |
| 273 | unsigned char mid; | 272 | unsigned char mid; |
| 274 | unsigned char prv; | 273 | unsigned char prv; |
| 275 | unsigned char mdt; | 274 | unsigned char mdt; |
| 276 | char pnm[7]; | 275 | char pnm[7]; |
| 277 | }; | 276 | }; |
| 278 | 277 | ||
| 279 | struct mmc_cmd { | 278 | struct mmc_cmd { |
| 280 | ushort cmdidx; | 279 | ushort cmdidx; |
| 281 | uint resp_type; | 280 | uint resp_type; |
| 282 | uint cmdarg; | 281 | uint cmdarg; |
| 283 | uint response[4]; | 282 | uint response[4]; |
| 284 | }; | 283 | }; |
| 285 | 284 | ||
| 286 | struct mmc_data { | 285 | struct mmc_data { |
| 287 | union { | 286 | union { |
| 288 | char *dest; | 287 | char *dest; |
| 289 | const char *src; /* src buffers don't get written to */ | 288 | const char *src; /* src buffers don't get written to */ |
| 290 | }; | 289 | }; |
| 291 | uint flags; | 290 | uint flags; |
| 292 | uint blocks; | 291 | uint blocks; |
| 293 | uint blocksize; | 292 | uint blocksize; |
| 294 | }; | 293 | }; |
| 295 | 294 | ||
| 296 | /* forward decl. */ | 295 | /* forward decl. */ |
| 297 | struct mmc; | 296 | struct mmc; |
| 298 | 297 | ||
| 299 | struct mmc_ops { | 298 | struct mmc_ops { |
| 300 | int (*send_cmd)(struct mmc *mmc, | 299 | int (*send_cmd)(struct mmc *mmc, |
| 301 | struct mmc_cmd *cmd, struct mmc_data *data); | 300 | struct mmc_cmd *cmd, struct mmc_data *data); |
| 302 | void (*set_ios)(struct mmc *mmc); | 301 | void (*set_ios)(struct mmc *mmc); |
| 303 | int (*init)(struct mmc *mmc); | 302 | int (*init)(struct mmc *mmc); |
| 304 | int (*getcd)(struct mmc *mmc); | 303 | int (*getcd)(struct mmc *mmc); |
| 305 | int (*getwp)(struct mmc *mmc); | 304 | int (*getwp)(struct mmc *mmc); |
| 306 | }; | 305 | }; |
| 307 | 306 | ||
| 308 | struct mmc_config { | 307 | struct mmc_config { |
| 309 | const char *name; | 308 | const char *name; |
| 310 | const struct mmc_ops *ops; | 309 | const struct mmc_ops *ops; |
| 311 | uint host_caps; | 310 | uint host_caps; |
| 312 | uint voltages; | 311 | uint voltages; |
| 313 | uint f_min; | 312 | uint f_min; |
| 314 | uint f_max; | 313 | uint f_max; |
| 315 | uint b_max; | 314 | uint b_max; |
| 316 | unsigned char part_type; | 315 | unsigned char part_type; |
| 317 | }; | 316 | }; |
| 318 | 317 | ||
| 319 | /* TODO struct mmc should be in mmc_private but it's hard to fix right now */ | 318 | /* TODO struct mmc should be in mmc_private but it's hard to fix right now */ |
| 320 | struct mmc { | 319 | struct mmc { |
| 321 | struct list_head link; | 320 | struct list_head link; |
| 322 | const struct mmc_config *cfg; /* provided configuration */ | 321 | const struct mmc_config *cfg; /* provided configuration */ |
| 323 | uint version; | 322 | uint version; |
| 324 | void *priv; | 323 | void *priv; |
| 325 | uint has_init; | 324 | uint has_init; |
| 326 | int high_capacity; | 325 | int high_capacity; |
| 327 | uint bus_width; | 326 | uint bus_width; |
| 328 | uint clock; | 327 | uint clock; |
| 329 | uint card_caps; | 328 | uint card_caps; |
| 330 | uint ocr; | 329 | uint ocr; |
| 331 | uint dsr; | 330 | uint dsr; |
| 332 | uint dsr_imp; | 331 | uint dsr_imp; |
| 333 | uint scr[2]; | 332 | uint scr[2]; |
| 334 | uint csd[4]; | 333 | uint csd[4]; |
| 335 | uint cid[4]; | 334 | uint cid[4]; |
| 336 | ushort rca; | 335 | ushort rca; |
| 337 | u8 part_support; | 336 | u8 part_support; |
| 338 | u8 part_attr; | 337 | u8 part_attr; |
| 339 | u8 wr_rel_set; | 338 | u8 wr_rel_set; |
| 340 | char part_config; | 339 | char part_config; |
| 341 | char part_num; | 340 | char part_num; |
| 342 | uint tran_speed; | 341 | uint tran_speed; |
| 343 | uint read_bl_len; | 342 | uint read_bl_len; |
| 344 | uint write_bl_len; | 343 | uint write_bl_len; |
| 345 | uint erase_grp_size; /* in 512-byte sectors */ | 344 | uint erase_grp_size; /* in 512-byte sectors */ |
| 346 | uint hc_wp_grp_size; /* in 512-byte sectors */ | 345 | uint hc_wp_grp_size; /* in 512-byte sectors */ |
| 347 | u64 capacity; | 346 | u64 capacity; |
| 348 | u64 capacity_user; | 347 | u64 capacity_user; |
| 349 | u64 capacity_boot; | 348 | u64 capacity_boot; |
| 350 | u64 capacity_rpmb; | 349 | u64 capacity_rpmb; |
| 351 | u64 capacity_gp[4]; | 350 | u64 capacity_gp[4]; |
| 352 | u64 enh_user_start; | 351 | u64 enh_user_start; |
| 353 | u64 enh_user_size; | 352 | u64 enh_user_size; |
| 354 | block_dev_desc_t block_dev; | 353 | block_dev_desc_t block_dev; |
| 355 | char op_cond_pending; /* 1 if we are waiting on an op_cond command */ | 354 | char op_cond_pending; /* 1 if we are waiting on an op_cond command */ |
| 356 | char init_in_progress; /* 1 if we have done mmc_start_init() */ | 355 | char init_in_progress; /* 1 if we have done mmc_start_init() */ |
| 357 | char preinit; /* start init as early as possible */ | 356 | char preinit; /* start init as early as possible */ |
| 358 | int ddr_mode; | 357 | int ddr_mode; |
| 359 | }; | 358 | }; |
| 360 | 359 | ||
| 361 | struct mmc_hwpart_conf { | 360 | struct mmc_hwpart_conf { |
| 362 | struct { | 361 | struct { |
| 363 | uint enh_start; /* in 512-byte sectors */ | 362 | uint enh_start; /* in 512-byte sectors */ |
| 364 | uint enh_size; /* in 512-byte sectors, if 0 no enh area */ | 363 | uint enh_size; /* in 512-byte sectors, if 0 no enh area */ |
| 365 | unsigned wr_rel_change : 1; | 364 | unsigned wr_rel_change : 1; |
| 366 | unsigned wr_rel_set : 1; | 365 | unsigned wr_rel_set : 1; |
| 367 | } user; | 366 | } user; |
| 368 | struct { | 367 | struct { |
| 369 | uint size; /* in 512-byte sectors */ | 368 | uint size; /* in 512-byte sectors */ |
| 370 | unsigned enhanced : 1; | 369 | unsigned enhanced : 1; |
| 371 | unsigned wr_rel_change : 1; | 370 | unsigned wr_rel_change : 1; |
| 372 | unsigned wr_rel_set : 1; | 371 | unsigned wr_rel_set : 1; |
| 373 | } gp_part[4]; | 372 | } gp_part[4]; |
| 374 | }; | 373 | }; |
| 375 | 374 | ||
| 376 | enum mmc_hwpart_conf_mode { | 375 | enum mmc_hwpart_conf_mode { |
| 377 | MMC_HWPART_CONF_CHECK, | 376 | MMC_HWPART_CONF_CHECK, |
| 378 | MMC_HWPART_CONF_SET, | 377 | MMC_HWPART_CONF_SET, |
| 379 | MMC_HWPART_CONF_COMPLETE, | 378 | MMC_HWPART_CONF_COMPLETE, |
| 380 | }; | 379 | }; |
| 381 | 380 | ||
| 382 | int mmc_register(struct mmc *mmc); | 381 | int mmc_register(struct mmc *mmc); |
| 383 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv); | 382 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv); |
| 384 | void mmc_destroy(struct mmc *mmc); | 383 | void mmc_destroy(struct mmc *mmc); |
| 385 | int mmc_initialize(bd_t *bis); | 384 | int mmc_initialize(bd_t *bis); |
| 386 | int mmc_init(struct mmc *mmc); | 385 | int mmc_init(struct mmc *mmc); |
| 387 | int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); | 386 | int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); |
| 388 | void mmc_set_clock(struct mmc *mmc, uint clock); | 387 | void mmc_set_clock(struct mmc *mmc, uint clock); |
| 389 | struct mmc *find_mmc_device(int dev_num); | 388 | struct mmc *find_mmc_device(int dev_num); |
| 390 | int mmc_set_dev(int dev_num); | 389 | int mmc_set_dev(int dev_num); |
| 391 | void print_mmc_devices(char separator); | 390 | void print_mmc_devices(char separator); |
| 392 | int get_mmc_num(void); | 391 | int get_mmc_num(void); |
| 393 | int mmc_switch_part(int dev_num, unsigned int part_num); | 392 | int mmc_switch_part(int dev_num, unsigned int part_num); |
| 394 | int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, | 393 | int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, |
| 395 | enum mmc_hwpart_conf_mode mode); | 394 | enum mmc_hwpart_conf_mode mode); |
| 396 | int mmc_getcd(struct mmc *mmc); | 395 | int mmc_getcd(struct mmc *mmc); |
| 397 | int board_mmc_getcd(struct mmc *mmc); | 396 | int board_mmc_getcd(struct mmc *mmc); |
| 398 | int mmc_getwp(struct mmc *mmc); | 397 | int mmc_getwp(struct mmc *mmc); |
| 399 | int board_mmc_getwp(struct mmc *mmc); | 398 | int board_mmc_getwp(struct mmc *mmc); |
| 400 | int mmc_set_dsr(struct mmc *mmc, u16 val); | 399 | int mmc_set_dsr(struct mmc *mmc, u16 val); |
| 401 | /* Function to change the size of boot partition and rpmb partitions */ | 400 | /* Function to change the size of boot partition and rpmb partitions */ |
| 402 | int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, | 401 | int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, |
| 403 | unsigned long rpmbsize); | 402 | unsigned long rpmbsize); |
| 404 | /* Function to modify the PARTITION_CONFIG field of EXT_CSD */ | 403 | /* Function to modify the PARTITION_CONFIG field of EXT_CSD */ |
| 405 | int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access); | 404 | int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access); |
| 406 | /* Function to modify the BOOT_BUS_WIDTH field of EXT_CSD */ | 405 | /* Function to modify the BOOT_BUS_WIDTH field of EXT_CSD */ |
| 407 | int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode); | 406 | int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode); |
| 408 | /* Function to modify the RST_n_FUNCTION field of EXT_CSD */ | 407 | /* Function to modify the RST_n_FUNCTION field of EXT_CSD */ |
| 409 | int mmc_set_rst_n_function(struct mmc *mmc, u8 enable); | 408 | int mmc_set_rst_n_function(struct mmc *mmc, u8 enable); |
| 410 | /* Functions to read / write the RPMB partition */ | 409 | /* Functions to read / write the RPMB partition */ |
| 411 | int mmc_rpmb_set_key(struct mmc *mmc, void *key); | 410 | int mmc_rpmb_set_key(struct mmc *mmc, void *key); |
| 412 | int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter); | 411 | int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter); |
| 413 | int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, | 412 | int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, |
| 414 | unsigned short cnt, unsigned char *key); | 413 | unsigned short cnt, unsigned char *key); |
| 415 | int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, | 414 | int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, |
| 416 | unsigned short cnt, unsigned char *key); | 415 | unsigned short cnt, unsigned char *key); |
| 417 | /** | 416 | /** |
| 418 | * Start device initialization and return immediately; it does not block on | 417 | * Start device initialization and return immediately; it does not block on |
| 419 | * polling OCR (operation condition register) status. Then you should call | 418 | * polling OCR (operation condition register) status. Then you should call |
| 420 | * mmc_init, which would block on polling OCR status and complete the device | 419 | * mmc_init, which would block on polling OCR status and complete the device |
| 421 | * initializatin. | 420 | * initializatin. |
| 422 | * | 421 | * |
| 423 | * @param mmc Pointer to a MMC device struct | 422 | * @param mmc Pointer to a MMC device struct |
| 424 | * @return 0 on success, IN_PROGRESS on waiting for OCR status, <0 on error. | 423 | * @return 0 on success, IN_PROGRESS on waiting for OCR status, <0 on error. |
| 425 | */ | 424 | */ |
| 426 | int mmc_start_init(struct mmc *mmc); | 425 | int mmc_start_init(struct mmc *mmc); |
| 427 | 426 | ||
| 428 | /** | 427 | /** |
| 429 | * Set preinit flag of mmc device. | 428 | * Set preinit flag of mmc device. |
| 430 | * | 429 | * |
| 431 | * This will cause the device to be pre-inited during mmc_initialize(), | 430 | * This will cause the device to be pre-inited during mmc_initialize(), |
| 432 | * which may save boot time if the device is not accessed until later. | 431 | * which may save boot time if the device is not accessed until later. |
| 433 | * Some eMMC devices take 200-300ms to init, but unfortunately they | 432 | * Some eMMC devices take 200-300ms to init, but unfortunately they |
| 434 | * must be sent a series of commands to even get them to start preparing | 433 | * must be sent a series of commands to even get them to start preparing |
| 435 | * for operation. | 434 | * for operation. |
| 436 | * | 435 | * |
| 437 | * @param mmc Pointer to a MMC device struct | 436 | * @param mmc Pointer to a MMC device struct |
| 438 | * @param preinit preinit flag value | 437 | * @param preinit preinit flag value |
| 439 | */ | 438 | */ |
| 440 | void mmc_set_preinit(struct mmc *mmc, int preinit); | 439 | void mmc_set_preinit(struct mmc *mmc, int preinit); |
| 441 | 440 | ||
| 442 | #ifdef CONFIG_GENERIC_MMC | 441 | #ifdef CONFIG_GENERIC_MMC |
| 443 | #ifdef CONFIG_MMC_SPI | 442 | #ifdef CONFIG_MMC_SPI |
| 444 | #define mmc_host_is_spi(mmc) ((mmc)->cfg->host_caps & MMC_MODE_SPI) | 443 | #define mmc_host_is_spi(mmc) ((mmc)->cfg->host_caps & MMC_MODE_SPI) |
| 445 | #else | 444 | #else |
| 446 | #define mmc_host_is_spi(mmc) 0 | 445 | #define mmc_host_is_spi(mmc) 0 |
| 447 | #endif | 446 | #endif |
| 448 | struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode); | 447 | struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode); |
| 449 | #else | 448 | #else |
| 450 | int mmc_legacy_init(int verbose); | 449 | int mmc_legacy_init(int verbose); |
| 451 | #endif | 450 | #endif |
| 452 | 451 | ||
| 453 | void board_mmc_power_init(void); | 452 | void board_mmc_power_init(void); |
| 454 | int board_mmc_init(bd_t *bis); | 453 | int board_mmc_init(bd_t *bis); |
| 455 | int cpu_mmc_init(bd_t *bis); | 454 | int cpu_mmc_init(bd_t *bis); |
| 456 | int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); | 455 | int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); |
| 457 | 456 | ||
| 458 | struct pci_device_id; | 457 | struct pci_device_id; |
| 459 | 458 | ||
| 460 | /** | 459 | /** |
| 461 | * pci_mmc_init() - set up PCI MMC devices | 460 | * pci_mmc_init() - set up PCI MMC devices |
| 462 | * | 461 | * |
| 463 | * This finds all the matching PCI IDs and sets them up as MMC devices. | 462 | * This finds all the matching PCI IDs and sets them up as MMC devices. |
| 464 | * | 463 | * |
| 465 | * @name: Name to use for devices | 464 | * @name: Name to use for devices |
| 466 | * @mmc_supported: PCI IDs to search for | 465 | * @mmc_supported: PCI IDs to search for |
| 467 | * @num_ids: Number of elements in @mmc_supported | 466 | * @num_ids: Number of elements in @mmc_supported |
| 468 | */ | 467 | */ |
| 469 | int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported, | 468 | int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported, |
| 470 | int num_ids); | 469 | int num_ids); |
| 471 | 470 | ||
| 472 | /* Set block count limit because of 16 bit register limit on some hardware*/ | 471 | /* Set block count limit because of 16 bit register limit on some hardware*/ |
| 473 | #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT | 472 | #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT |
| 474 | #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 | 473 | #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 |
| 475 | #endif | 474 | #endif |
| 476 | 475 | ||
| 477 | #endif /* _MMC_H_ */ | 476 | #endif /* _MMC_H_ */ |
| 478 | 477 |