//Mailbox Read Steps: //1. Interrupt going from the QCA4002 to the SPI host. //2. INTERNAL read from INTR_CAUSE register. //3. INTERNAL read from RDBUF_BYTE_AVA register. //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. //6. INTERNAL write to DMA_SIZE register with the packet size. //7. Start DMA read command and start reading the data by de-asserting chip select pin. //8. The packet available will be cleared by HW at the end of the DMA read. // AJ_EXPORT AJ_Status AJ_WSL_ReadFromMBox(uint8_t box, uint16_t* len, uint8_t** buf) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t cause = 0; uint16_t bytesInBuffer = 0; uint16_t bytesToRead = 0; uint16_t lookAhead; uint16_t payloadLength; AJ_ASSERT(0 == box); AJ_EnterCriticalRegion(); //2. INTERNAL read from INTR_CAUSE register. do { //3. INTERNAL read from RDBUF_BYTE_AVA register. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, &bytesInBuffer); AJ_ASSERT(status == AJ_OK); //bytesInBuffer = CPU_TO_BE16(bytesInBuffer); // The first few bytes of the packet can now be examined and the right amount of data read from the target //4. Internal read from RDBUF_LOOKAHEAD1 register //5. Internal read from RDBUF_LOOKAHEAD2 register. From the 4 bytes we have read from RDBUF_LOOKAHEAD registers, get the packet size. status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD1, &lookAhead); AJ_ASSERT(status == AJ_OK); lookAhead = CPU_TO_BE16(lookAhead); status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_LOOKAHEAD2, &payloadLength); AJ_ASSERT(status == AJ_OK); payloadLength = CPU_TO_BE16(payloadLength); // calculate number of bytes to read from the lookahead info, and round up to the next block size bytesToRead = payloadLength + 6; //sizeof(header); bytesToRead = ((bytesToRead / AJ_WSL_MBOX_BLOCK_SIZE) + ((bytesToRead % AJ_WSL_MBOX_BLOCK_SIZE) ? 1 : 0)) * AJ_WSL_MBOX_BLOCK_SIZE; *buf = (uint8_t*)AJ_WSL_Malloc(bytesToRead); *len = bytesToRead; //6. INTERNAL write to DMA_SIZE register with the packet size. // write size to be transferred status = AJ_WSL_SetDMABufferSize(bytesToRead); AJ_ASSERT(status == AJ_OK); AJ_WSL_SPI_ReadIntoBuffer(bytesToRead, buf); // clear the packet available interrupt cause = 0x1; status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, cause); AJ_ASSERT(status == AJ_OK); break; } while (0); AJ_LeaveCriticalRegion(); return status; }
AJ_Status AJ_WSL_GetReadBufferSpaceAvailable(uint16_t* spaceAvailable) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t space = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_RDBUF_BYTE_AVA, &space); *spaceAvailable = space & ((1 << 12) - 1); return status; }
AJ_Status AJ_WSL_GetWriteBufferSpaceAvailable(uint16_t* spaceAvailable) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t space = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, &space); *spaceAvailable = space & ((1 << 12) - 1); AJ_InfoPrintf(("write buffer space available: %x %d\n", space, *spaceAvailable)); return status; }
AJ_Status AJ_WSL_GetDMABufferSize(uint16_t* dmaSize) { AJ_Status status = AJ_ERR_SPI_READ; uint16_t size = 0; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_DMA_SIZE, &size); *dmaSize = size & ((1 << 12) - 1); return status; }
static void set_SPI_registers(void) { volatile uint16_t spi_API = 0; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // reset the target // spi_API = (1 << 15); // AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); // AJ_Sleep(1 << 22); // one extra write to force the device out of the reset state. spi_API = 0x80; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); AJ_Sleep(100); // write spi_API = 0x80; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_SPI_CONFIG, spi_API); // AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_CONFIG was %04x\n", spi_API)); AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&spi_API); spi_API = LE16_TO_CPU(spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_WRBUF_SPC_AVA was %04x\n", spi_API)); spi_API = 0x40; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_WRBUF_WATERMARK, spi_API); // AJ_InfoPrintf(("AJ_WSL_SPI_REG_SPI_CONFIG was %04x\n", spi_API)); spi_API = 0x400; // same as capture AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_CAUSE was %04x\n", spi_API)); spi_API = 0x3ff; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x0e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x1e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x0; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); spi_API = 0x1e; AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API); AJ_InfoPrintf(("AJ_WSL_SPI_REG_INTR_ENABLE was %04x\n", spi_API)); AJ_Sleep(100); }
void AJ_WSL_HTC_ProcessInterruptCause(void) { uint16_t cause = 0; AJ_Status status = AJ_ERR_SPI_READ; status = AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_INTR_CAUSE, (uint8_t*)&cause); AJ_ASSERT(status == AJ_OK); cause = LE16_TO_CPU(cause); if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE) { AJ_WSL_HTC_ProcessIncoming(); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE; //clear the bit } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_READ_DONE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_WRITE_DONE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_CPU_AWAKE; } if (cause & AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER) { uint16_t clearCause = CPU_TO_LE16(AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER); status = AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, clearCause); AJ_ASSERT(status == AJ_OK); cause = cause ^ AJ_WSL_SPI_REG_INTR_CAUSE_COUNTER; } if (cause & ~AJ_WSL_SPI_REG_INTR_CAUSE_DATA_AVAILABLE) { //AJ_InfoPrintf(("Some other interrupt cause as well %x\n", cause)); } }
AJ_Status AJ_WSL_SPI_HostControlRegisterRead(uint32_t targetRegister, uint8_t increment, uint16_t cbLen, uint8_t* spi_data) { aj_spi_status rc; wsl_spi_command send; AJ_Status status = AJ_ERR_SPI_WRITE; uint8_t pcs = AJ_WSL_SPI_PCS; // write the size AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, cbLen | (increment ? 0 : 0x40)); // now send the host_control_config register update { uint16_t externalRegister = 0; externalRegister = (1 << 15) | (0 << 14) | (targetRegister); // external access, write, counter dec externalRegister = CPU_TO_LE16(externalRegister); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_CONFIG, externalRegister); } // get the spi status { uint16_t spi_16 = 0; AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_STATUS, (uint8_t*)&spi_16); spi_16 = LE16_TO_CPU(spi_16); } // initialize an SPI CMD structure with the register of interest send.cmd_rx = AJ_WSL_SPI_READ; send.cmd_reg = AJ_WSL_SPI_INTERNAL; send.cmd_addr = AJ_WSL_SPI_REG_HOST_CTRL_RD_PORT; // write the register, one byte at a time, in the right order rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *((uint8_t*)&send + 1), AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); // toss. AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, *(uint8_t*)&send, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); // toss. AJ_ASSERT(rc == SPI_OK); // now, read the data back if (rc == SPI_OK) { while ((rc == SPI_OK) && (cbLen > 1)) { /* Test read: should return OK with what is sent. */ rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0, AJ_WSL_SPI_PCS, AJ_WSL_SPI_CONTINUE); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); AJ_ASSERT(rc == SPI_OK); spi_data++; cbLen = cbLen - 1; } if (rc == SPI_OK) { rc = AJ_SPI_WRITE(AJ_WSL_SPI_DEVICE, 0, AJ_WSL_SPI_PCS, AJ_WSL_SPI_END); AJ_ASSERT(rc == SPI_OK); rc = AJ_SPI_READ(AJ_WSL_SPI_DEVICE, spi_data, &pcs); AJ_ASSERT(rc == SPI_OK); } if (rc == SPI_OK) { status = AJ_OK; } } // clear the rd/wr buffer interrupt { uint16_t spi_16 = 0x300; spi_16 = CPU_TO_LE16(spi_16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_16); } return status; }
static void write_BOOT_PARAM(void) { uint32_t spi_API = 0; uint16_t spi_API16 = 0; AJ_AlwaysPrintf(("\n\n**************\nTEST: %s\n\n", __FUNCTION__)); // read the clock speed value spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_CLOCK_SPEED_ADDR; //0x00428878; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); //AJ_InfoPrintf(("cycles read back was %ld \n", spi_API)); // read the flash is present value { // let's try this dance of writing multiple times... spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_FLASH_PRESENT_ADDR; //0x0042880C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); //AJ_InfoPrintf(("host if flash is present read back was %ld \n", spi_API)); } // now write out the flash_is_present value spi_API = 0x00000002; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_FLASH_PRESENT_ADDR; //0x0042880C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_WRITE, TRUE, 4, (uint8_t*)&spi_API); // read the mbox block size spi_API = 0x88888888; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 1, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x42424242; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 2, FALSE, 4, (uint8_t*)&spi_API); spi_API = 0x00000000; AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ + 3, FALSE, 4, (uint8_t*)&spi_API); spi_API = AJ_WSL_SPI_TARGET_MBOX_BLOCKSZ_ADDR; //0x0042886C; spi_API = CPU_TO_LE32(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_TARGET_ADDR_READ, TRUE, 4, (uint8_t*)&spi_API); // now read back the value from the data port. AJ_WSL_SPI_HostControlRegisterRead(AJ_WSL_SPI_TARGET_VALUE, TRUE, 4, (uint8_t*)&spi_API); spi_API = LE32_TO_CPU(spi_API); AJ_WSL_MBOX_BLOCK_SIZE = spi_API; //AJ_InfoPrintf(("block size was %ld \n", spi_API)); spi_API16 = 0x001f; spi_API16 = CPU_TO_LE16(spi_API16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_ENABLE, spi_API16); // wait until the write has been processed. spi_API16 = 0; while (!(spi_API16 & 1)) { AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_SPI_STATUS, (uint8_t*)&spi_API16); spi_API16 = LE16_TO_CPU(spi_API16); uint16_t space = 0; AJ_WSL_SPI_RegisterRead(AJ_WSL_SPI_REG_WRBUF_SPC_AVA, (uint8_t*)&space); } // clear the read and write interrupt cause register spi_API = (1 << 9) | (1 << 8); spi_API = CPU_TO_LE16(spi_API); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_INTR_CAUSE, spi_API); { spi_API16 = 0x1; spi_API16 = CPU_TO_LE16(spi_API16); AJ_WSL_SPI_RegisterWrite(AJ_WSL_SPI_REG_HOST_CTRL_BYTE_SIZE, spi_API16); // waiting seems to allow the following write to succeed and thus enable interrupts. // we need something more deterministic. AJ_Sleep(1000); spi_API16 = 0x00FF; spi_API = CPU_TO_LE16(spi_API); AJ_WSL_SPI_HostControlRegisterWrite(AJ_WSL_SPI_CPU_INT_STATUS, FALSE, 1, (uint8_t*)&spi_API16); } }