coreboot-v2/src/devices/pnp_device.c
<<
>>
Prefs
   1/*
   2 * This file is part of the coreboot project.
   3 *
   4 * Copyright (C) 2004 Linux Networx
   5 * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
   6 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
   7 * Copyright (C) 2005 Tyan
   8 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; version 2 of the License.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  22 */
  23
  24#include <console/console.h>
  25#include <stdlib.h>
  26#include <stdint.h>
  27#include <bitops.h>
  28#include <string.h>
  29#include <arch/io.h>
  30#include <device/device.h>
  31#include <device/pnp.h>
  32
  33/* PNP fundamental operations */
  34
  35void pnp_write_config(device_t dev, uint8_t reg, uint8_t value)
  36{
  37        outb(reg, dev->path.pnp.port);
  38        outb(value, dev->path.pnp.port + 1);
  39}
  40
  41uint8_t pnp_read_config(device_t dev, uint8_t reg)
  42{
  43        outb(reg, dev->path.pnp.port);
  44        return inb(dev->path.pnp.port + 1);
  45}
  46
  47void pnp_set_logical_device(device_t dev)
  48{
  49        pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
  50}
  51
  52void pnp_set_enable(device_t dev, int enable)
  53{
  54        uint8_t tmp, bitpos;
  55
  56        tmp = pnp_read_config(dev, 0x30);
  57        /* handle the virtual devices, which share same LDN register */
  58        bitpos = (dev->path.pnp.device >> 8) & 0x7;
  59
  60        if (enable) {
  61                tmp |= (1 << bitpos);
  62        } else {
  63                tmp &= ~(1 << bitpos);
  64        }
  65        pnp_write_config(dev, 0x30, tmp);
  66}
  67
  68int pnp_read_enable(device_t dev)
  69{
  70        uint8_t tmp, bitpos;
  71        tmp = pnp_read_config(dev, 0x30);
  72        /* handle the virtual devices, which share same LDN register */
  73        bitpos = (dev->path.pnp.device >> 8) & 0x7;
  74        return !!(tmp & (1 << bitpos));
  75}
  76
  77void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
  78{
  79        /* Index == 0x60 or 0x62 */
  80        pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
  81        pnp_write_config(dev, index + 1, iobase & 0xff);
  82}
  83
  84void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
  85{
  86        /* Index == 0x70 or 0x72 */
  87        pnp_write_config(dev, index, irq);
  88}
  89
  90void pnp_set_drq(device_t dev, unsigned index, unsigned drq)
  91{
  92        /* Index == 0x74 */
  93        pnp_write_config(dev, index, drq & 0xff);
  94}
  95
  96/* PNP device operations */
  97
  98void pnp_read_resources(device_t dev)
  99{
 100        return;
 101}
 102
 103static void pnp_set_resource(device_t dev, struct resource *resource)
 104{
 105        if (!(resource->flags & IORESOURCE_ASSIGNED)) {
 106                printk_err("ERROR: %s %02lx %s size: 0x%010Lx not assigned\n",
 107                        dev_path(dev), resource->index,
 108                        resource_type(resource),
 109                        resource->size);
 110                return;
 111        }
 112
 113        /* Now store the resource */
 114        if (resource->flags & IORESOURCE_IO) {
 115                pnp_set_iobase(dev, resource->index, resource->base);
 116        }
 117        else if (resource->flags & IORESOURCE_DRQ) {
 118                pnp_set_drq(dev, resource->index, resource->base);
 119        }
 120        else if (resource->flags  & IORESOURCE_IRQ) {
 121                pnp_set_irq(dev, resource->index, resource->base);
 122        }
 123        else {
 124                printk_err("ERROR: %s %02lx unknown resource type\n",
 125                        dev_path(dev), resource->index);
 126                return;
 127        }
 128        resource->flags |= IORESOURCE_STORED;
 129
 130        report_resource_stored(dev, resource, "");
 131}
 132
 133void pnp_set_resources(device_t dev)
 134{
 135        int i;
 136
 137        /* Select the device */
 138        pnp_set_logical_device(dev);
 139
 140        /* Paranoia says I should disable the device here... */
 141        for(i = 0; i < dev->resources; i++) {
 142                pnp_set_resource(dev, &dev->resource[i]);
 143        }
 144}
 145
 146void pnp_enable_resources(device_t dev)
 147{
 148        pnp_set_logical_device(dev);
 149        pnp_set_enable(dev, 1);
 150}
 151
 152void pnp_enable(device_t dev)
 153{
 154        if (!dev->enabled) {
 155                pnp_set_logical_device(dev);
 156                pnp_set_enable(dev, 0);
 157        }
 158}
 159
 160struct device_operations pnp_ops = {
 161        .read_resources   = pnp_read_resources,
 162        .set_resources    = pnp_set_resources,
 163        .enable_resources = pnp_enable_resources,
 164        .enable           = pnp_enable,
 165};
 166
 167/* PNP chip opertations */
 168
 169static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info)
 170{
 171        struct resource *resource;
 172        unsigned moving, gran, step;
 173
 174        resource = new_resource(dev, index);
 175        
 176        /* Initilize the resource */
 177        resource->limit = 0xffff;
 178        resource->flags |= IORESOURCE_IO;
 179        
 180        /* Get the resource size */
 181        moving = info->mask;
 182        gran = 15;
 183        step = 1 << gran;
 184        /* Find the first bit that moves */
 185        while((moving & step) == 0) {
 186                gran--;
 187                step >>= 1;
 188        }
 189        /* Now find the first bit that does not move */
 190        while((moving & step) != 0) {
 191                gran--;
 192                step >>= 1;
 193        }
 194        /* Of the moving bits the last bit in the first group,
 195         * tells us the size of this resource.
 196         */
 197        if ((moving & step) == 0) {
 198                gran++;
 199                step <<= 1;
 200        }
 201        /* Set the resource size and alignment */
 202        resource->gran  = gran;
 203        resource->align = gran;
 204        resource->limit = info->mask | (step - 1);
 205        resource->size  = 1 << gran;
 206}
 207
 208static void get_resources(device_t dev, struct pnp_info *info)
 209{
 210        struct resource *resource;
 211
 212        if (info->flags & PNP_IO0) {
 213                pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0);
 214        }
 215        if (info->flags & PNP_IO1) {
 216                pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1);
 217        }
 218        if (info->flags & PNP_IO2) {
 219                pnp_get_ioresource(dev, PNP_IDX_IO2, &info->io2);
 220        }
 221        if (info->flags & PNP_IO3) {
 222                pnp_get_ioresource(dev, PNP_IDX_IO3, &info->io3);
 223        }
 224        if (info->flags & PNP_IRQ0) {
 225                resource = new_resource(dev, PNP_IDX_IRQ0);
 226                resource->size = 1;
 227                resource->flags |= IORESOURCE_IRQ;
 228        }
 229        if (info->flags & PNP_IRQ1) {
 230                resource = new_resource(dev, PNP_IDX_IRQ1);
 231                resource->size = 1;
 232                resource->flags |= IORESOURCE_IRQ;
 233        }
 234        if (info->flags & PNP_DRQ0) {
 235                resource = new_resource(dev, PNP_IDX_DRQ0);
 236                resource->size = 1;
 237                resource->flags |= IORESOURCE_DRQ;
 238        }
 239        if (info->flags & PNP_DRQ1) {
 240                resource = new_resource(dev, PNP_IDX_DRQ1);
 241                resource->size = 1;
 242                resource->flags |= IORESOURCE_DRQ;
 243        }       
 244} 
 245
 246void pnp_enable_devices(device_t base_dev, struct device_operations *ops, 
 247        unsigned functions, struct pnp_info *info)
 248{
 249        struct device_path path;
 250        device_t dev;
 251        int i;
 252
 253        path.type       = DEVICE_PATH_PNP;
 254        path.pnp.port = base_dev->path.pnp.port;
 255        
 256        /* Setup the ops and resources on the newly allocated devices */
 257        for(i = 0; i < functions; i++) {
 258                /* Skip logical devices this Super I/O doesn't have. */
 259                if (info[i].function == -1)
 260                        continue;
 261
 262                path.pnp.device = info[i].function;
 263                dev = alloc_find_dev(base_dev->bus, &path);
 264                
 265                /* Don't initialize a device multiple times */
 266                if (dev->ops) 
 267                        continue;
 268
 269                if (info[i].ops == 0) {
 270                        dev->ops = ops;
 271                } else {
 272                        dev->ops = info[i].ops;
 273                }
 274                get_resources(dev, &info[i]);
 275        }
 276}
 277
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.