Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emBIOS.
7
//
8
//    emBIOS is free software: you can redistribute it and/or
9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
13
//    emBIOS is distributed in the hope that it will be useful,
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
19
//    with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "util.h"
26
#include "timer.h"
27
#include "nand.h"
28
#include "i2c.h"
29
 
30
#define NAND_CMD_READ       0x00
31
#define NAND_CMD_PROGCNFRM  0x10
32
#define NAND_CMD_READ2      0x30
33
#define NAND_CMD_BLOCKERASE 0x60
34
#define NAND_CMD_GET_STATUS 0x70
35
#define NAND_CMD_PROGRAM    0x80
36
#define NAND_CMD_ERASECNFRM 0xD0
37
#define NAND_CMD_RESET      0xFF
38
 
39
#define NAND_STATUS_READY   0x40
40
 
41
#define NAND_DEVICEINFOTABLE_ENTRIES 33
42
 
43
static const struct nand_device_info_type nand_deviceinfotable[] =
44
{
45
    {0x1580F1EC, 1024, 968, 0x40, 6, 2, 1, 2, 1},
46
    {0x1580DAEC, 2048, 1936, 0x40, 6, 2, 1, 2, 1},
47
    {0x15C1DAEC, 2048, 1936, 0x40, 6, 2, 1, 2, 1},
48
    {0x1510DCEC, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
49
    {0x95C1DCEC, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
50
    {0x2514DCEC, 2048, 1936, 0x80, 7, 2, 1, 2, 1},
51
    {0x2514D3EC, 4096, 3872, 0x80, 7, 2, 1, 2, 1},
52
    {0x2555D3EC, 4096, 3872, 0x80, 7, 2, 1, 2, 1},
53
    {0x2555D5EC, 8192, 7744, 0x80, 7, 2, 1, 2, 1},
54
    {0x2585D3AD, 4096, 3872, 0x80, 7, 3, 2, 3, 2},
55
    {0x9580DCAD, 4096, 3872, 0x40, 6, 3, 2, 3, 2},
56
    {0xA514D3AD, 4096, 3872, 0x80, 7, 3, 2, 3, 2},
57
    {0xA550D3AD, 4096, 3872, 0x80, 7, 3, 2, 3, 2},
58
    {0xA560D5AD, 4096, 3872, 0x80, 7, 3, 2, 3, 2},
59
    {0xA555D5AD, 8192, 7744, 0x80, 7, 3, 2, 3, 2},
60
    {0xA585D598, 8320, 7744, 0x80, 7, 3, 1, 2, 1},
61
    {0xA584D398, 4160, 3872, 0x80, 7, 3, 1, 2, 1},
62
    {0x95D1D32C, 8192, 7744, 0x40, 6, 2, 1, 2, 1},
63
    {0x1580DC2C, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
64
    {0x15C1D32C, 8192, 7744, 0x40, 6, 2, 1, 2, 1},
65
    {0x9590DC2C, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
66
    {0xA594D32C, 4096, 3872, 0x80, 7, 2, 1, 2, 1},
67
    {0x2584DC2C, 2048, 1936, 0x80, 7, 2, 1, 2, 1},
68
    {0xA5D5D52C, 8192, 7744, 0x80, 7, 3, 2, 2, 1},
69
    {0x95D1D389, 8192, 7744, 0x40, 6, 2, 1, 2, 1},
70
    {0x1580DC89, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
71
    {0x15C1D389, 8192, 7744, 0x40, 6, 2, 1, 2, 1},
72
    {0x9590DC89, 4096, 3872, 0x40, 6, 2, 1, 2, 1},
73
    {0xA594D389, 4096, 3872, 0x80, 7, 2, 1, 2, 1},
74
    {0x2584DC89, 2048, 1936, 0x80, 7, 2, 1, 2, 1},
75
    {0xA5D5D589, 8192, 7744, 0x80, 7, 2, 1, 2, 1},
76
    {0xA514D320, 4096, 3872, 0x80, 7, 2, 1, 2, 1},
77
    {0xA555D520, 8192, 3872, 0x80, 7, 2, 1, 2, 1}
78
};
79
 
80
uint8_t nand_tunk1[4];
81
uint8_t nand_twp[4];
82
uint8_t nand_tunk2[4];
83
uint8_t nand_tunk3[4];
84
uint32_t nand_type[4];
85
 
86
static uint8_t nand_ctrl[0x200] __attribute__((aligned(16)));
87
static uint8_t nand_spare[0x40] __attribute__((aligned(16)));
88
static uint8_t nand_ecc[0x30] __attribute__((aligned(16)));
89
 
90
 
91
uint32_t nand_wait_rbbdone(void)
92
{
93
    uint32_t timeout = USEC_TIMER;
94
    while ((FMCSTAT & FMCSTAT_RBBDONE) == 0) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
95
    FMCSTAT = FMCSTAT_RBBDONE;
96
    return 0;
97
}
98
 
99
uint32_t nand_wait_cmddone(void)
100
{
101
    uint32_t timeout = USEC_TIMER;
102
    while ((FMCSTAT & FMCSTAT_CMDDONE) == 0) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
103
    FMCSTAT = FMCSTAT_CMDDONE;
104
    return 0;
105
}
106
 
107
uint32_t nand_wait_addrdone(void)
108
{
109
    uint32_t timeout = USEC_TIMER;
110
    while ((FMCSTAT & FMCSTAT_ADDRDONE) == 0) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
111
    FMCSTAT = FMCSTAT_ADDRDONE;
112
    return 0;
113
}
114
 
115
uint32_t nand_wait_chip_ready(uint32_t bank)
116
{
117
    uint32_t timeout = USEC_TIMER;
118
    while ((FMCSTAT & (FMCSTAT_BANK0READY << bank)) == 0) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
119
    FMCSTAT = (FMCSTAT_BANK0READY << bank);
120
    return 0;
121
}
122
 
123
void nand_set_fmctrl0(uint32_t bank, uint32_t flags)
124
{
125
    FMCTRL0 = (nand_tunk1[bank] << 16) | (nand_twp[bank] << 12)
126
            | (1 << 11) | 1 | (1 << (bank + 1)) | flags;
127
}
128
 
129
uint32_t nand_send_cmd(uint32_t cmd)
130
{
131
    FMCMD = cmd;
132
    return nand_wait_rbbdone();
133
}
134
 
135
uint32_t nand_send_address(uint32_t page, uint32_t offset)
136
{
137
    FMANUM = 4;
138
    FMADDR0 = (page << 16) | offset;
139
    FMADDR1 = (page >> 16) & 0xFF;
140
    FMCTRL1 = FMCTRL1_DOTRANSADDR;
141
    return nand_wait_cmddone();
142
}
143
 
144
uint32_t nand_reset(uint32_t bank)
145
{
146
    nand_set_fmctrl0(bank, 0);
147
    if (nand_send_cmd(NAND_CMD_RESET)) return 1;
148
    if (nand_wait_chip_ready(bank)) return 1;
149
    FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO;
150
    sleep(1000);
151
    return 0;
152
}
153
 
154
uint32_t nand_wait_status_ready(uint32_t bank)
155
{
156
    uint32_t timeout = USEC_TIMER;
157
    nand_set_fmctrl0(bank, 0);
158
    if ((FMCSTAT & (FMCSTAT_BANK0READY << bank)))
159
        FMCSTAT = (FMCSTAT_BANK0READY << bank);
160
    FMCTRL1 = FMCTRL1_CLEARRFIFO;
161
    if (nand_send_cmd(NAND_CMD_GET_STATUS)) return 1;
162
    while (1)
163
    {
164
        if (TIMEOUT_EXPIRED(timeout, 200)) return 1;
165
        FMDNUM = 0;
166
        FMCTRL1 = FMCTRL1_DOREADDATA;
167
        if (nand_wait_addrdone()) return 1;
168
        if ((FMFIFO & NAND_STATUS_READY)) break;
169
        FMCTRL1 = FMCTRL1_CLEARRFIFO;
170
    }
171
    FMCTRL1 = FMCTRL1_CLEARRFIFO;
172
    return nand_send_cmd(NAND_CMD_READ);
173
}
174
 
175
uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, void* buffer, uint32_t size)
176
{
177
    uint32_t timeout = USEC_TIMER;
178
    nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
179
    FMDNUM = size - 1;
180
    FMCTRL1 = FMCTRL1_DOREADDATA << direction;
181
    DMACON3 = (2 << DMACON_DEVICE_SHIFT)
182
            | (direction << DMACON_DIRECTION_SHIFT)
183
            | (2 << DMACON_DATA_SIZE_SHIFT)
184
            | (3 << DMACON_BURST_LEN_SHIFT);
185
    while ((DMAALLST & DMAALLST_CHAN3_MASK))
186
        DMACOM3 = DMACOM_CLEARBOTHDONE;
187
    DMABASE3 = (uint32_t)buffer;
188
    DMATCNT3 = (size >> 4) - 1;
189
    clean_dcache();
190
    DMACOM3 = 4;
191
    while ((DMAALLST & DMAALLST_DMABUSY3)) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
192
    if (!direction) invalidate_dcache();
193
    if (nand_wait_addrdone()) return 1;
194
    if (!direction) FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO;
195
    else FMCTRL1 = FMCTRL1_CLEARRFIFO;
196
    return 0;
197
}
198
 
199
uint32_t ecc_decode(uint32_t size, void* databuffer, void* sparebuffer)
200
{
201
    uint32_t timeout = USEC_TIMER;
202
    ECC_INT_CLR = 1;
203
    SRCPND = INTMSK_ECC;
204
    ECC_UNK1 = size;
205
    ECC_DATA_PTR = (uint32_t)databuffer;
206
    ECC_SPARE_PTR = (uint32_t)sparebuffer;
207
    clean_dcache();
208
    ECC_CTRL = ECCCTRL_STARTDECODING;
209
    while (!(SRCPND & INTMSK_ECC)) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
210
    invalidate_dcache();
211
    ECC_INT_CLR = 1;
212
    SRCPND = INTMSK_ECC;
213
    return ECC_RESULT;
214
}
215
 
216
uint32_t ecc_encode(uint32_t size, void* databuffer, void* sparebuffer)
217
{
218
    uint32_t timeout = USEC_TIMER;
219
    ECC_INT_CLR = 1;
220
    SRCPND = INTMSK_ECC;
221
    ECC_UNK1 = size;
222
    ECC_DATA_PTR = (uint32_t)databuffer;
223
    ECC_SPARE_PTR = (uint32_t)sparebuffer;
224
    clean_dcache();
225
    ECC_CTRL = ECCCTRL_STARTENCODING;
226
    while (!(SRCPND & INTMSK_ECC)) if (TIMEOUT_EXPIRED(timeout, 2000)) return 1;
227
    invalidate_dcache();
228
    ECC_INT_CLR = 1;
229
    SRCPND = INTMSK_ECC;
230
    return 0;
231
}
232
 
233
uint32_t nand_check_empty(uint8_t* buffer)
234
{
235
    uint32_t i, count;
236
    count = 0;
237
    for (i = 0; i < 0x40; i++) if (buffer[i] != 0xFF) count++;
238
    if (count < 2) return 1;
239
    return 0;
240
}
241
 
242
uint32_t nand_get_chip_type(uint32_t bank)
243
{
244
    uint32_t result;
245
    if (nand_reset(bank)) return 0xFFFFFFFF;
246
    if (nand_send_cmd(0x90)) return 0xFFFFFFFF;
247
    FMANUM = 0;
248
    FMADDR0 = 0;
249
    FMCTRL1 = FMCTRL1_DOTRANSADDR;
250
    if (nand_wait_cmddone()) return 0xFFFFFFFF;
251
    FMDNUM = 4;
252
    FMCTRL1 = FMCTRL1_DOREADDATA;
253
    if (nand_wait_addrdone()) return 0xFFFFFFFF;
254
    result = FMFIFO;
255
    FMCTRL1 = FMCTRL1_CLEARRFIFO;
256
    return result;
257
}
258
 
259
uint32_t nand_read_page(uint32_t bank, uint32_t page, void* data,
260
                        void* sparebuffer, uint32_t doecc, uint32_t checkempty)
261
{
262
    uint32_t rc, eccresult;
263
    uint8_t* spare = nand_spare;
264
    if (sparebuffer) spare = sparebuffer;
265
    nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
266
    if (nand_send_cmd(NAND_CMD_READ)) return 1;
267
    if (nand_send_address(page, data ? 0 : 0x800)) return 1;
268
    if (nand_send_cmd(NAND_CMD_READ2)) return 1;
269
    if (nand_wait_status_ready(bank)) return 1;
270
    if (data) if (nand_transfer_data(bank, 0, data, 0x800)) return 1;
271
    rc = 0;
272
    if (!doecc)
273
    {
274
        if (sparebuffer)
275
        {
276
            if (nand_transfer_data(bank, 0, spare, 0x40)) return 1;
277
            if (checkempty)
278
                rc = nand_check_empty((uint8_t*)spare) << 1;
279
        }
280
        return rc;
281
    }
282
    if (nand_transfer_data(bank, 0, spare, 0x40)) return 1;
283
    if (data)
284
    {
285
        memcpy(nand_ecc, &((uint8_t*)spare)[0xC], 0x28);
286
        rc |= (ecc_decode(3, data, nand_ecc) & 0xF) << 4;
287
    }
288
    memset(nand_ctrl, 0xFF, 0x200);
289
    memcpy(nand_ctrl, spare, 0xC);
290
    memcpy(nand_ecc, &((uint8_t*)spare)[0x34], 0xC);
291
    eccresult = ecc_decode(0, nand_ctrl, nand_ecc);
292
    rc |= (eccresult & 0xF) << 8;
293
    if (spare)
294
    {
295
        if (eccresult & 1) memset(spare, 0xFF, 0xC);
296
        else memcpy(spare, nand_ctrl, 0xC);
297
    }
298
    if (checkempty) rc |= nand_check_empty(spare) << 1;
299
    return rc;
300
}
301
 
302
uint32_t nand_write_page(uint32_t bank, uint32_t page, void* data,
303
                         void* sparebuffer, uint32_t doecc)
304
{
305
    uint8_t* spare = nand_spare;
306
    if (sparebuffer) spare = sparebuffer;
307
    else memset(spare, 0xFF, 0x40);
308
    if (doecc)
309
    {
310
        if (ecc_encode(3, data, nand_ecc)) return 1;
311
        memcpy(&spare[0xC], nand_ecc, 0x28);
312
        memset(nand_ctrl, 0xFF, 0x200);
313
        memcpy(nand_ctrl, spare, 0xC);
314
        if (ecc_encode(0, nand_ctrl, nand_ecc)) return 1;
315
        memcpy(&spare[0x34], nand_ecc, 0xC);
316
    }
317
    nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
318
    if (nand_send_cmd(NAND_CMD_PROGRAM)) return 1;
319
    if (nand_send_address(page, data ? 0 : 0x800)) return 1;
320
    if (data) if (nand_transfer_data(bank, 1, data, 0x800)) return 1;
321
    if (sparebuffer || doecc)
322
        if (nand_transfer_data(bank, 1, spare, 0x40)) return 1;
323
    if (nand_send_cmd(NAND_CMD_PROGCNFRM)) return 1;
324
    return nand_wait_status_ready(bank);
325
}
326
 
327
uint32_t nand_block_erase(uint32_t bank, uint32_t page)
328
{
329
    nand_set_fmctrl0(bank, 0);
330
    if (nand_send_cmd(NAND_CMD_BLOCKERASE)) return 1;
331
    FMANUM = 2;
332
    FMADDR0 = page;
333
    FMCTRL1 = FMCTRL1_DOTRANSADDR;
334
    if (nand_wait_cmddone()) return 1;
335
    if (nand_send_cmd(NAND_CMD_ERASECNFRM)) return 1;
336
    return nand_wait_status_ready(bank);
337
}
338
 
339
uint32_t nand_block_erase_fast(uint32_t page)
340
{
341
    uint32_t i, rc = 0;
342
    for (i = 0; i < 4; i++)
343
    {
344
        if (nand_type[i] == 0xFFFFFFFF) continue;
345
        nand_set_fmctrl0(i, 0);
346
        if (nand_send_cmd(NAND_CMD_BLOCKERASE))
347
        {
348
            rc |= 1 << i;
349
            continue;
350
        }
351
        FMANUM = 2;
352
        FMADDR0 = page;
353
        FMCTRL1 = FMCTRL1_DOTRANSADDR;
354
        if (nand_wait_cmddone())
355
        {
356
            rc |= 1 << i;
357
            continue;
358
        }
359
        if (nand_send_cmd(NAND_CMD_ERASECNFRM)) rc |= 1 << i;
360
    }
361
    for (i = 0; i < 4; i++)
362
    {
363
        if (nand_type[i] == 0xFFFFFFFF) continue;
364
        if (rc & (1 << i)) continue;
365
        if (nand_wait_status_ready(i)) rc |= 1 << i;
366
    }
367
    return rc;
368
}
369
 
370
const struct nand_device_info_type* nand_get_device_type(uint32_t bank)
371
{
372
    if (nand_type[bank] == 0xFFFFFFFF)
373
        return (struct nand_device_info_type*)0;
374
    return &nand_deviceinfotable[nand_type[bank]];
375
}
376
 
377
uint32_t nand_init()
378
{
379
    uint32_t type;
380
    uint32_t i, j;
381
    PWRCONEXT &= ~0x40;
382
    PWRCON &= ~0x100010;
15 theseven 383
    i2c_sendbyte(0, 0xE6, 0x35, 0x15);
384
    i2c_sendbyte(0, 0xE6, 0x36, 0x01);
2 theseven 385
    PCON2 = 0x33333333;
386
    PDAT2 = 0;
387
    PCON3 = 0x11113333;
388
    PDAT3 = 0;
389
    PCON4 = 0x33333333;
390
    PDAT4 = 0;
391
    PCON5 = (PCON5 & ~0xF) | 3;
392
    PUNK5 = 1;
393
    sleep(10000);
394
    for (i = 0; i < 4; i++)
395
    {
396
        nand_tunk1[i] = 7;
397
        nand_twp[i] = 7;
398
        nand_tunk2[i] = 7;
399
        nand_tunk3[i] = 7;
400
        type = nand_get_chip_type(i);
401
        nand_type[i] = 0xFFFFFFFF;
402
        if (type == 0xFFFFFFFF) continue;
403
        for (j = 0; ; j++)
404
        {
405
            if (j == NAND_DEVICEINFOTABLE_ENTRIES) break;
406
            else if (nand_deviceinfotable[j].id == type)
407
            {
408
                nand_type[i] = j;
409
                break;
410
            }
411
        }
412
        nand_tunk1[i] = nand_deviceinfotable[nand_type[i]].tunk1;
413
        nand_twp[i] = nand_deviceinfotable[nand_type[i]].twp;
414
        nand_tunk2[i] = nand_deviceinfotable[nand_type[i]].tunk2;
415
        nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3;
416
    }
417
    if (nand_type[0] == 0xFFFFFFFF) return 1;
418
    return 0;
419
}