sd-card.c revision 161370
1/*- 2 * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * This software is derived from software provide by Kwikbyte who specifically 25 * disclaimed copyright on the code. 26 * 27 * $FreeBSD: head/sys/boot/arm/at91/libat91/sd-card.c 161370 2006-08-16 23:39:58Z imp $ 28 */ 29 30//*---------------------------------------------------------------------------- 31//* ATMEL Microcontroller Software Support - ROUSSET - 32//*---------------------------------------------------------------------------- 33//* The software is delivered "AS IS" without warranty or condition of any 34//* kind, either express, implied or statutory. This includes without 35//* limitation any warranty or condition with respect to merchantability or 36//* fitness for any particular purpose, or against the infringements of 37//* intellectual property rights of others. 38//*---------------------------------------------------------------------------- 39//* File Name : main.c 40//* Object : main application written in C 41//* Creation : FB 21/11/2002 42//* 43//*---------------------------------------------------------------------------- 44#include "at91rm9200.h" 45#include "lib_AT91RM9200.h" 46#include "mci_device.h" 47#include "lib.h" 48#include "sd-card.h" 49 50#define AT91C_MCI_TIMEOUT 1000000 /* For AT91F_MCIDeviceWaitReady */ 51#define BUFFER_SIZE_MCI_DEVICE 512 52#define MASTER_CLOCK 60000000 53 54//Private functions 55//static void initInts(void); 56static void AT91F_MCI_Handler(void); 57 58//* Global Variables 59AT91S_MciDeviceFeatures MCI_Device_Features; 60AT91S_MciDeviceDesc MCI_Device_Desc; 61AT91S_MciDevice MCI_Device; 62char Buffer[BUFFER_SIZE_MCI_DEVICE]; 63 64/****************************************************************************** 65**Error return codes 66******************************************************************************/ 67#define MCI_UNSUPP_SIZE_ERROR 5 68#define MCI_UNSUPP_OFFSET_ERROR 6 69 70//*---------------------------------------------------------------------------- 71//* \fn AT91F_MCIDeviceWaitReady 72//* \brief Wait for MCI Device ready 73//*---------------------------------------------------------------------------- 74static void 75AT91F_MCIDeviceWaitReady(unsigned int timeout) 76{ 77 volatile int status; 78 79 do 80 { 81 status = AT91C_BASE_MCI->MCI_SR; 82 timeout--; 83 } 84 while( !(status & AT91C_MCI_NOTBUSY) && (timeout>0) ); 85 86#if IMP_DEBUG 87 if (timeout == 0) 88 printf("Timeout, status is 0x%x\r\n", status); 89#endif 90 91 //TODO: Make interrupts work! 92 AT91F_MCI_Handler(); 93} 94 95#if 0 96int 97MCI_write (unsigned dest, char* source, unsigned length) 98{ 99 unsigned sectorLength = MCI_Device.pMCI_DeviceFeatures->Max_Read_DataBlock_Lenfgth; 100 unsigned offset = dest % sectorLength; 101 AT91S_MCIDeviceStatus status; 102 int sizeToWrite; 103 104#if IMP_DEBUG 105 printf("\r\n"); 106#endif 107 108 //See if we are requested to write partial sectors, and have the capability to do so 109 if ((length % sectorLength) && !(MCI_Device_Features.Write_Partial)) 110 //Return error if appropriat 111 return MCI_UNSUPP_SIZE_ERROR; 112 113 //See if we are requested to write to anywhere but a sectors' boundary 114 //and have the capability to do so 115 if ((offset) && !(MCI_Device_Features.Write_Partial)) 116 //Return error if appropriat 117 return MCI_UNSUPP_OFFSET_ERROR; 118 119 //If the address we're trying to write != sector boundary 120 if (offset) 121 { 122 //* Wait MCI Device Ready 123 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 124 125 //Calculate the nr of bytes to write 126 sizeToWrite = sectorLength - offset; 127 //Do the writing 128 status = AT91F_MCI_WriteBlock(&MCI_Device, dest, (unsigned int*)source, sizeToWrite); 129 //TODO:Status checking 130 131 //Update counters & pointers 132 length -= sizeToWrite; 133 dest += sizeToWrite; 134 source += sizeToWrite; 135 } 136 137 //As long as there is data to write 138 while (length) 139 { 140 //See if we've got at least a sector to write 141 if (length > sectorLength) 142 sizeToWrite = sectorLength; 143 //Else just write the remainder 144 else 145 sizeToWrite = length; 146 147 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 148 //Do the writing 149 status = AT91F_MCI_WriteBlock(&MCI_Device, dest, (unsigned int*)source, sizeToWrite); 150 //TODO:Status checking 151 152 //Update counters & pointers 153 length -= sizeToWrite; 154 dest += sizeToWrite; 155 source += sizeToWrite; 156 } 157 158 return 0; 159} 160#endif 161 162inline static unsigned int 163swap(unsigned int a) 164{ 165 return (((a & 0xff) << 24) | ((a & 0xff00) << 8) | ((a & 0xff0000) >> 8) 166 | ((a & 0xff000000) >> 24)); 167} 168 169int 170MCI_read(char* dest, unsigned source, unsigned length) 171{ 172 unsigned sectorLength = MCI_Device.pMCI_DeviceFeatures->Max_Read_DataBlock_Length; 173 unsigned log2sl = MCI_Device.pMCI_DeviceFeatures->READ_BL_LEN; 174 unsigned slmask = ((1 << log2sl) - 1); 175// unsigned sector = (unsigned)source >> log2sl; 176 unsigned offset = (unsigned)source & slmask; 177 AT91S_MCIDeviceStatus status; 178 int sizeToRead; 179 unsigned int *walker; 180 181#if IMP_DEBUG 182 printf("Reading 0x%x bytes into ARM Addr 0x%x from card offset 0x%x\r\n", 183 length, dest, source); 184#endif 185 186 187 //See if we are requested to read partial sectors, and have the capability to do so 188 if ((length & slmask) && !(MCI_Device_Features.Read_Partial)) 189 //Return error if appropriat 190 return MCI_UNSUPP_SIZE_ERROR; 191 192 //See if we are requested to read from anywhere but a sectors' boundary 193 //and have the capability to do so 194 if ((offset) && !(MCI_Device_Features.Read_Partial)) 195 //Return error if appropriat 196 return MCI_UNSUPP_OFFSET_ERROR; 197 198 //If the address we're trying to read != sector boundary 199 if (offset) { 200 //* Wait MCI Device Ready 201 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 202 203 //Calculate the nr of bytes to read 204 sizeToRead = sectorLength - offset; 205 //Do the writing 206 status = AT91F_MCI_ReadBlock(&MCI_Device, source, (unsigned int*)dest, sizeToRead); 207 //TODO:Status checking 208 if (status != AT91C_READ_OK) { 209#if IMP_DEBUG 210 printf("STATUS is 0x%x\r\n", status); 211#endif 212 return -1; 213 } 214 215 //* Wait MCI Device Ready 216 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 217 // Fix erratum in MCI part 218 for (walker = (unsigned int *)dest; 219 walker < (unsigned int *)(dest + sizeToRead); walker++) 220 *walker = swap(*walker); 221 222 //Update counters & pointers 223 length -= sizeToRead; 224 dest += sizeToRead; 225 source += sizeToRead; 226 } 227 228 //As long as there is data to read 229 while (length) 230 { 231 //See if we've got at least a sector to read 232 if (length > sectorLength) 233 sizeToRead = sectorLength; 234 //Else just write the remainder 235 else 236 sizeToRead = length; 237 238 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 239 //Do the writing 240 status = AT91F_MCI_ReadBlock(&MCI_Device, source, (unsigned int*)dest, sizeToRead); 241#if IMP_DEBUG 242 printf("Reading 0x%x Addr 0x%x card 0x%x\r\n", 243 sizeToRead, dest, source); 244#endif 245 246 //TODO:Status checking 247 if (status != AT91C_READ_OK) { 248#if IMP_DEBUG 249 printf("STATUS is 0x%x\r\n", status); 250#endif 251 return -1; 252 } 253 254 //* Wait MCI Device Ready 255 AT91F_MCIDeviceWaitReady(AT91C_MCI_TIMEOUT); 256 257 // Fix erratum in MCI part 258 for (walker = (unsigned int *)dest; 259 walker < (unsigned int *)(dest + sizeToRead); walker++) 260 *walker = swap(*walker); 261 262 //Update counters & pointers 263 length -= sizeToRead; 264 dest += sizeToRead; 265 source += sizeToRead; 266 } 267 268 return 0; 269} 270 271 272//*---------------------------------------------------------------------------- 273//* \fn AT91F_CfgDevice 274//* \brief This function is used to initialise MMC or SDCard Features 275//*---------------------------------------------------------------------------- 276static void AT91F_CfgDevice(void) 277{ 278 // Init Device Structure 279 280 MCI_Device_Features.Relative_Card_Address = 0; 281 MCI_Device_Features.Card_Inserted = AT91C_SD_CARD_INSERTED; 282 MCI_Device_Features.Max_Read_DataBlock_Length = 0; 283 MCI_Device_Features.Max_Write_DataBlock_Length = 0; 284 MCI_Device_Features.Read_Partial = 0; 285 MCI_Device_Features.Write_Partial = 0; 286 MCI_Device_Features.Erase_Block_Enable = 0; 287 MCI_Device_Features.Sector_Size = 0; 288 MCI_Device_Features.Memory_Capacity = 0; 289 MCI_Device_Desc.state = AT91C_MCI_IDLE; 290 MCI_Device_Desc.SDCard_bus_width = AT91C_MCI_SCDBUS; 291 MCI_Device.pMCI_DeviceDesc = &MCI_Device_Desc; 292 MCI_Device.pMCI_DeviceFeatures = &MCI_Device_Features; 293 294} 295 296static void AT91F_MCI_Handler(void) 297{ 298 int status; 299 300// status = ( AT91C_BASE_MCI->MCI_SR & AT91C_BASE_MCI->MCI_IMR ); 301 status = AT91C_BASE_MCI->MCI_SR; 302 303 AT91F_MCI_Device_Handler(&MCI_Device,status); 304} 305 306//*---------------------------------------------------------------------------- 307//* \fn main 308//* \brief main function 309//*---------------------------------------------------------------------------- 310int 311sdcard_init(void) 312{ 313/////////////////////////////////////////////////////////////////////////////// 314// MCI Init : common to MMC and SDCard 315/////////////////////////////////////////////////////////////////////////////// 316 317 //initInts(); 318 319 // Init MCI for MMC and SDCard interface 320 AT91F_MCI_CfgPIO(); 321 AT91F_MCI_CfgPMC(); 322 AT91F_PDC_Open(AT91C_BASE_PDC_MCI); 323 324 // Init MCI Device Structures 325 AT91F_CfgDevice(); 326 327 AT91F_MCI_Configure(AT91C_BASE_MCI, 328 AT91C_MCI_DTOR_1MEGA_CYCLES, 329 AT91C_MCI_MR_PDCMODE, // 15MHz for MCK = 60MHz (CLKDIV = 1) 330 AT91C_MCI_SDCARD_4BITS_SLOTA); 331 332 if (AT91F_MCI_SDCard_Init(&MCI_Device) != AT91C_INIT_OK) 333 return 0; 334 return 1; 335} 336