📄 pciem86xx.c
字号:
/***************************************** Copyright (c) 2003-2007 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the EM86XX boot loader *//* * pciem86xx.c * * EM86XX as a PCI Host * * by Ho Lee 02/05/2003 */#include "config.h"#include "uart.h"#include "util.h"#include "hardware.h"#include "io.h"#include "irqs.h"#include "em86xxapi.h"#include "pciem86xx.h"//// global variables// static int g_pci_em86xx_inited = 0;static int g_pci_em86xx_lastidsel = 0;static unsigned int g_pcimem_busaddr = PCIBIOS_MIN_MEM_EM86XX - MEMORY_BASE_PCI_MEMORY;static unsigned int g_pcimem_phyaddr = DRAMBASE;static unsigned int g_pcimem_phyaddr_end = DRAMBASE;extern unsigned long loadaddr_pci_start;// static void pci_em86xx_busfault_irq(void *pdata);static unsigned int pci_em86xx_virt_to_bus(unsigned int virt);static unsigned int pci_em86xx_bus_to_virt(unsigned int bus);struct my_pci_op g_pciem86xx_op = { idsel_start : PCI_EM86XX_IDSEL_FIRST, idsel_end : PCI_EM86XX_IDSEL_MAX - 1, mem_offset : MEMORY_BASE_PCI_MEMORY, io_offset : MEMORY_BASE_PCI_CONFIG, init : pci_em86xx_init, info : pci_em86xx_info, select : pci_em86xx_select, virt_to_bus : pci_em86xx_virt_to_bus, bus_to_virt : pci_em86xx_bus_to_virt, pciio_base : pci_em86xx_pciio_base, pcimemory_base : pci_em86xx_pcimemory_base, read_config_byte : pci_em86xx_read_config_byte, read_config_word : pci_em86xx_read_config_word, read_config_dword : pci_em86xx_read_config_dword, write_config_byte : pci_em86xx_write_config_byte, write_config_word : pci_em86xx_write_config_word, write_config_dword : pci_em86xx_write_config_dword, in_byte : pci_em86xx_read_byte, in_word : pci_em86xx_read_word, in_dword : pci_em86xx_read_dword, out_byte : pci_em86xx_write_byte, out_word : pci_em86xx_write_word, out_dword : pci_em86xx_write_dword, read_byte : pci_em86xx_read_byte, read_word : pci_em86xx_read_word, read_dword : pci_em86xx_read_dword, write_byte : pci_em86xx_write_byte, write_word : pci_em86xx_write_word, write_dword : pci_em86xx_write_dword,#ifdef CONFIG_ENABLE_FULLFUNCTION test : pci_em86xx_test,#endif};//// PCI bus initialization//int pci_em86xx_init(int verbose){ extern unsigned long dram0_size; if (!g_pci_em86xx_inited) { g_pcimem_phyaddr_end += dram0_size; // EM86XX is Host __raw_writel(1, REG_BASE_HOST + PCI_chip_is_host);#ifdef CONFIG_ARCH_TANGO // select IDSEL 0 __raw_writew((0 << 8), REG_BASE_HOST + PCI_host_host_reg2);#endif#if (defined(CONFIG_ARCH_MAMBO) && (CONFIG_ARCH_MAMBO_REV == 1)) // PCI HOST registers initialization __raw_writel(0x00ff0000, REG_BASE_HOST + PCI_host_host_reg1);#elif (defined(CONFIG_ARCH_MAMBO) && (CONFIG_ARCH_MAMBO_REV >= 2)) || defined(CONFIG_ARCH_TANGO) // PCI HOST registers initialization __raw_writel(0xffff0000, REG_BASE_HOST + PCI_host_host_reg1);#ifdef CONFIG_ARCH_TANGO#if 1 __raw_writel(0x00030000, REG_BASE_HOST + PCI_pcictrl_reg1);#else __raw_writel(0x000700fc, REG_BASE_HOST + PCI_pcictrl_reg1);#endif#else __raw_writel(0x000300fc, REG_BASE_HOST + PCI_pcictrl_reg1);#endif __raw_writel(0x0003060d, REG_BASE_HOST + PCI_pcictrl_reg2); __raw_writel(0x00000000, REG_BASE_HOST + PCI_pcictrl_reg3); // PCI Arbiter registers initialization __raw_writel(0x10101010, REG_BASE_HOST + PCI_host_host_reg3); __raw_writel(0, REG_BASE_HOST + PCI_host_host_reg4); // Initialize EM86XX as a PCI slave { int i; unsigned int memsize, regsize, membase; while (pci_em86xx_select(0) == 0) ; // __raw_writeb(0x07, REG_BASE_HOST + PCI_devcfg_reg3); __raw_writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, MEMORY_BASE_PCI_CONFIG + PCI_COMMAND); __raw_writel(PCIBIOS_MIN_MEM_EM86XX - MEMORY_BASE_PCI_MEMORY, MEMORY_BASE_PCI_CONFIG + PCI_BASE_ADDRESS_0); __raw_writel(MEMORY_BASE_RISC, REG_BASE_HOST + PCI_region_base + (1 * 4)); memsize = __raw_readl(REG_BASE_HOST + PCI_devcfg_reg3) & 0x07; memsize = 1 << memsize; regsize = (memsize << 20) >> 3; // memory size / 8 g_pcimem_busaddr += regsize * 2; if (verbose) uart_printf("PCI: Configured EM86XX as a PCI slave with %dMB PCI memory\n", memsize); membase = loadaddr_pci_start; g_pcimem_phyaddr = membase; for (i = 2; i < 8; ++i) { __raw_writel(EM86XX_DRAM_C2NC(membase), REG_BASE_HOST + PCI_region_base + (i * 4)); membase += regsize; } if (g_pcimem_phyaddr_end > membase) g_pcimem_phyaddr_end = membase; if (verbose) { uart_printf("PCI: Each Region size is %dKB\n", regsize >> 10); uart_printf("PCI: Reserved memory from 0x%08x to 0x%08x for DMA and mapped to 0x%08x\n", g_pcimem_phyaddr, g_pcimem_phyaddr_end, g_pcimem_busaddr); } }#endif // em86xx_request_irq(IRQ_PCILOCALBUSFAULT, pci_em86xx_busfault_irq, NULL); g_pci_em86xx_inited = 1; } return 0;}#if 0static void pci_em86xx_busfault_irq(int irq, void *pdata){ static char *s_fault_reason[] = { "OK", "Master Abort", "Retry timer expired", "Unknown" }; static int s_faultcount; unsigned int data; data = __raw_readb(REG_BASE_HOST + PCI_host_host_reg2 + 3); uart_printf("PCI: PCI bus fault %d : %s\n", ++s_faultcount, s_fault_reason[data >> 1]); // clears PCI bus fault flags __raw_writeb(0x01, REG_BASE_HOST + PCI_host_host_reg2 + 3); __raw_writeb(0x00, REG_BASE_HOST + PCI_host_host_reg2 + 3);}#endifint pci_em86xx_info(void){ uart_puts("EM86XX PCI Host Controller : \n"); return 0;}// return 0 if device not found// return vendorid:deviceid if device foundunsigned int pci_em86xx_select(int idsel){#if defined(CONFIG_ARCH_MAMBO) unsigned int data;#endif unsigned int pciid; g_pci_em86xx_lastidsel = idsel; #if defined(CONFIG_ARCH_MAMBO) __raw_writew((idsel << 8), REG_BASE_HOST + PCI_host_host_reg2); pciid = __raw_readl(MEMORY_BASE_PCI_CONFIG); data = __raw_readl(REG_BASE_HOST + PCI_host_host_reg2); if (((data >> 25) & 0x03) == 0) { return pciid; } else { // clears PCI bus fault flags __raw_writeb(0x01, REG_BASE_HOST + PCI_host_host_reg2 + 3); __raw_writeb(0x00, REG_BASE_HOST + PCI_host_host_reg2 + 3); } return 0;#elif defined(CONFIG_ARCH_TANGO) return (pci_em86xx_read_config_dword(0, &pciid) == 0) ? pciid : 0;#else#error Unknown architecture#endif}//// Bus address translation//#define is_virt_dmable(x) (((x) >= g_pcimem_phyaddr && (x) < g_pcimem_phyaddr_end) ? 1 : 0)#define is_bus_dmable(x) ((((x) - g_pcimem_busaddr) < (g_pcimem_phyaddr_end - g_pcimem_phyaddr)) ? 1 : 0)unsigned int pci_em86xx_virt_to_bus(unsigned int virt){ if (!is_virt_dmable(virt)) { uart_printf("pci_em86xx_virt_to_bus : Invalid virtual address %08x\n", virt); return virt; } else return (virt - g_pcimem_phyaddr + g_pcimem_busaddr);}unsigned int pci_em86xx_bus_to_virt(unsigned int bus){ if (!is_bus_dmable(bus)) { uart_printf("pci_em86xx_bus_to_virt : Invalid bus address %08x\n", bus); return bus; } else return (bus + g_pcimem_phyaddr - g_pcimem_busaddr);}//// Basic //unsigned int pci_em86xx_pciio_base(int idsel){ return MEMORY_BASE_PCI_IO + (idsel * 0x00100000);}unsigned int pci_em86xx_pcimemory_base(int idsel){ return MEMORY_BASE_PCI_MEMORY + (idsel * 0x04000000);}//// primitive PCI configuration I/O//#if defined(CONFIG_ARCH_MAMBO)#define PCIEM86XX_READ_CONFIG_X(x, type, name) \ int pci_em86xx_read_config_##name(unsigned int addr, unsigned type *data) \ { \ *data = __raw_read##x(MEMORY_BASE_PCI_CONFIG + addr); \ return 0; \ }#define PCIEM86XX_WRITE_CONFIG_X(x, type, name) \ int pci_em86xx_write_config_##name(unsigned int addr, unsigned int data) \ { \ __raw_write##x(data, MEMORY_BASE_PCI_CONFIG + addr); \ return 0; \ }#elif defined(CONFIG_ARCH_TANGO)#define PCIEM86XX_READ_CONFIG_X(x, type, name) \ int pci_em86xx_read_config_##name(unsigned int addr, unsigned type *data) \ { \ unsigned int reg; \ *data = __raw_read##x(MEMORY_BASE_PCI_CONFIG + addr + (g_pci_em86xx_lastidsel << 11)); \ reg = __raw_readl(REG_BASE_HOST + PCI_host_host_reg2); \ if (((reg >> 25) & 0x03) == 0) { \ return 0; \ } else { \ /* clears PCI bus fault flags */ \ __raw_writeb(0x01, REG_BASE_HOST + PCI_host_host_reg2 + 3); \ __raw_writeb(0x00, REG_BASE_HOST + PCI_host_host_reg2 + 3); \ return 1; \ } \ }#define PCIEM86XX_WRITE_CONFIG_X(x, type, name) \ int pci_em86xx_write_config_##name(unsigned int addr, unsigned int data) \ { \ unsigned int reg; \ __raw_write##x(data, MEMORY_BASE_PCI_CONFIG + addr + (g_pci_em86xx_lastidsel << 11)); \ reg = __raw_readl(REG_BASE_HOST + PCI_host_host_reg2); \ if (((reg >> 25) & 0x03) == 0) { \ return 0; \ } else { \ /* clears PCI bus fault flags */ \ __raw_writeb(0x01, REG_BASE_HOST + PCI_host_host_reg2 + 3); \ __raw_writeb(0x00, REG_BASE_HOST + PCI_host_host_reg2 + 3); \ return 1; \ } \ }#else#error Unknown architecture#endifPCIEM86XX_READ_CONFIG_X(b, char, byte)PCIEM86XX_READ_CONFIG_X(w, short, word)PCIEM86XX_READ_CONFIG_X(l, int, dword)PCIEM86XX_WRITE_CONFIG_X(b, char, byte)PCIEM86XX_WRITE_CONFIG_X(w, short, word)PCIEM86XX_WRITE_CONFIG_X(l, int, dword)//// primitive PCI I/O, Memory access//#define PCIEM86XX_READ_X(x, type, name) \ unsigned type pci_em86xx_read_##name(unsigned int addr) \ { \ return __raw_read##x(addr); \ } #define PCIEM86XX_WRITE_X(x, type, name) \ void pci_em86xx_write_##name(unsigned int data, unsigned int addr) \ { \ __raw_write##x(data, addr); \ } PCIEM86XX_READ_X(b, char, byte)PCIEM86XX_READ_X(w, short, word)PCIEM86XX_READ_X(l, int, dword)PCIEM86XX_WRITE_X(b, char, byte)PCIEM86XX_WRITE_X(w, short, word)PCIEM86XX_WRITE_X(l, int, dword)//// PCI operation//// DMA Transfer#ifdef CONFIG_ENABLE_FULLFUNCTION// Using SBOX_PCI_MASTER <-- MBUS_R1_SBOXvoid pci_em86xx_dma_write(void *buf, int len, unsigned int addr, int verbose){ int port, irq; unsigned int regbase; em86xx_clean_cache_data_region((unsigned int) buf, (unsigned int) buf + len); em86xx_pcimaster_start_write(0); port = em86xx_mbus_alloc_dma(SBOX_PCIMASTER, 0, ®base, &irq); if (verbose) { uart_puts("Before DMA WRITE transfer...\n"); uart_printf(" SBOX = %08x\n", __raw_readl(REG_BASE_HOST + SBOX_route)); uart_printf(" MBUS regbase = %08x\n", regbase); uart_printf(" MBUS command = %d\n", __raw_readl(regbase + 0x0c)); uart_printf(" PCI write counter = %d\n", __raw_readl(REG_BASE_HOST + PCI_master_write_counter)); } if (__raw_readl(regbase + 0x0c) > 0 || __raw_readl(REG_BASE_HOST + PCI_master_write_counter) > 0) { uart_puts(" Aborting...\n"); __raw_writel(0, regbase + 0x0c); __raw_writel(0, REG_BASE_HOST + PCI_master_write_counter); return; } if (verbose) uart_puts("Start transfer...\n"); em86xx_pcimaster_setup_write(addr, len); em86xx_pcimaster_start_write(1); em86xx_mbus_setup_dma_linear(regbase, (unsigned int) buf, len); // em86xx_msleep(10); while (__raw_readl(REG_BASE_HOST + PCI_master_write_counter) > 0) ; em86xx_mbus_free_dma(port); em86xx_pcimaster_start_write(0); if (verbose) { uart_puts("After DMA WRITE transfer...\n"); uart_printf(" MBUS command = %d\n", __raw_readl(regbase + 0x0c)); uart_printf(" PCI write counter = %d\n", __raw_readl(REG_BASE_HOST + PCI_master_write_counter)); }}void pci_em86xx_dma_read(void *buf, int len, unsigned int addr, int verbose){ int port, irq; unsigned int regbase; em86xx_clean_cache_data_region((unsigned int) buf, (unsigned int) buf + len); em86xx_pcimaster_start_read(0); port = em86xx_mbus_alloc_dma(SBOX_PCIMASTER, 1, ®base, &irq); if (verbose) { uart_puts("Before DMA READ transfer...\n"); uart_printf(" SBOX = %08x\n", __raw_readl(REG_BASE_HOST + SBOX_route)); uart_printf(" MBUS regbase = %08x\n", regbase); uart_printf(" MBUS command = %d\n", __raw_readl(regbase + 0x0c)); uart_printf(" PCI read counter = %d\n", __raw_readl(REG_BASE_HOST + PCI_master_read_counter)); } if (__raw_readl(regbase + 0x0c) > 0 || __raw_readl(REG_BASE_HOST + PCI_master_read_counter) > 0) { uart_puts(" Aborting...\n"); __raw_writel(0, regbase + 0x0c); __raw_writel(0, REG_BASE_HOST + PCI_master_read_counter); return; } if (verbose) uart_puts("Start transfer...\n"); em86xx_mbus_setup_dma_linear(regbase, (unsigned int) buf, len); em86xx_pcimaster_setup_read(addr, len); em86xx_pcimaster_start_read(1); // em86xx_msleep(10); while (__raw_readl(REG_BASE_HOST + PCI_master_read_counter) > 0) ; em86xx_mbus_free_dma(port); em86xx_pcimaster_start_read(0); em86xx_flush_cache_data_region((unsigned int) buf, (unsigned int) buf + len); if (verbose) { uart_puts("After DMA READ transfer...\n"); uart_printf(" MBUS command = %d\n", __raw_readl(regbase + 0x0c)); uart_printf(" PCI read counter = %d\n", __raw_readl(REG_BASE_HOST + PCI_master_read_counter)); }}#endif#ifdef CONFIG_ENABLE_FULLFUNCTIONstatic void pci_em86xx_test_mambo(void) __attribute__ ((unused));static void pci_em86xx_test_mambo(void) { struct my_pci_dev pcidev, *pdev; // look for device pdev = pci_lookup(0x1105, 0, &pcidev); if (pdev && pdev->idsel == 0) pdev = pci_lookup(0x1105, 0, &pcidev); if (pdev == NULL) { uart_puts("No EM86XX found\n"); return; } uart_printf("Found EM86XX PCI device :\n"); uart_printf(" IDSEL = %d, Vendor ID = 0x%04x, Device ID = 0x%04x\n", pdev->idsel, pdev->vendor_id, pdev->device_id); // configure the device pci_configure_device(pdev); uart_printf(" Assign PCI memory space from 0x%08x, size 0x%08x\n", pdev->resource[0].start, pdev->resource[0].size); // enable the device pci_write_config_word(PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);}int pci_em86xx_test(int argc, char *argv[]){ return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -