mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-26 23:36:51 +00:00
DM: virtio-gpio: implement GPIO operations via accessing PIO
GPIO set/get value can be operated by accessing PIO space and the PIO register definition for GPIO is in gpio_dm.h, frontend driver or ACPI control methods can operate GPIO based on it. GPIO mediator also defines ACPI control methods to support GPIO operations, GPIO consumers can invoke PIO_GPIO_SET_VALUE/PIO_GPIO_GET_VALUE in their own DSDT to set/get one GPIO value via ACPI control method. v2: 1) Fix code style. 2) Use virtio configuration space callbacks to implement GPIO PIO operations that replace pci_gpio_read/pci_gpio_write with virtio_cfgread/virtio_cfgwrite. 3) Return 0xFFFFFFFF as invalid result of PIO reading instead 0. Tracked-On: #2512 Signed-off-by: Yuan Liu <yuan1.liu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
a66aa65f05
commit
4a6bc369ad
@ -24,6 +24,7 @@
|
|||||||
#include "pci_core.h"
|
#include "pci_core.h"
|
||||||
#include "mevent.h"
|
#include "mevent.h"
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
|
#include "gpio_dm.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPIO virtualization architecture
|
* GPIO virtualization architecture
|
||||||
@ -143,6 +144,10 @@ static FILE *dbg_file;
|
|||||||
/* make virtio gpio mediator a singleton mode */
|
/* make virtio gpio mediator a singleton mode */
|
||||||
static bool virtio_gpio_is_active;
|
static bool virtio_gpio_is_active;
|
||||||
|
|
||||||
|
/* GPIO PIO space */
|
||||||
|
#define GPIO_PIO_SIZE (VIRTIO_GPIO_MAX_VLINES * 4)
|
||||||
|
static uint64_t gpio_pio_start;
|
||||||
|
|
||||||
/* Uses the same packed config format as generic pinconf. */
|
/* Uses the same packed config format as generic pinconf. */
|
||||||
#define PIN_CONF_UNPACKED(p) ((unsigned long) p & 0xffUL)
|
#define PIN_CONF_UNPACKED(p) ((unsigned long) p & 0xffUL)
|
||||||
enum pin_config_param {
|
enum pin_config_param {
|
||||||
@ -231,6 +236,8 @@ struct gpio_line {
|
|||||||
int fd; /* native gpio line fd */
|
int fd; /* native gpio line fd */
|
||||||
int dir; /* gpio direction */
|
int dir; /* gpio direction */
|
||||||
bool busy; /* gpio line request by kernel */
|
bool busy; /* gpio line request by kernel */
|
||||||
|
int value; /* gpio value */
|
||||||
|
uint64_t config; /* gpio configuration */
|
||||||
struct native_gpio_chip *chip; /* parent gpio chip */
|
struct native_gpio_chip *chip; /* parent gpio chip */
|
||||||
struct gpio_irq_desc *irq; /* connect to irq descriptor */
|
struct gpio_irq_desc *irq; /* connect to irq descriptor */
|
||||||
};
|
};
|
||||||
@ -282,6 +289,8 @@ static void print_virtio_gpio_info(struct virtio_gpio_request *req,
|
|||||||
struct virtio_gpio_response *rsp, bool in);
|
struct virtio_gpio_response *rsp, bool in);
|
||||||
static void print_intr_statistics(struct gpio_irq_chip *chip);
|
static void print_intr_statistics(struct gpio_irq_chip *chip);
|
||||||
static void record_intr_statistics(struct gpio_irq_chip *chip, uint64_t mask);
|
static void record_intr_statistics(struct gpio_irq_chip *chip, uint64_t mask);
|
||||||
|
static void gpio_pio_write(struct virtio_gpio *gpio, int n, uint64_t reg);
|
||||||
|
static uint32_t gpio_pio_read(struct virtio_gpio *gpio, int n);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
native_gpio_update_line_info(struct gpio_line *line)
|
native_gpio_update_line_info(struct gpio_line *line)
|
||||||
@ -371,6 +380,15 @@ native_gpio_open_line(struct gpio_line *line, unsigned int flags,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags) {
|
||||||
|
line->config = flags;
|
||||||
|
if (flags & GPIOHANDLE_REQUEST_OUTPUT) {
|
||||||
|
line->dir = 0;
|
||||||
|
line->value = value;
|
||||||
|
} else if (flags & GPIOHANDLE_REQUEST_INPUT)
|
||||||
|
line->dir = 1;
|
||||||
|
}
|
||||||
|
|
||||||
line->fd = req.fd;
|
line->fd = req.fd;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -398,6 +416,7 @@ gpio_set_value(struct virtio_gpio *gpio, unsigned int offset,
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
line->value = value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,14 +574,41 @@ static void virtio_gpio_reset(void *vdev)
|
|||||||
virtio_reset_dev(&gpio->base);
|
virtio_reset_dev(&gpio->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virtio_gpio_cfgwrite(void *vdev, int offset, int size, uint32_t value)
|
||||||
|
{
|
||||||
|
int cfg_size;
|
||||||
|
|
||||||
|
cfg_size = sizeof(struct virtio_gpio_config);
|
||||||
|
offset -= cfg_size;
|
||||||
|
if (offset < 0 || offset >= GPIO_PIO_SIZE) {
|
||||||
|
DPRINTF("virtio_gpio: write to invalid reg %d\n", offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_pio_write((struct virtio_gpio *)vdev, offset >> 2, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virtio_gpio_cfgread(void *vdev, int offset, int size, uint32_t *retval)
|
virtio_gpio_cfgread(void *vdev, int offset, int size, uint32_t *retval)
|
||||||
{
|
{
|
||||||
struct virtio_gpio *gpio = vdev;
|
struct virtio_gpio *gpio = vdev;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
int cfg_size;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
ptr = (uint8_t *)&gpio->config + offset;
|
cfg_size = sizeof(struct virtio_gpio_config);
|
||||||
memcpy(retval, ptr, size);
|
if (offset < 0 || offset >= cfg_size + GPIO_PIO_SIZE) {
|
||||||
|
DPRINTF("virtio_gpio: read from invalid reg %d\n", offset);
|
||||||
|
return -1;
|
||||||
|
} else if (offset < cfg_size) {
|
||||||
|
ptr = (uint8_t *)&gpio->config + offset;
|
||||||
|
memcpy(retval, ptr, size);
|
||||||
|
} else {
|
||||||
|
reg = gpio_pio_read(gpio, (offset - cfg_size) >> 2);
|
||||||
|
memcpy(retval, ®, size);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,7 +619,7 @@ static struct virtio_ops virtio_gpio_ops = {
|
|||||||
virtio_gpio_reset, /* reset */
|
virtio_gpio_reset, /* reset */
|
||||||
NULL, /* device-wide qnotify */
|
NULL, /* device-wide qnotify */
|
||||||
virtio_gpio_cfgread, /* read virtio config */
|
virtio_gpio_cfgread, /* read virtio config */
|
||||||
NULL, /* write virtio config */
|
virtio_gpio_cfgwrite, /* write virtio config */
|
||||||
NULL, /* apply negotiated features */
|
NULL, /* apply negotiated features */
|
||||||
NULL, /* called on guest set status */
|
NULL, /* called on guest set status */
|
||||||
|
|
||||||
@ -1323,9 +1369,15 @@ virtio_gpio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate PIO space for GPIO */
|
||||||
|
virtio_gpio_ops.cfgsize += GPIO_PIO_SIZE;
|
||||||
|
|
||||||
/* use BAR 0 to map config regs in IO space */
|
/* use BAR 0 to map config regs in IO space */
|
||||||
virtio_set_io_bar(&gpio->base, 0);
|
virtio_set_io_bar(&gpio->base, 0);
|
||||||
|
|
||||||
|
gpio_pio_start = dev->bar[0].addr + VIRTIO_PCI_CONFIG_OFF(1) +
|
||||||
|
sizeof(struct virtio_gpio_config);
|
||||||
|
|
||||||
virtio_gpio_is_active = true;
|
virtio_gpio_is_active = true;
|
||||||
|
|
||||||
/* dump gpio information */
|
/* dump gpio information */
|
||||||
@ -1387,6 +1439,92 @@ virtio_gpio_write_dsdt(struct pci_vdev *dev)
|
|||||||
dsdt_line(" }");
|
dsdt_line(" }");
|
||||||
dsdt_line("}");
|
dsdt_line("}");
|
||||||
dsdt_line("");
|
dsdt_line("");
|
||||||
|
dsdt_line("Scope (_SB)");
|
||||||
|
dsdt_line("{");
|
||||||
|
dsdt_line(" Method (%s, 2, Serialized)", PIO_GPIO_CM_SET);
|
||||||
|
dsdt_line(" {");
|
||||||
|
dsdt_line(" Local0 = (0x%08x + (Arg0 << 2))", gpio_pio_start);
|
||||||
|
dsdt_line(" OperationRegion (GPOR, SystemIO, Local0, 0x04)");
|
||||||
|
dsdt_line(" Field (GPOR, DWordAcc, NoLock, Preserve)");
|
||||||
|
dsdt_line(" {");
|
||||||
|
dsdt_line(" TEMP, 2");
|
||||||
|
dsdt_line(" }");
|
||||||
|
dsdt_line(" TEMP = Arg1");
|
||||||
|
dsdt_line(" }");
|
||||||
|
dsdt_line("");
|
||||||
|
dsdt_line(" Method (%s, 1, Serialized)", PIO_GPIO_CM_GET);
|
||||||
|
dsdt_line(" {");
|
||||||
|
dsdt_line(" Local0 = (0x%08x + (Arg0 << 2))", gpio_pio_start);
|
||||||
|
dsdt_line(" OperationRegion (GPOR, SystemIO, Local0, 0x04)");
|
||||||
|
dsdt_line(" Field (GPOR, DWordAcc, NoLock, Preserve)");
|
||||||
|
dsdt_line(" {");
|
||||||
|
dsdt_line(" TEMP, 1,");
|
||||||
|
dsdt_line(" }");
|
||||||
|
dsdt_line(" Return (TEMP)");
|
||||||
|
dsdt_line(" }");
|
||||||
|
dsdt_line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gpio_pio_write(struct virtio_gpio *gpio, int n, uint64_t reg)
|
||||||
|
{
|
||||||
|
struct gpio_line *line;
|
||||||
|
int value, dir, mode;
|
||||||
|
uint16_t config;
|
||||||
|
|
||||||
|
if (n >= gpio->nvline) {
|
||||||
|
DPRINTF("pio write is invalid, n %d, nvline %d\n",
|
||||||
|
n, gpio->nvline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = gpio->vlines[n];
|
||||||
|
value = reg & PIO_GPIO_VALUE_MASK;
|
||||||
|
dir = (reg & PIO_GPIO_DIR_MASK) >> PIO_GPIO_DIR_OFFSET;
|
||||||
|
mode = (reg & PIO_GPIO_MODE_MASK) >> PIO_GPIO_MODE_OFFSET;
|
||||||
|
config = (reg & PIO_GPIO_CONFIG_MASK) >> PIO_GPIO_CONFIG_OFFSET;
|
||||||
|
|
||||||
|
/* 0 means GPIO, 1 means IRQ */
|
||||||
|
if (mode == 1) {
|
||||||
|
DPRINTF("pio write failure, gpio %d is in IRQ mode\n", n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF("pio write n %d, reg 0x%lX, val %d, dir %d, mod %d, cfg 0x%x\n",
|
||||||
|
n, reg, value, dir, mode, config);
|
||||||
|
|
||||||
|
if (config != line->config)
|
||||||
|
gpio_set_config(gpio, n, config);
|
||||||
|
|
||||||
|
/* 0 means output, 1 means input */
|
||||||
|
if (dir != line->dir || ((dir == 0) && (value != line->value)))
|
||||||
|
dir == 0 ? gpio_set_direction_output(gpio, n, value) :
|
||||||
|
gpio_set_direction_input(gpio, n);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
gpio_pio_read(struct virtio_gpio *gpio, int n)
|
||||||
|
{
|
||||||
|
struct gpio_line *line;
|
||||||
|
uint32_t reg = 0;
|
||||||
|
|
||||||
|
if (n >= gpio->nvline) {
|
||||||
|
DPRINTF("pio read is invalid, n %d, nvline %d\n",
|
||||||
|
n, gpio->nvline);
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = gpio->vlines[n];
|
||||||
|
reg = line->value;
|
||||||
|
reg |= ((line->dir << PIO_GPIO_DIR_OFFSET) & PIO_GPIO_DIR_MASK);
|
||||||
|
reg |= ((line->config << PIO_GPIO_CONFIG_OFFSET) &
|
||||||
|
PIO_GPIO_CONFIG_MASK);
|
||||||
|
if (line->irq->fd > 0)
|
||||||
|
reg |= 1 << PIO_GPIO_MODE_OFFSET;
|
||||||
|
|
||||||
|
DPRINTF("pio read n %d, reg 0x%X\n", n, reg);
|
||||||
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pci_vdev_ops pci_ops_virtio_gpio = {
|
struct pci_vdev_ops pci_ops_virtio_gpio = {
|
||||||
|
38
devicemodel/include/gpio_dm.h
Normal file
38
devicemodel/include/gpio_dm.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GPIO_DM_H_
|
||||||
|
#define _GPIO_DM_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPIO PIO register definition
|
||||||
|
*
|
||||||
|
* +---------------+----------+------+-----------+-------+
|
||||||
|
* | Configuration | Reserved | Mode | Direction | value |
|
||||||
|
* | 16b | 13b | 1b | 1b | 1b |
|
||||||
|
* +---------------+----------+------+-----------+-------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIO_GPIO_VALUE_MASK 0x1
|
||||||
|
#define PIO_GPIO_DIR_OFFSET 1
|
||||||
|
#define PIO_GPIO_DIR_MASK (0x1 << PIO_GPIO_DIR_OFFSET)
|
||||||
|
#define PIO_GPIO_MODE_OFFSET 2
|
||||||
|
#define PIO_GPIO_MODE_MASK (0x1 << PIO_GPIO_MODE_OFFSET)
|
||||||
|
#define PIO_GPIO_CONFIG_OFFSET 16
|
||||||
|
#define PIO_GPIO_CONFIG_MASK (0xff << PIO_GPIO_CONFIG_OFFSET)
|
||||||
|
|
||||||
|
/* PIO GPIO control method support */
|
||||||
|
#define PIO_GPIO_CM_GET "GPCG"
|
||||||
|
#define PIO_GPIO_CM_SET "GPCS"
|
||||||
|
|
||||||
|
/* PIO GPIO operations support */
|
||||||
|
#define PIO_GPIO_SET_VALUE(number, value) \
|
||||||
|
PIO_GPIO_CM_SET"("#number","#value")"
|
||||||
|
|
||||||
|
#define PIO_GPIO_GET_VALUE(number) \
|
||||||
|
PIO_GPIO_CM_GET"("#number")"
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user