/****************************************************** Title: Example Code To Boot Agent From Host RAM on Sandpoint. Purpose: This example program is meant to demonstrate how to boot an MPC8240/MPC107 based PCI Agent from Host local memory space on the Sandpoint reference platform. Background: DINK32 V12.0 is currently setup up so that once the Host boots up from the DINK image in ROM, it then configures the Agent. Once the Agent is configured, it's PCI Command Register is then set and it is allowed to boot up from the same DINK image in ROM. What this example code does is force the Agent to boot up from code it thinks is in ROM, but is actually in Host local memory space. Assumptions: 1) Running on a Sandpoint Reference Platform. 2) MPC8240/MPC107 based Agent in 32bit PCI slot #4 (Third from PMC). See Note 3 below on using alternate PCI slots. 3) Running DINK32 V12.0 or later. Usage: 1) Compile/Assemble the code below and link into S-Record format downloadable to 0x90000. 2) Download the S-Record to Host local memory using "dl -k" at the Host's DINK32 command prompt. 3) Launch the program using "go 90000" at the Host's DINK32 command prompt. Notes: 1) Usage of this program on the current release of DINK32 V12.0, requires the DINK32 source code to be modified to NOT allow a detected PCI agent to boot up from ROM. This modification will NOT be necessary in the next release of DINK32. The modification is as follows: In the except2.s file, modify the config_kahlua_agent routine by commenting out the store to PCI Command Register (PCICMD) instructions pointed to below... // slave enable: enable memory access in PCI command reg. // since we don't need to configure the ATU, we will // enable PCI master at this time. ori r3,r7,PCICMD li r4,0x0006 // set memory access bit -->// stwbrx r3,0,r5 sync -->// sthbrx r4,0,r6 // write sync 2) In order to use DINK's Dynamic Functions such as printf you must #include dinkusr.h and link dinkusr.s during compilation/link time. Please see DINK32 V12.0 User's Guide Appendix G for more info. 3) Using the other available Sandpoint PCI slots simply requires modifying the configuration address in the pciConfigOutWord() and pciConfigOutHalfWord() routines. Currently the routines are set for 0x800080XX, the configuration address for slot #4 on Sandpoint with the 0xXX representing the config register offset. Please refer to Rev 0.10 or later of the "Sandpoint Motherboard Technical Summary" white paper, Section 1.8 PCI Slot Information. The Configuration Address column of Table 1-1 shows the correct configuration address for each PCI slot. *****************************************************/ /*------- Include --------*/ //See DINK32 V12.0 User's Guide Appendix G on using //DINK's Dynamic Functions such as printf. #include "../../dinkusr.h" /*------- Prototypes -------*/ void main(); /*------- Externs ---------*/ extern void agentBoot(); extern void cacheDisable(); extern void pciConfigOutWord(); extern void pciConfigOutHalfWord(); extern void memcpy(); extern void mmuSetup(); extern void pgmreturn(); /*------ Typedefs ---------*/ typedef unsigned long ULONG; /*------- Defines ---------*/ #define DATA_CACHE 0xFFFFBFFF //to turn off D-Cache #define swapBytes(x) ((((x) & 0x000000ff) << 24)|\ (((x) & 0x0000ff00) << 8) |\ (((x) & 0x00ff0000) >> 8) |\ (((x) & 0xff000000) >> 24)) /*------- C Functions --------*/ /****************************************************** * main: routine to setup on the Agent a 1M Outbound * Translation Window starting at 0xFFF00000 to * translate to 0x00000000. The agent boot up code * is copied to the Host local memory space at * 0x00000100. The Agent is then allowed to begin * fetching instructions from the reset vector * 0xFFF00100, which is translated to 0x00000100 * in the Host's local memory space. * * input: none * output: none *****************************************************/ void main() { //Set up transfer base in order to use DINK's prinf command. //See DINK32 V12.0 User's Guide Appendix G on using //DINK's Dynamic Functions such as printf. set_up_transfer_base(); //Setup DBAT for PCI Space mmuSetup(); //Disable d-cache so agentBoot code will go to memory not cache cacheDisable(DATA_CACHE); //Copy agentBoot code to Host ram at 0x100 memcpy((ULONG)0x100, (ULONG)&agentBoot, (ULONG)0x100); ULONG PCSRBAR = 0xFC100000; ULONG* OTWR = (ULONG*)(PCSRBAR + 0x308); ULONG* OMBAR = (ULONG*)(PCSRBAR + 0x300); //Setup a valid PCSRBAR on Agent pciConfigOutWord(0x14, PCSRBAR); //Enable agent PCI Command Register to respond to memory //accesses before modifying the OTWR and OMBAR on the Agent pciConfigOutHalfWord(0x4, 2); //Setup the Agent's Outbound Translation Window and //Outbound Base Address *OTWR = swapBytes(19); // base = 0, size = 1M *OMBAR = swapBytes(0xFFF00000); //0xFFF00100 is reset address //Enable the agent PCI Command Register as a bus master pciConfigOutHalfWord(0x4, 6); //Wait for Agent to fetch and execute agent boot code while (1){ ULONG* msg = (ULONG*)0x4c04; if (*msg == 777) { printf("Agent: boot success.\n"); break; } } printf("Returning to DINK via exception handler.\n"); pgmreturn(); //return to dink via exception handler //Until the next DINK32 release, this is how //we safely return to DINK. } /**************** end main ***************************/ /*----------- ASM Functions --------*/ /****************************************************** * agentBoot: agent boot code to be copied to Host Ram. * * *****************************************************/ .text .align 2 .global agentBoot agentBoot: lis r9,0xfff0 //setup an address in the ori r9,r9,0x4c00 //outbound translation window addi r0,0,777 //load a value stw r0,4(r9) //store value ori 0,0,0 //no-op ori 0,0,0 //no-op b agentBoot /******************** end agentBoot ******************/ /****************************************************** * cacheDisable: disable cache * input: HID0 mask value in r3 * output: none *****************************************************/ .text .align 2 .global cacheDisable cacheDisable: mfspr r4,1008 //load HID0 and r4,r4,r3 //and w/ input mask mtspr 1008,r4 //store HID0 blr /***************** end cacheDisable *****************/ /****************************************************** * memcpy: copy agentBoot code to memory * input: r3 contains address to copy to * r4 contains address to copy from * r5 contains copy length * output: none *****************************************************/ .text .align 2 .global memcpy memcpy: addi r3,r3,-4 //start load/store address addi r4,r4,-4 //one word back to use stwu, lwzu loop1: lwzu r6,4(r4) //load word stwu r6,4(r3) //store word addic. r5,r5,-1 //decrement counter bne loop1 blr /******************* end memcpy *********************/ /****************************************************** * pciConfigOutHalfWord: write given data half word to * given config register. * input: r3 contains config address offset * r4 contains config data * output: none *****************************************************/ .text .align 2 .global pciConfigOutHalfWord pciConfigOutHalfWord: lis r5,0x8000 //load config_addr for PCI Slot 4 ori r5,r5,0x8000 //on Sandpoint or r3,r3,r5 //attach config register offset lis r5,0xfec0 //load config_addr_reg location ori r5,r5,0x0cf8 lis r6,0xfee0 //load config_data_reg location ori r6,r6,0x0cfc stwbrx r3,0,r5 //store config_addr sync sthbrx r4,0,r6 //store config_data sync blr /**************** end pciConfigOutHalfWord *****************/ /****************************************************** * pciConfigOutLong: write given data word to given * config register. * input: r3 contains config address offset * r4 contains config data * output: none *****************************************************/ .text .align 2 .global pciConfigOutWord pciConfigOutWord: lis r5,0x8000 //load config_addr for PCI Slot 4 ori r5,r5,0x8000 //on Sandpoint or r3,r3,r5 //attach config register offset lis r5,0xfec0 //load config_addr_reg location ori r5,r5,0x0cf8 lis r6,0xfee0 //load config_data_reg location ori r6,r6,0x0cfc stwbrx r3,0,r5 //store config_addr sync stwbrx r4,0,r6 //store config_data sync blr /**************** end pciConfigOutWord *****************/ /****************************************************** * pgmreturn: program return via DINK exception handler. * Take an illegal opcode exception. * Until the next DINK32 release, this is how * we safely return to DINK. * input: none * output: none *****************************************************/ .text .align 2 .global pgmreturn pgmreturn: b illegal_op //branch to illegal opcode /**************** end pgmreturn *****************/ /****************************************************** * mmuSetup: set up DBAT3 for PCI memory space * * input: none * output: none *****************************************************/ .text .align 2 .global mmuSetup mmuSetup: mfmsr r3 //turn off tranlations lis r4,0xffff //disable IR and DR in MSR ori r4,r4,0xffcf and r3,r3,r4 mtmsr r3 isync xor r3,r3,r3 mtspr 542,r3 //Clear upper DBAT3 lis r3,0xFC00 //PCI space lower DBAT3 ori r3,r3,0x001A //R/W, Cachable lis r4,0xFC00 //PCI space upper DBAT3 ori r4,r4,0x1fff //map 1MB mtspr 543,r3 //DBAT3L mtspr 542,r4 //DBAT3U isync mfmsr r3 //turn on translations ori r3,r3,0x0030 mtmsr r3 isync blr /**************** end mmuSetup *****************/ /****** Data Section ********/ .data .align 2 illegal_op: .long 0x00000000