1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "qemu/osdep.h"
18
19#include "hw/i2c/npcm7xx_smbus.h"
20#include "migration/vmstate.h"
21#include "qemu/bitops.h"
22#include "qemu/guest-random.h"
23#include "qemu/log.h"
24#include "qemu/module.h"
25#include "qemu/units.h"
26
27#include "trace.h"
28
29enum NPCM7xxSMBusCommonRegister {
30 NPCM7XX_SMB_SDA = 0x0,
31 NPCM7XX_SMB_ST = 0x2,
32 NPCM7XX_SMB_CST = 0x4,
33 NPCM7XX_SMB_CTL1 = 0x6,
34 NPCM7XX_SMB_ADDR1 = 0x8,
35 NPCM7XX_SMB_CTL2 = 0xa,
36 NPCM7XX_SMB_ADDR2 = 0xc,
37 NPCM7XX_SMB_CTL3 = 0xe,
38 NPCM7XX_SMB_CST2 = 0x18,
39 NPCM7XX_SMB_CST3 = 0x19,
40 NPCM7XX_SMB_VER = 0x1f,
41};
42
43enum NPCM7xxSMBusBank0Register {
44 NPCM7XX_SMB_ADDR3 = 0x10,
45 NPCM7XX_SMB_ADDR7 = 0x11,
46 NPCM7XX_SMB_ADDR4 = 0x12,
47 NPCM7XX_SMB_ADDR8 = 0x13,
48 NPCM7XX_SMB_ADDR5 = 0x14,
49 NPCM7XX_SMB_ADDR9 = 0x15,
50 NPCM7XX_SMB_ADDR6 = 0x16,
51 NPCM7XX_SMB_ADDR10 = 0x17,
52 NPCM7XX_SMB_CTL4 = 0x1a,
53 NPCM7XX_SMB_CTL5 = 0x1b,
54 NPCM7XX_SMB_SCLLT = 0x1c,
55 NPCM7XX_SMB_FIF_CTL = 0x1d,
56 NPCM7XX_SMB_SCLHT = 0x1e,
57};
58
59enum NPCM7xxSMBusBank1Register {
60 NPCM7XX_SMB_FIF_CTS = 0x10,
61 NPCM7XX_SMB_FAIR_PER = 0x11,
62 NPCM7XX_SMB_TXF_CTL = 0x12,
63 NPCM7XX_SMB_T_OUT = 0x14,
64 NPCM7XX_SMB_TXF_STS = 0x1a,
65 NPCM7XX_SMB_RXF_STS = 0x1c,
66 NPCM7XX_SMB_RXF_CTL = 0x1e,
67};
68
69
70#define NPCM7XX_SMBST_STP BIT(7)
71#define NPCM7XX_SMBST_SDAST BIT(6)
72#define NPCM7XX_SMBST_BER BIT(5)
73#define NPCM7XX_SMBST_NEGACK BIT(4)
74#define NPCM7XX_SMBST_STASTR BIT(3)
75#define NPCM7XX_SMBST_NMATCH BIT(2)
76#define NPCM7XX_SMBST_MODE BIT(1)
77#define NPCM7XX_SMBST_XMIT BIT(0)
78
79
80#define NPCM7XX_SMBCST_ARPMATCH BIT(7)
81#define NPCM7XX_SMBCST_MATCHAF BIT(6)
82#define NPCM7XX_SMBCST_TGSCL BIT(5)
83#define NPCM7XX_SMBCST_TSDA BIT(4)
84#define NPCM7XX_SMBCST_GCMATCH BIT(3)
85#define NPCM7XX_SMBCST_MATCH BIT(2)
86#define NPCM7XX_SMBCST_BB BIT(1)
87#define NPCM7XX_SMBCST_BUSY BIT(0)
88
89
90#define NPCM7XX_SMBCST2_INTSTS BIT(7)
91#define NPCM7XX_SMBCST2_MATCH7F BIT(6)
92#define NPCM7XX_SMBCST2_MATCH6F BIT(5)
93#define NPCM7XX_SMBCST2_MATCH5F BIT(4)
94#define NPCM7XX_SMBCST2_MATCH4F BIT(3)
95#define NPCM7XX_SMBCST2_MATCH3F BIT(2)
96#define NPCM7XX_SMBCST2_MATCH2F BIT(1)
97#define NPCM7XX_SMBCST2_MATCH1F BIT(0)
98
99
100#define NPCM7XX_SMBCST3_EO_BUSY BIT(7)
101#define NPCM7XX_SMBCST3_MATCH10F BIT(2)
102#define NPCM7XX_SMBCST3_MATCH9F BIT(1)
103#define NPCM7XX_SMBCST3_MATCH8F BIT(0)
104
105
106#define NPCM7XX_SMBCTL1_STASTRE BIT(7)
107#define NPCM7XX_SMBCTL1_NMINTE BIT(6)
108#define NPCM7XX_SMBCTL1_GCMEN BIT(5)
109#define NPCM7XX_SMBCTL1_ACK BIT(4)
110#define NPCM7XX_SMBCTL1_EOBINTE BIT(3)
111#define NPCM7XX_SMBCTL1_INTEN BIT(2)
112#define NPCM7XX_SMBCTL1_STOP BIT(1)
113#define NPCM7XX_SMBCTL1_START BIT(0)
114
115
116#define NPCM7XX_SMBCTL2_SCLFRQ(rv) extract8((rv), 1, 6)
117#define NPCM7XX_SMBCTL2_ENABLE BIT(0)
118
119
120#define NPCM7XX_SMBCTL3_SCL_LVL BIT(7)
121#define NPCM7XX_SMBCTL3_SDA_LVL BIT(6)
122#define NPCM7XX_SMBCTL3_BNK_SEL BIT(5)
123#define NPCM7XX_SMBCTL3_400K_MODE BIT(4)
124#define NPCM7XX_SMBCTL3_IDL_START BIT(3)
125#define NPCM7XX_SMBCTL3_ARPMEN BIT(2)
126#define NPCM7XX_SMBCTL3_SCLFRQ(rv) extract8((rv), 0, 2)
127
128
129#define NPCM7XX_ADDR_EN BIT(7)
130#define NPCM7XX_ADDR_A(rv) extract8((rv), 0, 6)
131
132
133
134#define NPCM7XX_SMBFIF_CTL_FIFO_EN BIT(4)
135#define NPCM7XX_SMBFIF_CTL_FAIR_RDY_IE BIT(2)
136#define NPCM7XX_SMBFIF_CTL_FAIR_RDY BIT(1)
137#define NPCM7XX_SMBFIF_CTL_FAIR_BUSY BIT(0)
138
139#define NPCM7XX_SMBFIF_CTS_STR BIT(7)
140#define NPCM7XX_SMBFIF_CTS_CLR_FIFO BIT(6)
141#define NPCM7XX_SMBFIF_CTS_RFTE_IE BIT(3)
142#define NPCM7XX_SMBFIF_CTS_RXF_TXE BIT(1)
143
144#define NPCM7XX_SMBTXF_CTL_THR_TXIE BIT(6)
145#define NPCM7XX_SMBTXF_CTL_TX_THR(rv) extract8((rv), 0, 5)
146
147#define NPCM7XX_SMBT_OUT_ST BIT(7)
148#define NPCM7XX_SMBT_OUT_IE BIT(6)
149#define NPCM7XX_SMBT_OUT_CLKDIV(rv) extract8((rv), 0, 6)
150
151#define NPCM7XX_SMBTXF_STS_TX_THST BIT(6)
152#define NPCM7XX_SMBTXF_STS_TX_BYTES(rv) extract8((rv), 0, 5)
153
154#define NPCM7XX_SMBRXF_STS_RX_THST BIT(6)
155#define NPCM7XX_SMBRXF_STS_RX_BYTES(rv) extract8((rv), 0, 5)
156
157#define NPCM7XX_SMBRXF_CTL_THR_RXIE BIT(6)
158#define NPCM7XX_SMBRXF_CTL_LAST BIT(5)
159#define NPCM7XX_SMBRXF_CTL_RX_THR(rv) extract8((rv), 0, 5)
160
161#define KEEP_OLD_BIT(o, n, b) (((n) & (~(b))) | ((o) & (b)))
162#define WRITE_ONE_CLEAR(o, n, b) ((n) & (b) ? (o) & (~(b)) : (o))
163
164#define NPCM7XX_SMBUS_ENABLED(s) ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
165#define NPCM7XX_SMBUS_FIFO_ENABLED(s) ((s)->fif_ctl & \
166 NPCM7XX_SMBFIF_CTL_FIFO_EN)
167
168
169#define NPCM7XX_SMBUS_VERSION_NUMBER 1
170#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 1
171
172
173#define NPCM7XX_SMB_ST_INIT_VAL 0x00
174#define NPCM7XX_SMB_CST_INIT_VAL 0x10
175#define NPCM7XX_SMB_CST2_INIT_VAL 0x00
176#define NPCM7XX_SMB_CST3_INIT_VAL 0x00
177#define NPCM7XX_SMB_CTL1_INIT_VAL 0x00
178#define NPCM7XX_SMB_CTL2_INIT_VAL 0x00
179#define NPCM7XX_SMB_CTL3_INIT_VAL 0xc0
180#define NPCM7XX_SMB_CTL4_INIT_VAL 0x07
181#define NPCM7XX_SMB_CTL5_INIT_VAL 0x00
182#define NPCM7XX_SMB_ADDR_INIT_VAL 0x00
183#define NPCM7XX_SMB_SCLLT_INIT_VAL 0x00
184#define NPCM7XX_SMB_SCLHT_INIT_VAL 0x00
185#define NPCM7XX_SMB_FIF_CTL_INIT_VAL 0x00
186#define NPCM7XX_SMB_FIF_CTS_INIT_VAL 0x00
187#define NPCM7XX_SMB_FAIR_PER_INIT_VAL 0x00
188#define NPCM7XX_SMB_TXF_CTL_INIT_VAL 0x00
189#define NPCM7XX_SMB_T_OUT_INIT_VAL 0x3f
190#define NPCM7XX_SMB_TXF_STS_INIT_VAL 0x00
191#define NPCM7XX_SMB_RXF_STS_INIT_VAL 0x00
192#define NPCM7XX_SMB_RXF_CTL_INIT_VAL 0x01
193
194static uint8_t npcm7xx_smbus_get_version(void)
195{
196 return NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED << 7 |
197 NPCM7XX_SMBUS_VERSION_NUMBER;
198}
199
200static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
201{
202 int level;
203
204 if (s->ctl1 & NPCM7XX_SMBCTL1_INTEN) {
205 level = !!((s->ctl1 & NPCM7XX_SMBCTL1_NMINTE &&
206 s->st & NPCM7XX_SMBST_NMATCH) ||
207 (s->st & NPCM7XX_SMBST_BER) ||
208 (s->st & NPCM7XX_SMBST_NEGACK) ||
209 (s->st & NPCM7XX_SMBST_SDAST) ||
210 (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
211 s->st & NPCM7XX_SMBST_SDAST) ||
212 (s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
213 s->cst3 & NPCM7XX_SMBCST3_EO_BUSY) ||
214 (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE &&
215 s->rxf_sts & NPCM7XX_SMBRXF_STS_RX_THST) ||
216 (s->txf_ctl & NPCM7XX_SMBTXF_CTL_THR_TXIE &&
217 s->txf_sts & NPCM7XX_SMBTXF_STS_TX_THST) ||
218 (s->fif_cts & NPCM7XX_SMBFIF_CTS_RFTE_IE &&
219 s->fif_cts & NPCM7XX_SMBFIF_CTS_RXF_TXE));
220
221 if (level) {
222 s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
223 } else {
224 s->cst2 &= ~NPCM7XX_SMBCST2_INTSTS;
225 }
226 qemu_set_irq(s->irq, level);
227 }
228}
229
230static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
231{
232 s->st &= ~NPCM7XX_SMBST_SDAST;
233 s->st |= NPCM7XX_SMBST_NEGACK;
234 s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
235}
236
237static void npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState *s)
238{
239 s->fif_cts &= ~NPCM7XX_SMBFIF_CTS_RXF_TXE;
240 s->txf_sts = 0;
241 s->rxf_sts = 0;
242}
243
244static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
245{
246 int rv = i2c_send(s->bus, value);
247
248 if (rv) {
249 npcm7xx_smbus_nack(s);
250 } else {
251 s->st |= NPCM7XX_SMBST_SDAST;
252 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
253 s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
254 if (NPCM7XX_SMBTXF_STS_TX_BYTES(s->txf_sts) ==
255 NPCM7XX_SMBTXF_CTL_TX_THR(s->txf_ctl)) {
256 s->txf_sts = NPCM7XX_SMBTXF_STS_TX_THST;
257 } else {
258 s->txf_sts = 0;
259 }
260 }
261 }
262 trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
263 npcm7xx_smbus_update_irq(s);
264}
265
266static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
267{
268 s->sda = i2c_recv(s->bus);
269 s->st |= NPCM7XX_SMBST_SDAST;
270 if (s->st & NPCM7XX_SMBCTL1_ACK) {
271 trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
272 i2c_nack(s->bus);
273 s->st &= NPCM7XX_SMBCTL1_ACK;
274 }
275 trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path), s->sda);
276 npcm7xx_smbus_update_irq(s);
277}
278
279static void npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState *s)
280{
281 uint8_t expected_bytes = NPCM7XX_SMBRXF_CTL_RX_THR(s->rxf_ctl);
282 uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
283 uint8_t pos;
284
285 if (received_bytes == expected_bytes) {
286 return;
287 }
288
289 while (received_bytes < expected_bytes &&
290 received_bytes < NPCM7XX_SMBUS_FIFO_SIZE) {
291 pos = (s->rx_cur + received_bytes) % NPCM7XX_SMBUS_FIFO_SIZE;
292 s->rx_fifo[pos] = i2c_recv(s->bus);
293 trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path),
294 s->rx_fifo[pos]);
295 ++received_bytes;
296 }
297
298 trace_npcm7xx_smbus_recv_fifo((DEVICE(s)->canonical_path),
299 received_bytes, expected_bytes);
300 s->rxf_sts = received_bytes;
301 if (unlikely(received_bytes < expected_bytes)) {
302 qemu_log_mask(LOG_GUEST_ERROR,
303 "%s: invalid rx_thr value: 0x%02x\n",
304 DEVICE(s)->canonical_path, expected_bytes);
305 return;
306 }
307
308 s->rxf_sts |= NPCM7XX_SMBRXF_STS_RX_THST;
309 if (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_LAST) {
310 trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
311 i2c_nack(s->bus);
312 s->rxf_ctl &= ~NPCM7XX_SMBRXF_CTL_LAST;
313 }
314 if (received_bytes == NPCM7XX_SMBUS_FIFO_SIZE) {
315 s->st |= NPCM7XX_SMBST_SDAST;
316 s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
317 } else if (!(s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE)) {
318 s->st |= NPCM7XX_SMBST_SDAST;
319 } else {
320 s->st &= ~NPCM7XX_SMBST_SDAST;
321 }
322 npcm7xx_smbus_update_irq(s);
323}
324
325static void npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState *s)
326{
327 uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
328
329 if (received_bytes == 0) {
330 npcm7xx_smbus_recv_fifo(s);
331 return;
332 }
333
334 s->sda = s->rx_fifo[s->rx_cur];
335 s->rx_cur = (s->rx_cur + 1u) % NPCM7XX_SMBUS_FIFO_SIZE;
336 --s->rxf_sts;
337 npcm7xx_smbus_update_irq(s);
338}
339
340static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
341{
342
343
344
345
346
347 int available = !i2c_bus_busy(s->bus) ||
348 s->status != NPCM7XX_SMBUS_STATUS_IDLE;
349
350 if (available) {
351 s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
352 s->cst |= NPCM7XX_SMBCST_BUSY;
353 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
354 s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
355 }
356 } else {
357 s->st &= ~NPCM7XX_SMBST_MODE;
358 s->cst &= ~NPCM7XX_SMBCST_BUSY;
359 s->st |= NPCM7XX_SMBST_BER;
360 }
361
362 trace_npcm7xx_smbus_start(DEVICE(s)->canonical_path, available);
363 s->cst |= NPCM7XX_SMBCST_BB;
364 s->status = NPCM7XX_SMBUS_STATUS_IDLE;
365 npcm7xx_smbus_update_irq(s);
366}
367
368static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
369{
370 int recv;
371 int rv;
372
373 recv = value & BIT(0);
374 rv = i2c_start_transfer(s->bus, value >> 1, recv);
375 trace_npcm7xx_smbus_send_address(DEVICE(s)->canonical_path,
376 value >> 1, recv, !rv);
377 if (rv) {
378 qemu_log_mask(LOG_GUEST_ERROR,
379 "%s: requesting i2c bus for 0x%02x failed: %d\n",
380 DEVICE(s)->canonical_path, value, rv);
381
382 if (recv) {
383 s->st &= ~NPCM7XX_SMBST_XMIT;
384 } else {
385 s->st |= NPCM7XX_SMBST_XMIT;
386 }
387 npcm7xx_smbus_nack(s);
388 npcm7xx_smbus_update_irq(s);
389 return;
390 }
391
392 s->st &= ~NPCM7XX_SMBST_NEGACK;
393 if (recv) {
394 s->status = NPCM7XX_SMBUS_STATUS_RECEIVING;
395 s->st &= ~NPCM7XX_SMBST_XMIT;
396 } else {
397 s->status = NPCM7XX_SMBUS_STATUS_SENDING;
398 s->st |= NPCM7XX_SMBST_XMIT;
399 }
400
401 if (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE) {
402 s->st |= NPCM7XX_SMBST_STASTR;
403 if (!recv) {
404 s->st |= NPCM7XX_SMBST_SDAST;
405 }
406 } else if (recv) {
407 s->st |= NPCM7XX_SMBST_SDAST;
408 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
409 npcm7xx_smbus_recv_fifo(s);
410 } else {
411 npcm7xx_smbus_recv_byte(s);
412 }
413 } else if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
414 s->st |= NPCM7XX_SMBST_SDAST;
415 s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
416 }
417 npcm7xx_smbus_update_irq(s);
418}
419
420static void npcm7xx_smbus_execute_stop(NPCM7xxSMBusState *s)
421{
422 i2c_end_transfer(s->bus);
423 s->st = 0;
424 s->cst = 0;
425 s->status = NPCM7XX_SMBUS_STATUS_IDLE;
426 s->cst3 |= NPCM7XX_SMBCST3_EO_BUSY;
427 trace_npcm7xx_smbus_stop(DEVICE(s)->canonical_path);
428 npcm7xx_smbus_update_irq(s);
429}
430
431
432static void npcm7xx_smbus_stop(NPCM7xxSMBusState *s)
433{
434 if (s->st & NPCM7XX_SMBST_MODE) {
435 switch (s->status) {
436 case NPCM7XX_SMBUS_STATUS_RECEIVING:
437 case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
438 s->status = NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE;
439 break;
440
441 case NPCM7XX_SMBUS_STATUS_NEGACK:
442 s->status = NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK;
443 break;
444
445 default:
446 npcm7xx_smbus_execute_stop(s);
447 break;
448 }
449 }
450}
451
452static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
453{
454 uint8_t value = s->sda;
455
456 switch (s->status) {
457 case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
458 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
459 if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) <= 1) {
460 npcm7xx_smbus_execute_stop(s);
461 }
462 if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) == 0) {
463 qemu_log_mask(LOG_GUEST_ERROR,
464 "%s: read to SDA with an empty rx-fifo buffer, "
465 "result undefined: %u\n",
466 DEVICE(s)->canonical_path, s->sda);
467 break;
468 }
469 npcm7xx_smbus_read_byte_fifo(s);
470 value = s->sda;
471 } else {
472 npcm7xx_smbus_execute_stop(s);
473 }
474 break;
475
476 case NPCM7XX_SMBUS_STATUS_RECEIVING:
477 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
478 npcm7xx_smbus_read_byte_fifo(s);
479 value = s->sda;
480 } else {
481 npcm7xx_smbus_recv_byte(s);
482 }
483 break;
484
485 default:
486
487 break;
488 }
489
490 return value;
491}
492
493static void npcm7xx_smbus_write_sda(NPCM7xxSMBusState *s, uint8_t value)
494{
495 s->sda = value;
496 if (s->st & NPCM7XX_SMBST_MODE) {
497 switch (s->status) {
498 case NPCM7XX_SMBUS_STATUS_IDLE:
499 npcm7xx_smbus_send_address(s, value);
500 break;
501 case NPCM7XX_SMBUS_STATUS_SENDING:
502 npcm7xx_smbus_send_byte(s, value);
503 break;
504 default:
505 qemu_log_mask(LOG_GUEST_ERROR,
506 "%s: write to SDA in invalid status %d: %u\n",
507 DEVICE(s)->canonical_path, s->status, value);
508 break;
509 }
510 }
511}
512
513static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
514{
515 s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STP);
516 s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_BER);
517 s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STASTR);
518 s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_NMATCH);
519
520 if (value & NPCM7XX_SMBST_NEGACK) {
521 s->st &= ~NPCM7XX_SMBST_NEGACK;
522 if (s->status == NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK) {
523 npcm7xx_smbus_execute_stop(s);
524 }
525 }
526
527 if (value & NPCM7XX_SMBST_STASTR &&
528 s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
529 if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
530 npcm7xx_smbus_recv_fifo(s);
531 } else {
532 npcm7xx_smbus_recv_byte(s);
533 }
534 }
535
536 npcm7xx_smbus_update_irq(s);
537}
538
539static void npcm7xx_smbus_write_cst(NPCM7xxSMBusState *s, uint8_t value)
540{
541 uint8_t new_value = s->cst;
542
543 s->cst = WRITE_ONE_CLEAR(new_value, value, NPCM7XX_SMBCST_BB);
544 npcm7xx_smbus_update_irq(s);
545}
546
547static void npcm7xx_smbus_write_cst3(NPCM7xxSMBusState *s, uint8_t value)
548{
549 s->cst3 = WRITE_ONE_CLEAR(s->cst3, value, NPCM7XX_SMBCST3_EO_BUSY);
550 npcm7xx_smbus_update_irq(s);
551}
552
553static void npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState *s, uint8_t value)
554{
555 s->ctl1 = KEEP_OLD_BIT(s->ctl1, value,
556 NPCM7XX_SMBCTL1_START | NPCM7XX_SMBCTL1_STOP | NPCM7XX_SMBCTL1_ACK);
557
558 if (value & NPCM7XX_SMBCTL1_START) {
559 npcm7xx_smbus_start(s);
560 }
561
562 if (value & NPCM7XX_SMBCTL1_STOP) {
563 npcm7xx_smbus_stop(s);
564 }
565
566 npcm7xx_smbus_update_irq(s);
567}
568
569static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
570{
571 s->ctl2 = value;
572
573 if (!NPCM7XX_SMBUS_ENABLED(s)) {
574
575 s->ctl1 = 0;
576 s->st = 0;
577 s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
578 s->cst = 0;
579 npcm7xx_smbus_clear_buffer(s);
580 }
581}
582
583static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
584{
585 uint8_t old_ctl3 = s->ctl3;
586
587
588 s->ctl3 = KEEP_OLD_BIT(old_ctl3, value,
589 NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
590}
591
592static void npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState *s, uint8_t value)
593{
594 uint8_t new_ctl = value;
595
596 new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
597 new_ctl = WRITE_ONE_CLEAR(new_ctl, value, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
598 new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_BUSY);
599 s->fif_ctl = new_ctl;
600}
601
602static void npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState *s, uint8_t value)
603{
604 s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_STR);
605 s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_RXF_TXE);
606 s->fif_cts = KEEP_OLD_BIT(value, s->fif_cts, NPCM7XX_SMBFIF_CTS_RFTE_IE);
607
608 if (value & NPCM7XX_SMBFIF_CTS_CLR_FIFO) {
609 npcm7xx_smbus_clear_buffer(s);
610 }
611}
612
613static void npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState *s, uint8_t value)
614{
615 s->txf_ctl = value;
616}
617
618static void npcm7xx_smbus_write_t_out(NPCM7xxSMBusState *s, uint8_t value)
619{
620 uint8_t new_t_out = value;
621
622 if ((value & NPCM7XX_SMBT_OUT_ST) || (!(s->t_out & NPCM7XX_SMBT_OUT_ST))) {
623 new_t_out &= ~NPCM7XX_SMBT_OUT_ST;
624 } else {
625 new_t_out |= NPCM7XX_SMBT_OUT_ST;
626 }
627
628 s->t_out = new_t_out;
629}
630
631static void npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState *s, uint8_t value)
632{
633 s->txf_sts = WRITE_ONE_CLEAR(s->txf_sts, value, NPCM7XX_SMBTXF_STS_TX_THST);
634}
635
636static void npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState *s, uint8_t value)
637{
638 if (value & NPCM7XX_SMBRXF_STS_RX_THST) {
639 s->rxf_sts &= ~NPCM7XX_SMBRXF_STS_RX_THST;
640 if (s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
641 npcm7xx_smbus_recv_fifo(s);
642 }
643 }
644}
645
646static void npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState *s, uint8_t value)
647{
648 uint8_t new_ctl = value;
649
650 if (!(value & NPCM7XX_SMBRXF_CTL_LAST)) {
651 new_ctl = KEEP_OLD_BIT(s->rxf_ctl, new_ctl, NPCM7XX_SMBRXF_CTL_LAST);
652 }
653 s->rxf_ctl = new_ctl;
654}
655
656static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
657{
658 NPCM7xxSMBusState *s = opaque;
659 uint64_t value = 0;
660 uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
661
662
663 switch (offset) {
664 case NPCM7XX_SMB_SDA:
665 value = npcm7xx_smbus_read_sda(s);
666 break;
667
668 case NPCM7XX_SMB_ST:
669 value = s->st;
670 break;
671
672 case NPCM7XX_SMB_CST:
673 value = s->cst;
674 break;
675
676 case NPCM7XX_SMB_CTL1:
677 value = s->ctl1;
678 break;
679
680 case NPCM7XX_SMB_ADDR1:
681 value = s->addr[0];
682 break;
683
684 case NPCM7XX_SMB_CTL2:
685 value = s->ctl2;
686 break;
687
688 case NPCM7XX_SMB_ADDR2:
689 value = s->addr[1];
690 break;
691
692 case NPCM7XX_SMB_CTL3:
693 value = s->ctl3;
694 break;
695
696 case NPCM7XX_SMB_CST2:
697 value = s->cst2;
698 break;
699
700 case NPCM7XX_SMB_CST3:
701 value = s->cst3;
702 break;
703
704 case NPCM7XX_SMB_VER:
705 value = npcm7xx_smbus_get_version();
706 break;
707
708
709 default:
710 if (bank) {
711
712 switch (offset) {
713 case NPCM7XX_SMB_FIF_CTS:
714 value = s->fif_cts;
715 break;
716
717 case NPCM7XX_SMB_FAIR_PER:
718 value = s->fair_per;
719 break;
720
721 case NPCM7XX_SMB_TXF_CTL:
722 value = s->txf_ctl;
723 break;
724
725 case NPCM7XX_SMB_T_OUT:
726 value = s->t_out;
727 break;
728
729 case NPCM7XX_SMB_TXF_STS:
730 value = s->txf_sts;
731 break;
732
733 case NPCM7XX_SMB_RXF_STS:
734 value = s->rxf_sts;
735 break;
736
737 case NPCM7XX_SMB_RXF_CTL:
738 value = s->rxf_ctl;
739 break;
740
741 default:
742 qemu_log_mask(LOG_GUEST_ERROR,
743 "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
744 DEVICE(s)->canonical_path, offset);
745 break;
746 }
747 } else {
748
749 switch (offset) {
750 case NPCM7XX_SMB_ADDR3:
751 value = s->addr[2];
752 break;
753
754 case NPCM7XX_SMB_ADDR7:
755 value = s->addr[6];
756 break;
757
758 case NPCM7XX_SMB_ADDR4:
759 value = s->addr[3];
760 break;
761
762 case NPCM7XX_SMB_ADDR8:
763 value = s->addr[7];
764 break;
765
766 case NPCM7XX_SMB_ADDR5:
767 value = s->addr[4];
768 break;
769
770 case NPCM7XX_SMB_ADDR9:
771 value = s->addr[8];
772 break;
773
774 case NPCM7XX_SMB_ADDR6:
775 value = s->addr[5];
776 break;
777
778 case NPCM7XX_SMB_ADDR10:
779 value = s->addr[9];
780 break;
781
782 case NPCM7XX_SMB_CTL4:
783 value = s->ctl4;
784 break;
785
786 case NPCM7XX_SMB_CTL5:
787 value = s->ctl5;
788 break;
789
790 case NPCM7XX_SMB_SCLLT:
791 value = s->scllt;
792 break;
793
794 case NPCM7XX_SMB_FIF_CTL:
795 value = s->fif_ctl;
796 break;
797
798 case NPCM7XX_SMB_SCLHT:
799 value = s->sclht;
800 break;
801
802 default:
803 qemu_log_mask(LOG_GUEST_ERROR,
804 "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
805 DEVICE(s)->canonical_path, offset);
806 break;
807 }
808 }
809 break;
810 }
811
812 trace_npcm7xx_smbus_read(DEVICE(s)->canonical_path, offset, value, size);
813
814 return value;
815}
816
817static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
818 unsigned size)
819{
820 NPCM7xxSMBusState *s = opaque;
821 uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
822
823 trace_npcm7xx_smbus_write(DEVICE(s)->canonical_path, offset, value, size);
824
825
826 switch (offset) {
827 case NPCM7XX_SMB_SDA:
828 npcm7xx_smbus_write_sda(s, value);
829 break;
830
831 case NPCM7XX_SMB_ST:
832 npcm7xx_smbus_write_st(s, value);
833 break;
834
835 case NPCM7XX_SMB_CST:
836 npcm7xx_smbus_write_cst(s, value);
837 break;
838
839 case NPCM7XX_SMB_CTL1:
840 npcm7xx_smbus_write_ctl1(s, value);
841 break;
842
843 case NPCM7XX_SMB_ADDR1:
844 s->addr[0] = value;
845 break;
846
847 case NPCM7XX_SMB_CTL2:
848 npcm7xx_smbus_write_ctl2(s, value);
849 break;
850
851 case NPCM7XX_SMB_ADDR2:
852 s->addr[1] = value;
853 break;
854
855 case NPCM7XX_SMB_CTL3:
856 npcm7xx_smbus_write_ctl3(s, value);
857 break;
858
859 case NPCM7XX_SMB_CST2:
860 qemu_log_mask(LOG_GUEST_ERROR,
861 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
862 DEVICE(s)->canonical_path, offset);
863 break;
864
865 case NPCM7XX_SMB_CST3:
866 npcm7xx_smbus_write_cst3(s, value);
867 break;
868
869 case NPCM7XX_SMB_VER:
870 qemu_log_mask(LOG_GUEST_ERROR,
871 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
872 DEVICE(s)->canonical_path, offset);
873 break;
874
875
876 default:
877 if (bank) {
878
879 switch (offset) {
880 case NPCM7XX_SMB_FIF_CTS:
881 npcm7xx_smbus_write_fif_cts(s, value);
882 break;
883
884 case NPCM7XX_SMB_FAIR_PER:
885 s->fair_per = value;
886 break;
887
888 case NPCM7XX_SMB_TXF_CTL:
889 npcm7xx_smbus_write_txf_ctl(s, value);
890 break;
891
892 case NPCM7XX_SMB_T_OUT:
893 npcm7xx_smbus_write_t_out(s, value);
894 break;
895
896 case NPCM7XX_SMB_TXF_STS:
897 npcm7xx_smbus_write_txf_sts(s, value);
898 break;
899
900 case NPCM7XX_SMB_RXF_STS:
901 npcm7xx_smbus_write_rxf_sts(s, value);
902 break;
903
904 case NPCM7XX_SMB_RXF_CTL:
905 npcm7xx_smbus_write_rxf_ctl(s, value);
906 break;
907
908 default:
909 qemu_log_mask(LOG_GUEST_ERROR,
910 "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
911 DEVICE(s)->canonical_path, offset);
912 break;
913 }
914 } else {
915
916 switch (offset) {
917 case NPCM7XX_SMB_ADDR3:
918 s->addr[2] = value;
919 break;
920
921 case NPCM7XX_SMB_ADDR7:
922 s->addr[6] = value;
923 break;
924
925 case NPCM7XX_SMB_ADDR4:
926 s->addr[3] = value;
927 break;
928
929 case NPCM7XX_SMB_ADDR8:
930 s->addr[7] = value;
931 break;
932
933 case NPCM7XX_SMB_ADDR5:
934 s->addr[4] = value;
935 break;
936
937 case NPCM7XX_SMB_ADDR9:
938 s->addr[8] = value;
939 break;
940
941 case NPCM7XX_SMB_ADDR6:
942 s->addr[5] = value;
943 break;
944
945 case NPCM7XX_SMB_ADDR10:
946 s->addr[9] = value;
947 break;
948
949 case NPCM7XX_SMB_CTL4:
950 s->ctl4 = value;
951 break;
952
953 case NPCM7XX_SMB_CTL5:
954 s->ctl5 = value;
955 break;
956
957 case NPCM7XX_SMB_SCLLT:
958 s->scllt = value;
959 break;
960
961 case NPCM7XX_SMB_FIF_CTL:
962 npcm7xx_smbus_write_fif_ctl(s, value);
963 break;
964
965 case NPCM7XX_SMB_SCLHT:
966 s->sclht = value;
967 break;
968
969 default:
970 qemu_log_mask(LOG_GUEST_ERROR,
971 "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
972 DEVICE(s)->canonical_path, offset);
973 break;
974 }
975 }
976 break;
977 }
978}
979
980static const MemoryRegionOps npcm7xx_smbus_ops = {
981 .read = npcm7xx_smbus_read,
982 .write = npcm7xx_smbus_write,
983 .endianness = DEVICE_LITTLE_ENDIAN,
984 .valid = {
985 .min_access_size = 1,
986 .max_access_size = 1,
987 .unaligned = false,
988 },
989};
990
991static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
992{
993 NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
994
995 s->st = NPCM7XX_SMB_ST_INIT_VAL;
996 s->cst = NPCM7XX_SMB_CST_INIT_VAL;
997 s->cst2 = NPCM7XX_SMB_CST2_INIT_VAL;
998 s->cst3 = NPCM7XX_SMB_CST3_INIT_VAL;
999 s->ctl1 = NPCM7XX_SMB_CTL1_INIT_VAL;
1000 s->ctl2 = NPCM7XX_SMB_CTL2_INIT_VAL;
1001 s->ctl3 = NPCM7XX_SMB_CTL3_INIT_VAL;
1002 s->ctl4 = NPCM7XX_SMB_CTL4_INIT_VAL;
1003 s->ctl5 = NPCM7XX_SMB_CTL5_INIT_VAL;
1004
1005 for (int i = 0; i < NPCM7XX_SMBUS_NR_ADDRS; ++i) {
1006 s->addr[i] = NPCM7XX_SMB_ADDR_INIT_VAL;
1007 }
1008 s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
1009 s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
1010
1011 s->fif_ctl = NPCM7XX_SMB_FIF_CTL_INIT_VAL;
1012 s->fif_cts = NPCM7XX_SMB_FIF_CTS_INIT_VAL;
1013 s->fair_per = NPCM7XX_SMB_FAIR_PER_INIT_VAL;
1014 s->txf_ctl = NPCM7XX_SMB_TXF_CTL_INIT_VAL;
1015 s->t_out = NPCM7XX_SMB_T_OUT_INIT_VAL;
1016 s->txf_sts = NPCM7XX_SMB_TXF_STS_INIT_VAL;
1017 s->rxf_sts = NPCM7XX_SMB_RXF_STS_INIT_VAL;
1018 s->rxf_ctl = NPCM7XX_SMB_RXF_CTL_INIT_VAL;
1019
1020 npcm7xx_smbus_clear_buffer(s);
1021 s->status = NPCM7XX_SMBUS_STATUS_IDLE;
1022 s->rx_cur = 0;
1023}
1024
1025static void npcm7xx_smbus_hold_reset(Object *obj)
1026{
1027 NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1028
1029 qemu_irq_lower(s->irq);
1030}
1031
1032static void npcm7xx_smbus_init(Object *obj)
1033{
1034 NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1035 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1036
1037 sysbus_init_irq(sbd, &s->irq);
1038 memory_region_init_io(&s->iomem, obj, &npcm7xx_smbus_ops, s,
1039 "regs", 4 * KiB);
1040 sysbus_init_mmio(sbd, &s->iomem);
1041
1042 s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
1043}
1044
1045static const VMStateDescription vmstate_npcm7xx_smbus = {
1046 .name = "npcm7xx-smbus",
1047 .version_id = 0,
1048 .minimum_version_id = 0,
1049 .fields = (VMStateField[]) {
1050 VMSTATE_UINT8(sda, NPCM7xxSMBusState),
1051 VMSTATE_UINT8(st, NPCM7xxSMBusState),
1052 VMSTATE_UINT8(cst, NPCM7xxSMBusState),
1053 VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
1054 VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
1055 VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
1056 VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
1057 VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
1058 VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
1059 VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
1060 VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
1061 VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
1062 VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
1063 VMSTATE_UINT8(fif_ctl, NPCM7xxSMBusState),
1064 VMSTATE_UINT8(fif_cts, NPCM7xxSMBusState),
1065 VMSTATE_UINT8(fair_per, NPCM7xxSMBusState),
1066 VMSTATE_UINT8(txf_ctl, NPCM7xxSMBusState),
1067 VMSTATE_UINT8(t_out, NPCM7xxSMBusState),
1068 VMSTATE_UINT8(txf_sts, NPCM7xxSMBusState),
1069 VMSTATE_UINT8(rxf_sts, NPCM7xxSMBusState),
1070 VMSTATE_UINT8(rxf_ctl, NPCM7xxSMBusState),
1071 VMSTATE_UINT8_ARRAY(rx_fifo, NPCM7xxSMBusState,
1072 NPCM7XX_SMBUS_FIFO_SIZE),
1073 VMSTATE_UINT8(rx_cur, NPCM7xxSMBusState),
1074 VMSTATE_END_OF_LIST(),
1075 },
1076};
1077
1078static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
1079{
1080 ResettableClass *rc = RESETTABLE_CLASS(klass);
1081 DeviceClass *dc = DEVICE_CLASS(klass);
1082
1083 dc->desc = "NPCM7xx System Management Bus";
1084 dc->vmsd = &vmstate_npcm7xx_smbus;
1085 rc->phases.enter = npcm7xx_smbus_enter_reset;
1086 rc->phases.hold = npcm7xx_smbus_hold_reset;
1087}
1088
1089static const TypeInfo npcm7xx_smbus_types[] = {
1090 {
1091 .name = TYPE_NPCM7XX_SMBUS,
1092 .parent = TYPE_SYS_BUS_DEVICE,
1093 .instance_size = sizeof(NPCM7xxSMBusState),
1094 .class_init = npcm7xx_smbus_class_init,
1095 .instance_init = npcm7xx_smbus_init,
1096 },
1097};
1098DEFINE_TYPES(npcm7xx_smbus_types);
1099