/*******************************************************************************/ /* */ /* Boot ROM for the Blackfin products and silicon revisions */ /* */ /* ADSP-BF531-0.1 */ /* ADSP-BF532-0.1 */ /* ADSP-BF533-0.1 */ /* */ /* for documentation see application note */ /* */ /* ADSP-BF533 Blackfin® Booting Process (EE-240) */ /* */ /* at http://www.analog.com/ee-notes */ /* */ /* (c) Analog Devices Inc. (2002) */ /* Hiren Desai */ /*******************************************************************************/ #include #define L1_DataBA 0xFF800000 // L1 Data Bank A #define L1_DataBB 0xFF900000 // L1 Data Bank B #define L1_Code 0xFFA00000 // L1 Code SRAM #define ASYNC_Bank0 0x20000000 // Async Bank 0 #define Stack_END 0xFFBFFFFC /*******************************************************************************/ /* */ /* Data section for intermediate storage of DMA headers. */ /* These 32 address locations must not be used by the application, or at */ /* least they cannot be initialized at boot time */ /* */ /*******************************************************************************/ .SECTION tempdata; .VAR HeaderTargetAddress; // 0xFF900000 .VAR HeaderByteCount; // 0xFF900004 .BYTE2 HeaderFlags; // 0xFF900008 .BYTE2 Reerved1; // 0xFF90000A .VAR Reserved[1]; // 0xFF90000C .SECTION program; .GLOBAL _bootkernel; _bootkernel: /*******************************************************************************/ /* */ /* Initialize global register variables */ /* */ /*******************************************************************************/ L0 = 0x0; L1 = 0x0; L2 = 0x0; L3 = 0x0; SP.L = LO(Stack_END); // Set up supervisor stack in the end of SP.H = HI(Stack_END); // L1 Scratch Memory P0.L = LO(EVT0); // Point to the Event Vector Table P0.H = HI(EVT0); P1.L = SERVICE_IVG15; P1.H = SERVICE_IVG15; [P0+0x3C] = P1; // Place the address of start code in EVT15 P1.L = DMA_INT; P1.H = DMA_INT; [P0+0x34] = P1; // Place the address of MemDMA ISR in EVT13 [P0+0x28] = P1; // Place the address of MemDMA ISR in EVT9 P0.L = LO(IMASK); R0 = [P0]; // For testing purposes R1.L = LO(EVT_IVG15 | EVT_IVG13 | EVT_IVG10); [P0] = R1; // Set(enable) IVG15, IVG13, and IVG9 in FCIC // Interrupt Mask Register /*******************************************************************************/ /* */ /* Degrade interrupt level from reset down to IVG15 */ /* Continue to operate in supervisor mode */ /* */ /*******************************************************************************/ RAISE 15; // Invoke IVG15 interrupt P0.L = WAIT_FOR_IVG15; P0.H = WAIT_FOR_IVG15; RETI = P0; // Set Reset Return Address RTI; // Return from Reset Interrupt WAIT_FOR_IVG15: // Wait here till IVG15 interrupt is JUMP WAIT_FOR_IVG15; // processed SERVICE_IVG15: [--SP] = RETI; // RETI must be pushed to enable interrupts. // Boot code in supervisor mode starts here. /*******************************************************************************/ /* */ /* Test Bit 4 of SYSCR Register whether need to reboot on software reset. */ /* Otherwise bypass boot sequence and jump to reset vector. */ /* */ /*******************************************************************************/ P5.L = LO(L1_Code); // Set P5 to the L1 Code SRAM P5.H = HI(L1_Code); P3.L = LO(SYSCR); // System Reset Configuration Register P3.H = HI(SYSCR); R0 = W[P3] (Z); CC = BITTST(R0,4); IF !CC JUMP HARD_RESET; JUMP (P5); // If Software Reset and Bypass Normal Boot // Sequence, Jump to L1 Code SRAM HARD_RESET: // Test BMODE Pins /*******************************************************************************/ /* */ /* Test BMODE pins and jump to respective boot threads */ /* */ /* BMODE[1:0] = 00 Bypass (no-boot) mode, bootkernel is not even invoked */ /* 01 Boot from 8-bit parallel Flash */ /* 10 Boot from 8-bit SPI Serial Memory */ /* 11 Boot from 16-bit SPI Serial Memory */ /* */ /*******************************************************************************/ R1 = 0x000E; R0 = R0 & R1; R1 = 0x2; CC = R0 == R1; IF CC JUMP FLASH_BOOT; // BMODE = 001, Boot from 8-bit Flash R1 = 0x4; CC = R0 == R1; R7 = 0x0; IF CC JUMP SPI0_BOOT; // BMODE = 010, Boot from 8-bit SPI0 ROM R1 = 0x6; CC = R0 == R1; R7 = 0x1; IF CC JUMP SPI0_BOOT; // BMODE = 011, Boot from 16-bit SPI0 ROM IDLE; // otherwise hang here /*******************************************************************************/ /*******************************************************************************/ /* */ /* Boot from 8-bit parallel flash thread . */ /* */ /*******************************************************************************/ /*******************************************************************************/ .ALIGN 2; FLASH_BOOT: /*******************************************************************************/ /* */ /* Configure EBIU Port for Async Bank 0 (/MS0) */ /* */ /* 3 Hold Cycles (Max), 15 Wait States (Max), */ /* 15 Cycles for Read Access Time (Max), ADRDY polarity = 1 */ /* */ /*******************************************************************************/ P3.H = HI(EBIU_AMGCTL); P3.L = LO(EBIU_AMGCTL); // Asynchronous Memory Global Control Register R6.L = LO(AMBEN_B0); R6.H = HI(AMBEN_B0); [P3] = R6; // Enable External Async Memory Bank 0 P3.L = LO(EBIU_AMBCTL0); // Asynchronous Memory Bank Control Register R6 = [P3]; R6.L = 0x0; R7.L = LO(B0RDYPOL | B0HT_3 | B0RAT_15 | B0WAT_15); R7 = R7 | R6; [P3] = R7; /*******************************************************************************/ /* */ /* DMA from 8-bit memory reads even address locations only. */ /* */ /*******************************************************************************/ P0.L = LO(MDMA_S0_START_ADDR); // MDMA Source Registers P0.H = HI(MDMA_S0_START_ADDR); P1.L = LO(MDMA_D0_START_ADDR); // MDMA Destination Registers P1.H = HI(MDMA_D0_START_ADDR); R6 = 0x2 (Z); W[P0+0x10] = R6; // Source Modify = 2 R6 = 0x1 (Z); W[P1+0x10] = R6; // Destination Modify = 1 P3.L = HeaderTargetAddress; P3.H = HeaderTargetAddress; P4.L = ZERO; P4.H = ZERO; R0.L = LO(ASYNC_Bank0); R0.H = HI(ASYNC_Bank0); R3.L = 0x1; // Source DMAConfig Value (8-bit words) R4.L = 0x83; // Destination DMAConfig Value (8-bit words) /*******************************************************************************/ /* */ /* Parse Boot Stream Block by Block . */ /* */ /* First DMA 10-bytes header in and evaluate flags */ /* */ /* Bit 0: ZEROFILL */ /* Bit 1: RESVECT */ /* Bit 2: reserved */ /* Bit 3: INIT (not supported by this version yet) */ /* Bit 4: IGNORE (not supported by this version yet) */ /* Bits 14-5: reserved */ /* Bits 15: FINAL */ /* */ /*******************************************************************************/ FGRAB_HEADER: R1 = P3; // DMA Destination Address R2 = 0xA (Z); // Count Value for Header CALL FDMA; R0 = [P0+0x20]; // Get Source Base Address R7 = R0; // and save for zero fill R1 = [P3]; // Get Destination Base Address R2 = [P3+0x4]; // Get Count R5 = W[P3+0x8] (Z); // Get Flag /*******************************************************************************/ /* */ /* Test ZEROFILL Flag . */ /* */ /* If set simply patch the MDMA Source Pointer and set Source Modifier zero */ /* */ /*******************************************************************************/ CC = BITTST(R5,0); IF !CC JUMP FDO_DMA; // Zero Fill? R0 = P4; // Source Base Address = ZERO Location R6 = 0x0; W[P0+0x10] = R6; // Source Modify = 0 for Zero Fill FDO_DMA: /*******************************************************************************/ /* */ /* Finally perform the Memory DMA . */ /* */ /*******************************************************************************/ CALL FDMA; /*******************************************************************************/ /* */ /* Restore all registers that have potentially been patched: . */ /* DMA source modify is 2 for 8-bit mode */ /* R0 points to Next Boot Block again */ /* */ /*******************************************************************************/ R6 = 0x2 (Z); W[P0+0x10] = R6; // Restore Source Modify to 2 for Zero Fill Case IF CC R0 = R7; // If Zero Fill, Restore R0 to Flash Memory R7 = [P0+0x20]; IF !CC R0 = R7; // If Not Zero Fill, R0 = Current Source Base // Address /*******************************************************************************/ /* */ /* Test FINAL Flag . */ /* */ /* Either fetch next block header or exit and jump to reset vector */ /* */ /*******************************************************************************/ CC = BITTST(R5,15); // Last Section? IF !CC JUMP FNEXT_HEADER; /*******************************************************************************/ /* */ /* Test RESVECT Flag . */ /* */ /* Before jumping to reset vector determine part the code is running on. */ /* Note that all parts use the identical bootkernel. Therefore the reset */ /* is encoded by the RESVECT bit of the boot stream's Flag word. */ /* */ /* ADSP-BF531: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF532: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF533: 0xFFA00000 RESVECT = 1 */ /* */ /*******************************************************************************/ CC = BITTST(R5,1); P5.L = LO(L1_Code); // Set P5 to the L1 Code SRAM P5.H = HI(L1_Code); IF CC JUMP ADSP_BF533; P5.L = 0x8000; ADSP_BF533: JUMP(P5); // JUMP to 0xFFA00000 for BF533 // JUMP to 0xFFA08000 for BF531/BF532 FNEXT_HEADER: JUMP FGRAB_HEADER; // If not FINAL fetch next block header FLASH_BOOT.END: /*******************************************************************************/ /* */ /* FDMA Subroutine for Flash Boot Mode . */ /* */ /* Sets up a MDMA sequence and waits until MDMA is done. */ /* This functions is used to fetch block headers, to boot payload data, as */ /* well as to perform zero-initialization. */ /* */ /* Supports byte counts from 1 to 65536. */ /* */ /*******************************************************************************/ FDMA: [P0] = R0; // Set Source Base Address W[P0+0xC] = R2; // Set Source Count W[P0+0x4] = R3; // Set Source DMAConfig = DMA Enable, Memory Read, // 16-Bit Transfers, 1-D DMA, Flow = Stop [P1] = R1; // Set Destination Base Address W[P1+0xC] = R2; // Set Destination Count W[P1+0x4] = R4; // Set Destination DMAConfig = DMA Enable, // Memory Write, 16-Bit Transfers, 1-D DMA, // Flow = Stop, Interrupt on Completion IDLE; // Wait for DMA to Complete RTS; FDMA.END: /*******************************************************************************/ /* */ /* DMA_INT MDMA Interrupt Service Routine for Flash Boot Mode . */ /* */ /* Simply clears the MDMA interrupt request by a W1C operation. */ /* */ /*******************************************************************************/ DMA_INT: R0 = 0x1; W[P1+0x24] = R0; // Write 1 to clear DMA interrupt RTI; // RTI from MemDMA Interrupt DMA_INT.END: /*******************************************************************************/ /* */ /* Zero byte required for ZEROINIT Memory DMA . */ /* */ /*******************************************************************************/ .BYTE ZERO[1] = 0x0; /*******************************************************************************/ /*******************************************************************************/ /* */ /* Boot from SPI memory thread . */ /* */ /*******************************************************************************/ /*******************************************************************************/ .ALIGN 2; SPI0_BOOT: /*******************************************************************************/ /* */ /* Set Bit Rate . */ /* */ /*******************************************************************************/ P3.L = LO(SPI_BAUD); P3.H = HI(SPI_BAUD); R1.L = 0x0085; W[P3] = R1; // set baud rate register /*******************************************************************************/ /* */ /* Use PF2/SSEL2 as SPI chip select. . */ /* */ /*******************************************************************************/ P3.L = LO(SPI_FLG); R1 = 0xFF04(Z); W[P3] = R1; // set SPI0 flag register - use SPISEL2 /*******************************************************************************/ /* */ /* Enable SPI for master mode and DMA transfer mode with receive . */ /* */ /*******************************************************************************/ P3.L = LO(SPI_CTL); R1 = W[P3] (Z); // for test purposes R2 = LO(SPE|CPOL|CPHA|MSTR|0x2); W[P3] = R2; /*******************************************************************************/ /* */ /* Set chip select. . */ /* */ /*******************************************************************************/ P3.L = LO(SPI_FLG); R1 = 0xFB04(Z); W[P3] = R1; P4.L = LO(SPI_TDBR); P4.H = HI(SPI_TDBR); P5.L = LO(SPI_RDBR); P5.H = HI(SPI_RDBR); /*******************************************************************************/ /* */ /* DMA Settings. . */ /* */ /*******************************************************************************/ P1.L = LO(DMA5_START_ADDR); // DMA SPI Registers P1.H = HI(DMA5_START_ADDR); R6 = 0x1; W[P1+0x10] = R6; // Destination Modify = 1 R4.L = DI_EN | WDSIZE_8 | WNR | DMAEN; // 0x0083, SPI DMA Config R4.H = WDSIZE_8 | DMAEN; // 0x0001; Source DMA Config for // Zero Fill operation P3.L = HeaderTargetAddress; // DMA Destination Address to store header P3.H = HeaderTargetAddress; R3 = 0x0(Z); // Initial address of external memory /*******************************************************************************/ /* */ /* Parse Boot Stream Block by Block . */ /* */ /* First DMA 10-bytes header in and evaluate flags */ /* */ /* Bit 0: ZEROFILL */ /* Bit 1: RESVECT */ /* Bits 14-2 reserved */ /* Bits 15: FINAL */ /* */ /*******************************************************************************/ GRAB_HEADER: R1 = P3; // Destination Base Address for header R2 = 0xA (Z); // Count Value for Header R5 = 0x0; CALL DMA; // Call DMA to get header R3 = R3 + R2; // Increment external address by header R1 = [P3]; // Get Destination Base Address R2 = [P3+0x4]; // Get Count R5 = W[P3+0x8] (Z); // Get Flag /*******************************************************************************/ /* */ /* Test ZEROFILL Flag . */ /* */ /* If set perform a Memory DMA rather than an SPI DMA */ /* */ /*******************************************************************************/ CC = BITTST(R5,0); IF !CC JUMP DO_DMA; // Zero Fill? P0.L = LO(MDMA_S0_START_ADDR); // Switch over to MemDMA for Zero Fill P0.H = HI(MDMA_S0_START_ADDR); P1.L = LO(MDMA_D0_START_ADDR); P1.H = HI(MDMA_D0_START_ADDR); R6 = 0x0; W[P0+0x10] = R6; // Source Modify = 0 for Zero Fill DO_DMA: /*******************************************************************************/ /* */ /* DMA payload data in . */ /* */ /*******************************************************************************/ CALL DMA; /*******************************************************************************/ /* */ /* Test FINAL Flag . */ /* */ /* Either fetch next block header or exit and jump to reset vector */ /* */ /*******************************************************************************/ CC = BITTST(R5,15); // Last Section? IF !CC JUMP NEXT_HEADER; /*******************************************************************************/ /* */ /* Test RESVECT Flag . */ /* */ /* Before jumping to reset vector determine part the code is running on. */ /* Note that all parts use the identical bootkernel. Therefore the reset */ /* is encoded by the RESVECT bit of the boot stream's Flag word. */ /* */ /* ADSP-BF531: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF532: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF533: 0xFFA00000 RESVECT = 1 */ /* */ /*******************************************************************************/ P2.L = LO(L1_Code); // Set P5 to the L1 Code SRAM P2.H = HI(L1_Code); IF CC JUMP ADSP_BF533_SPI; P2.L = 0x8000; ADSP_BF533_SPI: JUMP(P2); // JUMP to 0xFFA00000 for BF533 // JUMP to 0xFFA08000 for BF531/BF532 /*******************************************************************************/ /* */ /* If not FINAL, switch back to SPI DMA and fetch next block header . */ /* */ /*******************************************************************************/ NEXT_HEADER: R3 = R3 + R2; // Increment external address by count value P1.L = LO(DMA5_START_ADDR); P1.H = HI(DMA5_START_ADDR); JUMP GRAB_HEADER; SPI0_BOOT.END: /*******************************************************************************/ /* */ /* DMA Subroutine for SPI Boot Mode . */ /* */ /* Starts either an SPI DMA or a MDMA for ZEROFILL */ /* */ /* Supports byte counts from 1 to 65536. */ /* */ /*******************************************************************************/ DMA: R6 = RETS; R0 = 0x3; W[P4] = R0; // send out control word CALL READ_TEST; R0 = W[P5] (Z); // do dummy read W[P4] = R3; // send out byte to address eprom CALL READ_TEST; R0 = W[P5] (Z); // do dummy read CC = BITTST(R7,0); IF !CC JUMP CONT3; R0 = R3 >> 16; W[P4] = R0; // send out another byte to address CALL READ_TEST; // 16-bit device R0 = W[P5] (Z); // do dummy read CONT3: R0 = 0x0; // send out dummy zero for first data read W[P4] = R0; // and then kick off DMA CALL READ_TEST; CC = BITTST(R5,0); // If ZEROFILL do MDMA IF !CC JUMP SPI_DMA; // otherwise SPI DMA R0.L = ZERO; // MDMA source address R0.H = ZERO; [P0] = R0; // Set Source Base Address W[P0+0xC] = R2; // Set Source Count R0 = R4 >> 16; // Extract R4.H W[P0+0x4] = R0; // Set Source DMAConfig = DMA Enable, // Memory Read, 16-Bit Transfers, 1-D DMA, // Flow = Stop SPI_DMA: [P1] = R1; // Set Destination Base Address W[P1+0xC] = R2; // Set Destination Count W[P1+0x4] = R4; // Set Destination DMAConfig = DMA Enable, // Memory Write, 1-D DMA, Flow = Stop, // Interrupt on Completion IDLE; // Wait for DMA to Complete RETS = R6; RTS; DMA.END: /*******************************************************************************/ /* */ /* READ_TEST Subroutine for SPI Boot Mode . */ /* */ /* Waits untils SPI RXS bit is set. */ /* */ /*******************************************************************************/ READ_TEST: P2.L = LO(SPI_STAT); P2.H = HI(SPI_STAT); R0 = W[P2] (Z); CC = BITTST(R0,5); // Test RXS bit IF !CC JUMP READ_TEST; RTS; READ_TEST.END: END: nop; _bootkernel.END: /*******************************************************************************/ /* */ /* end of boot kernel . */ /* */ /*******************************************************************************/