[99895] | 1 | /* $Id: DevPL061.cpp 101617 2023-10-27 12:46:15Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * DevPL061 - ARM PL061 PrimeCell GPIO.
|
---|
| 4 | *
|
---|
| 5 | * The documentation for this device was taken from
|
---|
| 6 | * https://developer.arm.com/documentation/ddi0190/b/programmer-s-model/summary-of-primecell-gpio-registers (2023-05-22).
|
---|
| 7 | */
|
---|
| 8 |
|
---|
| 9 | /*
|
---|
| 10 | * Copyright (C) 2023 Oracle and/or its affiliates.
|
---|
| 11 | *
|
---|
| 12 | * This file is part of VirtualBox base platform packages, as
|
---|
| 13 | * available from https://www.virtualbox.org.
|
---|
| 14 | *
|
---|
| 15 | * This program is free software; you can redistribute it and/or
|
---|
| 16 | * modify it under the terms of the GNU General Public License
|
---|
| 17 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 18 | * License.
|
---|
| 19 | *
|
---|
| 20 | * This program is distributed in the hope that it will be useful, but
|
---|
| 21 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 23 | * General Public License for more details.
|
---|
| 24 | *
|
---|
| 25 | * You should have received a copy of the GNU General Public License
|
---|
| 26 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 27 | *
|
---|
| 28 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
| 29 | */
|
---|
| 30 |
|
---|
| 31 |
|
---|
| 32 | /*********************************************************************************************************************************
|
---|
| 33 | * Header Files *
|
---|
| 34 | *********************************************************************************************************************************/
|
---|
[101617] | 35 | #define LOG_GROUP LOG_GROUP_DEV_GPIO
|
---|
[99895] | 36 | #include <VBox/vmm/pdmdev.h>
|
---|
| 37 | #include <iprt/assert.h>
|
---|
| 38 | #include <iprt/uuid.h>
|
---|
| 39 | #include <iprt/string.h>
|
---|
| 40 | #include <iprt/semaphore.h>
|
---|
| 41 | #include <iprt/critsect.h>
|
---|
| 42 |
|
---|
| 43 | #include "VBoxDD.h"
|
---|
| 44 |
|
---|
| 45 |
|
---|
| 46 | /*********************************************************************************************************************************
|
---|
| 47 | * Defined Constants And Macros *
|
---|
| 48 | *********************************************************************************************************************************/
|
---|
| 49 |
|
---|
| 50 | /** The current serial code saved state version. */
|
---|
| 51 | #define PL061_SAVED_STATE_VERSION 1
|
---|
| 52 |
|
---|
| 53 | /** PL061 MMIO region size in bytes. */
|
---|
| 54 | #define PL061_MMIO_SIZE _4K
|
---|
[101617] | 55 | /** PL061 number of GPIO pins. */
|
---|
| 56 | #define PL061_GPIO_NUM 8
|
---|
[99895] | 57 |
|
---|
[101617] | 58 | /** The offset of the GPIODATA (data) register from the beginning of the region. */
|
---|
[99895] | 59 | #define PL061_REG_GPIODATA_INDEX 0x0
|
---|
[101617] | 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
|
---|
[99895] | 80 |
|
---|
| 81 | /** The offset of the GPIOPeriphID0 register from the beginning of the region. */
|
---|
| 82 | #define PL061_REG_GPIO_PERIPH_ID0_INDEX 0xfe0
|
---|
| 83 | /** The offset of the GPIOPeriphID1 register from the beginning of the region. */
|
---|
| 84 | #define PL061_REG_GPIO_PERIPH_ID1_INDEX 0xfe4
|
---|
| 85 | /** The offset of the GPIOPeriphID2 register from the beginning of the region. */
|
---|
| 86 | #define PL061_REG_GPIO_PERIPH_ID2_INDEX 0xfe8
|
---|
| 87 | /** The offset of the GPIOPeriphID3 register from the beginning of the region. */
|
---|
| 88 | #define PL061_REG_GPIO_PERIPH_ID3_INDEX 0xfec
|
---|
| 89 | /** The offset of the GPIOPCellID0 register from the beginning of the region. */
|
---|
| 90 | #define PL061_REG_GPIO_PCELL_ID0_INDEX 0xff0
|
---|
| 91 | /** The offset of the GPIOPCellID1 register from the beginning of the region. */
|
---|
| 92 | #define PL061_REG_GPIO_PCELL_ID1_INDEX 0xff4
|
---|
| 93 | /** The offset of the GPIOPCellID2 register from the beginning of the region. */
|
---|
| 94 | #define PL061_REG_GPIO_PCELL_ID2_INDEX 0xff8
|
---|
| 95 | /** The offset of the GPIOPCellID3 register from the beginning of the region. */
|
---|
| 96 | #define PL061_REG_GPIO_PCELL_ID3_INDEX 0xffc
|
---|
| 97 |
|
---|
| 98 | /** Set the specified bits in the given register. */
|
---|
| 99 | #define PL061_REG_SET(a_Reg, a_Set) ((a_Reg) |= (a_Set))
|
---|
| 100 | /** Clear the specified bits in the given register. */
|
---|
| 101 | #define PL061_REG_CLR(a_Reg, a_Clr) ((a_Reg) &= ~(a_Clr))
|
---|
| 102 |
|
---|
| 103 |
|
---|
| 104 | /*********************************************************************************************************************************
|
---|
| 105 | * Structures and Typedefs *
|
---|
| 106 | *********************************************************************************************************************************/
|
---|
| 107 |
|
---|
| 108 | /**
|
---|
| 109 | * Shared PL061 GPIO device state.
|
---|
| 110 | */
|
---|
| 111 | typedef struct DEVPL061
|
---|
| 112 | {
|
---|
| 113 | /** The MMIO handle. */
|
---|
| 114 | IOMMMIOHANDLE hMmio;
|
---|
| 115 | /** The base MMIO address the device is registered at. */
|
---|
| 116 | RTGCPHYS GCPhysMmioBase;
|
---|
| 117 | /** The IRQ value. */
|
---|
| 118 | uint16_t u16Irq;
|
---|
| 119 |
|
---|
| 120 | /** @name Registers.
|
---|
| 121 | * @{ */
|
---|
[101617] | 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;
|
---|
[99895] | 138 | /** @} */
|
---|
| 139 | } DEVPL061;
|
---|
| 140 | /** Pointer to the shared serial device state. */
|
---|
| 141 | typedef DEVPL061 *PDEVPL061;
|
---|
| 142 |
|
---|
| 143 |
|
---|
| 144 | /**
|
---|
| 145 | * PL061 device state for ring-3.
|
---|
| 146 | */
|
---|
| 147 | typedef struct DEVPL061R3
|
---|
| 148 | {
|
---|
| 149 | /** LUN\#0: The base interface. */
|
---|
| 150 | PDMIBASE IBase;
|
---|
[101617] | 151 | /** GPIO port interface. */
|
---|
| 152 | PDMIGPIOPORT IGpioPort;
|
---|
[99895] | 153 | /** Pointer to the attached base driver. */
|
---|
| 154 | R3PTRTYPE(PPDMIBASE) pDrvBase;
|
---|
[101617] | 155 | /** Pointer to the attached GPIO connector interface. */
|
---|
| 156 | R3PTRTYPE(PPDMIGPIOCONNECTOR) pDrvGpio;
|
---|
[99895] | 157 | /** Pointer to the device instance - only for getting our bearings in
|
---|
| 158 | * interface methods. */
|
---|
| 159 | PPDMDEVINS pDevIns;
|
---|
| 160 | } DEVPL061R3;
|
---|
| 161 | /** Pointer to the PL061 device state for ring-3. */
|
---|
| 162 | typedef DEVPL061R3 *PDEVPL061R3;
|
---|
| 163 |
|
---|
| 164 |
|
---|
| 165 | /**
|
---|
| 166 | * PL061 device state for ring-0.
|
---|
| 167 | */
|
---|
| 168 | typedef struct DEVPL061R0
|
---|
| 169 | {
|
---|
[101617] | 170 | /** Dummy. */
|
---|
[99895] | 171 | uint8_t bDummy;
|
---|
| 172 | } DEVPL061R0;
|
---|
| 173 | /** Pointer to the PL061 device state for ring-0. */
|
---|
| 174 | typedef DEVPL061R0 *PDEVPL061R0;
|
---|
| 175 |
|
---|
| 176 |
|
---|
| 177 | /**
|
---|
| 178 | * PL061 device state for raw-mode.
|
---|
| 179 | */
|
---|
| 180 | typedef struct DEVPL061RC
|
---|
| 181 | {
|
---|
[101617] | 182 | /** Dummy. */
|
---|
[99895] | 183 | uint8_t bDummy;
|
---|
| 184 | } DEVPL061RC;
|
---|
| 185 | /** Pointer to the serial device state for raw-mode. */
|
---|
| 186 | typedef DEVPL061RC *PDEVPL061RC;
|
---|
| 187 |
|
---|
| 188 | /** The PL061 device state for the current context. */
|
---|
| 189 | typedef CTX_SUFF(DEVPL061) DEVPL061CC;
|
---|
| 190 | /** Pointer to the PL016 device state for the current context. */
|
---|
| 191 | typedef CTX_SUFF(PDEVPL061) PDEVPL061CC;
|
---|
| 192 |
|
---|
| 193 |
|
---|
| 194 | /*********************************************************************************************************************************
|
---|
| 195 | * Internal Functions *
|
---|
| 196 | *********************************************************************************************************************************/
|
---|
| 197 |
|
---|
| 198 | #ifndef VBOX_DEVICE_STRUCT_TESTCASE
|
---|
| 199 |
|
---|
| 200 | /**
|
---|
| 201 | * Updates the IRQ state based on the current device state.
|
---|
| 202 | *
|
---|
| 203 | * @param pDevIns The device instance.
|
---|
| 204 | * @param pThis The shared PL061 instance data.
|
---|
| 205 | */
|
---|
[101617] | 206 | DECLINLINE(void) pl061IrqUpdate(PPDMDEVINS pDevIns, PDEVPL061 pThis)
|
---|
[99895] | 207 | {
|
---|
[101617] | 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);
|
---|
[99895] | 216 | }
|
---|
| 217 |
|
---|
| 218 |
|
---|
[101617] | 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 | }
|
---|
| 235 |
|
---|
| 236 |
|
---|
[99895] | 237 | /* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
|
---|
| 238 |
|
---|
| 239 |
|
---|
| 240 | /**
|
---|
| 241 | * @callback_method_impl{FNIOMMMIONEWREAD}
|
---|
| 242 | */
|
---|
| 243 | static DECLCALLBACK(VBOXSTRICTRC) pl061MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
|
---|
| 244 | {
|
---|
| 245 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 246 | RT_NOREF(pvUser);
|
---|
| 247 | Assert(cb == 4);
|
---|
[100108] | 248 | Assert(!(off & (cb - 1))); RT_NOREF(cb);
|
---|
[99895] | 249 |
|
---|
[101617] | 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 | }
|
---|
[99895] | 264 |
|
---|
| 265 | uint32_t u32Val = 0;
|
---|
| 266 | VBOXSTRICTRC rc = VINF_SUCCESS;
|
---|
| 267 | switch (off)
|
---|
| 268 | {
|
---|
[101617] | 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;
|
---|
[99895] | 293 | case PL061_REG_GPIO_PERIPH_ID0_INDEX:
|
---|
| 294 | u32Val = 0x61;
|
---|
| 295 | break;
|
---|
| 296 | case PL061_REG_GPIO_PERIPH_ID1_INDEX:
|
---|
| 297 | u32Val = 0x10;
|
---|
| 298 | break;
|
---|
| 299 | case PL061_REG_GPIO_PERIPH_ID2_INDEX:
|
---|
| 300 | u32Val = 0x04;
|
---|
| 301 | break;
|
---|
| 302 | case PL061_REG_GPIO_PERIPH_ID3_INDEX:
|
---|
| 303 | u32Val = 0x00;
|
---|
| 304 | break;
|
---|
| 305 | case PL061_REG_GPIO_PCELL_ID0_INDEX:
|
---|
| 306 | u32Val = 0x0d;
|
---|
| 307 | break;
|
---|
| 308 | case PL061_REG_GPIO_PCELL_ID1_INDEX:
|
---|
| 309 | u32Val = 0xf0;
|
---|
| 310 | break;
|
---|
| 311 | case PL061_REG_GPIO_PCELL_ID2_INDEX:
|
---|
| 312 | u32Val = 0x05;
|
---|
| 313 | break;
|
---|
| 314 | case PL061_REG_GPIO_PCELL_ID3_INDEX:
|
---|
| 315 | u32Val = 0xb1;
|
---|
| 316 | break;
|
---|
| 317 | default:
|
---|
| 318 | break;
|
---|
| 319 | }
|
---|
| 320 |
|
---|
| 321 | if (rc == VINF_SUCCESS)
|
---|
| 322 | *(uint32_t *)pv = u32Val;
|
---|
| 323 |
|
---|
[101617] | 324 | LogFlowFunc(("%RGp cb=%u u32=%RX32 -> %Rrc\n", off, cb, u32Val, rc));
|
---|
[99895] | 325 | return rc;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 |
|
---|
| 329 | /**
|
---|
| 330 | * @callback_method_impl{FNIOMMMIONEWWRITE}
|
---|
| 331 | */
|
---|
| 332 | static DECLCALLBACK(VBOXSTRICTRC) pl061MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
|
---|
| 333 | {
|
---|
| 334 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 335 | LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
|
---|
| 336 | RT_NOREF(pvUser);
|
---|
[101617] | 337 | Assert(cb == 4 || cb == 8); RT_NOREF(cb);
|
---|
[99895] | 338 | Assert(!(off & (cb - 1)));
|
---|
| 339 |
|
---|
[101617] | 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 |
|
---|
[99895] | 359 | VBOXSTRICTRC rcStrict = VINF_SUCCESS;
|
---|
[101617] | 360 | uint8_t u8Val = (uint8_t)*(uint32_t *)pv;
|
---|
[99895] | 361 | switch (off)
|
---|
| 362 | {
|
---|
[101617] | 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;
|
---|
[99895] | 390 | default:
|
---|
| 391 | break;
|
---|
| 392 |
|
---|
| 393 | }
|
---|
| 394 | return rcStrict;
|
---|
| 395 | }
|
---|
| 396 |
|
---|
| 397 |
|
---|
| 398 | #ifdef IN_RING3
|
---|
| 399 |
|
---|
| 400 | /* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
|
---|
| 401 |
|
---|
| 402 | /**
|
---|
| 403 | * @interface_method_impl{PDMIBASE,pfnQueryInterface}
|
---|
| 404 | */
|
---|
| 405 | static DECLCALLBACK(void *) pl061R3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
|
---|
| 406 | {
|
---|
| 407 | PDEVPL061CC pThisCC = RT_FROM_MEMBER(pInterface, DEVPL061CC, IBase);
|
---|
| 408 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
|
---|
[101617] | 409 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIGPIOPORT, &pThisCC->IGpioPort);
|
---|
[99895] | 410 | return NULL;
|
---|
| 411 | }
|
---|
| 412 |
|
---|
| 413 |
|
---|
[101617] | 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 |
|
---|
| 466 |
|
---|
| 467 |
|
---|
[99895] | 468 | /* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
|
---|
| 469 |
|
---|
| 470 | /**
|
---|
| 471 | * @callback_method_impl{FNSSMDEVLIVEEXEC}
|
---|
| 472 | */
|
---|
| 473 | static DECLCALLBACK(int) pl061R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
|
---|
| 474 | {
|
---|
| 475 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 476 | PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
|
---|
| 477 | RT_NOREF(uPass);
|
---|
| 478 |
|
---|
| 479 | pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
|
---|
| 480 | pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
|
---|
| 481 | return VINF_SSM_DONT_CALL_AGAIN;
|
---|
| 482 | }
|
---|
| 483 |
|
---|
| 484 |
|
---|
| 485 | /**
|
---|
| 486 | * @callback_method_impl{FNSSMDEVSAVEEXEC}
|
---|
| 487 | */
|
---|
| 488 | static DECLCALLBACK(int) pl061R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
|
---|
| 489 | {
|
---|
| 490 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 491 | PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
|
---|
| 492 |
|
---|
| 493 | pHlp->pfnSSMPutU16(pSSM, pThis->u16Irq);
|
---|
| 494 | pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
|
---|
| 495 |
|
---|
[101617] | 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);
|
---|
| 504 |
|
---|
[99895] | 505 | return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
|
---|
| 506 | }
|
---|
| 507 |
|
---|
| 508 |
|
---|
| 509 | /**
|
---|
| 510 | * @callback_method_impl{FNSSMDEVLOADEXEC}
|
---|
| 511 | */
|
---|
| 512 | static DECLCALLBACK(int) pl061R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
|
---|
| 513 | {
|
---|
| 514 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 515 | PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
|
---|
| 516 | uint16_t u16Irq;
|
---|
| 517 | RTGCPHYS GCPhysMmioBase;
|
---|
| 518 | int rc;
|
---|
| 519 |
|
---|
| 520 | RT_NOREF(uVersion);
|
---|
| 521 |
|
---|
| 522 | pHlp->pfnSSMGetU16( pSSM, &u16Irq);
|
---|
| 523 | pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
|
---|
| 524 | if (uPass == SSM_PASS_FINAL)
|
---|
| 525 | {
|
---|
[101617] | 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);
|
---|
[99895] | 534 | AssertRCReturn(rc, rc);
|
---|
| 535 | }
|
---|
| 536 |
|
---|
| 537 | if (uPass == SSM_PASS_FINAL)
|
---|
| 538 | {
|
---|
| 539 | /* The marker. */
|
---|
| 540 | uint32_t u32;
|
---|
| 541 | rc = pHlp->pfnSSMGetU32(pSSM, &u32);
|
---|
| 542 | AssertRCReturn(rc, rc);
|
---|
| 543 | AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 | /*
|
---|
| 547 | * Check the config.
|
---|
| 548 | */
|
---|
| 549 | if ( pThis->u16Irq != u16Irq
|
---|
| 550 | || pThis->GCPhysMmioBase != GCPhysMmioBase)
|
---|
| 551 | return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
|
---|
| 552 | N_("Config mismatch - saved Irq=%#x GCPhysMmioBase=%#RGp; configured Irq=%#x GCPhysMmioBase=%#RGp"),
|
---|
| 553 | u16Irq, GCPhysMmioBase, pThis->u16Irq, pThis->GCPhysMmioBase);
|
---|
| 554 |
|
---|
| 555 | return VINF_SUCCESS;
|
---|
| 556 | }
|
---|
| 557 |
|
---|
| 558 |
|
---|
| 559 | /**
|
---|
| 560 | * @callback_method_impl{FNSSMDEVLOADDONE}
|
---|
| 561 | */
|
---|
| 562 | static DECLCALLBACK(int) pl061R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
|
---|
| 563 | {
|
---|
| 564 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 565 | PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
|
---|
| 566 |
|
---|
| 567 | RT_NOREF(pThis, pThisCC, pSSM);
|
---|
[100768] | 568 | return VINF_SUCCESS;
|
---|
[99895] | 569 | }
|
---|
| 570 |
|
---|
| 571 |
|
---|
| 572 | /* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
|
---|
| 573 |
|
---|
| 574 | /**
|
---|
| 575 | * @interface_method_impl{PDMDEVREG,pfnReset}
|
---|
| 576 | */
|
---|
| 577 | static DECLCALLBACK(void) pl061R3Reset(PPDMDEVINS pDevIns)
|
---|
| 578 | {
|
---|
| 579 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 580 |
|
---|
[101617] | 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;
|
---|
[99895] | 589 | }
|
---|
| 590 |
|
---|
| 591 |
|
---|
| 592 | /**
|
---|
| 593 | * @interface_method_impl{PDMDEVREG,pfnAttach}
|
---|
| 594 | */
|
---|
| 595 | static DECLCALLBACK(int) pl061R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
|
---|
| 596 | {
|
---|
| 597 | PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
|
---|
| 598 | RT_NOREF(fFlags);
|
---|
| 599 | AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
|
---|
| 600 |
|
---|
| 601 | int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThisCC->IBase, &pThisCC->pDrvBase, "PL016 Gpio");
|
---|
| 602 | if (RT_SUCCESS(rc))
|
---|
| 603 | {
|
---|
[101617] | 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 | }
|
---|
[99895] | 610 | }
|
---|
| 611 | else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
|
---|
| 612 | {
|
---|
| 613 | pThisCC->pDrvBase = NULL;
|
---|
| 614 | LogRel(("PL061#%d: no unit\n", pDevIns->iInstance));
|
---|
| 615 | }
|
---|
| 616 | else /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
|
---|
| 617 | LogRel(("PL061#%d: Failed to attach to GPIO driver. rc=%Rrc\n", pDevIns->iInstance, rc));
|
---|
| 618 |
|
---|
| 619 | return rc;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 |
|
---|
| 623 | /**
|
---|
| 624 | * @interface_method_impl{PDMDEVREG,pfnDetach}
|
---|
| 625 | */
|
---|
| 626 | static DECLCALLBACK(void) pl061R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
|
---|
| 627 | {
|
---|
| 628 | PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
|
---|
| 629 | RT_NOREF(fFlags);
|
---|
| 630 | AssertReturnVoid(iLUN == 0);
|
---|
| 631 |
|
---|
| 632 | /* Zero out important members. */
|
---|
| 633 | pThisCC->pDrvBase = NULL;
|
---|
[101617] | 634 | pThisCC->pDrvGpio = NULL;
|
---|
[99895] | 635 | }
|
---|
| 636 |
|
---|
| 637 |
|
---|
| 638 | /**
|
---|
| 639 | * @interface_method_impl{PDMDEVREG,pfnDestruct}
|
---|
| 640 | */
|
---|
| 641 | static DECLCALLBACK(int) pl061R3Destruct(PPDMDEVINS pDevIns)
|
---|
| 642 | {
|
---|
| 643 | PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
|
---|
| 644 |
|
---|
| 645 | /* Nothing to do (for now). */
|
---|
| 646 | return VINF_SUCCESS;
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 |
|
---|
| 650 | /**
|
---|
| 651 | * @interface_method_impl{PDMDEVREG,pfnConstruct}
|
---|
| 652 | */
|
---|
| 653 | static DECLCALLBACK(int) pl061R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
|
---|
| 654 | {
|
---|
| 655 | PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
|
---|
| 656 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 657 | PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
|
---|
| 658 | PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
|
---|
| 659 | int rc;
|
---|
| 660 |
|
---|
| 661 | Assert(iInstance < 4);
|
---|
| 662 |
|
---|
| 663 | pThisCC->pDevIns = pDevIns;
|
---|
| 664 |
|
---|
| 665 | /* IBase */
|
---|
| 666 | pThisCC->IBase.pfnQueryInterface = pl061R3QueryInterface;
|
---|
[101617] | 667 | /* IGpioPort */
|
---|
| 668 | pThisCC->IGpioPort.pfnGpioLineChange = pl061R3GpioPort_GpioLineChange;
|
---|
| 669 | pThisCC->IGpioPort.pfnGpioLineIsInput = pl061R3GpioPort_GpioLineIsInput;
|
---|
[99895] | 670 |
|
---|
| 671 | /*
|
---|
| 672 | * Validate and read the configuration.
|
---|
| 673 | */
|
---|
| 674 | PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase", "");
|
---|
| 675 |
|
---|
| 676 | uint16_t u16Irq = 0;
|
---|
| 677 | rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
|
---|
| 678 | if (RT_FAILURE(rc))
|
---|
| 679 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
|
---|
| 680 |
|
---|
| 681 | RTGCPHYS GCPhysMmioBase = 0;
|
---|
| 682 | rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
|
---|
| 683 | if (RT_FAILURE(rc))
|
---|
| 684 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 685 | N_("Configuration error: Failed to get the \"IOBase\" value"));
|
---|
| 686 |
|
---|
| 687 | pThis->u16Irq = u16Irq;
|
---|
| 688 | pThis->GCPhysMmioBase = GCPhysMmioBase;
|
---|
| 689 |
|
---|
| 690 | /*
|
---|
| 691 | * Register and map the MMIO region.
|
---|
| 692 | */
|
---|
| 693 | rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL061_MMIO_SIZE, pl061MmioWrite, pl061MmioRead,
|
---|
| 694 | IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL061", &pThis->hMmio);
|
---|
| 695 | AssertRCReturn(rc, rc);
|
---|
| 696 |
|
---|
| 697 |
|
---|
| 698 | /*
|
---|
| 699 | * Saved state.
|
---|
| 700 | */
|
---|
| 701 | rc = PDMDevHlpSSMRegisterEx(pDevIns, PL061_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
|
---|
| 702 | NULL, pl061R3LiveExec, NULL,
|
---|
| 703 | NULL, pl061R3SaveExec, NULL,
|
---|
| 704 | NULL, pl061R3LoadExec, pl061R3LoadDone);
|
---|
| 705 | AssertRCReturn(rc, rc);
|
---|
| 706 |
|
---|
| 707 | /*
|
---|
| 708 | * Attach the GPIO driver and get the interfaces.
|
---|
| 709 | */
|
---|
| 710 | rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "GPIO");
|
---|
| 711 | if (RT_SUCCESS(rc))
|
---|
| 712 | {
|
---|
[101617] | 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 | }
|
---|
[99895] | 719 | }
|
---|
| 720 | else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
|
---|
| 721 | {
|
---|
| 722 | pThisCC->pDrvBase = NULL;
|
---|
[101617] | 723 | pThisCC->pDrvGpio = NULL;
|
---|
[99895] | 724 | LogRel(("PL061#%d: no unit\n", iInstance));
|
---|
| 725 | }
|
---|
| 726 | else
|
---|
| 727 | {
|
---|
| 728 | AssertLogRelMsgFailed(("PL061#%d: Failed to attach to gpio driver. rc=%Rrc\n", iInstance, rc));
|
---|
| 729 | /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
|
---|
| 730 | return rc;
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | pl061R3Reset(pDevIns);
|
---|
| 734 | return VINF_SUCCESS;
|
---|
| 735 | }
|
---|
| 736 |
|
---|
| 737 | #else /* !IN_RING3 */
|
---|
| 738 |
|
---|
| 739 | /**
|
---|
| 740 | * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
|
---|
| 741 | */
|
---|
| 742 | static DECLCALLBACK(int) pl061RZConstruct(PPDMDEVINS pDevIns)
|
---|
| 743 | {
|
---|
| 744 | PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
|
---|
| 745 | PDEVPL061 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL061);
|
---|
| 746 | PDEVPL061CC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPL061CC);
|
---|
| 747 |
|
---|
| 748 | int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl061MmioWrite, pl061MmioRead, NULL /*pvUser*/);
|
---|
| 749 | AssertRCReturn(rc, rc);
|
---|
| 750 |
|
---|
| 751 | return VINF_SUCCESS;
|
---|
| 752 | }
|
---|
| 753 |
|
---|
| 754 | #endif /* !IN_RING3 */
|
---|
| 755 |
|
---|
| 756 | /**
|
---|
| 757 | * The device registration structure.
|
---|
| 758 | */
|
---|
| 759 | const PDMDEVREG g_DevicePl061Gpio =
|
---|
| 760 | {
|
---|
| 761 | /* .u32Version = */ PDM_DEVREG_VERSION,
|
---|
| 762 | /* .uReserved0 = */ 0,
|
---|
| 763 | /* .szName = */ "arm-pl061-gpio",
|
---|
| 764 | /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
|
---|
[101617] | 765 | /* .fClass = */ PDM_DEVREG_CLASS_GPIO,
|
---|
[99895] | 766 | /* .cMaxInstances = */ UINT32_MAX,
|
---|
| 767 | /* .uSharedVersion = */ 42,
|
---|
| 768 | /* .cbInstanceShared = */ sizeof(DEVPL061),
|
---|
| 769 | /* .cbInstanceCC = */ sizeof(DEVPL061CC),
|
---|
| 770 | /* .cbInstanceRC = */ sizeof(DEVPL061RC),
|
---|
| 771 | /* .cMaxPciDevices = */ 0,
|
---|
| 772 | /* .cMaxMsixVectors = */ 0,
|
---|
| 773 | /* .pszDescription = */ "ARM PL061 PrimeCell GPIO",
|
---|
| 774 | #if defined(IN_RING3)
|
---|
| 775 | /* .pszRCMod = */ "VBoxDDRC.rc",
|
---|
| 776 | /* .pszR0Mod = */ "VBoxDDR0.r0",
|
---|
| 777 | /* .pfnConstruct = */ pl061R3Construct,
|
---|
| 778 | /* .pfnDestruct = */ pl061R3Destruct,
|
---|
| 779 | /* .pfnRelocate = */ NULL,
|
---|
| 780 | /* .pfnMemSetup = */ NULL,
|
---|
| 781 | /* .pfnPowerOn = */ NULL,
|
---|
| 782 | /* .pfnReset = */ pl061R3Reset,
|
---|
| 783 | /* .pfnSuspend = */ NULL,
|
---|
| 784 | /* .pfnResume = */ NULL,
|
---|
| 785 | /* .pfnAttach = */ pl061R3Attach,
|
---|
| 786 | /* .pfnDetach = */ pl061R3Detach,
|
---|
| 787 | /* .pfnQueryInterface = */ NULL,
|
---|
| 788 | /* .pfnInitComplete = */ NULL,
|
---|
| 789 | /* .pfnPowerOff = */ NULL,
|
---|
| 790 | /* .pfnSoftReset = */ NULL,
|
---|
| 791 | /* .pfnReserved0 = */ NULL,
|
---|
| 792 | /* .pfnReserved1 = */ NULL,
|
---|
| 793 | /* .pfnReserved2 = */ NULL,
|
---|
| 794 | /* .pfnReserved3 = */ NULL,
|
---|
| 795 | /* .pfnReserved4 = */ NULL,
|
---|
| 796 | /* .pfnReserved5 = */ NULL,
|
---|
| 797 | /* .pfnReserved6 = */ NULL,
|
---|
| 798 | /* .pfnReserved7 = */ NULL,
|
---|
| 799 | #elif defined(IN_RING0)
|
---|
| 800 | /* .pfnEarlyConstruct = */ NULL,
|
---|
| 801 | /* .pfnConstruct = */ pl061RZConstruct,
|
---|
| 802 | /* .pfnDestruct = */ NULL,
|
---|
| 803 | /* .pfnFinalDestruct = */ NULL,
|
---|
| 804 | /* .pfnRequest = */ NULL,
|
---|
| 805 | /* .pfnReserved0 = */ NULL,
|
---|
| 806 | /* .pfnReserved1 = */ NULL,
|
---|
| 807 | /* .pfnReserved2 = */ NULL,
|
---|
| 808 | /* .pfnReserved3 = */ NULL,
|
---|
| 809 | /* .pfnReserved4 = */ NULL,
|
---|
| 810 | /* .pfnReserved5 = */ NULL,
|
---|
| 811 | /* .pfnReserved6 = */ NULL,
|
---|
| 812 | /* .pfnReserved7 = */ NULL,
|
---|
| 813 | #elif defined(IN_RC)
|
---|
| 814 | /* .pfnConstruct = */ pl061RZConstruct,
|
---|
| 815 | /* .pfnReserved0 = */ NULL,
|
---|
| 816 | /* .pfnReserved1 = */ NULL,
|
---|
| 817 | /* .pfnReserved2 = */ NULL,
|
---|
| 818 | /* .pfnReserved3 = */ NULL,
|
---|
| 819 | /* .pfnReserved4 = */ NULL,
|
---|
| 820 | /* .pfnReserved5 = */ NULL,
|
---|
| 821 | /* .pfnReserved6 = */ NULL,
|
---|
| 822 | /* .pfnReserved7 = */ NULL,
|
---|
| 823 | #else
|
---|
| 824 | # error "Not in IN_RING3, IN_RING0 or IN_RC!"
|
---|
| 825 | #endif
|
---|
| 826 | /* .u32VersionEnd = */ PDM_DEVREG_VERSION
|
---|
| 827 | };
|
---|
| 828 |
|
---|
| 829 | #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
|
---|
| 830 |
|
---|