summaryrefslogtreecommitdiffstats
path: root/arch/mips/mach-malta
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-07-04 17:26:05 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-07-04 17:26:05 +0200
commit45d593bc5ec78e26e3a967517ed7a51f27c8b91f (patch)
tree197cc45c686dc86b4537ce55313d5ec074671918 /arch/mips/mach-malta
parent6724928c6972842b73962dc5af70d26de9969582 (diff)
parent988ecf42691e101a35ecae83d26253e9590d14c6 (diff)
downloadbarebox-45d593bc5ec78e26e3a967517ed7a51f27c8b91f.tar.gz
barebox-45d593bc5ec78e26e3a967517ed7a51f27c8b91f.tar.xz
Merge branch 'for-next/mips'
Diffstat (limited to 'arch/mips/mach-malta')
-rw-r--r--arch/mips/mach-malta/Makefile1
-rw-r--r--arch/mips/mach-malta/include/mach/mach-gt64120.h2
-rw-r--r--arch/mips/mach-malta/pci.c236
3 files changed, 239 insertions, 0 deletions
diff --git a/arch/mips/mach-malta/Makefile b/arch/mips/mach-malta/Makefile
index f3cc6684b8..0c5a7018d4 100644
--- a/arch/mips/mach-malta/Makefile
+++ b/arch/mips/mach-malta/Makefile
@@ -1 +1,2 @@
obj-y += reset.o
+obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/mach-malta/include/mach/mach-gt64120.h b/arch/mips/mach-malta/include/mach/mach-gt64120.h
index ed1e23e9e0..8f20fcf26f 100644
--- a/arch/mips/mach-malta/include/mach/mach-gt64120.h
+++ b/arch/mips/mach-malta/include/mach/mach-gt64120.h
@@ -10,4 +10,6 @@
#define MIPS_GT_BASE 0x1be00000
+#define GT64120_BASE 0xbbe00000
+
#endif /* _ASM_MACH_MIPS_MACH_GT64120_DEP_H */
diff --git a/arch/mips/mach-malta/pci.c b/arch/mips/mach-malta/pci.c
new file mode 100644
index 0000000000..90351758e0
--- /dev/null
+++ b/arch/mips/mach-malta/pci.c
@@ -0,0 +1,236 @@
+#include <common.h>
+#include <types.h>
+#include <driver.h>
+#include <init.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#include <linux/pci.h>
+#include <asm/gt64120.h>
+
+#include <mach/mach-gt64120.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static struct resource gt64120_mem_resource = {
+ .name = "GT-64120 PCI MEM",
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource gt64120_io_resource = {
+ .name = "GT-64120 PCI I/O",
+ .flags = IORESOURCE_IO,
+};
+
+static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
+{
+ unsigned char busnum = bus->number;
+ u32 intr;
+
+ if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
+ return -1; /* Because of a bug in the galileo (for slot 31). */
+
+ /* Clear cause register bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ /* Setup address */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+ (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+ ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+ GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else
+ __GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ *data = GT_READ(GT_PCI0_CFGDATA_OFS);
+ } else
+ *data = __GT_READ(GT_PCI0_CFGDATA_OFS);
+ }
+
+ /* Check for master or target abort */
+ intr = GT_READ(GT_INTRCAUSE_OFS);
+
+ if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+ /* Error occurred */
+
+ /* Clear bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+
+ if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+ where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4)
+ data = val;
+ else {
+ if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus,
+ devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn,
+ where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* function returns memory address for begin of pci resource */
+static int gt64xxx_res_start(struct pci_bus *bus, resource_size_t res_addr)
+{
+ return KSEG0ADDR(res_addr);
+}
+
+struct pci_ops gt64xxx_pci0_ops = {
+ .read = gt64xxx_pci0_pcibios_read,
+ .write = gt64xxx_pci0_pcibios_write,
+
+ .res_start = gt64xxx_res_start,
+};
+
+static struct pci_controller gt64120_controller = {
+ .pci_ops = &gt64xxx_pci0_ops,
+ .io_resource = &gt64120_io_resource,
+ .mem_resource = &gt64120_mem_resource,
+};
+
+static int pcibios_init(void)
+{
+ resource_size_t start, end, map, start1, end1, map1, mask, res_end;
+
+ /*
+ * Due to a bug in the Galileo system controller, we need
+ * to setup the PCI BAR for the Galileo internal registers.
+ * This should be done in the bios/bootprom and will be
+ * fixed in a later revision of YAMON (the MIPS boards
+ * boot prom).
+ */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
+ (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
+ (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
+ ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
+ GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+ /* Perform the write */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
+
+ /* Here is linux code. It assumes, that firmware
+ (pbl in case of barebox) made the work... */
+
+ /* Set up resource ranges from the controller's registers. */
+ start = GT_READ(GT_PCI0M0LD_OFS);
+ end = GT_READ(GT_PCI0M0HD_OFS);
+ map = GT_READ(GT_PCI0M0REMAP_OFS);
+ end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+ start1 = GT_READ(GT_PCI0M1LD_OFS);
+ end1 = GT_READ(GT_PCI0M1HD_OFS);
+ map1 = GT_READ(GT_PCI0M1REMAP_OFS);
+ end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
+
+ mask = ~(start ^ end);
+
+ /* We don't support remapping with a discontiguous mask. */
+ BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+ mask != ~((mask & -mask) - 1));
+ gt64120_mem_resource.start = start;
+ gt64120_mem_resource.end = end;
+ gt64120_controller.mem_offset = (start & mask) - (map & mask);
+ /* Addresses are 36-bit, so do shifts in the destinations. */
+ gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
+ gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
+ gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+ gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
+
+ start = GT_READ(GT_PCI0IOLD_OFS);
+ end = GT_READ(GT_PCI0IOHD_OFS);
+ map = GT_READ(GT_PCI0IOREMAP_OFS);
+ end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+ mask = ~(start ^ end);
+
+ /* We don't support remapping with a discontiguous mask. */
+ BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+ mask != ~((mask & -mask) - 1));
+ gt64120_io_resource.start = map & mask;
+ res_end = (map & mask) | ~mask;
+ gt64120_controller.io_offset = 0;
+ /* Addresses are 36-bit, so do shifts in the destinations. */
+ gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
+ gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
+ gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+ GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
+ GT_PCI0_CMD_SBYTESWAP_BIT);
+#else
+ GT_WRITE(GT_PCI0_CMD_OFS, 0);
+#endif
+
+ /* Fix up PCI I/O mapping if necessary (for Atlas). */
+ start = GT_READ(GT_PCI0IOLD_OFS);
+ map = GT_READ(GT_PCI0IOREMAP_OFS);
+ if ((start & map) != 0) {
+ map &= ~start;
+ GT_WRITE(GT_PCI0IOREMAP_OFS, map);
+ }
+
+ register_pci_controller(&gt64120_controller);
+
+ return 0;
+}
+postcore_initcall(pcibios_init);