OpenCores
URL https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk

Subversion Repositories xulalx25soc

[/] [xulalx25soc/] [trunk/] [sw/] [flashdrvr.cpp] - Blame information for rev 42

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 29 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    flashdrvr.cpp
4
//
5
// Project:     XuLA2-LX25 System on a Chip
6
//
7
// Purpose:     Flash driver.  Encapsulate writing to the flash device.
8
//
9
// Creator:     Dan Gisselquist
10
//              Gisselquist Tecnology, LLC
11
//
12
////////////////////////////////////////////////////////////////////////////////
13
//
14
// Copyright (C) 2016, Gisselquist Technology, LLC
15
//
16
// This program is free software (firmware): you can redistribute it and/or
17
// modify it under the terms of  the GNU General Public License as published
18
// by the Free Software Foundation, either version 3 of the License, or (at
19
// your option) any later version.
20
//
21
// This program is distributed in the hope that it will be useful, but WITHOUT
22
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24
// for more details.
25
//
26
// License:     GPL, v3, as defined and found on www.gnu.org,
27
//              http://www.gnu.org/licenses/gpl.html
28
//
29
//
30
////////////////////////////////////////////////////////////////////////////////
31
//
32
//
33
//
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <unistd.h>
37
#include <strings.h>
38
#include <ctype.h>
39
#include <string.h>
40
#include <signal.h>
41
#include <assert.h>
42
 
43
#include "port.h"
44
#include "regdefs.h"
45
#include "flashdrvr.h"
46
 
47
const   bool    HIGH_SPEED = false;
48
 
49
void    FLASHDRVR::flwait(void) {
50
        DEVBUS::BUSW    v;
51
 
52
        v = m_fpga->readio(R_QSPI_EREG);
53
        if ((v&ERASEFLAG)==0)
54
                return;
55
        m_fpga->writeio(R_ICONTROL, ISPIF_DIS);
56
        m_fpga->clear();
57
        m_fpga->writeio(R_ICONTROL, ISPIF_EN);
58
 
59
        do {
60
                // Start by checking that we are still erasing.  The interrupt
61
                // may have been generated while we were setting things up and
62
                // disabling things, so this just double checks for us.  If
63
                // the interrupt was tripped, we're done.  If not, we can now
64
                // wait for an interrupt.
65
                v = m_fpga->readio(R_QSPI_EREG);
66
                if (v&ERASEFLAG) {
67
                        m_fpga->usleep(400);
68
                        if (m_fpga->poll()) {
69
                                m_fpga->clear();
70
                                m_fpga->writeio(R_ICONTROL, ISPIF_EN);
71
                        }
72
                }
73
        } while(v & ERASEFLAG);
74
}
75
 
76
bool    FLASHDRVR::erase_sector(const unsigned sector, const bool verify_erase) {
77 38 dgisselq
        DEVBUS::BUSW    page[SZPAGE];
78 29 dgisselq
 
79
        printf("Erasing sector: %08x\n", sector);
80
        m_fpga->writeio(R_QSPI_EREG, DISABLEWP);
81
        m_fpga->writeio(R_QSPI_EREG, ERASEFLAG + sector);
82
 
83
        // If we're in high speed mode and we want to verify the erase, then
84
        // we can skip waiting for the erase to complete by issueing a read
85
        // command immediately.  As soon as the erase completes the read will
86
        // begin sending commands back.  This allows us to recover the lost 
87
        // time between the interrupt and the next command being received.
88
        if  ((!HIGH_SPEED)||(!verify_erase)) {
89
                flwait();
90
 
91
                printf("@%08x -> %08x\n", R_QSPI_EREG,
92
                                m_fpga->readio(R_QSPI_EREG));
93
                printf("@%08x -> %08x\n", R_QSPI_SREG,
94
                                m_fpga->readio(R_QSPI_SREG));
95
                printf("@%08x -> %08x\n", sector,
96
                                m_fpga->readio(sector));
97
        }
98
 
99
        // Now, let's verify that we erased the sector properly
100
        if (verify_erase) {
101
                for(int i=0; i<NPAGES; i++) {
102
                        m_fpga->readi(sector+i*SZPAGE, SZPAGE, page);
103
                        for(int i=0; i<SZPAGE; i++)
104
                                if (page[i] != 0xffffffff)
105
                                        return false;
106
                }
107
        }
108
 
109
        return true;
110
}
111
 
