~increscent/rk3128-brom

41826178213a49ee05deb45cdd68b7ad3af7c197 — Robert Williams 2 months ago a960b33 main
Updated dram tests
4 files changed, 393 insertions(+), 42 deletions(-)

A memtest/memtest.c
A memtest/memtest.h
M uart/bits.rs
M uart/uart.rs
A memtest/memtest.c => memtest/memtest.c +221 -0
@@ 0,0 1,221 @@
/**********************************************************************
 *
 * Filename:    memtest.c
 * 
 * Description: General-purpose memory testing functions.
 *
 * Notes:       This software can be easily ported to systems with
 *              different data bus widths by redefining 'datum'.
 *
 * 
 * Copyright (c) 1998 by Michael Barr.  This software is placed into
 * the public domain and may be used for any purpose.  However, this
 * notice must not be changed or removed and no warranty is either
 * expressed or implied by its publication or distribution.
 **********************************************************************/


#include "memtest.h"


/**********************************************************************
 *
 * Function:    memTestDataBus()
 *
 * Description: Test the data bus wiring in a memory region by
 *              performing a walking 1's test at a fixed address
 *              within that region.  The address (and hence the
 *              memory region) is selected by the caller.
 *
 * Notes:       
 *
 * Returns:     0 if the test succeeds.  
 *              A non-zero result is the first pattern that failed.
 *
 **********************************************************************/
datum
memTestDataBus(volatile datum * address)
{
    datum pattern;


    /*
     * Perform a walking 1's test at the given address.
     */
    for (pattern = 1; pattern != 0; pattern <<= 1)
    {
        /*
         * Write the test pattern.
         */
        *address = pattern;

        /*
         * Read it back (immediately is okay for this test).
         */
        if (*address != pattern) 
        {
            return (pattern);
        }
    }

    return (0);

}   /* memTestDataBus() */


/**********************************************************************
 *
 * Function:    memTestAddressBus()
 *
 * Description: Test the address bus wiring in a memory region by
 *              performing a walking 1's test on the relevant bits
 *              of the address and checking for aliasing. This test
 *              will find single-bit address failures such as stuck
 *              -high, stuck-low, and shorted pins.  The base address
 *              and size of the region are selected by the caller.
 *
 * Notes:       For best results, the selected base address should
 *              have enough LSB 0's to guarantee single address bit
 *              changes.  For example, to test a 64-Kbyte region, 
 *              select a base address on a 64-Kbyte boundary.  Also, 
 *              select the region size as a power-of-two--if at all 
 *              possible.
 *
 * Returns:     NULL if the test succeeds.  
 *              A non-zero result is the first address at which an
 *              aliasing problem was uncovered.  By examining the
 *              contents of memory, it may be possible to gather
 *              additional information about the problem.
 *
 **********************************************************************/
datum * 
memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes)
{
    unsigned long addressMask = (nBytes/sizeof(datum) - 1);
    unsigned long offset;
    unsigned long testOffset;

    datum pattern     = (datum) 0xAAAAAAAA;
    datum antipattern = (datum) 0x55555555;


    /*
     * Write the default pattern at each of the power-of-two offsets.
     */
    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
        baseAddress[offset] = pattern;
    }

    /* 
     * Check for address bits stuck high.
     */
    testOffset = 0;
    baseAddress[testOffset] = antipattern;

    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
        if (baseAddress[offset] != pattern)
        {
            return ((datum *) &baseAddress[offset]);
        }
    }

    baseAddress[testOffset] = pattern;

    /*
     * Check for address bits stuck low or shorted.
     */
    for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
    {
        baseAddress[testOffset] = antipattern;

		if (baseAddress[0] != pattern)
		{
			return ((datum *) &baseAddress[testOffset]);
		}

        for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
        {
            if ((baseAddress[offset] != pattern) && (offset != testOffset))
            {
                return ((datum *) &baseAddress[testOffset]);
            }
        }

        baseAddress[testOffset] = pattern;
    }

    return (NULL);

}   /* memTestAddressBus() */


