📄 hw_sdmmc.c
字号:
/* * Copyright (C) 2006-2007 Pawel Kolodziejski * * Some defines are from linux 2.6 kernel sources * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "types.h"#include "pxa-regs.h"#include "gpio.h"#define STOP_CLOCK (1 << 0)#define START_CLOCK (2 << 0)#define STAT_END_CMD_RES (1 << 13)#define STAT_PRG_DONE (1 << 12)#define STAT_DATA_TRAN_DONE (1 << 11)#define STAT_CLK_EN (1 << 8)#define STAT_RECV_FIFO_FULL (1 << 7)#define STAT_XMIT_FIFO_EMPTY (1 << 6)#define STAT_RES_CRC_ERR (1 << 5)#define STAT_SPI_READ_ERROR_TOKEN (1 << 4)#define STAT_CRC_READ_ERROR (1 << 3)#define STAT_CRC_WRITE_ERROR (1 << 2)#define STAT_TIME_OUT_RESPONSE (1 << 1)#define STAT_READ_TIME_OUT (1 << 0)#define CMDAT_DMAEN (1 << 7)#define CMDAT_INIT (1 << 6)#define CMDAT_BUSY (1 << 5)#define CMDAT_STREAM (1 << 4) /* 1 = stream */#define CMDAT_WRITE (1 << 3) /* 1 = write */#define CMDAT_DATAEN (1 << 2)#define CMDAT_RESP_NONE (0 << 0)#define CMDAT_RESP_SHORT (1 << 0)#define CMDAT_RESP_R2 (2 << 0)#define CMDAT_RESP_R3 (3 << 0)#define TXFIFO_WR_REQ (1 << 6)#define RXFIFO_RD_REQ (1 << 5)#define CLK_IS_OFF (1 << 4)#define STOP_CMD (1 << 3)#define END_CMD_RES (1 << 2)#define PRG_DONE (1 << 1)#define DATA_TRAN_DONE (1 << 0)#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_CARD_BUSY 0x80000000#define MMC_GO_IDLE_STATE 0#define MMC_SEND_OP_COND 1#define MMC_ALL_SEND_CID 2#define MMC_SET_RELATIVE_ADDR 3#define MMC_SELECT_CARD 7#define MMC_SEND_CSD 9#define MMC_SET_BLOCKLEN 16#define MMC_READ_SINGLE_BLOCK 17#define MMC_WRITE_BLOCK 24#define SD_APP_OP_COND 41#define MMC_APP_CMD 55int sd_check_inserted(void) { return GPLR0 & 0x400 ? -1 : 0;}static int sd_error(char *str) { drawText(0, 21, str, 0, 0xf800); for (;;) {}}static int sd_send_cmd(u8 cmd, u32 param, u16 cmdat) { int i; MMC_STRPCL = STOP_CLOCK; for (i = 100; i; i--) { if ((MMC_STAT & STAT_CLK_EN) != STAT_CLK_EN) goto ok1; } sd_error("sd_send_cmd: clock not stopped");ok1: if (cmd == MMC_SET_BLOCKLEN) { MMC_RDTO = 0xffff; MMC_BLKLEN = 512; MMC_NOB = 1; } MMC_CMD = cmd; MMC_ARGH = param >> 16; MMC_ARGL = param & 0xffff; MMC_CMDAT = cmdat; MMC_STRPCL = START_CLOCK; for (i = 300000; i; i--) { if ((MMC_STAT & STAT_END_CMD_RES) == STAT_END_CMD_RES) goto ok2; } sd_error("sd_send_cmd: missing response");ok2: ;}int sd_setup_for_transfer(int addr) { //drawText(0, 18, "MMC_SELECT_CARD ", 0, 0x0000); sd_send_cmd(MMC_SELECT_CARD, addr << 16, CMDAT_RESP_SHORT); sd_read_resp_short(); //drawText(0, 18, "MMC_SET_BLOCKLEN ", 0, 0x0000); sd_send_cmd(MMC_SET_BLOCKLEN, 512, CMDAT_RESP_SHORT); sd_read_resp_short();}int sd_turn_on(void) { int i; CKEN |= CKEN12_MMC; gpo_clear(GPO_A716_SD_POWER_N); mdelay(10); MMC_STRPCL = STOP_CLOCK; for (i = 100; i; i--) { if ((MMC_STAT & STAT_CLK_EN) != STAT_CLK_EN) break; mdelay(1); } MMC_SPI = 0; MMC_RESTO = 64;}int sd_turn_off(void) { int i; MMC_STRPCL = STOP_CLOCK; for (i = 100; i; i--) { if ((MMC_STAT & STAT_CLK_EN) != STAT_CLK_EN) break; mdelay(1); } gpo_set(GPO_A716_SD_POWER_N); //CKEN &= ~CKEN12_MMC;}int sd_read_resp_short(void) { int l; int *response = (int *)0xA3100200; u8 *res = (u8 *)0xA3100200; char string[32]; u32 v; for (l = 0; l < 4; l++) { response[l] = MMC_RES & 0xffff; }/* drawText(0, 19, " ", 0, 0xffff); drawText(0, 20, " ", 0, 0xffff); sprintf(string, "%04x %04x %04x %04x %04x", response[0], response[1], response[2], response[3], response[4]); drawText(0, 19, string, 0, 0x0000);*/}static int sd_read_resp_long(void) { int l; int *response = (int *)0xA3100200; u8 *res = (u8 *)0xA3100200; char string[32]; u32 v; for (l = 0; l < 8; l++) { response[l] = MMC_RES & 0xffff; }/* drawText(0, 19, " ", 0, 0xffff); drawText(0, 20, " ", 0, 0xffff); sprintf(string, "%04x %04x %04x %04x", response[0], response[1], response[2], response[3]); drawText(0, 19, string, 0, 0x0000); sprintf(string, "%04x %04x %04x %04x %04x", response[4], response[5], response[6], response[7], response[8]); drawText(0, 20, string, 0, 0x0000);*/}int sd_card_init(void) { int i; int addr; int *response = (int *)0xA3100200; char string[32]; int is_sd = 0; MMC_CLKRT = 6; // set to minimum clock rate //drawText(0, 18, "MMC_GO_IDLE_STATE ", 0, 0x0000); sd_send_cmd(MMC_GO_IDLE_STATE, 0, CMDAT_RESP_NONE); //mdelay(5000); for (i = 300000; i; i--) { if (is_sd == 0) { //drawText(0, 18, "MMC_APP_CMD ", 0, 0x0000); sd_send_cmd(MMC_APP_CMD, 0, CMDAT_RESP_SHORT); sd_read_resp_short(); //sprintf(string, "%04x", response[0]); //drawText(0, 26, string, 0, 0x0000); //mdelay(5000); if (response[0] != 0x3700) { is_sd = -1; } } //mdelay(5000); //drawText(0, 18, "SD_APP_OP_COND ", 0, 0x0000); //sprintf(string, "%04x", response[0]); //drawText(0, 26, string, 0, 0x0000); //mdelay(5000); if (is_sd == 0) sd_send_cmd(SD_APP_OP_COND, MMC_VDD_32_33 | MMC_VDD_33_34, CMDAT_INIT | CMDAT_RESP_R3); else sd_send_cmd(MMC_SEND_OP_COND, MMC_VDD_32_33 | MMC_VDD_33_34, CMDAT_INIT | CMDAT_RESP_R3); sd_read_resp_short(); //sprintf(string, "%04x", response[0]); //drawText(0, 26, string, 0, 0x0000); //mdelay(5000); if (response[0] == 0x3f80) goto ok1; } sd_error("SD/MMC card not initialised"); return 0;ok1: //drawText(0, 18, "MMC_ALL_SEND_CID ", 0, 0x0000); sd_send_cmd(MMC_ALL_SEND_CID, 0, CMDAT_RESP_R2); sd_read_resp_long(); //mdelay(5000); //drawText(0, 18, "MMC_SET_RELATIVE_ADDR ", 0, 0x0000); sd_send_cmd(MMC_SET_RELATIVE_ADDR, 0, CMDAT_RESP_SHORT); sd_read_resp_short(); if (is_sd == 0) addr = ((response[0] & 0xff) << 8) | ((response[1] & 0xff00) >> 8); else addr = 1; //sprintf(string, "%04x", addr); //drawText(0, 26, string, 0, 0x0000); //mdelay(5000); //drawText(0, 18, "MMC_SEND_CSD ", 0, 0x0000); sd_send_cmd(MMC_SEND_CSD, addr << 16, CMDAT_RESP_R2); sd_read_resp_long(); //mdelay(5000); MMC_CLKRT = 0; // set to maximum clock rate return addr;}int sd_read_sector(u8 *buffer, unsigned long sector) { unsigned long i, r, s; char string[32]; //drawText(0, 18, "MMC_READ_SINGLE_BLOCK ", 0, 0x0000); sd_send_cmd(MMC_READ_SINGLE_BLOCK, sector * 512, CMDAT_RESP_SHORT | CMDAT_DATAEN); sd_read_resp_short(); //mdelay(5000); for (r = 0; r < 16; r++) { for (i = 300000; i; i--) { if (MMC_STAT & STAT_RECV_FIFO_FULL) goto ok2; } sd_error("sd_read_sector: no data in fifo");ok2: ; for (s = 0; s < 32; s++) { buffer[s + (r * 32)] = MMC_RXFIFO & 0xff; } if (MMC_STAT & STAT_READ_TIME_OUT) { sd_error("sd_read_sector: read data timeout"); return -1; } if (MMC_STAT & STAT_CRC_READ_ERROR) { sd_error("sd_read_sector: data crc error"); return -1; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -