Used RTC tick counter for low level delays.

Added timeout on NAND operations.
Removed tmrsetup() calls from all drivers (no setup needed, added to boot_prime.c)
This commit is contained in:
claudiol 2021-05-27 18:10:16 -04:00
parent 8a1657f442
commit 341e4f329e
6 changed files with 55 additions and 62 deletions

View file

@ -877,13 +877,17 @@ extern void ts_init();
#define PIXELS_PER_WORD 8 #define PIXELS_PER_WORD 8
// LOW LEVEL TIMER FUNCTIONS FOR HARDWARE SETUP // LOW LEVEL TIMER FUNCTIONS FOR HARDWARE SETUP
void __tmr_setupdelay();
// Do a single delay 100 usec // Do a single delay 100 usec
void __tmr_delay100us(); void __tmr_delay100us();
// Do a single delay 10 msec // Do a single delay 10 msec
void __tmr_delay10ms(); void __tmr_delay10ms();
// Do a single delay 20 msec // Do a single delay 20 msec
void __tmr_delay20ms(); void __tmr_delay20ms();
// Prepare for an open loop timeout
void __tmr_setuptimeoutms(int delayms,unsigned int *start,unsigned int *end);
// Check if clock timed out or not
int __tmr_timedout(unsigned int start,unsigned int end);
// OTHER ADDITIONAL HARDWARE FUNCTIONS // OTHER ADDITIONAL HARDWARE FUNCTIONS

View file

@ -225,9 +225,6 @@ void setup_hardware()
lcd_off(); lcd_off();
// Playing it safe for testing -
NANDWriteProtect();
*PWRCFG |= 0x20000; // Enable Wait for Interrupt mode *PWRCFG |= 0x20000; // Enable Wait for Interrupt mode
// Disable SoC blocks that we don't use // Disable SoC blocks that we don't use
@ -236,6 +233,10 @@ void setup_hardware()
*PCLKCON &= ~0x8034e; // Disable PCLK going to SPI_HS0, AC97, I2S0, and PCM audio interfaces *PCLKCON &= ~0x8034e; // Disable PCLK going to SPI_HS0, AC97, I2S0, and PCM audio interfaces
*SCLKCON &= ~0xa05242; // Disable special clocks to HSMMC0, I2S0, PCM0, SPI, USB Host *SCLKCON &= ~0xa05242; // Disable special clocks to HSMMC0, I2S0, PCM0, SPI, USB Host
*RTCCON = 0x10; // RTC clock set to defaults, plus tick counter at 1/32768 second
*TICNT0 = 0x80; // Enable tick interrupt, counter to zero (make TICKCNT tick at 32.768 kHz)
*TICNT1 = 0; // Counter to zero
*TICNT2 = 0; // Counter to zero
} }

View file

