1*5dbdb7daSHaojian Zhuang /* 2*5dbdb7daSHaojian Zhuang * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 3*5dbdb7daSHaojian Zhuang * 4*5dbdb7daSHaojian Zhuang * Redistribution and use in source and binary forms, with or without 5*5dbdb7daSHaojian Zhuang * modification, are permitted provided that the following conditions are met: 6*5dbdb7daSHaojian Zhuang * 7*5dbdb7daSHaojian Zhuang * Redistributions of source code must retain the above copyright notice, this 8*5dbdb7daSHaojian Zhuang * list of conditions and the following disclaimer. 9*5dbdb7daSHaojian Zhuang * 10*5dbdb7daSHaojian Zhuang * Redistributions in binary form must reproduce the above copyright notice, 11*5dbdb7daSHaojian Zhuang * this list of conditions and the following disclaimer in the documentation 12*5dbdb7daSHaojian Zhuang * and/or other materials provided with the distribution. 13*5dbdb7daSHaojian Zhuang * 14*5dbdb7daSHaojian Zhuang * Neither the name of ARM nor the names of its contributors may be used 15*5dbdb7daSHaojian Zhuang * to endorse or promote products derived from this software without specific 16*5dbdb7daSHaojian Zhuang * prior written permission. 17*5dbdb7daSHaojian Zhuang * 18*5dbdb7daSHaojian Zhuang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*5dbdb7daSHaojian Zhuang * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*5dbdb7daSHaojian Zhuang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*5dbdb7daSHaojian Zhuang * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*5dbdb7daSHaojian Zhuang * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*5dbdb7daSHaojian Zhuang * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*5dbdb7daSHaojian Zhuang * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*5dbdb7daSHaojian Zhuang * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*5dbdb7daSHaojian Zhuang * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*5dbdb7daSHaojian Zhuang * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*5dbdb7daSHaojian Zhuang * POSSIBILITY OF SUCH DAMAGE. 29*5dbdb7daSHaojian Zhuang */ 30*5dbdb7daSHaojian Zhuang 31*5dbdb7daSHaojian Zhuang #include <arch.h> 32*5dbdb7daSHaojian Zhuang #include <arch_helpers.h> 33*5dbdb7daSHaojian Zhuang #include <assert.h> 34*5dbdb7daSHaojian Zhuang #include <debug.h> 35*5dbdb7daSHaojian Zhuang #include <delay_timer.h> 36*5dbdb7daSHaojian Zhuang #include <dw_mmc.h> 37*5dbdb7daSHaojian Zhuang #include <emmc.h> 38*5dbdb7daSHaojian Zhuang #include <errno.h> 39*5dbdb7daSHaojian Zhuang #include <mmio.h> 40*5dbdb7daSHaojian Zhuang #include <string.h> 41*5dbdb7daSHaojian Zhuang 42*5dbdb7daSHaojian Zhuang #define DWMMC_CTRL (0x00) 43*5dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN (1 << 25) 44*5dbdb7daSHaojian Zhuang #define CTRL_DMA_EN (1 << 5) 45*5dbdb7daSHaojian Zhuang #define CTRL_INT_EN (1 << 4) 46*5dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET (1 << 2) 47*5dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET (1 << 1) 48*5dbdb7daSHaojian Zhuang #define CTRL_RESET (1 << 0) 49*5dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \ 50*5dbdb7daSHaojian Zhuang CTRL_RESET) 51*5dbdb7daSHaojian Zhuang 52*5dbdb7daSHaojian Zhuang #define DWMMC_PWREN (0x04) 53*5dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV (0x08) 54*5dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC (0x0c) 55*5dbdb7daSHaojian Zhuang #define DWMMC_CLKENA (0x10) 56*5dbdb7daSHaojian Zhuang #define DWMMC_TMOUT (0x14) 57*5dbdb7daSHaojian Zhuang #define DWMMC_CTYPE (0x18) 58*5dbdb7daSHaojian Zhuang #define CTYPE_8BIT (1 << 16) 59*5dbdb7daSHaojian Zhuang #define CTYPE_4BIT (1) 60*5dbdb7daSHaojian Zhuang #define CTYPE_1BIT (0) 61*5dbdb7daSHaojian Zhuang 62*5dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ (0x1c) 63*5dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT (0x20) 64*5dbdb7daSHaojian Zhuang #define DWMMC_INTMASK (0x24) 65*5dbdb7daSHaojian Zhuang #define INT_EBE (1 << 15) 66*5dbdb7daSHaojian Zhuang #define INT_SBE (1 << 13) 67*5dbdb7daSHaojian Zhuang #define INT_HLE (1 << 12) 68*5dbdb7daSHaojian Zhuang #define INT_FRUN (1 << 11) 69*5dbdb7daSHaojian Zhuang #define INT_DRT (1 << 9) 70*5dbdb7daSHaojian Zhuang #define INT_RTO (1 << 8) 71*5dbdb7daSHaojian Zhuang #define INT_DCRC (1 << 7) 72*5dbdb7daSHaojian Zhuang #define INT_RCRC (1 << 6) 73*5dbdb7daSHaojian Zhuang #define INT_RXDR (1 << 5) 74*5dbdb7daSHaojian Zhuang #define INT_TXDR (1 << 4) 75*5dbdb7daSHaojian Zhuang #define INT_DTO (1 << 3) 76*5dbdb7daSHaojian Zhuang #define INT_CMD_DONE (1 << 2) 77*5dbdb7daSHaojian Zhuang #define INT_RE (1 << 1) 78*5dbdb7daSHaojian Zhuang 79*5dbdb7daSHaojian Zhuang #define DWMMC_CMDARG (0x28) 80*5dbdb7daSHaojian Zhuang #define DWMMC_CMD (0x2c) 81*5dbdb7daSHaojian Zhuang #define CMD_START (1 << 31) 82*5dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */ 83*5dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY (1 << 21) 84*5dbdb7daSHaojian Zhuang #define CMD_SEND_INIT (1 << 15) 85*5dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD (1 << 14) 86*5dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE (1 << 13) 87*5dbdb7daSHaojian Zhuang #define CMD_WRITE (1 << 10) 88*5dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT (1 << 9) 89*5dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC (1 << 8) 90*5dbdb7daSHaojian Zhuang #define CMD_RESP_LEN (1 << 7) 91*5dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT (1 << 6) 92*5dbdb7daSHaojian Zhuang #define CMD(x) (x & 0x3f) 93*5dbdb7daSHaojian Zhuang 94*5dbdb7daSHaojian Zhuang #define DWMMC_RESP0 (0x30) 95*5dbdb7daSHaojian Zhuang #define DWMMC_RESP1 (0x34) 96*5dbdb7daSHaojian Zhuang #define DWMMC_RESP2 (0x38) 97*5dbdb7daSHaojian Zhuang #define DWMMC_RESP3 (0x3c) 98*5dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS (0x44) 99*5dbdb7daSHaojian Zhuang #define DWMMC_STATUS (0x48) 100*5dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY (1 << 9) 101*5dbdb7daSHaojian Zhuang 102*5dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH (0x4c) 103*5dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x) (x & 0xfff) 104*5dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16) 105*5dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28) 106*5dbdb7daSHaojian Zhuang 107*5dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE (0x64) 108*5dbdb7daSHaojian Zhuang #define DWMMC_BMOD (0x80) 109*5dbdb7daSHaojian Zhuang #define BMOD_ENABLE (1 << 7) 110*5dbdb7daSHaojian Zhuang #define BMOD_FB (1 << 1) 111*5dbdb7daSHaojian Zhuang #define BMOD_SWRESET (1 << 0) 112*5dbdb7daSHaojian Zhuang 113*5dbdb7daSHaojian Zhuang #define DWMMC_DBADDR (0x88) 114*5dbdb7daSHaojian Zhuang #define DWMMC_IDSTS (0x8c) 115*5dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN (0x90) 116*5dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL (0x100) 117*5dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16) 118*5dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN (1 << 0) 119*5dbdb7daSHaojian Zhuang 120*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC (1 << 1) 121*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD (1 << 2) 122*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS (1 << 3) 123*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH (1 << 4) 124*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER (1 << 5) 125*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES (1 << 30) 126*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_OWN (1 << 31) 127*5dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x) ((x) & 0x1fff) 128*5dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) 129*5dbdb7daSHaojian Zhuang 130*5dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8) 131*5dbdb7daSHaojian Zhuang 132*5dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE (1 << 6) 133*5dbdb7daSHaojian Zhuang 134*5dbdb7daSHaojian Zhuang #define TIMEOUT 100000 135*5dbdb7daSHaojian Zhuang 136*5dbdb7daSHaojian Zhuang struct dw_idmac_desc { 137*5dbdb7daSHaojian Zhuang unsigned int des0; 138*5dbdb7daSHaojian Zhuang unsigned int des1; 139*5dbdb7daSHaojian Zhuang unsigned int des2; 140*5dbdb7daSHaojian Zhuang unsigned int des3; 141*5dbdb7daSHaojian Zhuang }; 142*5dbdb7daSHaojian Zhuang 143*5dbdb7daSHaojian Zhuang static void dw_init(void); 144*5dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd); 145*5dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width); 146*5dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size); 147*5dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size); 148*5dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size); 149*5dbdb7daSHaojian Zhuang 150*5dbdb7daSHaojian Zhuang static const emmc_ops_t dw_mmc_ops = { 151*5dbdb7daSHaojian Zhuang .init = dw_init, 152*5dbdb7daSHaojian Zhuang .send_cmd = dw_send_cmd, 153*5dbdb7daSHaojian Zhuang .set_ios = dw_set_ios, 154*5dbdb7daSHaojian Zhuang .prepare = dw_prepare, 155*5dbdb7daSHaojian Zhuang .read = dw_read, 156*5dbdb7daSHaojian Zhuang .write = dw_write, 157*5dbdb7daSHaojian Zhuang }; 158*5dbdb7daSHaojian Zhuang 159*5dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params; 160*5dbdb7daSHaojian Zhuang 161*5dbdb7daSHaojian Zhuang static void dw_update_clk(void) 162*5dbdb7daSHaojian Zhuang { 163*5dbdb7daSHaojian Zhuang unsigned int data; 164*5dbdb7daSHaojian Zhuang 165*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CMD, 166*5dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY | 167*5dbdb7daSHaojian Zhuang CMD_START); 168*5dbdb7daSHaojian Zhuang while (1) { 169*5dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_CMD); 170*5dbdb7daSHaojian Zhuang if ((data & CMD_START) == 0) 171*5dbdb7daSHaojian Zhuang break; 172*5dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); 173*5dbdb7daSHaojian Zhuang assert(data & INT_HLE); 174*5dbdb7daSHaojian Zhuang } 175*5dbdb7daSHaojian Zhuang } 176*5dbdb7daSHaojian Zhuang 177*5dbdb7daSHaojian Zhuang static void dw_set_clk(int clk) 178*5dbdb7daSHaojian Zhuang { 179*5dbdb7daSHaojian Zhuang unsigned int data; 180*5dbdb7daSHaojian Zhuang int div; 181*5dbdb7daSHaojian Zhuang 182*5dbdb7daSHaojian Zhuang assert(clk > 0); 183*5dbdb7daSHaojian Zhuang 184*5dbdb7daSHaojian Zhuang for (div = 1; div < 256; div++) { 185*5dbdb7daSHaojian Zhuang if ((dw_params.clk_rate / (2 * div)) <= clk) { 186*5dbdb7daSHaojian Zhuang break; 187*5dbdb7daSHaojian Zhuang } 188*5dbdb7daSHaojian Zhuang } 189*5dbdb7daSHaojian Zhuang assert(div < 256); 190*5dbdb7daSHaojian Zhuang 191*5dbdb7daSHaojian Zhuang /* wait until controller is idle */ 192*5dbdb7daSHaojian Zhuang do { 193*5dbdb7daSHaojian Zhuang data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS); 194*5dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 195*5dbdb7daSHaojian Zhuang 196*5dbdb7daSHaojian Zhuang /* disable clock before change clock rate */ 197*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0); 198*5dbdb7daSHaojian Zhuang dw_update_clk(); 199*5dbdb7daSHaojian Zhuang 200*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div); 201*5dbdb7daSHaojian Zhuang dw_update_clk(); 202*5dbdb7daSHaojian Zhuang 203*5dbdb7daSHaojian Zhuang /* enable clock */ 204*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1); 205*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0); 206*5dbdb7daSHaojian Zhuang dw_update_clk(); 207*5dbdb7daSHaojian Zhuang } 208*5dbdb7daSHaojian Zhuang 209*5dbdb7daSHaojian Zhuang static void dw_init(void) 210*5dbdb7daSHaojian Zhuang { 211*5dbdb7daSHaojian Zhuang unsigned int data; 212*5dbdb7daSHaojian Zhuang uintptr_t base; 213*5dbdb7daSHaojian Zhuang 214*5dbdb7daSHaojian Zhuang assert((dw_params.reg_base & EMMC_BLOCK_MASK) == 0); 215*5dbdb7daSHaojian Zhuang 216*5dbdb7daSHaojian Zhuang base = dw_params.reg_base; 217*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_PWREN, 1); 218*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL); 219*5dbdb7daSHaojian Zhuang do { 220*5dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_CTRL); 221*5dbdb7daSHaojian Zhuang } while (data); 222*5dbdb7daSHaojian Zhuang 223*5dbdb7daSHaojian Zhuang /* enable DMA in CTRL */ 224*5dbdb7daSHaojian Zhuang data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN; 225*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CTRL, data); 226*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 227*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_INTMASK, 0); 228*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_TMOUT, ~0); 229*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_IDINTEN, ~0); 230*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BLKSIZ, EMMC_BLOCK_SIZE); 231*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024); 232*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff); 233*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET); 234*5dbdb7daSHaojian Zhuang do { 235*5dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_BMOD); 236*5dbdb7daSHaojian Zhuang } while (data & BMOD_SWRESET); 237*5dbdb7daSHaojian Zhuang /* enable DMA in BMOD */ 238*5dbdb7daSHaojian Zhuang data |= BMOD_ENABLE | BMOD_FB; 239*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BMOD, data); 240*5dbdb7daSHaojian Zhuang 241*5dbdb7daSHaojian Zhuang udelay(100); 242*5dbdb7daSHaojian Zhuang dw_set_clk(EMMC_BOOT_CLK_RATE); 243*5dbdb7daSHaojian Zhuang udelay(100); 244*5dbdb7daSHaojian Zhuang } 245*5dbdb7daSHaojian Zhuang 246*5dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd) 247*5dbdb7daSHaojian Zhuang { 248*5dbdb7daSHaojian Zhuang unsigned int op, data, err_mask; 249*5dbdb7daSHaojian Zhuang uintptr_t base; 250*5dbdb7daSHaojian Zhuang int timeout; 251*5dbdb7daSHaojian Zhuang 252*5dbdb7daSHaojian Zhuang assert(cmd); 253*5dbdb7daSHaojian Zhuang 254*5dbdb7daSHaojian Zhuang base = dw_params.reg_base; 255*5dbdb7daSHaojian Zhuang 256*5dbdb7daSHaojian Zhuang switch (cmd->cmd_idx) { 257*5dbdb7daSHaojian Zhuang case EMMC_CMD0: 258*5dbdb7daSHaojian Zhuang op = CMD_SEND_INIT; 259*5dbdb7daSHaojian Zhuang break; 260*5dbdb7daSHaojian Zhuang case EMMC_CMD12: 261*5dbdb7daSHaojian Zhuang op = CMD_STOP_ABORT_CMD; 262*5dbdb7daSHaojian Zhuang break; 263*5dbdb7daSHaojian Zhuang case EMMC_CMD13: 264*5dbdb7daSHaojian Zhuang op = CMD_WAIT_PRVDATA_COMPLETE; 265*5dbdb7daSHaojian Zhuang break; 266*5dbdb7daSHaojian Zhuang case EMMC_CMD8: 267*5dbdb7daSHaojian Zhuang case EMMC_CMD17: 268*5dbdb7daSHaojian Zhuang case EMMC_CMD18: 269*5dbdb7daSHaojian Zhuang op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; 270*5dbdb7daSHaojian Zhuang break; 271*5dbdb7daSHaojian Zhuang case EMMC_CMD24: 272*5dbdb7daSHaojian Zhuang case EMMC_CMD25: 273*5dbdb7daSHaojian Zhuang op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | 274*5dbdb7daSHaojian Zhuang CMD_WAIT_PRVDATA_COMPLETE; 275*5dbdb7daSHaojian Zhuang break; 276*5dbdb7daSHaojian Zhuang default: 277*5dbdb7daSHaojian Zhuang op = 0; 278*5dbdb7daSHaojian Zhuang break; 279*5dbdb7daSHaojian Zhuang } 280*5dbdb7daSHaojian Zhuang op |= CMD_USE_HOLD_REG | CMD_START; 281*5dbdb7daSHaojian Zhuang switch (cmd->resp_type) { 282*5dbdb7daSHaojian Zhuang case 0: 283*5dbdb7daSHaojian Zhuang break; 284*5dbdb7daSHaojian Zhuang case EMMC_RESPONSE_R2: 285*5dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC | 286*5dbdb7daSHaojian Zhuang CMD_RESP_LEN; 287*5dbdb7daSHaojian Zhuang break; 288*5dbdb7daSHaojian Zhuang case EMMC_RESPONSE_R3: 289*5dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT; 290*5dbdb7daSHaojian Zhuang break; 291*5dbdb7daSHaojian Zhuang default: 292*5dbdb7daSHaojian Zhuang op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC; 293*5dbdb7daSHaojian Zhuang break; 294*5dbdb7daSHaojian Zhuang } 295*5dbdb7daSHaojian Zhuang timeout = TIMEOUT; 296*5dbdb7daSHaojian Zhuang do { 297*5dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_STATUS); 298*5dbdb7daSHaojian Zhuang if (--timeout <= 0) 299*5dbdb7daSHaojian Zhuang panic(); 300*5dbdb7daSHaojian Zhuang } while (data & STATUS_DATA_BUSY); 301*5dbdb7daSHaojian Zhuang 302*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 303*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg); 304*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx); 305*5dbdb7daSHaojian Zhuang 306*5dbdb7daSHaojian Zhuang err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE | 307*5dbdb7daSHaojian Zhuang INT_DCRC | INT_DRT | INT_SBE; 308*5dbdb7daSHaojian Zhuang timeout = TIMEOUT; 309*5dbdb7daSHaojian Zhuang do { 310*5dbdb7daSHaojian Zhuang udelay(500); 311*5dbdb7daSHaojian Zhuang data = mmio_read_32(base + DWMMC_RINTSTS); 312*5dbdb7daSHaojian Zhuang 313*5dbdb7daSHaojian Zhuang if (data & err_mask) 314*5dbdb7daSHaojian Zhuang return -EIO; 315*5dbdb7daSHaojian Zhuang if (data & INT_DTO) 316*5dbdb7daSHaojian Zhuang break; 317*5dbdb7daSHaojian Zhuang if (--timeout == 0) { 318*5dbdb7daSHaojian Zhuang ERROR("%s, RINTSTS:0x%x\n", __func__, data); 319*5dbdb7daSHaojian Zhuang panic(); 320*5dbdb7daSHaojian Zhuang } 321*5dbdb7daSHaojian Zhuang } while (!(data & INT_CMD_DONE)); 322*5dbdb7daSHaojian Zhuang 323*5dbdb7daSHaojian Zhuang if (op & CMD_RESP_EXPECT) { 324*5dbdb7daSHaojian Zhuang cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0); 325*5dbdb7daSHaojian Zhuang if (op & CMD_RESP_LEN) { 326*5dbdb7daSHaojian Zhuang cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1); 327*5dbdb7daSHaojian Zhuang cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2); 328*5dbdb7daSHaojian Zhuang cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3); 329*5dbdb7daSHaojian Zhuang } 330*5dbdb7daSHaojian Zhuang } 331*5dbdb7daSHaojian Zhuang return 0; 332*5dbdb7daSHaojian Zhuang } 333*5dbdb7daSHaojian Zhuang 334*5dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width) 335*5dbdb7daSHaojian Zhuang { 336*5dbdb7daSHaojian Zhuang switch (width) { 337*5dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_1: 338*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT); 339*5dbdb7daSHaojian Zhuang break; 340*5dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_4: 341*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT); 342*5dbdb7daSHaojian Zhuang break; 343*5dbdb7daSHaojian Zhuang case EMMC_BUS_WIDTH_8: 344*5dbdb7daSHaojian Zhuang mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT); 345*5dbdb7daSHaojian Zhuang break; 346*5dbdb7daSHaojian Zhuang default: 347*5dbdb7daSHaojian Zhuang assert(0); 348*5dbdb7daSHaojian Zhuang } 349*5dbdb7daSHaojian Zhuang dw_set_clk(clk); 350*5dbdb7daSHaojian Zhuang return 0; 351*5dbdb7daSHaojian Zhuang } 352*5dbdb7daSHaojian Zhuang 353*5dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size) 354*5dbdb7daSHaojian Zhuang { 355*5dbdb7daSHaojian Zhuang struct dw_idmac_desc *desc; 356*5dbdb7daSHaojian Zhuang int desc_cnt, i, last; 357*5dbdb7daSHaojian Zhuang uintptr_t base; 358*5dbdb7daSHaojian Zhuang 359*5dbdb7daSHaojian Zhuang assert(((buf & EMMC_BLOCK_MASK) == 0) && 360*5dbdb7daSHaojian Zhuang ((size % EMMC_BLOCK_SIZE) == 0) && 361*5dbdb7daSHaojian Zhuang (dw_params.desc_size > 0) && 362*5dbdb7daSHaojian Zhuang ((dw_params.reg_base & EMMC_BLOCK_MASK) == 0) && 363*5dbdb7daSHaojian Zhuang ((dw_params.desc_base & EMMC_BLOCK_MASK) == 0) && 364*5dbdb7daSHaojian Zhuang ((dw_params.desc_size & EMMC_BLOCK_MASK) == 0)); 365*5dbdb7daSHaojian Zhuang 366*5dbdb7daSHaojian Zhuang desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) / 367*5dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE; 368*5dbdb7daSHaojian Zhuang assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size); 369*5dbdb7daSHaojian Zhuang 370*5dbdb7daSHaojian Zhuang base = dw_params.reg_base; 371*5dbdb7daSHaojian Zhuang desc = (struct dw_idmac_desc *)dw_params.desc_base; 372*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_BYTCNT, size); 373*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_RINTSTS, ~0); 374*5dbdb7daSHaojian Zhuang for (i = 0; i < desc_cnt; i++) { 375*5dbdb7daSHaojian Zhuang desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; 376*5dbdb7daSHaojian Zhuang desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE); 377*5dbdb7daSHaojian Zhuang desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i; 378*5dbdb7daSHaojian Zhuang desc[i].des3 = dw_params.desc_base + 379*5dbdb7daSHaojian Zhuang (sizeof(struct dw_idmac_desc)) * (i + 1); 380*5dbdb7daSHaojian Zhuang } 381*5dbdb7daSHaojian Zhuang /* first descriptor */ 382*5dbdb7daSHaojian Zhuang desc->des0 |= IDMAC_DES0_FS; 383*5dbdb7daSHaojian Zhuang /* last descriptor */ 384*5dbdb7daSHaojian Zhuang last = desc_cnt - 1; 385*5dbdb7daSHaojian Zhuang (desc + last)->des0 |= IDMAC_DES0_LD; 386*5dbdb7daSHaojian Zhuang (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH); 387*5dbdb7daSHaojian Zhuang (desc + last)->des1 = IDMAC_DES1_BS1(size - (last * 388*5dbdb7daSHaojian Zhuang DWMMC_DMA_MAX_BUFFER_SIZE)); 389*5dbdb7daSHaojian Zhuang /* set next descriptor address as 0 */ 390*5dbdb7daSHaojian Zhuang (desc + last)->des3 = 0; 391*5dbdb7daSHaojian Zhuang 392*5dbdb7daSHaojian Zhuang mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base); 393*5dbdb7daSHaojian Zhuang clean_dcache_range(dw_params.desc_base, 394*5dbdb7daSHaojian Zhuang desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); 395*5dbdb7daSHaojian Zhuang 396*5dbdb7daSHaojian Zhuang return 0; 397*5dbdb7daSHaojian Zhuang } 398*5dbdb7daSHaojian Zhuang 399*5dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size) 400*5dbdb7daSHaojian Zhuang { 401*5dbdb7daSHaojian Zhuang return 0; 402*5dbdb7daSHaojian Zhuang } 403*5dbdb7daSHaojian Zhuang 404*5dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size) 405*5dbdb7daSHaojian Zhuang { 406*5dbdb7daSHaojian Zhuang return 0; 407*5dbdb7daSHaojian Zhuang } 408*5dbdb7daSHaojian Zhuang 409*5dbdb7daSHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params) 410*5dbdb7daSHaojian Zhuang { 411*5dbdb7daSHaojian Zhuang assert((params != 0) && 412*5dbdb7daSHaojian Zhuang ((params->reg_base & EMMC_BLOCK_MASK) == 0) && 413*5dbdb7daSHaojian Zhuang ((params->desc_base & EMMC_BLOCK_MASK) == 0) && 414*5dbdb7daSHaojian Zhuang ((params->desc_size & EMMC_BLOCK_MASK) == 0) && 415*5dbdb7daSHaojian Zhuang (params->desc_size > 0) && 416*5dbdb7daSHaojian Zhuang (params->clk_rate > 0) && 417*5dbdb7daSHaojian Zhuang ((params->bus_width == EMMC_BUS_WIDTH_1) || 418*5dbdb7daSHaojian Zhuang (params->bus_width == EMMC_BUS_WIDTH_4) || 419*5dbdb7daSHaojian Zhuang (params->bus_width == EMMC_BUS_WIDTH_8))); 420*5dbdb7daSHaojian Zhuang 421*5dbdb7daSHaojian Zhuang memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); 422*5dbdb7daSHaojian Zhuang emmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, 423*5dbdb7daSHaojian Zhuang params->flags); 424*5dbdb7daSHaojian Zhuang } 425