[U-Boot] [PATCH] pci_ftpci100: Implementation FTPCI100 PCI driver

FTPCI100 is a SoC PCI componenet of Faraday company. Which is usually built into SoC chips for providing embedded PCI functions.
Signed-off-by: Gavin Guo gavinguo@andestech.com --- drivers/pci/pci_ftpci100.c | 282 ++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci_ftpci100.h | 117 ++++++++++++++++++ 2 files changed, 399 insertions(+), 0 deletions(-) create mode 100644 drivers/pci/pci_ftpci100.c create mode 100644 drivers/pci/pci_ftpci100.h
diff --git a/drivers/pci/pci_ftpci100.c b/drivers/pci/pci_ftpci100.c new file mode 100644 index 0000000..4c534c2 --- /dev/null +++ b/drivers/pci/pci_ftpci100.c @@ -0,0 +1,282 @@ +/* + * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation + * + * Copyright (C) 2010 Andes Technology Corporation + * Gavin Guo, Andes Technology Corporation gavinguo@andestech.com + * Macpaul Lin, Andes Technology Corporation macpaul@andestech.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __io +#define __io +#endif + +#include <asm/io.h> +#include <asm/types.h> /* u32, u16.... used by pci.h */ +#include <common.h> +#include <pci.h> +#include "pci_ftpci100.h" + +int ftpci_probed; +struct pci_controller hose; +static unsigned int pci_config_addr; +static unsigned int pci_config_data; +static unsigned int mmio_base; +static unsigned int io_base; +static unsigned int mem_base; +unsigned int ndevices; +unsigned int nmbars; +unsigned int niobars; + +struct pci_config devices[FTPCI100_MAX_FUNCTIONS]; + +void setup_pci_bar (unsigned int bus, unsigned int dev, unsigned func, + unsigned char header) +{ + unsigned int i, tmp32, bar_no, iovsmem = 1; + pci_dev_t dev_nu; + + /* A device is present, add an entry to the array */ + devices[ndevices].bus = bus; + devices[ndevices].device = dev; + devices[ndevices].func = func; + + dev_nu = PCI_BDF(bus, dev, func); + + if ((header & 0x7f) == 0x01) + /* PCI-PCI Bridge */ + bar_no = 2; + else + bar_no = 6; + /* Allocate address spaces by configuring BARs */ + for (i = 0; i < bar_no; i++) { + pci_hose_write_config_dword (&hose, dev_nu, + PCI_BASE_ADDRESS_0 + i * 4, 0xffffffff); + pci_hose_read_config_dword (&hose, dev_nu, + PCI_BASE_ADDRESS_0 + i * 4, &tmp32); + + if (tmp32 == 0x0) + continue; + + /* IO space */ + if (tmp32 & 0x1) { + iovsmem = 0; + unsigned int size_mask = ~(tmp32 & 0xfffffffc); + + if (io_base & size_mask) + io_base = (io_base & ~size_mask) + size_mask + 1; + + devices[ndevices].bar[i].address = io_base; + devices[ndevices].bar[i].size = size_mask + 1; + + pci_hose_write_config_dword (&hose, dev_nu, + PCI_BASE_ADDRESS_0 + i * 4, io_base); +#ifdef CONFIG_FTPCI100_DEBUG + printf ("Allocated IO address 0x%X-" \ + "0x%X for Bus %d, Device %d, Function %d\n", + io_base, io_base + size_mask, bus, dev, func); +#endif + io_base += size_mask + 1; + } + /* Memory space */ + else { + unsigned int is_64bit = ((tmp32 & 0x6) == 0x4); + unsigned int is_pref = tmp32 & 0x8; + unsigned int size_mask = ~(tmp32 & 0xfffffff0); + unsigned int alloc_base; + unsigned int *addr_mem_base; + + if (is_pref) { + addr_mem_base = &mem_base; + } else { + addr_mem_base = &mmio_base; + } + + alloc_base = *addr_mem_base; + + if (alloc_base & size_mask) + alloc_base = (alloc_base & ~size_mask) + size_mask + 1; + + pci_hose_write_config_dword (&hose, dev_nu, + PCI_BASE_ADDRESS_0 + i * 4, alloc_base); +#ifdef CONFIG_FTPCI100_DEBUG + printf ("Allocated %s address 0x%X-" \ + "0x%X for Bus %d, Device %d, Function %d\n", + is_pref ? "MEM" : "MMIO", alloc_base, + alloc_base + size_mask, bus, dev, func); +#endif + + devices[ndevices].bar[i].address = alloc_base; + devices[ndevices].bar[i].size = size_mask + 1; +#ifdef CONFIG_FTPCI100_DEBUG + printf ("BAR address BAR size\n"); + printf ("%010x %08d\n", + devices[ndevices].bar[0].address, + devices[ndevices].bar[0].size); +#endif + alloc_base += size_mask + 1; + *addr_mem_base = alloc_base; + + if (is_64bit) { + i++; + pci_hose_write_config_dword (&hose, dev_nu, + PCI_BASE_ADDRESS_0 + i * 4, 0x0); + } + } + } + + /* Enable Bus Master, Memory Space, and IO Space */ + pci_hose_read_config_dword (&hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32); + pci_hose_write_config_dword (&hose, dev_nu, PCI_CACHE_LINE_SIZE, 0x08); + pci_hose_read_config_dword (&hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32); + + pci_hose_read_config_dword (&hose, dev_nu, PCI_COMMAND, &tmp32); + + tmp32 &= 0xffff; + if (iovsmem == 0) + tmp32 |= 0x5; + else + tmp32 |= 0x6; + + pci_hose_write_config_dword (&hose, dev_nu, PCI_COMMAND, tmp32); +} + +void pci_bus_scan (void) +{ + unsigned int bus, dev, func; + pci_dev_t dev_nu; + unsigned int data32, membase; + unsigned char header; + unsigned char intPin; + + ndevices = 1; + + nmbars = 0; + niobars = 0; + + for (bus = 0; bus < MAX_BUS_NUM; bus++) + for (dev = 0; dev < MAX_DEV_NUM; dev++) + for (func = 0; func < MAX_FUN_NUM; func++) { + dev_nu = PCI_BDF(bus, dev, func); + pci_hose_read_config_dword (&hose, dev_nu, + PCI_VENDOR_ID, &data32); + + /* + * some broken boards return 0 or ~0, + * if a slot is empty. + */ + if (data32 == 0xffffffff || data32 == 0x00000000 || + data32 == 0x0000ffff || data32 == 0xffff0000) + continue; + + pci_hose_read_config_dword (&hose, dev_nu, PCI_HEADER_TYPE, &header); + setup_pci_bar (bus, dev, func, header); + + devices[ndevices].vendor_id = (unsigned short)(data32 & 0x0000ffff); + + devices[ndevices].device_id = (unsigned short)((data32 & 0xffff0000) >> 16); + + /* Figure out what INTX# line the card uses */ + pci_hose_read_config_byte (&hose, dev_nu, + PCI_INTERRUPT_PIN, &intPin); + + /* assign the appropriate irq line */ + if (intPin > PCI_IRQ_LINES) { + printf ("more irq lines than expect\n"); + } else if (intPin != 0) { + /* This device uses an interrupt line */ + devices[ndevices].pin = intPin; + } + + pci_hose_read_config_dword (&hose, dev_nu, + PCI_CLASS_DEVICE, &data32); + +#ifdef CONFIG_PCI_SCAN_SHOW + printf ("%06d %03d %03d " \ + "%04d %08x %08x " \ + "%03d %08x %06d %08x\n", + ndevices, devices[ndevices].bus, devices[ndevices].device, + devices[ndevices].func, devices[ndevices].device_id, devices[ndevices].vendor_id, + devices[ndevices].pin, devices[ndevices].bar[0].address, + devices[ndevices].bar[0].size, data32 >> 8); + ndevices++; +#endif + + } +} + +static int ftpci_probe (unsigned int addr_p) +{ + unsigned int *addr = (unsigned int *) addr_p; + *(volatile unsigned int *) addr = 0x80000000; + + if (*(volatile unsigned int *) addr == 0x80000000) { + printf ("Faraday ftpci100 PCI bridge probed ok\n"); + ftpci_probed = 1; + } else + ftpci_probed = 0; + + *(volatile unsigned int *) addr = 0x0; + return ftpci_probed; +} + +void ftpci_preinit () +{ + printf ("ftpci_preinit()\n\r"); + + pci_config_addr = CONFIG_FTPCI100_BASE + FTPCI100_CFG_ADR_REG; + pci_config_data = CONFIG_FTPCI100_BASE + FTPCI100_CFG_DATA_REG; + printf ("Config addr is %08X, data port is %08X\n", + (int) pci_config_addr, (int) pci_config_data); + + io_base = CONFIG_FTPCI100_BASE + CONFIG_FTPCI100_IO_SIZE; + mmio_base = CONFIG_FTPCI100_MEM_BASE; + mem_base = CONFIG_FTPCI100_MEM_BASE + CONFIG_FTPCI100_MEM_SIZE; + pci_setup_indirect(&hose, pci_config_addr, pci_config_data); + pci_register_hose(&hose); + + if (!ftpci_probe(pci_config_addr)) + return; +} + +void pci_ftpci_init () +{ + struct pci_device_id bridge_ids[] = { + {FTPCI100_BRIDGE_VENDORID, FTPCI100_BRIDGE_DEVICEID}, + {0, 0} + }; + pci_dev_t bridge_num; + + ftpci_preinit (); +#ifdef CONFIG_PCI_SCAN_SHOW + printf ("Device bus dev func deviceID vendorID pin address" \ + " size class\n"); +#endif + pci_bus_scan (); + + /* + * Setup the PCI Bridge Window to 1GB, + * it will cause USB OHCI Host controller Unrecoverable Error + * if it is not set. + */ + bridge_num = pci_find_devices (bridge_ids, 0); + if (bridge_num == -1) { + printf("PCI Bridge not found\n"); + return; + } + pci_hose_write_config_dword (&hose, bridge_num, PCI_MEM_BASE_SIZE1, + FTPCI100_WINDOW_BASE_ADR_SIZE_1GB); + return; +} diff --git a/drivers/pci/pci_ftpci100.h b/drivers/pci/pci_ftpci100.h new file mode 100644 index 0000000..7bb056d --- /dev/null +++ b/drivers/pci/pci_ftpci100.h @@ -0,0 +1,117 @@ +/* + * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation + * + * Copyright (C) 2010 Andes Technology Corporation + * Gavin Guo, Andes Technology Corporation gavinguo@andestech.com + * Macpaul Lin, Andes Technology Corporation macpaul@andestech.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __FTPCI100_H +#define __FTPCI100_H + +#define FTPCI100_IOSIZE_REG 0x0 +#define FTPCI100_PROT_REG 0x4 +#define FTPCI100_CTRL_REG 0x8 +#define FTPCI100_ERREN_REG 0xc +#define FTPCI100_SOFTRST_REG 0x10 +#define FTPCI100_EN64_REG 0x14 +#define FTPCI100_ADDRH32_REG 0x18 +#define FTPCI100_CFG_ADR_REG 0x28 +#define FTPCI100_CFG_DATA_REG 0x2c + +/* + * FTPCI100_IOSIZE_REG's constant definitions + */ +#define FTPCI100_BASE_IO_SIZE_1M 0x0 +#define FTPCI100_BASE_IO_SIZE_2M 0x1 +#define FTPCI100_BASE_IO_SIZE_4M 0x2 +#define FTPCI100_BASE_IO_SIZE_8M 0x3 +#define FTPCI100_BASE_IO_SIZE_17M 0x4 +#define FTPCI100_BASE_IO_SIZE_32M 0x5 +#define FTPCI100_BASE_IO_SIZE_64M 0x6 +#define FTPCI100_BASE_IO_SIZE_128M 0x7 +#define FTPCI100_BASE_IO_SIZE_256M 0x8 +#define FTPCI100_BASE_IO_SIZE_512M 0x9 +#define FTPCI100_BASE_IO_SIZE_1G 0xa +#define FTPCI100_BASE_IO_SIZE_2G 0xb + +/* + * PCI Configuration Register + */ +#define PCI_INT_MASK 0x4c +#define PCI_MEM_BASE_SIZE1 0x50 +#define PCI_MEM_BASE_SIZE2 0x54 +#define PCI_MEM_BASE_SIZE3 0x58 + +/* + * PCI_INT_MASK's bit definitions + */ +#define PCI_INTA_ENABLE (1U<<22) +#define PCI_INTB_ENABLE (1U<<23) +#define PCI_INTC_ENABLE (1U<<24) +#define PCI_INTD_ENABLE (1U<<25) + +/* + * PCI_MEM_BASE_SIZE1's constant definitions + */ +#define FTPCI100_BASE_ADR_SIZE_1MB (PHYS_OFFSET | (0x0<<16)) +#define FTPCI100_BASE_ADR_SIZE_2MB (PHYS_OFFSET | (0x1<<16)) +#define FTPCI100_BASE_ADR_SIZE_4MB (PHYS_OFFSET | (0x2<<16)) +#define FTPCI100_BASE_ADR_SIZE_8MB (PHYS_OFFSET | (0x3<<16)) +#define FTPCI100_BASE_ADR_SIZE_16MB (PHYS_OFFSET | (0x4<<16)) +#define FTPCI100_BASE_ADR_SIZE_32MB (PHYS_OFFSET | (0x5<<16)) +#define FTPCI100_BASE_ADR_SIZE_64MB (PHYS_OFFSET | (0x6<<16)) +#define FTPCI100_BASE_ADR_SIZE_128MB (PHYS_OFFSET | (0x7<<16)) +#define FTPCI100_BASE_ADR_SIZE_256MB (PHYS_OFFSET | (0x8<<16)) +#define FTPCI100_BASE_ADR_SIZE_512MB (PHYS_OFFSET | (0x9<<16)) +#define FTPCI100_BASE_ADR_SIZE_1GB (PHYS_OFFSET | (0xa<<16)) +#define FTPCI100_BASE_ADR_SIZE_2GB (PHYS_OFFSET | (0xb<<16)) + +#define FTPCI100_MAX_FUNCTIONS 20 +#define PCI_IRQ_LINES 4 + +#define MAX_BUS_NUM 256 +#define MAX_DEV_NUM 32 +#define MAX_FUN_NUM 8 + +#define PCI_MAX_BAR_PER_FUNC 6 + +/* This is quick reference for io and mem size */ +#define FTPCI100_SIZE_256 (1 << 8) /* 0x00000100 */ +#define FTPCI100_SIZE_128M (1 << 27) /* 0x08000000 */ + +/* This definition is used by pci_ftpci_init() */ +#define FTPCI100_BRIDGE_VENDORID 0x159b +#define FTPCI100_BRIDGE_DEVICEID 0x4321 +#define FTPCI100_WINDOW_BASE_ADR_SIZE_1GB (0x0 | (0xa<<16)) + +struct pcibar { + unsigned int size; + unsigned int address; +}; + +struct pci_config { + unsigned int bus; + unsigned int device; + unsigned int func; + unsigned int pin; + unsigned short vendor_id; + unsigned short device_id; + struct pcibar bar[PCI_MAX_BAR_PER_FUNC + 1]; +}; + +#endif
participants (1)
-
Gavin Guo