mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 12:54:27 +00:00
Add amdgpio, driver for GPIO controller on AMD-based x86_64 platforms
Submitted by: Rajesh Kumar <rajbsd@gmail.com> Differential Revision: https://reviews.freebsd.org/D16865
This commit is contained in:
parent
c9bd5bee1a
commit
8ce574de3b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=339523
|
@ -208,6 +208,7 @@ dev/acpi_support/acpi_wmi_if.m standard
|
|||
dev/agp/agp_amd64.c optional agp
|
||||
dev/agp/agp_i810.c optional agp
|
||||
dev/agp/agp_via.c optional agp
|
||||
dev/amdgpio/amdgpio.c optional amdgpio
|
||||
dev/amdsbwd/amdsbwd.c optional amdsbwd
|
||||
dev/amdsmn/amdsmn.c optional amdsmn | amdtemp
|
||||
dev/amdtemp/amdtemp.c optional amdtemp
|
||||
|
|
468
sys/dev/amdgpio/amdgpio.c
Normal file
468
sys/dev/amdgpio/amdgpio.c
Normal file
|
@ -0,0 +1,468 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2018 Advanced Micro Devices
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_acpi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/gpio.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/gpio/gpiobusvar.h>
|
||||
|
||||
#include "gpio_if.h"
|
||||
#include "amdgpio.h"
|
||||
|
||||
static struct resource_spec amdgpio_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||
{ -1, 0, 0 }
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off)
|
||||
{
|
||||
return (bus_read_4(sc->sc_res[0], off));
|
||||
}
|
||||
|
||||
static inline void
|
||||
amdgpio_write_4(struct amdgpio_softc *sc, bus_size_t off,
|
||||
uint32_t val)
|
||||
{
|
||||
bus_write_4(sc->sc_res[0], off, val);
|
||||
}
|
||||
|
||||
static bool
|
||||
amdgpio_is_pin_output(struct amdgpio_softc *sc, uint32_t pin)
|
||||
{
|
||||
uint32_t reg, val;
|
||||
bool ret;
|
||||
|
||||
/* Get the current pin state */
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
reg = AMDGPIO_PIN_REGISTER(pin);
|
||||
val = amdgpio_read_4(sc, reg);
|
||||
|
||||
if (val & BIT(OUTPUT_ENABLE_OFF))
|
||||
ret = true;
|
||||
else
|
||||
ret = false;
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static device_t
|
||||
amdgpio_get_bus(device_t dev)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("busdev %p\n", sc->sc_busdev);
|
||||
return (sc->sc_busdev);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_max(device_t dev, int *maxpin)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
*maxpin = sc->sc_npins - 1;
|
||||
dprintf("npins %d maxpin %d\n", sc->sc_npins, *maxpin);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static bool
|
||||
amdgpio_valid_pin(struct amdgpio_softc *sc, int pin)
|
||||
{
|
||||
dprintf("pin %d\n", pin);
|
||||
if (sc->sc_res[0] == NULL)
|
||||
return (false);
|
||||
|
||||
if ((sc->sc_gpio_pins[pin].gp_pin == pin) &&
|
||||
(sc->sc_gpio_pins[pin].gp_caps != 0))
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_getname(device_t dev, uint32_t pin, char *name)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
|
||||
dprintf("pin %d\n", pin);
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
/* Set a very simple name */
|
||||
snprintf(name, GPIOMAXNAME, "%s", sc->sc_gpio_pins[pin].gp_name);
|
||||
name[GPIOMAXNAME - 1] = '\0';
|
||||
|
||||
dprintf("pin %d name %s\n", pin, name);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("pin %d\n", pin);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
*caps = sc->sc_gpio_pins[pin].gp_caps;
|
||||
|
||||
dprintf("pin %d caps 0x%x\n", pin, *caps);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
|
||||
dprintf("pin %d\n", pin);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
*flags = sc->sc_gpio_pins[pin].gp_flags;
|
||||
|
||||
dprintf("pin %d flags 0x%x\n", pin, *flags);
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
uint32_t reg, val, allowed;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("pin %d flags 0x%x\n", pin, flags);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
|
||||
|
||||
/*
|
||||
* Only directtion flag allowed
|
||||
*/
|
||||
if (flags & ~allowed)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Not both directions simultaneously
|
||||
*/
|
||||
if ((flags & allowed) == allowed)
|
||||
return (EINVAL);
|
||||
|
||||
/* Set the GPIO mode and state */
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
reg = AMDGPIO_PIN_REGISTER(pin);
|
||||
val = amdgpio_read_4(sc, reg);
|
||||
|
||||
if (flags & GPIO_PIN_INPUT) {
|
||||
val &= ~BIT(OUTPUT_ENABLE_OFF);
|
||||
sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT;
|
||||
} else {
|
||||
val |= BIT(OUTPUT_ENABLE_OFF);
|
||||
sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT;
|
||||
}
|
||||
|
||||
amdgpio_write_4(sc, reg, val);
|
||||
|
||||
dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n",
|
||||
pin, flags, val, sc->sc_gpio_pins[pin].gp_flags);
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
uint32_t reg, val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("pin %d\n", pin);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
*value = 0;
|
||||
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
reg = AMDGPIO_PIN_REGISTER(pin);
|
||||
val = amdgpio_read_4(sc, reg);
|
||||
|
||||
if (val & BIT(OUTPUT_VALUE_OFF))
|
||||
*value = GPIO_PIN_HIGH;
|
||||
else
|
||||
*value = GPIO_PIN_LOW;
|
||||
|
||||
dprintf("pin %d value 0x%x\n", pin, *value);
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
uint32_t reg, val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("pin %d value 0x%x\n", pin, value);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
if (!amdgpio_is_pin_output(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
reg = AMDGPIO_PIN_REGISTER(pin);
|
||||
val = amdgpio_read_4(sc, reg);
|
||||
|
||||
if (value == GPIO_PIN_LOW)
|
||||
val &= ~BIT(OUTPUT_VALUE_OFF);
|
||||
else
|
||||
val |= BIT(OUTPUT_VALUE_OFF);
|
||||
|
||||
amdgpio_write_4(sc, reg, val);
|
||||
|
||||
dprintf("pin %d value 0x%x val 0x%x\n", pin, value, val);
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_pin_toggle(device_t dev, uint32_t pin)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
uint32_t reg, val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
dprintf("pin %d\n", pin);
|
||||
if (!amdgpio_valid_pin(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
if (!amdgpio_is_pin_output(sc, pin))
|
||||
return (EINVAL);
|
||||
|
||||
/* Toggle the pin */
|
||||
AMDGPIO_LOCK(sc);
|
||||
|
||||
reg = AMDGPIO_PIN_REGISTER(pin);
|
||||
val = amdgpio_read_4(sc, reg);
|
||||
dprintf("pin %d value before 0x%x\n", pin, val);
|
||||
val = val ^ BIT(OUTPUT_VALUE_OFF);
|
||||
dprintf("pin %d value after 0x%x\n", pin, val);
|
||||
amdgpio_write_4(sc, reg, val);
|
||||
|
||||
AMDGPIO_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_probe(device_t dev)
|
||||
{
|
||||
static char *gpio_ids[] = { "AMD0030", "AMDI0030", NULL };
|
||||
|
||||
if (acpi_disabled("gpio") ||
|
||||
ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids) == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "AMD GPIO Controller");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpio_attach(device_t dev)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
int i, pin, bank;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_handle = acpi_get_handle(dev);
|
||||
|
||||
AMDGPIO_LOCK_INIT(sc);
|
||||
|
||||
sc->sc_nbanks = AMD_GPIO_NUM_PIN_BANK;
|
||||
sc->sc_npins = AMD_GPIO_PINS_MAX;
|
||||
sc->sc_bank_prefix = AMD_GPIO_PREFIX;
|
||||
sc->sc_pin_info = kernzp_pins;
|
||||
sc->sc_ngroups = nitems(kernzp_groups);
|
||||
sc->sc_groups = kernzp_groups;
|
||||
|
||||
if (bus_alloc_resources(dev, amdgpio_spec, sc->sc_res)) {
|
||||
device_printf(dev, "could not allocate resources\n");
|
||||
goto err_rsrc;
|
||||
}
|
||||
|
||||
sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
|
||||
sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
|
||||
|
||||
/* Initialize all possible pins to be Invalid */
|
||||
for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) {
|
||||
snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
|
||||
"Unexposed PIN %d\n", i);
|
||||
sc->sc_gpio_pins[i].gp_pin = -1;
|
||||
sc->sc_gpio_pins[i].gp_caps = 0;
|
||||
sc->sc_gpio_pins[i].gp_flags = 0;
|
||||
}
|
||||
|
||||
/* Initialize only driver exposed pins with appropriate capabilities */
|
||||
for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) {
|
||||
pin = kernzp_pins[i].pin_num;
|
||||
bank = pin/AMD_GPIO_PINS_PER_BANK;
|
||||
snprintf(sc->sc_gpio_pins[pin].gp_name, GPIOMAXNAME, "%s%d_%s\n",
|
||||
AMD_GPIO_PREFIX, bank, kernzp_pins[i].pin_name);
|
||||
sc->sc_gpio_pins[pin].gp_pin = pin;
|
||||
sc->sc_gpio_pins[pin].gp_caps = AMDGPIO_DEFAULT_CAPS;
|
||||
sc->sc_gpio_pins[pin].gp_flags = (amdgpio_is_pin_output(sc, pin)?
|
||||
GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
|
||||
}
|
||||
|
||||
sc->sc_busdev = gpiobus_attach_bus(dev);
|
||||
if (sc->sc_busdev == NULL) {
|
||||
device_printf(dev, "could not attach gpiobus\n");
|
||||
goto err_bus;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
err_bus:
|
||||
bus_release_resources(dev, amdgpio_spec, sc->sc_res);
|
||||
|
||||
err_rsrc:
|
||||
AMDGPIO_LOCK_DESTROY(sc);
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
amdgpio_detach(device_t dev)
|
||||
{
|
||||
struct amdgpio_softc *sc;
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_busdev)
|
||||
gpiobus_detach_bus(dev);
|
||||
|
||||
bus_release_resources(dev, amdgpio_spec, sc->sc_res);
|
||||
|
||||
AMDGPIO_LOCK_DESTROY(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t amdgpio_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, amdgpio_probe),
|
||||
DEVMETHOD(device_attach, amdgpio_attach),
|
||||
DEVMETHOD(device_detach, amdgpio_detach),
|
||||
|
||||
/* GPIO protocol */
|
||||
DEVMETHOD(gpio_get_bus, amdgpio_get_bus),
|
||||
DEVMETHOD(gpio_pin_max, amdgpio_pin_max),
|
||||
DEVMETHOD(gpio_pin_getname, amdgpio_pin_getname),
|
||||
DEVMETHOD(gpio_pin_getcaps, amdgpio_pin_getcaps),
|
||||
DEVMETHOD(gpio_pin_getflags, amdgpio_pin_getflags),
|
||||
DEVMETHOD(gpio_pin_setflags, amdgpio_pin_setflags),
|
||||
DEVMETHOD(gpio_pin_get, amdgpio_pin_get),
|
||||
DEVMETHOD(gpio_pin_set, amdgpio_pin_set),
|
||||
DEVMETHOD(gpio_pin_toggle, amdgpio_pin_toggle),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t amdgpio_driver = {
|
||||
"gpio",
|
||||
amdgpio_methods,
|
||||
sizeof(struct amdgpio_softc),
|
||||
};
|
||||
|
||||
static devclass_t amdgpio_devclass;
|
||||
DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, amdgpio_devclass, 0, 0);
|
||||
MODULE_DEPEND(amdgpio, acpi, 1, 1, 1);
|
||||
MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1);
|
||||
MODULE_VERSION(amdgpio, 1);
|
332
sys/dev/amdgpio/amdgpio.h
Normal file
332
sys/dev/amdgpio/amdgpio.h
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2018 Advanced Micro Devices
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define dprintf(fmt, args...) do { \
|
||||
printf("%s(): ", __func__); \
|
||||
printf(fmt,##args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define dprintf(fmt, args...)
|
||||
#endif
|
||||
|
||||
#define AMD_GPIO_PREFIX "AMDGPIO"
|
||||
|
||||
#define AMD_GPIO_NUM_PIN_BANK 4
|
||||
#define AMD_GPIO_PINS_PER_BANK 64
|
||||
#define AMD_GPIO_PINS_MAX 256 /* 4 banks * 64 pins */
|
||||
|
||||
/* Number of pins in each bank */
|
||||
#define AMD_GPIO_PINS_BANK0 63
|
||||
#define AMD_GPIO_PINS_BANK1 64
|
||||
#define AMD_GPIO_PINS_BANK2 56
|
||||
#define AMD_GPIO_PINS_BANK3 32
|
||||
#define AMD_GPIO_PIN_PRESENT (AMD_GPIO_PINS_BANK0 + \
|
||||
AMD_GPIO_PINS_BANK1 + \
|
||||
AMD_GPIO_PINS_BANK2 + \
|
||||
AMD_GPIO_PINS_BANK3)
|
||||
#define AMDGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
|
||||
|
||||
/* Register related macros */
|
||||
#define AMDGPIO_PIN_REGISTER(pin) (pin * 4)
|
||||
|
||||
#define WAKE_INT_MASTER_REG 0xfc
|
||||
#define EOI_MASK (1 << 29)
|
||||
#define WAKE_INT_STATUS_REG0 0x2f8
|
||||
#define WAKE_INT_STATUS_REG1 0x2fc
|
||||
|
||||
/* Bit definition of 32 bits of each pin register */
|
||||
#define DB_TMR_OUT_OFF 0
|
||||
#define DB_TMR_OUT_UNIT_OFF 4
|
||||
#define DB_CNTRL_OFF 5
|
||||
#define DB_TMR_LARGE_OFF 7
|
||||
#define LEVEL_TRIG_OFF 8
|
||||
#define ACTIVE_LEVEL_OFF 9
|
||||
#define INTERRUPT_ENABLE_OFF 11
|
||||
#define INTERRUPT_MASK_OFF 12
|
||||
#define WAKE_CNTRL_OFF_S0I3 13
|
||||
#define WAKE_CNTRL_OFF_S3 14
|
||||
#define WAKE_CNTRL_OFF_S4 15
|
||||
#define PIN_STS_OFF 16
|
||||
#define DRV_STRENGTH_SEL_OFF 17
|
||||
#define PULL_UP_SEL_OFF 19
|
||||
#define PULL_UP_ENABLE_OFF 20
|
||||
#define PULL_DOWN_ENABLE_OFF 21
|
||||
#define OUTPUT_VALUE_OFF 22
|
||||
#define OUTPUT_ENABLE_OFF 23
|
||||
#define SW_CNTRL_IN_OFF 24
|
||||
#define SW_CNTRL_EN_OFF 25
|
||||
#define INTERRUPT_STS_OFF 28
|
||||
#define WAKE_STS_OFF 29
|
||||
|
||||
#define DB_TMR_OUT_MASK 0xFUL
|
||||
#define DB_CNTRL_MASK 0x3UL
|
||||
#define ACTIVE_LEVEL_MASK 0x3UL
|
||||
#define DRV_STRENGTH_SEL_MASK 0x3UL
|
||||
|
||||
#define DB_TYPE_NO_DEBOUNCE 0x0UL
|
||||
#define DB_TYPE_PRESERVE_LOW_GLITCH 0x1UL
|
||||
#define DB_TYPE_PRESERVE_HIGH_GLITCH 0x2UL
|
||||
#define DB_TYPE_REMOVE_GLITCH 0x3UL
|
||||
|
||||
#define EDGE_TRIGGER 0x0UL
|
||||
#define LEVEL_TRIGGER 0x1UL
|
||||
|
||||
#define ACTIVE_HIGH 0x0UL
|
||||
#define ACTIVE_LOW 0x1UL
|
||||
#define BOTH_EDGE 0x2UL
|
||||
|
||||
#define ENABLE_INTERRUPT 0x1UL
|
||||
#define DISABLE_INTERRUPT 0x0UL
|
||||
|
||||
#define ENABLE_INTERRUPT_MASK 0x0UL
|
||||
#define DISABLE_INTERRUPT_MASK 0x1UL
|
||||
#define CLR_INTR_STAT 0x1UL
|
||||
|
||||
#define BIT(bit) (1 << bit)
|
||||
#define GPIO_PIN_INFO(p, n) { .pin_num = (p), .pin_name = (n) }
|
||||
|
||||
struct pin_info {
|
||||
int pin_num;
|
||||
char *pin_name;
|
||||
};
|
||||
|
||||
/* Pins exposed to drivers */
|
||||
static const struct pin_info kernzp_pins[] = {
|
||||
GPIO_PIN_INFO(0, "PIN_0"),
|
||||
GPIO_PIN_INFO(1, "PIN_1"),
|
||||
GPIO_PIN_INFO(2, "PIN_2"),
|
||||
GPIO_PIN_INFO(3, "PIN_3"),
|
||||
GPIO_PIN_INFO(4, "PIN_4"),
|
||||
GPIO_PIN_INFO(5, "PIN_5"),
|
||||
GPIO_PIN_INFO(6, "PIN_6"),
|
||||
GPIO_PIN_INFO(7, "PIN_7"),
|
||||
GPIO_PIN_INFO(8, "PIN_8"),
|
||||
GPIO_PIN_INFO(9, "PIN_9"),
|
||||
GPIO_PIN_INFO(10, "PIN_10"),
|
||||
GPIO_PIN_INFO(11, "PIN_11"),
|
||||
GPIO_PIN_INFO(12, "PIN_12"),
|
||||
GPIO_PIN_INFO(13, "PIN_13"),
|
||||
GPIO_PIN_INFO(14, "PIN_14"),
|
||||
GPIO_PIN_INFO(15, "PIN_15"),
|
||||
GPIO_PIN_INFO(16, "PIN_16"),
|
||||
GPIO_PIN_INFO(17, "PIN_17"),
|
||||
GPIO_PIN_INFO(18, "PIN_18"),
|
||||
GPIO_PIN_INFO(19, "PIN_19"),
|
||||
GPIO_PIN_INFO(20, "PIN_20"),
|
||||
GPIO_PIN_INFO(23, "PIN_23"),
|
||||
GPIO_PIN_INFO(24, "PIN_24"),
|
||||
GPIO_PIN_INFO(25, "PIN_25"),
|
||||
GPIO_PIN_INFO(26, "PIN_26"),
|
||||
GPIO_PIN_INFO(39, "PIN_39"),
|
||||
GPIO_PIN_INFO(40, "PIN_40"),
|
||||
GPIO_PIN_INFO(43, "PIN_43"),
|
||||
GPIO_PIN_INFO(46, "PIN_46"),
|
||||
GPIO_PIN_INFO(47, "PIN_47"),
|
||||
GPIO_PIN_INFO(48, "PIN_48"),
|
||||
GPIO_PIN_INFO(49, "PIN_49"),
|
||||
GPIO_PIN_INFO(50, "PIN_50"),
|
||||
GPIO_PIN_INFO(51, "PIN_51"),
|
||||
GPIO_PIN_INFO(52, "PIN_52"),
|
||||
GPIO_PIN_INFO(53, "PIN_53"),
|
||||
GPIO_PIN_INFO(54, "PIN_54"),
|
||||
GPIO_PIN_INFO(55, "PIN_55"),
|
||||
GPIO_PIN_INFO(56, "PIN_56"),
|
||||
GPIO_PIN_INFO(57, "PIN_57"),
|
||||
GPIO_PIN_INFO(58, "PIN_58"),
|
||||
GPIO_PIN_INFO(59, "PIN_59"),
|
||||
GPIO_PIN_INFO(60, "PIN_60"),
|
||||
GPIO_PIN_INFO(61, "PIN_61"),
|
||||
GPIO_PIN_INFO(62, "PIN_62"),
|
||||
GPIO_PIN_INFO(64, "PIN_64"),
|
||||
GPIO_PIN_INFO(65, "PIN_65"),
|
||||
GPIO_PIN_INFO(66, "PIN_66"),
|
||||
GPIO_PIN_INFO(68, "PIN_68"),
|
||||
GPIO_PIN_INFO(69, "PIN_69"),
|
||||
GPIO_PIN_INFO(70, "PIN_70"),
|
||||
GPIO_PIN_INFO(71, "PIN_71"),
|
||||
GPIO_PIN_INFO(72, "PIN_72"),
|
||||
GPIO_PIN_INFO(74, "PIN_74"),
|
||||
GPIO_PIN_INFO(75, "PIN_75"),
|
||||
GPIO_PIN_INFO(76, "PIN_76"),
|
||||
GPIO_PIN_INFO(84, "PIN_84"),
|
||||
GPIO_PIN_INFO(85, "PIN_85"),
|
||||
GPIO_PIN_INFO(86, "PIN_86"),
|
||||
GPIO_PIN_INFO(87, "PIN_87"),
|
||||
GPIO_PIN_INFO(88, "PIN_88"),
|
||||
GPIO_PIN_INFO(89, "PIN_89"),
|
||||
GPIO_PIN_INFO(90, "PIN_90"),
|
||||
GPIO_PIN_INFO(91, "PIN_91"),
|
||||
GPIO_PIN_INFO(92, "PIN_92"),
|
||||
GPIO_PIN_INFO(93, "PIN_93"),
|
||||
GPIO_PIN_INFO(95, "PIN_95"),
|
||||
GPIO_PIN_INFO(96, "PIN_96"),
|
||||
GPIO_PIN_INFO(97, "PIN_97"),
|
||||
GPIO_PIN_INFO(98, "PIN_98"),
|
||||
GPIO_PIN_INFO(99, "PIN_99"),
|
||||
GPIO_PIN_INFO(100, "PIN_100"),
|
||||
GPIO_PIN_INFO(101, "PIN_101"),
|
||||
GPIO_PIN_INFO(102, "PIN_102"),
|
||||
GPIO_PIN_INFO(113, "PIN_113"),
|
||||
GPIO_PIN_INFO(114, "PIN_114"),
|
||||
GPIO_PIN_INFO(115, "PIN_115"),
|
||||
GPIO_PIN_INFO(116, "PIN_116"),
|
||||
GPIO_PIN_INFO(117, "PIN_117"),
|
||||
GPIO_PIN_INFO(118, "PIN_118"),
|
||||
GPIO_PIN_INFO(119, "PIN_119"),
|
||||
GPIO_PIN_INFO(120, "PIN_120"),
|
||||
GPIO_PIN_INFO(121, "PIN_121"),
|
||||
GPIO_PIN_INFO(122, "PIN_122"),
|
||||
GPIO_PIN_INFO(126, "PIN_126"),
|
||||
GPIO_PIN_INFO(129, "PIN_129"),
|
||||
GPIO_PIN_INFO(130, "PIN_130"),
|
||||
GPIO_PIN_INFO(131, "PIN_131"),
|
||||
GPIO_PIN_INFO(132, "PIN_132"),
|
||||
GPIO_PIN_INFO(133, "PIN_133"),
|
||||
GPIO_PIN_INFO(135, "PIN_135"),
|
||||
GPIO_PIN_INFO(136, "PIN_136"),
|
||||
GPIO_PIN_INFO(137, "PIN_137"),
|
||||
GPIO_PIN_INFO(138, "PIN_138"),
|
||||
GPIO_PIN_INFO(139, "PIN_139"),
|
||||
GPIO_PIN_INFO(140, "PIN_140"),
|
||||
GPIO_PIN_INFO(141, "PIN_141"),
|
||||
GPIO_PIN_INFO(142, "PIN_142"),
|
||||
GPIO_PIN_INFO(143, "PIN_143"),
|
||||
GPIO_PIN_INFO(144, "PIN_144"),
|
||||
GPIO_PIN_INFO(145, "PIN_145"),
|
||||
GPIO_PIN_INFO(146, "PIN_146"),
|
||||
GPIO_PIN_INFO(147, "PIN_147"),
|
||||
GPIO_PIN_INFO(148, "PIN_148"),
|
||||
GPIO_PIN_INFO(166, "PIN_166"),
|
||||
GPIO_PIN_INFO(167, "PIN_167"),
|
||||
GPIO_PIN_INFO(168, "PIN_168"),
|
||||
GPIO_PIN_INFO(169, "PIN_169"),
|
||||
GPIO_PIN_INFO(170, "PIN_170"),
|
||||
GPIO_PIN_INFO(171, "PIN_171"),
|
||||
GPIO_PIN_INFO(172, "PIN_172"),
|
||||
GPIO_PIN_INFO(173, "PIN_173"),
|
||||
GPIO_PIN_INFO(174, "PIN_174"),
|
||||
GPIO_PIN_INFO(175, "PIN_175"),
|
||||
GPIO_PIN_INFO(176, "PIN_176"),
|
||||
GPIO_PIN_INFO(177, "PIN_177"),
|
||||
};
|
||||
|
||||
#define AMD_GPIO_PINS_EXPOSED nitems(kernzp_pins)
|
||||
|
||||
static const unsigned i2c0_pins[] = {145, 146};
|
||||
static const unsigned i2c1_pins[] = {147, 148};
|
||||
static const unsigned i2c2_pins[] = {113, 114};
|
||||
static const unsigned i2c3_pins[] = {19, 20};
|
||||
static const unsigned i2c4_pins[] = {149, 150};
|
||||
static const unsigned i2c5_pins[] = {151, 152};
|
||||
|
||||
static const unsigned uart0_pins[] = {135, 136, 137, 138, 139};
|
||||
static const unsigned uart1_pins[] = {140, 141, 142, 143, 144};
|
||||
|
||||
struct amd_pingroup {
|
||||
const char *name;
|
||||
const unsigned *pins;
|
||||
unsigned npins;
|
||||
};
|
||||
|
||||
static const struct amd_pingroup kernzp_groups[] = {
|
||||
{
|
||||
.name = "i2c0",
|
||||
.pins = i2c0_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "i2c1",
|
||||
.pins = i2c1_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "i2c2",
|
||||
.pins = i2c2_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "i2c3",
|
||||
.pins = i2c3_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "i2c4",
|
||||
.pins = i2c4_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "i2c5",
|
||||
.pins = i2c5_pins,
|
||||
.npins = 2,
|
||||
},
|
||||
{
|
||||
.name = "uart0",
|
||||
.pins = uart0_pins,
|
||||
.npins = 5,
|
||||
},
|
||||
{
|
||||
.name = "uart1",
|
||||
.pins = uart1_pins,
|
||||
.npins = 5,
|
||||
},
|
||||
};
|
||||
|
||||
/* Macros for driver mutex locking */
|
||||
#define AMDGPIO_LOCK_INIT(_sc) \
|
||||
mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
|
||||
"amdgpio", MTX_SPIN)
|
||||
#define AMDGPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
|
||||
#define AMDGPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)
|
||||
#define AMDGPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
|
||||
#define AMDGPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
|
||||
#define AMDGPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
|
||||
|
||||
struct amdgpio_softc {
|
||||
ACPI_HANDLE sc_handle;
|
||||
device_t sc_dev;
|
||||
device_t sc_busdev;
|
||||
const char* sc_bank_prefix;
|
||||
int sc_nbanks;
|
||||
int sc_npins;
|
||||
int sc_ngroups;
|
||||
struct mtx sc_mtx;
|
||||
struct resource *sc_res[AMD_GPIO_NUM_PIN_BANK + 1];
|
||||
bus_space_tag_t sc_bst;
|
||||
bus_space_handle_t sc_bsh;
|
||||
struct gpio_pin sc_gpio_pins[AMD_GPIO_PINS_MAX];
|
||||
const struct pin_info *sc_pin_info;
|
||||
const struct amd_pingroup *sc_groups;
|
||||
};
|
||||
|
||||
struct amdgpio_sysctl {
|
||||
struct amdgpio_softc *sc;
|
||||
uint32_t pin;
|
||||
};
|
|
@ -34,6 +34,7 @@ SUBDIR= \
|
|||
ale \
|
||||
alq \
|
||||
${_amd_ecc_inject} \
|
||||
${_amdgpio} \
|
||||
${_amdsbwd} \
|
||||
${_amdsmn} \
|
||||
${_amdtemp} \
|
||||
|
@ -717,6 +718,7 @@ _x86bios= x86bios
|
|||
.endif
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
_amdgpio= amdgpio
|
||||
_ccp= ccp
|
||||
_efirt= efirt
|
||||
_iavf= iavf
|
||||
|
|
8
sys/modules/amdgpio/Makefile
Normal file
8
sys/modules/amdgpio/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/amdgpio
|
||||
KMOD= amdgpio
|
||||
SRCS= amdgpio.c
|
||||
SRCS+= acpi_if.h device_if.h bus_if.h gpio_if.h pic_if.h opt_acpi.h opt_platform.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in a new issue