|  | /* | 
|  | * (C) Copyright 2005 | 
|  | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | * | 
|  | * The test exercises SDRAM accesses in burst mode | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <exports.h> | 
|  |  | 
|  | #include <commproc.h> | 
|  | #include <asm/mmu.h> | 
|  | #include <asm/processor.h> | 
|  |  | 
|  | #include <serial.h> | 
|  | #include <watchdog.h> | 
|  |  | 
|  | #include "test_burst.h" | 
|  |  | 
|  | /* 8 MB test region of physical RAM */ | 
|  | #define TEST_PADDR	0x00800000 | 
|  | /* The uncached virtual region */ | 
|  | #define TEST_VADDR_NC	0x00800000 | 
|  | /* The cached virtual region */ | 
|  | #define TEST_VADDR_C	0x01000000 | 
|  | /* When an error is detected, the address where the error has been found, | 
|  | and also the current and the expected data will be written to | 
|  | the following flash address | 
|  | */ | 
|  | #define TEST_FLASH_ADDR	0x40100000 | 
|  |  | 
|  | /* Define GPIO ports to signal start of burst transfers and errors */ | 
|  | #ifdef CONFIG_LWMON | 
|  | /* Use PD.8 to signal start of burst transfers */ | 
|  | #define GPIO1_DAT	(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat) | 
|  | #define GPIO1_BIT	0x0080 | 
|  | /* Configure PD.8 as general purpose output */ | 
|  | #define GPIO1_INIT \ | 
|  | ((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar &= ~GPIO1_BIT; \ | 
|  | ((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir |=  GPIO1_BIT; | 
|  | /* Use PD.9 to signal error */ | 
|  | #define GPIO2_DAT	(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat) | 
|  | #define GPIO2_BIT	0x0040 | 
|  | /* Configure PD.9 as general purpose output */ | 
|  | #define GPIO2_INIT \ | 
|  | ((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar &= ~GPIO2_BIT; \ | 
|  | ((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir |=  GPIO2_BIT; | 
|  | #endif /* CONFIG_LWMON */ | 
|  |  | 
|  |  | 
|  | static void test_prepare (void); | 
|  | static int test_burst_start (unsigned long size, unsigned long pattern); | 
|  | static void test_map_8M (unsigned long paddr, unsigned long vaddr, int cached); | 
|  | static int test_mmu_is_on(void); | 
|  | static void test_desc(unsigned long size); | 
|  | static void test_error(char * step, volatile void * addr, unsigned long val, unsigned long pattern); | 
|  | static void signal_init(void); | 
|  | static void signal_start(void); | 
|  | static void signal_error(void); | 
|  | static void test_usage(void); | 
|  |  | 
|  | static unsigned long test_pattern [] = { | 
|  | 0x00000000, | 
|  | 0xffffffff, | 
|  | 0x55555555, | 
|  | 0xaaaaaaaa, | 
|  | }; | 
|  |  | 
|  |  | 
|  | int test_burst (int argc, char *argv[]) | 
|  | { | 
|  | unsigned long size = CACHE_LINE_SIZE; | 
|  | unsigned int pass = 0; | 
|  | int res = 0; | 
|  | int i, j; | 
|  |  | 
|  | if (argc == 3) { | 
|  | char * d; | 
|  | for (size = 0, d = argv[1]; *d >= '0' && *d <= '9'; d++) { | 
|  | size *= 10; | 
|  | size += *d - '0'; | 
|  | } | 
|  | if (size == 0 || *d) { | 
|  | test_usage(); | 
|  | return 1; | 
|  | } | 
|  | for (d = argv[2]; *d >= '0' && *d <= '9'; d++) { | 
|  | pass *= 10; | 
|  | pass += *d - '0'; | 
|  | } | 
|  | if (*d) { | 
|  | test_usage(); | 
|  | return 1; | 
|  | } | 
|  | } else if (argc > 3) { | 
|  | test_usage(); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | size +=  (CACHE_LINE_SIZE - 1); | 
|  | size &= ~(CACHE_LINE_SIZE - 1); | 
|  |  | 
|  | if (!test_mmu_is_on()) { | 
|  | test_prepare(); | 
|  | } | 
|  |  | 
|  | test_desc(size); | 
|  |  | 
|  | for (j = 0; !pass || j < pass; j++) { | 
|  | for (i = 0; i < sizeof(test_pattern) / sizeof(test_pattern[0]); | 
|  | i++) { | 
|  | res = test_burst_start(size, test_pattern[i]); | 
|  | if (res != 0) { | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | printf ("Iteration #%d passed\n", j + 1); | 
|  |  | 
|  | if (tstc() && 0x03 == getc()) | 
|  | break; | 
|  | } | 
|  | Done: | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static void test_prepare (void) | 
|  | { | 
|  | printf ("\n"); | 
|  |  | 
|  | caches_init(); | 
|  | disable_interrupts(); | 
|  | mmu_init(); | 
|  |  | 
|  | printf ("Interrupts are disabled\n"); | 
|  | printf ("I-Cache is ON\n"); | 
|  | printf ("D-Cache is ON\n"); | 
|  | printf ("MMU is ON\n"); | 
|  |  | 
|  | printf ("\n"); | 
|  |  | 
|  | test_map_8M (TEST_PADDR, TEST_VADDR_NC, 0); | 
|  | test_map_8M (TEST_PADDR, TEST_VADDR_C,  1); | 
|  |  | 
|  | test_map_8M (TEST_FLASH_ADDR & 0xFF800000, TEST_FLASH_ADDR & 0xFF800000, 0); | 
|  |  | 
|  | /* Configure GPIO ports */ | 
|  | signal_init(); | 
|  | } | 
|  |  | 
|  | static int test_burst_start (unsigned long size, unsigned long pattern) | 
|  | { | 
|  | volatile unsigned long * vaddr_c = (unsigned long *)TEST_VADDR_C; | 
|  | volatile unsigned long * vaddr_nc = (unsigned long *)TEST_VADDR_NC; | 
|  | int i, n; | 
|  | int res = 1; | 
|  |  | 
|  | printf ("Test pattern %08lx ...", pattern); | 
|  |  | 
|  | n = size / 4; | 
|  |  | 
|  | for (i = 0; i < n; i ++) { | 
|  | vaddr_c [i] = pattern; | 
|  | } | 
|  | signal_start(); | 
|  | flush_dcache_range((unsigned long)vaddr_c, (unsigned long)(vaddr_c + n) - 1); | 
|  |  | 
|  | for (i = 0; i < n; i ++) { | 
|  | register unsigned long tmp = vaddr_nc [i]; | 
|  | if (tmp != pattern) { | 
|  | test_error("2a", vaddr_nc + i, tmp, pattern); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = 0; i < n; i ++) { | 
|  | register unsigned long tmp = vaddr_c [i]; | 
|  | if (tmp != pattern) { | 
|  | test_error("2b", vaddr_c + i, tmp, pattern); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = 0; i < n; i ++) { | 
|  | vaddr_nc [i] = pattern; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < n; i ++) { | 
|  | register unsigned long tmp = vaddr_nc [i]; | 
|  | if (tmp != pattern) { | 
|  | test_error("3a", vaddr_nc + i, tmp, pattern); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | signal_start(); | 
|  | for (i = 0; i < n; i ++) { | 
|  | register unsigned long tmp = vaddr_c [i]; | 
|  | if (tmp != pattern) { | 
|  | test_error("3b", vaddr_c + i, tmp, pattern); | 
|  | goto Done; | 
|  | } | 
|  | } | 
|  |  | 
|  | res = 0; | 
|  | Done: | 
|  | printf(" %s\n", res == 0 ? "OK" : ""); | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | static void test_map_8M (unsigned long paddr, unsigned long vaddr, int cached) | 
|  | { | 
|  | mtspr (MD_EPN, (vaddr & 0xFFFFFC00) | MI_EVALID); | 
|  | mtspr (MD_TWC, MI_PS8MEG | MI_SVALID); | 
|  | mtspr (MD_RPN, (paddr & 0xFFFFF000) | MI_BOOTINIT | (cached ? 0 : 2)); | 
|  | mtspr (MD_AP, MI_Kp); | 
|  | } | 
|  |  | 
|  | static int test_mmu_is_on(void) | 
|  | { | 
|  | unsigned long msr; | 
|  |  | 
|  | asm volatile("mfmsr %0" : "=r" (msr) :); | 
|  |  | 
|  | return msr & MSR_DR; | 
|  | } | 
|  |  | 
|  | static void test_desc(unsigned long size) | 
|  | { | 
|  | printf( | 
|  | "The following tests will be conducted:\n" | 
|  | "1)  Map %ld-byte region of physical RAM at 0x%08x\n" | 
|  | "    into two virtual regions:\n" | 
|  | "    one cached at 0x%08x and\n" | 
|  | "    the the other uncached at 0x%08x.\n", | 
|  | size, TEST_PADDR, TEST_VADDR_NC, TEST_VADDR_C); | 
|  |  | 
|  | puts( | 
|  | "2)  Fill the cached region with a pattern, and flush the cache\n" | 
|  | "2a) Check the uncached region to match the pattern\n" | 
|  | "2b) Check the cached region to match the pattern\n" | 
|  | "3)  Fill the uncached region with a pattern\n" | 
|  | "3a) Check the cached region to match the pattern\n" | 
|  | "3b) Check the uncached region to match the pattern\n" | 
|  | "2b) Change the patterns and go to step 2\n" | 
|  | "\n" | 
|  | ); | 
|  | } | 
|  |  | 
|  | static void test_error( | 
|  | char * step, volatile void * addr, unsigned long val, unsigned long pattern) | 
|  | { | 
|  | volatile unsigned long * p = (void *)TEST_FLASH_ADDR; | 
|  |  | 
|  | signal_error(); | 
|  |  | 
|  | p[0] = (unsigned long)addr; | 
|  | p[1] = val; | 
|  | p[2] = pattern; | 
|  |  | 
|  | printf ("\nError at step %s, addr %08lx: read %08lx, pattern %08lx", | 
|  | step, (unsigned long)addr, val, pattern); | 
|  | } | 
|  |  | 
|  | static void signal_init(void) | 
|  | { | 
|  | #if defined(GPIO1_INIT) | 
|  | GPIO1_INIT; | 
|  | #endif | 
|  | #if defined(GPIO2_INIT) | 
|  | GPIO2_INIT; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void signal_start(void) | 
|  | { | 
|  | #if defined(GPIO1_INIT) | 
|  | if (GPIO1_DAT & GPIO1_BIT) { | 
|  | GPIO1_DAT &= ~GPIO1_BIT; | 
|  | } else { | 
|  | GPIO1_DAT |= GPIO1_BIT; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void signal_error(void) | 
|  | { | 
|  | #if defined(GPIO2_INIT) | 
|  | if (GPIO2_DAT & GPIO2_BIT) { | 
|  | GPIO2_DAT &= ~GPIO2_BIT; | 
|  | } else { | 
|  | GPIO2_DAT |= GPIO2_BIT; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void test_usage(void) | 
|  | { | 
|  | printf("Usage: go 0x40004 [size] [count]\n"); | 
|  | } |