npcm7xx_smbus.c (32992B)
1/* 2 * Nuvoton NPCM7xx SMBus Module. 3 * 4 * Copyright 2020 Google LLC 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 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/* ST fields */ 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/* CST fields */ 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/* CST2 fields */ 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/* CST3 fields */ 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/* CTL1 fields */ 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/* CTL2 fields */ 116#define NPCM7XX_SMBCTL2_SCLFRQ(rv) extract8((rv), 1, 6) 117#define NPCM7XX_SMBCTL2_ENABLE BIT(0) 118 119/* CTL3 fields */ 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/* ADDR fields */ 129#define NPCM7XX_ADDR_EN BIT(7) 130#define NPCM7XX_ADDR_A(rv) extract8((rv), 0, 6) 131 132/* FIFO Mode Register Fields */ 133/* FIF_CTL fields */ 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/* FIF_CTS fields */ 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/* TXF_CTL fields */ 144#define NPCM7XX_SMBTXF_CTL_THR_TXIE BIT(6) 145#define NPCM7XX_SMBTXF_CTL_TX_THR(rv) extract8((rv), 0, 5) 146/* T_OUT fields */ 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/* TXF_STS fields */ 151#define NPCM7XX_SMBTXF_STS_TX_THST BIT(6) 152#define NPCM7XX_SMBTXF_STS_TX_BYTES(rv) extract8((rv), 0, 5) 153/* RXF_STS fields */ 154#define NPCM7XX_SMBRXF_STS_RX_THST BIT(6) 155#define NPCM7XX_SMBRXF_STS_RX_BYTES(rv) extract8((rv), 0, 5) 156/* RXF_CTL fields */ 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/* VERSION fields values, read-only. */ 169#define NPCM7XX_SMBUS_VERSION_NUMBER 1 170#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 1 171 172/* Reset values */ 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 * We can start the bus if one of these is true: 344 * 1. The bus is idle (so we can request it) 345 * 2. We are the occupier (it's a repeated start condition.) 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 /* Failed to start transfer. NACK to reject.*/ 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 /* Do nothing */ 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 /* Disable this SMBus module. */ 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 /* Write to SDA and SCL bits are ignored. */ 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 /* The order of the registers are their order in memory. */ 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 /* This register is either invalid or banked at this point. */ 709 default: 710 if (bank) { 711 /* Bank 1 */ 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 /* Bank 0 */ 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 /* The order of the registers are their order in memory. */ 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 /* This register is either invalid or banked at this point. */ 876 default: 877 if (bank) { 878 /* Bank 1 */ 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 /* Bank 0 */ 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);