[49a40165] | 1 | /*--------------------------------------------------------------------------------- |
---|
| 2 | Copyright (C) 2005 |
---|
| 3 | Michael Noland (joat) |
---|
| 4 | Jason Rogers (dovoto) |
---|
| 5 | Dave Murphy (WinterMute) |
---|
| 6 | |
---|
| 7 | This software is provided 'as-is', without any express or implied |
---|
| 8 | warranty. In no event will the authors be held liable for any |
---|
| 9 | damages arising from the use of this software. |
---|
| 10 | |
---|
| 11 | Permission is granted to anyone to use this software for any |
---|
| 12 | purpose, including commercial applications, and to alter it and |
---|
| 13 | redistribute it freely, subject to the following restrictions: |
---|
| 14 | |
---|
| 15 | 1. The origin of this software must not be misrepresented; you |
---|
| 16 | must not claim that you wrote the original software. If you use |
---|
| 17 | this software in a product, an acknowledgment in the product |
---|
| 18 | documentation would be appreciated but is not required. |
---|
| 19 | 2. Altered source versions must be plainly marked as such, and |
---|
| 20 | must not be misrepresented as being the original software. |
---|
| 21 | 3. This notice may not be removed or altered from any source |
---|
| 22 | distribution. |
---|
| 23 | |
---|
| 24 | |
---|
| 25 | ---------------------------------------------------------------------------------*/ |
---|
| 26 | #include "nds/card.h" |
---|
| 27 | #include "nds/dma.h" |
---|
| 28 | #include "nds/memory.h" |
---|
| 29 | |
---|
| 30 | |
---|
| 31 | //--------------------------------------------------------------------------------- |
---|
| 32 | void cardWriteCommand(const uint8 * command) { |
---|
| 33 | //--------------------------------------------------------------------------------- |
---|
| 34 | int index; |
---|
| 35 | |
---|
| 36 | CARD_CR1H = CARD_CR1_ENABLE | CARD_CR1_IRQ; |
---|
| 37 | |
---|
| 38 | for (index = 0; index < 8; index++) { |
---|
| 39 | CARD_COMMAND[7-index] = command[index]; |
---|
| 40 | } |
---|
| 41 | } |
---|
| 42 | |
---|
| 43 | |
---|
| 44 | //--------------------------------------------------------------------------------- |
---|
| 45 | void cardPolledTransfer(uint32 flags, uint32 * destination, uint32 length, const uint8 * command) { |
---|
| 46 | //--------------------------------------------------------------------------------- |
---|
| 47 | u32 data;; |
---|
| 48 | cardWriteCommand(command); |
---|
| 49 | CARD_CR2 = flags; |
---|
| 50 | uint32 * target = destination + length; |
---|
| 51 | do { |
---|
| 52 | // Read data if available |
---|
| 53 | if (CARD_CR2 & CARD_DATA_READY) { |
---|
| 54 | data=CARD_DATA_RD; |
---|
| 55 | if (destination < target) |
---|
| 56 | *destination = data; |
---|
| 57 | destination++; |
---|
| 58 | } |
---|
| 59 | } while (CARD_CR2 & CARD_BUSY); |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | |
---|
| 63 | //--------------------------------------------------------------------------------- |
---|
| 64 | void cardStartTransfer(const uint8 * command, uint32 * destination, int channel, uint32 flags) { |
---|
| 65 | //--------------------------------------------------------------------------------- |
---|
| 66 | cardWriteCommand(command); |
---|
| 67 | |
---|
| 68 | // Set up a DMA channel to transfer a word every time the card makes one |
---|
| 69 | DMA_SRC(channel) = (uint32)&CARD_DATA_RD; |
---|
| 70 | DMA_DEST(channel) = (uint32)destination; |
---|
| 71 | DMA_CR(channel) = DMA_ENABLE | DMA_START_CARD | DMA_32_BIT | DMA_REPEAT | DMA_SRC_FIX | 0x0001;; |
---|
| 72 | |
---|
| 73 | CARD_CR2 = flags; |
---|
| 74 | } |
---|
| 75 | |
---|
| 76 | |
---|
| 77 | //--------------------------------------------------------------------------------- |
---|
| 78 | uint32 cardWriteAndRead(const uint8 * command, uint32 flags) { |
---|
| 79 | //--------------------------------------------------------------------------------- |
---|
| 80 | cardWriteCommand(command); |
---|
| 81 | CARD_CR2 = flags | CARD_ACTIVATE | CARD_nRESET | 0x07000000; |
---|
| 82 | while (!(CARD_CR2 & CARD_DATA_READY)) ; |
---|
| 83 | return CARD_DATA_RD; |
---|
| 84 | } |
---|
| 85 | |
---|
| 86 | |
---|
| 87 | //--------------------------------------------------------------------------------- |
---|
| 88 | void cardRead00(uint32 address, uint32 * destination, uint32 length, uint32 flags) { |
---|
| 89 | //---------------------------------------------------------------------------------f |
---|
| 90 | uint8 command[8]; |
---|
| 91 | command[7] = 0; |
---|
| 92 | command[6] = (address >> 24) & 0xff; |
---|
| 93 | command[5] = (address >> 16) & 0xff; |
---|
| 94 | command[4] = (address >> 8) & 0xff; |
---|
| 95 | command[3] = address & 0xff; |
---|
| 96 | command[2] = 0; |
---|
| 97 | command[1] = 0; |
---|
| 98 | command[0] = 0; |
---|
| 99 | cardPolledTransfer(flags, destination, length, command); |
---|
| 100 | } |
---|
| 101 | |
---|
| 102 | |
---|
| 103 | //--------------------------------------------------------------------------------- |
---|
| 104 | void cardReadHeader(uint8 * header) { |
---|
| 105 | //--------------------------------------------------------------------------------- |
---|
| 106 | cardRead00(0, (uint32 *)header, 512, 0xA93F1FFF); |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | |
---|
| 110 | //--------------------------------------------------------------------------------- |
---|
| 111 | int cardReadID(uint32 flags) { |
---|
| 112 | //--------------------------------------------------------------------------------- |
---|
| 113 | uint8 command[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90}; |
---|
| 114 | return cardWriteAndRead(command, flags); |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | |
---|
| 118 | //--------------------------------------------------------------------------------- |
---|
[9a85541] | 119 | static inline void EepromWaitBusy(void) { |
---|
[49a40165] | 120 | //--------------------------------------------------------------------------------- |
---|
| 121 | while (CARD_CR1 & /*BUSY*/0x80); |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | //--------------------------------------------------------------------------------- |
---|
| 125 | uint8 cardEepromReadID(uint8 i) { |
---|
| 126 | //--------------------------------------------------------------------------------- |
---|
| 127 | return cardEepromCommand(/*READID*/0xAB, i&1); |
---|
| 128 | } |
---|
| 129 | |
---|
| 130 | //--------------------------------------------------------------------------------- |
---|
| 131 | uint8 cardEepromCommand(uint8 command, uint32 address) { |
---|
| 132 | //--------------------------------------------------------------------------------- |
---|
| 133 | uint8 retval; |
---|
| 134 | int k; |
---|
| 135 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 136 | |
---|
| 137 | CARD_CR1 = 0xFFFF; |
---|
| 138 | CARD_EEPDATA = command; |
---|
| 139 | |
---|
| 140 | EepromWaitBusy(); |
---|
| 141 | |
---|
| 142 | CARD_EEPDATA = (address >> 16) & 0xFF; |
---|
| 143 | EepromWaitBusy(); |
---|
| 144 | |
---|
| 145 | CARD_EEPDATA = (address >> 8) & 0xFF; |
---|
| 146 | EepromWaitBusy(); |
---|
| 147 | |
---|
| 148 | CARD_EEPDATA = (address) & 0xFF; |
---|
| 149 | EepromWaitBusy(); |
---|
| 150 | |
---|
| 151 | for(k=0;k<256;k++) |
---|
| 152 | { |
---|
| 153 | retval = CARD_EEPDATA; |
---|
| 154 | if(retval!=0xFF) |
---|
| 155 | break; |
---|
| 156 | EepromWaitBusy(); |
---|
| 157 | } |
---|
| 158 | |
---|
| 159 | CARD_CR1 = /*MODE*/0x40; |
---|
| 160 | return retval; |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | //--------------------------------------------------------------------------------- |
---|
| 164 | int cardEepromGetType(void) |
---|
| 165 | //--------------------------------------------------------------------------------- |
---|
| 166 | { |
---|
| 167 | uint8 c00; |
---|
| 168 | uint8 c05; |
---|
| 169 | uint8 c9f; |
---|
| 170 | uint8 c03; |
---|
| 171 | |
---|
| 172 | #ifdef ARM9 |
---|
| 173 | sysSetBusOwners(BUS_OWNER_ARM9, BUS_OWNER_ARM9); |
---|
| 174 | #endif |
---|
| 175 | |
---|
| 176 | c03=cardEepromCommand(0x03,0); |
---|
| 177 | c05=cardEepromCommand(0x05,0); |
---|
| 178 | c9f=cardEepromCommand(0x9f,0); |
---|
| 179 | c00=cardEepromCommand(0x00,0); |
---|
| 180 | |
---|
[32b8506] | 181 | if((c00==0x00) && (c9f==0x00)) return 0; // PassMe? |
---|
[49a40165] | 182 | if((c00==0xff) && (c05==0xff) && (c9f==0xff))return -1; |
---|
| 183 | |
---|
| 184 | if((c00==0xff) && (c05 & 0xFD) == 0xF0 && (c9f==0xff))return 1; |
---|
| 185 | if((c00==0xff) && (c05 & 0xFD) == 0x00 && (c9f==0xff))return 2; |
---|
| 186 | if((c00==0xff) && (c05 & 0xFD) == 0x00 && (c9f==0x00))return 3; |
---|
| 187 | if((c00==0xff) && (c05 & 0xFD) == 0x00 && (c9f==0x12))return 3; // NEW TYPE 3 |
---|
| 188 | if((c00==0xff) && (c05 & 0xFD) == 0x00 && (c9f==0x13))return 3; // NEW TYPE 3+ 4Mbit |
---|
| 189 | if((c00==0xff) && (c05 & 0xFD) == 0x00 && (c9f==0x14))return 3; // NEW TYPE 3++ 8Mbit MK4-FLASH Memory |
---|
| 190 | |
---|
| 191 | return 0; |
---|
| 192 | } |
---|
| 193 | |
---|
| 194 | //--------------------------------------------------------------------------------- |
---|
| 195 | uint32 cardEepromGetSize() { |
---|
| 196 | //--------------------------------------------------------------------------------- |
---|
| 197 | |
---|
| 198 | int type = cardEepromGetType(); |
---|
| 199 | |
---|
| 200 | if(type == -1) |
---|
| 201 | return 0; |
---|
| 202 | if(type == 0) |
---|
| 203 | return 8192; |
---|
| 204 | if(type == 1) |
---|
| 205 | return 512; |
---|
| 206 | if(type == 2) { |
---|
| 207 | static const uint32 offset0 = (8*1024-1); // 8KB |
---|
| 208 | static const uint32 offset1 = (2*8*1024-1); // 16KB |
---|
| 209 | u8 buf1; // +0k data read -> write |
---|
| 210 | u8 buf2; // +8k data read -> read |
---|
| 211 | u8 buf3; // +0k ~data write |
---|
| 212 | u8 buf4; // +8k data new comp buf2 |
---|
| 213 | cardReadEeprom(offset0,&buf1,1,type); |
---|
| 214 | cardReadEeprom(offset1,&buf2,1,type); |
---|
| 215 | buf3=~buf1; |
---|
| 216 | cardWriteEeprom(offset0,&buf3,1,type); |
---|
| 217 | cardReadEeprom (offset1,&buf4,1,type); |
---|
| 218 | cardWriteEeprom(offset0,&buf1,1,type); |
---|
| 219 | if(buf4!=buf2) // +8k |
---|
| 220 | return 8*1024; // 8KB(64kbit) |
---|
| 221 | else |
---|
| 222 | return 64*1024; // 64KB(512kbit) |
---|
| 223 | } |
---|
| 224 | if(type == 3) { |
---|
| 225 | uint8 c9f; |
---|
| 226 | c9f=cardEepromCommand(0x9f,0); |
---|
| 227 | |
---|
[32b8506] | 228 | if(c9f==0x14) |
---|
[49a40165] | 229 | return 1024*1024; // NEW TYPE 3++ 8Mbit(1024KByte) |
---|
| 230 | |
---|
[32b8506] | 231 | if(c9f==0x13) |
---|
[49a40165] | 232 | return 512*1024; // NEW TYPE 3+ 4Mbit(512KByte) |
---|
| 233 | |
---|
| 234 | return 256*1024; // TYPE 3 2Mbit(256KByte) |
---|
| 235 | } |
---|
| 236 | |
---|
| 237 | return 0; |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | |
---|
| 241 | //--------------------------------------------------------------------------------- |
---|
| 242 | void cardReadEeprom(uint32 address, uint8 *data, uint32 length, uint32 addrtype) { |
---|
| 243 | //--------------------------------------------------------------------------------- |
---|
| 244 | |
---|
| 245 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 246 | CARD_EEPDATA = 0x03 | ((addrtype == 1) ? address>>8<<3 : 0); |
---|
| 247 | EepromWaitBusy(); |
---|
| 248 | |
---|
| 249 | if (addrtype == 3) { |
---|
| 250 | CARD_EEPDATA = (address >> 16) & 0xFF; |
---|
| 251 | EepromWaitBusy(); |
---|
[32b8506] | 252 | } |
---|
| 253 | |
---|
[49a40165] | 254 | if (addrtype >= 2) { |
---|
| 255 | CARD_EEPDATA = (address >> 8) & 0xFF; |
---|
| 256 | EepromWaitBusy(); |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | |
---|
| 260 | CARD_EEPDATA = (address) & 0xFF; |
---|
| 261 | EepromWaitBusy(); |
---|
| 262 | |
---|
| 263 | while (length > 0) { |
---|
| 264 | CARD_EEPDATA = 0; |
---|
| 265 | EepromWaitBusy(); |
---|
| 266 | *data++ = CARD_EEPDATA; |
---|
| 267 | length--; |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | EepromWaitBusy(); |
---|
| 271 | CARD_CR1 = /*MODE*/0x40; |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | |
---|
| 275 | //--------------------------------------------------------------------------------- |
---|
| 276 | void cardWriteEeprom(uint32 address, uint8 *data, uint32 length, uint32 addrtype) { |
---|
| 277 | //--------------------------------------------------------------------------------- |
---|
| 278 | |
---|
| 279 | uint32 address_end = address + length; |
---|
| 280 | int i; |
---|
| 281 | int maxblocks = 32; |
---|
| 282 | if(addrtype == 1) maxblocks = 16; |
---|
| 283 | if(addrtype == 2) maxblocks = 32; |
---|
| 284 | if(addrtype == 3) maxblocks = 256; |
---|
| 285 | |
---|
| 286 | while (address < address_end) { |
---|
| 287 | // set WEL (Write Enable Latch) |
---|
| 288 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 289 | CARD_EEPDATA = 0x06; EepromWaitBusy(); |
---|
| 290 | CARD_CR1 = /*MODE*/0x40; |
---|
| 291 | |
---|
| 292 | // program maximum of 32 bytes |
---|
| 293 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 294 | |
---|
| 295 | if(addrtype == 1) { |
---|
| 296 | // WRITE COMMAND 0x02 + A8 << 3 |
---|
| 297 | CARD_EEPDATA = 0x02 | (address & BIT(8)) >> (8-3) ; |
---|
| 298 | EepromWaitBusy(); |
---|
| 299 | CARD_EEPDATA = address & 0xFF; |
---|
| 300 | EepromWaitBusy(); |
---|
| 301 | } |
---|
| 302 | else if(addrtype == 2) { |
---|
| 303 | CARD_EEPDATA = 0x02; |
---|
| 304 | EepromWaitBusy(); |
---|
| 305 | CARD_EEPDATA = address >> 8; |
---|
| 306 | EepromWaitBusy(); |
---|
| 307 | CARD_EEPDATA = address & 0xFF; |
---|
| 308 | EepromWaitBusy(); |
---|
| 309 | } |
---|
| 310 | else if(addrtype == 3) { |
---|
| 311 | CARD_EEPDATA = 0x02; |
---|
| 312 | EepromWaitBusy(); |
---|
| 313 | CARD_EEPDATA = (address >> 16) & 0xFF; |
---|
| 314 | EepromWaitBusy(); |
---|
| 315 | CARD_EEPDATA = (address >> 8) & 0xFF; |
---|
| 316 | EepromWaitBusy(); |
---|
| 317 | CARD_EEPDATA = address & 0xFF; |
---|
| 318 | EepromWaitBusy(); |
---|
| 319 | } |
---|
| 320 | |
---|
[32b8506] | 321 | for (i=0; address<address_end && i<maxblocks; i++, address++) { |
---|
| 322 | CARD_EEPDATA = *data++; |
---|
| 323 | EepromWaitBusy(); |
---|
[49a40165] | 324 | } |
---|
| 325 | CARD_CR1 = /*MODE*/0x40; |
---|
| 326 | |
---|
| 327 | // wait programming to finish |
---|
| 328 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 329 | CARD_EEPDATA = 0x05; EepromWaitBusy(); |
---|
| 330 | do { CARD_EEPDATA = 0; EepromWaitBusy(); } while (CARD_EEPDATA & 0x01); // WIP (Write In Progress) ? |
---|
| 331 | EepromWaitBusy(); |
---|
| 332 | CARD_CR1 = /*MODE*/0x40; |
---|
| 333 | } |
---|
| 334 | } |
---|
| 335 | |
---|
| 336 | |
---|
| 337 | // Chip Erase : clear FLASH MEMORY (TYPE 3 ONLY) |
---|
| 338 | //--------------------------------------------------------------------------------- |
---|
| 339 | void cardEepromChipErase(void) { |
---|
| 340 | //--------------------------------------------------------------------------------- |
---|
| 341 | int sz; |
---|
| 342 | sz=cardEepromGetSize(); |
---|
| 343 | cardEepromSectorErase(0x00000); |
---|
| 344 | cardEepromSectorErase(0x10000); |
---|
| 345 | cardEepromSectorErase(0x20000); |
---|
| 346 | cardEepromSectorErase(0x30000); |
---|
| 347 | if(sz==512*1024) |
---|
| 348 | { |
---|
| 349 | cardEepromSectorErase(0x40000); |
---|
| 350 | cardEepromSectorErase(0x50000); |
---|
| 351 | cardEepromSectorErase(0x60000); |
---|
| 352 | cardEepromSectorErase(0x70000); |
---|
| 353 | } |
---|
| 354 | } |
---|
| 355 | |
---|
| 356 | // COMMAND Sec.erase 0xD8 |
---|
| 357 | void cardEepromSectorErase(uint32 address) |
---|
| 358 | { |
---|
| 359 | // set WEL (Write Enable Latch) |
---|
| 360 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 361 | CARD_EEPDATA = 0x06; |
---|
| 362 | EepromWaitBusy(); |
---|
| 363 | |
---|
| 364 | CARD_CR1 = /*MODE*/0x40; |
---|
| 365 | |
---|
| 366 | // SectorErase 0xD8 |
---|
| 367 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 368 | CARD_EEPDATA = 0xD8; |
---|
| 369 | EepromWaitBusy(); |
---|
| 370 | CARD_EEPDATA = (address >> 16) & 0xFF; |
---|
| 371 | EepromWaitBusy(); |
---|
| 372 | CARD_EEPDATA = (address >> 8) & 0xFF; |
---|
| 373 | EepromWaitBusy(); |
---|
| 374 | CARD_EEPDATA = address & 0xFF; |
---|
| 375 | EepromWaitBusy(); |
---|
| 376 | |
---|
| 377 | CARD_CR1 = /*MODE*/0x40; |
---|
| 378 | |
---|
| 379 | // wait erase to finish |
---|
| 380 | CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40; |
---|
| 381 | CARD_EEPDATA = 0x05; |
---|
| 382 | EepromWaitBusy(); |
---|
| 383 | |
---|
| 384 | do |
---|
| 385 | { |
---|
| 386 | CARD_EEPDATA = 0; |
---|
| 387 | EepromWaitBusy(); |
---|
| 388 | } while (CARD_EEPDATA & 0x01); // WIP (Write In Progress) ? |
---|
| 389 | CARD_CR1 = /*MODE*/0x40; |
---|
| 390 | } |
---|
| 391 | |
---|
| 392 | |
---|