/* * This file is part of the coreboot project. * * Copyright (C) 2005 Linux Networx * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx) * Copyright (C) 2005 Ronald G. Minnich <rminnich@gmail.com> * * 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 <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> #include <device/cardbus.h> /* * I don't think this code is quite correct but it is close. * Anyone with a cardbus bridge and a little time should be able * to make it usable quickly. -- Eric Biederman 24 March 2005 */ /* * IO should be max 256 bytes. However, since we may have a P2P bridge below * a cardbus bridge, we need 4K. */ #define CARDBUS_IO_SIZE 4096 #define CARDBUS_MEM_SIZE (32 * 1024 * 1024) static void cardbus_record_bridge_resource(device_t dev, resource_t moving, resource_t min_size, unsigned int index, unsigned long type) { struct resource *resource; unsigned long gran; resource_t step; /* Initialize the constraints on the current bus. */ resource = NULL; if (!moving) return; resource = new_resource(dev, index); resource->size = 0; gran = 0; step = 1; while ((moving & step) == 0) { gran += 1; step <<= 1; } resource->gran = gran; resource->align = gran; resource->limit = moving | (step - 1); resource->flags = type; /* Don't let the minimum size exceed what we can put in the resource. */ if ((min_size - 1) > resource->limit) min_size = resource->limit + 1; resource->size = min_size; } static void cardbus_size_bridge_resource(device_t dev, unsigned int index) { struct resource *resource; resource_t min_size; resource = find_resource(dev, index); if (resource) { min_size = resource->size; /* * Always allocate at least the miniumum size to a * cardbus bridge in case a new card is plugged in. */ if (resource->size < min_size) resource->size = min_size; } } void cardbus_read_resources(device_t dev) { resource_t moving_base, moving_limit, moving; unsigned long type; u16 ctl; /* See if needs a card control registers base address. */ pci_get_resource(dev, PCI_BASE_ADDRESS_0); compact_resources(dev); /* See which bridge I/O resources are implemented. */ moving_base = pci_moving_config32(dev, PCI_CB_IO_BASE_0); moving_limit = pci_moving_config32(dev, PCI_CB_IO_LIMIT_0); moving = moving_base & moving_limit; /* Initialize the I/O space constraints on the current bus. */ cardbus_record_bridge_resource(dev, moving, CARDBUS_IO_SIZE, PCI_CB_IO_BASE_0, IORESOURCE_IO); cardbus_size_bridge_resource(dev, PCI_CB_IO_BASE_0); /* See which bridge I/O resources are implemented. */ moving_base = pci_moving_config32(dev, PCI_CB_IO_BASE_1); moving_limit = pci_moving_config32(dev, PCI_CB_IO_LIMIT_1); moving = moving_base & moving_limit; /* Initialize the I/O space constraints on the current bus. */ cardbus_record_bridge_resource(dev, moving, CARDBUS_IO_SIZE, PCI_CB_IO_BASE_1, IORESOURCE_IO); /* If I can, enable prefetch for mem0. */ ctl = pci_read_config16(dev, PCI_CB_BRIDGE_CONTROL); ctl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; ctl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; ctl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; pci_write_config16(dev, PCI_CB_BRIDGE_CONTROL, ctl); ctl = pci_read_config16(dev, PCI_CB_BRIDGE_CONTROL); /* See which bridge memory resources are implemented. */ moving_base = pci_moving_config32(dev, PCI_CB_MEMORY_BASE_0); moving_limit = pci_moving_config32(dev, PCI_CB_MEMORY_LIMIT_0); moving = moving_base & moving_limit; /* Initialize the memory space constraints on the current bus. */ type = IORESOURCE_MEM; if (ctl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) type |= IORESOURCE_PREFETCH; cardbus_record_bridge_resource(dev, moving, CARDBUS_MEM_SIZE, PCI_CB_MEMORY_BASE_0, type); if (type & IORESOURCE_PREFETCH) cardbus_size_bridge_resource(dev, PCI_CB_MEMORY_BASE_0); /* See which bridge memory resources are implemented. */ moving_base = pci_moving_config32(dev, PCI_CB_MEMORY_BASE_1); moving_limit = pci_moving_config32(dev, PCI_CB_MEMORY_LIMIT_1); moving = moving_base & moving_limit; /* Initialize the memory space constraints on the current bus. */ cardbus_record_bridge_resource(dev, moving, CARDBUS_MEM_SIZE, PCI_CB_MEMORY_BASE_1, IORESOURCE_MEM); cardbus_size_bridge_resource(dev, PCI_CB_MEMORY_BASE_1); compact_resources(dev); } void cardbus_enable_resources(device_t dev) { u16 ctrl; ctrl = pci_read_config16(dev, PCI_CB_BRIDGE_CONTROL); ctrl |= (dev->link_list->bridge_ctrl & ( PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA | PCI_BRIDGE_CTL_VGA | PCI_BRIDGE_CTL_MASTER_ABORT | PCI_BRIDGE_CTL_BUS_RESET)); /* Error check */ ctrl |= (PCI_CB_BRIDGE_CTL_PARITY + PCI_CB_BRIDGE_CTL_SERR); printk(BIOS_DEBUG, "%s bridge ctrl <- %04x\n", dev_path(dev), ctrl); pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); pci_dev_enable_resources(dev); } struct device_operations default_cardbus_ops_bus = { .read_resources = cardbus_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = cardbus_enable_resources, .init = 0, .scan_bus = pci_scan_bridge, .enable = 0, .reset_bus = pci_bus_reset, };