__irq void irq_handler(void) #endif { UINT32 intr_stat = GETREG(APB_INT_STS); if (intr_stat & (INTR_TIMER_1 | INTR_TIMER_2 | INTR_TIMER_3)) { g_timer_interrupt_count++; CLEAR_TIMER_INTR(TIMER_CH1); CLEAR_TIMER_INTR(TIMER_CH2); CLEAR_TIMER_INTR(TIMER_CH3); SETREG(APB_INT_STS, INTR_TIMER_1 | INTR_TIMER_2 | INTR_TIMER_3); } else if (intr_stat & INTR_FLASH) { ftl_isr(); } else if (intr_stat & INTR_SDRAM) { UINT32 sdram_interrupt = GETREG(SDRAM_INTSTATUS); SETREG(SDRAM_INTSTATUS, 0xFFFFFFFF); // clear the DRAM interrupt flag at the interrupt controller SETREG(APB_INT_STS, INTR_SDRAM); if (sdram_interrupt & SDRAM_INT_ECC_CORR) { // Bit errors were detected and corrected. // Usually this is NOT an indication of poor SDRAM quality. // If the firmware has a bug due to which SDRAM is written by CPU without the help of mem util functions, // ECC correction or ECC failure can happen. g_sdram_ecc_count++; } if (sdram_interrupt & SDRAM_INT_ECC_FAIL) { // Bit errors were detected but could not be corrected. g_sdram_ecc_fail_count++; } if (sdram_interrupt & SDRAM_INT_ADDR_OF) { // There was an attempt to access beyond DRAM address boundary. uart_printf("Error: SDRAM interrupt occred: attempt to access beyond DRAM address boundary"); led_blink(); } } }
void ftl_write(UINT32 const lba, UINT32 const total_sectors) { UINT32 num_sectors_to_write; UINT32 sect_offset = lba % SECTORS_PER_PAGE; UINT32 remain_sectors = total_sectors; while (remain_sectors != 0) { if (sect_offset + remain_sectors >= SECTORS_PER_PAGE) { num_sectors_to_write = SECTORS_PER_PAGE - sect_offset; } else { num_sectors_to_write = remain_sectors; } while (g_ftl_write_buf_id == GETREG(SATA_WBUF_PTR)); // bm_write_limit should not outpace SATA_WBUF_PTR g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS; // Circular buffer SETREG(BM_STACK_WRSET, g_ftl_write_buf_id); // change bm_write_limit SETREG(BM_STACK_RESET, 0x01); // change bm_write_limit sect_offset = 0; remain_sectors -= num_sectors_to_write; } }
void ftl_read(UINT32 const lba, UINT32 const total_sectors) { UINT32 num_sectors_to_read; UINT32 lpage_addr = lba / SECTORS_PER_PAGE; // logical page address UINT32 sect_offset = lba % SECTORS_PER_PAGE; // sector offset within the page UINT32 sectors_remain = total_sectors; while (sectors_remain != 0) // one page per iteration { if (sect_offset + sectors_remain < SECTORS_PER_PAGE) { num_sectors_to_read = sectors_remain; } else { num_sectors_to_read = SECTORS_PER_PAGE - sect_offset; } UINT32 next_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; while (next_read_buf_id == GETREG(SATA_RBUF_PTR)); // wait if the read buffer is full (slow host) SETREG(BM_STACK_RDSET, next_read_buf_id); // change bm_read_limit SETREG(BM_STACK_RESET, 0x02); // change bm_read_limit g_ftl_read_buf_id = next_read_buf_id; sect_offset = 0; sectors_remain -= num_sectors_to_read; lpage_addr++; } }
HANDLER_DEF_END HANDLER_DEF_BEGIN(pop_r32_handler) { uint32_t *stack = (uint32_t *)get_real_address( context->esp, table, WRITE, false ); context->esp+=sizeof(uint32_t); switch( context->code[0] ) { case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: GETREG(context,context->code[0]-0x58) = *stack; break; default: log_message( ERROR, "Invalid opcode for POP r"); assert(0); break; } context->eip++; context->code++; }
static UINT32 opMULUr(void) // mulu r1,r2 { UINT32 op1=GETREG(GET1); UINT32 op2=GETREG(GET2); UINT64 tmp; tmp=(UINT64)op1*(UINT64)op2; op2=tmp&0xffffffff; tmp>>=32; CHECK_ZS(tmp);//z = bad! SET_Z( (tmp|op2)==0 ); SET_OV((tmp!=0)); SET_CY((tmp!=0)); SETREG(GET2,op2); SETREG(30,tmp); return clkIF; }
void ftl_read(UINT32 const lba, UINT32 const num_sectors) { UINT32 remain_sects, num_sectors_to_read; UINT32 lpn, sect_offset; UINT32 bank, vpn; lpn = lba / SECTORS_PER_PAGE; sect_offset = lba % SECTORS_PER_PAGE; remain_sects = num_sectors; while (remain_sects != 0) { if ((sect_offset + remain_sects) < SECTORS_PER_PAGE) { num_sectors_to_read = remain_sects; } else { num_sectors_to_read = SECTORS_PER_PAGE - sect_offset; } bank = get_num_bank(lpn); // page striping vpn = get_vpn(lpn); CHECK_VPAGE(vpn); if (vpn != NULL) { nand_page_ptread_to_host(bank, vpn / PAGES_PER_BLK, vpn % PAGES_PER_BLK, sect_offset, num_sectors_to_read); } // The host is requesting to read a logical page that has never been written to. else { UINT32 next_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; #if OPTION_FTL_TEST == 0 while (next_read_buf_id == GETREG(SATA_RBUF_PTR)); // wait if the read buffer is full (slow host) #endif // fix bug @ v.1.0.6 // Send 0xFF...FF to host when the host request to read the sector that has never been written. // In old version, for example, if the host request to read unwritten sector 0 after programming in sector 1, Jasmine would send 0x00...00 to host. // However, if the host already wrote to sector 1, Jasmine would send 0xFF...FF to host when host request to read sector 0. (ftl_read() in ftl_xxx/ftl.c) mem_set_dram(RD_BUF_PTR(g_ftl_read_buf_id) + sect_offset*BYTES_PER_SECTOR, 0xFFFFFFFF, num_sectors_to_read*BYTES_PER_SECTOR); flash_finish(); SETREG(BM_STACK_RDSET, next_read_buf_id); // change bm_read_limit SETREG(BM_STACK_RESET, 0x02); // change bm_read_limit g_ftl_read_buf_id = next_read_buf_id; } sect_offset = 0; remain_sects -= num_sectors_to_read; lpn++; } }
void ftl_trim(UINT32 const lba, UINT32 const num_sectors) { ASSERT(num_sectors > 0); uart_printf("Num sectors: %u", num_sectors); uart_printf("SATA_WBUF_PTR: %u", GETREG(SATA_WBUF_PTR)); uart_printf("g_ftl_write_buf_id: %u", g_ftl_write_buf_id); UINT32 next_write_buf_id = (g_ftl_write_buf_id + num_sectors) % NUM_WR_BUFFERS; for (UINT32 i=0;i<num_sectors;i++) { for (UINT32 j=0;j<512/8;j=j+2) { UINT32 address = read_dram_32(WR_BUF_PTR(g_ftl_write_buf_id)+j*sizeof(UINT32)); UINT32 reg2 = read_dram_32(WR_BUF_PTR(g_ftl_write_buf_id)+(j+1)*sizeof(UINT32)); UINT32 count = reg2 & 0xFFFF0000; // Count stored in the first four words. // If count is zero. We continue, but also, if address is 48bit. // We shouldn't get these unless it is an error. if (count == 0 || (reg2 & 0x0000FFFF) > 0) // continue; // uart_print_hex(address); // uart_print_hex(count); } g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS; } SETREG(BM_STACK_WRSET, next_write_buf_id); // change bm_read_limit SETREG(BM_STACK_RESET, 0x02); // change bm_read_limi }
static int msm_bus_ipend(struct uart_softc *sc) { struct msm_uart_softc *u = (struct msm_uart_softc *)sc; struct uart_bas *bas = &sc->sc_bas; uint32_t isr; int ipend; uart_lock(sc->sc_hwmtx); /* Get ISR status */ isr = GETREG(bas, UART_DM_MISR); ipend = 0; /* Uart RX starting, notify upper layer */ if (isr & UART_DM_RXLEV) { u->ier &= ~UART_DM_RXLEV; SETREG(bas, UART_DM_IMR, u->ier); uart_barrier(bas); ipend |= SER_INT_RXREADY; } /* Stale RX interrupt */ if (isr & UART_DM_RXSTALE) { /* Disable and reset it */ SETREG(bas, UART_DM_CR, UART_DM_STALE_EVENT_DISABLE); SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT); uart_barrier(bas); ipend |= SER_INT_RXREADY; } /* TX READY interrupt */ if (isr & UART_DM_TX_READY) { /* Clear TX Ready */ SETREG(bas, UART_DM_CR, UART_DM_CLEAR_TX_READY); /* Disable TX_READY */ u->ier &= ~UART_DM_TX_READY; SETREG(bas, UART_DM_IMR, u->ier); uart_barrier(bas); if (sc->sc_txbusy != 0) ipend |= SER_INT_TXIDLE; } if (isr & UART_DM_TXLEV) { /* TX FIFO is empty */ u->ier &= ~UART_DM_TXLEV; SETREG(bas, UART_DM_IMR, u->ier); uart_barrier(bas); if (sc->sc_txbusy != 0) ipend |= SER_INT_TXIDLE; } uart_unlock(sc->sc_hwmtx); return (ipend); }
static UINT32 opSHRi(void) // shr imm5,r2 { UINT64 tmp; UINT32 count=UI5(OP); SET_OV(0); SET_CY(0); if(count) { tmp=GETREG(GET2); tmp>>=count-1; SET_CY(tmp&1); tmp>>=1; SETREG(GET2,tmp&0xffffffff); } CHECK_ZS(GETREG(GET2)); return clkIF; }
static UINT32 opSARi(void) // sar imm5,r2 { UINT64 tmp; UINT32 count=UI5(OP); SET_OV(0); SET_CY(0); if(count) { tmp=GETREG(GET2); tmp>>=count-1; SET_CY(tmp&1); tmp>>=1; SETREG(GET2,(tmp&0xffffffff)|(~(((GETREG(GET2)&0x80000000)>>count)-1))); } CHECK_ZS(GETREG(GET2)); return clkIF; }
static void opCVTS(void) { float val1=u2f(GETREG(GET1)); SET_OV(0); SET_Z((val1==0.0)?1:0); SET_S((val1<0.0)?1:0); SETREG(GET2,(INT32)val1); }
static UINT32 opSHRr(void) // shr r1,r2 { UINT64 tmp; UINT32 count=GETREG(GET1); count&=0x1f; SET_OV(0); SET_CY(0); if(count) { tmp=GETREG(GET2); tmp>>=count-1; SET_CY(tmp&1); SETREG(GET2,(tmp>>1)&0xffffffff); } CHECK_ZS(GETREG(GET2)); return clkIF; }
static UINT32 opSHLi(void) // shl imm5,r2 { UINT64 tmp; UINT32 count=UI5(OP); SET_OV(0); SET_CY(0); if(count) { tmp=GETREG(GET2); tmp<<=count; CHECK_CY(tmp); SETREG(GET2,tmp&0xffffffff); } CHECK_ZS(GETREG(GET2)); return clkIF; }
static UINT32 opNOTr(void) // not r1,r2 { UINT32 op1=GETREG(GET1); UINT32 op2=~op1; CHECK_ZS(op2); SET_OV(0); SETREG(GET2,op2); return clkIF; }
static UINT32 opMOVEA(void) // movea imm16, reg1, reg2 { UINT32 op1=GETREG(GET1); UINT32 op2=R_OP(PC); PC+=2; op2=I16(op2); SETREG(GET2,op1+op2); return clkIF; }
static UINT32 opMOVHI(void) // movhi imm16, reg1 ,reg2 { UINT32 op2=R_OP(PC); PC+=2; op2=UI16(op2); op2<<=16; SETREG(GET2,GETREG(GET1)+op2); return clkIF; }
static void opCVTW(void) { //TODO: CY float val1=GETREG(GET1); SET_OV(0); SET_Z((val1==0.0)?1:0); SET_S((val1<0.0)?1:0); SETREG(GET2,f2u(val1)); }
void nand_page_read_to_host(UINT32 const bank, UINT32 const vblock, UINT32 const page_num) { #if PrintStats uart_print_level_1("FR "); uart_print_level_1_int(SECTORS_PER_PAGE); uart_print_level_1("\r\n"); #endif UINT32 row; ASSERT(bank < NUM_BANKS); ASSERT(vblock < VBLKS_PER_BANK); ASSERT(page_num < PAGES_PER_BLK); row = (vblock * PAGES_PER_BLK) + page_num; uart_print("nand_page_read_to_host bank="); uart_print_int(bank); uart_print(", vblock="); uart_print_int(vblock); uart_print(", page="); uart_print_int(page_num); uart_print("\r\n"); uart_print("Reading row="); uart_print_int(row); uart_print("\r\n"); uart_print("read flash: bank="); uart_print_int(bank); uart_print(", page="); uart_print_int(row); uart_print("\r\n"); SETREG(FCP_CMD, FC_COL_ROW_READ_OUT); SETREG(FCP_DMA_ADDR, RD_BUF_PTR(g_ftl_read_buf_id)); SETREG(FCP_DMA_CNT, BYTES_PER_PAGE); SETREG(FCP_COL, 0); #if OPTION_FTL_TEST == TRUE SETREG(FCP_OPTION, FO_P | FO_E); #else SETREG(FCP_OPTION, FO_P | FO_E | FO_B_SATA_R); #endif SETREG(FCP_ROW_L(bank), row); SETREG(FCP_ROW_H(bank), row); g_ftl_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; #if OPTION_FTL_TEST == FALSE { int count=0; while (1) { count ++; if (count > 100000) { uart_print_level_1("Warning1 in nand_page_read_to_host\r\n"); count=0; } UINT32 sata_id = GETREG(SATA_RBUF_PTR); if (g_ftl_read_buf_id != sata_id) break; } } #endif flash_issue_cmd(bank, RETURN_ON_ISSUE); }
static UINT32 opINW(void) // in.w disp16[reg1],reg2 { UINT32 tmp=R_OP(PC); PC+=2; tmp=D16(tmp); tmp+=GETREG(GET1); tmp=RIO_W(tmp&~3); SETREG(GET2,tmp); return clkIF+clkMEM; }
static UINT32 opCMPi(void) // cmpi imm5,r2 { UINT32 op1=I5(OP); UINT32 op2=GETREG(GET2); UINT64 res=(UINT64)op2-(UINT64)op1; CHECK_CY(res); CHECK_OVSUB(op1,op2,res); CHECK_ZS(res); return clkIF; }
static UINT32 opSHLr(void) // shl r1,r2 { UINT64 tmp; UINT32 count=GETREG(GET1); count&=0x1f; SET_OV(0); SET_CY(0); if(count) { tmp=GETREG(GET2); tmp<<=count; CHECK_CY(tmp); SETREG(GET2,tmp&0xffffffff); CHECK_ZS(GETREG(GET2)); } return clkIF; }
static void format(void) { // This function is called upon the very first power-up of the SSD. // This function does the low-level format (i.e. FTL level format) of SSD. // A typical FTL would create its mapping table and the list of free blocks. // However, this example does nothing more than erasing all the free blocks. // // This function may take a long time to complete. For example, erasing all the flash blocks can // take more than ten seconds depending on the total density. // In that case, the host will declare time-out error. (no response from SSD for a long time) // A suggested solution to this problem is: // When you power-up the SSD for the first time, connect the power cable but not the SATA cable. // At the end of this function, you can put a call to led(1) to indicate that the low level format // has been completed. When the LED is on, turn off the power, connect the SATA cable, and turn on // the power again. UINT32 vblk_offset, bank; for (vblk_offset = 1; vblk_offset < VBLKS_PER_BANK; vblk_offset++) { for (bank = 0; bank < NUM_BANKS; bank++) { if (is_bad_block(bank, vblk_offset)) continue; // You do not need to set the values of FCP_DMA_ADDR, FCP_DMA_CNT and FCP_COL for FC_ERASE. SETREG(FCP_CMD, FC_ERASE); SETREG(FCP_BANK, REAL_BANK(bank)); SETREG(FCP_OPTION, FO_P); SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK); SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK); // You should not issue a new command when Waiting Room is not empty. while ((GETREG(WR_STAT) & 0x00000001) != 0); // By writing any value to FCP_ISSUE, you put FC_ERASE into Waiting Room. // The value written to FCP_ISSUE does not have any meaning. SETREG(FCP_ISSUE, NULL); } } // In general, write_format_mark() should be called upon completion of low level format in order to prevent // format() from being called again. // However, since the tutorial FTL does not support power off recovery, // format() should be called every time. init_meta_data(); ftl_flush(); write_format_mark(); led(1); }
void ata_check_power_mode(UINT32 lba, UINT32 sector_count) { UINT32 fis_type = FISTYPE_REGISTER_D2H; UINT32 flags = B_IRQ; UINT32 status = B_DRDY | BIT4; SETREG(SATA_FIS_D2H_0, fis_type | (flags << 8) | (status << 16)); SETREG(SATA_FIS_D2H_1, GETREG(SATA_FIS_H2D_1)); SETREG(SATA_FIS_D2H_2, GETREG(SATA_FIS_H2D_2) & 0x00FFFFFF); SETREG(SATA_FIS_D2H_3, 0x000000FF); SETREG(SATA_FIS_D2H_4, 0); SETREG(SATA_FIS_D2H_LEN, 5); if ((GETREG(SATA_PHY_STATUS) & 0xF0F) != 0x103) { return; } SETREG(SATA_CTRL_2, SEND_NON_DATA_FIS); }
static UINT32 opADDi(void) // add imm5,r2 { UINT32 op1=I5(OP); UINT32 op2=GETREG(GET2); UINT64 res=(UINT64)op2+(UINT64)op1; CHECK_CY(res); CHECK_OVADD(op1,op2,res); CHECK_ZS(res); SETREG(GET2,res); return clkIF; }
static UINT32 opLDH(void) // ld.h disp16[reg1],reg2 { UINT32 tmp=R_OP(PC); PC+=2; tmp=D16(tmp); tmp+=GETREG(GET1); tmp=R_H(tmp&~1); tmp|=(tmp&0x8000)?0xffff0000:0; SETREG(GET2,tmp); return clkIF+clkMEM; }
static BOOL32 check_format_mark(void) { // This function reads a flash page from (bank #0, block #0) in order to check whether the SSD is formatted or not. #ifdef __GNUC__ extern UINT32 size_of_firmware_image; UINT32 firmware_image_pages = (((UINT32) (&size_of_firmware_image)) + BYTES_PER_FW_PAGE - 1) / BYTES_PER_FW_PAGE; #else extern UINT32 Image$$ER_CODE$$RO$$Length; extern UINT32 Image$$ER_RW$$RW$$Length; UINT32 firmware_image_bytes = ((UINT32) &Image$$ER_CODE$$RO$$Length) + ((UINT32) &Image$$ER_RW$$RW$$Length); UINT32 firmware_image_pages = (firmware_image_bytes + BYTES_PER_FW_PAGE - 1) / BYTES_PER_FW_PAGE; #endif UINT32 format_mark_page_offset = FW_PAGE_OFFSET + firmware_image_pages; UINT32 temp; flash_clear_irq(); // clear any flash interrupt flags that might have been set SETREG(FCP_CMD, FC_COL_ROW_READ_OUT); SETREG(FCP_BANK, REAL_BANK(0)); SETREG(FCP_OPTION, FO_E); SETREG(FCP_DMA_ADDR, FTL_BUF_ADDR); // flash -> DRAM SETREG(FCP_DMA_CNT, BYTES_PER_SECTOR); SETREG(FCP_COL, 0); SETREG(FCP_ROW_L(0), format_mark_page_offset); SETREG(FCP_ROW_H(0), format_mark_page_offset); // At this point, we do not have to check Waiting Room status before issuing a command, // because scan list loading has been completed just before this function is called. SETREG(FCP_ISSUE, NULL); // wait for the FC_COL_ROW_READ_OUT command to be accepted by bank #0 while ((GETREG(WR_STAT) & 0x00000001) != 0); // wait until bank #0 finishes the read operation while (BSP_FSM(0) != BANK_IDLE); // Now that the read operation is complete, we can check interrupt flags. temp = BSP_INTR(0) & FIRQ_ALL_FF; // clear interrupt flags CLR_BSP_INTR(0, 0xFF); if (temp != 0) { return FALSE; // the page contains all-0xFF (the format mark does not exist.) } else { return TRUE; // the page contains something other than 0xFF (it must be the format mark) } }
static UINT32 opXORI(void) // xori imm16,r1,r2 { UINT32 op1=GETREG(GET1); UINT32 op2=R_OP(PC); PC+=2; op2=UI16(op2); op2^=op1; CHECK_ZS(op2); SET_OV(0); SET_S(0); SETREG(GET2,op2); return clkIF; }
void ftl_read(UINT32 const lba, UINT32 const total_sectors) //modified by GYUHWA { UINT32 sect_offset, count, next_read_buf_id; sect_offset = lba % SECTORS_PER_PAGE; //sect_offset : offset of RD_BUFFER for(count = 0; count < total_sectors; count++) { ftl_read_sector(lba+count, sect_offset++); //read one sector if(sect_offset == SECTORS_PER_PAGE ) //One page is read complete { next_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; #if OPTION_FTL_TEST == 0 while (next_read_buf_id == GETREG(SATA_RBUF_PTR)); // wait if the read buffer is full (slow host) #endif g_ftl_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; while (GETREG(MON_CHABANKIDLE) != 0); // This while() loop ensures that Waiting Room is empty and all the banks are idle. SETREG(BM_STACK_RDSET, next_read_buf_id); // change bm_read_limit SETREG(BM_STACK_RESET, 0x02); // change bm_read_limit sect_offset = 0; } } if(sect_offset != 0) //no complete page -> make read command, example : only 4 sector read command { next_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; #if OPTION_FTL_TEST == 0 while (next_read_buf_id == GETREG(SATA_RBUF_PTR)); // wait if the read buffer is full (slow host) #endif g_ftl_read_buf_id = (g_ftl_read_buf_id + 1) % NUM_RD_BUFFERS; while (GETREG(MON_CHABANKIDLE) != 0); // This while() loop ensures that Waiting Room is empty and all the banks are idle. SETREG(BM_STACK_RDSET, next_read_buf_id); // change bm_read_limit SETREG(BM_STACK_RESET, 0x02); // change bm_read_limit // change bm_read_limit } }
static u_int imx_uart_getbaud(struct uart_bas *bas) { uint32_t rate, ubir, ubmr; u_int baud, blo, bhi, i; static const u_int predivs[] = {6, 5, 4, 3, 2, 1, 7, 1}; static const u_int std_rates[] = { 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600 }; /* * Get the baud rate the hardware is programmed for, then search the * table of standard baud rates for a number that's within 3% of the * actual rate the hardware is programmed for. It's more comforting to * see that your console is running at 115200 than 114942. Note that * here we cannot make a simplifying assumption that the predivider and * numerator are 1 (like we do when setting the baud rate), because we * don't know what u-boot might have set up. */ i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >> IMXUART_UFCR_RFDIV_SHIFT; rate = imx_ccm_uart_hz() / predivs[i]; ubir = GETREG(bas, REG(UBIR)) + 1; ubmr = GETREG(bas, REG(UBMR)) + 1; baud = ((rate / 16 ) * ubir) / ubmr; blo = (baud * 100) / 103; bhi = (baud * 100) / 97; for (i = 0; i < nitems(std_rates); i++) { rate = std_rates[i]; if (rate >= blo && rate <= bhi) { baud = rate; break; } } return (baud); }
// BSP interrupt service routine void ftl_isr(void) { UINT32 bank; UINT32 bsp_intr_flag; uart_print("BSP interrupt occured..."); // interrupt pending clear (ICU) SETREG(APB_INT_STS, INTR_FLASH); for (bank = 0; bank < NUM_BANKS; bank++) { while (BSP_FSM(bank) != BANK_IDLE); // get interrupt flag from BSP bsp_intr_flag = BSP_INTR(bank); if (bsp_intr_flag == 0) { continue; } UINT32 fc = GETREG(BSP_CMD(bank)); // BSP clear CLR_BSP_INTR(bank, bsp_intr_flag); // interrupt handling if (bsp_intr_flag & FIRQ_DATA_CORRUPT) { uart_printf("BSP interrupt at bank: 0x%x", bank); uart_print("FIRQ_DATA_CORRUPT occured..."); } if (bsp_intr_flag & (FIRQ_BADBLK_H | FIRQ_BADBLK_L)) { uart_printf("BSP interrupt at bank: 0x%x", bank); if (fc == FC_COL_ROW_IN_PROG || fc == FC_IN_PROG || fc == FC_PROG) { uart_print("find runtime bad block when block program..."); } else { uart_printf("find runtime bad block when block erase...vblock #: %d", GETREG(BSP_ROW_H(bank)) / PAGES_PER_BLK); ASSERT(fc == FC_ERASE); } } } }