Download firmware/hal/mmc.c from Snapkitty/phaser-ags: direct link, hf CLI and curl.
- Browser
- Download file 6.79 kB
-
https://huggingface.co/Snapkitty/phaser-ags/resolve/main/firmware/hal/mmc.c
- Command line
-
hf download hf://Snapkitty/phaser-ags/firmware/hal/mmc.c
-
curl -L -o mmc.c https://huggingface.co/Snapkitty/phaser-ags/resolve/main/firmware/hal/mmc.c
6.79 kB
| /* | |
| * OMAP3530 HSMMC driver | |
| */ | |
| static int mmc_wait_status(mmc_dev_t *dev, uint32_t mask, uint32_t timeout) { | |
| while (timeout--) { | |
| if (reg_read32(dev->base + MMC_STAT) & mask) | |
| return 0; | |
| } | |
| return -1; | |
| } | |
| static void mmc_set_clock(mmc_dev_t *dev, uint32_t freq) { | |
| hw_reg32_t base = dev->base; | |
| /* Stop clock */ | |
| reg_clr32(base + MMC_SYSCTL, MMC_SYSCTL_CEN); | |
| /* Calculate divider: MMC_CLK = SYS_CLK / (2 * CLKD) */ | |
| uint32_t div = 1; | |
| while ((dev->clock_hz / (2 * div)) > freq) div++; | |
| if (div > 0x3FF) div = 0x3FF; | |
| /* Set divider */ | |
| reg32_t sysctl = reg_read32(base + MMC_SYSCTL); | |
| sysctl &= ~(0x3FF << MMC_SYSCTL_CLKD_SHIFT); | |
| sysctl |= (div << MMC_SYSCTL_CLKD_SHIFT); | |
| reg_write32(base + MMC_SYSCTL, sysctl); | |
| /* Enable clock */ | |
| reg_set32(base + MMC_SYSCTL, MMC_SYSCTL_ICE); | |
| while (!(reg_read32(base + MMC_SYSCTL) & MMC_SYSCTL_ICS)) | |
| ; | |
| reg_set32(base + MMC_SYSCTL, MMC_SYSCTL_CEN); | |
| dev->card_clock = dev->clock_hz / (2 * div); | |
| } | |
| int mmc_init(mmc_dev_t *dev, uint32_t base, uint32_t clock_hz) { | |
| dev->base = (hw_reg32_t)base; | |
| dev->clock_hz = clock_hz; | |
| dev->rca = 0; | |
| dev->bus_width = 1; | |
| dev->high_capacity = 0; | |
| /* Soft reset */ | |
| reg_set32(dev->base + MMC_SYSCONFIG, 0x02); | |
| delay_cycles(200); | |
| while (!(reg_read32(dev->base + MMC_SYSSTATUS) & 0x01)) | |
| ; | |
| /* Reset CMD and DAT lines */ | |
| reg_set32(dev->base + MMC_SYSCTL, MMC_SYSCTL_SRD | MMC_SYSCTL_SRH); | |
| delay_cycles(200); | |
| while (reg_read32(dev->base + MMC_SYSCTL) & (MMC_SYSCTL_SRD | MMC_SYSCTL_SRH)) | |
| ; | |
| /* Set voltage to 3.0V */ | |
| reg32_t hctl = reg_read32(dev->base + MMC_HCTL); | |
| hctl &= ~(0xF << MMC_HCTL_SDVS_SHIFT); | |
| hctl |= (6 << MMC_HCTL_SDVS_SHIFT); /* 3.0V */ | |
| reg_write32(dev->base + MMC_HCTL, hctl); | |
| /* Turn on bus power */ | |
| reg_set32(dev->base + MMC_HCTL, MMC_HCTL_SDBP); | |
| delay_cycles(500); | |
| /* Start with identification clock (400kHz) */ | |
| mmc_set_clock(dev, 400000); | |
| /* Enable all interrupts */ | |
| reg_write32(dev->base + MMC_IE, 0xFFFFFFFF); | |
| reg_write32(dev->base + MMC_ISE, 0xFFFFFFFF); | |
| /* Set block length to 512 */ | |
| reg_write32(dev->base + MMC_BLK, (1 << MMC_BLK_NBLK_SHIFT) | MMC_BLOCK_SIZE); | |
| return 0; | |
| } | |
| int mmc_send_cmd(mmc_dev_t *dev, uint32_t cmd, uint32_t arg, | |
| uint32_t rsp_type, uint32_t *rsp) { | |
| hw_reg32_t base = dev->base; | |
| /* Wait for CMD and DAT lines to be free */ | |
| uint32_t timeout = 1000000; | |
| while ((reg_read32(base + MMC_PSTATE) & (MMC_PSTATE_CMDI | MMC_PSTATE_DATI)) && timeout--) | |
| ; | |
| /* Clear status */ | |
| reg_write32(base + MMC_STAT, 0xFFFFFFFF); | |
| /* Set argument */ | |
| reg_write32(base + MMC_ARG, arg); | |
| /* Set command */ | |
| reg32_t cmd_reg = (cmd << MMC_CMD_INDX_SHIFT) | rsp_type; | |
| reg_write32(base + MMC_CMD, cmd_reg); | |
| /* Wait for command complete */ | |
| if (mmc_wait_status(dev, MMC_STAT_CC, 1000000) != 0) | |
| return -1; | |
| /* Read response if requested */ | |
| if (rsp && rsp_type != MMC_CMD_RSP_NONE) { | |
| if (rsp_type == MMC_CMD_RSP_136) { | |
| rsp[0] = reg_read32(base + MMC_RSP10); | |
| rsp[1] = reg_read32(base + MMC_RSP32); | |
| rsp[2] = reg_read32(base + MMC_RSP54); | |
| rsp[3] = reg_read32(base + MMC_RSP76); | |
| } else { | |
| rsp[0] = reg_read32(base + MMC_RSP10); | |
| } | |
| } | |
| /* Clear CC status */ | |
| reg_write32(base + MMC_STAT, MMC_STAT_CC); | |
| return 0; | |
| } | |
| int mmc_detect_card(mmc_dev_t *dev) { | |
| uint32_t rsp[4]; | |
| /* CMD0: GO_IDLE_STATE */ | |
| if (mmc_send_cmd(dev, SD_CMD_GO_IDLE_STATE, 0, MMC_CMD_RSP_NONE, (uint32_t *)0) != 0) | |
| return -1; | |
| /* CMD8: SEND_IF_COND (SD v2.0 check) */ | |
| int cmd8_result = mmc_send_cmd(dev, SD_CMD_SEND_IF_COND, 0x000001AA, | |
| MMC_CMD_RSP_48, rsp); | |
| if (cmd8_result == 0 && (rsp[0] & 0xFF) == 0xAA) { | |
| dev->high_capacity = 1; | |
| } | |
| /* ACMD41: SD_SEND_OP_COND (repeat until busy bit set) */ | |
| uint32_t retry = 1000; | |
| do { | |
| /* CMD55: APP_CMD */ | |
| mmc_send_cmd(dev, SD_CMD_APP_CMD, 0, MMC_CMD_RSP_48, rsp); | |
| /* ACMD41: HCS=1 for SDHC support */ | |
| mmc_send_cmd(dev, SD_ACMD_SD_SEND_OP_COND, | |
| 0x40FF8000, MMC_CMD_RSP_48, rsp); | |
| retry--; | |
| } while (!(rsp[0] & (1 << 31)) && retry > 0); | |
| if (retry == 0) | |
| return -1; | |
| if (rsp[0] & (1 << 30)) | |
| dev->high_capacity = 1; | |
| /* CMD2: ALL_SEND_CID */ | |
| mmc_send_cmd(dev, SD_CMD_ALL_SEND_CID, 0, MMC_CMD_RSP_136, rsp); | |
| /* CMD3: SEND_RELATIVE_ADDR */ | |
| mmc_send_cmd(dev, SD_CMD_SEND_RELATIVE_ADDR, 0, MMC_CMD_RSP_48, rsp); | |
| dev->rca = (uint16_t)(rsp[0] >> 16); | |
| /* Switch to data transfer clock (25MHz) */ | |
| mmc_set_clock(dev, 25000000); | |
| /* CMD7: SELECT_CARD */ | |
| mmc_send_cmd(dev, SD_CMD_SELECT_CARD, (uint32_t)dev->rca << 16, | |
| MMC_CMD_RSP_48B, rsp); | |
| /* ACMD6: SET_BUS_WIDTH to 4-bit */ | |
| mmc_send_cmd(dev, SD_CMD_APP_CMD, (uint32_t)dev->rca << 16, | |
| MMC_CMD_RSP_48, rsp); | |
| mmc_send_cmd(dev, SD_ACMD_SET_BUS_WIDTH, 2, MMC_CMD_RSP_48, rsp); | |
| /* Configure 4-bit bus in HCTL */ | |
| reg32_t hctl = reg_read32(dev->base + MMC_HCTL); | |
| hctl &= ~(0x3 << MMC_HCTL_DTW_SHIFT); | |
| hctl |= (1 << MMC_HCTL_DTW_SHIFT); /* 4-bit */ | |
| reg_write32(dev->base + MMC_HCTL, hctl); | |
| dev->bus_width = 4; | |
| return 0; | |
| } | |
| int mmc_read_block(mmc_dev_t *dev, uint32_t block, uint8_t *buf) { | |
| hw_reg32_t base = dev->base; | |
| /* Set block count and length */ | |
| reg_write32(base + MMC_BLK, (1 << MMC_BLK_NBLK_SHIFT) | MMC_BLOCK_SIZE); | |
| /* For standard capacity cards, address is byte offset */ | |
| uint32_t addr = dev->high_capacity ? block : (block * MMC_BLOCK_SIZE); | |
| /* CMD17: READ_SINGLE_BLOCK */ | |
| reg_write32(base + MMC_ARG, addr); | |
| reg32_t cmd_reg = (SD_CMD_READ_SINGLE_BLOCK << MMC_CMD_INDX_SHIFT) | |
| | MMC_CMD_RSP_48B | MMC_CMD_DP; | |
| reg_write32(base + MMC_CMD, cmd_reg); | |
| /* Wait for transfer complete */ | |
| if (mmc_wait_status(dev, MMC_STAT_TC, 5000000) != 0) | |
| return -1; | |
| /* Read data from FIFO */ | |
| uint32_t *buf32 = (uint32_t *)buf; | |
| for (int i = 0; i < MMC_BLOCK_SIZE / 4; i++) { | |
| while (!(reg_read32(base + MMC_PSTATE) & (1 << 4))) /* BREN */ | |
| ; | |
| buf32[i] = reg_read32(base + MMC_DATA); | |
| } | |
| /* Clear status */ | |
| reg_write32(base + MMC_STAT, 0xFFFFFFFF); | |
| return 0; | |
| } | |
| int mmc_read_blocks(mmc_dev_t *dev, uint32_t start, uint8_t *buf, uint32_t count) { | |
| for (uint32_t i = 0; i < count; i++) { | |
| if (mmc_read_block(dev, start + i, buf + i * MMC_BLOCK_SIZE) != 0) | |
| return -1; | |
| } | |
| return 0; | |
| } | |