/* This code was original written by Ulrich Radig and modified by Embedded Artists AB (www.embeddedartists.com). 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 #include #include #include #define MMC_Enable() PUT32(IO1CLR, 1l << 22) #define MMC_Disable() PUT32(IO1SET, 1l << 22) #define mmc_spi_cfg() spi_set_clock(8); spi_set_cfg(0, 1, 0); static unsigned char Write_Command_MMC (unsigned char *CMD); static void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, unsigned short int Bytes); /* initialize the hardware */ int mmc_hw_init(void) { unsigned long a; unsigned short int Timeout = 0; unsigned char b; unsigned char CMD[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95}; /* set-up GPIO and SPI */ (*((volatile unsigned long *)PINSEL2)) &= ~(1l << 3); /* clear bit 3 */ (*((volatile unsigned long *)IO1DIR)) |= (1l << 22); /* set bit 22 (output) */ MMC_Disable(); spi_lock(); spi_set_clock(248); spi_set_cfg(0, 1, 0); MMC_Enable(); /* waste some time */ for(a=0; a < 20000; a++) asm("nop"); /* Put the MMC/SD-card into SPI-mode */ for (b = 0; b < 10; b++) /* Sends min 74+ clocks to the MMC/SD-card */ spi_write(0xff); /* Sends command CMD0 to MMC/SD-card */ while (Write_Command_MMC(CMD) != 1) { if (Timeout++ > 200) { MMC_Disable(); spi_unlock(); return(1); /* Abort with command 1 (return 1) */ } } /* Sends Command CMD1 an MMC/SD-card */ Timeout = 0; CMD[0] = 0x41;/* Command 1 */ CMD[5] = 0xFF; while (Write_Command_MMC(CMD) != 0) { if (Timeout++ > 200) { MMC_Disable(); spi_unlock(); return (2); /* Abort with command 2 (return 2) */ } } MMC_Disable(); spi_unlock(); return 0; } /* ############################################################################ Sends a command to the MMC/SD-card ######################################################################### */ static unsigned char Write_Command_MMC (unsigned char *CMD) { unsigned char a, tmp = 0xff; unsigned short int Timeout = 0; MMC_Disable(); spi_write(0xFF); MMC_Enable(); for (a = 0; a < 0x06; a++) spi_write(*CMD++); while (tmp == 0xff) { tmp = spi_read(); if (Timeout++ > 5000) break; } return (tmp); } /* ############################################################################ Routine to read the CID register from the MMC/SD-card (16 bytes) ######################################################################### */ void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, unsigned short int Bytes) { unsigned short int a; spi_lock(); mmc_spi_cfg(); MMC_Enable(); if (Write_Command_MMC(CMD) != 0) { MMC_Disable(); spi_unlock(); return; } while (spi_read() != 0xfe) {}; for (a = 0; a < Bytes; a++) *Buffer++ = spi_read(); /* Read the CRC-byte */ spi_read(); /* CRC - byte is discarded */ spi_read(); /* CRC - byte is discarded */ /* set MMC_Chip_Select to high (MMC/SD-card Inaktiv) */ MMC_Disable(); spi_unlock(); return; } /* ############################################################################ Routine to read a block (512 bytes) from the MMC/SD-card ######################################################################### */ unsigned char mmc_read_sector (unsigned long addr,unsigned char *Buffer) { /* Command 16 to read aBlocks from the MMC/SD - caed */ unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; /* The address on the MMC/SD-card is in bytes, addr is transformed from blocks to bytes and the result is placed into the command */ addr = addr << 9; /* addr = addr * 512 */ CMD[1] = ((addr & 0xFF000000) >> 24); CMD[2] = ((addr & 0x00FF0000) >> 16); CMD[3] = ((addr & 0x0000FF00) >> 8 ); MMC_Read_Block(CMD, Buffer, 512); return (0); } /* ############################################################################ Routine to write a block (512 byte) to the MMC/SD-card ######################################################################### */ unsigned char mmc_write_sector (unsigned long addr,unsigned char *Buffer) { unsigned char tmp, a; unsigned short int b; /* Command 24 to write a block to the MMC/SD - card */ unsigned char CMD[] = {0x58, 0x00, 0x00, 0x00, 0x00, 0xFF}; /* The address on the MMC/SD-card is in bytes, addr is transformed from blocks to bytes and the result is placed into the command */ addr = addr << 9; /* addr = addr * 512 */ CMD[1] = ((addr & 0xFF000000) >> 24); CMD[2] = ((addr & 0x00FF0000) >> 16); CMD[3] = ((addr & 0x0000FF00) >> 8 ); spi_lock(); mmc_spi_cfg(); MMC_Enable(); /* Send command CMD24 to the MMC/SD-card (Write 1 Block/512 Bytes) */ tmp = Write_Command_MMC(CMD); if (tmp != 0) { MMC_Disable(); spi_unlock(); return(tmp); } /* Do a short delay and send a clock-pulse to the MMC/SD-card */ for (a = 0; a < 100; a++) spi_read(); /* Send a start byte to the MMC/SD-card */ spi_write(0xFE); /* Write the block (512 bytes) to the MMC/SD-card */ for (b = 0; b < 512; b++) spi_write(*Buffer++); /* write the CRC-Byte */ spi_write(0xFF); /* write a dummy CRC */ spi_write(0xFF); /* CRC code is not used */ /* Wait for MMC/SD-card busy */ while (spi_read() != 0xff) {}; /* set MMC_Chip_Select to high (MMC/SD-card inactive) */ MMC_Disable(); spi_unlock(); return (0); } /* ######################################################################### Routine to read the CSD register from the MMC/SD-card (16 bytes) ######################################################################### */ unsigned char mmc_read_csd (unsigned char *Buffer) { /* Command to read the CSD register */ unsigned char CMD[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0xFF}; MMC_Read_Block(CMD, Buffer, 16); return (0); }