static uint32_t pci_scan( uint32_t handle, pci_scan_helper_t helper, void *arg ) { uint32_t vendor; uint8_t bus; uint8_t dev; uint8_t fun; uint8_t hd; bus = PCIB_DEVSIG_BUS( (unsigned long)handle ); dev = PCIB_DEVSIG_DEV( (unsigned long)handle ); fun = PCIB_DEVSIG_FUNC( (unsigned long)handle ); hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1; for (; bus<pci_bus_count(); bus++, dev=0) { for (; dev<PCI_MAX_DEVICES; dev++, fun=0) { for (; fun<hd; fun++) { /* * The last devfn id/slot is special; must skip it */ if ((PCI_MAX_DEVICES-1 == dev) && (PCI_MAX_FUNCTIONS-1 == fun) ) break; (void)pci_read_config_dword(bus, dev, 0, PCI_VENDOR_ID, &vendor); if (PCI_INVALID_VENDORDEVICEID == vendor) continue; if ( fun == 0 ) { pci_read_config_byte(bus,dev, 0, PCI_HEADER_TYPE, &hd); hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1); } (void)pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &vendor); if (PCI_INVALID_VENDORDEVICEID == vendor) continue; #ifdef PCI_DEBUG fprintf( stderr, "pci_scan: found 0x%08" PRIx32 " at %d/x%02x/%d\n", vendor, bus, dev, fun ); #endif if ( (*helper)(bus, dev, fun, arg) > 0 ) { if ( ++fun >= hd ) { fun = 0; if ( ++dev >= PCI_MAX_DEVICES ) { dev = 0; bus++; } } return PCIB_DEVSIG_MAKE(bus,dev,fun); } } } } return 0; }
void pci_list_devices( void ) { uint32_t d; unsigned char bus,dev,fun,hd; printk( "BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 " "BASE_ADDR1 IRQ_PIN -> IRQ_LINE\n" ); for (bus=0 ; bus<pci_bus_count(); bus++) { for (dev=0 ; dev<PCI_MAX_DEVICES; dev++) { for (fun=0 ; fun<PCI_MAX_FUNCTIONS; fun++) { /* * The last devfn id/slot is special; must skip it */ if (PCI_MAX_DEVICES-1==dev && PCI_MAX_FUNCTIONS-1 == fun) break; (void) pci_read_config_dword(bus,dev,0,PCI_VENDOR_ID,&d); if (PCI_INVALID_VENDORDEVICEID == d) continue; if ( 0 == fun ) { pci_read_config_byte(bus,dev,0, PCI_HEADER_TYPE, &hd); hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1); } (void)pci_read_config_dword(bus,dev,fun,PCI_VENDOR_ID,&d); if (PCI_INVALID_VENDORDEVICEID == d) continue; print_device_config( bus, dev, fun ); } } } }
static int pci_summary(void) { char *str; char *cfglib_strs[5] = {"NONE", "AUTO", "STATIC", "READ", "PERIPHERAL"}; if (pci_system_type == PCI_SYSTEM_HOST) str = "HOST"; else if (pci_system_type == PCI_SYSTEM_PERIPHERAL) str = "PERIPHERAL"; else str = "UNKNOWN / UNINITIALIZED"; printf(" SYSTEM: %s\n", str); if (pci_config_lib_type > PCI_CONFIG_LIB_PERIPHERAL) { puts(" Bad configuration library"); return 1; } printf(" CFG LIBRARY: %s\n", cfglib_strs[pci_config_lib_type]); printf(" NO. PCI BUSES: %d buses\n", pci_bus_count()); printf(" PCI ENDIAN: %s\n", pci_endian ? "Big" : "Little"); #if (CPU_LITTLE_ENDIAN == TRUE) puts(" MACHINE ENDIAN: Little"); #else puts(" MACHINE ENDIAN: Big"); #endif return 0; }
/* This is a very ugly hack. I don't want to change the shared * code to support multiple hoses so we hide everything under * the hood with horrible kludges for now. Sorry. */ void BSP_pci_initialize(void) { #if 0 /* These values are already set up for the shared/pci.c code */ { extern pci_config_access_functions pci_indirect_functions; /* by means of the PCI_CONFIG_ADDR/PCI_CONFIG_DATA macros (bsp.h) */ BSP_pci_configuration.pci_config_addr = hoses[0].pci_config_addr; BSP_pci_configuration.pci_config_data = hoses[0].pci_config_data; BSP_pci_configuration.pci_functions = &pci_indirect_functions; } #endif /* initialize the first hose */ /* scan hose 0 and sets the maximum bus number */ pci_initialize(); /* remember the boundary */ BSP_pci_hose1_bus_base = pci_bus_count(); /* so far, so good -- now comes the cludgy part: */ /* hack/reset the bus count */ ucMaxPCIBus = 0; /* scan hose 1 */ BSP_pci_configuration.pci_config_addr = hoses[1].pci_config_addr; BSP_pci_configuration.pci_config_data = hoses[1].pci_config_data; pci_initialize(); /* check for overflow of an unsigned char */ if ( BSP_pci_hose1_bus_base + pci_bus_count() > 255 ) { BSP_panic("Too many PCI busses in the system"); } /* readjust total number */ ucMaxPCIBus+=BSP_pci_hose1_bus_base; /* install new access functions that can hide the hoses */ BSP_pci_configuration.pci_config_addr = (volatile unsigned char *)0xdeadbeef; BSP_pci_configuration.pci_config_data = (volatile unsigned char *)0xdeadbeef; BSP_pci_configuration.pci_functions = &pci_hosed_indirect_functions; }
static int FindPCIbridge( int mybus, struct pcibridge *pb ) { int pbus, pslot; uint8_t bussec, buspri; uint16_t devid, vendorid, dclass; for(pbus=0; pbus< pci_bus_count(); pbus++) { for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++) { pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid); if ( devid == 0xffff ) continue; pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid); if ( vendorid == 0xffff ) continue; pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass); if ( dclass == PCI_CLASS_BRIDGE_PCI ) { pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS, &buspri); pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec); #ifdef SHOW_PCI_SETTING printk("pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ", pbus, pslot, mybus, buspri, bussec ); #endif if ( bussec == mybus ) { #ifdef SHOW_PCI_SETTING printk("match\n"); #endif /* found our nearest bridge going towards the root */ pb->bus = pbus; pb->slot = pslot; return 0; } #ifdef SHOW_PCI_SETTING printk("no match\n"); #endif } } } return -1; }
int pci_for_each(int (*func)(pci_dev_t, void*), void *arg) { uint32_t id; uint8_t hd; int bus, dev, fun, result, fail; int maxbus = pci_bus_count(); pci_dev_t pcidev; for (bus = 0; bus < maxbus ; bus++) { for (dev = 0; dev < PCI_MAX_DEVICES; dev++) { pcidev = PCI_DEV(bus, dev, 0); for (fun = 0; fun < PCI_MAX_FUNCTIONS; fun++, pcidev++) { fail = pci_cfg_r32(pcidev, PCI_VENDOR_ID, &id); if (fail || (0xffffffff == id) || (0 == id)) { if (fun == 0) break; else continue; } DBG("pcibus_for_each: found 0x%08lx at" " %d/%d/%d\n", id, bus, dev, fun); result = func(pcidev, arg); if (result != 0) return result; /* Stopped */ /* Stop if not a multi-function device */ if (fun == 0) { pci_cfg_r8(pcidev, PCI_HEADER_TYPE, &hd); if ((hd & PCI_MULTI_FUNCTION) == 0) break; } } } } return 0; /* scanned all */ }
void bsp_start( void ) { #ifdef CONF_VPD int i; #endif #ifdef SHOW_LCR1_REGISTER unsigned l1cr; #endif #ifdef SHOW_LCR2_REGISTER unsigned l2cr; #endif #ifdef SHOW_LCR3_REGISTER unsigned l3cr; #endif uintptr_t intrStackStart; uintptr_t intrStackSize; ppc_cpu_id_t myCpu; ppc_cpu_revision_t myCpuRevision; Triv121PgTbl pt=0; /* Till Straumann: 4/2005 * Need to map the system registers early, so we can printk... * (otherwise we silently die) */ /* * Kate Feng : PCI 0 domain memory space, want to leave room for the VME window */ setdbat(2, PCI0_MEM_BASE, PCI0_MEM_BASE, 0x10000000, IO_PAGE); /* Till Straumann: 2004 * map the PCI 0, 1 Domain I/O space, GT64260B registers * and the reserved area so that the size is the power of 2. * 2009 : map the entire 256 M space * */ setdbat(3,PCI0_IO_BASE, PCI0_IO_BASE, 0x10000000, IO_PAGE); /* * Get CPU identification dynamically. Note that the get_ppc_cpu_type() function * store the result in global variables so that it can be used latter... */ myCpu = get_ppc_cpu_type(); myCpuRevision = get_ppc_cpu_revision(); #ifdef SHOW_LCR1_REGISTER l1cr = get_L1CR(); printk("Initial L1CR value = %x\n", l1cr); #endif /* * Initialize the interrupt related settings. */ intrStackStart = (uintptr_t) __rtems_end; intrStackSize = rtems_configuration_get_interrupt_stack_size(); /* * Initialize default raw exception handlers. */ ppc_exc_initialize( PPC_INTERRUPT_DISABLE_MASK_DEFAULT, intrStackStart, intrStackSize ); /* * Init MMU block address translation to enable hardware * access * More PCI1 memory mapping to be done after BSP_pgtbl_activate. */ printk("-----------------------------------------\n"); printk("Welcome to %s on MVME5500-0163\n", _RTEMS_version ); printk("-----------------------------------------\n"); BSP_mem_size = probeMemoryEnd(); /* TODO: calculate the BSP_bus_frequency using the REF_CLK bit * of System Status register */ /* rtems_bsp_delay_in_bus_cycles are defined in registers.h */ BSP_bus_frequency = 133333333; BSP_processor_frequency = 1000000000; /* P94 : 7455 clocks the TB/DECR at 1/4 of the system bus clock frequency */ BSP_time_base_divisor = 4000; /* Maybe not setup yet becuase of the warning message */ /* Allocate and set up the page table mappings * This is only available on >604 CPUs. * * NOTE: This setup routine may modify the available memory * size. It is essential to call it before * calculating the workspace etc. */ pt = BSP_pgtbl_setup(&BSP_mem_size); if (!pt) printk("WARNING: unable to setup page tables.\n"); printk("Now BSP_mem_size = 0x%x\n",BSP_mem_size); /* P94 : 7455 TB/DECR is clocked by the system bus clock frequency */ bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000); /* * Initalize RTEMS IRQ system */ BSP_rtems_irq_mng_init(0); #ifdef SHOW_LCR2_REGISTER l2cr = get_L2CR(); printk("Initial L2CR value = %x\n", l2cr); #endif #ifdef SHOW_LCR3_REGISTER /* L3CR needs DEC int. handler installed for bsp_delay()*/ l3cr = get_L3CR(); printk("Initial L3CR value = %x\n", l3cr); #endif /* Activate the page table mappings only after * initializing interrupts because the irq_mng_init() * routine needs to modify the text */ if (pt) { #ifdef SHOW_MORE_INIT_SETTINGS printk("Page table setup finished; will activate it NOW...\n"); #endif BSP_pgtbl_activate(pt); } /* Read Configuration Vital Product Data (VPD) */ if ( I2Cread_eeprom(0xa8, 4,2, &ConfVPD_buff[0], 150)) printk("I2Cread_eeprom() error \n"); else { #ifdef CONF_VPD printk("\n"); for (i=0; i<150; i++) { printk("%2x ", ConfVPD_buff[i]); if ((i % 20)==0 ) printk("\n"); } printk("\n"); #endif } /* * PCI 1 domain memory space */ setdbat(1, PCI1_MEM_BASE, PCI1_MEM_BASE, 0x10000000, IO_PAGE); #ifdef SHOW_MORE_INIT_SETTINGS printk("Going to start PCI buses scanning and initialization\n"); #endif pci_initialize(); #ifdef SHOW_MORE_INIT_SETTINGS printk("Number of PCI buses found is : %d\n", pci_bus_count()); #endif /* Install our own exception handler (needs PCI) */ globalExceptHdl = BSP_exceptionHandler; /* clear hostbridge errors. MCP signal is not used on the MVME5500 * PCI config space scanning code will trip otherwise :-( */ _BSP_clear_hostbridge_errors(0, 1 /*quiet*/); #ifdef SHOW_MORE_INIT_SETTINGS printk("MSR %x \n", _read_MSR()); printk("Exit from bspstart\n"); #endif }
void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) ) { unsigned char cvalue; uint16_t devid; int ismatch, i, j, pbus, pslot, pfun, int_pin, int_name, nfuns; /* * If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific * INTERRUPT_NAME if one isn't already in place. Then, drivers can * trivially use INTERRUPT_NAME to hook up with devices. */ for (pbus=0; pbus< pci_bus_count(); pbus++) { for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) { pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid); if ( devid == 0xffff ) continue; /* got a device */ pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue); nfuns = cvalue & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1; for (pfun=0; pfun< nfuns; pfun++) { pci_read_config_word(pbus, pslot, pfun, PCI_DEVICE_ID, &devid); if( devid == 0xffff ) continue; pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_PIN, &cvalue); int_pin = cvalue; pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue); int_name = cvalue; /* printk("pci : device %d:0x%02x:%i devid %04x, intpin %d, intline %d\n", pbus, pslot, pfun, devid, int_pin, int_name ); */ #ifdef SHOW_PCI_SETTING { unsigned short cmd,stat; unsigned char lat, seclat, csize; pci_read_config_word(pbus,pslot,pfun,PCI_COMMAND, &cmd ); pci_read_config_word(pbus,pslot,pfun,PCI_STATUS, &stat ); pci_read_config_byte(pbus,pslot,pfun,PCI_LATENCY_TIMER, &lat ); pci_read_config_byte(pbus,pslot,pfun,PCI_SEC_LATENCY_TIMER, &seclat ); pci_read_config_byte(pbus,pslot,pfun,PCI_CACHE_LINE_SIZE, &csize ); printk("pci : device %d:0x%02x:%d cmd %04X, stat %04X, latency %d, " " sec_latency %d, clsize %d\n", pbus, pslot, pfun, cmd, stat, lat, seclat, csize); } #endif if ( int_pin > 0 ) { ismatch = 0; /* * first run thru the bspmap table and see if we have an * explicit configuration */ for (i=0; bspmap[i].bus > -1; i++) { if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) { ismatch = -1; /* we have a record in the table that gives specific * pins and interrupts for devices in this slot */ if ( int_name == 255 ) { /* find the vector associated with whatever pin the * device gives us */ for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ) { if ( bspmap[i].pin_route[j].pin == int_pin ) { int_name = bspmap[i].pin_route[j].int_name[0]; break; } } if ( int_name == -1 ) { printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled int " "pin %i to an interrupt_line.\n", pbus, pslot, pfun, int_pin ); } else { PRINT_MSG(); pci_write_config_byte( pbus,pslot,pfun, PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue)); } } else { test_intname( &bspmap[i],pbus,pslot,pfun,int_pin,int_name); } break; } } if ( !ismatch ) { /* * no match, which means we're on a bus someplace. Work * backwards from it to one of our defined busses, * swizzling thru each bridge on the way. */ /* keep pbus, pslot pointed to the device being * configured while we track down the bridges using * tbus,tslot. We keep searching the routing table because * we may end up finding our bridge in it */ int tbus= pbus, tslot= pslot; for (;;) { for (i=0; bspmap[i].bus > -1; i++) { if ( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) ) { ismatch = -1; /* found a record for this bus, so swizzle the * int_pin which we then use to find the * interrupt_name. */ if ( int_name == 255 ) { /* * FIXME. I can't believe this little hack * is right. It does not yield an error in * convienently simple situations. */ if ( tbus ) int_pin = (*swizzler)(tslot,int_pin); /* * int_pin points to the interrupt channel * this card ends up delivering interrupts * on. Find the int_name servicing it. */ for (int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++){ if ( bspmap[i].pin_route[j].pin == int_pin ) { int_name = bspmap[i].pin_route[j].int_name[0]; break; } } if ( int_name == -1 ) { printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled " "int pin %i to an interrupt_line.\n", pbus, pslot, pfun, int_pin ); } else { PRINT_MSG(); pci_write_config_byte(pbus,pslot,pfun, PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue)); } } else { test_intname(&bspmap[i],pbus,pslot,pfun,int_pin,int_name); } goto donesearch; } } if ( !ismatch ) { struct pcibridge pb; /* * Haven't found our bus in the int map, so work * upwards thru the bridges till we find it. */ if ( FindPCIbridge( tbus, &pb )== 0 ) { int_pin = (*swizzler)(tslot,int_pin); /* our next bridge up is on pb.bus, pb.slot- now * instead of pointing to the device we're * trying to configure, we move from bridge to * bridge. */ tbus = pb.bus; tslot = pb.slot; } else { printk("pci : No bridge from bus %i towards root found\n", tbus ); goto donesearch; } } } } donesearch: if ( !ismatch && int_pin != 0 && int_name == 255 ) { printk("pci : Unable to match device %d:0x%02x:%d with an int " "routing table entry\n", pbus, pslot, pfun ); } } } } } }
void BSP_motload_pci_fixup(void) { uint32_t b0,b1,r0,r1,lim,dis; /* MotLoad on the mvme5500 and mvme6100 configures the PCI * busses nicely, i.e., the values read from the memory address * space BARs by means of PCI config cycles directly reflect the * CPU memory map. Thus, the presence of two hoses is already hidden. * * Unfortunately, all PCI I/O addresses are 'zero-based' i.e., * a hose-specific base address would have to be added to * the values read from config space. * * We fix this here so I/O BARs also reflect the CPU memory map. * * Furthermore, the mvme5500 uses * f000.0000 * ..f07f.ffff for PCI-0 / hose0 * * and * * f080.0000 * ..f0ff.0000 for PCI-1 / hose 0 * * whereas the mvme6100 does it the other way round... */ b0 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Low_Decode) ); b1 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Low_Decode) ); r0 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap) ); r1 = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap) ); switch ( BSP_getDiscoveryVersion(0) ) { case MV_64360: /* In case of the MV64360 the 'limit' is actually a 'size'! * Disable by setting special bits in the 'BAR disable reg'. */ dis = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL) ); /* disable PCI0 I/O and PCI1 I/O */ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis | (1<<9) | (1<<14) ); /* remap busses on hose 0; if the remap register was already set, assume * that someone else [such as the bootloader] already performed the fixup */ if ( (b0 & 0xffff) && 0 == (r0 & 0xffff) ) { rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xffff)<<16 ); out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xffff) ); } /* remap busses on hose 1 */ if ( (b1 & 0xffff) && 0 == (r1 & 0xffff) ) { rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xffff)<<16 ); out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xffff) ); } /* re-enable */ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis ); break; case GT_64260_A: case GT_64260_B: if ( (b0 & 0xfff) && 0 == (r0 & 0xfff) ) { /* base are only 12 bits */ /* switch window off by setting the limit < base */ lim = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode) ); out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), 0 ); /* remap busses on hose 0 */ rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xfff)<<20 ); /* BTW: it seems that writing the base register also copies the * value into the 'remap' register automatically (??) */ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xfff) ); /* re-enable */ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), lim ); } if ( (b1 & 0xfff) && 0 == (r1 & 0xfff) ) { /* base are only 12 bits */ /* switch window off by setting the limit < base */ lim = in_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode) ); out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), 0 ); /* remap busses on hose 1 */ rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xfff)<<20 ); out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xfff) ); /* re-enable */ out_le32( (volatile unsigned*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), lim ); } break; default: BSP_panic("Unknown discovery version; switch in file: "__FILE__" not implemented (yet)"); break; /* never get here */ } /* Fixup the IRQ lines; the mvme6100 maps them nicely into our scheme, i.e., GPP * interrupts start at 64 upwards * * The mvme5500 is apparently initialized differently :-(. GPP interrupts start at 0 * Since all PCI interrupts are wired to GPP we simply check for a value < 64 and * reprogram the interrupt line register. */ BSP_pciScan(0, fixup_irq_line, 0); }
void VIA_isa_bridge_interrupts_setup(void) { pci_isa_bridge_device pci_dev; uint32_t temp; unsigned char tmp; unsigned char maxBus; unsigned found = 0; maxBus = pci_bus_count(); pci_dev.function = 0; /* Assumes the bidge is the first function */ for (pci_dev.bus = 0; pci_dev.bus < maxBus; pci_dev.bus++) { #ifdef SCAN_PCI_PRINT printk("isa_bridge_interrupts_setup: Scanning bus %d\n", pci_dev.bus); #endif for (pci_dev.device = 0; pci_dev.device < PCI_MAX_DEVICES; pci_dev.device++) { #ifdef SCAN_PCI_PRINT printk("isa_bridge_interrupts_setup: Scanning device %d\n", pci_dev.device); #endif pci_read_config_dword(pci_dev.bus, pci_dev.device, pci_dev.function, PCI_VENDOR_ID, &temp); #ifdef SCAN_PCI_PRINT printk("Vendor/device = %x\n", temp); #endif if ((temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16))) ) { bridge = pci_dev; via_82c586 = &bridge; #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS /* * Should print : bus = 0, device = 11, function = 0 on a MCP750. */ printk("Via PCI/ISA bridge found at bus = %d, device = %d, function = %d\n", via_82c586->bus, via_82c586->device, via_82c586->function); #endif found = 1; goto loop_exit; } } } loop_exit: if (!found) BSP_panic("VIA_82C586 PCI/ISA bridge not found!n"); tmp = inb(0x810); if ( !(tmp & 0x2)) { #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk("This is a second generation MCP750 board\n"); printk("We must reprogram the PCI/ISA bridge...\n"); #endif pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x47, &tmp); #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); #endif /* * Enable 4D0/4D1 ISA interrupt level/edge config registers */ tmp |= 0x20; pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x47, tmp); /* * Now program the ISA interrupt edge/level */ tmp = ELCRS_INT9_LVL | ELCRS_INT10_LVL | ELCRS_INT11_LVL; outb(tmp, ISA8259_S_ELCR); tmp = ELCRM_INT5_LVL; outb(tmp, ISA8259_M_ELCR);; /* * Set the Interrupt inputs to non-inverting level interrupt */ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x54, &tmp); #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); #endif tmp = 0; pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x54, tmp); } else { #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk("This is a first generation MCP750 board\n"); printk("We just show the actual value used by PCI/ISA bridge\n"); #endif pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x47, &tmp); #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); #endif /* * Show the Interrupt inputs inverting/non-inverting level status */ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, 0x54, &tmp); #ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); #endif } }
void bsp_start( void ) { rtems_status_code sc = RTEMS_SUCCESSFUL; #if !defined(mvme2100) unsigned l2cr; #endif uintptr_t intrStackStart; uintptr_t intrStackSize; ppc_cpu_id_t myCpu; ppc_cpu_revision_t myCpuRevision; prep_t boardManufacturer; motorolaBoard myBoard; Triv121PgTbl pt=0; /* * Get CPU identification dynamically. Note that the get_ppc_cpu_type() * function store the result in global variables so that it can be used * later... */ myCpu = get_ppc_cpu_type(); myCpuRevision = get_ppc_cpu_revision(); /* * Init MMU block address translation to enable hardware access */ #if !defined(mvme2100) /* * PC legacy IO space used for inb/outb and all PC compatible hardware */ setdbat(1, _IO_BASE, _IO_BASE, 0x10000000, IO_PAGE); #endif /* * PCI devices memory area. Needed to access OpenPIC features * provided by the Raven * * T. Straumann: give more PCI address space */ setdbat(2, PCI_MEM_BASE+PCI_MEM_WIN0, PCI_MEM_BASE+PCI_MEM_WIN0, 0x10000000, IO_PAGE); /* * Must have acces to open pic PCI ACK registers provided by the RAVEN */ setdbat(3, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); #if defined(mvme2100) /* Need 0xfec00000 mapped for this */ EUMBBAR = get_eumbbar(); #endif /* * enables L1 Cache. Note that the L1_caches_enables() codes checks for * relevant CPU type so that the reason why there is no use of myCpu... */ L1_caches_enables(); #if !defined(mvme2100) /* * Enable L2 Cache. Note that the set_L2CR(L2CR) codes checks for * relevant CPU type (mpc750)... */ l2cr = get_L2CR(); #ifdef SHOW_LCR2_REGISTER printk("Initial L2CR value = %x\n", l2cr); #endif if ( (! (l2cr & 0x80000000)) && ((int) l2cr == -1)) set_L2CR(0xb9A14000); #endif /* * Initialize the interrupt related settings. */ intrStackStart = (uintptr_t) __rtems_end; intrStackSize = rtems_configuration_get_interrupt_stack_size(); /* * Initialize default raw exception handlers. */ sc = ppc_exc_initialize( PPC_INTERRUPT_DISABLE_MASK_DEFAULT, intrStackStart, intrStackSize ); if (sc != RTEMS_SUCCESSFUL) { BSP_panic("cannot initialize exceptions"); } select_console(CONSOLE_LOG); /* * We check that the keyboard is present and immediately * select the serial console if not. */ #if defined(BSP_KBD_IOBASE) { int err; err = kbdreset(); if (err) select_console(CONSOLE_SERIAL); } #else select_console(CONSOLE_SERIAL); #endif boardManufacturer = checkPrepBoardType(&residualCopy); if (boardManufacturer != PREP_Motorola) { printk("Unsupported hardware vendor\n"); while (1); } myBoard = getMotorolaBoard(); printk("-----------------------------------------\n"); printk("Welcome to %s on %s\n", _RTEMS_version, motorolaBoardToString(myBoard)); printk("-----------------------------------------\n"); #ifdef SHOW_MORE_INIT_SETTINGS printk("Residuals are located at %x\n", (unsigned) &residualCopy); printk("Additionnal boot options are %s\n", loaderParam); printk("Initial system stack at %x\n",stack); printk("Software IRQ stack starts at %x with size %u\n", intrStackStart, intrStackSize); printk("-----------------------------------------\n"); #endif #ifdef TEST_RETURN_TO_PPCBUG printk("Hit <Enter> to return to PPCBUG monitor\n"); printk("When Finished hit GO. It should print <Back from monitor>\n"); debug_getc(); _return_to_ppcbug(); printk("Back from monitor\n"); _return_to_ppcbug(); #endif /* TEST_RETURN_TO_PPCBUG */ #ifdef SHOW_MORE_INIT_SETTINGS printk("Going to start PCI buses scanning and initialization\n"); #endif pci_initialize(); { const struct _int_map *bspmap = motorolaIntMap(currentBoard); if( bspmap ) { printk("pci : Configuring interrupt routing for '%s'\n", motorolaBoardToString(currentBoard)); FixupPCI(bspmap, motorolaIntSwizzle(currentBoard)); } else printk("pci : Interrupt routing not available for this bsp\n"); } #ifdef SHOW_MORE_INIT_SETTINGS printk("Number of PCI buses found is : %d\n", pci_bus_count()); #endif #ifdef TEST_RAW_EXCEPTION_CODE printk("Testing exception handling Part 1\n"); /* * Cause a software exception */ __asm__ __volatile ("sc"); /* * Check we can still catch exceptions and return coorectly. */ printk("Testing exception handling Part 2\n"); __asm__ __volatile ("sc"); /* * Somehow doing the above seems to clobber SPRG0 on the mvme2100. The * interrupt disable mask is stored in SPRG0. Is this a problem? */ ppc_interrupt_set_disable_mask( PPC_INTERRUPT_DISABLE_MASK_DEFAULT); #endif /* See above */ BSP_mem_size = residualCopy.TotalMemory; BSP_bus_frequency = residualCopy.VitalProductData.ProcessorBusHz; BSP_processor_frequency = residualCopy.VitalProductData.ProcessorHz; BSP_time_base_divisor = (residualCopy.VitalProductData.TimeBaseDivisor? residualCopy.VitalProductData.TimeBaseDivisor : 4000); /* clear hostbridge errors but leave MCP disabled - * PCI config space scanning code will trip otherwise :-( */ _BSP_clear_hostbridge_errors(0 /* enableMCP */, 0/*quiet*/); /* Allocate and set up the page table mappings * This is only available on >604 CPUs. * * NOTE: This setup routine may modify the available memory * size. It is essential to call it before * calculating the workspace etc. */ pt = BSP_pgtbl_setup(&BSP_mem_size); if (!pt || TRIV121_MAP_SUCCESS != triv121PgTblMap( pt, TRIV121_121_VSID, 0xfeff0000, 1, TRIV121_ATTR_IO_PAGE, TRIV121_PP_RW_PAGE)) { printk("WARNING: unable to setup page tables VME " "bridge must share PCI space\n"); } /* * initialize the device driver parameters */ bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000); /* * Initalize RTEMS IRQ system */ BSP_rtems_irq_mng_init(0); /* Activate the page table mappings only after * initializing interrupts because the irq_mng_init() * routine needs to modify the text */ if (pt) { #ifdef SHOW_MORE_INIT_SETTINGS printk("Page table setup finished; will activate it NOW...\n"); #endif BSP_pgtbl_activate(pt); /* finally, switch off DBAT3 */ setdbat(3, 0, 0, 0, 0); } #if defined(DEBUG_BATS) ShowBATS(); #endif #ifdef SHOW_MORE_INIT_SETTINGS printk("Exit from bspstart\n"); #endif }