Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
273 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
427 farthen 6
//    This file is part of emCORE.
273 theseven 7
//
427 farthen 8
//    emCORE is free software: you can redistribute it and/or
273 theseven 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
//
427 farthen 13
//    emCORE is distributed in the hope that it will be useful,
273 theseven 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
427 farthen 19
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
273 theseven 20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "bootflash.h"
26
#include "contextswitch.h"
27
#include "util.h"
28
#include "spi.h"
29
#include "s5l8702.h"
30
 
31
 
32
void bootflash_ce(int port, bool state)
33
{
34
    if (state)
35
    {
36
        if (port == 2) PDAT(0xe) &= ~0x40;
37
        else if (port == 1) PDAT(6) &= ~0x10;
38
        else PDAT(0) &= ~1;
39
    }
40
    else
41
    {
42
        if (port == 2) PDAT(0xe) |= 0x40;
43
        else if (port == 1) PDAT(6) |= 0x10;
44
        else PDAT(0) |= 1;
45
    }
46
}
47
 
48
void bootflash_wait_ready(int port)
49
{
50
    while (true)
51
    {
52
        bootflash_ce(port, true);
53
        spi_write(port, 5);
54
        if (!(spi_write(port, 0xff) & 1)) break;
55
        bootflash_ce(port, false);
56
    }
57
    bootflash_ce(port, false);
58
}
59
 
60
void bootflash_enable_writing(int port, bool state)
61
{
62
    if (!state)
63
    {
64
        bootflash_ce(port, true);
65
        spi_write(port, 4);
66
        bootflash_ce(port, false);
67
    }
68
    bootflash_ce(port, true);
69
    spi_write(port, 0x50);
70
    bootflash_ce(port, false);
71
    bootflash_ce(port, true);
72
    spi_write(port, 1);
73
    spi_write(port, state ? 0 : 0x1c);
74
    bootflash_ce(port, false);
75
    if (state)
76
    {
77
        bootflash_ce(port, true);
78
        spi_write(port, 6);
79
        bootflash_ce(port, false);
80
    }
81
}
82
 
83
void bootflash_readraw(void* addr, int offset, int size)
84
{
85
    spi_prepare(0);
86
    bootflash_wait_ready(0);
87
    bootflash_ce(0, true);
88
    spi_write(0, 3);
89
    spi_write(0, (offset >> 16) & 0xff);
90
    spi_write(0, (offset >> 8) & 0xff);
91
    spi_write(0, offset & 0xff);
92
    spi_read(0, size, addr);
93
    bootflash_ce(0, false);
94
    spi_release(0);
95
}
96
 
97
void bootflash_write_internal(int port, uint32_t addr, uint32_t size, void* buf)
98
{
99
    uint8_t* buffer = (uint8_t*)buf;
100
    bool first = true;
101
    spi_prepare(port);
102
    bootflash_wait_ready(port);
103
    bootflash_enable_writing(port, true);
104
    while (size)
105
    {
106
        bootflash_ce(port, true);
107
        spi_write(port, 0xad);
108
        if (first)
109
        {
110
            spi_write(port, (addr >> 16) & 0xff);
111
            spi_write(port, (addr >> 8) & 0xff);
112
            spi_write(port, addr & 0xff);
113
            first = false;
114
        }
115
        spi_write(port, *buffer++);
116
        spi_write(port, *buffer++);
117
        bootflash_ce(port, false);
118
        bootflash_wait_ready(port);
119
        size -= 2;
120
    }
121
    bootflash_enable_writing(port, false);
122
    spi_release(port);
123
}
124
 
125
void bootflash_erase_internal(int port, uint32_t addr)
126
{
127
    spi_prepare(port);
128
    bootflash_wait_ready(port);
129
    bootflash_enable_writing(port, true);
130
    bootflash_ce(port, true);
131
    spi_write(port, 0x20);
132
    spi_write(port, (addr >> 16) & 0xff);
133
    spi_write(port, (addr >> 8) & 0xff);
134
    spi_write(port, addr & 0xff);
135
    bootflash_ce(port, false);
136
    bootflash_enable_writing(port, false);
137
    spi_release(port);
138
}
139
 
