15dbdb7daSHaojian Zhuang /* 25dbdb7daSHaojian Zhuang * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 35dbdb7daSHaojian Zhuang * 4*82cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 55dbdb7daSHaojian Zhuang */ 65dbdb7daSHaojian Zhuang 75dbdb7daSHaojian Zhuang #include <arch.h> 85dbdb7daSHaojian Zhuang #include <arch_helpers.h> 95dbdb7daSHaojian Zhuang #include <assert.h> 105dbdb7daSHaojian Zhuang #include <debug.h> 115dbdb7daSHaojian Zhuang #include <delay_timer.h> 125dbdb7daSHaojian Zhuang #include <dw_mmc.h> 135dbdb7daSHaojian Zhuang #include <emmc.h> 145dbdb7daSHaojian Zhuang #include <errno.h> 155dbdb7daSHaojian Zhuang #include <mmio.h> 165dbdb7daSHaojian Zhuang #include <string.h> 175dbdb7daSHaojian Zhuang 185dbdb7daSHaojian Zhuang #define DWMMC_CTRL (0x00) 195dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN (1 << 25) 205dbdb7daSHaojian Zhuang #define CTRL_DMA_EN (1 << 5) 215dbdb7daSHaojian Zhuang #define CTRL_INT_EN (1 << 4) 225dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET (1 << 2) 235dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET (1 << 1) 245dbdb7daSHaojian Zhuang #define CTRL_RESET (1 << 0) 255dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \ 265dbdb7daSHaojian Zhuang CTRL_RESET) 275dbdb7daSHaojian Zhuang 285dbdb7daSHaojian Zhuang #define DWMMC_PWREN (0x04) 295dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV (0x08) 305dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC (0x0c) 315dbdb7daSHaojian Zhuang #define DWMMC_CLKENA (0x10) 325dbdb7daSHaojian Zhuang #define DWMMC_TMOUT (0x14) 335dbdb7daSHaojian Zhuang #define DWMMC_CTYPE (0x18) 345dbdb7daSHaojian Zhuang #define CTYPE_8BIT (1 << 16) 355dbdb7daSHaojian Zhuang #define CTYPE_4BIT (1) 365dbdb7daSHaojian Zhuang #define CTYPE_1BIT (0) 375dbdb7daSHaojian Zhuang 385dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ (0x1c) 395dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT (0x20) 405dbdb7daSHaojian Zhuang #define DWMMC_INTMASK (0x24) 415dbdb7daSHaojian Zhuang #define INT_EBE (1 << 15) 425dbdb7daSHaojian Zhuang #define INT_SBE (1 << 13) 435dbdb7daSHaojian Zhuang #define INT_HLE (1 << 12) 445dbdb7daSHaojian Zhuang #define INT_FRUN (1 << 11) 455dbdb7daSHaojian Zhuang #define INT_DRT (1 << 9) 465dbdb7daSHaojian Zhuang #define INT_RTO (1 << 8) 475dbdb7daSHaojian Zhuang #define INT_DCRC (1 << 7) 485dbdb7daSHaojian Zhuang #define INT_RCRC (1 << 6) 495dbdb7daSHaojian Zhuang #define INT_RXDR (1 << 5) 505dbdb7daSHaojian Zhuang #define INT_TXDR (1 << 4) 515dbdb7daSHaojian Zhuang #define INT_DTO (1 << 3) 525dbdb7daSHaojian Zhuang #define INT_CMD_DONE (1 << 2) 535dbdb7daSHaojian Zhuang #define INT_RE (1 << 1) 545dbdb7daSHaojian Zhuang 555dbdb7daSHaojian Zhuang #define DWMMC_CMDARG (0x28) 565dbdb7daSHaojian Zhuang #define DWMMC_CMD (0x2c) 575dbdb7daSHaojian Zhuang #define CMD_START (1 << 31) 585dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */ 595dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY (1 << 21) 605dbdb7daSHaojian Zhuang #define CMD_SEND_INIT (1 << 15) 615dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD (1 << 14) 625dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE (1 << 13) 635dbdb7daSHaojian Zhuang #define CMD_WRITE (1 << 10) 645dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT (1 << 9) 655dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC (1 << 8) 665dbdb7daSHaojian Zhuang #define CMD_RESP_LEN (1 << 7) 675dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT (1 << 6) 685dbdb7daSHaojian Zhuang #define CMD(x) (x & 0x3f) 695dbdb7daSHaojian Zhuang 705dbdb7daSHaojian Zhuang #define DWMMC_RESP0 (0x30) 715dbdb7daSHaojian Zhuang #define DWMMC_RESP1 (0x34) 725dbdb7daSHaojian Zhuang #define DWMMC_RESP2 (0x38) 735dbdb7daSHaojian Zhuang #define DWMMC_RESP3 (0x3c) 745dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS (0x44) 755dbdb7daSHaojian Zhuang #define DWMMC_STATUS (0x48) 765dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY (1 << 9) 775dbdb7daSHaojian Zhuang 785dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH (0x4c) 795dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x) (x & 0xfff) 805dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16) 815dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28) 825dbdb7daSHaojian Zhuang 835dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE (0x64) 845dbdb7daSHaojian Zhuang #define DWMMC_BMOD (0x80) 855dbdb7daSHaojian Zhuang #define BMOD_ENABLE (1 << 7) 865dbdb7daSHaojian Zhuang #define BMOD_FB (1 << 1) 875dbdb7daSHaojian Zhuang #define BMOD_SWRESET (1 << 0) 885dbdb7daSHaojian Zhuang 895dbdb7daSHaojian Zhuang #define DWMMC_DBADDR (0x88) 905dbdb7daSHaojian Zhuang #define DWMMC_IDSTS (0x8c) 915dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN (0x90) 925dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL (0x100) 935dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16) 945dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN (1 << 0) 955dbdb7daSHaojian Zhuang 965dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC (1 << 1) 975dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD (1 << 2) 985dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS (1 << 3) 995dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH (1 << 4) 1005dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER (1 << 5) 1015dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES (1 << 30) 1025dbdb7daSHaojian Zhuang #define IDMAC_DES0_OWN (1 << 31) 1035dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x) ((x) & 0x1fff) 1045dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) 1055dbdb7daSHaojian Zhuang 1065dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8) 1075dbdb7daSHaojian Zhuang 1085dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE (1 << 6) 1095dbdb7daSHaojian Zhuang 1105dbdb7daSHaojian Zhuang #define TIMEOUT 100000 1115dbdb7daSHaojian Zhuang 1125dbdb7daSHaojian Zhuang struct dw_idmac_desc { 1135dbdb7daSHaojian Zhuang unsigned int des0; 1145dbdb7daSHaojian Zhuang unsigned int des1; 1155dbdb7daSHaojian Zhuang unsigned int des2; 1165dbdb7daSHaojian Zhuang unsigned int des3; 1175dbdb7daSHaojian Zhuang }; 1185dbdb7daSHaojian Zhuang 1195dbdb7daSHaojian Zhuang static void dw_init(void); 1205dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd); 1215dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width); 1225dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size); 1235dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size); 1245dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size); 1255dbdb7daSHaojian Zhuang 1265dbdb7daSHaojian Zhuang static const emmc_ops_t dw_mmc_ops = { 1275dbdb7daSHaojian Zhuang .init = dw_init, 1285dbdb7daSHaojian Zhuang .send_cmd = dw_send_cmd, 1295dbdb7daSHaojian Zhuang .set_ios = dw_set_ios, 1305dbdb7daSHaojian Zhuang .prepare = dw_prepare, 1315dbdb7daSHaojian Zhuang .read = dw_read, 1325dbdb7daSHaojian Zhuang .write = dw_write, 1335dbdb7daSHaojian Zhuang }; 1345dbdb7daSHaojian Zhuang 1355dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params; 1365dbdb7daSHaojian Zhuang 1375dbdb7daSHaojian Zhuang static void dw_update_clk(void) 1385dbdb7daSHaojian Zhuang { 1395dbdb7daSHaojian Zhuang unsigned int data; 1405dbdb7daSHaojian Zhuang 1415dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CMD, 1425dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY | 1435dbdb7daSHaojian Zhuang CMD_START); 1445dbdb7daSHaojian Zhuang while (1) { 1455dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_CMD); 1465dbdb7daSHaojian Zhuang if ((data & CMD_START) == 0) 1475dbdb7daSHaojian Zhuang break; 1485dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); 1495dbdb7daSHaojian Zhuang assert(data & INT_HLE); 1505dbdb7daSHaojian Zhuang } 1515dbdb7daSHaojian Zhuang } 1525dbdb7daSHaojian Zhuang 1535dbdb7daSHaojian Zhuang static void dw_set_clk(int clk) 1545dbdb7daSHaojian Zhuang { 1555dbdb7daSHaojian Zhuang unsigned int data; 1565dbdb7daSHaojian Zhuang int div; 1575dbdb7daSHaojian Zhuang 1585dbdb7daSHaojian Zhuang assert(clk > 0); 1595dbdb7daSHaojian Zhuang 1605dbdb7daSHaojian Zhuang for (div = 1; div < 256; div++) { 1615dbdb7daSHaojian Zhuang if ((dw_params.clk_rate / (2 * div)) <= clk) { 1625dbdb7daSHaojian Zhuang break; 1635dbdb7daSHaojian Zhuang } 1645dbdb7daSHaojian Zhuang } 1655dbdb7daSHaojian Zhuang assert(div < 256); 1665dbdb7daSHaojian Zhuang 1675dbdb7daSHaojian Zhuang /* wait until controller is idle */ 1685dbdb7daSHaojian Zhuang do { 1695dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS); 1705dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 1715dbdb7daSHaojian Zhuang 1725dbdb7daSHaojian Zhuang /* disable clock before change clock rate */ 1735dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0); 1745dbdb7daSHaojian Zhuang dw_update_clk(); 1755dbdb7daSHaojian Zhuang 1765dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div); 1775dbdb7daSHaojian Zhuang dw_update_clk(); 1785dbdb7daSHaojian Zhuang 1795dbdb7daSHaojian Zhuang /* enable clock */ 1805dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1); 1815dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0); 1825dbdb7daSHaojian Zhuang dw_update_clk(); 1835dbdb7daSHaojian Zhuang } 1845dbdb7daSHaojian Zhuang 1855dbdb7daSHaojian Zhuang static void dw_init(void) 1865dbdb7daSHaojian Zhuang { 1875dbdb7daSHaojian Zhuang unsigned int data; 1885dbdb7daSHaojian Zhuang uintptr_t base; 1895dbdb7daSHaojian Zhuang 1905dbdb7daSHaojian Zhuang assert((dw_params.reg_base & EMMC_BLOCK_MASK) == 0); 1915dbdb7daSHaojian Zhuang 1925dbdb7daSHaojian Zhuang base = dw_params.reg_base; 1935dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_PWREN, 1); 1945dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL); 1955dbdb7daSHaojian Zhuang do { 1965dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_CTRL); 1975dbdb7daSHaojian Zhuang } while (data); 1985dbdb7daSHaojian Zhuang 1995dbdb7daSHaojian Zhuang /* enable DMA in CTRL */ 2005dbdb7daSHaojian Zhuang data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN; 2015dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, data); 2025dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 2035dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_INTMASK, 0); 2045dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_TMOUT, ~0); 2055dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_IDINTEN, ~0); 2065dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BLKSIZ, EMMC_BLOCK_SIZE); 2075dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024); 2085dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff); 2095dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET); 2105dbdb7daSHaojian Zhuang do { 2115dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_BMOD); 2125dbdb7daSHaojian Zhuang } while (data & BMOD_SWRESET); 2135dbdb7daSHaojian Zhuang /* enable DMA in BMOD */ 2145dbdb7daSHaojian Zhuang data |= BMOD_ENABLE | BMOD_FB; 2155dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, data); 2165dbdb7daSHaojian Zhuang 2175dbdb7daSHaojian Zhuang udelay(100); 2185dbdb7daSHaojian Zhuang dw_set_clk(EMMC_BOOT_CLK_RATE); 2195dbdb7daSHaojian Zhuang udelay(100); 2205dbdb7daSHaojian Zhuang } 2215dbdb7daSHaojian Zhuang 2225dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd) 2235dbdb7daSHaojian Zhuang { 2245dbdb7daSHaojian Zhuang unsigned int op, data, err_mask; 2255dbdb7daSHaojian Zhuang uintptr_t base; 2265dbdb7daSHaojian Zhuang int timeout; 2275dbdb7daSHaojian Zhuang 2285dbdb7daSHaojian Zhuang assert(cmd); 2295dbdb7daSHaojian Zhuang 2305dbdb7daSHaojian Zhuang base = dw_params.reg_base; 2315dbdb7daSHaojian Zhuang 2325dbdb7daSHaojian Zhuang switch (cmd->cmd_idx) { 2335dbdb7daSHaojian Zhuang case EMMC_CMD0: 2345dbdb7daSHaojian Zhuang op = CMD_SEND_INIT; 2355dbdb7daSHaojian Zhuang break; 2365dbdb7daSHaojian Zhuang case EMMC_CMD12: 2375dbdb7daSHaojian Zhuang op = CMD_STOP_ABORT_CMD; 2385dbdb7daSHaojian Zhuang break; 2395dbdb7daSHaojian Zhuang case EMMC_CMD13: 2405dbdb7daSHaojian Zhuang op = CMD_WAIT_PRVDATA_COMPLETE; 2415dbdb7daSHaojian Zhuang break; 2425dbdb7daSHaojian Zhuang case EMMC_CMD8: 2435dbdb7daSHaojian Zhuang case EMMC_CMD17: 2445dbdb7daSHaojian Zhuang case EMMC_CMD18: 2455dbdb7daSHaojian Zhuang op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; 2465dbdb7daSHaojian Zhuang break; 2475dbdb7daSHaojian Zhuang case EMMC_CMD24: 2485dbdb7daSHaojian Zhuang case EMMC_CMD25: 2495dbdb7daSHaojian Zhuang op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | 2505dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE; 2515dbdb7daSHaojian Zhuang break; 2525dbdb7daSHaojian Zhuang default: 2535dbdb7daSHaojian Zhuang op = 0; 2545dbdb7daSHaojian Zhuang break; 2555dbdb7daSHaojian Zhuang } 2565dbdb7daSHaojian Zhuang op |= CMD_USE_HOLD_REG | CMD_START; 2575dbdb7daSHaojian Zhuang switch (cmd->resp_type) { 2585dbdb7daSHaojian Zhuang case 0: 2595dbdb7daSHaojian Zhuang break; 2605dbdb7daSHaojian Zhuang case EMMC_RESPONSE_R2: 2615dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC | 2625dbdb7daSHaojian Zhuang CMD_RESP_LEN; 2635dbdb7daSHaojian Zhuang break; 2645dbdb7daSHaojian Zhuang case EMMC_RESPONSE_R3: 2655dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT; 2665dbdb7daSHaojian Zhuang break; 2675dbdb7daSHaojian Zhuang default: 2685dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC; 2695dbdb7daSHaojian Zhuang break; 2705dbdb7daSHaojian Zhuang } 2715dbdb7daSHaojian Zhuang timeout = TIMEOUT; 2725dbdb7daSHaojian Zhuang do { 2735dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_STATUS); 2745dbdb7daSHaojian Zhuang if (--timeout <= 0) 2755dbdb7daSHaojian Zhuang panic(); 2765dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 2775dbdb7daSHaojian Zhuang 2785dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 2795dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg); 2805dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx); 2815dbdb7daSHaojian Zhuang 2825dbdb7daSHaojian Zhuang err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE | 2835dbdb7daSHaojian Zhuang INT_DCRC | INT_DRT | INT_SBE; 2845dbdb7daSHaojian Zhuang timeout = TIMEOUT; 2855dbdb7daSHaojian Zhuang do { 2865dbdb7daSHaojian Zhuang udelay(500); 2875dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_RINTSTS); 2885dbdb7daSHaojian Zhuang 2895dbdb7daSHaojian Zhuang if (data & err_mask) 2905dbdb7daSHaojian Zhuang return -EIO; 2915dbdb7daSHaojian Zhuang if (data & INT_DTO) 2925dbdb7daSHaojian Zhuang break; 2935dbdb7daSHaojian Zhuang if (--timeout == 0) { 2945dbdb7daSHaojian Zhuang ERROR("%s, RINTSTS:0x%x\n", __func__, data); 2955dbdb7daSHaojian Zhuang panic(); 2965dbdb7daSHaojian Zhuang } 2975dbdb7daSHaojian Zhuang } while (!(data & INT_CMD_DONE)); 2985dbdb7daSHaojian Zhuang 2995dbdb7daSHaojian Zhuang if (op & CMD_RESP_EXPECT) { 3005dbdb7daSHaojian Zhuang cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0); 3015dbdb7daSHaojian Zhuang if (op & CMD_RESP_LEN) { 3025dbdb7daSHaojian Zhuang cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1); 3035dbdb7daSHaojian Zhuang cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2); 3045dbdb7daSHaojian Zhuang cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3); 3055dbdb7daSHaojian Zhuang } 3065dbdb7daSHaojian Zhuang } 3075dbdb7daSHaojian Zhuang return 0; 3085dbdb7daSHaojian Zhuang } 3095dbdb7daSHaojian Zhuang 3105dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width) 3115dbdb7daSHaojian Zhuang { 3125dbdb7daSHaojian Zhuang switch (width) { 3135dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_1: 3145dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT); 3155dbdb7daSHaojian Zhuang break; 3165dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_4: 3175dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT); 3185dbdb7daSHaojian Zhuang break; 3195dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_8: 3205dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT); 3215dbdb7daSHaojian Zhuang break; 3225dbdb7daSHaojian Zhuang default: 3235dbdb7daSHaojian Zhuang assert(0); 3245dbdb7daSHaojian Zhuang } 3255dbdb7daSHaojian Zhuang dw_set_clk(clk); 3265dbdb7daSHaojian Zhuang return 0; 3275dbdb7daSHaojian Zhuang } 3285dbdb7daSHaojian Zhuang 3295dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size) 3305dbdb7daSHaojian Zhuang { 3315dbdb7daSHaojian Zhuang struct dw_idmac_desc *desc; 3325dbdb7daSHaojian Zhuang int desc_cnt, i, last; 3335dbdb7daSHaojian Zhuang uintptr_t base; 3345dbdb7daSHaojian Zhuang 3355dbdb7daSHaojian Zhuang assert(((buf & EMMC_BLOCK_MASK) == 0) && 3365dbdb7daSHaojian Zhuang ((size % EMMC_BLOCK_SIZE) == 0) && 3375dbdb7daSHaojian Zhuang (dw_params.desc_size > 0) && 3385dbdb7daSHaojian Zhuang ((dw_params.reg_base & EMMC_BLOCK_MASK) == 0) && 3395dbdb7daSHaojian Zhuang ((dw_params.desc_base & EMMC_BLOCK_MASK) == 0) && 3405dbdb7daSHaojian Zhuang ((dw_params.desc_size & EMMC_BLOCK_MASK) == 0)); 3415dbdb7daSHaojian Zhuang 3425dbdb7daSHaojian Zhuang desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) / 3435dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE; 3445dbdb7daSHaojian Zhuang assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size); 3455dbdb7daSHaojian Zhuang 3465dbdb7daSHaojian Zhuang base = dw_params.reg_base; 3475dbdb7daSHaojian Zhuang desc = (struct dw_idmac_desc *)dw_params.desc_base; 3485dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, size); 3495dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 3505dbdb7daSHaojian Zhuang for (i = 0; i < desc_cnt; i++) { 3515dbdb7daSHaojian Zhuang desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; 3525dbdb7daSHaojian Zhuang desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE); 3535dbdb7daSHaojian Zhuang desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i; 3545dbdb7daSHaojian Zhuang desc[i].des3 = dw_params.desc_base + 3555dbdb7daSHaojian Zhuang (sizeof(struct dw_idmac_desc)) * (i + 1); 3565dbdb7daSHaojian Zhuang } 3575dbdb7daSHaojian Zhuang /* first descriptor */ 3585dbdb7daSHaojian Zhuang desc->des0 |= IDMAC_DES0_FS; 3595dbdb7daSHaojian Zhuang /* last descriptor */ 3605dbdb7daSHaojian Zhuang last = desc_cnt - 1; 3615dbdb7daSHaojian Zhuang (desc + last)->des0 |= IDMAC_DES0_LD; 3625dbdb7daSHaojian Zhuang (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH); 3635dbdb7daSHaojian Zhuang (desc + last)->des1 = IDMAC_DES1_BS1(size - (last * 3645dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE)); 3655dbdb7daSHaojian Zhuang /* set next descriptor address as 0 */ 3665dbdb7daSHaojian Zhuang (desc + last)->des3 = 0; 3675dbdb7daSHaojian Zhuang 3685dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base); 3695dbdb7daSHaojian Zhuang clean_dcache_range(dw_params.desc_base, 3705dbdb7daSHaojian Zhuang desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); 3715dbdb7daSHaojian Zhuang 3725dbdb7daSHaojian Zhuang return 0; 3735dbdb7daSHaojian Zhuang } 3745dbdb7daSHaojian Zhuang 3755dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size) 3765dbdb7daSHaojian Zhuang { 3775dbdb7daSHaojian Zhuang return 0; 3785dbdb7daSHaojian Zhuang } 3795dbdb7daSHaojian Zhuang 3805dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size) 3815dbdb7daSHaojian Zhuang { 3825dbdb7daSHaojian Zhuang return 0; 3835dbdb7daSHaojian Zhuang } 3845dbdb7daSHaojian Zhuang 3855dbdb7daSHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params) 3865dbdb7daSHaojian Zhuang { 3875dbdb7daSHaojian Zhuang assert((params != 0) && 3885dbdb7daSHaojian Zhuang ((params->reg_base & EMMC_BLOCK_MASK) == 0) && 3895dbdb7daSHaojian Zhuang ((params->desc_base & EMMC_BLOCK_MASK) == 0) && 3905dbdb7daSHaojian Zhuang ((params->desc_size & EMMC_BLOCK_MASK) == 0) && 3915dbdb7daSHaojian Zhuang (params->desc_size > 0) && 3925dbdb7daSHaojian Zhuang (params->clk_rate > 0) && 3935dbdb7daSHaojian Zhuang ((params->bus_width == EMMC_BUS_WIDTH_1) || 3945dbdb7daSHaojian Zhuang (params->bus_width == EMMC_BUS_WIDTH_4) || 3955dbdb7daSHaojian Zhuang (params->bus_width == EMMC_BUS_WIDTH_8))); 3965dbdb7daSHaojian Zhuang 3975dbdb7daSHaojian Zhuang memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); 3985dbdb7daSHaojian Zhuang emmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, 3995dbdb7daSHaojian Zhuang params->flags); 4005dbdb7daSHaojian Zhuang } 401