xref: /inferno-os/os/port/flashamd29f0x0.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
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