/*******************************************************************************/ /* */ /* Boot ROM for the Blackfin products and silicon revisions */ /* */ /* ADSP-BF531-0.2 */ /* ADSP-BF532-0.2 */ /* ADSP-BF533-0.2 */ /* */ /* for documentation see application note */ /* */ /* ADSP-BF533 Blackfin® Booting Process (EE-240) */ /* */ /* at http://www.analog.com/ee-notes */ /* */ /* (c) Analog Devices Inc. (2003) */ /* Hiren Desai */ /*******************************************************************************/ #include .EXTERN ldf_stack_end; #define SYSMMR_BASE 0xFFC00000 #define COREMMR_BASE 0xFFE00000 #define L1_Code 0xFFA00000 // L1 Code SRAM #define ASYNC_Bank0 0x20000000 // Async Bank 0 #define SYSCFG_VALUE 0x30 // For Anomaly #22. /*******************************************************************************/ /* */ /* 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; // 0xFF807FE0 .VAR HeaderByteCount; // 0xFF807FE4 .BYTE2 HeaderFlags; // 0xFF807FE8 .BYTE2 TrashCan; // 0xFF807FEA .VAR Reserved[5]; // 0xFF807FEC .SECTION program; .GLOBAL _bootkernel; _bootkernel: /*******************************************************************************/ /* */ /* Initialize global register variables */ /* */ /*******************************************************************************/ L0 = 0x0; L1 = 0x0; L2 = 0x0; L3 = 0x0; r1 = SYSCFG_VALUE; SYSCFG = r1; // For Anomaly #22. SP.H = ldf_stack_end; // Set up supervisor stack in the end of SP.L = ldf_stack_end; // L1 Scratch Memory P0.H = HI(COREMMR_BASE); // P0 Points to the beginning of CORE MMR P0.L = LO(COREMMR_BASE); // Space P1.H = HI(SYSMMR_BASE); // P1 Points to the beginning of SYSTEM MMR P1.L = LO(SYSMMR_BASE); // Space P3.L = HeaderTargetAddress; // P3 Points to the DMA Header Destination. P3.H = HeaderTargetAddress; /*******************************************************************************/ /* */ /* Degrade interrupt level from reset down to IVG15 */ /* Continue to operate in supervisor mode */ /* */ /*******************************************************************************/ P2.L = SERVICE_IVG15; P2.H = SERVICE_IVG15; [P0+LO(EVT15)] = P2; //Place the address of start code in IVG15 of EVT R0 = [P0+LO(IMASK)]; // For testing purposes R1.L = LO(EVT_IVG15); [P0+LO(IMASK)] = R1; // Set(enable) IVG15 RAISE 15; // Invoke IVG15 interrupt P2.L = WAIT_FOR_IVG15; P2.H = WAIT_FOR_IVG15; RETI = P2; // Set Reset Return Address RTI; // Return from Reset Interrupt WAIT_FOR_IVG15: // Wait here till IVG15 interrupt is latched JUMP WAIT_FOR_IVG15; // The only instruction user mode SERVICE_IVG15: [--SP] = RETI; // RETI must be pushed to enable interrupts. P5.L = LO(L1_Code); // Set P5 to the L1 Code SRAM P5.H = HI(L1_Code); /*******************************************************************************/ /* */ /* Test Bit 4 of SYSCR Register whether need to reboot on software reset. */ /* Otherwise bypass boot sequence and jump to reset vector. */ /* */ /*******************************************************************************/ R7 = W[P1+LO(SYSCR)] (Z); CC = BITTST(R7,4); IF CC JUMP SWRESET; // If Software Reset and Bypass Normal Boot // Sequence, Jump to L1 Code SRAM HARD_RESET: R3.H = HI(IWR_ENABLE(21) | IWR_ENABLE(13)); // Enable Wake-Up function R3.L = LO(IWR_ENABLE(21) | IWR_ENABLE(13)); // for MemDMA and SPI DMA [P1+LO(SIC_IWR)] = R3; /*******************************************************************************/ /* */ /* 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 8/16/24-bit SPI Memory */ /* */ /*******************************************************************************/ R1 = 0x000E; // Get Bit Field from SYSCR Register R0 = R7 & R1; R1 = 0x2; CC = R0 == R1; IF CC JUMP FLASH_BOOT; // BMODE = 001, Boot from 8-bit Flash R1 = 0x4; CC = R0 == R1; IF CC JUMP SPI0_BOOT; // BMODE = 010, Boot from 8-bit SPI0 Serial ROM R1 = 0x6; CC = R0 == R1; IF CC JUMP SPI0_BOOT; // BMODE = 011, Boot from 8-/16-/24-bit SPI0 // Serial ROM IDLE; // Should never get 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 */ /* */ /*******************************************************************************/ R6.L = LO(AMBEN_B0); W[P1+LO(EBIU_AMGCTL)] = R6; // Enable External Async Memory Bank 0 R6 = [P1+LO(EBIU_AMBCTL0)]; // Asynchronous Memory Bank Control Register R6.L = 0x0; R7.L = LO(B0RDYPOL | B0HT_3 | B0RAT_15 | B0WAT_15); R7 = R7 | R6; [P1+LO(EBIU_AMBCTL0)] = R7; /*******************************************************************************/ /* */ /* DMA from 8-bit memory reads even address locations only. */ /* */ /*******************************************************************************/ R6 = 0x2 (Z); W[P1+LO(MDMA_S0_X_MODIFY)] = R6; // Source DMA Modify = 2 R6 = 0x1 (Z); W[P1+LO(MDMA_D0_X_MODIFY)] = R6; // Destination DMA Modify = 1 P4.L = ZERO; P4.H = ZERO; R0.L = LO(ASYNC_Bank0); // Boot Stream expected at /MS0 address R0.H = HI(ASYNC_Bank0); // 0x2000.0000 R3.L = WDSIZE_8 | DMAEN; // 0x0001; Source DMA Config R4.L = DI_EN | WDSIZE_8 | WNR | DMAEN; // 0x0083, Destination DMA Config /*******************************************************************************/ /* */ /* 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 */ /* Bit 4: IGNORE */ /* Bits 14-5: reserved */ /* Bits 15: FINAL */ /* */ /*******************************************************************************/ FGRAB_HEADER: R1 = P3; // DMA Destination Address in L1 R2 = 0xA (Z); // Count Value for Header (10 bytes) CALL FDMA; // Do Memory DMA R0 = [P1+LO(MDMA_S0_CURR_ADDR)]; // Get Source Base Address R7 = R0; // and save for zero fill R1 = [P3]; // Get Destination Base Address R2 = [P3+0x4]; // Get Byte Count R5 = W[P3+0x8] (Z); // Get Flag Word /*******************************************************************************/ /* */ /* Test IGNORE Flag . */ /* */ /* If set don't perform further DMA. Only update Next Boot Block Pointer in */ /* R0 by the block's byte count, which is multiplied by 2 in 8-bit boot mode. */ /* */ /*******************************************************************************/ FCHECK_IGNORE_BIT: CC = BITTST(R5,4); IF !CC JUMP FCHECK_INIT_BIT; R2 = R2 << 1; // Multiply address increment by 2 // because of 8-bit data om 16-bit port R0 = R0 + R2; // Update Source Base Address JUMP FGRAB_HEADER; // Jump to get next header, ignore // this one /*******************************************************************************/ /* */ /* Test INIT Flag . */ /* */ /* If set issue a CALL instruction to the blocks target address after having */ /* it booted in. */ /* */ /*******************************************************************************/ FCHECK_INIT_BIT: CC = BITTST(R5,3); IF !CC JUMP FCHECK_ZERO_FILL_BIT; P0 = R1; // Save Target Address for Call CALL FDMA; // Memory DMA of Init Code R0 = [P1+LO(MDMA_S0_CURR_ADDR)]; // Get Source Base Address CALL(P0); // Call Init Code JUMP FGRAB_HEADER; // Jump to get next header /*******************************************************************************/ /* */ /* Test ZEROFILL Flag . */ /* */ /* If set simply patch the MDMA Source Pointer and set Source Modifier zero */ /* */ /*******************************************************************************/ FCHECK_ZERO_FILL_BIT: CC = BITTST(R5,0); IF !CC JUMP FDO_DMA; // Zero Fill? R0 = P4; // Source Base Address = ZERO Location R6 = 0x0; W[P1+LO(MDMA_S0_X_MODIFY)] = R6; // Source Modify = 0 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); // Restore Source Modify to 2 for Zero W[P1+LO(MDMA_S0_X_MODIFY)] = R6; // Fill Case IF CC R0 = R7; // If Zero Fill, Restore R0 to Flash R7 = [P1+LO(MDMA_S0_CURR_ADDR)]; // Memory. Otherwise, IF !CC R0 = R7; // 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 FGRAB_HEADER; // If not, Jump to grab header R3.H = HI(IWR_ENABLE_ALL); // Restore reset value of wake-up R3.L = LO(IWR_ENABLE_ALL); // register [P1+LO(SIC_IWR)] = R3; /*******************************************************************************/ /* */ /* 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); // Test RESVECT IF CC JUMP ADSP_BF533; P5.L = 0x8000; ADSP_BF533: // JUMP to 0xFFA00000 for BF533 JUMP(P5); // JUMP to 0xFFA08000 for BF531/BF532 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: [P1+LO(MDMA_S0_START_ADDR)] = R0; // Set Source Base Address W[P1+LO(MDMA_S0_X_COUNT)] = R2; // Set Source Count W[P1+LO(MDMA_S0_CONFIG)] = R3; // Set Source DMAConfig = DMA Enable, // Memory Read, 16-Bit Transfers, // 1-D DMA, Flow = Stop [P1+LO(MDMA_D0_START_ADDR)] = R1; // Set Destination Base Address W[P1+LO(MDMA_D0_X_COUNT)] = R2; // Set Destination Count W[P1+LO(MDMA_D0_CONFIG)] = 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 R0 = 0x1; W[P1+LO(MDMA_D0_IRQ_STATUS)] = R0; // Write 1 to clear DMA interrupt RTS; FDMA.END: /*******************************************************************************/ /*******************************************************************************/ /* */ /* Boot from SPI memory thread . */ /* */ /*******************************************************************************/ /*******************************************************************************/ .ALIGN 2; SPI0_BOOT: /*******************************************************************************/ /* */ /* Set Bit Rate . */ /* */ /*******************************************************************************/ #ifdef _DSP_MODE_ R1 = 0x0005(Z); // Smaller Value for faster simulation. #else R1 = 0x0085(Z); #endif W[P1+LO(SPI_BAUD)] = R1; // set baud rate register /*******************************************************************************/ /* */ /* Use PF2/SSEL2 as SPI chip select. . */ /* */ /*******************************************************************************/ R1 = 0xFB04(Z); W[P1+LO(SPI_FLG)] = R1; // set SPI0 flag register - use SPISEL2 /*******************************************************************************/ /* */ /* DMA Settings. . */ /* */ /*******************************************************************************/ R6 = 0x1; W[P1+LO(DMA5_X_MODIFY)] = 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 R3 = 0x0(Z); // Initial address of external memory /*******************************************************************************/ /* */ /* Perform autodetection whether 8/16/24-bit device is connected only if */ /* BMODE = 11. If BMODE = 10 always assume 8-bit type of memory. */ /* */ /*******************************************************************************/ CC = BITTST(R7,1); IF !CC JUMP GRAB_HEADER; CALL PART_SELECT; /*******************************************************************************/ /* */ /* 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 */ /* Bit 4: IGNORE */ /* Bits 14-5 reserved */ /* Bits 15: FINAL */ /* */ /*******************************************************************************/ GRAB_HEADER: R1 = P3; // Destination Base Address for header in L1 R2 = 0xA (Z); // Count Value for Header (10 bytes) R5 = 0x0; CALL SPI_DMA; // Call DMA to load header R3 = R3 + R2; // Increment external address by header size R1 = [P3]; // Get Destination Base Address R2 = [P3+0x4]; // Get Byte Count R5 = W[P3+0x8] (Z); // Get Flag Word /*******************************************************************************/ /* */ /* Test IGNORE Flag . */ /* */ /* If set incremenent Source Address Pointer R3 and don't perform any DMA. */ /* */ /*******************************************************************************/ CHECK_IGNORE_BIT: CC = BITTST(R5,4); IF !CC JUMP CHECK_INIT_BIT; R3 = R3 + R2; // Update Source Base Address JUMP GRAB_HEADER; // Jump to get next header, ignore this one /*******************************************************************************/ /* */ /* Test INIT Flag . */ /* */ /* If set DMA data in and issue a CALL instruction to the target address. */ /* */ /*******************************************************************************/ CHECK_INIT_BIT: CC = BITTST(R5,3); IF !CC JUMP CHECK_ZERO_FILL_BIT; CALL SPI_DMA; // DMA Init Code into destination memory R3 = R3 + R2; // Update Source Base address P0 = R1; CALL(P0); // Call Init Code JUMP GRAB_HEADER; // Jump to load next header /*******************************************************************************/ /* */ /* Test ZEROFILL Flag . */ /* */ /* If set perform a Memory DMA rather than an SPI DMA */ /* */ /*******************************************************************************/ CHECK_ZERO_FILL_BIT: CC = BITTST(R5,0); IF !CC JUMP DO_DMA; // Zero Fill? CALL ZERO_DMA; // Memory DMA to zero target CC = BITTST(R5,15); // Last Block? IF CC JUMP BOOT_END; JUMP GRAB_HEADER; // Jump to load next header /*******************************************************************************/ /* */ /* DMA payload data in . */ /* */ /*******************************************************************************/ DO_DMA: CALL SPI_DMA; /*******************************************************************************/ /* */ /* Test FINAL Flag . */ /* */ /* Either fetch next block header or exit and jump to reset vector */ /* */ /*******************************************************************************/ CC = BITTST(R5,15); // Last Block? IF CC JUMP BOOT_END; R3 = R3 + R2; // If no, increment external address by JUMP GRAB_HEADER; // count value and fetch next header SPI_BOOT.END: /*******************************************************************************/ /* */ /* SPI_DMA Subroutine for SPI Boot Modes */ /* */ /* It starts a SPI DMA and wait until it completes */ /* It supports byte counts from 1 to 65536 bytes */ /* */ /*******************************************************************************/ SPI_DMA: R0 = RETS; I0 = R0; CALL SPI_SETUP; [P1+LO(DMA5_START_ADDR)] = R1; // Set Destination Base Address W[P1+LO(DMA5_X_COUNT)] = R2; // Set Destination Count W[P1+LO(DMA5_CONFIG)] = R4; // Set Destination DMAConfig = DMA Enable, // Memory Write, 1-D DMA, Flow = Stop, // Interrupt on completion R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 2); // 0x5C02; W[P1+LO(SPI_CTL)] = R0; // enable SPI, DMA RX mode, 8 bit data IDLE; // Wait for DMA to Complete R0 = 0x1; W[P1+LO(DMA5_IRQ_STATUS)] = R0; // Write 1 to clear DMA interrupt /*******************************************************************************/ /* */ /* Disable SPI Controller and DMA and pause for 500ns */ /* */ /*******************************************************************************/ R0 = 0x0; W[P1+LO(DMA5_CONFIG)] = R0; // Disable DMA R0 = CPHA; // 0x0400; W[P1+LO(SPI_CTL)] = R0; // disable SPI R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear RXS SSYNC; P2.L = 0x01A4; // 500ns at SCLK=600MHz P2.H = 0x0000; LSETUP(DELAY_LOOP, DELAY_LOOP) LC0=P2; DELAY_LOOP: NOP; R0 = I0; RETS = R0; RTS; SPI_DMA.END: /*******************************************************************************/ /* */ /* SPI_SETUP Subroutine for SPI Boot Modes */ /* */ /* Setup SPI Port for DMA transfer or Single word Read */ /* */ /* R3 = Address we want to see in SPI. */ /* R7 = Bit 1 = 0 for 8-bit addressing, 1 for 16-bit addressing */ /* */ /*******************************************************************************/ SPI_SETUP: R0 = RETS; I1 = R0; R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 1); // 0x5C01; W[P1+LO(SPI_CTL)] = R0; // enable SPI, Non-DMA TX mode, 8-bit data R0 = 0x3; W[P1+LO(SPI_TDBR)] = R0; // send out control word CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status CC = BITTST(R7,1); IF CC JUMP SPI_SETUP_11; // if BMODE = 11 SPI_SETUP_10: // if BMODE = 10 W[P1+LO(SPI_TDBR)] = R3; // send out lower address byte to address // eprom CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 0); // 0x5C00; W[P1+LO(SPI_CTL)] = R0; // set TIMOD = 00 for SPI port R0 = I1; RETS = R0; RTS; SPI_SETUP.END: /*******************************************************************************/ /* */ /* ZERO_DMA Subroutine for SPI Boot Modes */ /* */ /* Performs a Memory DMA with Source Address = ZERO and Source Modify = 0 */ /* */ /*******************************************************************************/ ZERO_DMA: R0 = 0x0; W[P1+LO(MDMA_S0_X_MODIFY)] = R0; // Source Modify = 0 R0.L = ZERO; // Address that holds a zero byte R0.H = ZERO; [P1+LO(MDMA_S0_START_ADDR)] = R0; // Set Source Base Address to ZERO W[P1+LO(MDMA_S0_X_COUNT)] = R2; // Set Source Count R0 = R4 >> 16; // Extract R4.H (Config Value) W[P1+LO(MDMA_S0_CONFIG)] = R0; // Set Source DMAConfig = DMA Enable, // Memory Read, 16-Bit Transfers, // 1-D DMA, Flow = Stop R0 = 0x1 (Z); W[P1+LO(MDMA_D0_X_MODIFY)] = R0; // Destination Modify = 1 [P1+LO(MDMA_D0_START_ADDR)] = R1; // Set Destination Base Address W[P1+LO(MDMA_D0_X_COUNT)] = R2; // Set Destination Count W[P1+LO(MDMA_D0_CONFIG)] = R4; // Set Destination DMAConfig = DMA Enable, // Memory Write, 1-D DMA, Flow = Stop, // Interrupt on completion IDLE; // Wait for DMA to Complete R0 = 0x1; W[P1+LO(MDMA_D0_IRQ_STATUS)] = R0; // Write 1 to clear DMA interrupt RTS; ZERO_DMA.END: /*******************************************************************************/ /* */ /* PART_SELECT Subroutine for SPI Boot Mode 11 . */ /* */ /* The following type of SPI devices are supported: */ /* SPI Flash/EEPROM with 8-bit addressing scheme (1 address byte) */ /* SPI Flash/EEPROM with 16-bit addressing scheme (2 address bytes) */ /* SPI Flash/EEPROM with 24-bit addressing scheme (3 address bytes) */ /* */ /* This functionality requires the first byte of the boot stream to be 0x00. */ /* Furthermore there must be a pull-up on the MISO pin. */ /* */ /* Result is returned in R6 as follows */ /* */ /* R6=0: 8-bit device */ /* R6=1: 16-bit device */ /* R6=2: 24-bit device */ /* */ /* */ /*******************************************************************************/ PART_SELECT: R0 = RETS; I0 = R0; R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 1); // 0x5C01; W[P1+LO(SPI_CTL)] = R0; // enable SPI, Non-DMA TX mode, 8 bit R0 = 0x3; W[P1+LO(SPI_TDBR)] = R0; // send out control word CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status W[P1+LO(SPI_TDBR)] = R3; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status W[P1+LO(SPI_TDBR)] = R3; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // read and check if 8-bit part /*******************************************************************************/ /* */ /* An 8-bit device already sent its first data byte which is 0x00 by */ /* definition. A 16-bit device still waits for the second address byte and */ /* tri-states its output pin. */ /* */ /*******************************************************************************/ R6 = 0x0(Z); CC = R0 == R6; IF CC JUMP EIGHT_BIT; W[P1+LO(SPI_TDBR)] = R3; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // read & check if 16-bit part /*******************************************************************************/ /* */ /* Now a 16-bit device sent its first data byte which is 0x00 by */ /* definition. A 24-bit device still waits for the third address byte and */ /* tri-states its output pin. */ /* */ /*******************************************************************************/ CC = R0 == R6; IF CC JUMP SIXTEEN_BIT; W[P1+LO(SPI_TDBR)] = R3; // send out dummy byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // read & check if 24-bit part /*******************************************************************************/ /* */ /* Now also a 24-bit device sent its first data byte which is 0x00 by */ /* definition. If no 0x00 byte is read, then there is either no SPI device */ /* out there or it does not contain a valid boot stream: wait forever. */ /* */ /*******************************************************************************/ CC = R0 == R6; IF CC JUMP TWENTYFOUR_BIT; ERROR: JUMP ERROR; EIGHT_BIT: R6 = 0x0(Z); JUMP PART_SELECT_DONE; SIXTEEN_BIT: R6 = 0x1(Z); JUMP PART_SELECT_DONE; TWENTYFOUR_BIT: R6 = 0x2(Z); JUMP PART_SELECT_DONE; PART_SELECT_DONE: R0 = CPHA; // 0x0400; W[P1+LO(SPI_CTL)] = R0; // disable SPI R0 = W[P1+LO(SPI_RDBR)] (Z); // dummy read to clear RXS SSYNC; P2.L = 0x01A4; // 500ns at 600MHz P2.H = 0x0000; // stay inactive for a while LSETUP(DELAY_LOOP2, DELAY_LOOP2) LC0=P2; DELAY_LOOP2: NOP; R0 = I0; RETS = R0; RTS; PART_SELECT.END: /*******************************************************************************/ /* */ /* SPI_SETUP Subroutine Part 2 for SPI Boot BMODE = 11 */ /* */ /* Send more address bytes */ /* */ /*******************************************************************************/ SPI_SETUP_11: CC = R6 < 1; IF CC JUMP ADDRESS_8; CC = R6 < 2; IF CC JUMP ADDRESS_16; ADDRESS_24: R0 = R3 >> 16; W[P1+LO(SPI_TDBR)] = R0; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status ADDRESS_16: R0 = R3 >> 8; W[P1+LO(SPI_TDBR)] = R0; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status ADDRESS_8: W[P1+LO(SPI_TDBR)] = R3; // send out address byte CALL WAIT_FOR_RXS; // wait until transfer has completed R0 = W[P1+LO(SPI_RDBR)] (Z); // do dummy read to clear status R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 0); // 0x5C00; W[P1+LO(SPI_CTL)] = R0; // set TIMOD = 00 for SPI port R0 = I1; RETS = R0; RTS; SPI_SETUP_11.END: /*******************************************************************************/ /* */ /* WAIT_FOR_RXS Subroutine for SPI Boot Modes */ /* */ /* Waits until SPI transfer complets */ /* */ /*******************************************************************************/ WAIT_FOR_RXS: R0 = W[P1+LO(SPI_STAT)] (Z); CC = bittst(R0,bitpos(RXS)); // test bit 5 of SPI_STAT register IF !CC JUMP WAIT_FOR_RXS; RTS; WAIT_FOR_RXS.END: /*******************************************************************************/ /* */ /* On software resets that don't require booting need to determine reset */ /* vector of the device. This requires an extra access to the boot device. */ /* */ /*******************************************************************************/ SWRESET: R1 = 0x000E; // Test BMODE from SYSCR R0 = R7 & R1; R1 = 0x2; CC = R0 == R1; IF !CC JUMP SPISWRST; // BMODE = 01, Boot from 8-bit Flash /*******************************************************************************/ /* */ /* read Flag word from 8-bit parallel Flash */ /* */ /*******************************************************************************/ P0.H = HI(ASYNC_Bank0); P0.L = 0x10; // read lower byte of first R5 = W[P0] (Z); // Flag word JUMP BOOT_END; /*******************************************************************************/ /* */ /* Read Flag word from 8/16/24-bit SPI memory. This requires a complete new */ /* Initialization of the SPI controller as well as a SPI device type auto */ /* detection sequence. */ /* */ /*******************************************************************************/ SPISWRST: #ifdef _DSP_MODE_ R3 = 0x0005(Z); // Smaller Value for faster simulation. #else R3 = 0x0085(Z); #endif W[P1+LO(SPI_BAUD)] = R3; // set baud rate register R3 = 0xFB04(Z); W[P1+LO(SPI_FLG)] = R3; // set SPI0 flag register - use SPISEL2 R3 = 0x0(Z); // starting from address 0 CALL PART_SELECT; // perfrom device detection R3 = 0x8; // send address 0x0008 CALL SPI_SETUP; // to SPI memory R0 = SPE | MSTR | CPOL | CPHA | (TIMOD & 1); // 0x5C01, enable SPI, W[P1+LO(SPI_CTL)] = R0; // Non-DMA TX mode, 8 bit W[P1+LO(SPI_TDBR)] = R3; // initiate transfer WAIT_FOR_RXS2: R0 = W[P1+LO(SPI_STAT)] (Z); CC = bittst(R0,bitpos(RXS)); // test bit 5 of SPI_STAT IF !CC JUMP WAIT_FOR_RXS2; R5 = W[P1+LO(SPI_RDBR)] (Z); // read lower byte of flag word BOOT_END: R3.H = HI(IWR_ENABLE_ALL); // restore reset value for R3.L = LO(IWR_ENABLE_ALL); // wake-up register [P1+LO(SIC_IWR)] = R3; // enable all peripherals /*******************************************************************************/ /* */ /* Test RESVECT Flag and jump to the respective reset vector. */ /* */ /* ADSP-BF531: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF532: 0xFFA08000 RESVECT = 0 */ /* ADSP-BF533: 0xFFA00000 RESVECT = 1 */ /* */ /* Note that all parts use the identical bootkernel */ /* */ /*******************************************************************************/ CC = BITTST(R5,1); P2.L = LO(L1_Code); P2.H = HI(L1_Code); // JUMP to 0xFFA00000 for BF533 IF CC JUMP ADSP_BF533_SPI; P2.L = 0x8000; // JUMP to 0xFFA08000 for BF531/BF532 ADSP_BF533_SPI: JUMP(P2); nop; nop; nop; nop; nop; nop; nop; nop; /*******************************************************************************/ /* */ /* Zero byte required for ZEROINIT Memory DMA . */ /* */ /*******************************************************************************/ .BYTE ZERO[1] = 0x0; _bootkernel.END: /*******************************************************************************/ /* */ /* end of boot kernel . */ /* */ /*******************************************************************************/