182 lines
4.4 KiB
C
182 lines
4.4 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <config.h>
|
||
|
|
|
||
|
|
#ifdef CONFIG_GENERIC_MMC
|
||
|
|
#include <asm/arch/platform.h>
|
||
|
|
#include <compiler.h>
|
||
|
|
|
||
|
|
#ifndef CONFIG_ASIC
|
||
|
|
#define DELAY_US 10
|
||
|
|
#else
|
||
|
|
#define DELAY_US 1000
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define MMC_BLK_SZ 512
|
||
|
|
|
||
|
|
/* mmc.h */
|
||
|
|
#define MMC_CMD_GO_IDLE_STATE 0
|
||
|
|
#define MMC_CMD_SEND_OP_COND 1
|
||
|
|
#define MMC_CMD_ALL_SEND_CID 2
|
||
|
|
#define MMC_CMD_SET_RELATIVE_ADDR 3
|
||
|
|
#define MMC_CMD_SET_DSR 4
|
||
|
|
#define MMC_CMD_SWITCH 6
|
||
|
|
#define MMC_CMD_SELECT_CARD 7
|
||
|
|
#define MMC_CMD_SEND_EXT_CSD 8
|
||
|
|
#define MMC_CMD_SEND_CSD 9
|
||
|
|
#define MMC_CMD_SEND_CID 10
|
||
|
|
#define MMC_CMD_STOP_TRANSMISSION 12
|
||
|
|
#define MMC_CMD_SEND_STATUS 13
|
||
|
|
#define MMC_CMD_SET_BLOCKLEN 16
|
||
|
|
#define MMC_CMD_READ_SINGLE_BLOCK 17
|
||
|
|
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
|
||
|
|
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
|
||
|
|
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
|
||
|
|
#define MMC_CMD_APP_CMD 55
|
||
|
|
#define SD_CMD_SEND_IF_COND 8
|
||
|
|
#define SD_CMD_APP_SEND_OP_COND 41
|
||
|
|
#define SD_CMD_APP_SET_BUS_WIDTH 6
|
||
|
|
|
||
|
|
#define OCR_BUSY 0x80000000
|
||
|
|
#define OCR_HCS 0x40000000
|
||
|
|
|
||
|
|
#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
|
||
|
|
#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
|
||
|
|
|
||
|
|
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */
|
||
|
|
|
||
|
|
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
|
||
|
|
#define EXT_CSD_HS_TIMING 185 /* R/W */
|
||
|
|
|
||
|
|
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
|
||
|
|
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
|
||
|
|
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
|
||
|
|
|
||
|
|
static inline void delay(unsigned int cnt)
|
||
|
|
{
|
||
|
|
while (cnt--)
|
||
|
|
__asm__ __volatile__("nop");
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef CONFIG_SDHCI
|
||
|
|
#define SDHCI_BUFFER 0x20
|
||
|
|
#define SDHCI_INT_STATUS 0x30
|
||
|
|
#define SDHCI_INT_DATA_AVAIL 0x00000020
|
||
|
|
#define SDHCI_INT_ERROR_MASK 0xFFFF8000
|
||
|
|
|
||
|
|
#define debug_printf(fmt, args...) ;
|
||
|
|
|
||
|
|
static inline unsigned int sdhci_readl(unsigned addr)
|
||
|
|
{
|
||
|
|
uintptr_t reg_addr = EMMC_BASE_REG + addr;
|
||
|
|
|
||
|
|
return *((volatile unsigned *) (reg_addr));
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline void sdhci_writel(unsigned val, unsigned addr)
|
||
|
|
{
|
||
|
|
uintptr_t reg_addr = EMMC_BASE_REG + addr;
|
||
|
|
|
||
|
|
(*(volatile unsigned *) (reg_addr)) = (val);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void sdhci_read_block_pio(void *data_addr, unsigned int block)
|
||
|
|
{
|
||
|
|
const unsigned int offset = sizeof(unsigned int);
|
||
|
|
unsigned int size;
|
||
|
|
unsigned char *buf;
|
||
|
|
|
||
|
|
size = MMC_BLK_SZ;
|
||
|
|
buf = (unsigned char *)data_addr + MMC_BLK_SZ * block;
|
||
|
|
while (size) {
|
||
|
|
*(unsigned int *)buf = sdhci_readl(SDHCI_BUFFER);
|
||
|
|
buf += offset;
|
||
|
|
size -= offset;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int sdhci_check_int_status(unsigned int mask, unsigned int timeout)
|
||
|
|
{
|
||
|
|
unsigned int reg;
|
||
|
|
|
||
|
|
for (;;) {
|
||
|
|
reg = sdhci_readl(SDHCI_INT_STATUS);
|
||
|
|
if (reg & mask)
|
||
|
|
break;
|
||
|
|
if (!(--timeout)) {
|
||
|
|
debug_printf("wait int status time out, reg = 0x%x, mask = 0x%x\n",
|
||
|
|
reg, mask);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (reg & SDHCI_INT_ERROR_MASK) {
|
||
|
|
debug_printf("int err: reg = 0x%x\n", reg);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
delay(1000 * DELAY_US); /* ms converted to us multiplied by 1000 */
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void copy_step1_to_ddr(unsigned int *dst, unsigned int *src, unsigned int size)
|
||
|
|
{
|
||
|
|
const unsigned int cycle = size / sizeof(unsigned int);
|
||
|
|
unsigned int i;
|
||
|
|
|
||
|
|
for (i = 0; i < cycle; i++)
|
||
|
|
*dst++ = *src++;
|
||
|
|
}
|
||
|
|
|
||
|
|
#define CP_STEP1_SIZE 0x6000
|
||
|
|
int sdhci_read_boot_data(void *data_addr, unsigned int data_size)
|
||
|
|
{
|
||
|
|
const unsigned int timeout = 2000; /* 2s timeout: 2000000 * 1us */
|
||
|
|
unsigned int blocks = 0;
|
||
|
|
unsigned int read_block;
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
if (data_size <= CP_STEP1_SIZE) {
|
||
|
|
copy_step1_to_ddr((void *)data_addr, (void *)RAM_START_ADRS, data_size);
|
||
|
|
return 0;
|
||
|
|
} else {
|
||
|
|
copy_step1_to_ddr((void *)data_addr, (void *)RAM_START_ADRS, CP_STEP1_SIZE);
|
||
|
|
data_addr += CP_STEP1_SIZE;
|
||
|
|
data_size -= CP_STEP1_SIZE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (data_size % MMC_BLK_SZ) {
|
||
|
|
debug_printf("sdhci_read_boot_data error\n");
|
||
|
|
debug_printf("data_size:%d not round by block size\n", data_size);
|
||
|
|
read_block = data_size / MMC_BLK_SZ + 1;
|
||
|
|
} else {
|
||
|
|
read_block = data_size / MMC_BLK_SZ;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (1) {
|
||
|
|
ret = sdhci_check_int_status(SDHCI_INT_DATA_AVAIL, timeout);
|
||
|
|
if (ret) {
|
||
|
|
debug_printf("wait data available int time out\n");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
sdhci_writel(SDHCI_INT_DATA_AVAIL, SDHCI_INT_STATUS);
|
||
|
|
sdhci_read_block_pio(data_addr, blocks);
|
||
|
|
|
||
|
|
blocks++;
|
||
|
|
if (blocks == read_block)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void emmc_boot_read(void *ptr, unsigned int size)
|
||
|
|
{
|
||
|
|
sdhci_read_boot_data(ptr, size);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
#endif
|