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

Subversion Repositories openarty

[/] [openarty/] [trunk/] [sw/] [host/] [flashdrvr.cpp] - Blame information for rev 4

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

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

powered by: WebSVN 2.1.0

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