/** * \brief Test the data integrity * * Tests the integrity of the entire SDRAM by filling it a sequence of * incrementing 32-bit values and then verifying its content. * This is done in two passes, with an inversion of the content after * the first pass of verification. * * \note This test does not give 100% coverage for possible faults in SDRAM. * For exhaustive testing of memory, you may refer to literature on MARCH test * algorithms. * * \param test Current test case. */ void run_data_integrity_test(const struct test_case *test) { struct ebi_test_params *params; hugemem_ptr_t base; uint32_t size; uint32_t offset; uint32_t pattern; params = (struct ebi_test_params *)test_get_data(); base = params->base; size = params->size; // Fill memory with a known pattern. for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; p = (hugemem_ptr_t)((uint32_t)base + offset); hugemem_write32(p, pattern); } // Check each location and invert it for the second pass. for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; uint32_t actual; uint32_t expected; p = (hugemem_ptr_t)((uint32_t)base + offset); actual = hugemem_read32(p); test_assert_true(test, actual == pattern, "Read 0x%08lx @ 0x%08lx, expected 0x%08lx", actual, (uint32_t)p, pattern); expected = ~pattern; hugemem_write32(p, expected); } // Check each location for the inverted pattern and zero it. for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; uint32_t actual; uint32_t expected; p = (hugemem_ptr_t)((uint32_t)base + offset); expected = ~pattern; actual = hugemem_read32(p); test_assert_true(test, actual == expected, "Read 0x%08lx @ 0x%08lx, expected 0x%08lx", actual, (uint32_t)p, expected); } }
/** * \brief Perform a SDRAM data integrity test * * This function will perform a SDRAM data integrity test by writing 0s and 1s * to the entire external device. * * \param base Base address of the external memory device * \param size Size of the external memory device * * \retval STATUS_OK on success, and \ref status_code_t error code on failure */ static status_code_t ebi_test_data_integrity(hugemem_ptr_t base, uint32_t size) { uint32_t offset; uint32_t pattern; /* Fill memory with a known pattern. */ for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; p = (hugemem_ptr_t)((uint32_t)base + offset); hugemem_write32(p, pattern); } /* Check each location and invert it for the second pass. */ for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; uint32_t actual; uint32_t expected; p = (hugemem_ptr_t)((uint32_t)base + offset); actual = hugemem_read32(p); if (actual != pattern) { return ERR_IO_ERROR; } expected = ~pattern; hugemem_write32(p, expected); } /* Check each location for the inverted pattern and zero it. */ for (pattern = 1, offset = 0; offset < size; pattern++, offset += sizeof(uint32_t)) { hugemem_ptr_t p; uint32_t actual; uint32_t expected; p = (hugemem_ptr_t)((uint32_t)base + offset); expected = ~pattern; actual = hugemem_read32(p); if (actual != expected) { return ERR_IO_ERROR; } } return STATUS_OK; }
/** * \brief Test the data bus * * Tests the data bus for stuck and coupled lines by writing and verifying bit * patterns in RAM. * * First, unique 32-bit patterns with a single set bit are written to successive * locations in memory. These patterns are referred to as a walking 1 since the * bit pattern is shifted by 1 position for each new memory location. * * The patterns are then read back for verification, inverted and written back * to the memory location -- the memory locations now contain a walking 0. These * patterns are read back again for verification. * * \param test Current test case. */ void run_data_bus_test(const struct test_case *test) { struct ebi_test_params *params; hugemem_ptr_t base; hugemem_ptr_t p; uint_fast8_t i; params = (struct ebi_test_params *)test_get_data(); base = params->base; // Write walking 1s for (p = base, i = 0; i < 32; i++) { hugemem_write32(p, 1UL << i); p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } // Read walking 1s, write walking 0s for (p = base, i = 0; i < 32; i++) { uint32_t expected = 1UL << i; uint32_t actual; actual = hugemem_read32(p); test_assert_true(test, actual == expected, "Read 0x%04x, expected 0x%04x (walking 1)", actual, expected); hugemem_write32(p, ~expected); p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } // Read walking 0s for (p = base, i = 0; i < 32; i++) { uint32_t actual; uint32_t expected = ~(1UL << i); actual = hugemem_read32(p); test_assert_true(test, actual == expected, "Read 0x%04x, expected 0x%04x (walking 0)", actual, expected); p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } }
/** * \brief Test the EBI data bus wired to the SDRAM * * This function will perform a walking 1s to locate any shorts or open leads * to the SDRAM device. * * \param base Base address of the external memory device * * \retval STATUS_OK on success, and \ref status_code_t error code on failure */ static status_code_t ebi_test_data_bus(hugemem_ptr_t base) { hugemem_ptr_t p; uint_fast8_t i; /* Write walking 1s */ for (p = base, i = 0; i < 32; i++) { hugemem_write32(p, 1UL << i); p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } /* Read walking 1s, write walking 0s */ for (p = base, i = 0; i < 32; i++) { uint32_t expected = 1UL << i; uint32_t actual; actual = hugemem_read32(p); if (actual != expected) { return ERR_IO_ERROR; } hugemem_write32(p, ~expected); p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } /* Read walking 0s */ for (p = base, i = 0; i < 32; i++) { uint32_t actual; uint32_t expected = ~(1UL << i); actual = hugemem_read32(p); if (actual != expected) { return ERR_IO_ERROR; } p = (hugemem_ptr_t)((uint32_t)p + sizeof(uint32_t)); } return STATUS_OK; }
/** * * \brief Set DMA configuration, and read it back * * \note This function writes a configuration to the DMA * controller, and reads it back to verify settings have * been correctly set. * * \param test Current test case */ static void run_dma_config_interface_test(const struct test_case *test) { struct dma_channel_config config_params; struct dma_channel_config read_config; const uint16_t transfer_count = 1024; const uint8_t repeats = 64; uint8_t channel_index; #ifdef CONFIG_HAVE_HUGEMEM hugemem_ptr_t dest_huge_addr = HUGEMEM_NULL; hugemem_ptr_t src_huge_addr = HUGEMEM_NULL; hugemem_write32(dest_huge_addr, 0xABCD1234); hugemem_write32(src_huge_addr, 0xAAAABBBB); #else const uint16_t dest_addr = 0xBEEF; const uint16_t src_addr = 0xABCD; #endif memset(&config_params, 0, sizeof(config_params)); dma_enable(); /* Apply some parameters */ dma_channel_set_burst_length(&config_params, DMA_CH_BURSTLEN_4BYTE_gc); dma_channel_set_single_shot(&config_params); dma_channel_set_interrupt_level(&config_params, PMIC_LVL_HIGH); dma_channel_set_src_reload_mode(&config_params, DMA_CH_SRCRELOAD_BLOCK_gc); dma_channel_set_dest_reload_mode(&config_params, DMA_CH_DESTRELOAD_BURST_gc); dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_DEC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_DEC_gc); dma_channel_set_trigger_source(&config_params, DMA_CH_TRIGSRC_TCC0_CCA_gc); dma_channel_set_transfer_count(&config_params, transfer_count); dma_channel_set_repeats(&config_params, repeats); #ifdef CONFIG_HAVE_HUGEMEM dma_channel_set_destination_hugemem(&config_params, dest_huge_addr); dma_channel_set_source_hugemem(&config_params, src_huge_addr); #else dma_channel_set_destination_address(&config_params, dest_addr); dma_channel_set_source_address(&config_params, src_addr); #endif /* Loop through all channels, read back config from them, and verify */ for (channel_index = 0; channel_index < DMA_NUMBER_OF_CHANNELS; channel_index++) { dma_channel_write_config(channel_index, &config_params); /* Null out the read_config struct */ memset(&read_config, 0, sizeof(read_config)); /* Read the config back from the module */ dma_channel_read_config(channel_index, &read_config); test_assert_true(test, read_config.addrctrl == config_params.addrctrl, "CH %d: Address control register does not match configuration", channel_index); test_assert_true(test, read_config.ctrla == config_params.ctrla, "CH %d: Control register A does not match configuration", channel_index); test_assert_true(test, read_config.repcnt == config_params.repcnt, "CH %d: Repeat counter register does not match configuration", channel_index); test_assert_true(test, read_config.trfcnt == config_params.trfcnt, "CH %d: Transfer counter register does not" " match configuration", channel_index); test_assert_true(test, read_config.trigsrc == config_params.trigsrc, "CH %d: Trigger source register does not match configuration", channel_index); #ifdef CONFIG_HAVE_HUGEMEM test_assert_true(test, read_config.destaddr == config_params.destaddr, "CH %d: Destination address register does not" " match configuration", channel_index); test_assert_true(test, read_config.srcaddr == config_params.srcaddr, "CH %d: Source address register does not match configuration", channel_index); #else test_assert_true(test, read_config.destaddr16 == config_params.destaddr16, "CH %d: DESTADDR16 does not match configuration", channel_index); test_assert_true(test, read_config.srcaddr16 == config_params.srcaddr16, "CH %d: SRCADDR16 does not match configuration"); #endif } /* Reset the channel */ dma_channel_reset(DMA_CHANNEL_0); /* Check set and unset single shot */ memset(&config_params, 0, sizeof(config_params)); memset(&read_config, 0, sizeof(read_config)); dma_channel_set_single_shot(&config_params); dma_channel_write_config(DMA_CHANNEL_0, &config_params); dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, read_config.ctrla == config_params.ctrla, "Single shot mode not set correctly"); memset(&config_params, 0, sizeof(config_params)); dma_channel_unset_single_shot(&config_params); dma_channel_write_config(DMA_CHANNEL_0, &config_params); dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, read_config.ctrla == config_params.ctrla, "Single shot mode not unset correctly"); /* Reset it again, and test the direct configuration functions */ memset(&read_config, 0, sizeof(read_config)); dma_channel_write_burst_length(DMA_CHANNEL_0, DMA_CH_BURSTLEN_4BYTE_gc); dma_channel_write_transfer_count(DMA_CHANNEL_0, transfer_count); dma_channel_write_repeats(DMA_CHANNEL_0, repeats); #ifdef CONFIG_HAVE_HUGEMEM dma_channel_write_source_hugemem(DMA_CHANNEL_0, src_huge_addr); dma_channel_write_destination_hugemem(DMA_CHANNEL_0, dest_huge_addr); #else dma_channel_write_source(DMA_CHANNEL_0, src_addr); dma_channel_write_destination(DMA_CHANNEL_0, dest_addr); #endif /* Verify that settings have been set correctly */ dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, (read_config.ctrla & DMA_CH_BURSTLEN_gm) == DMA_CH_BURSTLEN_4BYTE_gc, "Read burst length does not match configuration"); test_assert_true(test, read_config.trfcnt == transfer_count, "Read transfer count does not match configuration"); test_assert_true(test, read_config.repcnt == repeats, "Read repeat value does not match configuration"); #ifdef CONFIG_HAVE_HUGEMEM test_assert_true(test, read_config.srcaddr == src_huge_addr, "Read source address does not match configuration"); test_assert_true(test, read_config.destaddr == dest_huge_addr, "Read destination address does not match configuration"); #else test_assert_true(test, read_config.srcaddr16 == src_addr, "Read source address does not match configuration"); test_assert_true(test, read_config.destaddr16 == dest_addr, "Read destination address does not match configuration"); #endif dma_disable(); }