/**********************************************************************
 *
 * Function:    memTestDevice()
 *
 * Description: Test the integrity of a physical memory device by
 *              performing an increment/decrement test over the
 *              entire region.  In the process every storage bit 
 *              in the device is tested as a zero and a one.  The
 *              base address and the size of the region are
 *              selected by the caller.
 *
 * Notes:       
 *
 * Returns:     NULL if the test succeeds.
 *
 *              A non-zero result is the first address at which an
 *              incorrect value was read back.  By examining the
 *              contents of memory, it may be possible to gather
 *              additional information about the problem.
 *
 **********************************************************************/
datum * 
memTestDevice(volatile datum * baseAddress, unsigned long nBytes)	
{
    unsigned long offset;
    unsigned long nWords = nBytes / sizeof(datum);

    datum pattern;
    datum antipattern;


    /*
     * Fill memory with a known pattern.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        baseAddress[offset] = pattern;
    }

    /*
     * Check each location and invert it for the second pass.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        if (baseAddress[offset] != pattern)
        {
            return ((datum *) &baseAddress[offset]);
        }

        antipattern = ~pattern;
        baseAddress[offset] = antipattern;
    }

    /*
     * Check each location for the inverted pattern and zero it.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        antipattern = ~pattern;
        if (baseAddress[offset] != antipattern)
        {
            return ((datum *) &baseAddress[offset]);
        }
    }

    return (NULL);

}   /* memTestDevice() */

A memtest/memtest.h => memtest/memtest.h +41 -0
@@ 0,0 1,41 @@
/**********************************************************************
 *
 * Filename:    memtest.h
 * 
 * Description: Memory-testing module API.
 *
 * Notes:       The memory tests can be easily ported to systems with
 *              different data bus widths by redefining 'datum' type.
 *
 * 
 * Copyright (c) 2000 by Michael Barr.  This software is placed into
 * the public domain and may be used for any purpose.  However, this
 * notice must not be changed or removed and no warranty is either
 * expressed or implied by its publication or distribution.
 **********************************************************************/

#ifndef _memtest_h
#define _memtest_h


/*
 * Define NULL pointer value.
 */
#ifndef NULL
#define NULL  (void *) 0
#endif

/*
 * Set the data bus width.
 */
typedef unsigned long datum;

/*
 * Function prototypes.
 */
datum   memTestDataBus(volatile datum * address);
datum * memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes);
datum * memTestDevice(volatile datum * baseAddress, unsigned long nBytes);


#endif /* _memtest_h */
\ No newline at end of file

M uart/bits.rs => uart/bits.rs +14 -2
@@ 1,14 1,26 @@

