diff options
| -rw-r--r-- | arch/arm/mach-msm/dma.c | 5 | ||||
| -rw-r--r-- | arch/arm/mach-msm/include/mach/dma.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 472 | ||||
| -rw-r--r-- | drivers/mmc/host/msm_sdcc.h | 15 |
4 files changed, 308 insertions, 186 deletions
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 3d725ae518e4..d029d1f5f9e2 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c | |||
| @@ -69,6 +69,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | |||
| 69 | writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); | 69 | writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); |
| 70 | } | 70 | } |
| 71 | #endif | 71 | #endif |
| 72 | if (cmd->execute_func) | ||
| 73 | cmd->execute_func(cmd); | ||
| 72 | PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); | 74 | PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); |
| 73 | list_add_tail(&cmd->list, &active_commands[id]); | 75 | list_add_tail(&cmd->list, &active_commands[id]); |
| 74 | if (!channel_active) | 76 | if (!channel_active) |
| @@ -116,6 +118,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) | |||
| 116 | 118 | ||
| 117 | cmd.dmov_cmd.cmdptr = cmdptr; | 119 | cmd.dmov_cmd.cmdptr = cmdptr; |
| 118 | cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; | 120 | cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; |
| 121 | cmd.dmov_cmd.execute_func = NULL; | ||
| 119 | cmd.id = id; | 122 | cmd.id = id; |
| 120 | init_completion(&cmd.complete); | 123 | init_completion(&cmd.complete); |
| 121 | 124 | ||
| @@ -221,6 +224,8 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
| 221 | cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); | 224 | cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); |
| 222 | list_del(&cmd->list); | 225 | list_del(&cmd->list); |
| 223 | list_add_tail(&cmd->list, &active_commands[id]); | 226 | list_add_tail(&cmd->list, &active_commands[id]); |
| 227 | if (cmd->execute_func) | ||
| 228 | cmd->execute_func(cmd); | ||
| 224 | PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); | 229 | PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); |
| 225 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | 230 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); |
| 226 | } | 231 | } |
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 04c51cc04f31..00f9bbfadbe6 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h | |||
| @@ -28,6 +28,8 @@ struct msm_dmov_cmd { | |||
| 28 | void (*complete_func)(struct msm_dmov_cmd *cmd, | 28 | void (*complete_func)(struct msm_dmov_cmd *cmd, |
| 29 | unsigned int result, | 29 | unsigned int result, |
| 30 | struct msm_dmov_errdata *err); | 30 | struct msm_dmov_errdata *err); |
| 31 | void (*execute_func)(struct msm_dmov_cmd *cmd); | ||
| 32 | void *data; | ||
| 31 | }; | 33 | }; |
| 32 | 34 | ||
| 33 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); | 35 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); |
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 04ae884383f6..61f1d27fed3f 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2007 Google Inc, | 4 | * Copyright (C) 2007 Google Inc, |
| 5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. | 5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. |
| 6 | * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. | ||
| 6 | * | 7 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| @@ -26,6 +27,7 @@ | |||
| 26 | #include <linux/log2.h> | 27 | #include <linux/log2.h> |
| 27 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
| 28 | #include <linux/mmc/card.h> | 29 | #include <linux/mmc/card.h> |
| 30 | #include <linux/mmc/sdio.h> | ||
| 29 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
| 30 | #include <linux/scatterlist.h> | 32 | #include <linux/scatterlist.h> |
| 31 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
| @@ -47,6 +49,8 @@ | |||
| 47 | 49 | ||
| 48 | #define DRIVER_NAME "msm-sdcc" | 50 | #define DRIVER_NAME "msm-sdcc" |
| 49 | 51 | ||
| 52 | #define BUSCLK_PWRSAVE 1 | ||
| 53 | #define BUSCLK_TIMEOUT (HZ) | ||
| 50 | static unsigned int msmsdcc_fmin = 144000; | 54 | static unsigned int msmsdcc_fmin = 144000; |
| 51 | static unsigned int msmsdcc_fmax = 50000000; | 55 | static unsigned int msmsdcc_fmax = 50000000; |
| 52 | static unsigned int msmsdcc_4bit = 1; | 56 | static unsigned int msmsdcc_4bit = 1; |
| @@ -57,6 +61,67 @@ static unsigned int msmsdcc_sdioirq; | |||
| 57 | #define PIO_SPINMAX 30 | 61 | #define PIO_SPINMAX 30 |
| 58 | #define CMD_SPINMAX 20 | 62 | #define CMD_SPINMAX 20 |
| 59 | 63 | ||
| 64 | |||
| 65 | static inline void | ||
| 66 | msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) | ||
| 67 | { | ||
| 68 | WARN_ON(!host->clks_on); | ||
| 69 | |||
| 70 | BUG_ON(host->curr.mrq); | ||
| 71 | |||
| 72 | if (deferr) { | ||
| 73 | mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); | ||
| 74 | } else { | ||
| 75 | del_timer_sync(&host->busclk_timer); | ||
| 76 | /* Need to check clks_on again in case the busclk | ||
| 77 | * timer fired | ||
| 78 | */ | ||
| 79 | if (host->clks_on) { | ||
| 80 | clk_disable(host->clk); | ||
| 81 | clk_disable(host->pclk); | ||
| 82 | host->clks_on = 0; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline int | ||
| 88 | msmsdcc_enable_clocks(struct msmsdcc_host *host) | ||
| 89 | { | ||
| 90 | int rc; | ||
| 91 | |||
| 92 | del_timer_sync(&host->busclk_timer); | ||
| 93 | |||
| 94 | if (!host->clks_on) { | ||
| 95 | rc = clk_enable(host->pclk); | ||
| 96 | if (rc) | ||
| 97 | return rc; | ||
| 98 | rc = clk_enable(host->clk); | ||
| 99 | if (rc) { | ||
| 100 | clk_disable(host->pclk); | ||
| 101 | return rc; | ||
| 102 | } | ||
| 103 | udelay(1 + ((3 * USEC_PER_SEC) / | ||
| 104 | (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); | ||
| 105 | host->clks_on = 1; | ||
| 106 | } | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline unsigned int | ||
| 111 | msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) | ||
| 112 | { | ||
| 113 | return readl(host->base + reg); | ||
| 114 | } | ||
| 115 | |||
| 116 | static inline void | ||
| 117 | msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) | ||
| 118 | { | ||
| 119 | writel(data, host->base + reg); | ||
| 120 | /* 3 clk delay required! */ | ||
| 121 | udelay(1 + ((3 * USEC_PER_SEC) / | ||
| 122 | (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); | ||
| 123 | } | ||
| 124 | |||
| 60 | static void | 125 | static void |
| 61 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | 126 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, |
| 62 | u32 c); | 127 | u32 c); |
| @@ -64,8 +129,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | |||
| 64 | static void | 129 | static void |
| 65 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | 130 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) |
| 66 | { | 131 | { |
| 67 | writel(0, host->base + MMCICOMMAND); | ||
| 68 | |||
| 69 | BUG_ON(host->curr.data); | 132 | BUG_ON(host->curr.data); |
| 70 | 133 | ||
| 71 | host->curr.mrq = NULL; | 134 | host->curr.mrq = NULL; |
| @@ -76,6 +139,9 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
| 76 | if (mrq->cmd->error == -ETIMEDOUT) | 139 | if (mrq->cmd->error == -ETIMEDOUT) |
| 77 | mdelay(5); | 140 | mdelay(5); |
| 78 | 141 | ||
| 142 | #if BUSCLK_PWRSAVE | ||
| 143 | msmsdcc_disable_clocks(host, 1); | ||
| 144 | #endif | ||
| 79 | /* | 145 | /* |
| 80 | * Need to drop the host lock here; mmc_request_done may call | 146 | * Need to drop the host lock here; mmc_request_done may call |
| 81 | * back into the driver... | 147 | * back into the driver... |
| @@ -88,7 +154,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
| 88 | static void | 154 | static void |
| 89 | msmsdcc_stop_data(struct msmsdcc_host *host) | 155 | msmsdcc_stop_data(struct msmsdcc_host *host) |
| 90 | { | 156 | { |
| 91 | writel(0, host->base + MMCIDATACTRL); | ||
| 92 | host->curr.data = NULL; | 157 | host->curr.data = NULL; |
| 93 | host->curr.got_dataend = host->curr.got_datablkend = 0; | 158 | host->curr.got_dataend = host->curr.got_datablkend = 0; |
| 94 | } | 159 | } |
| @@ -109,6 +174,31 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) | |||
| 109 | return 0; | 174 | return 0; |
| 110 | } | 175 | } |
| 111 | 176 | ||
| 177 | static inline void | ||
| 178 | msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { | ||
| 179 | msmsdcc_writel(host, arg, MMCIARGUMENT); | ||
| 180 | msmsdcc_writel(host, c, MMCICOMMAND); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void | ||
| 184 | msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) | ||
| 185 | { | ||
| 186 | struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; | ||
| 187 | |||
| 188 | msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); | ||
| 189 | msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, | ||
| 190 | MMCIDATALENGTH); | ||
| 191 | msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); | ||
| 192 | msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); | ||
| 193 | |||
| 194 | if (host->cmd_cmd) { | ||
| 195 | msmsdcc_start_command_exec(host, | ||
| 196 | (u32) host->cmd_cmd->arg, | ||
| 197 | (u32) host->cmd_c); | ||
| 198 | } | ||
| 199 | host->dma.active = 1; | ||
| 200 | } | ||
| 201 | |||
| 112 | static void | 202 | static void |
| 113 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | 203 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, |
| 114 | unsigned int result, | 204 | unsigned int result, |
| @@ -121,8 +211,11 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
| 121 | struct mmc_request *mrq; | 211 | struct mmc_request *mrq; |
| 122 | 212 | ||
| 123 | spin_lock_irqsave(&host->lock, flags); | 213 | spin_lock_irqsave(&host->lock, flags); |
| 214 | host->dma.active = 0; | ||
| 215 | |||
| 124 | mrq = host->curr.mrq; | 216 | mrq = host->curr.mrq; |
| 125 | BUG_ON(!mrq); | 217 | BUG_ON(!mrq); |
| 218 | WARN_ON(!mrq->data); | ||
| 126 | 219 | ||
| 127 | if (!(result & DMOV_RSLT_VALID)) { | 220 | if (!(result & DMOV_RSLT_VALID)) { |
| 128 | pr_err("msmsdcc: Invalid DataMover result\n"); | 221 | pr_err("msmsdcc: Invalid DataMover result\n"); |
| @@ -146,7 +239,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
| 146 | if (!mrq->data->error) | 239 | if (!mrq->data->error) |
| 147 | mrq->data->error = -EIO; | 240 | mrq->data->error = -EIO; |
| 148 | } | 241 | } |
| 149 | host->dma.busy = 0; | ||
| 150 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, | 242 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, |
| 151 | host->dma.dir); | 243 | host->dma.dir); |
| 152 | 244 | ||
| @@ -159,6 +251,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
| 159 | } | 251 | } |
| 160 | 252 | ||
| 161 | host->dma.sg = NULL; | 253 | host->dma.sg = NULL; |
| 254 | host->dma.busy = 0; | ||
| 162 | 255 | ||
| 163 | if ((host->curr.got_dataend && host->curr.got_datablkend) | 256 | if ((host->curr.got_dataend && host->curr.got_datablkend) |
| 164 | || mrq->data->error) { | 257 | || mrq->data->error) { |
| @@ -172,12 +265,14 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
| 172 | if (!mrq->data->error) | 265 | if (!mrq->data->error) |
| 173 | host->curr.data_xfered = host->curr.xfer_size; | 266 | host->curr.data_xfered = host->curr.xfer_size; |
| 174 | if (!mrq->data->stop || mrq->cmd->error) { | 267 | if (!mrq->data->stop || mrq->cmd->error) { |
| 175 | writel(0, host->base + MMCICOMMAND); | ||
| 176 | host->curr.mrq = NULL; | 268 | host->curr.mrq = NULL; |
| 177 | host->curr.cmd = NULL; | 269 | host->curr.cmd = NULL; |
| 178 | mrq->data->bytes_xfered = host->curr.data_xfered; | 270 | mrq->data->bytes_xfered = host->curr.data_xfered; |
| 179 | 271 | ||
| 180 | spin_unlock_irqrestore(&host->lock, flags); | 272 | spin_unlock_irqrestore(&host->lock, flags); |
| 273 | #if BUSCLK_PWRSAVE | ||
| 274 | msmsdcc_disable_clocks(host, 1); | ||
| 275 | #endif | ||
| 181 | mmc_request_done(host->mmc, mrq); | 276 | mmc_request_done(host->mmc, mrq); |
| 182 | return; | 277 | return; |
| 183 | } else | 278 | } else |
| @@ -218,6 +313,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 218 | host->dma.sg = data->sg; | 313 | host->dma.sg = data->sg; |
| 219 | host->dma.num_ents = data->sg_len; | 314 | host->dma.num_ents = data->sg_len; |
| 220 | 315 | ||
| 316 | BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ | ||
| 317 | |||
| 221 | nc = host->dma.nc; | 318 | nc = host->dma.nc; |
| 222 | 319 | ||
| 223 | switch (host->pdev_id) { | 320 | switch (host->pdev_id) { |
| @@ -246,22 +343,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 246 | 343 | ||
| 247 | host->curr.user_pages = 0; | 344 | host->curr.user_pages = 0; |
| 248 | 345 | ||
| 249 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
| 250 | host->dma.num_ents, host->dma.dir); | ||
| 251 | |||
| 252 | if (n != host->dma.num_ents) { | ||
| 253 | pr_err("%s: Unable to map in all sg elements\n", | ||
| 254 | mmc_hostname(host->mmc)); | ||
| 255 | host->dma.sg = NULL; | ||
| 256 | host->dma.num_ents = 0; | ||
| 257 | return -ENOMEM; | ||
| 258 | } | ||
| 259 | |||
| 260 | box = &nc->cmd[0]; | 346 | box = &nc->cmd[0]; |
| 261 | for (i = 0; i < host->dma.num_ents; i++) { | 347 | for (i = 0; i < host->dma.num_ents; i++) { |
| 262 | box->cmd = CMD_MODE_BOX; | 348 | box->cmd = CMD_MODE_BOX; |
| 263 | 349 | ||
| 264 | if (i == (host->dma.num_ents - 1)) | 350 | /* Initialize sg dma address */ |
| 351 | sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) | ||
| 352 | + sg->offset; | ||
| 353 | |||
| 354 | if (i == (host->dma.num_ents - 1)) | ||
| 265 | box->cmd |= CMD_LC; | 355 | box->cmd |= CMD_LC; |
| 266 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? | 356 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? |
| 267 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : | 357 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : |
| @@ -300,15 +390,70 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 300 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); | 390 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); |
| 301 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; | 391 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; |
| 302 | 392 | ||
| 393 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
| 394 | host->dma.num_ents, host->dma.dir); | ||
| 395 | /* dsb inside dma_map_sg will write nc out to mem as well */ | ||
| 396 | |||
| 397 | if (n != host->dma.num_ents) { | ||
| 398 | printk(KERN_ERR "%s: Unable to map in all sg elements\n", | ||
| 399 | mmc_hostname(host->mmc)); | ||
| 400 | host->dma.sg = NULL; | ||
| 401 | host->dma.num_ents = 0; | ||
| 402 | return -ENOMEM; | ||
| 403 | } | ||
| 404 | |||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | static int | ||
| 409 | snoop_cccr_abort(struct mmc_command *cmd) | ||
| 410 | { | ||
| 411 | if ((cmd->opcode == 52) && | ||
| 412 | (cmd->arg & 0x80000000) && | ||
| 413 | (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) | ||
| 414 | return 1; | ||
| 303 | return 0; | 415 | return 0; |
| 304 | } | 416 | } |
| 305 | 417 | ||
| 306 | static void | 418 | static void |
| 307 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | 419 | msmsdcc_start_command_deferred(struct msmsdcc_host *host, |
| 420 | struct mmc_command *cmd, u32 *c) | ||
| 421 | { | ||
| 422 | *c |= (cmd->opcode | MCI_CPSM_ENABLE); | ||
| 423 | |||
| 424 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
| 425 | if (cmd->flags & MMC_RSP_136) | ||
| 426 | *c |= MCI_CPSM_LONGRSP; | ||
| 427 | *c |= MCI_CPSM_RESPONSE; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (/*interrupt*/0) | ||
| 431 | *c |= MCI_CPSM_INTERRUPT; | ||
| 432 | |||
| 433 | if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || | ||
| 434 | ((cmd->opcode == 24) || (cmd->opcode == 25))) || | ||
| 435 | (cmd->opcode == 53)) | ||
| 436 | *c |= MCI_CSPM_DATCMD; | ||
| 437 | |||
| 438 | if (cmd == cmd->mrq->stop) | ||
| 439 | *c |= MCI_CSPM_MCIABORT; | ||
| 440 | |||
| 441 | if (snoop_cccr_abort(cmd)) | ||
| 442 | *c |= MCI_CSPM_MCIABORT; | ||
| 443 | |||
| 444 | if (host->curr.cmd != NULL) { | ||
| 445 | printk(KERN_ERR "%s: Overlapping command requests\n", | ||
| 446 | mmc_hostname(host->mmc)); | ||
| 447 | } | ||
| 448 | host->curr.cmd = cmd; | ||
| 449 | } | ||
| 450 | |||
| 451 | static void | ||
| 452 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, | ||
| 453 | struct mmc_command *cmd, u32 c) | ||
| 308 | { | 454 | { |
| 309 | unsigned int datactrl, timeout; | 455 | unsigned int datactrl, timeout; |
| 310 | unsigned long long clks; | 456 | unsigned long long clks; |
| 311 | void __iomem *base = host->base; | ||
| 312 | unsigned int pio_irqmask = 0; | 457 | unsigned int pio_irqmask = 0; |
| 313 | 458 | ||
| 314 | host->curr.data = data; | 459 | host->curr.data = data; |
| @@ -320,13 +465,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 320 | 465 | ||
| 321 | memset(&host->pio, 0, sizeof(host->pio)); | 466 | memset(&host->pio, 0, sizeof(host->pio)); |
| 322 | 467 | ||
| 323 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; | ||
| 324 | do_div(clks, NSEC_PER_SEC); | ||
| 325 | timeout = data->timeout_clks + (unsigned int)clks; | ||
| 326 | writel(timeout, base + MMCIDATATIMER); | ||
| 327 | |||
| 328 | writel(host->curr.xfer_size, base + MMCIDATALENGTH); | ||
| 329 | |||
| 330 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); | 468 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); |
| 331 | 469 | ||
| 332 | if (!msmsdcc_config_dma(host, data)) | 470 | if (!msmsdcc_config_dma(host, data)) |
| @@ -347,47 +485,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 347 | if (data->flags & MMC_DATA_READ) | 485 | if (data->flags & MMC_DATA_READ) |
| 348 | datactrl |= MCI_DPSM_DIRECTION; | 486 | datactrl |= MCI_DPSM_DIRECTION; |
| 349 | 487 | ||
| 350 | writel(pio_irqmask, base + MMCIMASK1); | 488 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; |
| 351 | writel(datactrl, base + MMCIDATACTRL); | 489 | do_div(clks, NSEC_PER_SEC); |
| 490 | timeout = data->timeout_clks + (unsigned int)clks*2 ; | ||
| 352 | 491 | ||
| 353 | if (datactrl & MCI_DPSM_DMAENABLE) { | 492 | if (datactrl & MCI_DPSM_DMAENABLE) { |
| 493 | /* Save parameters for the exec function */ | ||
| 494 | host->cmd_timeout = timeout; | ||
| 495 | host->cmd_pio_irqmask = pio_irqmask; | ||
| 496 | host->cmd_datactrl = datactrl; | ||
| 497 | host->cmd_cmd = cmd; | ||
| 498 | |||
| 499 | host->dma.hdr.execute_func = msmsdcc_dma_exec_func; | ||
| 500 | host->dma.hdr.data = (void *)host; | ||
| 354 | host->dma.busy = 1; | 501 | host->dma.busy = 1; |
| 502 | |||
| 503 | if (cmd) { | ||
| 504 | msmsdcc_start_command_deferred(host, cmd, &c); | ||
| 505 | host->cmd_c = c; | ||
| 506 | } | ||
| 355 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); | 507 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); |
| 508 | } else { | ||
| 509 | msmsdcc_writel(host, timeout, MMCIDATATIMER); | ||
| 510 | |||
| 511 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); | ||
| 512 | |||
| 513 | msmsdcc_writel(host, pio_irqmask, MMCIMASK1); | ||
| 514 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); | ||
| 515 | |||
| 516 | if (cmd) { | ||
| 517 | /* Daisy-chain the command if requested */ | ||
| 518 | msmsdcc_start_command(host, cmd, c); | ||
| 519 | } | ||
| 356 | } | 520 | } |
| 357 | } | 521 | } |
| 358 | 522 | ||
| 359 | static void | 523 | static void |
| 360 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) | 524 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) |
| 361 | { | 525 | { |
| 362 | void __iomem *base = host->base; | ||
| 363 | |||
| 364 | if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { | ||
| 365 | writel(0, base + MMCICOMMAND); | ||
| 366 | udelay(2 + ((5 * 1000000) / host->clk_rate)); | ||
| 367 | } | ||
| 368 | |||
| 369 | c |= cmd->opcode | MCI_CPSM_ENABLE; | ||
| 370 | |||
| 371 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
| 372 | if (cmd->flags & MMC_RSP_136) | ||
| 373 | c |= MCI_CPSM_LONGRSP; | ||
| 374 | c |= MCI_CPSM_RESPONSE; | ||
| 375 | } | ||
| 376 | |||
| 377 | if (cmd->opcode == 17 || cmd->opcode == 18 || | ||
| 378 | cmd->opcode == 24 || cmd->opcode == 25 || | ||
| 379 | cmd->opcode == 53) | ||
| 380 | c |= MCI_CSPM_DATCMD; | ||
| 381 | |||
| 382 | if (cmd == cmd->mrq->stop) | 526 | if (cmd == cmd->mrq->stop) |
| 383 | c |= MCI_CSPM_MCIABORT; | 527 | c |= MCI_CSPM_MCIABORT; |
| 384 | 528 | ||
| 385 | host->curr.cmd = cmd; | ||
| 386 | |||
| 387 | host->stats.cmds++; | 529 | host->stats.cmds++; |
| 388 | 530 | ||
| 389 | writel(cmd->arg, base + MMCIARGUMENT); | 531 | msmsdcc_start_command_deferred(host, cmd, &c); |
| 390 | writel(c, base + MMCICOMMAND); | 532 | msmsdcc_start_command_exec(host, cmd->arg, c); |
| 391 | } | 533 | } |
| 392 | 534 | ||
| 393 | static void | 535 | static void |
| @@ -421,13 +563,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, | |||
| 421 | static int | 563 | static int |
| 422 | msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) | 564 | msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) |
| 423 | { | 565 | { |
| 424 | void __iomem *base = host->base; | ||
| 425 | uint32_t *ptr = (uint32_t *) buffer; | 566 | uint32_t *ptr = (uint32_t *) buffer; |
| 426 | int count = 0; | 567 | int count = 0; |
| 427 | 568 | ||
| 428 | while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { | 569 | while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { |
| 429 | 570 | *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); | |
| 430 | *ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE)); | ||
| 431 | ptr++; | 571 | ptr++; |
| 432 | count += sizeof(uint32_t); | 572 | count += sizeof(uint32_t); |
| 433 | 573 | ||
| @@ -459,7 +599,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, | |||
| 459 | if (remain == 0) | 599 | if (remain == 0) |
| 460 | break; | 600 | break; |
| 461 | 601 | ||
| 462 | status = readl(base + MMCISTATUS); | 602 | status = msmsdcc_readl(host, MMCISTATUS); |
| 463 | } while (status & MCI_TXFIFOHALFEMPTY); | 603 | } while (status & MCI_TXFIFOHALFEMPTY); |
| 464 | 604 | ||
| 465 | return ptr - buffer; | 605 | return ptr - buffer; |
| @@ -469,7 +609,7 @@ static int | |||
| 469 | msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) | 609 | msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) |
| 470 | { | 610 | { |
| 471 | while (maxspin) { | 611 | while (maxspin) { |
| 472 | if ((readl(host->base + MMCISTATUS) & mask)) | 612 | if ((msmsdcc_readl(host, MMCISTATUS) & mask)) |
| 473 | return 0; | 613 | return 0; |
| 474 | udelay(1); | 614 | udelay(1); |
| 475 | --maxspin; | 615 | --maxspin; |
| @@ -477,14 +617,13 @@ msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) | |||
| 477 | return -ETIMEDOUT; | 617 | return -ETIMEDOUT; |
| 478 | } | 618 | } |
| 479 | 619 | ||
| 480 | static int | 620 | static irqreturn_t |
| 481 | msmsdcc_pio_irq(int irq, void *dev_id) | 621 | msmsdcc_pio_irq(int irq, void *dev_id) |
| 482 | { | 622 | { |
| 483 | struct msmsdcc_host *host = dev_id; | 623 | struct msmsdcc_host *host = dev_id; |
| 484 | void __iomem *base = host->base; | ||
| 485 | uint32_t status; | 624 | uint32_t status; |
| 486 | 625 | ||
| 487 | status = readl(base + MMCISTATUS); | 626 | status = msmsdcc_readl(host, MMCISTATUS); |
| 488 | 627 | ||
| 489 | do { | 628 | do { |
| 490 | unsigned long flags; | 629 | unsigned long flags; |
| @@ -539,14 +678,14 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
| 539 | host->pio.sg_off = 0; | 678 | host->pio.sg_off = 0; |
| 540 | } | 679 | } |
| 541 | 680 | ||
| 542 | status = readl(base + MMCISTATUS); | 681 | status = msmsdcc_readl(host, MMCISTATUS); |
| 543 | } while (1); | 682 | } while (1); |
| 544 | 683 | ||
| 545 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) | 684 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) |
| 546 | writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); | 685 | msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); |
| 547 | 686 | ||
| 548 | if (!host->curr.xfer_remain) | 687 | if (!host->curr.xfer_remain) |
| 549 | writel(0, base + MMCIMASK1); | 688 | msmsdcc_writel(host, 0, MMCIMASK1); |
| 550 | 689 | ||
| 551 | return IRQ_HANDLED; | 690 | return IRQ_HANDLED; |
| 552 | } | 691 | } |
| @@ -554,15 +693,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
| 554 | static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | 693 | static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) |
| 555 | { | 694 | { |
| 556 | struct mmc_command *cmd = host->curr.cmd; | 695 | struct mmc_command *cmd = host->curr.cmd; |
| 557 | void __iomem *base = host->base; | ||
| 558 | 696 | ||
| 559 | host->curr.cmd = NULL; | 697 | host->curr.cmd = NULL; |
| 560 | cmd->resp[0] = readl(base + MMCIRESPONSE0); | 698 | cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); |
| 561 | cmd->resp[1] = readl(base + MMCIRESPONSE1); | 699 | cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); |
| 562 | cmd->resp[2] = readl(base + MMCIRESPONSE2); | 700 | cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); |
| 563 | cmd->resp[3] = readl(base + MMCIRESPONSE3); | 701 | cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); |
| 564 | 702 | ||
| 565 | del_timer(&host->command_timer); | ||
| 566 | if (status & MCI_CMDTIMEOUT) { | 703 | if (status & MCI_CMDTIMEOUT) { |
| 567 | cmd->error = -ETIMEDOUT; | 704 | cmd->error = -ETIMEDOUT; |
| 568 | } else if (status & MCI_CMDCRCFAIL && | 705 | } else if (status & MCI_CMDCRCFAIL && |
| @@ -580,8 +717,10 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | |||
| 580 | msmsdcc_request_end(host, cmd->mrq); | 717 | msmsdcc_request_end(host, cmd->mrq); |
| 581 | } else /* host->data == NULL */ | 718 | } else /* host->data == NULL */ |
| 582 | msmsdcc_request_end(host, cmd->mrq); | 719 | msmsdcc_request_end(host, cmd->mrq); |
| 583 | } else if (!(cmd->data->flags & MMC_DATA_READ)) | 720 | } else if (cmd->data) |
| 584 | msmsdcc_start_data(host, cmd->data); | 721 | if (!(cmd->data->flags & MMC_DATA_READ)) |
| 722 | msmsdcc_start_data(host, cmd->data, | ||
| 723 | NULL, 0); | ||
| 585 | } | 724 | } |
| 586 | 725 | ||
| 587 | static void | 726 | static void |
| @@ -590,6 +729,11 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | |||
| 590 | { | 729 | { |
| 591 | struct mmc_data *data = host->curr.data; | 730 | struct mmc_data *data = host->curr.data; |
| 592 | 731 | ||
| 732 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | ||
| 733 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
| 734 | msmsdcc_do_cmdirq(host, status); | ||
| 735 | } | ||
| 736 | |||
| 593 | if (!data) | 737 | if (!data) |
| 594 | return; | 738 | return; |
| 595 | 739 | ||
| @@ -602,7 +746,8 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | |||
| 602 | msm_dmov_stop_cmd(host->dma.channel, | 746 | msm_dmov_stop_cmd(host->dma.channel, |
| 603 | &host->dma.hdr, 0); | 747 | &host->dma.hdr, 0); |
| 604 | else { | 748 | else { |
| 605 | msmsdcc_stop_data(host); | 749 | if (host->curr.data) |
| 750 | msmsdcc_stop_data(host); | ||
| 606 | if (!data->stop) | 751 | if (!data->stop) |
| 607 | msmsdcc_request_end(host, data->mrq); | 752 | msmsdcc_request_end(host, data->mrq); |
| 608 | else | 753 | else |
| @@ -657,17 +802,18 @@ msmsdcc_irq(int irq, void *dev_id) | |||
| 657 | spin_lock(&host->lock); | 802 | spin_lock(&host->lock); |
| 658 | 803 | ||
| 659 | do { | 804 | do { |
| 660 | status = readl(base + MMCISTATUS); | 805 | status = msmsdcc_readl(host, MMCISTATUS); |
| 806 | status &= (msmsdcc_readl(host, MMCIMASK0) | | ||
| 807 | MCI_DATABLOCKENDMASK); | ||
| 808 | msmsdcc_writel(host, status, MMCICLEAR); | ||
| 661 | 809 | ||
| 662 | status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); | 810 | if (status & MCI_SDIOINTR) |
| 663 | writel(status, base + MMCICLEAR); | 811 | status &= ~MCI_SDIOINTR; |
| 664 | 812 | ||
| 665 | msmsdcc_handle_irq_data(host, status, base); | 813 | if (!status) |
| 814 | break; | ||
| 666 | 815 | ||
| 667 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | 816 | msmsdcc_handle_irq_data(host, status, base); |
| 668 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
| 669 | msmsdcc_do_cmdirq(host, status); | ||
| 670 | } | ||
| 671 | 817 | ||
| 672 | if (status & MCI_SDIOINTOPER) { | 818 | if (status & MCI_SDIOINTOPER) { |
| 673 | cardint = 1; | 819 | cardint = 1; |
| @@ -714,24 +860,27 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 714 | return; | 860 | return; |
| 715 | } | 861 | } |
| 716 | 862 | ||
| 863 | msmsdcc_enable_clocks(host); | ||
| 864 | |||
| 717 | host->curr.mrq = mrq; | 865 | host->curr.mrq = mrq; |
| 718 | 866 | ||
| 719 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) | 867 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) |
| 720 | msmsdcc_start_data(host, mrq->data); | 868 | /* Queue/read data, daisy-chain command when data starts */ |
| 721 | 869 | msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); | |
| 722 | msmsdcc_start_command(host, mrq->cmd, 0); | 870 | else |
| 871 | msmsdcc_start_command(host, mrq->cmd, 0); | ||
| 723 | 872 | ||
| 724 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, | 873 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, |
| 725 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, | 874 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, |
| 726 | CMD_SPINMAX)) { | 875 | CMD_SPINMAX)) { |
| 727 | uint32_t status = readl(host->base + MMCISTATUS); | 876 | uint32_t status = msmsdcc_readl(host, MMCISTATUS); |
| 728 | msmsdcc_do_cmdirq(host, status); | 877 | msmsdcc_do_cmdirq(host, status); |
| 729 | writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, | 878 | msmsdcc_writel(host, |
| 730 | host->base + MMCICLEAR); | 879 | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, |
| 880 | MMCICLEAR); | ||
| 731 | host->stats.cmdpoll_hits++; | 881 | host->stats.cmdpoll_hits++; |
| 732 | } else { | 882 | } else { |
| 733 | host->stats.cmdpoll_misses++; | 883 | host->stats.cmdpoll_misses++; |
| 734 | mod_timer(&host->command_timer, jiffies + HZ); | ||
| 735 | } | 884 | } |
| 736 | spin_unlock_irqrestore(&host->lock, flags); | 885 | spin_unlock_irqrestore(&host->lock, flags); |
| 737 | } | 886 | } |
| @@ -742,14 +891,13 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 742 | struct msmsdcc_host *host = mmc_priv(mmc); | 891 | struct msmsdcc_host *host = mmc_priv(mmc); |
| 743 | u32 clk = 0, pwr = 0; | 892 | u32 clk = 0, pwr = 0; |
| 744 | int rc; | 893 | int rc; |
| 894 | unsigned long flags; | ||
| 745 | 895 | ||
| 746 | if (ios->clock) { | 896 | spin_lock_irqsave(&host->lock, flags); |
| 747 | 897 | ||
| 748 | if (!host->clks_on) { | 898 | msmsdcc_enable_clocks(host); |
| 749 | clk_enable(host->pclk); | 899 | |
| 750 | clk_enable(host->clk); | 900 | if (ios->clock) { |
| 751 | host->clks_on = 1; | ||
| 752 | } | ||
| 753 | if (ios->clock != host->clk_rate) { | 901 | if (ios->clock != host->clk_rate) { |
| 754 | rc = clk_set_rate(host->clk, ios->clock); | 902 | rc = clk_set_rate(host->clk, ios->clock); |
| 755 | if (rc < 0) | 903 | if (rc < 0) |
| @@ -787,18 +935,16 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 787 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) | 935 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) |
| 788 | pwr |= MCI_OD; | 936 | pwr |= MCI_OD; |
| 789 | 937 | ||
| 790 | writel(clk, host->base + MMCICLOCK); | 938 | msmsdcc_writel(host, clk, MMCICLOCK); |
| 791 | 939 | ||
| 792 | if (host->pwr != pwr) { | 940 | if (host->pwr != pwr) { |
| 793 | host->pwr = pwr; | 941 | host->pwr = pwr; |
| 794 | writel(pwr, host->base + MMCIPOWER); | 942 | msmsdcc_writel(host, pwr, MMCIPOWER); |
| 795 | } | ||
| 796 | |||
| 797 | if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { | ||
| 798 | clk_disable(host->clk); | ||
| 799 | clk_disable(host->pclk); | ||
| 800 | host->clks_on = 0; | ||
| 801 | } | 943 | } |
| 944 | #if BUSCLK_PWRSAVE | ||
| 945 | msmsdcc_disable_clocks(host, 1); | ||
| 946 | #endif | ||
| 947 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 802 | } | 948 | } |
| 803 | 949 | ||
| 804 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | 950 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) |
| @@ -809,13 +955,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
| 809 | 955 | ||
| 810 | spin_lock_irqsave(&host->lock, flags); | 956 | spin_lock_irqsave(&host->lock, flags); |
| 811 | if (msmsdcc_sdioirq == 1) { | 957 | if (msmsdcc_sdioirq == 1) { |
| 812 | status = readl(host->base + MMCIMASK0); | 958 | status = msmsdcc_readl(host, MMCIMASK0); |
| 813 | if (enable) | 959 | if (enable) |
| 814 | status |= MCI_SDIOINTOPERMASK; | 960 | status |= MCI_SDIOINTOPERMASK; |
| 815 | else | 961 | else |
| 816 | status &= ~MCI_SDIOINTOPERMASK; | 962 | status &= ~MCI_SDIOINTOPERMASK; |
| 817 | host->saved_irq0mask = status; | 963 | host->saved_irq0mask = status; |
| 818 | writel(status, host->base + MMCIMASK0); | 964 | msmsdcc_writel(host, status, MMCIMASK0); |
| 819 | } | 965 | } |
| 820 | spin_unlock_irqrestore(&host->lock, flags); | 966 | spin_unlock_irqrestore(&host->lock, flags); |
| 821 | } | 967 | } |
| @@ -875,42 +1021,13 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) | |||
| 875 | msmsdcc_check_status((unsigned long) host); | 1021 | msmsdcc_check_status((unsigned long) host); |
| 876 | } | 1022 | } |
| 877 | 1023 | ||
| 878 | /* | ||
| 879 | * called when a command expires. | ||
| 880 | * Dump some debugging, and then error | ||
| 881 | * out the transaction. | ||
| 882 | */ | ||
| 883 | static void | 1024 | static void |
| 884 | msmsdcc_command_expired(unsigned long _data) | 1025 | msmsdcc_busclk_expired(unsigned long _data) |
| 885 | { | 1026 | { |
| 886 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; | 1027 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; |
| 887 | struct mmc_request *mrq; | ||
| 888 | unsigned long flags; | ||
| 889 | |||
| 890 | spin_lock_irqsave(&host->lock, flags); | ||
| 891 | mrq = host->curr.mrq; | ||
| 892 | |||
| 893 | if (!mrq) { | ||
| 894 | pr_info("%s: Command expiry misfire\n", | ||
| 895 | mmc_hostname(host->mmc)); | ||
| 896 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 897 | return; | ||
| 898 | } | ||
| 899 | |||
| 900 | pr_err("%s: Command timeout (%p %p %p %p)\n", | ||
| 901 | mmc_hostname(host->mmc), mrq, mrq->cmd, | ||
| 902 | mrq->data, host->dma.sg); | ||
| 903 | |||
| 904 | mrq->cmd->error = -ETIMEDOUT; | ||
| 905 | msmsdcc_stop_data(host); | ||
| 906 | 1028 | ||
| 907 | writel(0, host->base + MMCICOMMAND); | 1029 | if (host->clks_on) |
| 908 | 1030 | msmsdcc_disable_clocks(host, 0); | |
| 909 | host->curr.mrq = NULL; | ||
| 910 | host->curr.cmd = NULL; | ||
| 911 | |||
| 912 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 913 | mmc_request_done(host->mmc, mrq); | ||
| 914 | } | 1031 | } |
| 915 | 1032 | ||
| 916 | static int | 1033 | static int |
| @@ -1012,6 +1129,7 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1012 | host->pdev_id = pdev->id; | 1129 | host->pdev_id = pdev->id; |
| 1013 | host->plat = plat; | 1130 | host->plat = plat; |
| 1014 | host->mmc = mmc; | 1131 | host->mmc = mmc; |
| 1132 | host->curr.cmd = NULL; | ||
| 1015 | 1133 | ||
| 1016 | host->cmdpoll = 1; | 1134 | host->cmdpoll = 1; |
| 1017 | 1135 | ||
| @@ -1027,36 +1145,35 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1027 | host->dmares = dmares; | 1145 | host->dmares = dmares; |
| 1028 | spin_lock_init(&host->lock); | 1146 | spin_lock_init(&host->lock); |
| 1029 | 1147 | ||
| 1148 | #ifdef CONFIG_MMC_EMBEDDED_SDIO | ||
| 1149 | if (plat->embedded_sdio) | ||
| 1150 | mmc_set_embedded_sdio_data(mmc, | ||
| 1151 | &plat->embedded_sdio->cis, | ||
| 1152 | &plat->embedded_sdio->cccr, | ||
| 1153 | plat->embedded_sdio->funcs, | ||
| 1154 | plat->embedded_sdio->num_funcs); | ||
| 1155 | #endif | ||
| 1156 | |||
| 1030 | /* | 1157 | /* |
| 1031 | * Setup DMA | 1158 | * Setup DMA |
| 1032 | */ | 1159 | */ |
| 1033 | msmsdcc_init_dma(host); | 1160 | msmsdcc_init_dma(host); |
| 1034 | 1161 | ||
| 1035 | /* | 1162 | /* Get our clocks */ |
| 1036 | * Setup main peripheral bus clock | ||
| 1037 | */ | ||
| 1038 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); | 1163 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); |
| 1039 | if (IS_ERR(host->pclk)) { | 1164 | if (IS_ERR(host->pclk)) { |
| 1040 | ret = PTR_ERR(host->pclk); | 1165 | ret = PTR_ERR(host->pclk); |
| 1041 | goto host_free; | 1166 | goto host_free; |
| 1042 | } | 1167 | } |
| 1043 | 1168 | ||
| 1044 | ret = clk_enable(host->pclk); | ||
| 1045 | if (ret) | ||
| 1046 | goto pclk_put; | ||
| 1047 | |||
| 1048 | host->pclk_rate = clk_get_rate(host->pclk); | ||
| 1049 | |||
| 1050 | /* | ||
| 1051 | * Setup SDC MMC clock | ||
| 1052 | */ | ||
| 1053 | host->clk = clk_get(&pdev->dev, "sdc_clk"); | 1169 | host->clk = clk_get(&pdev->dev, "sdc_clk"); |
| 1054 | if (IS_ERR(host->clk)) { | 1170 | if (IS_ERR(host->clk)) { |
| 1055 | ret = PTR_ERR(host->clk); | 1171 | ret = PTR_ERR(host->clk); |
| 1056 | goto pclk_disable; | 1172 | goto pclk_put; |
| 1057 | } | 1173 | } |
| 1058 | 1174 | ||
| 1059 | ret = clk_enable(host->clk); | 1175 | /* Enable clocks */ |
| 1176 | ret = msmsdcc_enable_clocks(host); | ||
| 1060 | if (ret) | 1177 | if (ret) |
| 1061 | goto clk_put; | 1178 | goto clk_put; |
| 1062 | 1179 | ||
| @@ -1066,10 +1183,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1066 | goto clk_disable; | 1183 | goto clk_disable; |
| 1067 | } | 1184 | } |
| 1068 | 1185 | ||
| 1186 | host->pclk_rate = clk_get_rate(host->pclk); | ||
| 1069 | host->clk_rate = clk_get_rate(host->clk); | 1187 | host->clk_rate = clk_get_rate(host->clk); |
| 1070 | 1188 | ||
| 1071 | host->clks_on = 1; | ||
| 1072 | |||
| 1073 | /* | 1189 | /* |
| 1074 | * Setup MMC host structure | 1190 | * Setup MMC host structure |
| 1075 | */ | 1191 | */ |
| @@ -1092,10 +1208,10 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1092 | mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ | 1208 | mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ |
| 1093 | mmc->max_seg_size = mmc->max_req_size; | 1209 | mmc->max_seg_size = mmc->max_req_size; |
| 1094 | 1210 | ||
| 1095 | writel(0, host->base + MMCIMASK0); | 1211 | msmsdcc_writel(host, 0, MMCIMASK0); |
| 1096 | writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ | 1212 | msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); |
| 1097 | 1213 | ||
| 1098 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); | 1214 | msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); |
| 1099 | host->saved_irq0mask = MCI_IRQENABLE; | 1215 | host->saved_irq0mask = MCI_IRQENABLE; |
| 1100 | 1216 | ||
| 1101 | /* | 1217 | /* |
| @@ -1137,13 +1253,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1137 | host->eject = !host->oldstat; | 1253 | host->eject = !host->oldstat; |
| 1138 | } | 1254 | } |
| 1139 | 1255 | ||
| 1140 | /* | 1256 | init_timer(&host->busclk_timer); |
| 1141 | * Setup a command timer. We currently need this due to | 1257 | host->busclk_timer.data = (unsigned long) host; |
| 1142 | * some 'strange' timeout / error handling situations. | 1258 | host->busclk_timer.function = msmsdcc_busclk_expired; |
| 1143 | */ | ||
| 1144 | init_timer(&host->command_timer); | ||
| 1145 | host->command_timer.data = (unsigned long) host; | ||
| 1146 | host->command_timer.function = msmsdcc_command_expired; | ||
| 1147 | 1259 | ||
| 1148 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, | 1260 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, |
| 1149 | DRIVER_NAME " (cmd)", host); | 1261 | DRIVER_NAME " (cmd)", host); |
| @@ -1181,6 +1293,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1181 | if (host->timer.function) | 1293 | if (host->timer.function) |
| 1182 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); | 1294 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); |
| 1183 | 1295 | ||
| 1296 | #if BUSCLK_PWRSAVE | ||
| 1297 | msmsdcc_disable_clocks(host, 1); | ||
| 1298 | #endif | ||
| 1184 | return 0; | 1299 | return 0; |
| 1185 | cmd_irq_free: | 1300 | cmd_irq_free: |
| 1186 | free_irq(cmd_irqres->start, host); | 1301 | free_irq(cmd_irqres->start, host); |
| @@ -1188,11 +1303,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 1188 | if (host->stat_irq) | 1303 | if (host->stat_irq) |
| 1189 | free_irq(host->stat_irq, host); | 1304 | free_irq(host->stat_irq, host); |
| 1190 | clk_disable: | 1305 | clk_disable: |
| 1191 | clk_disable(host->clk); | 1306 | msmsdcc_disable_clocks(host, 0); |
| 1192 | clk_put: | 1307 | clk_put: |
| 1193 | clk_put(host->clk); | 1308 | clk_put(host->clk); |
| 1194 | pclk_disable: | ||
| 1195 | clk_disable(host->pclk); | ||
| 1196 | pclk_put: | 1309 | pclk_put: |
| 1197 | clk_put(host->pclk); | 1310 | clk_put(host->pclk); |
| 1198 | host_free: | 1311 | host_free: |
| @@ -1215,15 +1328,10 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
| 1215 | 1328 | ||
| 1216 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) | 1329 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) |
| 1217 | rc = mmc_suspend_host(mmc, state); | 1330 | rc = mmc_suspend_host(mmc, state); |
| 1218 | if (!rc) { | 1331 | if (!rc) |
| 1219 | writel(0, host->base + MMCIMASK0); | 1332 | msmsdcc_writel(host, 0, MMCIMASK0); |
| 1220 | 1333 | if (host->clks_on) | |
| 1221 | if (host->clks_on) { | 1334 | msmsdcc_disable_clocks(host, 0); |
| 1222 | clk_disable(host->clk); | ||
| 1223 | clk_disable(host->pclk); | ||
| 1224 | host->clks_on = 0; | ||
| 1225 | } | ||
| 1226 | } | ||
| 1227 | } | 1335 | } |
| 1228 | return rc; | 1336 | return rc; |
| 1229 | } | 1337 | } |
| @@ -1232,27 +1340,21 @@ static int | |||
| 1232 | msmsdcc_resume(struct platform_device *dev) | 1340 | msmsdcc_resume(struct platform_device *dev) |
| 1233 | { | 1341 | { |
| 1234 | struct mmc_host *mmc = mmc_get_drvdata(dev); | 1342 | struct mmc_host *mmc = mmc_get_drvdata(dev); |
| 1235 | unsigned long flags; | ||
| 1236 | 1343 | ||
| 1237 | if (mmc) { | 1344 | if (mmc) { |
| 1238 | struct msmsdcc_host *host = mmc_priv(mmc); | 1345 | struct msmsdcc_host *host = mmc_priv(mmc); |
| 1239 | 1346 | ||
| 1240 | spin_lock_irqsave(&host->lock, flags); | 1347 | msmsdcc_enable_clocks(host); |
| 1241 | 1348 | ||
| 1242 | if (!host->clks_on) { | 1349 | msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); |
| 1243 | clk_enable(host->pclk); | ||
| 1244 | clk_enable(host->clk); | ||
| 1245 | host->clks_on = 1; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | writel(host->saved_irq0mask, host->base + MMCIMASK0); | ||
| 1249 | |||
| 1250 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 1251 | 1350 | ||
| 1252 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) | 1351 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) |
| 1253 | mmc_resume_host(mmc); | 1352 | mmc_resume_host(mmc); |
| 1254 | if (host->stat_irq) | 1353 | if (host->stat_irq) |
| 1255 | enable_irq(host->stat_irq); | 1354 | enable_irq(host->stat_irq); |
| 1355 | #if BUSCLK_PWRSAVE | ||
| 1356 | msmsdcc_disable_clocks(host, 1); | ||
| 1357 | #endif | ||
| 1256 | } | 1358 | } |
| 1257 | return 0; | 1359 | return 0; |
| 1258 | } | 1360 | } |
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 8c8448469811..da0039c9285e 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h | |||
| @@ -171,6 +171,7 @@ struct msmsdcc_dma_data { | |||
| 171 | int channel; | 171 | int channel; |
| 172 | struct msmsdcc_host *host; | 172 | struct msmsdcc_host *host; |
| 173 | int busy; /* Set if DM is busy */ | 173 | int busy; /* Set if DM is busy */ |
| 174 | int active; | ||
| 174 | }; | 175 | }; |
| 175 | 176 | ||
| 176 | struct msmsdcc_pio_data { | 177 | struct msmsdcc_pio_data { |
| @@ -213,7 +214,7 @@ struct msmsdcc_host { | |||
| 213 | struct clk *clk; /* main MMC bus clock */ | 214 | struct clk *clk; /* main MMC bus clock */ |
| 214 | struct clk *pclk; /* SDCC peripheral bus clock */ | 215 | struct clk *pclk; /* SDCC peripheral bus clock */ |
| 215 | unsigned int clks_on; /* set if clocks are enabled */ | 216 | unsigned int clks_on; /* set if clocks are enabled */ |
| 216 | struct timer_list command_timer; | 217 | struct timer_list busclk_timer; |
| 217 | 218 | ||
| 218 | unsigned int eject; /* eject state */ | 219 | unsigned int eject; /* eject state */ |
| 219 | 220 | ||
| @@ -233,6 +234,18 @@ struct msmsdcc_host { | |||
| 233 | struct msmsdcc_pio_data pio; | 234 | struct msmsdcc_pio_data pio; |
| 234 | int cmdpoll; | 235 | int cmdpoll; |
| 235 | struct msmsdcc_stats stats; | 236 | struct msmsdcc_stats stats; |
| 237 | |||
| 238 | #ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ | ||
| 239 | struct work_struct resume_task; | ||
| 240 | #endif | ||
| 241 | |||
| 242 | /* Command parameters */ | ||
| 243 | unsigned int cmd_timeout; | ||
| 244 | unsigned int cmd_pio_irqmask; | ||
| 245 | unsigned int cmd_datactrl; | ||
| 246 | struct mmc_command *cmd_cmd; | ||
| 247 | u32 cmd_c; | ||
| 248 | |||
| 236 | }; | 249 | }; |
| 237 | 250 | ||
| 238 | #endif | 251 | #endif |
