1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 #include "../port/flashif.h" 10 11 /* 12 * AMD29F0x0 with 4 interleaved to give 32 bits 13 */ 14 15 enum { 16 DQ7 = 0x80808080, 17 DQ6 = 0x40404040, 18 DQ5 = 0x20202020, 19 DQ3 = 0x08080808, 20 DQ2 = 0x04040404, 21 }; 22 23 #define DPRINT if(0)print 24 #define EPRINT if(1)print 25 26 static char* 27 amdwait(ulong *p, ulong ticks) 28 { 29 ulong v0, v1; 30 31 ticks += m->ticks+1; 32 v0 = *p; 33 for(;;){ 34 sched(); 35 v1 = *p; 36 if((v1 & DQ6) == (v0 & DQ6)) 37 break; 38 if((v1 & DQ5) == DQ5){ 39 v0 = *p; 40 v1 = *p; 41 if((v1 & DQ6) == (v0 & DQ6)) 42 break; 43 EPRINT("flash: DQ5 error: %8.8lux %8.8lux\n", v0, v1); 44 return "flash write error"; 45 } 46 if(m->ticks >= ticks){ 47 EPRINT("flash: timed out: %8.8lux\n", *p); 48 return "flash write timed out"; 49 } 50 v0 = v1; 51 } 52 return nil; 53 } 54 55 static int 56 eraseall(Flash *f) 57 { 58 ulong *p; 59 int s; 60 char *e; 61 62 DPRINT("flash: erase all\n"); 63 p = (ulong*)f->addr; 64 s = splhi(); 65 *(p+0x555) = 0xAAAAAAAA; 66 *(p+0x2AA) = 0x55555555; 67 *(p+0x555) = 0x80808080; 68 *(p+0x555) = 0xAAAAAAAA; 69 *(p+0x2AA) = 0x55555555; 70 *(p+0x555) = 0x10101010; /* chip erase */ 71 splx(s); 72 e = amdwait(p, MS2TK(64*1000)); 73 *p = 0xF0F0F0F0; /* reset */ 74 if(e != nil) 75 error(e); 76 return 0; 77 } 78 79 static int 80 erasezone(Flash *f, Flashregion *r, ulong addr) 81 { 82 ulong *p; 83 int s; 84 char *e; 85 86 DPRINT("flash: erase %8.8lux\n", addr); 87 if(addr & (r->erasesize-1)) 88 return -1; /* bad zone */ 89 p = (ulong*)f->addr; 90 s = splhi(); 91 *(p+0x555) = 0xAAAAAAAA; 92 *(p+0x2AA) = 0x55555555; 93 *(p+0x555) = 0x80808080; 94 *(p+0x555) = 0xAAAAAAAA; 95 *(p+0x2AA) = 0x55555555; 96 p += addr>>2; 97 *p = 0x30303030; /* sector erase */ 98 splx(s); 99 e = amdwait(p, MS2TK(8*1000)); 100 *p = 0xF0F0F0F0; /* reset */ 101 if(e != nil) 102 error(e); 103 return 0; 104 } 105 106 static int 107 write4(Flash *f, ulong offset, void *buf, long n) 108 { 109 ulong *p, *a, *v, w; 110 int s; 111 char *e; 112 113 p = (ulong*)f->addr; 114 if(((ulong)p|offset|n)&3) 115 return -1; 116 n >>= 2; 117 a = p + (offset>>2); 118 v = buf; 119 for(; --n >= 0; v++, a++){ 120 w = *a; 121 DPRINT("flash: write %lux %lux -> %lux\n", (ulong)a, w, *v); 122 if(w == *v) 123 continue; /* already set */ 124 if(~w & *v) 125 error("flash not erased"); 126 s = splhi(); 127 *(p+0x555) = 0xAAAAAAAA; 128 *(p+0x2AA) = 0x55555555; 129 *(p+0x555) = 0xA0A0A0A0; /* program */ 130 *a = *v; 131 splx(s); 132 microdelay(8); 133 if(*a != *v){ 134 microdelay(8); 135 while(*a != *v){ 136 e = amdwait(a, 1); 137 if(e != nil) 138 error(e); 139 } 140 } 141 } 142 return 0; 143 } 144 145 static int 146 reset(Flash *f) 147 { 148 f->id = 0x01; /* can't use autoselect: might be running in flash */ 149 f->devid = 0; 150 f->write = write4; 151 f->eraseall = eraseall; 152 f->erasezone = erasezone; 153 f->suspend = nil; 154 f->resume = nil; 155 f->width = 4; 156 f->interleave = 0; /* TO DO */ 157 f->nr = 1; 158 f->regions[0] = (Flashregion){f->size/(4*64*1024), 0, f->size, 4*64*1024, 0}; 159 *(ulong*)f->addr = 0xF0F0F0F0; /* reset (just in case) */ 160 return 0; 161 } 162 163 void 164 flashamd29f0x0link(void) 165 { 166 addflashcard("AMD29F0x0", reset); 167 } 168