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