112
bool    FLASHDRVR::write_page(const unsigned addr, const unsigned len,
113
                const unsigned *data, const bool verify_write) {
114 38 dgisselq
        DEVBUS::BUSW    buf[SZPAGE];
115 29 dgisselq
 
116
        assert(len > 0);
117
        assert(len <= PGLEN);
118
        assert(PAGEOF(addr)==PAGEOF(addr+len-1));
119
 
120
        if (len <= 0)
121
                return true;
122
 
123
        // Write the page
124
        m_fpga->writeio(R_ICONTROL, ISPIF_DIS);
125
        m_fpga->clear();
126
        m_fpga->writeio(R_ICONTROL, ISPIF_EN);
127
        printf("Writing page: 0x%08x - 0x%08x\n", addr, addr+len-1);
128
        m_fpga->writeio(R_QSPI_EREG, DISABLEWP);
129
        m_fpga->writei(addr, len, data);
130
 
131
        // If we're in high speed mode and we want to verify the write, then
132
        // we can skip waiting for the write to complete by issueing a read
133
        // command immediately.  As soon as the write completes the read will
134
        // begin sending commands back.  This allows us to recover the lost 
135
        // time between the interrupt and the next command being received.
136
        if ((!HIGH_SPEED)||(!verify_write)) {
137
                flwait();
138
        } if (verify_write) {
139
                // NOW VERIFY THE PAGE
140
                m_fpga->readi(addr, len, buf);
141 38 dgisselq
                for(unsigned i=0; i<len; i++) {
142 29 dgisselq
                        if (buf[i] != data[i]) {
143
                                printf("\nVERIFY FAILS[%d]: %08x\n", i, i+addr);
144
                                printf("\t(Flash[%d]) %08x != %08x (Goal[%08x])\n",
145
                                        i, buf[i], data[i], i+addr);
146
                                return false;
147
                        }
148
                }
149
        } return true;
150
}
151
 
152
bool    FLASHDRVR::write(const unsigned addr, const unsigned len,
153
                const unsigned *data, const bool verify) {
154
        // Work through this one sector at a time.
155
        // If this buffer is equal to the sector value(s), go on
156
        // If not, erase the sector
157
 
158
        // m_fpga->writeio(R_QSPI_CREG, 2);
159
        // m_fpga->readio(R_VERSION);   // Read something innocuous
160
        // m_fpga->writeio(R_QSPI_SREG, 0);
161
        // m_fpga->readio(R_VERSION);   // Read something innocuous
162
 
163
        for(unsigned s=SECTOROF(addr); s<SECTOROF(addr+len+SECTORSZ-1); s+=SECTORSZ) {
164
                // printf("IN LOOP, s=%08x\n", s);
165
                // Do we need to erase?
166
                bool    need_erase = false;
167
                unsigned newv = 0; // (s<addr)?addr:s;
168
                {
169
                        DEVBUS::BUSW    *sbuf = new DEVBUS::BUSW[SECTORSZ];
170
                        const DEVBUS::BUSW *dp;
171
                        unsigned        base,ln;
172
                        base = (addr>s)?addr:s;
173
                        ln=((addr+len>s+SECTORSZ)?(s+SECTORSZ):(addr+len))-base;
174
                        m_fpga->readi(base, ln, sbuf);
175
 
176
                        dp = &data[base-addr];
177
                        for(unsigned i=0; i<ln; i++) {
178
                                if ((sbuf[i]&dp[i]) != dp[i]) {
179
                                        printf("\nNEED-ERASE @0x%08x ... %08x != %08x (Goal)\n",
180
                                                i+base-addr, sbuf[i], dp[i]);
181
                                        need_erase = true;
182
                                        newv = i+base;
183
                                        break;
184
                                } else if ((sbuf[i] != dp[i])&&(newv == 0)) {
185
                                        // if (newv == 0)
186
                                                // printf("MEM[%08x] = %08x (!= %08x (Goal))\n",
187
                                                        // i+base, sbuf[i], dp[i]);
188
                                        newv = i+base;
189
                                }
190
                        }
191
                }
192
 
193
                if (newv == 0)
194
                        continue; // This sector already matches
195
 
196
                // Just erase anyway
197
                if ((need_erase)&&(!erase_sector(s, verify))) {
198
                        printf("SECTOR ERASE FAILED!\n");
199
                        return false;
200
                } else if (!need_erase)
201
                        printf("NO ERASE NEEDED\n");
202
                else {
203
                        printf("ERASING SECTOR %08x\n", s);
204
                        newv = (s<addr) ? addr : s;
205
                }
206
                for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN))
207
                        if (!write_page(p, (p+PGLEN<addr+len)
208
                                ?((PAGEOF(p)!=PAGEOF(p+PGLEN-1))?(PAGEOF(p+PGLEN-1)-p):PGLEN)
209
                                :(addr+len-p), &data[p-addr]), verify) {
210
                                printf("WRITE-PAGE FAILED!\n");
211
                                return false;
212
                }
213
        }
214
 
215
        m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection
216 38 dgisselq
 
217
        return true;
218 29 dgisselq
}
219
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.