@ -339,8 +339,6 @@ int lcd_setmode(int mode, unsigned int *physbuf)
void lcd_poweron() void lcd_poweron()
{ {
__tmr_setupdelay(); // SETUP TIMERS TO GET ACCURATE DELAYS
// Setup GPIO // Setup GPIO
*GPCCON = (*GPCCON&0xfc00) | 0xaaaa02aa; // ALL GPC PINS SET FOR LCD FUNCTION *GPCCON = (*GPCCON&0xfc00) | 0xaaaa02aa; // ALL GPC PINS SET FOR LCD FUNCTION

View file

@ -104,7 +104,12 @@ static inline void NANDEnableChipSelect(void)
static inline void NANDWaitReady(void) static inline void NANDWaitReady(void)
{ {
while ((*NFSTAT & NFSTAT_RnB_TransDetect) == 0); unsigned int start,end;
// Flash datasheet lists Block Erase as the longest operation with a max. 10 ms
// So in 12 ms it MUST have finished or there was an error.
__tmr_setuptimeoutms(12,&start,&end);
while ((*NFSTAT & NFSTAT_RnB_TransDetect) == 0) if(__tmr_timedout(start,end)) return;
} }
static inline void NANDClearReady(void) static inline void NANDClearReady(void)
@ -511,12 +516,17 @@ int NANDBlockErase(uint32_t nand_address)
*NFCMMD = NAND_CMD_BLOCK_ERASE2nd; *NFCMMD = NAND_CMD_BLOCK_ERASE2nd;
red_led_on();
NANDWaitReady(); NANDWaitReady();
blue_led_on();
// NOTE BL2 does not check NFSTAT_IllegalAccess here // NOTE BL2 does not check NFSTAT_IllegalAccess here
if (NANDCheckWrite() == 0) { if (NANDCheckWrite() == 0) {
retval = 0; retval = 0;
} }
green_led_on();
NANDDisableChipSelect(); NANDDisableChipSelect();
@ -592,7 +602,7 @@ int NANDWrite(uint32_t virtual_address, uint8_t const *source_address, unsigned
uint32_t nand_write_address = NANDTranslateVirtualAddress(block_start); uint32_t nand_write_address = NANDTranslateVirtualAddress(block_start);
if (offset != 0 || num_bytes < NAND_BLOCK_SIZE) { if ( (offset != 0) || (num_bytes < NAND_BLOCK_SIZE)) {
if (NANDReadBlock(nand_write_address, nand_buffer) == 0) { if (NANDReadBlock(nand_write_address, nand_buffer) == 0) {
return 0; return 0;
} }

View file

@ -455,74 +455,57 @@ void tmr_eventkill(HEVENT event)
// INDEPENDENT TIMING FUNCTIONS THAT DON'T DEPEND ON INTERRUPTS OR THE TIMER MODULE TO BE INITIALIZED TO WORK // INDEPENDENT TIMING FUNCTIONS THAT DON'T DEPEND ON INTERRUPTS OR THE TIMER MODULE TO BE INITIALIZED TO WORK
// USED MAINLY FOR HARDWARE SETUP THAT NEEDS ACCURATE TIMING // USED MAINLY FOR HARDWARE SETUP THAT NEEDS ACCURATE TIMING
// Setup TIMER 4 for delays in LCD chip communications // Use RTC tick counter for delays in LCD chip communications
#define __LLTIMER_FREQ 100000 // 100 kHz tick #define __LLTIMER_FREQ 32768 // 32.768 kHz tick
void __tmr_setupdelay()
{
unsigned int pclk = __cpu_getPCLK();
unsigned int divider, prescaler;
prescaler = (pclk << 3) / __LLTIMER_FREQ;
divider = 1;
while(prescaler > (1 << (11 + divider))) {
divider++;
}
prescaler += (1 << (2 + divider));
prescaler >>= divider + 3;
//if(divider>4) PCLK TOO HIGH TO ACHIEVE TIMER FREQUENCY, USE HIGHER MULTIPLE
if(divider > 4)
divider = 4;
// SET PRESCALER VALUES FOR TIMERS 2,3 AND 4
*TCFG0 = (*TCFG0 & (~0xFF00)) | ((prescaler - 1)<<8);
*TCFG1 =
(*TCFG1 & (~0xf0000)) | ((divider - 1) << 16);
// SET COUNT VALUES TO MAXIMUM
*TCNTB4 = 0xffff;
// Make sure no interrupts are fired by timer4
*INTMSK1 |= 0x4000;
}
// Do a single delay 100 usec // Do a single delay 100 usec
void __tmr_delay100us() void __tmr_delay100us()
{ {
*TCNTB4= (__LLTIMER_FREQ * 100) / 1000000; unsigned int start,end;
*TCON= (*TCON&~0x700000) | 0x200000; // Update the count start = *TICKCNT;
*TCON= (*TCON&~0x700000) | 0x100000; // Start the timer, single shot end = *TICKCNT + (__LLTIMER_FREQ * 100) / 1000000;
while((*TCNTO4&0xffff)!=0); // And wait for the timer to count to zero if(end<start) while(*TICKCNT>=start); // Wait for the counter to wrap
while(*TICKCNT<end); // And wait for the timer count to reach the end
} }
// Do a single delay 100 usec // Do a single delay 10 msec
void __tmr_delay10ms() void __tmr_delay10ms()
{ {
*TCNTB4= (__LLTIMER_FREQ * 10) / 1000; unsigned int start,end;
*TCON= (*TCON&~0x700000) | 0x200000; // Update the count start = *TICKCNT;
*TCON= (*TCON&~0x700000) | 0x100000; // Start the timer, single shot end = *TICKCNT + (__LLTIMER_FREQ * 10) / 1000;
while((*TCNTO4&0xffff)!=0); // And wait for the timer to count to zero if(end<start) while(*TICKCNT>=start); // Wait for the counter to wrap
while(*TICKCNT<end); // And wait for the timer count to reach the end
} }
// Do a single delay 100 usec // Do a single delay 100 usec
void __tmr_delay20ms() void __tmr_delay20ms()
{ {
*TCNTB4= (__LLTIMER_FREQ * 20) / 1000; unsigned int start,end;
*TCON= (*TCON&~0x700000) | 0x200000; // Update the count start = *TICKCNT;
*TCON= (*TCON&~0x700000) | 0x100000; // Start the timer, single shot end = *TICKCNT + (__LLTIMER_FREQ * 20) / 1000;
while((*TCNTO4&0xffff)!=0); // And wait for the timer to count to zero if(end<start) while(*TICKCNT>=start); // Wait for the counter to wrap
while(*TICKCNT<end); // And wait for the timer count to reach the end
} }
// Prepare for an open loop timeout
void __tmr_setuptimeoutms(int delayms,unsigned int *start,unsigned int *end)
{
*start = *TICKCNT;
*end = *TICKCNT + (__LLTIMER_FREQ * delayms) / 1000;
}
// Check if clock timed out or not
int __tmr_timedout(unsigned int start,unsigned int end)
{
if(end<start) if(*TICKCNT>=start) return 0; // Wait for the counter to wrap
if(*TICKCNT>=end) return 1; // And wait for the timer count to reach the end
return 0;
}

View file

@ -378,9 +378,6 @@ static void usb_reset_full(void)
void usb_hwsetup() void usb_hwsetup()
{ {
__tmr_setupdelay(); // SETUP SOME TIMERS TO GET ACCURATE DELAYS
// POWER OFF FIRST TO CAUSE A FULL RESET OF THE USB BLOCK // POWER OFF FIRST TO CAUSE A FULL RESET OF THE USB BLOCK
*UCLKCON &= ~0x80000000; // SIGNAL THE HOST A DEVICE HAS BEEN DISCONNECTED *UCLKCON &= ~0x80000000; // SIGNAL THE HOST A DEVICE HAS BEEN DISCONNECTED