/* * RTL8196B PCIE Host Controller Glue Driver * Author: ghhuang@realtek.com.tw * * Notes: * - Two host controllers available. * - Each host direcly connects to one device * - Supports PCI devices through PCIE-to-PCI bridges * - If no PCI devices are connected to RC. Timeout monitor shall be * enabled to prevent bus hanging. */ #include #include #include #include #include #include #include "bspchip.h" #define PCI_8BIT_ACCESS 1 #define PCI_16BIT_ACCESS 2 #define PCI_32BIT_ACCESS 4 #define PCI_ACCESS_READ 8 #define PCI_ACCESS_WRITE 16 #define MAX_NUM_DEV 4 #define DEBUG_PRINTK 0 //#define PIN_208 static int pci0_bus_number = 0xff; static int pci1_bus_number = 0xff; static struct resource rtl8196b_pci0_io_resource = { .name = "RTL8196B PCI0 IO", .flags = IORESOURCE_IO, .start = PADDR(BSP_PCIE0_D_IO), .end = PADDR(BSP_PCIE0_D_IO + 0x1FFFFF) }; static struct resource rtl8196b_pci0_mem_resource = { .name = "RTL8196B PCI0 MEM", .flags = IORESOURCE_MEM, .start = PADDR(BSP_PCIE0_D_MEM), .end = PADDR(BSP_PCIE0_D_MEM + 0xFFFFFF) }; #ifdef PIN_208 static struct resource rtl8196b_pci1_io_resource = { .name = "RTL8196B PCI1 IO", .flags = IORESOURCE_IO, .start = PADDR(BSP_PCIE1_D_IO), .end = PADDR(BSP_PCIE1_D_IO + 0x1FFFFF) }; static struct resource rtl8196b_pci1_mem_resource = { .name = "RTL8196B PCI1 MEM", .flags = IORESOURCE_MEM, .start = PADDR(BSP_PCIE1_D_MEM), .end = PADDR(BSP_PCIE1_D_MEM + 0xFFFFFF) }; #endif //HOST PCIE #define PCIE0_RC_EXT_BASE (0xb8b01000) //RC Extended register #define PCIE0_MDIO (PCIE0_RC_EXT_BASE+0x00) //MDIO #define PCIE_MDIO_DATA_OFFSET (16) #define PCIE_MDIO_DATA_MASK (0xffff <number; #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); #endif if (bus->number == pci0_bus_number) { /* PCIE host controller */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE0_H_CFG + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &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; } else return PCIBIOS_DEVICE_NOT_FOUND; } else if (bus->number == (pci0_bus_number + 1)) { /* PCIE devices directly connected */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE0_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else { /* Devices connected through bridge */ if (PCI_SLOT(devfn) < MAX_NUM_DEV) { WRITE_MEM32(BSP_PCIE0_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); addr = BSP_PCIE0_D_CFG1 + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Read Value: 0x%08X\n", *val); #endif return PCIBIOS_SUCCESSFUL; } static int rtl8196b_pcibios0_write(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int val) { unsigned int data = 0; unsigned int addr = 0; static int pci0_bus_number = 0xff; if (pci0_bus_number == 0xff) pci0_bus_number = bus->number; #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); #endif if (bus->number == pci0_bus_number) { /* PCIE host controller */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE0_H_CFG + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &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)); else data = val; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else if (bus->number == (pci0_bus_number + 1)) { /* PCIE devices directly connected */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE0_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else { /* Devices connected through bridge */ if (PCI_SLOT(devfn) < MAX_NUM_DEV) { WRITE_MEM32(BSP_PCIE0_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); addr = BSP_PCIE0_D_CFG1 + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } return PCIBIOS_SUCCESSFUL; } /* * RTL8196b supports config word read access for 8/16/32 bit * * FIXME: currently only utilize 32bit access */ #ifdef PIN_208 static int rtl8196b_pcibios1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int *val) { unsigned int data = 0; unsigned int addr = 0; if (pci1_bus_number == 0xff) pci1_bus_number = bus->number; #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); #endif if (bus->number == pci1_bus_number) { /* PCIE host controller */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE1_H_CFG + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &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; } else return PCIBIOS_DEVICE_NOT_FOUND; } else if (bus->number == (pci1_bus_number + 1)) { /* PCIE devices directly connected */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE1_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else { /* Devices connected through bridge */ if (PCI_SLOT(devfn) < MAX_NUM_DEV) { WRITE_MEM32(BSP_PCIE1_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); addr = BSP_PCIE1_D_CFG1 + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | size, addr, val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Read Value: 0x%08X\n", *val); #endif return PCIBIOS_SUCCESSFUL; } static int rtl8196b_pcibios1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned int val) { unsigned int data = 0; unsigned int addr = 0; static int pci1_bus_number = 0xff; if (pci1_bus_number == 0xff) pci1_bus_number = bus->number; #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("Bus: %d, Slot: %d, Func: %d, Where: %d, Size: %d\n", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); #endif if (bus->number == pci1_bus_number) { /* PCIE host controller */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE1_H_CFG + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_READ | PCI_32BIT_ACCESS, addr & ~(0x3), &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)); else data = val; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | PCI_32BIT_ACCESS, addr & ~(0x3), &data)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else if (bus->number == (pci1_bus_number + 1)) { /* PCIE devices directly connected */ if (PCI_SLOT(devfn) == 0) { addr = BSP_PCIE1_D_CFG0 + (PCI_FUNC(devfn) << 12) + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } else { /* Devices connected through bridge */ if (PCI_SLOT(devfn) < MAX_NUM_DEV) { WRITE_MEM32(BSP_PCIE1_H_IPCFG, ((bus->number) << 8) | (PCI_SLOT(devfn) << 3) | PCI_FUNC(devfn)); addr = BSP_PCIE1_D_CFG1 + where; if (rtl8196b_pcibios_config_access(PCI_ACCESS_WRITE | size, addr, &val)) return PCIBIOS_DEVICE_NOT_FOUND; } else return PCIBIOS_DEVICE_NOT_FOUND; } return PCIBIOS_SUCCESSFUL; } #endif struct pci_ops rtl8196b_pci0_ops = { .read = rtl8196b_pcibios0_read, .write = rtl8196b_pcibios0_write }; #ifdef PIN_208 struct pci_ops rtl8196b_pci1_ops = { .read = rtl8196b_pcibios1_read, .write = rtl8196b_pcibios1_write }; #endif static struct pci_controller rtl8196b_pci0_controller = { .pci_ops = &rtl8196b_pci0_ops, .mem_resource = &rtl8196b_pci0_mem_resource, .io_resource = &rtl8196b_pci0_io_resource, }; #ifdef PIN_208 static struct pci_controller rtl8196b_pci1_controller = { .pci_ops = &rtl8196b_pci1_ops, .mem_resource = &rtl8196b_pci1_mem_resource, .io_resource = &rtl8196b_pci1_io_resource, }; #endif int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); printk("**Slot: %d\n", slot); printk("**Pin: %d\n", pin); printk("**Dev->BUS->Number: %d\n", dev->bus->number); #endif if (dev->bus->number < pci1_bus_number) return BSP_PCIE_IRQ; else return BSP_PCIE2_IRQ; } /* Do platform specific device initialization at pci_enable_device() time */ int pcibios_plat_dev_init(struct pci_dev *dev) { #if DEBUG_PRINTK printk("File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return 0; } static __init int bsp_pcie_init(void) { //rtl8196b_pci_reset(); PCIE_reset_procedure(0,0,1); #if DEBUG_PRINTK printk("<<<<>>>>\n"); #ifdef PIN_208 printk("<<<<>>>>\n"); #endif #endif register_pci_controller(&rtl8196b_pci0_controller); #ifdef PIN_208 register_pci_controller(&rtl8196b_pci1_controller); #endif return 0; } arch_initcall(bsp_pcie_init);