summaryrefslogtreecommitdiff
path: root/src/superio
diff options
context:
space:
mode:
Diffstat (limited to 'src/superio')
-rw-r--r--src/superio/winbond/w83627thf/Config.lb2
-rw-r--r--src/superio/winbond/w83627thf/chip.h21
-rw-r--r--src/superio/winbond/w83627thf/superio.c324
3 files changed, 347 insertions, 0 deletions
diff --git a/src/superio/winbond/w83627thf/Config.lb b/src/superio/winbond/w83627thf/Config.lb
new file mode 100644
index 0000000000..f62a567d61
--- /dev/null
+++ b/src/superio/winbond/w83627thf/Config.lb
@@ -0,0 +1,2 @@
+config chip.h
+object superio.o
diff --git a/src/superio/winbond/w83627thf/chip.h b/src/superio/winbond/w83627thf/chip.h
new file mode 100644
index 0000000000..4dee9d80a7
--- /dev/null
+++ b/src/superio/winbond/w83627thf/chip.h
@@ -0,0 +1,21 @@
+#ifndef PNP_INDEX_REG
+#define PNP_INDEX_REG 0x15C
+#endif
+#ifndef PNP_DATA_REG
+#define PNP_DATA_REG 0x15D
+#endif
+#ifndef SIO_COM1
+#define SIO_COM1_BASE 0x3F8
+#endif
+#ifndef SIO_COM2
+#define SIO_COM2_BASE 0x2F8
+#endif
+
+extern struct chip_control superio_winbond_w83627thf_control;
+
+struct superio_winbond_w83627thf_config {
+ struct com_ports com1, com2;
+
+ struct lpt_ports lpt;
+ int port;
+};
diff --git a/src/superio/winbond/w83627thf/superio.c b/src/superio/winbond/w83627thf/superio.c
new file mode 100644
index 0000000000..e3e9382c15
--- /dev/null
+++ b/src/superio/winbond/w83627thf/superio.c
@@ -0,0 +1,324 @@
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/chip.h>
+#include <console/console.h>
+#include <string.h>
+#include <bitops.h>
+#include "chip.h"
+
+void pnp_output(char address, char data)
+{
+ outb(address, PNP_INDEX_REG);
+ outb(data, PNP_DATA_REG);
+}
+
+static void sio_enable(struct chip *chip, enum chip_pass pass)
+{
+
+ struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
+
+ switch (pass) {
+ case CONF_PASS_PRE_CONSOLE:
+ /* Enable Super IO Chip */
+ pnp_output(0x07, 6); /* LD 6 = UART1 */
+ pnp_output(0x30, 0); /* Dectivate */
+ pnp_output(0x60, conf->port >> 8); /* IO Base */
+ pnp_output(0x61, conf->port & 0xFF); /* IO Base */
+ pnp_output(0x30, 1); /* Activate */
+ break;
+ default:
+ /* nothing yet */
+ break;
+ }
+}
+
+static void pnp_write_config(device_t dev, unsigned char value, unsigned char reg)
+{
+ outb(reg, dev->path.u.pnp.port);
+ outb(value, dev->path.u.pnp.port + 1);
+}
+
+static unsigned char pnp_read_config(device_t dev, unsigned char reg)
+{
+ outb(reg, dev->path.u.pnp.port);
+ return inb(dev->path.u.pnp.port + 1);
+}
+
+static void pnp_set_logical_device(device_t dev)
+{
+ pnp_write_config(dev, dev->path.u.pnp.device, 0x07);
+}
+
+static void pnp_set_enable(device_t dev, int enable)
+{
+ pnp_write_config(dev, enable?0x1:0x0, 0x30);
+}
+
+static int pnp_read_enable(device_t dev)
+{
+ return !!pnp_read_config(dev, 0x30);
+}
+
+#define FLOPPY_DEVICE 0
+#define PARALLEL_DEVICE 1
+#define COM2_DEVICE 2
+#define COM1_DEVICE 3
+#define SWC_DEVICE 4
+#define MOUSE_DEVICE 5
+#define KBC_DEVICE 6
+#define GPIO_DEVICE 7
+#define ACB_DEVICE 8
+#define FSCM_DEVICE 9
+#define WDT_DEVICE 10
+
+struct io_info {
+ unsigned mask, set;
+};
+struct pnp_info {
+ unsigned flags;
+#define PNP_IO0 0x01
+#define PNP_IO1 0x02
+#define PNP_IRQ0 0x04
+#define PNP_IRQ1 0x08
+#define PNP_DRQ0 0x10
+#define PNP_DRQ1 0x20
+ struct io_info io0, io1;
+};
+
+static struct pnp_info pnp_dev_info[] = {
+ [ 0] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, },
+ [ 1] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, },
+ [ 2] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, },
+ [ 3] = { PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
+ [ 4] = { PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, },
+ [ 5] = { PNP_IRQ0 },
+ [ 6] = { PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, },
+ [ 7] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ [ 8] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ [ 9] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
+ [10] = { PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } },
+};
+
+static struct resource *get_resource(device_t dev, unsigned index)
+{
+ struct resource *resource;
+ int i;
+ resource = 0;
+ for(i = 0; i < dev->resources; i++) {
+ resource = &dev->resource[i];
+ if (resource->index == index) {
+ break;
+ }
+ }
+ if (!resource || (resource->index != index)) {
+ resource = &dev->resource[dev->resources];
+ memset(resource, 0, sizeof(*resource));
+ dev->resources++;
+ }
+ /* Initialize the resource values */
+ if (!(resource->flags & IORESOURCE_FIXED)) {
+ resource->flags = 0;
+ resource->base = 0;
+ }
+ resource->size = 0;
+ resource->limit = 0;
+ resource->flags = 0;
+ resource->index = index;
+ resource->align = 0;
+ resource->gran = 0;
+
+ return resource;
+}
+
+static void pnp_read_ioresource(device_t dev, unsigned index, struct io_info *info)
+{
+ struct resource *resource;
+ uint32_t size;
+ resource = get_resource(dev, index);
+
+ /* Initilize the resource */
+ resource->limit = 0xffff;
+ resource->flags |= IORESOURCE_IO;
+
+ /* Set the resource size and alignment */
+ size = (0xffff & info->mask);
+ resource->size = (~(size | 0xfffff800) + 1);
+ resource->align = log2(resource->size);
+ resource->gran = resource->align;
+}
+
+
+static void pnp_read_resources(device_t dev)
+{
+ struct pnp_info *info;
+ struct resource *resource;
+ pnp_set_logical_device(dev);
+
+ info = &pnp_dev_info[dev->path.u.pnp.device];
+
+ if (info->flags & PNP_IO0) {
+ pnp_read_ioresource(dev, 0x60, &info->io0);
+ }
+ if (info->flags & PNP_IO1) {
+ pnp_read_ioresource(dev, 0x62, &info->io1);
+ }
+ if (info->flags & PNP_IRQ0) {
+ resource = get_resource(dev, 0x70);
+ resource->size = 1;
+ resource->flags |= IORESOURCE_IRQ;
+ }
+ if (info->flags & PNP_IRQ1) {
+ resource = get_resource(dev, 0x72);
+ resource->size = 1;
+ resource->flags |= IORESOURCE_IRQ;
+ }
+ if (info->flags & PNP_DRQ0) {
+ resource = get_resource(dev, 0x74);
+ resource->size = 1;
+ resource->flags |= IORESOURCE_DRQ;
+ }
+ if (info->flags & PNP_DRQ1) {
+ resource = get_resource(dev, 0x75);
+ resource->size = 1;
+ resource->flags |= IORESOURCE_DRQ;
+ }
+}
+
+static void pnp_set_iobase(device_t dev, unsigned iobase, unsigned index)
+{
+ /* Index == 0x60 or 0x62 */
+ pnp_write_config(dev, (iobase >> 8) & 0xff, index);
+ pnp_write_config(dev, iobase & 0xff, index + 1);
+}
+
+static void pnp_set_irq(device_t dev, unsigned irq, unsigned index)
+{
+ /* Index == 0x70 or 0x72 */
+ pnp_write_config(dev, irq, index);
+}
+
+static void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
+{
+ /* Index == 0x74 */
+ pnp_write_config(dev, drq & 0xff, index);
+}
+
+
+static void pnp_set_resource(device_t dev, struct resource *resource)
+{
+ if (!(resource->flags & IORESOURCE_SET)) {
+#if 1
+ printk_err("ERROR: %s %02x not allocated\n",
+ dev_path(dev), resource->index);
+#endif
+ return;
+ }
+ if (resource->flags & IORESOURCE_IO) {
+ pnp_set_iobase(dev, resource->base, resource->index);
+ }
+ else if (resource->flags & IORESOURCE_DRQ) {
+ pnp_set_drq(dev, resource->base, resource->index);
+ }
+ else if (resource->flags & IORESOURCE_IRQ) {
+ pnp_set_irq(dev, resource->base, resource->index);
+ }
+ else {
+ printk_err("ERROR: %s %02x unknown resource type\n",
+ dev_path(dev), resource->index);
+ return;
+ }
+ printk_debug(
+ "%s %02x <- [0x%08lx - 0x%08lx %s\n",
+ dev_path(dev),
+ resource->index,
+ resource->base, resource->base + resource->size - 1,
+ (resource->flags & IORESOURCE_IO)? "io":
+ (resource->flags & IORESOURCE_DRQ)? "drq":
+ (resource->flags & IORESOURCE_IRQ)? "irq":
+ (resource->flags & IORESOURCE_MEM)? "mem":
+ "???");
+}
+
+static void pnp_set_resources(device_t dev)
+{
+ int i;
+ pnp_set_logical_device(dev);
+ for(i = 0; i < dev->resources; i++) {
+ pnp_set_resource(dev, &dev->resource[i]);
+ }
+
+}
+static void pnp_enable_resources(device_t dev)
+{
+ pnp_set_logical_device(dev);
+ pnp_set_enable(dev, 1);
+
+}
+static void pnp_enable(device_t dev)
+{
+ pnp_set_logical_device(dev);
+ if (!dev->enable) {
+ pnp_set_enable(dev, 0);
+ }
+}
+
+static struct device_operations pnp_ops = {
+ .read_resources = pnp_read_resources,
+ .set_resources = pnp_set_resources,
+ .enable_resources = pnp_enable_resources,
+ .enable = pnp_enable,
+};
+
+#define MAX_FUNCTION 10
+static void enumerate(struct chip *chip)
+{
+ struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
+ struct resource *resource;
+ struct device_path path;
+ device_t dev;
+ int i;
+
+ chip_enumerate(chip);
+ path.type = DEVICE_PATH_PNP;
+ path.u.pnp.port = chip->dev->path.u.pnp.port;
+
+ /* Set the ops on the newly allocated devices */
+ for(i = 0; i <= WDT_DEVICE; i++) {
+ path.u.pnp.device = i;
+ dev = alloc_find_dev(chip->bus, &path);
+ dev->ops = &pnp_ops;
+ }
+
+ /* Processes the hard codes for com1 */
+ path.u.pnp.device = COM1_DEVICE;
+ dev = alloc_find_dev(chip->bus, &path);
+ resource = get_resource(dev, 0x60);
+ if (conf->com1.base) {
+ resource->base = conf->com1.base;
+ resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
+ }
+ resource = get_resource(dev, 0x70);
+ if (conf->com1.irq) {
+ resource->base = conf->com1.irq;
+ resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET;
+ }
+
+ /* Process the hard codes for the keyboard controller */
+ path.u.pnp.device = KBC_DEVICE;
+ dev = alloc_find_dev(dev, &path);
+ resource = get_resource(dev, 0x60);
+ resource->base = 0x60;
+ resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
+ resource = get_resource(dev, 0x62);
+ resource->base = 0x64;
+ resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
+}
+
+struct chip_control superio_NSC_pc87360_control = {
+ .enable = sio_enable,
+ .enumerate = enumerate,
+ .name = "winbond w83627thf";
+};