Lines Matching +full:pxa +full:- +full:mmc
1 // SPDX-License-Identifier: GPL-2.0+
3 * Freescale i.MX28 SSP MMC driver
9 * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
15 * Based vaguely on the pxa mmc code:
17 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
21 #include <mmc.h>
25 #include <asm/arch/imx-regs.h>
27 #include <asm/mach-imx/dma.h>
37 struct mmc_config cfg; /* mmc configuration */
45 struct mxs_ssp_regs *ssp_regs = priv->regs; in mxsmmc_cd()
47 if (priv->mmc_cd) in mxsmmc_cd()
48 return priv->mmc_cd(priv->id); in mxsmmc_cd()
50 return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT); in mxsmmc_cd()
55 struct mxs_ssp_regs *ssp_regs = priv->regs; in mxsmmc_send_cmd_pio()
59 uint32_t data_count = data->blocksize * data->blocks; in mxsmmc_send_cmd_pio()
61 if (data->flags & MMC_DATA_READ) { in mxsmmc_send_cmd_pio()
62 data_ptr = (uint32_t *)data->dest; in mxsmmc_send_cmd_pio()
63 while (data_count && --timeout) { in mxsmmc_send_cmd_pio()
64 reg = readl(&ssp_regs->hw_ssp_status); in mxsmmc_send_cmd_pio()
66 *data_ptr++ = readl(&ssp_regs->hw_ssp_data); in mxsmmc_send_cmd_pio()
67 data_count -= 4; in mxsmmc_send_cmd_pio()
73 data_ptr = (uint32_t *)data->src; in mxsmmc_send_cmd_pio()
75 while (data_count && --timeout) { in mxsmmc_send_cmd_pio()
76 reg = readl(&ssp_regs->hw_ssp_status); in mxsmmc_send_cmd_pio()
78 writel(*data_ptr++, &ssp_regs->hw_ssp_data); in mxsmmc_send_cmd_pio()
79 data_count -= 4; in mxsmmc_send_cmd_pio()
86 return timeout ? 0 : -ECOMM; in mxsmmc_send_cmd_pio()
91 uint32_t data_count = data->blocksize * data->blocks; in mxsmmc_send_cmd_dma()
93 struct mxs_dma_desc *desc = priv->desc; in mxsmmc_send_cmd_dma()
99 desc->address = (dma_addr_t)desc; in mxsmmc_send_cmd_dma()
101 if (data->flags & MMC_DATA_READ) { in mxsmmc_send_cmd_dma()
102 priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; in mxsmmc_send_cmd_dma()
103 addr = data->dest; in mxsmmc_send_cmd_dma()
106 priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; in mxsmmc_send_cmd_dma()
107 addr = (void *)data->src; in mxsmmc_send_cmd_dma()
113 priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer; in mxsmmc_send_cmd_dma()
115 priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | in mxsmmc_send_cmd_dma()
118 dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; in mxsmmc_send_cmd_dma()
119 mxs_dma_desc_append(dmach, priv->desc); in mxsmmc_send_cmd_dma()
122 return -ECOMM; in mxsmmc_send_cmd_dma()
131 * Sends a command out on the bus. Takes the mmc pointer,
135 mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) in mxsmmc_send_cmd() argument
137 struct mxsmmc_priv *priv = mmc->priv; in mxsmmc_send_cmd()
138 struct mxs_ssp_regs *ssp_regs = priv->regs; in mxsmmc_send_cmd()
144 debug("MMC%d: CMD%d\n", mmc->block_dev.devnum, cmd->cmdidx); in mxsmmc_send_cmd()
148 while (--timeout) { in mxsmmc_send_cmd()
150 reg = readl(&ssp_regs->hw_ssp_status); in mxsmmc_send_cmd()
159 printf("MMC%d: Bus busy timeout!\n", mmc->block_dev.devnum); in mxsmmc_send_cmd()
160 return -ETIMEDOUT; in mxsmmc_send_cmd()
165 printf("MMC%d: No card detected!\n", mmc->block_dev.devnum); in mxsmmc_send_cmd()
166 return -ENOMEDIUM; in mxsmmc_send_cmd()
170 ctrl0 = priv->buswidth; in mxsmmc_send_cmd()
173 if (!(cmd->resp_type & MMC_RSP_CRC)) in mxsmmc_send_cmd()
175 if (cmd->resp_type & MMC_RSP_PRESENT) /* Need to get response */ in mxsmmc_send_cmd()
177 if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */ in mxsmmc_send_cmd()
180 if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER)) in mxsmmc_send_cmd()
181 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr); in mxsmmc_send_cmd()
183 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set); in mxsmmc_send_cmd()
186 reg = readl(&ssp_regs->hw_ssp_cmd0); in mxsmmc_send_cmd()
188 reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET; in mxsmmc_send_cmd()
189 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) in mxsmmc_send_cmd()
191 writel(reg, &ssp_regs->hw_ssp_cmd0); in mxsmmc_send_cmd()
194 writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1); in mxsmmc_send_cmd()
199 if (data->flags & MMC_DATA_READ) { in mxsmmc_send_cmd()
201 } else if (priv->mmc_is_wp && in mxsmmc_send_cmd()
202 priv->mmc_is_wp(mmc->block_dev.devnum)) { in mxsmmc_send_cmd()
203 printf("MMC%d: Can not write a locked card!\n", in mxsmmc_send_cmd()
204 mmc->block_dev.devnum); in mxsmmc_send_cmd()
205 return -EOPNOTSUPP; in mxsmmc_send_cmd()
210 reg = data->blocksize * data->blocks; in mxsmmc_send_cmd()
214 clrsetbits_le32(&ssp_regs->hw_ssp_cmd0, in mxsmmc_send_cmd()
216 ((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) | in mxsmmc_send_cmd()
217 ((ffs(data->blocksize) - 1) << in mxsmmc_send_cmd()
220 writel(reg, &ssp_regs->hw_ssp_xfer_size); in mxsmmc_send_cmd()
222 reg = ((data->blocks - 1) << in mxsmmc_send_cmd()
224 ((ffs(data->blocksize) - 1) << in mxsmmc_send_cmd()
226 writel(reg, &ssp_regs->hw_ssp_block_size); in mxsmmc_send_cmd()
232 writel(ctrl0, &ssp_regs->hw_ssp_ctrl0); in mxsmmc_send_cmd()
236 while (--timeout) { in mxsmmc_send_cmd()
238 reg = readl(&ssp_regs->hw_ssp_status); in mxsmmc_send_cmd()
244 printf("MMC%d: Command %d busy\n", in mxsmmc_send_cmd()
245 mmc->block_dev.devnum, cmd->cmdidx); in mxsmmc_send_cmd()
246 return -ETIMEDOUT; in mxsmmc_send_cmd()
251 printf("MMC%d: Command %d timeout (status 0x%08x)\n", in mxsmmc_send_cmd()
252 mmc->block_dev.devnum, cmd->cmdidx, reg); in mxsmmc_send_cmd()
253 return -ETIMEDOUT; in mxsmmc_send_cmd()
258 printf("MMC%d: Command %d error (status 0x%08x)!\n", in mxsmmc_send_cmd()
259 mmc->block_dev.devnum, cmd->cmdidx, reg); in mxsmmc_send_cmd()
260 return -ECOMM; in mxsmmc_send_cmd()
264 if (cmd->resp_type & MMC_RSP_136) { in mxsmmc_send_cmd()
265 cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0); in mxsmmc_send_cmd()
266 cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1); in mxsmmc_send_cmd()
267 cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2); in mxsmmc_send_cmd()
268 cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3); in mxsmmc_send_cmd()
270 cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0); in mxsmmc_send_cmd()
276 if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) { in mxsmmc_send_cmd()
279 printf("MMC%d: Data timeout with command %d " in mxsmmc_send_cmd()
281 mmc->block_dev.devnum, cmd->cmdidx, reg); in mxsmmc_send_cmd()
287 printf("MMC%d: DMA transfer failed\n", in mxsmmc_send_cmd()
288 mmc->block_dev.devnum); in mxsmmc_send_cmd()
294 reg = readl(&ssp_regs->hw_ssp_status); in mxsmmc_send_cmd()
298 printf("MMC%d: Data error with command %d (status 0x%08x)!\n", in mxsmmc_send_cmd()
299 mmc->block_dev.devnum, cmd->cmdidx, reg); in mxsmmc_send_cmd()
300 return -ECOMM; in mxsmmc_send_cmd()
306 static int mxsmmc_set_ios(struct mmc *mmc) in mxsmmc_set_ios() argument
308 struct mxsmmc_priv *priv = mmc->priv; in mxsmmc_set_ios()
309 struct mxs_ssp_regs *ssp_regs = priv->regs; in mxsmmc_set_ios()
312 if (mmc->clock) in mxsmmc_set_ios()
313 mxs_set_ssp_busclock(priv->id, mmc->clock / 1000); in mxsmmc_set_ios()
315 switch (mmc->bus_width) { in mxsmmc_set_ios()
317 priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT; in mxsmmc_set_ios()
320 priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT; in mxsmmc_set_ios()
323 priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT; in mxsmmc_set_ios()
328 clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0, in mxsmmc_set_ios()
329 SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth); in mxsmmc_set_ios()
331 debug("MMC%d: Set %d bits bus width\n", in mxsmmc_set_ios()
332 mmc->block_dev.devnum, mmc->bus_width); in mxsmmc_set_ios()
337 static int mxsmmc_init(struct mmc *mmc) in mxsmmc_init() argument
339 struct mxsmmc_priv *priv = mmc->priv; in mxsmmc_init()
340 struct mxs_ssp_regs *ssp_regs = priv->regs; in mxsmmc_init()
343 mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); in mxsmmc_init()
345 /* Reconfigure the SSP block for MMC operation */ in mxsmmc_init()
355 &ssp_regs->hw_ssp_ctrl1_set); in mxsmmc_init()
358 mxs_set_ssp_busclock(priv->id, 400); in mxsmmc_init()
361 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set); in mxsmmc_init()
363 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr); in mxsmmc_init()
376 struct mmc *mmc = NULL; in mxsmmc_initialize() local
382 return -ENODEV; in mxsmmc_initialize()
386 return -ENOMEM; in mxsmmc_initialize()
388 priv->desc = mxs_dma_desc_alloc(); in mxsmmc_initialize()
389 if (!priv->desc) { in mxsmmc_initialize()
391 return -ENOMEM; in mxsmmc_initialize()
398 priv->mmc_is_wp = wp; in mxsmmc_initialize()
399 priv->mmc_cd = cd; in mxsmmc_initialize()
400 priv->id = id; in mxsmmc_initialize()
401 priv->regs = mxs_ssp_regs_by_bus(id); in mxsmmc_initialize()
403 priv->cfg.name = "MXS MMC"; in mxsmmc_initialize()
404 priv->cfg.ops = &mxsmmc_ops; in mxsmmc_initialize()
406 priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; in mxsmmc_initialize()
408 priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | in mxsmmc_initialize()
417 priv->cfg.f_min = 400000; in mxsmmc_initialize()
418 priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2; in mxsmmc_initialize()
419 priv->cfg.b_max = 0x20; in mxsmmc_initialize()
421 mmc = mmc_create(&priv->cfg, priv); in mxsmmc_initialize()
422 if (mmc == NULL) { in mxsmmc_initialize()
423 mxs_dma_desc_free(priv->desc); in mxsmmc_initialize()
425 return -ENOMEM; in mxsmmc_initialize()