1*014e4678SGavin Guo /* 2*014e4678SGavin Guo * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation 3*014e4678SGavin Guo * 4*014e4678SGavin Guo * Copyright (C) 2011 Andes Technology Corporation 5*014e4678SGavin Guo * Gavin Guo, Andes Technology Corporation <gavinguo@andestech.com> 6*014e4678SGavin Guo * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> 7*014e4678SGavin Guo * 8*014e4678SGavin Guo * This program is free software; you can redistribute it and/or modify 9*014e4678SGavin Guo * it under the terms of the GNU General Public License as published by 10*014e4678SGavin Guo * the Free Software Foundation; either version 2 of the License, or 11*014e4678SGavin Guo * (at your option) any later version. 12*014e4678SGavin Guo * 13*014e4678SGavin Guo * This program is distributed in the hope that it will be useful, 14*014e4678SGavin Guo * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*014e4678SGavin Guo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*014e4678SGavin Guo * GNU General Public License for more details. 17*014e4678SGavin Guo * 18*014e4678SGavin Guo * You should have received a copy of the GNU General Public License 19*014e4678SGavin Guo * along with this program; if not, write to the Free Software 20*014e4678SGavin Guo * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*014e4678SGavin Guo */ 22*014e4678SGavin Guo #include <common.h> 23*014e4678SGavin Guo #include <malloc.h> 24*014e4678SGavin Guo #include <pci.h> 25*014e4678SGavin Guo 26*014e4678SGavin Guo #include <asm/io.h> 27*014e4678SGavin Guo #include <asm/types.h> /* u32, u16.... used by pci.h */ 28*014e4678SGavin Guo 29*014e4678SGavin Guo #include "pci_ftpci100.h" 30*014e4678SGavin Guo 31*014e4678SGavin Guo struct ftpci100_data { 32*014e4678SGavin Guo unsigned int reg_base; 33*014e4678SGavin Guo unsigned int io_base; 34*014e4678SGavin Guo unsigned int mem_base; 35*014e4678SGavin Guo unsigned int mmio_base; 36*014e4678SGavin Guo unsigned int ndevs; 37*014e4678SGavin Guo }; 38*014e4678SGavin Guo 39*014e4678SGavin Guo static struct pci_config devs[FTPCI100_MAX_FUNCTIONS]; 40*014e4678SGavin Guo static struct pci_controller local_hose; 41*014e4678SGavin Guo 42*014e4678SGavin Guo static void setup_pci_bar(unsigned int bus, unsigned int dev, unsigned func, 43*014e4678SGavin Guo unsigned char header, struct ftpci100_data *priv) 44*014e4678SGavin Guo { 45*014e4678SGavin Guo struct pci_controller *hose = (struct pci_controller *)&local_hose; 46*014e4678SGavin Guo unsigned int i, tmp32, bar_no, iovsmem = 1; 47*014e4678SGavin Guo pci_dev_t dev_nu; 48*014e4678SGavin Guo 49*014e4678SGavin Guo /* A device is present, add an entry to the array */ 50*014e4678SGavin Guo devs[priv->ndevs].bus = bus; 51*014e4678SGavin Guo devs[priv->ndevs].dev = dev; 52*014e4678SGavin Guo devs[priv->ndevs].func = func; 53*014e4678SGavin Guo 54*014e4678SGavin Guo dev_nu = PCI_BDF(bus, dev, func); 55*014e4678SGavin Guo 56*014e4678SGavin Guo if ((header & 0x7f) == 0x01) 57*014e4678SGavin Guo /* PCI-PCI Bridge */ 58*014e4678SGavin Guo bar_no = 2; 59*014e4678SGavin Guo else 60*014e4678SGavin Guo bar_no = 6; 61*014e4678SGavin Guo 62*014e4678SGavin Guo /* Allocate address spaces by configuring BARs */ 63*014e4678SGavin Guo for (i = 0; i < bar_no; i++) { 64*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, 65*014e4678SGavin Guo PCI_BASE_ADDRESS_0 + i * 4, 0xffffffff); 66*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, 67*014e4678SGavin Guo PCI_BASE_ADDRESS_0 + i * 4, &tmp32); 68*014e4678SGavin Guo 69*014e4678SGavin Guo if (tmp32 == 0x0) 70*014e4678SGavin Guo continue; 71*014e4678SGavin Guo 72*014e4678SGavin Guo /* IO space */ 73*014e4678SGavin Guo if (tmp32 & 0x1) { 74*014e4678SGavin Guo iovsmem = 0; 75*014e4678SGavin Guo unsigned int size_mask = ~(tmp32 & 0xfffffffc); 76*014e4678SGavin Guo 77*014e4678SGavin Guo if (priv->io_base & size_mask) 78*014e4678SGavin Guo priv->io_base = (priv->io_base & ~size_mask) + \ 79*014e4678SGavin Guo size_mask + 1; 80*014e4678SGavin Guo 81*014e4678SGavin Guo devs[priv->ndevs].bar[i].addr = priv->io_base; 82*014e4678SGavin Guo devs[priv->ndevs].bar[i].size = size_mask + 1; 83*014e4678SGavin Guo 84*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, 85*014e4678SGavin Guo PCI_BASE_ADDRESS_0 + i * 4, 86*014e4678SGavin Guo priv->io_base); 87*014e4678SGavin Guo 88*014e4678SGavin Guo debug("Allocated IO address 0x%X-" \ 89*014e4678SGavin Guo "0x%X for Bus %d, Device %d, Function %d\n", 90*014e4678SGavin Guo priv->io_base, 91*014e4678SGavin Guo priv->io_base + size_mask, bus, dev, func); 92*014e4678SGavin Guo 93*014e4678SGavin Guo priv->io_base += size_mask + 1; 94*014e4678SGavin Guo } else { 95*014e4678SGavin Guo /* Memory space */ 96*014e4678SGavin Guo unsigned int is_64bit = ((tmp32 & 0x6) == 0x4); 97*014e4678SGavin Guo unsigned int is_pref = tmp32 & 0x8; 98*014e4678SGavin Guo unsigned int size_mask = ~(tmp32 & 0xfffffff0); 99*014e4678SGavin Guo unsigned int alloc_base; 100*014e4678SGavin Guo unsigned int *addr_mem_base; 101*014e4678SGavin Guo 102*014e4678SGavin Guo if (is_pref) 103*014e4678SGavin Guo addr_mem_base = &priv->mem_base; 104*014e4678SGavin Guo else 105*014e4678SGavin Guo addr_mem_base = &priv->mmio_base; 106*014e4678SGavin Guo 107*014e4678SGavin Guo alloc_base = *addr_mem_base; 108*014e4678SGavin Guo 109*014e4678SGavin Guo if (alloc_base & size_mask) 110*014e4678SGavin Guo alloc_base = (alloc_base & ~size_mask) \ 111*014e4678SGavin Guo + size_mask + 1; 112*014e4678SGavin Guo 113*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, 114*014e4678SGavin Guo PCI_BASE_ADDRESS_0 + i * 4, alloc_base); 115*014e4678SGavin Guo 116*014e4678SGavin Guo debug("Allocated %s address 0x%X-" \ 117*014e4678SGavin Guo "0x%X for Bus %d, Device %d, Function %d\n", 118*014e4678SGavin Guo is_pref ? "MEM" : "MMIO", alloc_base, 119*014e4678SGavin Guo alloc_base + size_mask, bus, dev, func); 120*014e4678SGavin Guo 121*014e4678SGavin Guo devs[priv->ndevs].bar[i].addr = alloc_base; 122*014e4678SGavin Guo devs[priv->ndevs].bar[i].size = size_mask + 1; 123*014e4678SGavin Guo 124*014e4678SGavin Guo debug("BAR address BAR size\n"); 125*014e4678SGavin Guo debug("%010x %08d\n", 126*014e4678SGavin Guo devs[priv->ndevs].bar[0].addr, 127*014e4678SGavin Guo devs[priv->ndevs].bar[0].size); 128*014e4678SGavin Guo 129*014e4678SGavin Guo alloc_base += size_mask + 1; 130*014e4678SGavin Guo *addr_mem_base = alloc_base; 131*014e4678SGavin Guo 132*014e4678SGavin Guo if (is_64bit) { 133*014e4678SGavin Guo i++; 134*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, 135*014e4678SGavin Guo PCI_BASE_ADDRESS_0 + i * 4, 0x0); 136*014e4678SGavin Guo } 137*014e4678SGavin Guo } 138*014e4678SGavin Guo } 139*014e4678SGavin Guo 140*014e4678SGavin Guo /* Enable Bus Master, Memory Space, and IO Space */ 141*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32); 142*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, 0x08); 143*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32); 144*014e4678SGavin Guo 145*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, PCI_COMMAND, &tmp32); 146*014e4678SGavin Guo 147*014e4678SGavin Guo tmp32 &= 0xffff; 148*014e4678SGavin Guo 149*014e4678SGavin Guo if (iovsmem == 0) 150*014e4678SGavin Guo tmp32 |= 0x5; 151*014e4678SGavin Guo else 152*014e4678SGavin Guo tmp32 |= 0x6; 153*014e4678SGavin Guo 154*014e4678SGavin Guo pci_hose_write_config_dword(hose, dev_nu, PCI_COMMAND, tmp32); 155*014e4678SGavin Guo } 156*014e4678SGavin Guo 157*014e4678SGavin Guo static void pci_bus_scan(struct ftpci100_data *priv) 158*014e4678SGavin Guo { 159*014e4678SGavin Guo struct pci_controller *hose = (struct pci_controller *)&local_hose; 160*014e4678SGavin Guo unsigned int bus, dev, func; 161*014e4678SGavin Guo pci_dev_t dev_nu; 162*014e4678SGavin Guo unsigned int data32; 163*014e4678SGavin Guo unsigned int tmp; 164*014e4678SGavin Guo unsigned char header; 165*014e4678SGavin Guo unsigned char int_pin; 166*014e4678SGavin Guo unsigned int niobars; 167*014e4678SGavin Guo unsigned int nmbars; 168*014e4678SGavin Guo 169*014e4678SGavin Guo priv->ndevs = 1; 170*014e4678SGavin Guo 171*014e4678SGavin Guo nmbars = 0; 172*014e4678SGavin Guo niobars = 0; 173*014e4678SGavin Guo 174*014e4678SGavin Guo for (bus = 0; bus < MAX_BUS_NUM; bus++) 175*014e4678SGavin Guo for (dev = 0; dev < MAX_DEV_NUM; dev++) 176*014e4678SGavin Guo for (func = 0; func < MAX_FUN_NUM; func++) { 177*014e4678SGavin Guo dev_nu = PCI_BDF(bus, dev, func); 178*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, 179*014e4678SGavin Guo PCI_VENDOR_ID, &data32); 180*014e4678SGavin Guo 181*014e4678SGavin Guo /* 182*014e4678SGavin Guo * some broken boards return 0 or ~0, 183*014e4678SGavin Guo * if a slot is empty. 184*014e4678SGavin Guo */ 185*014e4678SGavin Guo if (data32 == 0xffffffff || 186*014e4678SGavin Guo data32 == 0x00000000 || 187*014e4678SGavin Guo data32 == 0x0000ffff || 188*014e4678SGavin Guo data32 == 0xffff0000) 189*014e4678SGavin Guo continue; 190*014e4678SGavin Guo 191*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, 192*014e4678SGavin Guo PCI_HEADER_TYPE, &tmp); 193*014e4678SGavin Guo header = (unsigned char)tmp; 194*014e4678SGavin Guo setup_pci_bar(bus, dev, func, header, priv); 195*014e4678SGavin Guo 196*014e4678SGavin Guo devs[priv->ndevs].v_id = (u16)(data32 & \ 197*014e4678SGavin Guo 0x0000ffff); 198*014e4678SGavin Guo 199*014e4678SGavin Guo devs[priv->ndevs].d_id = (u16)((data32 & \ 200*014e4678SGavin Guo 0xffff0000) >> 16); 201*014e4678SGavin Guo 202*014e4678SGavin Guo /* Figure out what INTX# line the card uses */ 203*014e4678SGavin Guo pci_hose_read_config_byte(hose, dev_nu, 204*014e4678SGavin Guo PCI_INTERRUPT_PIN, &int_pin); 205*014e4678SGavin Guo 206*014e4678SGavin Guo /* assign the appropriate irq line */ 207*014e4678SGavin Guo if (int_pin > PCI_IRQ_LINES) { 208*014e4678SGavin Guo printf("more irq lines than expect\n"); 209*014e4678SGavin Guo } else if (int_pin != 0) { 210*014e4678SGavin Guo /* This device uses an interrupt line */ 211*014e4678SGavin Guo devs[priv->ndevs].pin = int_pin; 212*014e4678SGavin Guo } 213*014e4678SGavin Guo 214*014e4678SGavin Guo pci_hose_read_config_dword(hose, dev_nu, 215*014e4678SGavin Guo PCI_CLASS_DEVICE, &data32); 216*014e4678SGavin Guo 217*014e4678SGavin Guo debug("%06d %03d %03d " \ 218*014e4678SGavin Guo "%04d %08x %08x " \ 219*014e4678SGavin Guo "%03d %08x %06d %08x\n", 220*014e4678SGavin Guo priv->ndevs, devs[priv->ndevs].bus, 221*014e4678SGavin Guo devs[priv->ndevs].dev, 222*014e4678SGavin Guo devs[priv->ndevs].func, 223*014e4678SGavin Guo devs[priv->ndevs].d_id, 224*014e4678SGavin Guo devs[priv->ndevs].v_id, 225*014e4678SGavin Guo devs[priv->ndevs].pin, 226*014e4678SGavin Guo devs[priv->ndevs].bar[0].addr, 227*014e4678SGavin Guo devs[priv->ndevs].bar[0].size, 228*014e4678SGavin Guo data32 >> 8); 229*014e4678SGavin Guo 230*014e4678SGavin Guo priv->ndevs++; 231*014e4678SGavin Guo } 232*014e4678SGavin Guo } 233*014e4678SGavin Guo 234*014e4678SGavin Guo static void ftpci_preinit(struct ftpci100_data *priv) 235*014e4678SGavin Guo { 236*014e4678SGavin Guo struct ftpci100_ahbc *ftpci100; 237*014e4678SGavin Guo struct pci_controller *hose = (struct pci_controller *)&local_hose; 238*014e4678SGavin Guo u32 pci_config_addr; 239*014e4678SGavin Guo u32 pci_config_data; 240*014e4678SGavin Guo 241*014e4678SGavin Guo priv->reg_base = CONFIG_FTPCI100_BASE; 242*014e4678SGavin Guo priv->io_base = CONFIG_FTPCI100_BASE + CONFIG_FTPCI100_IO_SIZE; 243*014e4678SGavin Guo priv->mmio_base = CONFIG_FTPCI100_MEM_BASE; 244*014e4678SGavin Guo priv->mem_base = CONFIG_FTPCI100_MEM_BASE + CONFIG_FTPCI100_MEM_SIZE; 245*014e4678SGavin Guo 246*014e4678SGavin Guo ftpci100 = (struct ftpci100_ahbc *)priv->reg_base; 247*014e4678SGavin Guo 248*014e4678SGavin Guo pci_config_addr = (u32) &ftpci100->conf; 249*014e4678SGavin Guo pci_config_data = (u32) &ftpci100->data; 250*014e4678SGavin Guo 251*014e4678SGavin Guo /* print device name */ 252*014e4678SGavin Guo printf("FTPCI100\n"); 253*014e4678SGavin Guo 254*014e4678SGavin Guo /* dump basic configuration */ 255*014e4678SGavin Guo debug("%s: Config addr is %08X, data port is %08X\n", 256*014e4678SGavin Guo __func__, pci_config_addr, pci_config_data); 257*014e4678SGavin Guo 258*014e4678SGavin Guo /* PCI memory space */ 259*014e4678SGavin Guo pci_set_region(hose->regions + 0, 260*014e4678SGavin Guo CONFIG_PCI_MEM_BUS, 261*014e4678SGavin Guo CONFIG_PCI_MEM_PHYS, 262*014e4678SGavin Guo CONFIG_PCI_MEM_SIZE, 263*014e4678SGavin Guo PCI_REGION_MEM); 264*014e4678SGavin Guo hose->region_count++; 265*014e4678SGavin Guo 266*014e4678SGavin Guo /* PCI IO space */ 267*014e4678SGavin Guo pci_set_region(hose->regions + 1, 268*014e4678SGavin Guo CONFIG_PCI_IO_BUS, 269*014e4678SGavin Guo CONFIG_PCI_IO_PHYS, 270*014e4678SGavin Guo CONFIG_PCI_IO_SIZE, 271*014e4678SGavin Guo PCI_REGION_IO); 272*014e4678SGavin Guo hose->region_count++; 273*014e4678SGavin Guo 274*014e4678SGavin Guo #if defined(CONFIG_PCI_SYS_BUS) 275*014e4678SGavin Guo /* PCI System Memory space */ 276*014e4678SGavin Guo pci_set_region(hose->regions + 2, 277*014e4678SGavin Guo CONFIG_PCI_SYS_BUS, 278*014e4678SGavin Guo CONFIG_PCI_SYS_PHYS, 279*014e4678SGavin Guo CONFIG_PCI_SYS_SIZE, 280*014e4678SGavin Guo PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); 281*014e4678SGavin Guo hose->region_count++; 282*014e4678SGavin Guo #endif 283*014e4678SGavin Guo 284*014e4678SGavin Guo /* setup indirect read/write function */ 285*014e4678SGavin Guo pci_setup_indirect(hose, pci_config_addr, pci_config_data); 286*014e4678SGavin Guo 287*014e4678SGavin Guo /* register hose */ 288*014e4678SGavin Guo pci_register_hose(hose); 289*014e4678SGavin Guo } 290*014e4678SGavin Guo 291*014e4678SGavin Guo void pci_ftpci_init(void) 292*014e4678SGavin Guo { 293*014e4678SGavin Guo struct ftpci100_data *priv = NULL; 294*014e4678SGavin Guo struct pci_controller *hose = (struct pci_controller *)&local_hose; 295*014e4678SGavin Guo pci_dev_t bridge_num; 296*014e4678SGavin Guo 297*014e4678SGavin Guo struct pci_device_id bridge_ids[] = { 298*014e4678SGavin Guo {FTPCI100_BRIDGE_VENDORID, FTPCI100_BRIDGE_DEVICEID}, 299*014e4678SGavin Guo {0, 0} 300*014e4678SGavin Guo }; 301*014e4678SGavin Guo 302*014e4678SGavin Guo priv = malloc(sizeof(struct ftpci100_data)); 303*014e4678SGavin Guo 304*014e4678SGavin Guo if (!priv) { 305*014e4678SGavin Guo printf("%s(): failed to malloc priv\n", __func__); 306*014e4678SGavin Guo return; 307*014e4678SGavin Guo } 308*014e4678SGavin Guo 309*014e4678SGavin Guo memset(priv, 0, sizeof(struct ftpci100_data)); 310*014e4678SGavin Guo 311*014e4678SGavin Guo ftpci_preinit(priv); 312*014e4678SGavin Guo 313*014e4678SGavin Guo debug("Device bus dev func deviceID vendorID pin address" \ 314*014e4678SGavin Guo " size class\n"); 315*014e4678SGavin Guo 316*014e4678SGavin Guo pci_bus_scan(priv); 317*014e4678SGavin Guo 318*014e4678SGavin Guo /* 319*014e4678SGavin Guo * Setup the PCI Bridge Window to 1GB, 320*014e4678SGavin Guo * it will cause USB OHCI Host controller Unrecoverable Error 321*014e4678SGavin Guo * if it is not set. 322*014e4678SGavin Guo */ 323*014e4678SGavin Guo bridge_num = pci_find_devices(bridge_ids, 0); 324*014e4678SGavin Guo if (bridge_num == -1) { 325*014e4678SGavin Guo printf("PCI Bridge not found\n"); 326*014e4678SGavin Guo return; 327*014e4678SGavin Guo } 328*014e4678SGavin Guo pci_hose_write_config_dword(hose, bridge_num, PCI_MEM_BASE_SIZE1, 329*014e4678SGavin Guo FTPCI100_BASE_ADR_SIZE(1024)); 330*014e4678SGavin Guo } 331