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 7*09d40e0eSAntonio Nino Diaz #include <assert.h> 8*09d40e0eSAntonio Nino Diaz #include <errno.h> 9*09d40e0eSAntonio Nino Diaz #include <string.h> 10*09d40e0eSAntonio Nino Diaz 115dbdb7daSHaojian Zhuang #include <arch.h> 125dbdb7daSHaojian Zhuang #include <arch_helpers.h> 13*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 14*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 15*09d40e0eSAntonio Nino Diaz #include <drivers/mmc.h> 16*09d40e0eSAntonio Nino Diaz #include <drivers/synopsys/dw_mmc.h> 17*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 185dbdb7daSHaojian Zhuang 195dbdb7daSHaojian Zhuang #define DWMMC_CTRL (0x00) 205dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN (1 << 25) 215dbdb7daSHaojian Zhuang #define CTRL_DMA_EN (1 << 5) 225dbdb7daSHaojian Zhuang #define CTRL_INT_EN (1 << 4) 235dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET (1 << 2) 245dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET (1 << 1) 255dbdb7daSHaojian Zhuang #define CTRL_RESET (1 << 0) 265dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \ 275dbdb7daSHaojian Zhuang CTRL_RESET) 285dbdb7daSHaojian Zhuang 295dbdb7daSHaojian Zhuang #define DWMMC_PWREN (0x04) 305dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV (0x08) 315dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC (0x0c) 325dbdb7daSHaojian Zhuang #define DWMMC_CLKENA (0x10) 335dbdb7daSHaojian Zhuang #define DWMMC_TMOUT (0x14) 345dbdb7daSHaojian Zhuang #define DWMMC_CTYPE (0x18) 355dbdb7daSHaojian Zhuang #define CTYPE_8BIT (1 << 16) 365dbdb7daSHaojian Zhuang #define CTYPE_4BIT (1) 375dbdb7daSHaojian Zhuang #define CTYPE_1BIT (0) 385dbdb7daSHaojian Zhuang 395dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ (0x1c) 405dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT (0x20) 415dbdb7daSHaojian Zhuang #define DWMMC_INTMASK (0x24) 425dbdb7daSHaojian Zhuang #define INT_EBE (1 << 15) 435dbdb7daSHaojian Zhuang #define INT_SBE (1 << 13) 445dbdb7daSHaojian Zhuang #define INT_HLE (1 << 12) 455dbdb7daSHaojian Zhuang #define INT_FRUN (1 << 11) 465dbdb7daSHaojian Zhuang #define INT_DRT (1 << 9) 475dbdb7daSHaojian Zhuang #define INT_RTO (1 << 8) 485dbdb7daSHaojian Zhuang #define INT_DCRC (1 << 7) 495dbdb7daSHaojian Zhuang #define INT_RCRC (1 << 6) 505dbdb7daSHaojian Zhuang #define INT_RXDR (1 << 5) 515dbdb7daSHaojian Zhuang #define INT_TXDR (1 << 4) 525dbdb7daSHaojian Zhuang #define INT_DTO (1 << 3) 535dbdb7daSHaojian Zhuang #define INT_CMD_DONE (1 << 2) 545dbdb7daSHaojian Zhuang #define INT_RE (1 << 1) 555dbdb7daSHaojian Zhuang 565dbdb7daSHaojian Zhuang #define DWMMC_CMDARG (0x28) 575dbdb7daSHaojian Zhuang #define DWMMC_CMD (0x2c) 585dbdb7daSHaojian Zhuang #define CMD_START (1 << 31) 595dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */ 605dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY (1 << 21) 615dbdb7daSHaojian Zhuang #define CMD_SEND_INIT (1 << 15) 625dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD (1 << 14) 635dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE (1 << 13) 645dbdb7daSHaojian Zhuang #define CMD_WRITE (1 << 10) 655dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT (1 << 9) 665dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC (1 << 8) 675dbdb7daSHaojian Zhuang #define CMD_RESP_LEN (1 << 7) 685dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT (1 << 6) 695dbdb7daSHaojian Zhuang #define CMD(x) (x & 0x3f) 705dbdb7daSHaojian Zhuang 715dbdb7daSHaojian Zhuang #define DWMMC_RESP0 (0x30) 725dbdb7daSHaojian Zhuang #define DWMMC_RESP1 (0x34) 735dbdb7daSHaojian Zhuang #define DWMMC_RESP2 (0x38) 745dbdb7daSHaojian Zhuang #define DWMMC_RESP3 (0x3c) 755dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS (0x44) 765dbdb7daSHaojian Zhuang #define DWMMC_STATUS (0x48) 775dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY (1 << 9) 785dbdb7daSHaojian Zhuang 795dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH (0x4c) 805dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x) (x & 0xfff) 815dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16) 825dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28) 835dbdb7daSHaojian Zhuang 845dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE (0x64) 855dbdb7daSHaojian Zhuang #define DWMMC_BMOD (0x80) 865dbdb7daSHaojian Zhuang #define BMOD_ENABLE (1 << 7) 875dbdb7daSHaojian Zhuang #define BMOD_FB (1 << 1) 885dbdb7daSHaojian Zhuang #define BMOD_SWRESET (1 << 0) 895dbdb7daSHaojian Zhuang 905dbdb7daSHaojian Zhuang #define DWMMC_DBADDR (0x88) 915dbdb7daSHaojian Zhuang #define DWMMC_IDSTS (0x8c) 925dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN (0x90) 935dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL (0x100) 945dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16) 955dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN (1 << 0) 965dbdb7daSHaojian Zhuang 975dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC (1 << 1) 985dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD (1 << 2) 995dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS (1 << 3) 1005dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH (1 << 4) 1015dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER (1 << 5) 1025dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES (1 << 30) 1035dbdb7daSHaojian Zhuang #define IDMAC_DES0_OWN (1 << 31) 1045dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x) ((x) & 0x1fff) 1055dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) 1065dbdb7daSHaojian Zhuang 1075dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8) 1085dbdb7daSHaojian Zhuang 1095dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE (1 << 6) 1105dbdb7daSHaojian Zhuang 1117a8b4830SHaojian Zhuang #define DWMMC_ADDRESS_MASK U(0x0f) 1127a8b4830SHaojian Zhuang 1135dbdb7daSHaojian Zhuang #define TIMEOUT 100000 1145dbdb7daSHaojian Zhuang 1155dbdb7daSHaojian Zhuang struct dw_idmac_desc { 1165dbdb7daSHaojian Zhuang unsigned int des0; 1175dbdb7daSHaojian Zhuang unsigned int des1; 1185dbdb7daSHaojian Zhuang unsigned int des2; 1195dbdb7daSHaojian Zhuang unsigned int des3; 1205dbdb7daSHaojian Zhuang }; 1215dbdb7daSHaojian Zhuang 1225dbdb7daSHaojian Zhuang static void dw_init(void); 1237a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd); 1247a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width); 1255dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size); 1265dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size); 1275dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size); 1285dbdb7daSHaojian Zhuang 1297a8b4830SHaojian Zhuang static const struct mmc_ops dw_mmc_ops = { 1305dbdb7daSHaojian Zhuang .init = dw_init, 1315dbdb7daSHaojian Zhuang .send_cmd = dw_send_cmd, 1325dbdb7daSHaojian Zhuang .set_ios = dw_set_ios, 1335dbdb7daSHaojian Zhuang .prepare = dw_prepare, 1345dbdb7daSHaojian Zhuang .read = dw_read, 1355dbdb7daSHaojian Zhuang .write = dw_write, 1365dbdb7daSHaojian Zhuang }; 1375dbdb7daSHaojian Zhuang 1385dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params; 1395dbdb7daSHaojian Zhuang 1405dbdb7daSHaojian Zhuang static void dw_update_clk(void) 1415dbdb7daSHaojian Zhuang { 1425dbdb7daSHaojian Zhuang unsigned int data; 1435dbdb7daSHaojian Zhuang 1445dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CMD, 1455dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY | 1465dbdb7daSHaojian Zhuang CMD_START); 1475dbdb7daSHaojian Zhuang while (1) { 1485dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_CMD); 1495dbdb7daSHaojian Zhuang if ((data & CMD_START) == 0) 1505dbdb7daSHaojian Zhuang break; 1515dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); 152e52f5291SHaojian Zhuang assert((data & INT_HLE) == 0); 1535dbdb7daSHaojian Zhuang } 1545dbdb7daSHaojian Zhuang } 1555dbdb7daSHaojian Zhuang 1565dbdb7daSHaojian Zhuang static void dw_set_clk(int clk) 1575dbdb7daSHaojian Zhuang { 1585dbdb7daSHaojian Zhuang unsigned int data; 1595dbdb7daSHaojian Zhuang int div; 1605dbdb7daSHaojian Zhuang 1615dbdb7daSHaojian Zhuang assert(clk > 0); 1625dbdb7daSHaojian Zhuang 1635dbdb7daSHaojian Zhuang for (div = 1; div < 256; div++) { 1645dbdb7daSHaojian Zhuang if ((dw_params.clk_rate / (2 * div)) <= clk) { 1655dbdb7daSHaojian Zhuang break; 1665dbdb7daSHaojian Zhuang } 1675dbdb7daSHaojian Zhuang } 1685dbdb7daSHaojian Zhuang assert(div < 256); 1695dbdb7daSHaojian Zhuang 1705dbdb7daSHaojian Zhuang /* wait until controller is idle */ 1715dbdb7daSHaojian Zhuang do { 1725dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS); 1735dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 1745dbdb7daSHaojian Zhuang 1755dbdb7daSHaojian Zhuang /* disable clock before change clock rate */ 1765dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0); 1775dbdb7daSHaojian Zhuang dw_update_clk(); 1785dbdb7daSHaojian Zhuang 1795dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div); 1805dbdb7daSHaojian Zhuang dw_update_clk(); 1815dbdb7daSHaojian Zhuang 1825dbdb7daSHaojian Zhuang /* enable clock */ 1835dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1); 1845dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0); 1855dbdb7daSHaojian Zhuang dw_update_clk(); 1865dbdb7daSHaojian Zhuang } 1875dbdb7daSHaojian Zhuang 1885dbdb7daSHaojian Zhuang static void dw_init(void) 1895dbdb7daSHaojian Zhuang { 1905dbdb7daSHaojian Zhuang unsigned int data; 1915dbdb7daSHaojian Zhuang uintptr_t base; 1925dbdb7daSHaojian Zhuang 1937a8b4830SHaojian Zhuang assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0); 1945dbdb7daSHaojian Zhuang 1955dbdb7daSHaojian Zhuang base = dw_params.reg_base; 1965dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_PWREN, 1); 1975dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL); 1985dbdb7daSHaojian Zhuang do { 1995dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_CTRL); 2005dbdb7daSHaojian Zhuang } while (data); 2015dbdb7daSHaojian Zhuang 2025dbdb7daSHaojian Zhuang /* enable DMA in CTRL */ 2035dbdb7daSHaojian Zhuang data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN; 2045dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, data); 2055dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 2065dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_INTMASK, 0); 2075dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_TMOUT, ~0); 2085dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_IDINTEN, ~0); 2097a8b4830SHaojian Zhuang mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE); 2105dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024); 2115dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff); 2125dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET); 2135dbdb7daSHaojian Zhuang do { 2145dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_BMOD); 2155dbdb7daSHaojian Zhuang } while (data & BMOD_SWRESET); 2165dbdb7daSHaojian Zhuang /* enable DMA in BMOD */ 2175dbdb7daSHaojian Zhuang data |= BMOD_ENABLE | BMOD_FB; 2185dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, data); 2195dbdb7daSHaojian Zhuang 2205dbdb7daSHaojian Zhuang udelay(100); 2217a8b4830SHaojian Zhuang dw_set_clk(MMC_BOOT_CLK_RATE); 2225dbdb7daSHaojian Zhuang udelay(100); 2235dbdb7daSHaojian Zhuang } 2245dbdb7daSHaojian Zhuang 2257a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd) 2265dbdb7daSHaojian Zhuang { 2275dbdb7daSHaojian Zhuang unsigned int op, data, err_mask; 2285dbdb7daSHaojian Zhuang uintptr_t base; 2295dbdb7daSHaojian Zhuang int timeout; 2305dbdb7daSHaojian Zhuang 2315dbdb7daSHaojian Zhuang assert(cmd); 2325dbdb7daSHaojian Zhuang 2335dbdb7daSHaojian Zhuang base = dw_params.reg_base; 2345dbdb7daSHaojian Zhuang 2355dbdb7daSHaojian Zhuang switch (cmd->cmd_idx) { 2367a8b4830SHaojian Zhuang case 0: 2375dbdb7daSHaojian Zhuang op = CMD_SEND_INIT; 2385dbdb7daSHaojian Zhuang break; 2397a8b4830SHaojian Zhuang case 12: 2405dbdb7daSHaojian Zhuang op = CMD_STOP_ABORT_CMD; 2415dbdb7daSHaojian Zhuang break; 2427a8b4830SHaojian Zhuang case 13: 2435dbdb7daSHaojian Zhuang op = CMD_WAIT_PRVDATA_COMPLETE; 2445dbdb7daSHaojian Zhuang break; 2457a8b4830SHaojian Zhuang case 8: 2467a8b4830SHaojian Zhuang case 17: 2477a8b4830SHaojian Zhuang case 18: 2485dbdb7daSHaojian Zhuang op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; 2495dbdb7daSHaojian Zhuang break; 2507a8b4830SHaojian Zhuang case 24: 2517a8b4830SHaojian Zhuang case 25: 2525dbdb7daSHaojian Zhuang op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | 2535dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE; 2545dbdb7daSHaojian Zhuang break; 2555dbdb7daSHaojian Zhuang default: 2565dbdb7daSHaojian Zhuang op = 0; 2575dbdb7daSHaojian Zhuang break; 2585dbdb7daSHaojian Zhuang } 2595dbdb7daSHaojian Zhuang op |= CMD_USE_HOLD_REG | CMD_START; 2605dbdb7daSHaojian Zhuang switch (cmd->resp_type) { 2615dbdb7daSHaojian Zhuang case 0: 2625dbdb7daSHaojian Zhuang break; 2632a82a9c9SJun Nie case MMC_RESPONSE_R2: 2645dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC | 2655dbdb7daSHaojian Zhuang CMD_RESP_LEN; 2665dbdb7daSHaojian Zhuang break; 2672a82a9c9SJun Nie case MMC_RESPONSE_R3: 2685dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT; 2695dbdb7daSHaojian Zhuang break; 2705dbdb7daSHaojian Zhuang default: 2715dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC; 2725dbdb7daSHaojian Zhuang break; 2735dbdb7daSHaojian Zhuang } 2745dbdb7daSHaojian Zhuang timeout = TIMEOUT; 2755dbdb7daSHaojian Zhuang do { 2765dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_STATUS); 2775dbdb7daSHaojian Zhuang if (--timeout <= 0) 2785dbdb7daSHaojian Zhuang panic(); 2795dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 2805dbdb7daSHaojian Zhuang 2815dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 2825dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg); 2835dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx); 2845dbdb7daSHaojian Zhuang 2855dbdb7daSHaojian Zhuang err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE | 2865dbdb7daSHaojian Zhuang INT_DCRC | INT_DRT | INT_SBE; 2875dbdb7daSHaojian Zhuang timeout = TIMEOUT; 2885dbdb7daSHaojian Zhuang do { 2895dbdb7daSHaojian Zhuang udelay(500); 2905dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_RINTSTS); 2915dbdb7daSHaojian Zhuang 2925dbdb7daSHaojian Zhuang if (data & err_mask) 2935dbdb7daSHaojian Zhuang return -EIO; 2945dbdb7daSHaojian Zhuang if (data & INT_DTO) 2955dbdb7daSHaojian Zhuang break; 2965dbdb7daSHaojian Zhuang if (--timeout == 0) { 2975dbdb7daSHaojian Zhuang ERROR("%s, RINTSTS:0x%x\n", __func__, data); 2985dbdb7daSHaojian Zhuang panic(); 2995dbdb7daSHaojian Zhuang } 3005dbdb7daSHaojian Zhuang } while (!(data & INT_CMD_DONE)); 3015dbdb7daSHaojian Zhuang 3025dbdb7daSHaojian Zhuang if (op & CMD_RESP_EXPECT) { 3035dbdb7daSHaojian Zhuang cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0); 3045dbdb7daSHaojian Zhuang if (op & CMD_RESP_LEN) { 3055dbdb7daSHaojian Zhuang cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1); 3065dbdb7daSHaojian Zhuang cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2); 3075dbdb7daSHaojian Zhuang cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3); 3085dbdb7daSHaojian Zhuang } 3095dbdb7daSHaojian Zhuang } 3105dbdb7daSHaojian Zhuang return 0; 3115dbdb7daSHaojian Zhuang } 3125dbdb7daSHaojian Zhuang 3137a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width) 3145dbdb7daSHaojian Zhuang { 3155dbdb7daSHaojian Zhuang switch (width) { 3167a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_1: 3175dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT); 3185dbdb7daSHaojian Zhuang break; 3197a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_4: 3205dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT); 3215dbdb7daSHaojian Zhuang break; 3227a8b4830SHaojian Zhuang case MMC_BUS_WIDTH_8: 3235dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT); 3245dbdb7daSHaojian Zhuang break; 3255dbdb7daSHaojian Zhuang default: 3265dbdb7daSHaojian Zhuang assert(0); 3275aa7498aSJonathan Wright break; 3285dbdb7daSHaojian Zhuang } 3295dbdb7daSHaojian Zhuang dw_set_clk(clk); 3305dbdb7daSHaojian Zhuang return 0; 3315dbdb7daSHaojian Zhuang } 3325dbdb7daSHaojian Zhuang 3335dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size) 3345dbdb7daSHaojian Zhuang { 3355dbdb7daSHaojian Zhuang struct dw_idmac_desc *desc; 3365dbdb7daSHaojian Zhuang int desc_cnt, i, last; 3375dbdb7daSHaojian Zhuang uintptr_t base; 3385dbdb7daSHaojian Zhuang 3397a8b4830SHaojian Zhuang assert(((buf & DWMMC_ADDRESS_MASK) == 0) && 3407a8b4830SHaojian Zhuang ((size % MMC_BLOCK_SIZE) == 0) && 3415dbdb7daSHaojian Zhuang (dw_params.desc_size > 0) && 3427a8b4830SHaojian Zhuang ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) && 3437a8b4830SHaojian Zhuang ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) && 3447a8b4830SHaojian Zhuang ((dw_params.desc_size & MMC_BLOCK_MASK) == 0)); 3457a8b4830SHaojian Zhuang 3467a8b4830SHaojian Zhuang flush_dcache_range(buf, size); 3475dbdb7daSHaojian Zhuang 3485dbdb7daSHaojian Zhuang desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) / 3495dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE; 3505dbdb7daSHaojian Zhuang assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size); 3515dbdb7daSHaojian Zhuang 3525dbdb7daSHaojian Zhuang base = dw_params.reg_base; 3535dbdb7daSHaojian Zhuang desc = (struct dw_idmac_desc *)dw_params.desc_base; 3545dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, size); 3555dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 3565dbdb7daSHaojian Zhuang for (i = 0; i < desc_cnt; i++) { 3575dbdb7daSHaojian Zhuang desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; 3585dbdb7daSHaojian Zhuang desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE); 3595dbdb7daSHaojian Zhuang desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i; 3605dbdb7daSHaojian Zhuang desc[i].des3 = dw_params.desc_base + 3615dbdb7daSHaojian Zhuang (sizeof(struct dw_idmac_desc)) * (i + 1); 3625dbdb7daSHaojian Zhuang } 3635dbdb7daSHaojian Zhuang /* first descriptor */ 3645dbdb7daSHaojian Zhuang desc->des0 |= IDMAC_DES0_FS; 3655dbdb7daSHaojian Zhuang /* last descriptor */ 3665dbdb7daSHaojian Zhuang last = desc_cnt - 1; 3675dbdb7daSHaojian Zhuang (desc + last)->des0 |= IDMAC_DES0_LD; 3685dbdb7daSHaojian Zhuang (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH); 3695dbdb7daSHaojian Zhuang (desc + last)->des1 = IDMAC_DES1_BS1(size - (last * 3705dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE)); 3715dbdb7daSHaojian Zhuang /* set next descriptor address as 0 */ 3725dbdb7daSHaojian Zhuang (desc + last)->des3 = 0; 3735dbdb7daSHaojian Zhuang 3745dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base); 3757a8b4830SHaojian Zhuang flush_dcache_range(dw_params.desc_base, 3765dbdb7daSHaojian Zhuang desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); 3775dbdb7daSHaojian Zhuang 3785dbdb7daSHaojian Zhuang return 0; 3795dbdb7daSHaojian Zhuang } 3805dbdb7daSHaojian Zhuang 3815dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size) 3825dbdb7daSHaojian Zhuang { 3835dbdb7daSHaojian Zhuang return 0; 3845dbdb7daSHaojian Zhuang } 3855dbdb7daSHaojian Zhuang 3865dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size) 3875dbdb7daSHaojian Zhuang { 3885dbdb7daSHaojian Zhuang return 0; 3895dbdb7daSHaojian Zhuang } 3905dbdb7daSHaojian Zhuang 3917a8b4830SHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info) 3925dbdb7daSHaojian Zhuang { 3935dbdb7daSHaojian Zhuang assert((params != 0) && 3947a8b4830SHaojian Zhuang ((params->reg_base & MMC_BLOCK_MASK) == 0) && 3957a8b4830SHaojian Zhuang ((params->desc_base & MMC_BLOCK_MASK) == 0) && 3967a8b4830SHaojian Zhuang ((params->desc_size & MMC_BLOCK_MASK) == 0) && 3975dbdb7daSHaojian Zhuang (params->desc_size > 0) && 3985dbdb7daSHaojian Zhuang (params->clk_rate > 0) && 3997a8b4830SHaojian Zhuang ((params->bus_width == MMC_BUS_WIDTH_1) || 4007a8b4830SHaojian Zhuang (params->bus_width == MMC_BUS_WIDTH_4) || 4017a8b4830SHaojian Zhuang (params->bus_width == MMC_BUS_WIDTH_8))); 4025dbdb7daSHaojian Zhuang 4035dbdb7daSHaojian Zhuang memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); 4047a8b4830SHaojian Zhuang mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, 4057a8b4830SHaojian Zhuang params->flags, info); 4065dbdb7daSHaojian Zhuang } 407