15dbdb7daSHaojian Zhuang /*
25dbdb7daSHaojian Zhuang * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
35dbdb7daSHaojian Zhuang *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
55dbdb7daSHaojian Zhuang */
65dbdb7daSHaojian Zhuang
709d40e0eSAntonio Nino Diaz #include <assert.h>
809d40e0eSAntonio Nino Diaz #include <errno.h>
909d40e0eSAntonio Nino Diaz #include <string.h>
1009d40e0eSAntonio Nino Diaz
115dbdb7daSHaojian Zhuang #include <arch.h>
125dbdb7daSHaojian Zhuang #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
1509d40e0eSAntonio Nino Diaz #include <drivers/mmc.h>
1609d40e0eSAntonio Nino Diaz #include <drivers/synopsys/dw_mmc.h>
17*9264f087SJustin Chadwell #include <lib/utils_def.h>
1809d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
195dbdb7daSHaojian Zhuang
205dbdb7daSHaojian Zhuang #define DWMMC_CTRL (0x00)
215dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN (1 << 25)
225dbdb7daSHaojian Zhuang #define CTRL_DMA_EN (1 << 5)
235dbdb7daSHaojian Zhuang #define CTRL_INT_EN (1 << 4)
245dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET (1 << 2)
255dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET (1 << 1)
265dbdb7daSHaojian Zhuang #define CTRL_RESET (1 << 0)
275dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \
285dbdb7daSHaojian Zhuang CTRL_RESET)
295dbdb7daSHaojian Zhuang
305dbdb7daSHaojian Zhuang #define DWMMC_PWREN (0x04)
315dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV (0x08)
325dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC (0x0c)
335dbdb7daSHaojian Zhuang #define DWMMC_CLKENA (0x10)
345dbdb7daSHaojian Zhuang #define DWMMC_TMOUT (0x14)
355dbdb7daSHaojian Zhuang #define DWMMC_CTYPE (0x18)
365dbdb7daSHaojian Zhuang #define CTYPE_8BIT (1 << 16)
375dbdb7daSHaojian Zhuang #define CTYPE_4BIT (1)
385dbdb7daSHaojian Zhuang #define CTYPE_1BIT (0)
395dbdb7daSHaojian Zhuang
405dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ (0x1c)
415dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT (0x20)
425dbdb7daSHaojian Zhuang #define DWMMC_INTMASK (0x24)
435dbdb7daSHaojian Zhuang #define INT_EBE (1 << 15)
445dbdb7daSHaojian Zhuang #define INT_SBE (1 << 13)
455dbdb7daSHaojian Zhuang #define INT_HLE (1 << 12)
465dbdb7daSHaojian Zhuang #define INT_FRUN (1 << 11)
475dbdb7daSHaojian Zhuang #define INT_DRT (1 << 9)
485dbdb7daSHaojian Zhuang #define INT_RTO (1 << 8)
495dbdb7daSHaojian Zhuang #define INT_DCRC (1 << 7)
505dbdb7daSHaojian Zhuang #define INT_RCRC (1 << 6)
515dbdb7daSHaojian Zhuang #define INT_RXDR (1 << 5)
525dbdb7daSHaojian Zhuang #define INT_TXDR (1 << 4)
535dbdb7daSHaojian Zhuang #define INT_DTO (1 << 3)
545dbdb7daSHaojian Zhuang #define INT_CMD_DONE (1 << 2)
555dbdb7daSHaojian Zhuang #define INT_RE (1 << 1)
565dbdb7daSHaojian Zhuang
575dbdb7daSHaojian Zhuang #define DWMMC_CMDARG (0x28)
585dbdb7daSHaojian Zhuang #define DWMMC_CMD (0x2c)
59*9264f087SJustin Chadwell #define CMD_START (U(1) << 31)
605dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */
615dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY (1 << 21)
625dbdb7daSHaojian Zhuang #define CMD_SEND_INIT (1 << 15)
635dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD (1 << 14)
645dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
655dbdb7daSHaojian Zhuang #define CMD_WRITE (1 << 10)
665dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT (1 << 9)
675dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC (1 << 8)
685dbdb7daSHaojian Zhuang #define CMD_RESP_LEN (1 << 7)
695dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT (1 << 6)
705dbdb7daSHaojian Zhuang #define CMD(x) (x & 0x3f)
715dbdb7daSHaojian Zhuang
725dbdb7daSHaojian Zhuang #define DWMMC_RESP0 (0x30)
735dbdb7daSHaojian Zhuang #define DWMMC_RESP1 (0x34)
745dbdb7daSHaojian Zhuang #define DWMMC_RESP2 (0x38)
755dbdb7daSHaojian Zhuang #define DWMMC_RESP3 (0x3c)
765dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS (0x44)
775dbdb7daSHaojian Zhuang #define DWMMC_STATUS (0x48)
785dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY (1 << 9)
795dbdb7daSHaojian Zhuang
805dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH (0x4c)
815dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x) (x & 0xfff)
825dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16)
835dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28)
845dbdb7daSHaojian Zhuang
855dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE (0x64)
865dbdb7daSHaojian Zhuang #define DWMMC_BMOD (0x80)
875dbdb7daSHaojian Zhuang #define BMOD_ENABLE (1 << 7)
885dbdb7daSHaojian Zhuang #define BMOD_FB (1 << 1)
895dbdb7daSHaojian Zhuang #define BMOD_SWRESET (1 << 0)
905dbdb7daSHaojian Zhuang
915dbdb7daSHaojian Zhuang #define DWMMC_DBADDR (0x88)
925dbdb7daSHaojian Zhuang #define DWMMC_IDSTS (0x8c)
935dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN (0x90)
945dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL (0x100)
955dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16)
965dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN (1 << 0)
975dbdb7daSHaojian Zhuang
985dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC (1 << 1)
995dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD (1 << 2)
1005dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS (1 << 3)
1015dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH (1 << 4)
1025dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER (1 << 5)
1035dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES (1 << 30)
104*9264f087SJustin Chadwell #define IDMAC_DES0_OWN (U(1) << 31)
1055dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x) ((x) & 0x1fff)
1065dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
1075dbdb7daSHaojian Zhuang
1085dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8)
1095dbdb7daSHaojian Zhuang
1105dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE (1 << 6)
1115dbdb7daSHaojian Zhuang
1127a8b4830SHaojian Zhuang #define DWMMC_ADDRESS_MASK U(0x0f)
1137a8b4830SHaojian Zhuang
1145dbdb7daSHaojian Zhuang #define TIMEOUT 100000
1155dbdb7daSHaojian Zhuang
1165dbdb7daSHaojian Zhuang struct dw_idmac_desc {
1175dbdb7daSHaojian Zhuang unsigned int des0;
1185dbdb7daSHaojian Zhuang unsigned int des1;
1195dbdb7daSHaojian Zhuang unsigned int des2;
1205dbdb7daSHaojian Zhuang unsigned int des3;
1215dbdb7daSHaojian Zhuang };
1225dbdb7daSHaojian Zhuang
1235dbdb7daSHaojian Zhuang static void dw_init(void);
1247a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd);
1257a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width);
1265dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size);
1275dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size);
1285dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size);
1295dbdb7daSHaojian Zhuang
1307a8b4830SHaojian Zhuang static const struct mmc_ops dw_mmc_ops = {
1315dbdb7daSHaojian Zhuang .init = dw_init,
1325dbdb7daSHaojian Zhuang .send_cmd = dw_send_cmd,
1335dbdb7daSHaojian Zhuang .set_ios = dw_set_ios,
1345dbdb7daSHaojian Zhuang .prepare = dw_prepare,
1355dbdb7daSHaojian Zhuang .read = dw_read,
1365dbdb7daSHaojian Zhuang .write = dw_write,
1375dbdb7daSHaojian Zhuang };
1385dbdb7daSHaojian Zhuang
1395dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params;
1405dbdb7daSHaojian Zhuang
dw_update_clk(void)1415dbdb7daSHaojian Zhuang static void dw_update_clk(void)
1425dbdb7daSHaojian Zhuang {
1435dbdb7daSHaojian Zhuang unsigned int data;
1445dbdb7daSHaojian Zhuang
1455dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CMD,
1465dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
1475dbdb7daSHaojian Zhuang CMD_START);
1485dbdb7daSHaojian Zhuang while (1) {
1495dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
1505dbdb7daSHaojian Zhuang if ((data & CMD_START) == 0)
1515dbdb7daSHaojian Zhuang break;
1525dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
153e52f5291SHaojian Zhuang assert((data & INT_HLE) == 0);
1545dbdb7daSHaojian Zhuang }
1555dbdb7daSHaojian Zhuang }
1565dbdb7daSHaojian Zhuang
dw_set_clk(int clk)1575dbdb7daSHaojian Zhuang static void dw_set_clk(int clk)
1585dbdb7daSHaojian Zhuang {
1595dbdb7daSHaojian Zhuang unsigned int data;
1605dbdb7daSHaojian Zhuang int div;
1615dbdb7daSHaojian Zhuang
1625dbdb7daSHaojian Zhuang assert(clk > 0);
1635dbdb7daSHaojian Zhuang
1645dbdb7daSHaojian Zhuang for (div = 1; div < 256; div++) {
1655dbdb7daSHaojian Zhuang if ((dw_params.clk_rate / (2 * div)) <= clk) {
1665dbdb7daSHaojian Zhuang break;
1675dbdb7daSHaojian Zhuang }
1685dbdb7daSHaojian Zhuang }
1695dbdb7daSHaojian Zhuang assert(div < 256);
1705dbdb7daSHaojian Zhuang
1715dbdb7daSHaojian Zhuang /* wait until controller is idle */
1725dbdb7daSHaojian Zhuang do {
1735dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
1745dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY);
1755dbdb7daSHaojian Zhuang
1765dbdb7daSHaojian Zhuang /* disable clock before change clock rate */
1775dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
1785dbdb7daSHaojian Zhuang dw_update_clk();
1795dbdb7daSHaojian Zhuang
1805dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
1815dbdb7daSHaojian Zhuang dw_update_clk();
1825dbdb7daSHaojian Zhuang
1835dbdb7daSHaojian Zhuang /* enable clock */
1845dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
1855dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
1865dbdb7daSHaojian Zhuang dw_update_clk();
1875dbdb7daSHaojian Zhuang }
1885dbdb7daSHaojian Zhuang
dw_init(void)1895dbdb7daSHaojian Zhuang static void dw_init(void)
1905dbdb7daSHaojian Zhuang {
1915dbdb7daSHaojian Zhuang unsigned int data;
1925dbdb7daSHaojian Zhuang uintptr_t base;
1935dbdb7daSHaojian Zhuang
1947a8b4830SHaojian Zhuang assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0);
1955dbdb7daSHaojian Zhuang
1965dbdb7daSHaojian Zhuang base = dw_params.reg_base;
1975dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_PWREN, 1);
1985dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
1995dbdb7daSHaojian Zhuang do {
2005dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_CTRL);
2015dbdb7daSHaojian Zhuang } while (data);
2025dbdb7daSHaojian Zhuang
2035dbdb7daSHaojian Zhuang /* enable DMA in CTRL */
2045dbdb7daSHaojian Zhuang data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
2055dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, data);
2065dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0);
2075dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_INTMASK, 0);
2085dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_TMOUT, ~0);
2095dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_IDINTEN, ~0);
2107a8b4830SHaojian Zhuang mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
2115dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
2125dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
2135dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
2145dbdb7daSHaojian Zhuang do {
2155dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_BMOD);
2165dbdb7daSHaojian Zhuang } while (data & BMOD_SWRESET);
2175dbdb7daSHaojian Zhuang /* enable DMA in BMOD */
2185dbdb7daSHaojian Zhuang data |= BMOD_ENABLE | BMOD_FB;
2195dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, data);
2205dbdb7daSHaojian Zhuang
2215dbdb7daSHaojian Zhuang udelay(100);
2227a8b4830SHaojian Zhuang dw_set_clk(MMC_BOOT_CLK_RATE);
2235dbdb7daSHaojian Zhuang udelay(100);
2245dbdb7daSHaojian Zhuang }
2255dbdb7daSHaojian Zhuang
dw_send_cmd(struct mmc_cmd * cmd)2267a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd)
2275dbdb7daSHaojian Zhuang {
2285dbdb7daSHaojian Zhuang unsigned int op, data, err_mask;
2295dbdb7daSHaojian Zhuang uintptr_t base;
2305dbdb7daSHaojian Zhuang int timeout;
2315dbdb7daSHaojian Zhuang
2325dbdb7daSHaojian Zhuang assert(cmd);
2335dbdb7daSHaojian Zhuang
2345dbdb7daSHaojian Zhuang base = dw_params.reg_base;
2355dbdb7daSHaojian Zhuang
2365dbdb7daSHaojian Zhuang switch (cmd->cmd_idx) {
2377a8b4830SHaojian Zhuang case 0:
2385dbdb7daSHaojian Zhuang op = CMD_SEND_INIT;
2395dbdb7daSHaojian Zhuang break;
2407a8b4830SHaojian Zhuang case 12:
2415dbdb7daSHaojian Zhuang op = CMD_STOP_ABORT_CMD;
2425dbdb7daSHaojian Zhuang break;
2437a8b4830SHaojian Zhuang case 13:
2445dbdb7daSHaojian Zhuang op = CMD_WAIT_PRVDATA_COMPLETE;
2455dbdb7daSHaojian Zhuang break;
2467a8b4830SHaojian Zhuang case 8:
2473d0f30bbSTien Hock, Loh if (dw_params.mmc_dev_type == MMC_IS_EMMC)
2483d0f30bbSTien Hock, Loh op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
2493d0f30bbSTien Hock, Loh else
2503d0f30bbSTien Hock, Loh op = CMD_WAIT_PRVDATA_COMPLETE;
2513d0f30bbSTien Hock, Loh break;
2527a8b4830SHaojian Zhuang case 17:
2537a8b4830SHaojian Zhuang case 18:
2545dbdb7daSHaojian Zhuang op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
2555dbdb7daSHaojian Zhuang break;
2567a8b4830SHaojian Zhuang case 24:
2577a8b4830SHaojian Zhuang case 25:
2585dbdb7daSHaojian Zhuang op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
2595dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE;
2605dbdb7daSHaojian Zhuang break;
2613d0f30bbSTien Hock, Loh case 51:
2623d0f30bbSTien Hock, Loh op = CMD_DATA_TRANS_EXPECT;
2633d0f30bbSTien Hock, Loh break;
2645dbdb7daSHaojian Zhuang default:
2655dbdb7daSHaojian Zhuang op = 0;
2665dbdb7daSHaojian Zhuang break;
2675dbdb7daSHaojian Zhuang }
2685dbdb7daSHaojian Zhuang op |= CMD_USE_HOLD_REG | CMD_START;
2695dbdb7daSHaojian Zhuang switch (cmd->resp_type) {
2705dbdb7daSHaojian Zhuang case 0:
2715dbdb7daSHaojian Zhuang break;
2722a82a9c9SJun Nie case MMC_RESPONSE_R2:
2735dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
2745dbdb7daSHaojian Zhuang CMD_RESP_LEN;
2755dbdb7daSHaojian Zhuang break;
2762a82a9c9SJun Nie case MMC_RESPONSE_R3:
2775dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT;
2785dbdb7daSHaojian Zhuang break;
2795dbdb7daSHaojian Zhuang default:
2805dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
2815dbdb7daSHaojian Zhuang break;
2825dbdb7daSHaojian Zhuang }
2835dbdb7daSHaojian Zhuang timeout = TIMEOUT;
2845dbdb7daSHaojian Zhuang do {
2855dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_STATUS);
2865dbdb7daSHaojian Zhuang if (--timeout <= 0)
2875dbdb7daSHaojian Zhuang panic();
2885dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY);
2895dbdb7daSHaojian Zhuang
2905dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0);
2915dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
2925dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
2935dbdb7daSHaojian Zhuang
2945dbdb7daSHaojian Zhuang err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
2955dbdb7daSHaojian Zhuang INT_DCRC | INT_DRT | INT_SBE;
2965dbdb7daSHaojian Zhuang timeout = TIMEOUT;
2975dbdb7daSHaojian Zhuang do {
2985dbdb7daSHaojian Zhuang udelay(500);
2995dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_RINTSTS);
3005dbdb7daSHaojian Zhuang
3015dbdb7daSHaojian Zhuang if (data & err_mask)
3025dbdb7daSHaojian Zhuang return -EIO;
3035dbdb7daSHaojian Zhuang if (data & INT_DTO)
3045dbdb7daSHaojian Zhuang break;
3055dbdb7daSHaojian Zhuang if (--timeout == 0) {
3065dbdb7daSHaojian Zhuang ERROR("%s, RINTSTS:0x%x\n", __func__, data);
3075dbdb7daSHaojian Zhuang panic();
3085dbdb7daSHaojian Zhuang }
3095dbdb7daSHaojian Zhuang } while (!(data & INT_CMD_DONE));
3105dbdb7daSHaojian Zhuang
3115dbdb7daSHaojian Zhuang if (op & CMD_RESP_EXPECT) {
3125dbdb7daSHaojian Zhuang cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
3135dbdb7daSHaojian Zhuang if (op & CMD_RESP_LEN) {
3145dbdb7daSHaojian Zhuang cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
3155dbdb7daSHaojian Zhuang cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
3165dbdb7daSHaojian Zhuang cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
3175dbdb7daSHaojian Zhuang }
3185dbdb7daSHaojian Zhuang }
3195dbdb7daSHaojian Zhuang return 0;
3205dbdb7daSHaojian Zhuang }
3215dbdb7daSHaojian Zhuang
dw_set_ios(unsigned int clk,unsigned int width)3227a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width)
3235dbdb7daSHaojian Zhuang {
3245dbdb7daSHaojian Zhuang switch (width) {
3257a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_1:
3265dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
3275dbdb7daSHaojian Zhuang break;
3287a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_4:
3295dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
3305dbdb7daSHaojian Zhuang break;
3317a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_8:
3325dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
3335dbdb7daSHaojian Zhuang break;
3345dbdb7daSHaojian Zhuang default:
3355dbdb7daSHaojian Zhuang assert(0);
3365aa7498aSJonathan Wright break;
3375dbdb7daSHaojian Zhuang }
3385dbdb7daSHaojian Zhuang dw_set_clk(clk);
3395dbdb7daSHaojian Zhuang return 0;
3405dbdb7daSHaojian Zhuang }
3415dbdb7daSHaojian Zhuang
dw_prepare(int lba,uintptr_t buf,size_t size)3425dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size)
3435dbdb7daSHaojian Zhuang {
3445dbdb7daSHaojian Zhuang struct dw_idmac_desc *desc;
3455dbdb7daSHaojian Zhuang int desc_cnt, i, last;
3465dbdb7daSHaojian Zhuang uintptr_t base;
3475dbdb7daSHaojian Zhuang
3487a8b4830SHaojian Zhuang assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
3495dbdb7daSHaojian Zhuang (dw_params.desc_size > 0) &&
3507a8b4830SHaojian Zhuang ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
3517a8b4830SHaojian Zhuang ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
3527a8b4830SHaojian Zhuang ((dw_params.desc_size & MMC_BLOCK_MASK) == 0));
3537a8b4830SHaojian Zhuang
3547a8b4830SHaojian Zhuang flush_dcache_range(buf, size);
3555dbdb7daSHaojian Zhuang
3565dbdb7daSHaojian Zhuang desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
3575dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE;
3585dbdb7daSHaojian Zhuang assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
3595dbdb7daSHaojian Zhuang
3605dbdb7daSHaojian Zhuang base = dw_params.reg_base;
3615dbdb7daSHaojian Zhuang desc = (struct dw_idmac_desc *)dw_params.desc_base;
3625dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, size);
3633d0f30bbSTien Hock, Loh
3643d0f30bbSTien Hock, Loh if (size < MMC_BLOCK_SIZE)
3653d0f30bbSTien Hock, Loh mmio_write_32(base + DWMMC_BLKSIZ, size);
3663d0f30bbSTien Hock, Loh else
3673d0f30bbSTien Hock, Loh mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
3683d0f30bbSTien Hock, Loh
3695dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0);
3705dbdb7daSHaojian Zhuang for (i = 0; i < desc_cnt; i++) {
3715dbdb7daSHaojian Zhuang desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
3725dbdb7daSHaojian Zhuang desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
3735dbdb7daSHaojian Zhuang desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
3745dbdb7daSHaojian Zhuang desc[i].des3 = dw_params.desc_base +
3755dbdb7daSHaojian Zhuang (sizeof(struct dw_idmac_desc)) * (i + 1);
3765dbdb7daSHaojian Zhuang }
3775dbdb7daSHaojian Zhuang /* first descriptor */
3785dbdb7daSHaojian Zhuang desc->des0 |= IDMAC_DES0_FS;
3795dbdb7daSHaojian Zhuang /* last descriptor */
3805dbdb7daSHaojian Zhuang last = desc_cnt - 1;
3815dbdb7daSHaojian Zhuang (desc + last)->des0 |= IDMAC_DES0_LD;
3825dbdb7daSHaojian Zhuang (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
3835dbdb7daSHaojian Zhuang (desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
3845dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE));
3855dbdb7daSHaojian Zhuang /* set next descriptor address as 0 */
3865dbdb7daSHaojian Zhuang (desc + last)->des3 = 0;
3875dbdb7daSHaojian Zhuang
3885dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
3897a8b4830SHaojian Zhuang flush_dcache_range(dw_params.desc_base,
3905dbdb7daSHaojian Zhuang desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
3915dbdb7daSHaojian Zhuang
3923d0f30bbSTien Hock, Loh
3935dbdb7daSHaojian Zhuang return 0;
3945dbdb7daSHaojian Zhuang }
3955dbdb7daSHaojian Zhuang
dw_read(int lba,uintptr_t buf,size_t size)3965dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size)
3975dbdb7daSHaojian Zhuang {
3983d0f30bbSTien Hock, Loh uint32_t data = 0;
3993d0f30bbSTien Hock, Loh int timeout = TIMEOUT;
4003d0f30bbSTien Hock, Loh
4013d0f30bbSTien Hock, Loh do {
4023d0f30bbSTien Hock, Loh data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
4033d0f30bbSTien Hock, Loh udelay(50);
4043d0f30bbSTien Hock, Loh } while (!(data & INT_DTO) && timeout-- > 0);
4053d0f30bbSTien Hock, Loh
4063d0f30bbSTien Hock, Loh inv_dcache_range(buf, size);
4073d0f30bbSTien Hock, Loh
4085dbdb7daSHaojian Zhuang return 0;
4095dbdb7daSHaojian Zhuang }
4105dbdb7daSHaojian Zhuang
dw_write(int lba,uintptr_t buf,size_t size)4115dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size)
4125dbdb7daSHaojian Zhuang {
4135dbdb7daSHaojian Zhuang return 0;
4145dbdb7daSHaojian Zhuang }
4155dbdb7daSHaojian Zhuang
dw_mmc_init(dw_mmc_params_t * params,struct mmc_device_info * info)4167a8b4830SHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
4175dbdb7daSHaojian Zhuang {
4185dbdb7daSHaojian Zhuang assert((params != 0) &&
4197a8b4830SHaojian Zhuang ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
4207a8b4830SHaojian Zhuang ((params->desc_base & MMC_BLOCK_MASK) == 0) &&
4217a8b4830SHaojian Zhuang ((params->desc_size & MMC_BLOCK_MASK) == 0) &&
4225dbdb7daSHaojian Zhuang (params->desc_size > 0) &&
4235dbdb7daSHaojian Zhuang (params->clk_rate > 0) &&
4247a8b4830SHaojian Zhuang ((params->bus_width == MMC_BUS_WIDTH_1) ||
4257a8b4830SHaojian Zhuang (params->bus_width == MMC_BUS_WIDTH_4) ||
4267a8b4830SHaojian Zhuang (params->bus_width == MMC_BUS_WIDTH_8)));
4275dbdb7daSHaojian Zhuang
4285dbdb7daSHaojian Zhuang memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
4292baa7270STien Hock, Loh dw_params.mmc_dev_type = info->mmc_dev_type;
4307a8b4830SHaojian Zhuang mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
4317a8b4830SHaojian Zhuang params->flags, info);
4325dbdb7daSHaojian Zhuang }
433