140
int bootflash_compare(int offset, void* addr, int size)
141
{
142
    int i;
143
    int result = 0;
144
    uint8_t buf[32];
145
    spi_prepare(0);
146
    bootflash_wait_ready(0);
147
    bootflash_ce(0, true);
148
    spi_write(0, 3);
149
    spi_write(0, (offset >> 16) & 0xff);
150
    spi_write(0, (offset >> 8) & 0xff);
151
    spi_write(0, offset & 0xff);
152
    while (size > 0)
153
    {
154
        spi_read(0, MIN(sizeof(buf), size), buf);
155
        if (memcmp((uint8_t*)addr, buf, MIN(sizeof(buf), size))) result |= 1;
156
        for (i = 0; i < MIN(sizeof(buf), size); i += 2)
157
            if (buf[i] != 0xff) result |= 2;
158
        addr = (void*)(((uint32_t)addr) + sizeof(buf));
159
        size -= sizeof(buf);
160
    }
161
    bootflash_ce(0, false);
162
    spi_release(0);
163
    return result;
164
}
165
 
166
void bootflash_writeraw(void* addr, int offset, int size)
167
{
168
    int i;
169
    bool needswrite;
170
    while (size > 0)
171
    {
172
        int remainder = MIN(0x1000 - (offset & 0xfff), size);
173
        int contentinfo = bootflash_compare(offset, addr, remainder);
174
        if (contentinfo & 1)
175
        {
176
            if (contentinfo & 2) bootflash_erase_internal(0, offset & ~0xfff); 
177
            needswrite = false;
178
            for (i = 0; i < remainder; i += 1)
179
                if (((uint8_t*)addr)[i] != 0xff)
180
                {
181
                    needswrite = true;
182
                    break;
183
                }
184
            if (needswrite) bootflash_write_internal(0, offset, remainder, addr);
185
        }
186
        addr = (void*)(((uint32_t)addr) + remainder);
187
        offset += remainder;
188
        size -= remainder;
189
    }
190
}
191
 
192
static uint32_t findflashfile(const char* filename, uint32_t* size)
193
{
194
    uint32_t i;
195
    uint32_t buf[4];
196
    spi_prepare(0);
197
    bootflash_wait_ready(0);
198
    bootflash_ce(0, true);
199
    spi_write(0, 3);
200
    spi_write(0, 0);
201
    spi_write(0, 0);
202
    spi_write(0, 0);
203
    for (i = 0; i < 0x100; i++)
204
    {
205
        spi_read(0, 16, buf);
206
        if (!memcmp(buf, filename, 8))
207
        {
208
            *size = buf[3];
209
            bootflash_ce(0, false);
210
            spi_release(0);
211
            return buf[2];
212
        }
213
    }
214
    bootflash_ce(0, false);
215
    spi_release(0);
216
    return 0;
217
}
218
 
219
int bootflash_filesize(const char* filename)
220
{
221
    uint32_t size;
222
    if (findflashfile(filename, &size)) return size & 0xfffff;
223
    else return -1;
224
}
225
 
226
int bootflash_attributes(const char* filename)
227
{
228
    uint32_t size;
229
    if (findflashfile(filename, &size)) return size >> 20;
230
    else return -1;
231
}
232
 
233
void* bootflash_getaddr(const char* filename)
234
{
235
    return NULL;
236
}
237
 
238
int bootflash_read(const char* filename, void* addr, int offset, int size)
239
{
240
    uint32_t fsize;
241
    uint32_t file = findflashfile(filename, &fsize);
242
    if (!file) return -1;
243
    fsize &= 0xfffff;
244
    if (offset + size > fsize) size = fsize - offset;
245
    if (size > 0) bootflash_readraw(addr, file + offset, size);
246
    return size;
247
}
248
 
249
void* bootflash_getrawaddr(int offset)
250
{
251
    return NULL;
252
}
253
 
254
bool bootflash_is_memmapped()
255
{
256
    return false;
257
}