mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-26 07:21:37 +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 "mevent.h"
|
||||
#include "virtio.h"
|
||||
#include "gpio_dm.h"
|
||||
|
||||
/*
|
||||
* GPIO virtualization architecture
|
||||
@ -143,6 +144,10 @@ static FILE *dbg_file;
|
||||
/* make virtio gpio mediator a singleton mode */
|
||||
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. */
|
||||
#define PIN_CONF_UNPACKED(p) ((unsigned long) p & 0xffUL)
|
||||
enum pin_config_param {
|
||||
@ -231,6 +236,8 @@ struct gpio_line {
|
||||
int fd; /* native gpio line fd */
|
||||
int dir; /* gpio direction */
|
||||
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 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);
|
||||
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 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
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
return rc;
|
||||
}
|
||||
@ -398,6 +416,7 @@ gpio_set_value(struct virtio_gpio *gpio, unsigned int offset,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
line->value = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -555,14 +574,41 @@ static void virtio_gpio_reset(void *vdev)
|
||||
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
|
||||
virtio_gpio_cfgread(void *vdev, int offset, int size, uint32_t *retval)
|
||||
{
|
||||
struct virtio_gpio *gpio = vdev;
|
||||
void *ptr;
|
||||
int cfg_size;
|
||||
uint32_t reg;
|
||||
|
||||
ptr = (uint8_t *)&gpio->config + offset;
|
||||
memcpy(retval, ptr, size);
|
||||
cfg_size = sizeof(struct virtio_gpio_config);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -573,7 +619,7 @@ static struct virtio_ops virtio_gpio_ops = {
|
||||
virtio_gpio_reset, /* reset */
|
||||
NULL, /* device-wide qnotify */
|
||||
virtio_gpio_cfgread, /* read virtio config */
|
||||
NULL, /* write virtio config */
|
||||
virtio_gpio_cfgwrite, /* write virtio config */
|
||||
NULL, /* apply negotiated features */
|
||||
NULL, /* called on guest set status */
|
||||
|
||||
@ -1323,9 +1369,15 @@ virtio_gpio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate PIO space for GPIO */
|
||||
virtio_gpio_ops.cfgsize += GPIO_PIO_SIZE;
|
||||
|
||||
/* use BAR 0 to map config regs in IO space */
|
||||
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;
|
||||
|
||||
/* dump gpio information */
|
||||
@ -1387,6 +1439,92 @@ virtio_gpio_write_dsdt(struct pci_vdev *dev)
|
||||
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 = {
|
||||
|
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