xref: /inferno-os/os/port/flashintel (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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