Changeset 101617 in vbox for trunk/src/VBox/Devices/Gpio
- Timestamp:
- Oct 27, 2023 12:46:15 PM (16 months ago)
- svn:sync-xref-src-repo-rev:
- 159704
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Gpio/DevPL061.cpp
r100768 r101617 33 33 * Header Files * 34 34 *********************************************************************************************************************************/ 35 #define LOG_GROUP LOG_GROUP_DEV_ SERIAL /** @todo */35 #define LOG_GROUP LOG_GROUP_DEV_GPIO 36 36 #include <VBox/vmm/pdmdev.h> 37 37 #include <iprt/assert.h> … … 53 53 /** PL061 MMIO region size in bytes. */ 54 54 #define PL061_MMIO_SIZE _4K 55 56 /** The offset of the GPIODATA register from the beginning of the region. */ 55 /** PL061 number of GPIO pins. */ 56 #define PL061_GPIO_NUM 8 57 58 /** The offset of the GPIODATA (data) register from the beginning of the region. */ 57 59 #define PL061_REG_GPIODATA_INDEX 0x0 60 /** The last offset of the GPIODATA (data) register from the beginning of the region. */ 61 #define PL061_REG_GPIODATA_INDEX_END 0x3fc 62 /** The offset of the GPIODIR (data direction) register from the beginning of the region. */ 63 #define PL061_REG_GPIODIR_INDEX 0x400 64 /** The offset of the GPIOIS (interrupt sense) register from the beginning of the region. */ 65 #define PL061_REG_GPIOIS_INDEX 0x404 66 /** The offset of the GPIOIBE (interrupt both edges) register from the beginning of the region. */ 67 #define PL061_REG_GPIOIBE_INDEX 0x408 68 /** The offset of the GPIOIEV (interrupt event) register from the beginning of the region. */ 69 #define PL061_REG_GPIOIEV_INDEX 0x40c 70 /** The offset of the GPIOIE (interrupt mask) register from the beginning of the region. */ 71 #define PL061_REG_GPIOIE_INDEX 0x410 72 /** The offset of the GPIORIS (raw interrupt status) register from the beginning of the region. */ 73 #define PL061_REG_GPIORIS_INDEX 0x414 74 /** The offset of the GPIOMIS (masked interrupt status) register from the beginning of the region. */ 75 #define PL061_REG_GPIOMIS_INDEX 0x418 76 /** The offset of the GPIOIC (interrupt clear) register from the beginning of the region. */ 77 #define PL061_REG_GPIOIC_INDEX 0x41c 78 /** The offset of the GPIOAFSEL (mode control select) register from the beginning of the region. */ 79 #define PL061_REG_GPIOAFSEL_INDEX 0x420 58 80 59 81 /** The offset of the GPIOPeriphID0 register from the beginning of the region. */ … … 98 120 /** @name Registers. 99 121 * @{ */ 100 /** @todo */ 122 /** Data register. */ 123 uint8_t u8RegData; 124 /** Direction register. */ 125 uint8_t u8RegDir; 126 /** Interrupt sense register. */ 127 uint8_t u8RegIs; 128 /** Interrupt both edges register. */ 129 uint8_t u8RegIbe; 130 /** Interrupt event register. */ 131 uint8_t u8RegIev; 132 /** Interrupt mask register. */ 133 uint8_t u8RegIe; 134 /** Raw interrupt status register. */ 135 uint8_t u8RegRis; 136 /** Mode control select register. */ 137 uint8_t u8RegAfsel; 101 138 /** @} */ 102 139 } DEVPL061; … … 112 149 /** LUN\#0: The base interface. */ 113 150 PDMIBASE IBase; 151 /** GPIO port interface. */ 152 PDMIGPIOPORT IGpioPort; 114 153 /** Pointer to the attached base driver. */ 115 154 R3PTRTYPE(PPDMIBASE) pDrvBase; 155 /** Pointer to the attached GPIO connector interface. */ 156 R3PTRTYPE(PPDMIGPIOCONNECTOR) pDrvGpio; 116 157 /** Pointer to the device instance - only for getting our bearings in 117 158 * interface methods. */ … … 127 168 typedef struct DEVPL061R0 128 169 { 129 /** Dummy .*/170 /** Dummy. */ 130 171 uint8_t bDummy; 131 172 } DEVPL061R0; … … 139 180 typedef struct DEVPL061RC 140 181 { 141 /** Dummy .*/182 /** Dummy. */ 142 183 uint8_t bDummy; 143 184 } DEVPL061RC; … … 157 198 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 158 199 159 #if 0 /* unused */160 200 /** 161 201 * Updates the IRQ state based on the current device state. … … 163 203 * @param pDevIns The device instance. 164 204 * @param pThis The shared PL061 instance data. 165 * @param pThisCC The PL061 instance data for the current context. 166 */ 167 static void pl061IrqUpdate(PPDMDEVINS pDevIns, PDEVPL061 pThis, PDEVPL061CC pThisCC) 168 { 169 LogFlowFunc(("pThis=%#p\n", pThis)); 170 RT_NOREF(pDevIns, pThis, pThisCC); 171 } 172 #endif 205 */ 206 DECLINLINE(void) pl061IrqUpdate(PPDMDEVINS pDevIns, PDEVPL061 pThis) 207 { 208 LogFlowFunc(("pThis=%#p u8RegRis=%#x u8RegIe=%#x -> %RTbool\n", 209 pThis, pThis->u8RegRis, pThis->u8RegIe, 210 RT_BOOL(pThis->u8RegRis & pThis->u8RegIe))); 211 212 if (pThis->u8RegRis & pThis->u8RegIe) 213 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 1); 214 else 215 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 0); 216 } 217 218 219 static void pl061InputUpdate(PPDMDEVINS pDevIns, PDEVPL061 pThis, uint8_t u8OldData) 220 { 221 /* Edge interrupts. */ 222 uint8_t u8ChangedData = pThis->u8RegData ^ u8OldData; 223 if (~pThis->u8RegIs & u8ChangedData) 224 { 225 /* Both edge interrupts can be treated easily. */ 226 pThis->u8RegRis |= u8ChangedData & pThis->u8RegIbe; 227 228 /** @todo Single edge. */ 229 } 230 231 /* Level interrupts. */ 232 pThis->u8RegRis |= (pThis->u8RegIs & pThis->u8RegData) & pThis->u8RegIev; 233 pl061IrqUpdate(pDevIns, pThis); 234 } 173 235 174 236 … … 186 248 Assert(!(off & (cb - 1))); RT_NOREF(cb); 187 249 188 LogFlowFunc(("%RGp cb=%u\n", off, cb)); 250 /* 251 * From the spec: 252 * Similarly, the values read from this register are determined for each bit, by the mask bit derived from the 253 * address used to access the data register, PADDR[9:2]. Bits that are 1 in the address mask cause the corresponding 254 * bits in GPIODATA to be read, and bits that are 0 in the address mask cause the corresponding bits in GPIODATA 255 * to be read as 0, regardless of their value. 256 */ 257 if ( off >= PL061_REG_GPIODATA_INDEX 258 && off < PL061_REG_GPIODATA_INDEX_END + sizeof(uint32_t)) 259 { 260 *(uint32_t *)pv = pThis->u8RegData & (uint8_t)(off >> 2); 261 LogFlowFunc(("%RGp cb=%u u32=%RX32\n", off, cb, *(uint32_t *)pv)); 262 return VINF_SUCCESS; 263 } 189 264 190 265 uint32_t u32Val = 0; … … 192 267 switch (off) 193 268 { 194 /** @todo */ RT_NOREF(pThis); 269 case PL061_REG_GPIODIR_INDEX: 270 u32Val = pThis->u8RegDir; 271 break; 272 case PL061_REG_GPIOIS_INDEX: 273 u32Val = pThis->u8RegIs; 274 break; 275 case PL061_REG_GPIOIBE_INDEX: 276 u32Val = pThis->u8RegIbe; 277 break; 278 case PL061_REG_GPIOIEV_INDEX: 279 u32Val = pThis->u8RegIev; 280 break; 281 case PL061_REG_GPIOIE_INDEX: 282 u32Val = pThis->u8RegIe; 283 break; 284 case PL061_REG_GPIORIS_INDEX: 285 u32Val = pThis->u8RegRis; 286 break; 287 case PL061_REG_GPIOMIS_INDEX: 288 u32Val = pThis->u8RegRis & pThis->u8RegIe; 289 break; 290 case PL061_REG_GPIOAFSEL_INDEX: 291 u32Val = pThis->u8RegAfsel; 292 break; 195 293 case PL061_REG_GPIO_PERIPH_ID0_INDEX: 196 294 u32Val = 0x61; … … 224 322 *(uint32_t *)pv = u32Val; 225 323 324 LogFlowFunc(("%RGp cb=%u u32=%RX32 -> %Rrc\n", off, cb, u32Val, rc)); 226 325 return rc; 227 326 } … … 234 333 { 235 334 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061); 236 PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);237 335 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef)); 238 336 RT_NOREF(pvUser); 239 Assert(cb == 4 || cb == 8); 337 Assert(cb == 4 || cb == 8); RT_NOREF(cb); 240 338 Assert(!(off & (cb - 1))); 241 339 340 /* 341 * From the spec: 342 * In order to write to GPIODATA, the corresponding bits in the mask, resulting from the address bus, PADDR[9:2], 343 * must be HIGH. Otherwise the bit values remain unchanged by the write. 344 */ 345 if ( off >= PL061_REG_GPIODATA_INDEX 346 && off < PL061_REG_GPIODATA_INDEX_END + sizeof(uint32_t)) 347 { 348 uint8_t uMask = (uint8_t)(off >> 2); 349 uint8_t uNewValue = (*(const uint32_t *)pv & uMask) | (pThis->u8RegData & ~uMask); 350 if (pThis->u8RegData ^ uNewValue) 351 { 352 /** @todo Reflect changes. */ 353 } 354 355 pThis->u8RegData = uNewValue & pThis->u8RegDir; /* Filter out all pins configured as input. */ 356 return VINF_SUCCESS; 357 } 358 242 359 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 243 uint 32_t u32Val =*(uint32_t *)pv;360 uint8_t u8Val = (uint8_t)*(uint32_t *)pv; 244 361 switch (off) 245 362 { 246 /** @todo */ RT_NOREF(pThis, pThisCC, u32Val, cb); 363 case PL061_REG_GPIODIR_INDEX: 364 pThis->u8RegDir = u8Val; 365 pl061IrqUpdate(pDevIns, pThis); 366 break; 367 case PL061_REG_GPIOIS_INDEX: 368 pThis->u8RegIs = u8Val; 369 pl061IrqUpdate(pDevIns, pThis); 370 break; 371 case PL061_REG_GPIOIBE_INDEX: 372 pThis->u8RegIbe = u8Val; 373 pl061IrqUpdate(pDevIns, pThis); 374 break; 375 case PL061_REG_GPIOIEV_INDEX: 376 pThis->u8RegIev = u8Val; 377 pl061IrqUpdate(pDevIns, pThis); 378 break; 379 case PL061_REG_GPIOIE_INDEX: 380 pThis->u8RegIe = u8Val; 381 pl061IrqUpdate(pDevIns, pThis); 382 break; 383 case PL061_REG_GPIOIC_INDEX: 384 pThis->u8RegRis &= ~u8Val; 385 pl061IrqUpdate(pDevIns, pThis); 386 break; 387 case PL061_REG_GPIOAFSEL_INDEX: 388 pThis->u8RegAfsel = u8Val; 389 break; 247 390 default: 248 391 break; … … 264 407 PDEVPL061CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL061CC, IBase); 265 408 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase); 409 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIGPIOPORT, &pThisCC->IGpioPort); 266 410 return NULL; 267 411 } 412 413 414 415 /* -=-=-=-=-=-=-=-=- PDMIGPIOPORT -=-=-=-=-=-=-=-=- */ 416 417 /** 418 * @interface_method_impl{PDMIGPIOPORT,pfnGpioLineChange} 419 */ 420 static DECLCALLBACK(int) pl061R3GpioPort_GpioLineChange(PPDMIGPIOPORT pInterface, uint32_t idGpio, bool fVal) 421 { 422 PDEVPL061CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL061CC, IGpioPort); 423 PPDMDEVINS pDevIns = pThisCC->pDevIns; 424 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061); 425 426 LogFlowFunc(("pInterface=%p idGpio=%u fVal=%RTbool\n", pInterface, idGpio, fVal)); 427 428 AssertReturn(idGpio < PL061_GPIO_NUM, VERR_INVALID_PARAMETER); 429 430 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 431 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 432 433 /* Only trigger an update on an actual change and if the GPIO line is configured as an input. */ 434 if ( RT_BOOL(pThis->u8RegData & RT_BIT(idGpio)) != fVal 435 && !(RT_BIT(idGpio) & pThis->u8RegDir)) 436 { 437 uint8_t u8OldData = pThis->u8RegData; 438 439 if (fVal) 440 PL061_REG_SET(pThis->u8RegData, RT_BIT(idGpio)); 441 else 442 PL061_REG_CLR(pThis->u8RegData, RT_BIT(idGpio)); 443 444 pl061InputUpdate(pDevIns, pThis, u8OldData); 445 } 446 447 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 448 return VINF_SUCCESS; 449 } 450 451 452 /** 453 * @interface_method_impl{PDMIGPIOPORT,pfnGpioLineIsInput} 454 */ 455 static DECLCALLBACK(bool) pl061R3GpioPort_GpioLineIsInput(PPDMIGPIOPORT pInterface, uint32_t idGpio) 456 { 457 PDEVPL061CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL061CC, IGpioPort); 458 PPDMDEVINS pDevIns = pThisCC->pDevIns; 459 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061); 460 461 AssertReturn(idGpio < PL061_GPIO_NUM, VERR_INVALID_PARAMETER); 462 463 return !RT_BOOL(pThis->u8RegDir & RT_BIT(idGpio)); /* Bit cleared means input. */ 464 } 465 268 466 269 467 … … 295 493 pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq); 296 494 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase); 495 496 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegData); 497 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegDir); 498 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegIs); 499 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegIbe); 500 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegIev); 501 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegIe); 502 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegRis); 503 pHlp->pfnSSMPutU8(pSSM, pThis->u8RegAfsel); 297 504 298 505 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */ … … 317 524 if (uPass == SSM_PASS_FINAL) 318 525 { 319 rc = VINF_SUCCESS; 526 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegData); 527 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegDir); 528 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegIs); 529 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegIbe); 530 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegIev); 531 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegIe); 532 pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegRis); 533 rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8RegAfsel); 320 534 AssertRCReturn(rc, rc); 321 535 } … … 364 578 { 365 579 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061); 366 PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC); 367 368 /** @todo */ 369 RT_NOREF(pThis, pThisCC); 580 581 pThis->u8RegData = 0; 582 pThis->u8RegDir = 0; 583 pThis->u8RegIs = 0; 584 pThis->u8RegIbe = 0; 585 pThis->u8RegIev = 0; 586 pThis->u8RegIe = 0; 587 pThis->u8RegRis = 0; 588 pThis->u8RegAfsel = 0; 370 589 } 371 590 … … 376 595 static DECLCALLBACK(int) pl061R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) 377 596 { 378 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);379 597 PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC); 380 598 RT_NOREF(fFlags); … … 384 602 if (RT_SUCCESS(rc)) 385 603 { 386 /** @todo */ RT_NOREF(pThis); 604 pThisCC->pDrvGpio = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIGPIOCONNECTOR); 605 if (!pThisCC->pDrvGpio) 606 { 607 AssertLogRelMsgFailed(("PL061#%d: instance %d has no GPIO interface!\n", pDevIns->iInstance)); 608 return VERR_PDM_MISSING_INTERFACE; 609 } 387 610 } 388 611 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER) … … 403 626 static DECLCALLBACK(void) pl061R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) 404 627 { 405 PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);406 628 PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC); 407 629 RT_NOREF(fFlags); … … 410 632 /* Zero out important members. */ 411 633 pThisCC->pDrvBase = NULL; 412 /** @todo */ RT_NOREF(pThis);634 pThisCC->pDrvGpio = NULL; 413 635 } 414 636 … … 443 665 /* IBase */ 444 666 pThisCC->IBase.pfnQueryInterface = pl061R3QueryInterface; 445 446 /** @todo Interface. */ 667 /* IGpioPort */ 668 pThisCC->IGpioPort.pfnGpioLineChange = pl061R3GpioPort_GpioLineChange; 669 pThisCC->IGpioPort.pfnGpioLineIsInput = pl061R3GpioPort_GpioLineIsInput; 447 670 448 671 /* … … 488 711 if (RT_SUCCESS(rc)) 489 712 { 490 /** @todo */ 713 pThisCC->pDrvGpio = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIGPIOCONNECTOR); 714 if (!pThisCC->pDrvGpio) 715 { 716 AssertLogRelMsgFailed(("Configuration error: instance %d has no GPIO interface!\n", iInstance)); 717 return VERR_PDM_MISSING_INTERFACE; 718 } 491 719 } 492 720 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER) 493 721 { 494 722 pThisCC->pDrvBase = NULL; 723 pThisCC->pDrvGpio = NULL; 495 724 LogRel(("PL061#%d: no unit\n", iInstance)); 496 725 } … … 534 763 /* .szName = */ "arm-pl061-gpio", 535 764 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE, 536 /* .fClass = */ PDM_DEVREG_CLASS_ SERIAL, /** @todo */765 /* .fClass = */ PDM_DEVREG_CLASS_GPIO, 537 766 /* .cMaxInstances = */ UINT32_MAX, 538 767 /* .uSharedVersion = */ 42,
Note:
See TracChangeset
for help on using the changeset viewer.