Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / firmware / lib / sd.c
1 /* -*- c -*- */
2 /*
3  * Copyright 2008 Ettus Research LLC
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "sd.h"
20 #include "memory_map.h"
21 #include "stdint.h"
22 #include "stdio.h"
23
24 static inline void
25 sd_packarg(unsigned char *argument,unsigned int value)
26 {
27   argument[3] = (unsigned char)(value >> 24);
28   argument[2] = (unsigned char)(value >> 16);
29   argument[1] = (unsigned char)(value >> 8);
30   argument[0] = (unsigned char)(value);
31 }
32
33 int
34 sd_init(void)
35 {
36   unsigned char response[5];
37   unsigned char argument[4];
38   int i,j;
39
40   for(i=0;i<4;i++)
41     argument[i] = 0;
42
43   // Set clock to less than 400 kHz to start out
44   sdspi_regs->clkdiv = 128;
45
46   // Delay at least 74 cycles
47   sd_assert_cs();
48   for(i = 0; i < 100; i++)
49     sd_send_byte(SD_IDLE);
50   sd_deassert_cs();
51   
52   // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58
53   // Put card in idle state
54   if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0)
55     return 0;  // Something went wrong in command
56
57   j = 0;
58   do {
59     j++;
60     if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1)
61       sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument);
62     else
63       j = SD_IDLE_WAIT_MAX;
64   }
65   while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX));
66
67   if(j>= SD_IDLE_WAIT_MAX)  // IDLE timeout exceeded, card asleep
68     return 0;
69   
70   // CMD58 reads the SD card capabilities
71   if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0)
72     return 0;  // CMD58 FAIL
73
74   if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33)
75     return 0;  // Card doesn't do 3.3V
76
77   //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]);
78
79   // Set blocklen here
80   sd_packarg(argument,SD_BLOCKLEN);
81   if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0)
82     return 0;    // Set Blocklen failed
83   
84   // Reset back to high speed
85   sdspi_regs->clkdiv = 4;
86   //puts("finished init\n");
87   return 1;
88 }
89
90 int sd_send_command(unsigned char cmd,unsigned char response_type,
91                     unsigned char *response,unsigned char *argument)
92 {
93   int i;
94   char response_length;
95   unsigned char tmp;
96
97   sd_assert_cs();
98   sd_send_byte((cmd & 0x3F) | 0x40);
99   for(i=3;i>=0;i--)
100     sd_send_byte(argument[i]);
101   sd_send_byte(SD_CRC);   // Always the same
102
103   response_length = 0;
104   switch(response_type)
105     {
106     case SD_R1:
107     case SD_R1B:
108       response_length = 1;
109       break;
110     case SD_R2:
111       response_length = 2;
112       break;
113     case SD_R3:
114       response_length = 5;
115       break;
116     default:
117       break;
118     }
119
120   // Wait for a response, which will have a 0 start bit
121   i = 0;
122   do
123     {
124       tmp = sd_rcv_byte();
125       i++;
126     }
127   while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT);
128
129   if(i>= SD_CMD_TIMEOUT)
130     {
131       sd_deassert_cs();
132       //puts("cmd send timeout\n");
133       return 0;
134     }
135
136   for(i=response_length-1; i>=0; i--)
137     {
138       response[i] = tmp;
139       tmp = sd_rcv_byte();
140     }
141   i = 0;
142   if(response_type == SD_R1B)
143     {
144       do
145         {
146           i++;
147           tmp = sd_rcv_byte();
148         }
149       while(tmp != SD_IDLE);
150       sd_send_byte(SD_IDLE);
151     }
152   
153   //puts("send cmd success\n");
154   sd_deassert_cs();
155   return 1;
156 }
157
158 int
159 sd_read_block (unsigned int blockaddr, unsigned char *buf)
160 {
161   unsigned char response[5];
162   unsigned char argument[4];
163   unsigned int i = 0;
164   unsigned char tmp;
165
166   blockaddr <<= SD_BLOCKLEN_NBITS;
167   sd_packarg(argument,blockaddr);
168   if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0)
169     return 0;    //Failed READ;
170   if(response[0] != 0)
171     return 0;    //Misaligned READ
172
173   sd_assert_cs();
174   i = 0;
175   do
176     {
177       tmp = sd_rcv_byte();
178       i++;
179     }
180   while((tmp == 0xFF) && (i < SD_RD_TIMEOUT));
181   if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0))
182     {
183       sd_send_byte(SD_IDLE);  // Send a dummy before quitting
184       return 0;   // Data ERROR
185     }
186   for(i=0;i<SD_BLOCKLEN;i++)
187     buf[i] = sd_rcv_byte();
188   return 1;
189
190 }
191
192 int
193 sd_write_block(unsigned int blockaddr, const unsigned char *buf)
194 {
195   // FIXME not implemented yet
196   return 0;
197 }