|
@@ -501,3 +501,174 @@ build_conf_addr(struct pci_controller *hose, u8 bus,
|
|
|
return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
|
|
|
}
|
|
|
|
|
|
+static unsigned long
|
|
|
+mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where)
|
|
|
+{
|
|
|
+ struct pci_controller *hose = pbus->sysdata;
|
|
|
+ struct io7_port *io7_port;
|
|
|
+ unsigned long addr = 0;
|
|
|
+ u8 bus = pbus->number;
|
|
|
+
|
|
|
+ if (!hose)
|
|
|
+ return addr;
|
|
|
+
|
|
|
+ /* Check for enabled. */
|
|
|
+ io7_port = hose->sysdata;
|
|
|
+ if (!io7_port->enabled)
|
|
|
+ return addr;
|
|
|
+
|
|
|
+ if (!pbus->parent) { /* No parent means peer PCI bus. */
|
|
|
+ /* Don't support idsel > 20 on primary bus. */
|
|
|
+ if (devfn >= PCI_DEVFN(21, 0))
|
|
|
+ return addr;
|
|
|
+ bus = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ addr = build_conf_addr(hose, bus, devfn, where);
|
|
|
+
|
|
|
+ DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
|
|
|
+ return addr;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+marvel_read_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
|
+ int size, u32 *value)
|
|
|
+{
|
|
|
+ unsigned long addr;
|
|
|
+
|
|
|
+ if (0 == (addr = mk_conf_addr(bus, devfn, where)))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ switch(size) {
|
|
|
+ case 1:
|
|
|
+ *value = __kernel_ldbu(*(vucp)addr);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ *value = __kernel_ldwu(*(vusp)addr);
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ *value = *(vuip)addr;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+marvel_write_config(struct pci_bus *bus, unsigned int devfn, int where,
|
|
|
+ int size, u32 value)
|
|
|
+{
|
|
|
+ unsigned long addr;
|
|
|
+
|
|
|
+ if (0 == (addr = mk_conf_addr(bus, devfn, where)))
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ switch (size) {
|
|
|
+ case 1:
|
|
|
+ __kernel_stb(value, *(vucp)addr);
|
|
|
+ mb();
|
|
|
+ __kernel_ldbu(*(vucp)addr);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ __kernel_stw(value, *(vusp)addr);
|
|
|
+ mb();
|
|
|
+ __kernel_ldwu(*(vusp)addr);
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ *(vuip)addr = value;
|
|
|
+ mb();
|
|
|
+ *(vuip)addr;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
+struct pci_ops marvel_pci_ops =
|
|
|
+{
|
|
|
+ .read = marvel_read_config,
|
|
|
+ .write = marvel_write_config,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Other PCI helper functions.
|
|
|
+ */
|
|
|
+void
|
|
|
+marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
|
|
|
+{
|
|
|
+ io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
|
|
|
+
|
|
|
+ wmb();
|
|
|
+ csrs->POx_SG_TBIA.csr = 0;
|
|
|
+ mb();
|
|
|
+ csrs->POx_SG_TBIA.csr;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * RTC Support
|
|
|
+ */
|
|
|
+struct marvel_rtc_access_info {
|
|
|
+ unsigned long function;
|
|
|
+ unsigned long index;
|
|
|
+ unsigned long data;
|
|
|
+};
|
|
|
+
|
|
|
+static void
|
|
|
+__marvel_access_rtc(void *info)
|
|
|
+{
|
|
|
+ struct marvel_rtc_access_info *rtc_access = info;
|
|
|
+
|
|
|
+ register unsigned long __r0 __asm__("$0");
|
|
|
+ register unsigned long __r16 __asm__("$16") = rtc_access->function;
|
|
|
+ register unsigned long __r17 __asm__("$17") = rtc_access->index;
|
|
|
+ register unsigned long __r18 __asm__("$18") = rtc_access->data;
|
|
|
+
|
|
|
+ __asm__ __volatile__(
|
|
|
+ "call_pal %4 # cserve rtc"
|
|
|
+ : "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
|
|
|
+ : "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
|
|
|
+ : "$1", "$22", "$23", "$24", "$25");
|
|
|
+
|
|
|
+ rtc_access->data = __r0;
|
|
|
+}
|
|
|
+
|
|
|
+static u8
|
|
|
+__marvel_rtc_io(u8 b, unsigned long addr, int write)
|
|
|
+{
|
|
|
+ static u8 index = 0;
|
|
|
+
|
|
|
+ struct marvel_rtc_access_info rtc_access;
|
|
|
+ u8 ret = 0;
|
|
|
+
|
|
|
+ switch(addr) {
|
|
|
+ case 0x70: /* RTC_PORT(0) */
|
|
|
+ if (write) index = b;
|
|
|
+ ret = index;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 0x71: /* RTC_PORT(1) */
|
|
|
+ rtc_access.index = index;
|
|
|
+ rtc_access.data = bcd2bin(b);
|
|
|
+ rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
|
|
|
+
|
|
|
+ __marvel_access_rtc(&rtc_access);
|
|
|
+
|
|
|
+ ret = bin2bcd(rtc_access.data);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|