#[inline]
pub fn write(addr: *mut u32, val: u32) {
pub fn write32(addr: *mut u32, val: u32) {
    unsafe { core::ptr::write_volatile(addr, val); }
}

#[inline]
pub fn read(addr: *mut u32) -> u32 {
pub fn write16(addr: *mut u16, val: u16) {
    unsafe { core::arch::asm!("strh {1}, [{0}]", in(reg) addr, in(reg) val); }
}

#[inline]
pub fn read32(addr: *mut u32) -> u32 {
    unsafe { core::ptr::read_volatile(addr) }
}

#[inline]
pub fn read16(addr: *mut u16) -> u16 {
    let mut val: u16;
    unsafe { core::arch::asm!("ldrh {1}, [{0}]", in(reg) addr, out(reg) val); }
    return val;
}

//#[inline]
//pub fn mask(addr: *mut u32, val: u32, mask: u32) {
//    write(addr, (val & mask) | (read(addr) & (!mask)));

M uart/uart.rs => uart/uart.rs +117 -40
@@ 25,7 25,7 @@ const UART_LSR: *mut u32 = (UART_BASE + 0x14) as *mut u32;
const UART_USR: *mut u32 = (UART_BASE + 0x7C) as *mut u32;

const DRAM_BASE: u32 = 0x6000_0000;
const DRAM_TEST_BASE: u32 = DRAM_BASE + 0x0000_2000; // So we don't overwrite our DRAM code
const DRAM_SIZE: u32 = 0x2000_0000;

#[no_mangle]
pub extern "C" fn main() {


@@ 33,31 33,26 @@ pub extern "C" fn main() {

    uart_puts("Hello, world!\n");

    const WORDS: u32 = 0x1_0000;
    const WRITES: u32 = 1;
    const VALUE1: u32 = 0x5A5A5A5A;
    const VALUE2: u32 = 0xA5A5A5A5;
    uart_puts("Starting DRAM tests!\n");

    for _ in 0..WRITES {
        for i in 0..WORDS {
            bits::write((DRAM_TEST_BASE + i * 4) as *mut u32, VALUE1);
        }
    for i in (0..DRAM_SIZE).step_by(1 << 13) {
        let addr = (DRAM_BASE + i) as *mut u16;
        let result = mem_test_data_bus(addr);

        for i in 0..WORDS {
            bits::write((DRAM_TEST_BASE + i * 4) as *mut u32, VALUE2);
        if result != 0 {
            uart_puts("Data bus test failed at address: ");
            uart_putx(addr as u32);
            uart_putsx(" pattern: ", result as u32);
        }
    }

    busy_wait(0xFFFF);
//    for i in (0..DRAM_SIZE).step_by(1 << 17) {
//        mem_test_address_bus(DRAM_BASE + i, 1 << 17);
//    }

    for i in 0..WORDS {
        let val = bits::read((DRAM_TEST_BASE + i * 4) as *mut u32);
        if val != VALUE2 {
            uart_puts("Bad Read! Addr: ");
            uart_putx(DRAM_TEST_BASE + i);
            uart_putsx(" Value: ", val);
        }
    }
    mem_test_address_bus(DRAM_BASE, DRAM_SIZE);

    uart_puts("Finished DRAM tests!\n");

    loop {
        let c = uart_getc();


@@ 73,30 68,112 @@ pub extern "C" fn main() {
    }
}

fn mem_test_data_bus(addr: *mut u16) -> u16 {
    let mut pattern: u16 = 1;

    while pattern != 0 {
        bits::write16(addr, pattern);

        if bits::read16(addr) != pattern {
            return pattern;
        }

        pattern <<= 1;
    }

    return 0;
}

fn mem_test_address_bus(base_addr: u32, n_bytes: u32) {
    const PATTERN: u16 = 0xAAAA;
    const ANTI_PATTERN: u16 = 0x5555;

    let address_mask: u32 = n_bytes - 1;

    let mut offset: u32 = 2;
    while (offset & address_mask) != 0 {
        bits::write16((base_addr + offset) as *mut u16, PATTERN);

        offset <<= 1;
    }

    bits::write16(base_addr as *mut u16, ANTI_PATTERN);

    offset = 2;
    while (offset & address_mask) != 0 {
        let result = bits::read16((base_addr + offset) as *mut u16);

        if result != PATTERN {
            uart_puts("Address bit stuck high. address: ");
            uart_putx(base_addr + offset);
            uart_puts(" expected value: ");
            uart_putx(PATTERN as u32);
            uart_putsx(" actual value: ", result as u32);
        }

        offset <<= 1;
    }

    bits::write16(base_addr as *mut u16, PATTERN);

    let mut test_offset: u32 = 2;
    while (test_offset & address_mask) != 0 {
        bits::write16((base_addr + test_offset) as *mut u16, ANTI_PATTERN);

        let result = bits::read16(base_addr as *mut u16);
        if result != PATTERN {
            uart_puts("Address bit stuck low or shorted. address: ");
            uart_putx(base_addr + test_offset);
            uart_puts(" expected value: ");
            uart_putx(PATTERN as u32);
            uart_putsx(" actual value: ", result as u32);
        }

        offset = 2;
        while (offset & address_mask) != 0 {
            let result = bits::read16((base_addr + offset) as *mut u16);

            if (offset != test_offset) && (result != PATTERN) {
                uart_puts("Address bit stuck low or shorted. address: ");
                uart_putx(base_addr + offset);
                uart_puts(" expected value: ");
                uart_putx(PATTERN as u32);
                uart_putsx(" actual value: ", result as u32);
            }

            offset <<= 1;
        }

        bits::write16((base_addr + test_offset) as *mut u16, PATTERN);

        test_offset <<= 1;
    }
}

fn uart_init() {
    // Disable UART interrupts
    bits::write(UART_IER, 0);
    bits::write32(UART_IER, 0);

    // Enable FIFO (and reset FIFOs)
    bits::write(UART_FCR, 0x7);
    bits::write32(UART_FCR, 0x7);

//    // No FIFO
//    bits::write(UART_FCR, 0);
//    bits::write32(UART_FCR, 0);

    // Wait until UART is not busy
    while (bits::read(UART_USR) & 0x1) != 0 {}
    while (bits::read32(UART_USR) & 0x1) != 0 {}
    const LCR_DIVISOR_LATCH: u32 = 0x80;
    const LCR_8_BIT_DATA: u32 = 0x03;
    // Set line control
    bits::write(UART_LCR, LCR_DIVISOR_LATCH | LCR_8_BIT_DATA);
    bits::write32(UART_LCR, LCR_DIVISOR_LATCH | LCR_8_BIT_DATA);

    // Setup baud rate
    // 24,000,000 / (16 * divisor) = 115,200
    // divisor = 13
    bits::write(UART_DLH, 0);
    bits::write(UART_DLL, 13);
    bits::write32(UART_DLH, 0);
    bits::write32(UART_DLL, 13);
    
    bits::write(UART_LCR, LCR_8_BIT_DATA);
    bits::write32(UART_LCR, LCR_8_BIT_DATA);
}

fn uart_puts(s: &str) {


@@ 112,19 189,19 @@ fn uart_putc(c: char) {
    const USR_TX_FIFO_NOT_FULL: u32 = 0x02;

    // Wait until there's space in the TX FIFO
    while (bits::read(UART_USR) & USR_TX_FIFO_NOT_FULL) == 0 {}
    while (bits::read32(UART_USR) & USR_TX_FIFO_NOT_FULL) == 0 {}
    // Wait until the Transmit Holding Register is empty
    while (bits::read(UART_LSR) & LSR_THRE) == 0 {}
    bits::write(UART_THR, c as u32);
    while (bits::read32(UART_LSR) & LSR_THRE) == 0 {}
    bits::write32(UART_THR, c as u32);
}

fn uart_getc() -> char {
    const LSR_DATA_READY: u32 = 0x01;

    // Wait until there's data in the RX FIFO
    while (bits::read(UART_LSR) & LSR_DATA_READY) == 0 {}
    while (bits::read32(UART_LSR) & LSR_DATA_READY) == 0 {}

    return ((bits::read(UART_RBR) & 0xFF) as u8) as char;
    return ((bits::read32(UART_RBR) & 0xFF) as u8) as char;
}

fn uart_putx(x: u32) {


@@ 147,10 224,10 @@ fn uart_putsx(s: &str, x: u32) {
    uart_puts("\n");
}

fn busy_wait(ops: u32) {
    for _ in 0..ops {
        unsafe {
            core::arch::asm!("nop");
        }
    }
}
//fn busy_wait(ops: u32) {
//    for _ in 0..ops {
//        unsafe {
//            core::arch::asm!("nop");
//        }
//    }
//}