VirtualBox

Changeset 101617 in vbox for trunk/src/VBox/Devices/Gpio


Ignore:
Timestamp:
Oct 27, 2023 12:46:15 PM (16 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
159704
Message:

Devices/Gpio/DevPL061: Updates to the code, bugref:10453

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Gpio/DevPL061.cpp

    r100768 r101617  
    3333*   Header Files                                                                                                                 *
    3434*********************************************************************************************************************************/
    35 #define LOG_GROUP LOG_GROUP_DEV_SERIAL /** @todo */
     35#define LOG_GROUP LOG_GROUP_DEV_GPIO
    3636#include <VBox/vmm/pdmdev.h>
    3737#include <iprt/assert.h>
     
    5353/** PL061 MMIO region size in bytes. */
    5454#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. */
    5759#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
    5880
    5981/** The offset of the GPIOPeriphID0 register from the beginning of the region. */
     
    98120    /** @name Registers.
    99121     * @{ */
    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;
    101138    /** @} */
    102139} DEVPL061;
     
    112149    /** LUN\#0: The base interface. */
    113150    PDMIBASE                        IBase;
     151    /** GPIO port interface. */
     152    PDMIGPIOPORT                    IGpioPort;
    114153    /** Pointer to the attached base driver. */
    115154    R3PTRTYPE(PPDMIBASE)            pDrvBase;
     155    /** Pointer to the attached GPIO connector interface. */
     156    R3PTRTYPE(PPDMIGPIOCONNECTOR)   pDrvGpio;
    116157    /** Pointer to the device instance - only for getting our bearings in
    117158     *  interface methods. */
     
    127168typedef struct DEVPL061R0
    128169{
    129     /** Dummy .*/
     170    /** Dummy. */
    130171    uint8_t                         bDummy;
    131172} DEVPL061R0;
     
    139180typedef struct DEVPL061RC
    140181{
    141     /** Dummy .*/
     182    /** Dummy. */
    142183    uint8_t                         bDummy;
    143184} DEVPL061RC;
     
    157198#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    158199
    159 #if 0 /* unused */
    160200/**
    161201 * Updates the IRQ state based on the current device state.
     
    163203 * @param   pDevIns             The device instance.
    164204 * @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 */
     206DECLINLINE(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
     219static 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}
    173235
    174236
     
    186248    Assert(!(off & (cb - 1))); RT_NOREF(cb);
    187249
    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    }
    189264
    190265    uint32_t u32Val = 0;
     
    192267    switch (off)
    193268    {
    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;
    195293        case PL061_REG_GPIO_PERIPH_ID0_INDEX:
    196294            u32Val = 0x61;
     
    224322        *(uint32_t *)pv = u32Val;
    225323
     324    LogFlowFunc(("%RGp cb=%u u32=%RX32 -> %Rrc\n", off, cb, u32Val, rc));
    226325    return rc;
    227326}
     
    234333{
    235334    PDEVPL061   pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
    236     PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
    237335    LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
    238336    RT_NOREF(pvUser);
    239     Assert(cb == 4 || cb == 8);
     337    Assert(cb == 4 || cb == 8); RT_NOREF(cb);
    240338    Assert(!(off & (cb - 1)));
    241339
     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
    242359    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
    243     uint32_t u32Val = *(uint32_t *)pv;
     360    uint8_t u8Val = (uint8_t)*(uint32_t *)pv;
    244361    switch (off)
    245362    {
    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;
    247390        default:
    248391            break;
     
    264407    PDEVPL061CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL061CC, IBase);
    265408    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
     409    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIGPIOPORT, &pThisCC->IGpioPort);
    266410    return NULL;
    267411}
     412
     413
     414
     415/* -=-=-=-=-=-=-=-=- PDMIGPIOPORT -=-=-=-=-=-=-=-=- */
     416
     417/**
     418 * @interface_method_impl{PDMIGPIOPORT,pfnGpioLineChange}
     419 */
     420static 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 */
     455static 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
    268466
    269467
     
    295493    pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
    296494    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);
    297504
    298505    return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
     
    317524    if (uPass == SSM_PASS_FINAL)
    318525    {
    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);
    320534        AssertRCReturn(rc, rc);
    321535    }
     
    364578{
    365579    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;
    370589}
    371590
     
    376595static DECLCALLBACK(int) pl061R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    377596{
    378     PDEVPL061   pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
    379597    PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
    380598    RT_NOREF(fFlags);
     
    384602    if (RT_SUCCESS(rc))
    385603    {
    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        }
    387610    }
    388611    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     
    403626static DECLCALLBACK(void) pl061R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    404627{
    405     PDEVPL061   pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
    406628    PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
    407629    RT_NOREF(fFlags);
     
    410632    /* Zero out important members. */
    411633    pThisCC->pDrvBase   = NULL;
    412     /** @todo */ RT_NOREF(pThis);
     634    pThisCC->pDrvGpio   = NULL;
    413635}
    414636
     
    443665    /* IBase */
    444666    pThisCC->IBase.pfnQueryInterface                = pl061R3QueryInterface;
    445 
    446     /** @todo Interface. */
     667    /* IGpioPort */
     668    pThisCC->IGpioPort.pfnGpioLineChange            = pl061R3GpioPort_GpioLineChange;
     669    pThisCC->IGpioPort.pfnGpioLineIsInput           = pl061R3GpioPort_GpioLineIsInput;
    447670
    448671    /*
     
    488711    if (RT_SUCCESS(rc))
    489712    {
    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        }
    491719    }
    492720    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    493721    {
    494722        pThisCC->pDrvBase   = NULL;
     723        pThisCC->pDrvGpio   = NULL;
    495724        LogRel(("PL061#%d: no unit\n", iInstance));
    496725    }
     
    534763    /* .szName = */                 "arm-pl061-gpio",
    535764    /* .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,
    537766    /* .cMaxInstances = */          UINT32_MAX,
    538767    /* .uSharedVersion = */         42,
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette