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 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 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 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 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 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 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 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 4115dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size) 4125dbdb7daSHaojian Zhuang { 4135dbdb7daSHaojian Zhuang return 0; 4145dbdb7daSHaojian Zhuang } 4155dbdb7daSHaojian Zhuang 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)); 4293d0f30bbSTien Hock, Loh mmio_write_32(dw_params.reg_base + DWMMC_FIFOTH, 0x103ff); 4302baa7270STien Hock, Loh dw_params.mmc_dev_type = info->mmc_dev_type; 4317a8b4830SHaojian Zhuang mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, 4327a8b4830SHaojian Zhuang params->flags, info); 4335dbdb7daSHaojian Zhuang } 434