Path: blob/master/arch/microblaze/pci/indirect_pci.c
10817 views
/*1* Support for indirect PCI bridges.2*3* Copyright (C) 1998 Gabriel Paubert.4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*/1011#include <linux/kernel.h>12#include <linux/pci.h>13#include <linux/delay.h>14#include <linux/string.h>15#include <linux/init.h>1617#include <asm/io.h>18#include <asm/prom.h>19#include <asm/pci-bridge.h>2021static int22indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,23int len, u32 *val)24{25struct pci_controller *hose = pci_bus_to_host(bus);26volatile void __iomem *cfg_data;27u8 cfg_type = 0;28u32 bus_no, reg;2930if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {31if (bus->number != hose->first_busno)32return PCIBIOS_DEVICE_NOT_FOUND;33if (devfn != 0)34return PCIBIOS_DEVICE_NOT_FOUND;35}3637if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)38if (bus->number != hose->first_busno)39cfg_type = 1;4041bus_no = (bus->number == hose->first_busno) ?42hose->self_busno : bus->number;4344if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)45reg = ((offset & 0xf00) << 16) | (offset & 0xfc);46else47reg = offset & 0xfc; /* Only 3 bits for function */4849if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)50out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |51(devfn << 8) | reg | cfg_type));52else53out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |54(devfn << 8) | reg | cfg_type));5556/*57* Note: the caller has already checked that offset is58* suitably aligned and that len is 1, 2 or 4.59*/60cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */61switch (len) {62case 1:63*val = in_8(cfg_data);64break;65case 2:66*val = in_le16(cfg_data);67break;68default:69*val = in_le32(cfg_data);70break;71}72return PCIBIOS_SUCCESSFUL;73}7475static int76indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,77int len, u32 val)78{79struct pci_controller *hose = pci_bus_to_host(bus);80volatile void __iomem *cfg_data;81u8 cfg_type = 0;82u32 bus_no, reg;8384if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {85if (bus->number != hose->first_busno)86return PCIBIOS_DEVICE_NOT_FOUND;87if (devfn != 0)88return PCIBIOS_DEVICE_NOT_FOUND;89}9091if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)92if (bus->number != hose->first_busno)93cfg_type = 1;9495bus_no = (bus->number == hose->first_busno) ?96hose->self_busno : bus->number;9798if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)99reg = ((offset & 0xf00) << 16) | (offset & 0xfc);100else101reg = offset & 0xfc;102103if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)104out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |105(devfn << 8) | reg | cfg_type));106else107out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |108(devfn << 8) | reg | cfg_type));109110/* suppress setting of PCI_PRIMARY_BUS */111if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)112if ((offset == PCI_PRIMARY_BUS) &&113(bus->number == hose->first_busno))114val &= 0xffffff00;115116/* Workaround for PCI_28 Errata in 440EPx/GRx */117if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) &&118offset == PCI_CACHE_LINE_SIZE) {119val = 0;120}121122/*123* Note: the caller has already checked that offset is124* suitably aligned and that len is 1, 2 or 4.125*/126cfg_data = hose->cfg_data + (offset & 3);127switch (len) {128case 1:129out_8(cfg_data, val);130break;131case 2:132out_le16(cfg_data, val);133break;134default:135out_le32(cfg_data, val);136break;137}138139return PCIBIOS_SUCCESSFUL;140}141142static struct pci_ops indirect_pci_ops = {143.read = indirect_read_config,144.write = indirect_write_config,145};146147void __init148setup_indirect_pci(struct pci_controller *hose,149resource_size_t cfg_addr,150resource_size_t cfg_data, u32 flags)151{152resource_size_t base = cfg_addr & PAGE_MASK;153void __iomem *mbase;154155mbase = ioremap(base, PAGE_SIZE);156hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);157if ((cfg_data & PAGE_MASK) != base)158mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);159hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);160hose->ops = &indirect_pci_ops;161hose->indirect_type = flags;162}163164165