summaryrefslogtreecommitdiffstats
path: root/arch/mips/pmc-sierra/yosemite/ht.c
diff options
context:
space:
mode:
authorAnton Arapov <anton@redhat.com>2012-04-16 10:05:28 +0200
committerAnton Arapov <anton@redhat.com>2012-04-16 10:05:28 +0200
commitb4b6116a13633898cf868f2f103c96a90c4c20f8 (patch)
tree93d1b7e2cfcdf473d8d4ff3ad141fa864f8491f6 /arch/mips/pmc-sierra/yosemite/ht.c
parentedd4be777c953e5faafc80d091d3084b4343f5d3 (diff)
downloadkernel-uprobes-b4b6116a13633898cf868f2f103c96a90c4c20f8.tar.gz
kernel-uprobes-b4b6116a13633898cf868f2f103c96a90c4c20f8.tar.xz
kernel-uprobes-b4b6116a13633898cf868f2f103c96a90c4c20f8.zip
fedora kernel: d9aad82f3319f3cfd1aebc01234254ef0c37ad84v3.3.2-1
Signed-off-by: Anton Arapov <anton@redhat.com>
Diffstat (limited to 'arch/mips/pmc-sierra/yosemite/ht.c')
-rw-r--r--arch/mips/pmc-sierra/yosemite/ht.c415
1 files changed, 415 insertions, 0 deletions
diff --git a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c
new file mode 100644
index 00000000000..63be40e470d
--- /dev/null
+++ b/arch/mips/pmc-sierra/yosemite/ht.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2003 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+
+#include <linux/init.h>
+#include <asm/titan_dep.h>
+
+#ifdef CONFIG_HYPERTRANSPORT
+
+
+/*
+ * This function check if the Hypertransport Link Initialization completed. If
+ * it did, then proceed further with scanning bus #2
+ */
+static __inline__ int check_titan_htlink(void)
+{
+ u32 val;
+
+ val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG);
+ if (val & 0x00000020)
+ /* HT Link Initialization completed */
+ return 1;
+ else
+ return 0;
+}
+
+static int titan_ht_config_read_dword(struct pci_dev *device,
+ int offset, u32* val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ RM9K_WRITE(address_reg, address);
+ RM9K_READ(data_reg, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int titan_ht_config_read_word(struct pci_dev *device,
+ int offset, u16* val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ if ((offset & 0x3) == 0)
+ offset = 0x2;
+ else
+ offset = 0x0;
+
+ RM9K_WRITE(address_reg, address);
+ RM9K_READ_16(data_reg + offset, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+u32 longswap(unsigned long l)
+{
+ unsigned char b1, b2, b3, b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((b1<<24) + (b2<<16) + (b3<<8) + b4);
+}
+
+
+static int titan_ht_config_read_byte(struct pci_dev *device,
+ int offset, u8* val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+ int offset1;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ RM9K_WRITE(address_reg, address);
+
+ if ((offset & 0x3) == 0) {
+ offset1 = 0x3;
+ }
+ if ((offset & 0x3) == 1) {
+ offset1 = 0x2;
+ }
+ if ((offset & 0x3) == 2) {
+ offset1 = 0x1;
+ }
+ if ((offset & 0x3) == 3) {
+ offset1 = 0x0;
+ }
+ RM9K_READ_8(data_reg + offset1, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int titan_ht_config_write_dword(struct pci_dev *device,
+ int offset, u8 val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ RM9K_WRITE(address_reg, address);
+ RM9K_WRITE(data_reg, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int titan_ht_config_write_word(struct pci_dev *device,
+ int offset, u8 val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ if ((offset & 0x3) == 0)
+ offset = 0x2;
+ else
+ offset = 0x0;
+
+ RM9K_WRITE(address_reg, address);
+ RM9K_WRITE_16(data_reg + offset, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int titan_ht_config_write_byte(struct pci_dev *device,
+ int offset, u8 val)
+{
+ int dev, bus, func;
+ uint32_t address_reg, data_reg;
+ uint32_t address;
+ int offset1;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+ func = PCI_FUNC(device->devfn);
+
+ /* XXX Need to change the Bus # */
+ if (bus > 2)
+ address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
+ 0x80000000 | 0x1;
+ else
+ address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
+
+ address_reg = RM9000x2_OCD_HTCFGA;
+ data_reg = RM9000x2_OCD_HTCFGD;
+
+ RM9K_WRITE(address_reg, address);
+
+ if ((offset & 0x3) == 0) {
+ offset1 = 0x3;
+ }
+ if ((offset & 0x3) == 1) {
+ offset1 = 0x2;
+ }
+ if ((offset & 0x3) == 2) {
+ offset1 = 0x1;
+ }
+ if ((offset & 0x3) == 3) {
+ offset1 = 0x0;
+ }
+
+ RM9K_WRITE_8(data_reg + offset1, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static void titan_pcibios_set_master(struct pci_dev *dev)
+{
+ u16 cmd;
+ int bus = dev->bus->number;
+
+ if (check_titan_htlink())
+ titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
+
+ cmd |= PCI_COMMAND_MASTER;
+
+ if (check_titan_htlink())
+ titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
+}
+
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ u8 tmp1;
+ int idx;
+ struct resource *r;
+ int bus = dev->bus->number;
+
+ if (check_titan_htlink())
+ titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
+
+ old_cmd = cmd;
+ for (idx = 0; idx < 6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR
+ "PCI: Device %s not available because of "
+ "resource collisions\n", pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ if (check_titan_htlink())
+ titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
+ }
+
+ if (check_titan_htlink())
+ titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
+
+ if (tmp1 != 8) {
+ printk(KERN_WARNING "PCI setting cache line size to 8 from "
+ "%d\n", tmp1);
+ }
+
+ if (check_titan_htlink())
+ titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+
+ if (check_titan_htlink())
+ titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1);
+
+ if (tmp1 < 32 || tmp1 == 0xff) {
+ printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
+ tmp1);
+ }
+
+ if (check_titan_htlink())
+ titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32);
+
+ return 0;
+}
+
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ return pcibios_enable_resources(dev);
+}
+
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ resource_size_t size, resource_size_t align)
+{
+ struct pci_dev *dev = data;
+ resource_size_t start = res->start;
+
+ if (res->flags & IORESOURCE_IO) {
+ /* We need to avoid collisions with `mirrored' VGA ports
+ and other strange ISA hardware, so we always want the
+ addresses kilobyte aligned. */
+ if (size > 0x100) {
+ printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+ " (%ld bytes)\n", pci_name(dev),
+ dev->resource - res, size);
+ }
+
+ start = (start + 1024 - 1) & ~(1024 - 1);
+ }
+
+ return start;
+}
+
+struct pci_ops titan_pci_ops = {
+ titan_ht_config_read_byte,
+ titan_ht_config_read_word,
+ titan_ht_config_read_dword,
+ titan_ht_config_write_byte,
+ titan_ht_config_write_word,
+ titan_ht_config_write_dword
+};
+
+void __init pcibios_fixup_bus(struct pci_bus *c)
+{
+ titan_ht_pcibios_fixup_bus(c);
+}
+
+void __init pcibios_init(void)
+{
+
+ /* Reset PCI I/O and PCI MEM values */
+ /* XXX Need to add the proper values here */
+ ioport_resource.start = 0xe0000000;
+ ioport_resource.end = 0xe0000000 + 0x20000000 - 1;
+ iomem_resource.start = 0xc0000000;
+ iomem_resource.end = 0xc0000000 + 0x20000000 - 1;
+
+ /* XXX Need to add bus values */
+ pci_scan_bus(2, &titan_pci_ops, NULL);
+ pci_scan_bus(3, &titan_pci_ops, NULL);
+}
+
+/*
+ * for parsing "pci=" kernel boot arguments.
+ */
+char *pcibios_setup(char *str)
+{
+ printk(KERN_INFO "rr: pcibios_setup\n");
+ /* Nothing to do for now. */
+
+ return str;
+}
+
+unsigned __init int pcibios_assign_all_busses(void)
+{
+ /* We want to use the PCI bus detection done by PMON */
+ return 0;
+}
+
+#endif /* CONFIG_HYPERTRANSPORT */