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