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

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [host/] [flashdrvr.cpp] - Blame information for rev 11

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

Line No. Rev Author Line
1 8 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    flashdrvr.cpp
4
//
5
// Project:     CMod S6 System on a Chip, ZipCPU demonstration project
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 11 dgisselq
#include "devbus.h"
44 8 dgisselq
#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
        DEVBUS::BUSW    page[SZPAGE];
78
 
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
        DEVBUS::BUSW    buf[SZPAGE];
115
 
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 11 dgisselq
        flwait();
137
        // if ((!HIGH_SPEED)||(!verify_write)) { }
138
        if (verify_write) {
139
                // printf("Attempting to verify page\n");
140 8 dgisselq
                // NOW VERIFY THE PAGE
141
                m_fpga->readi(addr, len, buf);
142
                for(unsigned i=0; i<len; i++) {
143
                        if (buf[i] != data[i]) {
144
                                printf("\nVERIFY FAILS[%d]: %08x\n", i, i+addr);
145
                                printf("\t(Flash[%d]) %08x != %08x (Goal[%08x])\n",
146
                                        i, buf[i], data[i], i+addr);
147
                                return false;
148
                        }
149 11 dgisselq
                } // printf("\nVerify success\n");
150 8 dgisselq
        } return true;
151
}
152
 
153
bool    FLASHDRVR::write(const unsigned addr, const unsigned len,
154
                const unsigned *data, const bool verify) {
155
        // Work through this one sector at a time.
156
        // If this buffer is equal to the sector value(s), go on
157
        // If not, erase the sector
158
 
159
        // m_fpga->writeio(R_QSPI_CREG, 2);
160
        // m_fpga->readio(R_VERSION);   // Read something innocuous
161
        // m_fpga->writeio(R_QSPI_SREG, 0);
162
        // m_fpga->readio(R_VERSION);   // Read something innocuous
163
 
164
        for(unsigned s=SECTOROF(addr); s<SECTOROF(addr+len+SECTORSZ-1); s+=SECTORSZ) {
165
                // printf("IN LOOP, s=%08x\n", s);
166
                // Do we need to erase?
167
                bool    need_erase = false;
168
                unsigned newv = 0; // (s<addr)?addr:s;
169
                {
170
                        DEVBUS::BUSW    *sbuf = new DEVBUS::BUSW[SECTORSZ];
171
                        const DEVBUS::BUSW *dp;
172
                        unsigned        base,ln;
173
                        base = (addr>s)?addr:s;
174
                        ln=((addr+len>s+SECTORSZ)?(s+SECTORSZ):(addr+len))-base;
175
                        m_fpga->readi(base, ln, sbuf);
176
 
177
                        dp = &data[base-addr];
178
                        for(unsigned i=0; i<ln; i++) {
179
                                if ((sbuf[i]&dp[i]) != dp[i]) {
180
                                        printf("\nNEED-ERASE @0x%08x ... %08x != %08x (Goal)\n",
181
                                                i+base-addr, sbuf[i], dp[i]);
182
                                        need_erase = true;
183
                                        newv = i+base;
184
                                        break;
185
                                } else if ((sbuf[i] != dp[i])&&(newv == 0)) {
186
                                        // if (newv == 0)
187
                                                // printf("MEM[%08x] = %08x (!= %08x (Goal))\n",
188
                                                        // i+base, sbuf[i], dp[i]);
189
                                        newv = i+base;
190
                                }
191
                        }
192
                }
193
 
194
                if (newv == 0)
195
                        continue; // This sector already matches
196
 
197
                // Just erase anyway
198 11 dgisselq
                if (!need_erase)
199 8 dgisselq
                        printf("NO ERASE NEEDED\n");
200
                else {
201
                        printf("ERASING SECTOR %08x\n", s);
202 11 dgisselq
                        if (!erase_sector(s, verify)) {
203
                                printf("SECTOR ERASE FAILED!\n");
204
                                return false;
205
                        } newv = (s<addr) ? addr : s;
206 8 dgisselq
                }
207 11 dgisselq
                for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) {
208
                        unsigned start = p, len = addr+len-start;
209
 
210
                        // BUT! if we cross page boundaries, we need to clip
211
                        // our results to the page boundary
212
                        if (PAGEOF(start+len-1)!=PAGEOF(start))
213
                                len = PAGEOF(start+PGLEN)-start;
214
                        if (!write_page(start, len, &data[p-addr], verify)) {
215 8 dgisselq
                                printf("WRITE-PAGE FAILED!\n");
216
                                return false;
217 11 dgisselq
                        }
218 8 dgisselq
                }
219
        }
220
 
221
        m_fpga->writeio(R_QSPI_EREG, 0); // Re-enable write protection
222
 
223
        return true;
224
}
225
 

powered by: WebSVN 2.1.0

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