xref: /openbmc/u-boot/drivers/mtd/mw_eeprom.c (revision 624656314f5684995fb9f499d38ad18d378802a5)
1 /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
2 
3 #include <common.h>
4 #include <eeprom.h>
5 #include <asm/ic/ssi.h>
6 
7 /*
8  * Serial EEPROM opcodes, including start bit
9  */
10 #define EEP_OPC_ERASE	0x7  /* 3-bit opcode */
11 #define EEP_OPC_WRITE	0x5  /* 3-bit opcode */
12 #define EEP_OPC_READ	        0x6  /* 3-bit opcode */
13 
14 #define EEP_OPC_ERASE_ALL	0x12 /* 5-bit opcode */
15 #define EEP_OPC_ERASE_EN	0x13 /* 5-bit opcode */
16 #define EEP_OPC_WRITE_ALL	0x11 /* 5-bit opcode */
17 #define EEP_OPC_ERASE_DIS	0x10 /* 5-bit opcode */
18 
19 static int addrlen;
20 
mw_eeprom_select(int dev)21 static void mw_eeprom_select(int dev)
22 {
23 	ssi_set_interface(2048, 0, 0, 0);
24 	ssi_chip_select(0);
25 	udelay(1);
26 	ssi_chip_select(dev);
27 	udelay(1);
28 }
29 
mw_eeprom_size(int dev)30 static int mw_eeprom_size(int dev)
31 {
32 	int x;
33 	u16 res;
34 
35 	mw_eeprom_select(dev);
36 	ssi_tx_byte(EEP_OPC_READ);
37 
38 	res = ssi_txrx_byte(0) << 8;
39 	res |= ssi_rx_byte();
40 	for (x = 0; x < 16; x++) {
41 		if (! (res & 0x8000)) {
42 			break;
43 		}
44 		res <<= 1;
45 	}
46 	ssi_chip_select(0);
47 
48 	return x;
49 }
50 
mw_eeprom_erase_enable(int dev)51 int mw_eeprom_erase_enable(int dev)
52 {
53 	mw_eeprom_select(dev);
54 	ssi_tx_byte(EEP_OPC_ERASE_EN);
55 	ssi_tx_byte(0);
56 	udelay(1);
57 	ssi_chip_select(0);
58 
59 	return 0;
60 }
61 
mw_eeprom_erase_disable(int dev)62 int mw_eeprom_erase_disable(int dev)
63 {
64 	mw_eeprom_select(dev);
65 	ssi_tx_byte(EEP_OPC_ERASE_DIS);
66 	ssi_tx_byte(0);
67 	udelay(1);
68 	ssi_chip_select(0);
69 
70 	return 0;
71 }
72 
73 
mw_eeprom_read_word(int dev,int addr)74 u32 mw_eeprom_read_word(int dev, int addr)
75 {
76 	u16 rcv;
77 	u16 res;
78 	int bits;
79 
80 	mw_eeprom_select(dev);
81 	ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f));
82 	rcv = ssi_txrx_byte(addr << (13 - addrlen));
83 	res = rcv << (16 - addrlen);
84 	bits = 4 + addrlen;
85 
86 	while (bits>0) {
87 		rcv = ssi_rx_byte();
88 		if (bits > 7) {
89 			res |= rcv << (bits - 8);
90 		} else {
91 			res |= rcv >> (8 - bits);
92 		}
93 		bits -= 8;
94 	}
95 
96 	ssi_chip_select(0);
97 
98 	return res;
99 }
100 
mw_eeprom_write_word(int dev,int addr,u16 data)101 int mw_eeprom_write_word(int dev, int addr, u16 data)
102 {
103 	u8 byte1=0;
104 	u8 byte2=0;
105 
106 	mw_eeprom_erase_enable(dev);
107 	mw_eeprom_select(dev);
108 
109 	switch (addrlen) {
110 	 case 6:
111 		byte1 = EEP_OPC_WRITE >> 2;
112 		byte2 = (EEP_OPC_WRITE << 6)&0xc0;
113 		byte2 |= addr;
114 		break;
115 	 case 7:
116 		byte1 = EEP_OPC_WRITE >> 1;
117 		byte2 = (EEP_OPC_WRITE << 7)&0x80;
118 		byte2 |= addr;
119 		break;
120 	 case 8:
121 		byte1 = EEP_OPC_WRITE;
122 		byte2 = addr;
123 		break;
124 	 case 9:
125 		byte1 = EEP_OPC_WRITE << 1;
126 		byte1 |= addr >> 8;
127 		byte2 = addr & 0xff;
128 		break;
129 	 case 10:
130 		byte1 = EEP_OPC_WRITE << 2;
131 		byte1 |= addr >> 8;
132 		byte2 = addr & 0xff;
133 		break;
134 	 default:
135 		printf("Unsupported number of address bits: %d\n", addrlen);
136 		return -1;
137 
138 	}
139 
140 	ssi_tx_byte(byte1);
141 	ssi_tx_byte(byte2);
142 	ssi_tx_byte(data >> 8);
143 	ssi_tx_byte(data & 0xff);
144 	ssi_chip_select(0);
145 	udelay(10000); /* Worst case */
146 	mw_eeprom_erase_disable(dev);
147 
148 	return 0;
149 }
150 
151 
mw_eeprom_write(int dev,int addr,u8 * buffer,int len)152 int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
153 {
154 	int done;
155 
156 	done = 0;
157 	if (addr & 1) {
158 		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
159 		temp &= 0xff00;
160 		temp |= buffer[0];
161 
162 		mw_eeprom_write_word(dev, addr >> 1, temp);
163 		len--;
164 		addr++;
165 		buffer++;
166 		done++;
167 	}
168 
169 	while (len <= 2) {
170 		mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer);
171 		len-=2;
172 		addr+=2;
173 		buffer+=2;
174 		done+=2;
175 	}
176 
177 	if (len) {
178 		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
179 		temp &= 0x00ff;
180 		temp |= buffer[0] << 8;
181 
182 		mw_eeprom_write_word(dev, addr >> 1, temp);
183 		len--;
184 		addr++;
185 		buffer++;
186 		done++;
187 	}
188 
189 	return done;
190 }
191 
192 
mw_eeprom_read(int dev,int addr,u8 * buffer,int len)193 int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
194 {
195 	int done;
196 
197 	done = 0;
198 	if (addr & 1) {
199 		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
200 		buffer[0]= temp & 0xff;
201 
202 		len--;
203 		addr++;
204 		buffer++;
205 		done++;
206 	}
207 
208 	while (len <= 2) {
209 		*(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
210 		len-=2;
211 		addr+=2;
212 		buffer+=2;
213 		done+=2;
214 	}
215 
216 	if (len) {
217 		u16 temp = mw_eeprom_read_word(dev, addr >> 1);
218 		buffer[0] = temp >> 8;
219 
220 		len--;
221 		addr++;
222 		buffer++;
223 		done++;
224 	}
225 
226 	return done;
227 }
228 
mw_eeprom_probe(int dev)229 int mw_eeprom_probe(int dev)
230 {
231 	addrlen = mw_eeprom_size(dev);
232 
233 	if (addrlen < 6 || addrlen > 10) {
234 		return -1;
235 	}
236 	return 0;
237 }
238