summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Smith <mgsmith@netgate.com>2015-11-18 10:33:01 -0600
committerMatt Smith <mgsmith@netgate.com>2015-11-18 10:33:01 -0600
commit2b4a207180f37dd6236d8ddab734d82d71dace07 (patch)
tree5f74a28f7b2babcd211e7782b99a7c9e92bb04cc
parent2c38246068447251e458dcad64ebd4cb17ce63ee (diff)
downloadFreeBSD-src-2b4a207180f37dd6236d8ddab734d82d71dace07.zip
FreeBSD-src-2b4a207180f37dd6236d8ddab734d82d71dace07.tar.gz
Importing pfSense patch gpioapu.tgz
-rw-r--r--sys/dev/gpioapu/gpioapu.c336
-rw-r--r--sys/modules/gpioapu/Makefile7
2 files changed, 343 insertions, 0 deletions
diff --git a/sys/dev/gpioapu/gpioapu.c b/sys/dev/gpioapu/gpioapu.c
new file mode 100644
index 0000000..11e5e13
--- /dev/null
+++ b/sys/dev/gpioapu/gpioapu.c
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 2013 Ermal Luci <eri@FreeBSD.org>
+ * 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>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/priv.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+
+#include <dev/pci/pcivar.h>
+#include <isa/isavar.h>
+
+/* SB7xx RRG 2.3.3.1.1. */
+#define AMDSB_PMIO_INDEX 0xcd6
+#define AMDSB_PMIO_DATA (PMIO_INDEX + 1)
+#define AMDSB_PMIO_WIDTH 2
+
+#define AMDSB_SMBUS_DEVID 0x43851002
+#define AMDSB8_SMBUS_REVID 0x40
+
+#define IOMUX_OFFSET 0xD00
+#define GPIO_SPACE_OFFSET 0x100
+#define GPIO_SPACE_SIZE 0x100
+/* SB8xx RRG 2.3.3. */
+#define AMDSB8_PM_WDT_EN 0x24
+
+#define GPIO_187 187 // MODESW
+#define GPIO_189 189 // LED1#
+#define GPIO_190 190 // LED2#
+#define GPIO_191 191 // LED3#
+#define GPIO_OUTPUT 0x08
+#define GPIO_INPUT 0x28
+
+struct gpioapu_softc {
+ device_t dev;
+ struct cdev *cdev;
+ struct resource *res_ctrl;
+ struct resource *res_count;
+ int rid_ctrl;
+ int rid_count;
+};
+
+static int gpioapu_open(struct cdev *dev, int flags, int fmt,
+ struct thread *td);
+static int gpioapu_close(struct cdev *dev, int flags, int fmt,
+ struct thread *td);
+static int gpioapu_write(struct cdev *dev, struct uio *uio, int ioflag);
+static int gpioapu_read(struct cdev *dev, struct uio *uio, int ioflag);
+
+static struct cdevsw gpioapu_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = gpioapu_open,
+ .d_read = gpioapu_read,
+ .d_write = gpioapu_write,
+ .d_close = gpioapu_close,
+ .d_name = "gpioapu",
+};
+
+static void gpioapu_identify(driver_t *driver, device_t parent);
+static int gpioapu_probe(device_t dev);
+static int gpioapu_attach(device_t dev);
+static int gpioapu_detach(device_t dev);
+
+static device_method_t gpioapu_methods[] = {
+ DEVMETHOD(device_identify, gpioapu_identify),
+ DEVMETHOD(device_probe, gpioapu_probe),
+ DEVMETHOD(device_attach, gpioapu_attach),
+ DEVMETHOD(device_detach, gpioapu_detach),
+ {0, 0}
+};
+
+static devclass_t gpioapu_devclass;
+
+static driver_t gpioapu_driver = {
+ "gpioapu",
+ gpioapu_methods,
+ sizeof(struct gpioapu_softc)
+};
+
+DRIVER_MODULE(gpioapu, isa, gpioapu_driver, gpioapu_devclass, NULL, NULL);
+
+
+static uint8_t
+pmio_read(struct resource *res, uint8_t reg)
+{
+ bus_write_1(res, 0, reg); /* Index */
+ return (bus_read_1(res, 1)); /* Data */
+}
+
+#if 0
+static void
+pmio_write(struct resource *res, uint8_t reg, uint8_t val)
+{
+ bus_write_1(res, 0, reg); /* Index */
+ bus_write_1(res, 1, val); /* Data */
+}
+#endif
+
+/* ARGSUSED */
+static int
+gpioapu_open(struct cdev *dev __unused, int flags __unused, int fmt __unused,
+ struct thread *td)
+{
+ int error;
+
+ error = priv_check(td, PRIV_IO);
+ if (error != 0)
+ return (error);
+ error = securelevel_gt(td->td_ucred, 0);
+ if (error != 0)
+ return (error);
+
+ return (error);
+}
+
+static int
+gpioapu_read(struct cdev *dev, struct uio *uio, int ioflag) {
+ struct gpioapu_softc *sc = dev->si_drv1;
+ uint8_t tmp;
+ char ch;
+ int error;
+
+ tmp = bus_read_1(sc->res_ctrl, GPIO_187);
+#ifdef DEBUG
+ device_printf(sc->dev, "returned %x\n", (u_int)tmp);
+#endif
+ if (tmp & 0x80)
+ ch = '1';
+ else
+ ch = '0';
+
+ error = uiomove(&ch, sizeof(ch), uio);
+
+ return (error);
+}
+static int
+gpioapu_write(struct cdev *dev, struct uio *uio, int ioflag) {
+ struct gpioapu_softc *sc = dev->si_drv1;
+ char ch[3];
+ uint8_t old;
+ int error, i, start;
+
+ error = uiomove(ch, sizeof(ch), uio);
+ if (error)
+ return (error);
+
+ start = GPIO_189;
+ for (i = 0; i < 3; i++) {
+ old = bus_read_1(sc->res_ctrl, start + i);
+#ifdef DEBUG
+ device_printf(sc->dev, "returned %x - %c\n", (u_int)old, ch[i]);
+#endif
+ if (ch[i] == '1')
+ old &= 0x80;
+ else
+ old = 0xc8;
+ bus_write_1(sc->res_ctrl, start + i, old);
+ }
+
+ return (error);
+}
+
+static int
+gpioapu_close(struct cdev *dev __unused, int flags __unused, int fmt __unused,
+ struct thread *td)
+{
+ struct gpioapu_softc *sc = dev->si_drv1;
+ int i, start;
+
+ start = GPIO_187;
+ for (i = 0; i < 2; i++) {
+ bus_write_1(sc->res_ctrl, start, 0xc8);
+ }
+
+ return (0);
+}
+
+static void
+gpioapu_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+ device_t smb_dev;
+
+ if (resource_disabled("gpioapu", 0))
+ return;
+
+
+ if (device_find_child(parent, "gpioapu", -1) != NULL)
+ return;
+
+ /*
+ * Try to identify SB600/SB7xx by PCI Device ID of SMBus device
+ * that should be present at bus 0, device 20, function 0.
+ */
+ smb_dev = pci_find_bsf(0, 20, 0);
+ if (smb_dev == NULL)
+ return;
+
+ if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID)
+ return;
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "gpioapu", -1);
+ if (child == NULL)
+ device_printf(parent, "add gpioapu child failed\n");
+}
+
+static int
+gpioapu_probe(device_t dev)
+{
+ struct resource *res;
+ uint32_t addr;
+ int rid;
+ int rc, i;
+ char *value;
+
+ value = getenv("smbios.system.product");
+ device_printf(dev, "Environment returned %s\n", value);
+ if (value == NULL || strncmp(value, "APU", strlen("APU")))
+ return (ENXIO);
+
+ /* Do not claim some ISA PnP device by accident. */
+ if (isa_get_logicalid(dev) != 0)
+ return (ENXIO);
+
+ rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
+ AMDSB_PMIO_WIDTH);
+ if (rc != 0) {
+ device_printf(dev, "bus_set_resource for IO failed\n");
+ return (ENXIO);
+ }
+ rid = 0;
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul,
+ AMDSB_PMIO_WIDTH, RF_ACTIVE | RF_SHAREABLE);
+ if (res == NULL) {
+ device_printf(dev, "bus_alloc_resource for IO failed\n");
+ return (ENXIO);
+ }
+
+ /* Find base address of memory mapped WDT registers. */
+ for (addr = 0, i = 0; i < 4; i++) {
+ addr <<= 8;
+ addr |= pmio_read(res, AMDSB8_PM_WDT_EN + 3 - i);
+ }
+ addr &= 0xFFFFF000;
+ device_printf(dev, "Address on reg 0x24 is 0x%x/%u\n", addr, addr);
+
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
+ bus_delete_resource(dev, SYS_RES_IOPORT, rid);
+
+ rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + GPIO_SPACE_OFFSET,
+ GPIO_SPACE_SIZE);
+ if (rc != 0) {
+ device_printf(dev, "bus_set_resource for memory failed\n");
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+gpioapu_attach(device_t dev)
+{
+ struct gpioapu_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->rid_ctrl = 0;
+
+ sc->res_ctrl = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid_ctrl, 0ul, ~0ul,
+ GPIO_SPACE_SIZE, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->res_ctrl == NULL) {
+ device_printf(dev, "bus_alloc_resource for memory failed\n");
+ return (ENXIO);
+ }
+
+ sc->dev = dev;
+ sc->cdev = make_dev(&gpioapu_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, "gpioapu");
+
+ sc->cdev->si_drv1 = sc;
+
+ return (0);
+
+}
+
+static int
+gpioapu_detach(device_t dev)
+{
+ struct gpioapu_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->res_ctrl != NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl,
+ sc->res_ctrl);
+ bus_delete_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl);
+ }
+
+ destroy_dev(sc->cdev);
+
+ return (0);
+}
diff --git a/sys/modules/gpioapu/Makefile b/sys/modules/gpioapu/Makefile
new file mode 100644
index 0000000..80fdd2c
--- /dev/null
+++ b/sys/modules/gpioapu/Makefile
@@ -0,0 +1,7 @@
+
+.PATH: ${.CURDIR}/../../dev/gpioapu
+KMOD = gpioapu
+SRCS = gpioapu.c
+SRCS += device_if.h bus_if.h pci_if.h isa_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud