1*d8e919c7SMasahiro Yamada /* 2*d8e919c7SMasahiro Yamada * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3*d8e919c7SMasahiro Yamada * 4*d8e919c7SMasahiro Yamada * SPDX-License-Identifier: BSD-3-Clause 5*d8e919c7SMasahiro Yamada */ 6*d8e919c7SMasahiro Yamada 7*d8e919c7SMasahiro Yamada #include <arch_helpers.h> 8*d8e919c7SMasahiro Yamada #include <assert.h> 9*d8e919c7SMasahiro Yamada #include <io/io_block.h> 10*d8e919c7SMasahiro Yamada #include <mmio.h> 11*d8e919c7SMasahiro Yamada #include <platform_def.h> 12*d8e919c7SMasahiro Yamada #include <sys/types.h> 13*d8e919c7SMasahiro Yamada #include <utils_def.h> 14*d8e919c7SMasahiro Yamada 15*d8e919c7SMasahiro Yamada #include "uniphier.h" 16*d8e919c7SMasahiro Yamada 17*d8e919c7SMasahiro Yamada #define MMC_CMD_SWITCH 6 18*d8e919c7SMasahiro Yamada #define MMC_CMD_SELECT_CARD 7 19*d8e919c7SMasahiro Yamada #define MMC_CMD_SEND_CSD 9 20*d8e919c7SMasahiro Yamada #define MMC_CMD_READ_MULTIPLE_BLOCK 18 21*d8e919c7SMasahiro Yamada 22*d8e919c7SMasahiro Yamada #define EXT_CSD_PART_CONF 179 /* R/W */ 23*d8e919c7SMasahiro Yamada 24*d8e919c7SMasahiro Yamada #define MMC_RSP_PRESENT BIT(0) 25*d8e919c7SMasahiro Yamada #define MMC_RSP_136 BIT(1) /* 136 bit response */ 26*d8e919c7SMasahiro Yamada #define MMC_RSP_CRC BIT(2) /* expect valid crc */ 27*d8e919c7SMasahiro Yamada #define MMC_RSP_BUSY BIT(3) /* card may send busy */ 28*d8e919c7SMasahiro Yamada #define MMC_RSP_OPCODE BIT(4) /* response contains opcode */ 29*d8e919c7SMasahiro Yamada 30*d8e919c7SMasahiro Yamada #define MMC_RSP_NONE (0) 31*d8e919c7SMasahiro Yamada #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) 32*d8e919c7SMasahiro Yamada #define MMC_RSP_R1b (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \ 33*d8e919c7SMasahiro Yamada MMC_RSP_BUSY) 34*d8e919c7SMasahiro Yamada #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) 35*d8e919c7SMasahiro Yamada #define MMC_RSP_R3 (MMC_RSP_PRESENT) 36*d8e919c7SMasahiro Yamada #define MMC_RSP_R4 (MMC_RSP_PRESENT) 37*d8e919c7SMasahiro Yamada #define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) 38*d8e919c7SMasahiro Yamada #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) 39*d8e919c7SMasahiro Yamada #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) 40*d8e919c7SMasahiro Yamada 41*d8e919c7SMasahiro Yamada #define SDHCI_DMA_ADDRESS 0x00 42*d8e919c7SMasahiro Yamada #define SDHCI_BLOCK_SIZE 0x04 43*d8e919c7SMasahiro Yamada #define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF)) 44*d8e919c7SMasahiro Yamada #define SDHCI_BLOCK_COUNT 0x06 45*d8e919c7SMasahiro Yamada #define SDHCI_ARGUMENT 0x08 46*d8e919c7SMasahiro Yamada #define SDHCI_TRANSFER_MODE 0x0C 47*d8e919c7SMasahiro Yamada #define SDHCI_TRNS_DMA BIT(0) 48*d8e919c7SMasahiro Yamada #define SDHCI_TRNS_BLK_CNT_EN BIT(1) 49*d8e919c7SMasahiro Yamada #define SDHCI_TRNS_ACMD12 BIT(2) 50*d8e919c7SMasahiro Yamada #define SDHCI_TRNS_READ BIT(4) 51*d8e919c7SMasahiro Yamada #define SDHCI_TRNS_MULTI BIT(5) 52*d8e919c7SMasahiro Yamada #define SDHCI_COMMAND 0x0E 53*d8e919c7SMasahiro Yamada #define SDHCI_CMD_RESP_MASK 0x03 54*d8e919c7SMasahiro Yamada #define SDHCI_CMD_CRC 0x08 55*d8e919c7SMasahiro Yamada #define SDHCI_CMD_INDEX 0x10 56*d8e919c7SMasahiro Yamada #define SDHCI_CMD_DATA 0x20 57*d8e919c7SMasahiro Yamada #define SDHCI_CMD_ABORTCMD 0xC0 58*d8e919c7SMasahiro Yamada #define SDHCI_CMD_RESP_NONE 0x00 59*d8e919c7SMasahiro Yamada #define SDHCI_CMD_RESP_LONG 0x01 60*d8e919c7SMasahiro Yamada #define SDHCI_CMD_RESP_SHORT 0x02 61*d8e919c7SMasahiro Yamada #define SDHCI_CMD_RESP_SHORT_BUSY 0x03 62*d8e919c7SMasahiro Yamada #define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff)) 63*d8e919c7SMasahiro Yamada #define SDHCI_RESPONSE 0x10 64*d8e919c7SMasahiro Yamada #define SDHCI_HOST_CONTROL 0x28 65*d8e919c7SMasahiro Yamada #define SDHCI_CTRL_DMA_MASK 0x18 66*d8e919c7SMasahiro Yamada #define SDHCI_CTRL_SDMA 0x00 67*d8e919c7SMasahiro Yamada #define SDHCI_BLOCK_GAP_CONTROL 0x2A 68*d8e919c7SMasahiro Yamada #define SDHCI_SOFTWARE_RESET 0x2F 69*d8e919c7SMasahiro Yamada #define SDHCI_RESET_CMD 0x02 70*d8e919c7SMasahiro Yamada #define SDHCI_RESET_DATA 0x04 71*d8e919c7SMasahiro Yamada #define SDHCI_INT_STATUS 0x30 72*d8e919c7SMasahiro Yamada #define SDHCI_INT_RESPONSE BIT(0) 73*d8e919c7SMasahiro Yamada #define SDHCI_INT_DATA_END BIT(1) 74*d8e919c7SMasahiro Yamada #define SDHCI_INT_DMA_END BIT(3) 75*d8e919c7SMasahiro Yamada #define SDHCI_INT_ERROR BIT(15) 76*d8e919c7SMasahiro Yamada #define SDHCI_SIGNAL_ENABLE 0x38 77*d8e919c7SMasahiro Yamada 78*d8e919c7SMasahiro Yamada /* RCA assigned by Boot ROM */ 79*d8e919c7SMasahiro Yamada #define UNIPHIER_EMMC_RCA 0x1000 80*d8e919c7SMasahiro Yamada 81*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd { 82*d8e919c7SMasahiro Yamada unsigned int cmdidx; 83*d8e919c7SMasahiro Yamada unsigned int resp_type; 84*d8e919c7SMasahiro Yamada unsigned int cmdarg; 85*d8e919c7SMasahiro Yamada unsigned int is_data; 86*d8e919c7SMasahiro Yamada }; 87*d8e919c7SMasahiro Yamada 88*d8e919c7SMasahiro Yamada static int uniphier_emmc_block_addressing; 89*d8e919c7SMasahiro Yamada 90*d8e919c7SMasahiro Yamada static int uniphier_emmc_send_cmd(uintptr_t host_base, 91*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd *cmd) 92*d8e919c7SMasahiro Yamada { 93*d8e919c7SMasahiro Yamada uint32_t mode = 0; 94*d8e919c7SMasahiro Yamada uint32_t end_bit; 95*d8e919c7SMasahiro Yamada uint32_t stat, flags, dma_addr; 96*d8e919c7SMasahiro Yamada 97*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_INT_STATUS, -1); 98*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_SIGNAL_ENABLE, 0); 99*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_ARGUMENT, cmd->cmdarg); 100*d8e919c7SMasahiro Yamada 101*d8e919c7SMasahiro Yamada if (cmd->is_data) 102*d8e919c7SMasahiro Yamada mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN | 103*d8e919c7SMasahiro Yamada SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ | 104*d8e919c7SMasahiro Yamada SDHCI_TRNS_MULTI; 105*d8e919c7SMasahiro Yamada 106*d8e919c7SMasahiro Yamada mmio_write_16(host_base + SDHCI_TRANSFER_MODE, mode); 107*d8e919c7SMasahiro Yamada 108*d8e919c7SMasahiro Yamada if (!(cmd->resp_type & MMC_RSP_PRESENT)) 109*d8e919c7SMasahiro Yamada flags = SDHCI_CMD_RESP_NONE; 110*d8e919c7SMasahiro Yamada else if (cmd->resp_type & MMC_RSP_136) 111*d8e919c7SMasahiro Yamada flags = SDHCI_CMD_RESP_LONG; 112*d8e919c7SMasahiro Yamada else if (cmd->resp_type & MMC_RSP_BUSY) 113*d8e919c7SMasahiro Yamada flags = SDHCI_CMD_RESP_SHORT_BUSY; 114*d8e919c7SMasahiro Yamada else 115*d8e919c7SMasahiro Yamada flags = SDHCI_CMD_RESP_SHORT; 116*d8e919c7SMasahiro Yamada 117*d8e919c7SMasahiro Yamada if (cmd->resp_type & MMC_RSP_CRC) 118*d8e919c7SMasahiro Yamada flags |= SDHCI_CMD_CRC; 119*d8e919c7SMasahiro Yamada if (cmd->resp_type & MMC_RSP_OPCODE) 120*d8e919c7SMasahiro Yamada flags |= SDHCI_CMD_INDEX; 121*d8e919c7SMasahiro Yamada if (cmd->is_data) 122*d8e919c7SMasahiro Yamada flags |= SDHCI_CMD_DATA; 123*d8e919c7SMasahiro Yamada 124*d8e919c7SMasahiro Yamada if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data) 125*d8e919c7SMasahiro Yamada end_bit = SDHCI_INT_DATA_END; 126*d8e919c7SMasahiro Yamada else 127*d8e919c7SMasahiro Yamada end_bit = SDHCI_INT_RESPONSE; 128*d8e919c7SMasahiro Yamada 129*d8e919c7SMasahiro Yamada mmio_write_16(host_base + SDHCI_COMMAND, 130*d8e919c7SMasahiro Yamada SDHCI_MAKE_CMD(cmd->cmdidx, flags)); 131*d8e919c7SMasahiro Yamada 132*d8e919c7SMasahiro Yamada do { 133*d8e919c7SMasahiro Yamada stat = mmio_read_32(host_base + SDHCI_INT_STATUS); 134*d8e919c7SMasahiro Yamada if (stat & SDHCI_INT_ERROR) 135*d8e919c7SMasahiro Yamada return -EIO; 136*d8e919c7SMasahiro Yamada 137*d8e919c7SMasahiro Yamada if (stat & SDHCI_INT_DMA_END) { 138*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_INT_STATUS, stat); 139*d8e919c7SMasahiro Yamada dma_addr = mmio_read_32(host_base + SDHCI_DMA_ADDRESS); 140*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_DMA_ADDRESS, dma_addr); 141*d8e919c7SMasahiro Yamada } 142*d8e919c7SMasahiro Yamada } while (!(stat & end_bit)); 143*d8e919c7SMasahiro Yamada 144*d8e919c7SMasahiro Yamada return 0; 145*d8e919c7SMasahiro Yamada } 146*d8e919c7SMasahiro Yamada 147*d8e919c7SMasahiro Yamada static int uniphier_emmc_switch_part(uintptr_t host_base, int part_num) 148*d8e919c7SMasahiro Yamada { 149*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd cmd = {0}; 150*d8e919c7SMasahiro Yamada 151*d8e919c7SMasahiro Yamada cmd.cmdidx = MMC_CMD_SWITCH; 152*d8e919c7SMasahiro Yamada cmd.resp_type = MMC_RSP_R1b; 153*d8e919c7SMasahiro Yamada cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24); 154*d8e919c7SMasahiro Yamada 155*d8e919c7SMasahiro Yamada return uniphier_emmc_send_cmd(host_base, &cmd); 156*d8e919c7SMasahiro Yamada } 157*d8e919c7SMasahiro Yamada 158*d8e919c7SMasahiro Yamada static int uniphier_emmc_is_over_2gb(uintptr_t host_base) 159*d8e919c7SMasahiro Yamada { 160*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd cmd = {0}; 161*d8e919c7SMasahiro Yamada uint32_t csd40, csd72; /* CSD[71:40], CSD[103:72] */ 162*d8e919c7SMasahiro Yamada int ret; 163*d8e919c7SMasahiro Yamada 164*d8e919c7SMasahiro Yamada cmd.cmdidx = MMC_CMD_SEND_CSD; 165*d8e919c7SMasahiro Yamada cmd.resp_type = MMC_RSP_R2; 166*d8e919c7SMasahiro Yamada cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; 167*d8e919c7SMasahiro Yamada 168*d8e919c7SMasahiro Yamada ret = uniphier_emmc_send_cmd(host_base, &cmd); 169*d8e919c7SMasahiro Yamada if (ret) 170*d8e919c7SMasahiro Yamada return ret; 171*d8e919c7SMasahiro Yamada 172*d8e919c7SMasahiro Yamada csd40 = mmio_read_32(host_base + SDHCI_RESPONSE + 4); 173*d8e919c7SMasahiro Yamada csd72 = mmio_read_32(host_base + SDHCI_RESPONSE + 8); 174*d8e919c7SMasahiro Yamada 175*d8e919c7SMasahiro Yamada return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3); 176*d8e919c7SMasahiro Yamada } 177*d8e919c7SMasahiro Yamada 178*d8e919c7SMasahiro Yamada static int uniphier_emmc_load_image(uintptr_t host_base, 179*d8e919c7SMasahiro Yamada uint32_t dev_addr, 180*d8e919c7SMasahiro Yamada unsigned long load_addr, 181*d8e919c7SMasahiro Yamada uint32_t block_cnt) 182*d8e919c7SMasahiro Yamada { 183*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd cmd = {0}; 184*d8e919c7SMasahiro Yamada uint8_t tmp; 185*d8e919c7SMasahiro Yamada 186*d8e919c7SMasahiro Yamada assert((load_addr >> 32) == 0); 187*d8e919c7SMasahiro Yamada 188*d8e919c7SMasahiro Yamada mmio_write_32(host_base + SDHCI_DMA_ADDRESS, load_addr); 189*d8e919c7SMasahiro Yamada mmio_write_16(host_base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 512)); 190*d8e919c7SMasahiro Yamada mmio_write_16(host_base + SDHCI_BLOCK_COUNT, block_cnt); 191*d8e919c7SMasahiro Yamada 192*d8e919c7SMasahiro Yamada tmp = mmio_read_8(host_base + SDHCI_HOST_CONTROL); 193*d8e919c7SMasahiro Yamada tmp &= ~SDHCI_CTRL_DMA_MASK; 194*d8e919c7SMasahiro Yamada tmp |= SDHCI_CTRL_SDMA; 195*d8e919c7SMasahiro Yamada mmio_write_8(host_base + SDHCI_HOST_CONTROL, tmp); 196*d8e919c7SMasahiro Yamada 197*d8e919c7SMasahiro Yamada tmp = mmio_read_8(host_base + SDHCI_BLOCK_GAP_CONTROL); 198*d8e919c7SMasahiro Yamada tmp &= ~1; /* clear Stop At Block Gap Request */ 199*d8e919c7SMasahiro Yamada mmio_write_8(host_base + SDHCI_BLOCK_GAP_CONTROL, tmp); 200*d8e919c7SMasahiro Yamada 201*d8e919c7SMasahiro Yamada cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 202*d8e919c7SMasahiro Yamada cmd.resp_type = MMC_RSP_R1; 203*d8e919c7SMasahiro Yamada cmd.cmdarg = dev_addr; 204*d8e919c7SMasahiro Yamada cmd.is_data = 1; 205*d8e919c7SMasahiro Yamada 206*d8e919c7SMasahiro Yamada return uniphier_emmc_send_cmd(host_base, &cmd); 207*d8e919c7SMasahiro Yamada } 208*d8e919c7SMasahiro Yamada 209*d8e919c7SMasahiro Yamada static size_t uniphier_emmc_read(int lba, uintptr_t buf, size_t size) 210*d8e919c7SMasahiro Yamada { 211*d8e919c7SMasahiro Yamada uintptr_t host_base = 0x5a000200; 212*d8e919c7SMasahiro Yamada int ret; 213*d8e919c7SMasahiro Yamada 214*d8e919c7SMasahiro Yamada inv_dcache_range(buf, size); 215*d8e919c7SMasahiro Yamada 216*d8e919c7SMasahiro Yamada if (!uniphier_emmc_block_addressing) 217*d8e919c7SMasahiro Yamada lba *= 512; 218*d8e919c7SMasahiro Yamada 219*d8e919c7SMasahiro Yamada ret = uniphier_emmc_load_image(host_base, lba, buf, size / 512); 220*d8e919c7SMasahiro Yamada 221*d8e919c7SMasahiro Yamada inv_dcache_range(buf, size); 222*d8e919c7SMasahiro Yamada 223*d8e919c7SMasahiro Yamada return ret ? 0 : size; 224*d8e919c7SMasahiro Yamada } 225*d8e919c7SMasahiro Yamada 226*d8e919c7SMasahiro Yamada static const struct io_block_dev_spec uniphier_emmc_dev_spec = { 227*d8e919c7SMasahiro Yamada .buffer = { 228*d8e919c7SMasahiro Yamada .offset = UNIPHIER_BLOCK_BUF_BASE, 229*d8e919c7SMasahiro Yamada .length = UNIPHIER_BLOCK_BUF_SIZE, 230*d8e919c7SMasahiro Yamada }, 231*d8e919c7SMasahiro Yamada .ops = { 232*d8e919c7SMasahiro Yamada .read = uniphier_emmc_read, 233*d8e919c7SMasahiro Yamada }, 234*d8e919c7SMasahiro Yamada .block_size = 512, 235*d8e919c7SMasahiro Yamada }; 236*d8e919c7SMasahiro Yamada 237*d8e919c7SMasahiro Yamada static int uniphier_emmc_hw_init(void) 238*d8e919c7SMasahiro Yamada { 239*d8e919c7SMasahiro Yamada uintptr_t host_base = 0x5a000200; 240*d8e919c7SMasahiro Yamada struct uniphier_mmc_cmd cmd = {0}; 241*d8e919c7SMasahiro Yamada int ret; 242*d8e919c7SMasahiro Yamada 243*d8e919c7SMasahiro Yamada /* 244*d8e919c7SMasahiro Yamada * deselect card before SEND_CSD command. 245*d8e919c7SMasahiro Yamada * Do not check the return code. It fails, but it is OK. 246*d8e919c7SMasahiro Yamada */ 247*d8e919c7SMasahiro Yamada cmd.cmdidx = MMC_CMD_SELECT_CARD; 248*d8e919c7SMasahiro Yamada cmd.resp_type = MMC_RSP_R1; 249*d8e919c7SMasahiro Yamada 250*d8e919c7SMasahiro Yamada uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */ 251*d8e919c7SMasahiro Yamada 252*d8e919c7SMasahiro Yamada /* reset CMD Line */ 253*d8e919c7SMasahiro Yamada mmio_write_8(host_base + SDHCI_SOFTWARE_RESET, 254*d8e919c7SMasahiro Yamada SDHCI_RESET_CMD | SDHCI_RESET_DATA); 255*d8e919c7SMasahiro Yamada while (mmio_read_8(host_base + SDHCI_SOFTWARE_RESET)) 256*d8e919c7SMasahiro Yamada ; 257*d8e919c7SMasahiro Yamada 258*d8e919c7SMasahiro Yamada ret = uniphier_emmc_is_over_2gb(host_base); 259*d8e919c7SMasahiro Yamada if (ret < 0) 260*d8e919c7SMasahiro Yamada return ret; 261*d8e919c7SMasahiro Yamada 262*d8e919c7SMasahiro Yamada uniphier_emmc_block_addressing = ret; 263*d8e919c7SMasahiro Yamada 264*d8e919c7SMasahiro Yamada cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; 265*d8e919c7SMasahiro Yamada 266*d8e919c7SMasahiro Yamada /* select card again */ 267*d8e919c7SMasahiro Yamada ret = uniphier_emmc_send_cmd(host_base, &cmd); 268*d8e919c7SMasahiro Yamada if (ret) 269*d8e919c7SMasahiro Yamada return ret; 270*d8e919c7SMasahiro Yamada 271*d8e919c7SMasahiro Yamada /* switch to Boot Partition 1 */ 272*d8e919c7SMasahiro Yamada ret = uniphier_emmc_switch_part(host_base, 1); 273*d8e919c7SMasahiro Yamada if (ret) 274*d8e919c7SMasahiro Yamada return ret; 275*d8e919c7SMasahiro Yamada 276*d8e919c7SMasahiro Yamada return 0; 277*d8e919c7SMasahiro Yamada } 278*d8e919c7SMasahiro Yamada 279*d8e919c7SMasahiro Yamada int uniphier_emmc_init(uintptr_t *block_dev_spec) 280*d8e919c7SMasahiro Yamada { 281*d8e919c7SMasahiro Yamada int ret; 282*d8e919c7SMasahiro Yamada 283*d8e919c7SMasahiro Yamada ret = uniphier_emmc_hw_init(); 284*d8e919c7SMasahiro Yamada if (ret) 285*d8e919c7SMasahiro Yamada return ret; 286*d8e919c7SMasahiro Yamada 287*d8e919c7SMasahiro Yamada *block_dev_spec = (uintptr_t)&uniphier_emmc_dev_spec; 288*d8e919c7SMasahiro Yamada 289*d8e919c7SMasahiro Yamada return 0; 290*d8e919c7SMasahiro Yamada } 291