Commit 130751ee24a5ec8d417fa063d3d956c54fea2033
1 parent
d7739d75
24C01 / 24C02 EEPROM emulation for Malta, by Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2458 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
125 additions
and
4 deletions
hw/mips_malta.c
... | ... | @@ -49,6 +49,7 @@ typedef struct { |
49 | 49 | uint32_t leds; |
50 | 50 | uint32_t brk; |
51 | 51 | uint32_t gpout; |
52 | + uint32_t i2cin; | |
52 | 53 | uint32_t i2coe; |
53 | 54 | uint32_t i2cout; |
54 | 55 | uint32_t i2csel; |
... | ... | @@ -83,6 +84,124 @@ static void malta_fpga_update_display(void *opaque) |
83 | 84 | qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); |
84 | 85 | } |
85 | 86 | |
87 | +/* | |
88 | + * EEPROM 24C01 / 24C02 emulation. | |
89 | + * | |
90 | + * Emulation for serial EEPROMs: | |
91 | + * 24C01 - 1024 bit (128 x 8) | |
92 | + * 24C02 - 2048 bit (256 x 8) | |
93 | + * | |
94 | + * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02. | |
95 | + */ | |
96 | + | |
97 | +//~ #define DEBUG | |
98 | + | |
99 | +#if defined(DEBUG) | |
100 | +# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args) | |
101 | +#else | |
102 | +# define logout(fmt, args...) ((void)0) | |
103 | +#endif | |
104 | + | |
105 | +struct _eeprom24c0x_t { | |
106 | + uint8_t tick; | |
107 | + uint8_t address; | |
108 | + uint8_t command; | |
109 | + uint8_t ack; | |
110 | + uint8_t scl; | |
111 | + uint8_t sda; | |
112 | + uint8_t data; | |
113 | + //~ uint16_t size; | |
114 | + uint8_t contents[256]; | |
115 | +}; | |
116 | + | |
117 | +typedef struct _eeprom24c0x_t eeprom24c0x_t; | |
118 | + | |
119 | +static eeprom24c0x_t eeprom = { | |
120 | + contents: { | |
121 | + /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00, | |
122 | + /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01, | |
123 | + /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00, | |
124 | + /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40, | |
125 | + /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00, | |
126 | + /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
127 | + /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
128 | + /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0, | |
129 | + /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
130 | + /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
131 | + /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
132 | + /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
133 | + /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
134 | + /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
135 | + /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | |
136 | + /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4, | |
137 | + }, | |
138 | +}; | |
139 | + | |
140 | +static uint8_t eeprom24c0x_read() | |
141 | +{ | |
142 | + logout("%u: scl = %u, sda = %u, data = 0x%02x\n", | |
143 | + eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); | |
144 | + return eeprom.sda; | |
145 | +} | |
146 | + | |
147 | +static void eeprom24c0x_write(int scl, int sda) | |
148 | +{ | |
149 | + if (eeprom.scl && scl && (eeprom.sda != sda)) { | |
150 | + logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n", | |
151 | + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start"); | |
152 | + if (!sda) { | |
153 | + eeprom.tick = 1; | |
154 | + eeprom.command = 0; | |
155 | + } | |
156 | + } else if (eeprom.tick == 0 && !eeprom.ack) { | |
157 | + /* Waiting for start. */ | |
158 | + logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n", | |
159 | + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); | |
160 | + } else if (!eeprom.scl && scl) { | |
161 | + logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n", | |
162 | + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); | |
163 | + if (eeprom.ack) { | |
164 | + logout("\ti2c ack bit = 0\n"); | |
165 | + sda = 0; | |
166 | + eeprom.ack = 0; | |
167 | + } else if (eeprom.sda == sda) { | |
168 | + uint8_t bit = (sda != 0); | |
169 | + logout("\ti2c bit = %d\n", bit); | |
170 | + if (eeprom.tick < 9) { | |
171 | + eeprom.command <<= 1; | |
172 | + eeprom.command += bit; | |
173 | + eeprom.tick++; | |
174 | + if (eeprom.tick == 9) { | |
175 | + logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write"); | |
176 | + eeprom.ack = 1; | |
177 | + } | |
178 | + } else if (eeprom.tick < 17) { | |
179 | + if (eeprom.command & 1) { | |
180 | + sda = ((eeprom.data & 0x80) != 0); | |
181 | + } | |
182 | + eeprom.address <<= 1; | |
183 | + eeprom.address += bit; | |
184 | + eeprom.tick++; | |
185 | + eeprom.data <<= 1; | |
186 | + if (eeprom.tick == 17) { | |
187 | + eeprom.data = eeprom.contents[eeprom.address]; | |
188 | + logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data); | |
189 | + eeprom.ack = 1; | |
190 | + eeprom.tick = 0; | |
191 | + } | |
192 | + } else if (eeprom.tick >= 17) { | |
193 | + sda = 0; | |
194 | + } | |
195 | + } else { | |
196 | + logout("\tsda changed with raising scl\n"); | |
197 | + } | |
198 | + } else { | |
199 | + logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); | |
200 | + } | |
201 | + eeprom.scl = scl; | |
202 | + eeprom.sda = sda; | |
203 | +} | |
204 | + | |
86 | 205 | static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) |
87 | 206 | { |
88 | 207 | MaltaFPGAState *s = opaque; |
... | ... | @@ -140,7 +259,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) |
140 | 259 | |
141 | 260 | /* I2CINP Register */ |
142 | 261 | case 0x00b00: |
143 | - val = 0x00000003; | |
262 | + val = ((s->i2cin & ~1) | eeprom24c0x_read()); | |
144 | 263 | break; |
145 | 264 | |
146 | 265 | /* I2COE Register */ |
... | ... | @@ -155,7 +274,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) |
155 | 274 | |
156 | 275 | /* I2CSEL Register */ |
157 | 276 | case 0x00b18: |
158 | - val = s->i2cout; | |
277 | + val = s->i2csel; | |
159 | 278 | break; |
160 | 279 | |
161 | 280 | default: |
... | ... | @@ -234,12 +353,13 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, |
234 | 353 | |
235 | 354 | /* I2COUT Register */ |
236 | 355 | case 0x00b10: |
237 | - s->i2cout = val & 0x03; | |
356 | + eeprom24c0x_write(val & 0x02, val & 0x01); | |
357 | + s->i2cout = val; | |
238 | 358 | break; |
239 | 359 | |
240 | 360 | /* I2CSEL Register */ |
241 | 361 | case 0x00b18: |
242 | - s->i2cout = val & 0x01; | |
362 | + s->i2csel = val & 0x01; | |
243 | 363 | break; |
244 | 364 | |
245 | 365 | default: |
... | ... | @@ -270,6 +390,7 @@ void malta_fpga_reset(void *opaque) |
270 | 390 | s->leds = 0x00; |
271 | 391 | s->brk = 0x0a; |
272 | 392 | s->gpout = 0x00; |
393 | + s->i2cin = 0x3; | |
273 | 394 | s->i2coe = 0x0; |
274 | 395 | s->i2cout = 0x3; |
275 | 396 | s->i2csel = 0x1; | ... | ... |