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; | ... | ... |