1 2enum { 3 DQ7 = I(0x80), 4 DQ6 = I(0x40), 5 DQ5 = I(0x20), 6 DQ4 = I(0x10), 7 DQ3 = I(0x08), 8 DQ2 = I(0x04), 9 DQ1 = I(0x02), 10 DQ0 = I(0x01), 11}; 12 13/* 14 * intel algorithm 15 */ 16 17enum { 18 ReadID = I(0x90), 19 ClearStatus = I(0x50), 20 ReadStatus = I(0x70), 21 Program = I(0x40), 22 BlockErase = I(0x20), 23 Confirm = I(0xD0), 24}; 25 26#define DPRINT if(0)print 27#define EPRINT if(1)print 28 29static char* 30intelwait(Flash *f, void *p, ulong ticks) 31{ 32 ulong csr, mask; 33 34 ticks += m->ticks+1; 35 mask = f->cmask; 36 for(;;){ 37 if(f->width == 2) 38 csr = *(ushort*)p; 39 else 40 csr = *(ulong*)p; 41 if((csr & mask) == (DQ7 & mask)) 42 break; 43 sched(); 44 if(m->ticks >= ticks) 45 return "flash write timed out"; 46 } 47 if(csr & (DQ5|DQ4|DQ3|DQ1)){ 48 EPRINT("flash: error: %8.8lux %8.8lux\n", p, csr); 49 if(csr & DQ1) 50 return "flash block locked"; 51 if(csr & DQ3) 52 return "low flash programming voltage"; 53 return Eio; 54 } 55 return nil; 56} 57 58static int 59intelerase(Flash *f, Flashregion *r, ulong addr) 60{ 61 int s; 62 char *e; 63 64 DPRINT("flash: erase zone %8.8lux\n", addr); 65 if(addr & (r->erasesize-1)) 66 return -1; /* bad zone */ 67 if(f->width == 2){ 68 ushort *p = (ushort*)((ulong)f->addr + addr); 69 s = splhi(); 70 *p = BlockErase & f->cmask; 71 *p = Confirm & f->cmask; 72 splx(s); 73 e = intelwait(f, p, MS2TK(8*1000)); 74 *p = ClearStatus & f->cmask; 75 *p = ReadArray & f->cmask; 76 }else{ 77 ulong *p = (ulong*)((ulong)f->addr + addr); 78 s = splhi(); 79 *p = BlockErase & f->cmask; 80 *p = Confirm & f->cmask; 81 splx(s); 82 e = intelwait(f, p, MS2TK(8*1000)); 83 *p = ClearStatus & f->cmask; 84 *p = ReadArray & f->cmask; 85 } 86 if(e != nil) 87 error(e); 88 return 0; 89} 90 91static int 92intelwrite2(Flash *f, ulong offset, void *buf, long n) 93{ 94 ushort *a, *v; 95 ulong w; 96 int s; 97 char *e; 98 99 if(((ulong)f->addr|offset|n)&(f->width-1)) 100 return -1; 101 a = (ushort*)((ulong)f->addr + offset); 102 n /= f->width; 103 v = buf; 104 if(waserror()){ 105 *a = ClearStatus & f->cmask; 106 *a = ReadArray & f->cmask; 107 nexterror(); 108 } 109 for(; --n >= 0; v++, a++){ 110 w = *a; 111 DPRINT("flash: write %p %#ulx -> %#lux\n", a, w, (ulong)*v); 112 if(w == *v) 113 continue; /* already set */ 114 if(~w & *v) 115 error("flash not erased"); 116 s = splhi(); 117 *a = Program & f->cmask; /* program */ 118 *a = *v; 119 splx(s); 120 microdelay(8); 121 e = intelwait(f, a, 5); 122 *a = ClearStatus & f->cmask; 123 *a = ReadArray & f->cmask; 124 if(e != nil) 125 error(e); 126 w = *a; 127 if(w != *v){ 128 EPRINT("flash: write %p %#8.8lux -> %#8.8lux failed\n", a, w, (ulong)*v); 129 error(Eio); 130 } 131 } 132 poperror(); 133 return 0; 134} 135 136static int 137intelwrite4(Flash *f, ulong offset, void *buf, long n) 138{ 139 ulong *a, *v; 140 ulong w; 141 int s; 142 char *e; 143 144 if(((ulong)f->addr|offset|n)&(f->width-1)) 145 return -1; 146 a = (ulong*)((ulong)f->addr + offset); 147 n /= f->width; 148 v = buf; 149 if(waserror()){ 150 *a = ClearStatus & f->cmask; 151 *a = ReadArray & f->cmask; 152 nexterror(); 153 } 154 for(; --n >= 0; v++, a++){ 155 w = *a; 156 DPRINT("flash: write %p %#ulx -> %#lux\n", a, w, (ulong)*v); 157 if(w == *v) 158 continue; /* already set */ 159 if(~w & *v) 160 error("flash not erased"); 161 s = splhi(); 162 *a = Program; /* program */ 163 *a = *v; 164 splx(s); 165 microdelay(8); 166 e = intelwait(f, a, 5); 167 *a = ClearStatus & f->cmask; 168 *a = ReadArray & f->cmask; 169 if(e != nil) 170 error(e); 171 w = *a; 172 if(w != *v){ 173 EPRINT("flash: write %p %#8.8lux -> %#8.8lux failed\n", a, w, *v); 174 error(Eio); 175 } 176 } 177 poperror(); 178 return 0; 179} 180