| /* |
| * multiverse.c |
| * |
| * VME driver for Multiverse |
| * |
| * Author : Sangmoon Kim |
| * dogoil@etinsys.com |
| * |
| * Copyright 2005 ETIN SYSTEMS Co.,Ltd. |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <asm/io.h> |
| #include <pci.h> |
| #include <linux/compiler.h> |
| |
| #include "multiverse.h" |
| |
| static unsigned long vme_asi_addr; |
| static unsigned long vme_iack_addr; |
| static unsigned long pci_reg_addr; |
| static unsigned long vme_reg_addr; |
| |
| int multiv_reset(unsigned long base) |
| { |
| writeb(0x09, base + VME_SLAVE32_AM); |
| writeb(0x39, base + VME_SLAVE24_AM); |
| writeb(0x29, base + VME_SLAVE16_AM); |
| writeb(0x2f, base + VME_SLAVE_REG_AM); |
| writeb((VME_A32_SLV_BUS >> 24) & 0xff, base + VME_SLAVE32_A); |
| writeb((VME_A24_SLV_BUS >> 16) & 0xff, base + VME_SLAVE24_A); |
| writeb((VME_A16_SLV_BUS >> 8 ) & 0xff, base + VME_SLAVE16_A); |
| #ifdef A32_SLV_WINDOW |
| if (readb(base + VME_STATUS) & VME_STATUS_SYSCON) { |
| writeb(((~(VME_A32_SLV_SIZE-1)) >> 24) & 0xff, |
| base + VME_SLAVE32_MASK); |
| writeb(0x01, base + VME_SLAVE32_EN); |
| } else { |
| writeb(0xff, base + VME_SLAVE32_MASK); |
| writeb(0x00, base + VME_SLAVE32_EN); |
| } |
| #else |
| writeb(0xff, base + VME_SLAVE32_MASK); |
| writeb(0x00, base + VME_SLAVE32_EN); |
| #endif |
| #ifdef A24_SLV_WINDOW |
| if (readb(base + VME_STATUS) & VME_STATUS_SYSCON) { |
| writeb(((~(VME_A24_SLV_SIZE-1)) >> 16) & 0xff, |
| base + VME_SLAVE24_MASK); |
| writeb(0x01, base + VME_SLAVE24_EN); |
| } else { |
| writeb(0xff, base + VME_SLAVE24_MASK); |
| writeb(0x00, base + VME_SLAVE24_EN); |
| } |
| #else |
| writeb(0xff, base + VME_SLAVE24_MASK); |
| writeb(0x00, base + VME_SLAVE24_EN); |
| #endif |
| #ifdef A16_SLV_WINDOW |
| if (readb(base + VME_STATUS) & VME_STATUS_SYSCON) { |
| writeb(((~(VME_A16_SLV_SIZE-1)) >> 8) & 0xff, |
| base + VME_SLAVE16_MASK); |
| writeb(0x01, base + VME_SLAVE16_EN); |
| } else { |
| writeb(0xff, base + VME_SLAVE16_MASK); |
| writeb(0x00, base + VME_SLAVE16_EN); |
| } |
| #else |
| writeb(0xff, base + VME_SLAVE16_MASK); |
| writeb(0x00, base + VME_SLAVE16_EN); |
| #endif |
| #ifdef REG_SLV_WINDOW |
| if (readb(base + VME_STATUS) & VME_STATUS_SYSCON) { |
| writeb(((~(VME_REG_SLV_SIZE-1)) >> 16) & 0xff, |
| base + VME_SLAVE_REG_MASK); |
| writeb(0x01, base + VME_SLAVE_REG_EN); |
| } else { |
| writeb(0xf8, base + VME_SLAVE_REG_MASK); |
| } |
| #else |
| writeb(0xf8, base + VME_SLAVE_REG_MASK); |
| #endif |
| writeb(0x09, base + VME_MASTER32_AM); |
| writeb(0x39, base + VME_MASTER24_AM); |
| writeb(0x29, base + VME_MASTER16_AM); |
| writeb(0x2f, base + VME_MASTER_REG_AM); |
| writel(0x00000000, base + VME_RMW_ADRS); |
| writeb(0x00, base + VME_IRQ); |
| writeb(0x00, base + VME_INT_EN); |
| writel(0x00000000, base + VME_IRQ1_REG); |
| writel(0x00000000, base + VME_IRQ2_REG); |
| writel(0x00000000, base + VME_IRQ3_REG); |
| writel(0x00000000, base + VME_IRQ4_REG); |
| writel(0x00000000, base + VME_IRQ5_REG); |
| writel(0x00000000, base + VME_IRQ6_REG); |
| writel(0x00000000, base + VME_IRQ7_REG); |
| return 0; |
| } |
| |
| void multiv_auto_slot_id(unsigned long base) |
| { |
| __maybe_unused unsigned int vector; |
| int slot_id = 1; |
| if (readb(base + VME_CTRL) & VME_CTRL_SYSFAIL) { |
| *(volatile unsigned int*)(base + VME_IRQ2_REG) = 0xfe; |
| writeb(readb(base + VME_IRQ) | 0x04, base + VME_IRQ); |
| writeb(readb(base + VME_CTRL) & ~VME_CTRL_SYSFAIL, |
| base + VME_CTRL); |
| while (readb(base + VME_STATUS) & VME_STATUS_SYSFAIL); |
| if (readb(base + VME_STATUS) & VME_STATUS_SYSCON) { |
| while (readb(base + VME_INT) & 0x04) { |
| vector = *(volatile unsigned int*) |
| (vme_iack_addr + VME_IACK2); |
| *(unsigned char*)(vme_asi_addr + 0x7ffff) |
| = (slot_id << 3) & 0xff; |
| slot_id ++; |
| if (slot_id > 31) |
| break; |
| } |
| } |
| } |
| } |
| |
| int multiverse_init(void) |
| { |
| int i; |
| pci_dev_t pdev; |
| unsigned int bar[6]; |
| |
| pdev = pci_find_device(0x1895, 0x0001, 0); |
| |
| if (pdev == 0) |
| return -1; |
| |
| for (i = 0; i < 6; i++) |
| pci_read_config_dword (pdev, |
| PCI_BASE_ADDRESS_0 + i * 4, &bar[i]); |
| |
| pci_reg_addr = bar[0]; |
| vme_reg_addr = bar[1] + 0x00F00000; |
| vme_iack_addr = bar[1] + 0x00200000; |
| vme_asi_addr = bar[3]; |
| |
| pci_write_config_dword (pdev, PCI_COMMAND, |
| PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); |
| |
| writel(0xFF000000, pci_reg_addr + P_TA1); |
| writel(0x04, pci_reg_addr + P_IMG_CTRL1); |
| writel(0xf0000000, pci_reg_addr + P_TA2); |
| writel(0x04, pci_reg_addr + P_IMG_CTRL2); |
| writel(0xF1000000, pci_reg_addr + P_TA3); |
| writel(0x04, pci_reg_addr + P_IMG_CTRL3); |
| writel(VME_A32_MSTR_BUS, pci_reg_addr + P_TA5); |
| writel(~(VME_A32_MSTR_SIZE-1), pci_reg_addr + P_AM5); |
| writel(0x04, pci_reg_addr + P_IMG_CTRL5); |
| |
| writel(VME_A32_SLV_BUS, pci_reg_addr + W_BA1); |
| writel(~(VME_A32_SLV_SIZE-1), pci_reg_addr + W_AM1); |
| writel(VME_A32_SLV_LOCAL, pci_reg_addr + W_TA1); |
| writel(0x04, pci_reg_addr + W_IMG_CTRL1); |
| |
| writel(0xF0000000, pci_reg_addr + W_BA2); |
| writel(0xFF000000, pci_reg_addr + W_AM2); |
| writel(VME_A24_SLV_LOCAL, pci_reg_addr + W_TA2); |
| writel(0x04, pci_reg_addr + W_IMG_CTRL2); |
| |
| writel(0xFF000000, pci_reg_addr + W_BA3); |
| writel(0xFF000000, pci_reg_addr + W_AM3); |
| writel(VME_A16_SLV_LOCAL, pci_reg_addr + W_TA3); |
| writel(0x04, pci_reg_addr + W_IMG_CTRL3); |
| |
| writel(0x00000001, pci_reg_addr + W_ERR_CS); |
| writel(0x00000001, pci_reg_addr + P_ERR_CS); |
| |
| multiv_reset(vme_reg_addr); |
| writeb(readb(vme_reg_addr + VME_CTRL) | VME_CTRL_SHORT_D, |
| vme_reg_addr + VME_CTRL); |
| |
| multiv_auto_slot_id(vme_reg_addr); |
| |
| return 0; |
| } |