diff options
author | Stefan Reinauer <reinauer@chromium.org> | 2012-11-30 12:34:04 -0800 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2012-11-30 23:59:58 +0100 |
commit | 8d7115560d469f901d7d8ccb242d0b437e7394aa (patch) | |
tree | 0f1b4bd63c48a233c49d5a9ca15f08a1675d1ff4 /src/device/pnp_device.c | |
parent | 4b6be985aae8bff84ae442e7be7669e93694fa1e (diff) |
Rename devices -> device
to match src/include/device
Change-Id: I5d0e5b4361c34881a3b81347aac48738cb5b9af0
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/1960
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Diffstat (limited to 'src/device/pnp_device.c')
-rw-r--r-- | src/device/pnp_device.c | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/src/device/pnp_device.c b/src/device/pnp_device.c new file mode 100644 index 0000000000..19b492db78 --- /dev/null +++ b/src/device/pnp_device.c @@ -0,0 +1,304 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2004 Linux Networx + * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx) + * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov> + * Copyright (C) 2005 Tyan + * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pnp.h> + +/* PNP fundamental operations */ + +void pnp_write_config(device_t dev, u8 reg, u8 value) +{ + outb(reg, dev->path.pnp.port); + outb(value, dev->path.pnp.port + 1); +} + +u8 pnp_read_config(device_t dev, u8 reg) +{ + outb(reg, dev->path.pnp.port); + return inb(dev->path.pnp.port + 1); +} + +void pnp_set_logical_device(device_t dev) +{ + pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff); +} + +void pnp_set_enable(device_t dev, int enable) +{ + u8 tmp, bitpos; + + tmp = pnp_read_config(dev, 0x30); + + /* Handle virtual devices, which share the same LDN register. */ + bitpos = (dev->path.pnp.device >> 8) & 0x7; + + if (enable) + tmp |= (1 << bitpos); + else + tmp &= ~(1 << bitpos); + + pnp_write_config(dev, 0x30, tmp); +} + +int pnp_read_enable(device_t dev) +{ + u8 tmp, bitpos; + + tmp = pnp_read_config(dev, 0x30); + + /* Handle virtual devices, which share the same LDN register. */ + bitpos = (dev->path.pnp.device >> 8) & 0x7; + + return !!(tmp & (1 << bitpos)); +} + +void pnp_set_iobase(device_t dev, u8 index, u16 iobase) +{ + /* Index == 0x60 or 0x62. */ + pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff); + pnp_write_config(dev, index + 1, iobase & 0xff); +} + +void pnp_set_irq(device_t dev, u8 index, u8 irq) +{ + /* Index == 0x70 or 0x72. */ + pnp_write_config(dev, index, irq); +} + +void pnp_set_drq(device_t dev, u8 index, u8 drq) +{ + /* Index == 0x74. */ + pnp_write_config(dev, index, drq & 0xff); +} + +/* PNP device operations */ + +void pnp_read_resources(device_t dev) +{ + return; +} + +static void pnp_set_resource(device_t dev, struct resource *resource) +{ + if (!(resource->flags & IORESOURCE_ASSIGNED)) { + printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx " + "not assigned\n", dev_path(dev), resource->index, + resource_type(resource), resource->size); + return; + } + + /* Now store the resource. */ + if (resource->flags & IORESOURCE_IO) { + pnp_set_iobase(dev, resource->index, resource->base); + } else if (resource->flags & IORESOURCE_DRQ) { + pnp_set_drq(dev, resource->index, resource->base); + } else if (resource->flags & IORESOURCE_IRQ) { + pnp_set_irq(dev, resource->index, resource->base); + } else { + printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n", + dev_path(dev), resource->index); + return; + } + resource->flags |= IORESOURCE_STORED; + + report_resource_stored(dev, resource, ""); +} + +void pnp_set_resources(device_t dev) +{ + struct resource *res; + + /* Select the logical device (LDN). */ + pnp_set_logical_device(dev); + + /* Paranoia says I should disable the device here... */ + for (res = dev->resource_list; res; res = res->next) + pnp_set_resource(dev, res); +} + +void pnp_enable_resources(device_t dev) +{ + pnp_set_logical_device(dev); + pnp_set_enable(dev, 1); +} + +void pnp_enable(device_t dev) +{ + if (!dev->enabled) { + pnp_set_logical_device(dev); + pnp_set_enable(dev, 0); + } +} + +struct device_operations pnp_ops = { + .read_resources = pnp_read_resources, + .set_resources = pnp_set_resources, + .enable_resources = pnp_enable_resources, + .enable = pnp_enable, +}; + +/* PNP chip operations */ + +static void pnp_get_ioresource(device_t dev, u8 index, struct io_info *info) +{ + struct resource *resource; + unsigned moving, gran, step; + + if (!info->mask) { + printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n", + dev_path(dev), index); + return; + } + + resource = new_resource(dev, index); + + /* Initilize the resource. */ + resource->limit = 0xffff; + resource->flags |= IORESOURCE_IO; + + /* Get the resource size... */ + + moving = info->mask; + gran = 15; + step = 1 << gran; + + /* Find the first bit that moves. */ + while ((moving & step) == 0) { + gran--; + step >>= 1; + } + + /* Now find the first bit that does not move. */ + while ((moving & step) != 0) { + gran--; + step >>= 1; + } + + /* + * Of the moving bits the last bit in the first group, + * tells us the size of this resource. + */ + if ((moving & step) == 0) { + gran++; + step <<= 1; + } + + /* Set the resource size and alignment. */ + resource->gran = gran; + resource->align = gran; + resource->limit = info->mask | (step - 1); + resource->size = 1 << gran; +} + +static void get_resources(device_t dev, struct pnp_info *info) +{ + struct resource *resource; + + if (info->flags & PNP_IO0) + pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0); + if (info->flags & PNP_IO1) + pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1); + if (info->flags & PNP_IO2) + pnp_get_ioresource(dev, PNP_IDX_IO2, &info->io2); + if (info->flags & PNP_IO3) + pnp_get_ioresource(dev, PNP_IDX_IO3, &info->io3); + + if (info->flags & PNP_IRQ0) { + resource = new_resource(dev, PNP_IDX_IRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_IRQ1) { + resource = new_resource(dev, PNP_IDX_IRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + + if (info->flags & PNP_DRQ0) { + resource = new_resource(dev, PNP_IDX_DRQ0); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + if (info->flags & PNP_DRQ1) { + resource = new_resource(dev, PNP_IDX_DRQ1); + resource->size = 1; + resource->flags |= IORESOURCE_DRQ; + } + + /* + * These are not IRQs, but set the flag to have the + * resource allocator do the right thing. + */ + if (info->flags & PNP_EN) { + resource = new_resource(dev, PNP_IDX_EN); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_MSC0) { + resource = new_resource(dev, PNP_IDX_MSC0); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } + if (info->flags & PNP_MSC1) { + resource = new_resource(dev, PNP_IDX_MSC1); + resource->size = 1; + resource->flags |= IORESOURCE_IRQ; + } +} + +void pnp_enable_devices(device_t base_dev, struct device_operations *ops, + unsigned int functions, struct pnp_info *info) +{ + struct device_path path; + device_t dev; + int i; + + path.type = DEVICE_PATH_PNP; + path.pnp.port = base_dev->path.pnp.port; + + /* Setup the ops and resources on the newly allocated devices. */ + for (i = 0; i < functions; i++) { + /* Skip logical devices this Super I/O doesn't have. */ + if (info[i].function == -1) + continue; + + path.pnp.device = info[i].function; + dev = alloc_find_dev(base_dev->bus, &path); + + /* Don't initialize a device multiple times. */ + if (dev->ops) + continue; + + if (info[i].ops == 0) + dev->ops = ops; + else + dev->ops = info[i].ops; + + get_resources(dev, &info[i]); + } +} |