X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fmips%2Fpci%2Fpci-ocelot-g.c;h=34c3ec8d164587e32975422fcbcdfcd97336d01e;hb=5e3b93f248c98873cc843e83092bb8da92ac85a2;hp=239b81fba17b0257caa3e9c8245f9cccbd861a3f;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/arch/mips/pci/pci-ocelot-g.c b/arch/mips/pci/pci-ocelot-g.c index 239b81fba..34c3ec8d1 100644 --- a/arch/mips/pci/pci-ocelot-g.c +++ b/arch/mips/pci/pci-ocelot-g.c @@ -1,98 +1,460 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Copyright 2002 Momentum Computer + * Author: Matthew Dharm * - * Copyright (C) 2004 by Ralf Baechle + * 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; either version 2 of the License, or (at your + * option) any later version. * - * This doesn't really fly - but I don't have a GT64240 system for testing. + * THIS SOFTWARE IS PROVIDED ``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 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include #include -#include -#include +#include +#include +#include +#include +#include "gt64240.h" + +#include + +#define SELF 0 +#define MASTER_ABORT_BIT 0x100 /* - * We assume these address ranges have been programmed into the GT-64240 by - * the firmware. PMON in case of the Ocelot G does that. Note the size of - * the I/O range is completly stupid; I/O mappings are limited to at most - * 256 bytes by the PCI spec and deprecated; and just to make things worse - * apparently many devices don't decode more than 64k of I/O space. + * These functions and structures provide the BIOS scan and mapping of the PCI + * devices. */ -#define gt_io_size 0x20000000UL -#define gt_io_base 0xe0000000UL +void gt64240_board_pcibios_fixup_bus(struct pci_bus *c); -static struct resource gt_pci_mem0_resource = { - .name = "MV64240 PCI0 MEM", - .start = 0xc0000000UL, - .end = 0xcfffffffUL, - .flags = IORESOURCE_MEM -}; +/* Functions to implement "pci ops" */ +static int galileo_pcibios_read_config_word(int bus, int devfn, + int offset, u16 * val); +static int galileo_pcibios_read_config_byte(int bus, int devfn, + int offset, u8 * val); +static int galileo_pcibios_read_config_dword(int bus, int devfn, + int offset, u32 * val); +static int galileo_pcibios_write_config_byte(int bus, int devfn, + int offset, u8 val); +static int galileo_pcibios_write_config_word(int bus, int devfn, + int offset, u16 val); +static int galileo_pcibios_write_config_dword(int bus, int devfn, + int offset, u32 val); -static struct resource gt_pci_io_mem0_resource = { - .name = "MV64240 PCI0 IO MEM", - .start = 0xe0000000UL, - .end = 0xefffffffUL, - .flags = IORESOURCE_IO -}; +static int pci_read(struct pci_bus *bus, unsigned int devfs, int where, + int size, u32 * val); +static int pci_write(struct pci_bus *bus, unsigned int devfs, int where, + int size, u32 val); -static struct mv_pci_controller gt_bus0_controller = { - .pcic = { - .pci_ops = &mv_pci_ops, - .mem_resource = >_pci_mem0_resource, - .mem_offset = 0xc0000000UL, - .io_resource = >_pci_io_mem0_resource, - .io_offset = 0x00000000UL - }, - .config_addr = PCI_0CONFIGURATION_ADDRESS, - .config_vreg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, -}; +/* + * General-purpose PCI functions. + */ -static struct resource gt_pci_mem1_resource = { - .name = "MV64240 PCI1 MEM", - .start = 0xd0000000UL, - .end = 0xdfffffffUL, - .flags = IORESOURCE_MEM -}; -static struct resource gt_pci_io_mem1_resource = { - .name = "MV64240 PCI1 IO MEM", - .start = 0xf0000000UL, - .end = 0xffffffffUL, - .flags = IORESOURCE_IO +/* + * pci_range_ck - + * + * Check if the pci device that are trying to access does really exists + * on the evaluation board. + * + * Inputs : + * bus - bus number (0 for PCI 0 ; 1 for PCI 1) + * dev - number of device on the specific pci bus + * + * Outpus : + * 0 - if OK , 1 - if failure + */ +static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev) +{ + /* Accessing device 31 crashes the GT-64240. */ + if (dev < 5) + return 0; + return -1; +} + +/* + * galileo_pcibios_(read/write)_config_(dword/word/byte) - + * + * reads/write a dword/word/byte register from the configuration space + * of a device. + * + * Note that bus 0 and bus 1 are local, and we assume all other busses are + * bridged from bus 1. This is a safe assumption, since any other + * configuration will require major modifications to the CP7000G + * + * Inputs : + * bus - bus number + * dev - device number + * offset - register offset in the configuration space + * val - value to be written / read + * + * Outputs : + * PCIBIOS_SUCCESSFUL when operation was succesfull + * PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous + * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned + */ + +static int galileo_pcibios_read_config_dword(int bus, int devfn, + int offset, u32 * val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT); + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT); + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* read the data */ + GT_READ(data_reg, val); + + return PCIBIOS_SUCCESSFUL; +} + + +static int galileo_pcibios_read_config_word(int bus, int devfn, + int offset, u16 * val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + GT_WRITE(PCI_0ERROR_CAUSE, ~MASTER_ABORT_BIT); + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + GT_WRITE(PCI_1ERROR_CAUSE, ~MASTER_ABORT_BIT); + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* read the data */ + GT_READ_16(data_reg + (offset & 0x3), val); + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_read_config_byte(int bus, int devfn, + int offset, u8 * val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* write the data */ + GT_READ_8(data_reg + (offset & 0x3), val); + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_write_config_dword(int bus, int devfn, + int offset, u32 val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* write the data */ + GT_WRITE(data_reg, val); + + return PCIBIOS_SUCCESSFUL; +} + + +static int galileo_pcibios_write_config_word(int bus, int devfn, + int offset, u16 val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* write the data */ + GT_WRITE_16(data_reg + (offset & 0x3), val); + + return PCIBIOS_SUCCESSFUL; +} + +static int galileo_pcibios_write_config_byte(int bus, int devfn, + int offset, u8 val) +{ + int dev, func; + uint32_t address_reg, data_reg; + uint32_t address; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* verify the range */ + if (pci_range_ck(bus, dev)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* select the GT-64240 registers to communicate with the PCI bus */ + if (bus == 0) { + address_reg = PCI_0CONFIGURATION_ADDRESS; + data_reg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER; + } else { + address_reg = PCI_1CONFIGURATION_ADDRESS; + data_reg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER; + if (bus == 1) + bus = 0; + } + + address = (bus << 16) | (dev << 11) | (func << 8) | + (offset & 0xfc) | 0x80000000; + + /* start the configuration cycle */ + GT_WRITE(address_reg, address); + + /* write the data */ + GT_WRITE_8(data_reg + (offset & 0x3), val); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops galileo_pci_ops = { + .read = pci_read, + .write = pci_write }; -static struct mv_pci_controller gt_bus1_controller = { - .pcic = { - .pci_ops = &mv_pci_ops, - .mem_resource = >_pci_mem1_resource, - .mem_offset = 0xd0000000UL, - .io_resource = >_pci_io_mem1_resource, - .io_offset = 0x10000000UL - }, - .config_addr = PCI_1CONFIGURATION_ADDRESS, - .config_vreg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER, +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 * val) +{ + switch (size) { + case 1: + return galileo_pcibios_read_config_byte(bus->number, + devfn, where, + (u8 *) val); + case 2: + return galileo_pcibios_read_config_word(bus->number, + devfn, where, + (u16 *) val); + case 4: + return galileo_pcibios_read_config_dword(bus->number, + devfn, where, + (u32 *) val); + } + return PCIBIOS_FUNC_NOT_SUPPORTED; +} + +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + switch (size) { + case 1: + return galileo_pcibios_write_config_byte(bus->number, + devfn, where, + val); + case 2: + return galileo_pcibios_write_config_word(bus->number, + devfn, where, + val); + case 4: + return galileo_pcibios_write_config_dword(bus->number, + devfn, where, + val); + } + return PCIBIOS_FUNC_NOT_SUPPORTED; +} + +struct pci_fixup pcibios_fixups[] = { + {0} }; -static __init int __init ocelot_g_pci_init(void) +void __devinit pcibios_fixup_bus(struct pci_bus *c) { - unsigned long io_v_base; + gt64240_board_pcibios_fixup_bus(c); +} - if (gt_io_size) { - io_v_base = (unsigned long) ioremap(gt_io_base, gt_io_size); - if (!io_v_base) - panic("Could not ioremap I/O port range"); - set_io_port_base(io_v_base); - } +/******************************************************************** +* pci0P2PConfig - This function set the PCI_0 P2P configurate. +* For more information on the P2P read PCI spec. +* +* Inputs: unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower +* Boundry. +* unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper +* Boundry. +* unsigned int busNum - The CPI bus number to which the PCI interface +* is connected. +* unsigned int devNum - The PCI interface's device number. +* +* Returns: true. +*/ +void pci0P2PConfig(unsigned int SecondBusLow, unsigned int SecondBusHigh, + unsigned int busNum, unsigned int devNum) +{ + uint32_t regData; + + regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) | + ((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24); + GT_WRITE(PCI_0P2P_CONFIGURATION, regData); +} + +/******************************************************************** +* pci1P2PConfig - This function set the PCI_1 P2P configurate. +* For more information on the P2P read PCI spec. +* +* Inputs: unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower +* Boundry. +* unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper +* Boundry. +* unsigned int busNum - The CPI bus number to which the PCI interface +* is connected. +* unsigned int devNum - The PCI interface's device number. +* +* Returns: true. +*/ +void pci1P2PConfig(unsigned int SecondBusLow, unsigned int SecondBusHigh, + unsigned int busNum, unsigned int devNum) +{ + uint32_t regData; + + regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) | + ((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24); + GT_WRITE(PCI_1P2P_CONFIGURATION, regData); +} + +#define PCI0_STATUS_COMMAND_REG 0x4 +#define PCI1_STATUS_COMMAND_REG 0x84 + +static int __init pcibios_init(void) +{ + /* Reset PCI I/O and PCI MEM values */ + ioport_resource.start = 0xe0000000; + ioport_resource.end = 0xe0000000 + 0x20000000 - 1; + iomem_resource.start = 0xc0000000; + iomem_resource.end = 0xc0000000 + 0x20000000 - 1; - register_pci_controller(>_bus0_controller.pcic); - register_pci_controller(>_bus1_controller.pcic); + pci_scan_bus(0, &galileo_pci_ops, NULL); + pci_scan_bus(1, &galileo_pci_ops, NULL); return 0; } -arch_initcall(ocelot_g_pci_init); +subsys_initcall(pcibios_init);