Path: blob/master/arch/mips/pmc-sierra/yosemite/ht.c
15118 views
/*1* Copyright 2003 PMC-Sierra2* Author: Manish Lachwani ([email protected])3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License as published by the6* Free Software Foundation; either version 2 of the License, or (at your7* option) any later version.8*9* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED10* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN12* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,13* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT14* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF15* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON16* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT17* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF18* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.19*20* You should have received a copy of the GNU General Public License along21* with this program; if not, write to the Free Software Foundation, Inc.,22* 675 Mass Ave, Cambridge, MA 02139, USA.23*/2425#include <linux/types.h>26#include <linux/pci.h>27#include <linux/kernel.h>28#include <asm/pci.h>29#include <asm/io.h>3031#include <linux/init.h>32#include <asm/titan_dep.h>3334#ifdef CONFIG_HYPERTRANSPORT353637/*38* This function check if the Hypertransport Link Initialization completed. If39* it did, then proceed further with scanning bus #240*/41static __inline__ int check_titan_htlink(void)42{43u32 val;4445val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG);46if (val & 0x00000020)47/* HT Link Initialization completed */48return 1;49else50return 0;51}5253static int titan_ht_config_read_dword(struct pci_dev *device,54int offset, u32* val)55{56int dev, bus, func;57uint32_t address_reg, data_reg;58uint32_t address;5960bus = device->bus->number;61dev = PCI_SLOT(device->devfn);62func = PCI_FUNC(device->devfn);6364/* XXX Need to change the Bus # */65if (bus > 2)66address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |670x80000000 | 0x1;68else69address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;7071address_reg = RM9000x2_OCD_HTCFGA;72data_reg = RM9000x2_OCD_HTCFGD;7374RM9K_WRITE(address_reg, address);75RM9K_READ(data_reg, val);7677return PCIBIOS_SUCCESSFUL;78}798081static int titan_ht_config_read_word(struct pci_dev *device,82int offset, u16* val)83{84int dev, bus, func;85uint32_t address_reg, data_reg;86uint32_t address;8788bus = device->bus->number;89dev = PCI_SLOT(device->devfn);90func = PCI_FUNC(device->devfn);9192/* XXX Need to change the Bus # */93if (bus > 2)94address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |950x80000000 | 0x1;96else97address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;9899address_reg = RM9000x2_OCD_HTCFGA;100data_reg = RM9000x2_OCD_HTCFGD;101102if ((offset & 0x3) == 0)103offset = 0x2;104else105offset = 0x0;106107RM9K_WRITE(address_reg, address);108RM9K_READ_16(data_reg + offset, val);109110return PCIBIOS_SUCCESSFUL;111}112113114u32 longswap(unsigned long l)115{116unsigned char b1, b2, b3, b4;117118b1 = l&255;119b2 = (l>>8)&255;120b3 = (l>>16)&255;121b4 = (l>>24)&255;122123return ((b1<<24) + (b2<<16) + (b3<<8) + b4);124}125126127static int titan_ht_config_read_byte(struct pci_dev *device,128int offset, u8* val)129{130int dev, bus, func;131uint32_t address_reg, data_reg;132uint32_t address;133int offset1;134135bus = device->bus->number;136dev = PCI_SLOT(device->devfn);137func = PCI_FUNC(device->devfn);138139/* XXX Need to change the Bus # */140if (bus > 2)141address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |1420x80000000 | 0x1;143else144address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;145146address_reg = RM9000x2_OCD_HTCFGA;147data_reg = RM9000x2_OCD_HTCFGD;148149RM9K_WRITE(address_reg, address);150151if ((offset & 0x3) == 0) {152offset1 = 0x3;153}154if ((offset & 0x3) == 1) {155offset1 = 0x2;156}157if ((offset & 0x3) == 2) {158offset1 = 0x1;159}160if ((offset & 0x3) == 3) {161offset1 = 0x0;162}163RM9K_READ_8(data_reg + offset1, val);164165return PCIBIOS_SUCCESSFUL;166}167168169static int titan_ht_config_write_dword(struct pci_dev *device,170int offset, u8 val)171{172int dev, bus, func;173uint32_t address_reg, data_reg;174uint32_t address;175176bus = device->bus->number;177dev = PCI_SLOT(device->devfn);178func = PCI_FUNC(device->devfn);179180/* XXX Need to change the Bus # */181if (bus > 2)182address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |1830x80000000 | 0x1;184else185address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;186187address_reg = RM9000x2_OCD_HTCFGA;188data_reg = RM9000x2_OCD_HTCFGD;189190RM9K_WRITE(address_reg, address);191RM9K_WRITE(data_reg, val);192193return PCIBIOS_SUCCESSFUL;194}195196static int titan_ht_config_write_word(struct pci_dev *device,197int offset, u8 val)198{199int dev, bus, func;200uint32_t address_reg, data_reg;201uint32_t address;202203bus = device->bus->number;204dev = PCI_SLOT(device->devfn);205func = PCI_FUNC(device->devfn);206207/* XXX Need to change the Bus # */208if (bus > 2)209address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |2100x80000000 | 0x1;211else212address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;213214address_reg = RM9000x2_OCD_HTCFGA;215data_reg = RM9000x2_OCD_HTCFGD;216217if ((offset & 0x3) == 0)218offset = 0x2;219else220offset = 0x0;221222RM9K_WRITE(address_reg, address);223RM9K_WRITE_16(data_reg + offset, val);224225return PCIBIOS_SUCCESSFUL;226}227228static int titan_ht_config_write_byte(struct pci_dev *device,229int offset, u8 val)230{231int dev, bus, func;232uint32_t address_reg, data_reg;233uint32_t address;234int offset1;235236bus = device->bus->number;237dev = PCI_SLOT(device->devfn);238func = PCI_FUNC(device->devfn);239240/* XXX Need to change the Bus # */241if (bus > 2)242address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |2430x80000000 | 0x1;244else245address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;246247address_reg = RM9000x2_OCD_HTCFGA;248data_reg = RM9000x2_OCD_HTCFGD;249250RM9K_WRITE(address_reg, address);251252if ((offset & 0x3) == 0) {253offset1 = 0x3;254}255if ((offset & 0x3) == 1) {256offset1 = 0x2;257}258if ((offset & 0x3) == 2) {259offset1 = 0x1;260}261if ((offset & 0x3) == 3) {262offset1 = 0x0;263}264265RM9K_WRITE_8(data_reg + offset1, val);266return PCIBIOS_SUCCESSFUL;267}268269270static void titan_pcibios_set_master(struct pci_dev *dev)271{272u16 cmd;273int bus = dev->bus->number;274275if (check_titan_htlink())276titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);277278cmd |= PCI_COMMAND_MASTER;279280if (check_titan_htlink())281titan_ht_config_write_word(dev, PCI_COMMAND, cmd);282}283284285int pcibios_enable_resources(struct pci_dev *dev)286{287u16 cmd, old_cmd;288u8 tmp1;289int idx;290struct resource *r;291int bus = dev->bus->number;292293if (check_titan_htlink())294titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);295296old_cmd = cmd;297for (idx = 0; idx < 6; idx++) {298r = &dev->resource[idx];299if (!r->start && r->end) {300printk(KERN_ERR301"PCI: Device %s not available because of "302"resource collisions\n", pci_name(dev));303return -EINVAL;304}305if (r->flags & IORESOURCE_IO)306cmd |= PCI_COMMAND_IO;307if (r->flags & IORESOURCE_MEM)308cmd |= PCI_COMMAND_MEMORY;309}310if (cmd != old_cmd) {311if (check_titan_htlink())312titan_ht_config_write_word(dev, PCI_COMMAND, cmd);313}314315if (check_titan_htlink())316titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);317318if (tmp1 != 8) {319printk(KERN_WARNING "PCI setting cache line size to 8 from "320"%d\n", tmp1);321}322323if (check_titan_htlink())324titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8);325326if (check_titan_htlink())327titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1);328329if (tmp1 < 32 || tmp1 == 0xff) {330printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",331tmp1);332}333334if (check_titan_htlink())335titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32);336337return 0;338}339340341int pcibios_enable_device(struct pci_dev *dev, int mask)342{343return pcibios_enable_resources(dev);344}345346resource_size_t pcibios_align_resource(void *data, const struct resource *res,347resource_size_t size, resource_size_t align)348{349struct pci_dev *dev = data;350resource_size_t start = res->start;351352if (res->flags & IORESOURCE_IO) {353/* We need to avoid collisions with `mirrored' VGA ports354and other strange ISA hardware, so we always want the355addresses kilobyte aligned. */356if (size > 0x100) {357printk(KERN_ERR "PCI: I/O Region %s/%d too large"358" (%ld bytes)\n", pci_name(dev),359dev->resource - res, size);360}361362start = (start + 1024 - 1) & ~(1024 - 1);363}364365return start;366}367368struct pci_ops titan_pci_ops = {369titan_ht_config_read_byte,370titan_ht_config_read_word,371titan_ht_config_read_dword,372titan_ht_config_write_byte,373titan_ht_config_write_word,374titan_ht_config_write_dword375};376377void __init pcibios_fixup_bus(struct pci_bus *c)378{379titan_ht_pcibios_fixup_bus(c);380}381382void __init pcibios_init(void)383{384385/* Reset PCI I/O and PCI MEM values */386/* XXX Need to add the proper values here */387ioport_resource.start = 0xe0000000;388ioport_resource.end = 0xe0000000 + 0x20000000 - 1;389iomem_resource.start = 0xc0000000;390iomem_resource.end = 0xc0000000 + 0x20000000 - 1;391392/* XXX Need to add bus values */393pci_scan_bus(2, &titan_pci_ops, NULL);394pci_scan_bus(3, &titan_pci_ops, NULL);395}396397/*398* for parsing "pci=" kernel boot arguments.399*/400char *pcibios_setup(char *str)401{402printk(KERN_INFO "rr: pcibios_setup\n");403/* Nothing to do for now. */404405return str;406}407408unsigned __init int pcibios_assign_all_busses(void)409{410/* We want to use the PCI bus detection done by PMON */411return 0;412}413414#endif /* CONFIG_HYPERTRANSPORT */415416417