Skip to content

Instantly share code, notes, and snippets.

@dogtopus
Created March 5, 2023 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dogtopus/5c6c54b7d7ee9926bb2bcde02d4eaa26 to your computer and use it in GitHub Desktop.
Save dogtopus/5c6c54b7d7ee9926bb2bcde02d4eaa26 to your computer and use it in GitHub Desktop.
Besta RTOS i.MX233 memory info+dumper
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <muteki/ui/event.h>
#include <muteki/ui/canvas.h>
#include <muteki/file.h>
#include <mutekix/console.h>
#define dbgprintf mutekix_console_printf
#define dbgputs mutekix_console_puts
const void *SDRAM_ADDR = (void *) 0x40000000;
const void *SRAM_ADDR = (void *) 0x0;
const size_t SRAM_SIZE = 0x8000;
const void *BOOTROM_ADDR = (void *) 0xc0000000;
const size_t BOOTROM_SIZE = 0x10000;
const char SRAM_DUMP_FILE[] = "C:\\sram@0x0.dmp";
const char SDRAM_DUMP_FILE[] = "C:\\sdram@0x40000000.dmp";
//const char BOOTROM_DUMP_FILE[] = "C:\\bootrom@0xc0000000.dmp";
const unsigned int CLK_XTAL24M_KHZ = 24000;
const unsigned int PLL_MULTIPLIER = 20;
volatile unsigned int *HW_CLKCTRL_EMI = (volatile unsigned int *) 0x800400a0u;
volatile unsigned int *HW_CLKCTRL_FRAC = (volatile unsigned int *) 0x800400f0u;
volatile unsigned int *HW_DIGCTL_CHIPID = (volatile unsigned int *) 0x8001c310u;
volatile unsigned int *HW_DRAM_CTL10 = (volatile unsigned int *) 0x800e0028u;
volatile unsigned int *HW_DRAM_CTL11 = (volatile unsigned int *) 0x800e002cu;
volatile unsigned int *HW_DRAM_CTL13 = (volatile unsigned int *) 0x800e0034u;
volatile unsigned int *HW_DRAM_CTL14 = (volatile unsigned int *) 0x800e0038u;
volatile unsigned int *HW_DRAM_CTL15 = (volatile unsigned int *) 0x800e003cu;
const int HW_CLKCTRL_EMI_DIV_EMI_MASK = 0x3f;
const int HW_CLKCTRL_FRAC_EMIFRAC_MASK = 0x3f;
const int HW_CLKCTRL_FRAC_EMIFRAC_SHIFT = 8;
const int HW_DIGCTL_CHIPID_REVISION_MASK = 0xff;
const int HW_DIGCTL_CHIPID_PRODUCT_CODE_MASK = 0xffff;
const int HW_DIGCTL_CHIPID_PRODUCT_CODE_SHIFT = 16;
const int HW_DRAM_CTL10_ADDR_PINS_MASK = 0x7;
const int HW_DRAM_CTL10_ADDR_PINS_SHIFT = 16;
const int HW_DRAM_CTL11_COLUMN_SIZE_MASK = 0x7;
const int HW_DRAM_CTL11_COLUMN_SIZE_SHIFT = 8;
const int HW_DRAM_CTL13_CASLAT_LIN_MASK = 0xf;
const int HW_DRAM_CTL13_CASLAT_LIN_SHIFT = 16;
const int HW_DRAM_CTL14_CS_MAP_MASK = 0xf;
const int HW_DRAM_CTL14_MAX_COL_REG_MASK = 0xf;
const int HW_DRAM_CTL14_MAX_COL_REG_SHIFT = 24;
const int HW_DRAM_CTL15_MAX_ROW_REG_MASK = 0xf;
// Max column and row.
const unsigned int MAXC = 12;
const unsigned int MAXR = 13;
bool mem_dump(const char *destfile, const void *src, size_t len) {
FILE *destf = fopen(destfile, "w");
if (destf == NULL) {
return false;
}
size_t result = fwrite(src, 1, len, destf);
fclose(destf);
if (result == len) {
return true;
} else {
return false;
}
}
size_t read_memory_capacity() {
// row and column shifts
unsigned int row_shift = ((*HW_DRAM_CTL10) >> HW_DRAM_CTL10_ADDR_PINS_SHIFT) & HW_DRAM_CTL10_ADDR_PINS_MASK;
unsigned int col_shift = ((*HW_DRAM_CTL11) >> HW_DRAM_CTL11_COLUMN_SIZE_SHIFT) & HW_DRAM_CTL11_COLUMN_SIZE_MASK;
// chips TODO: split it into its own function?
unsigned int cs_map = (*HW_DRAM_CTL14) & HW_DRAM_CTL14_CS_MAP_MASK;
int nchips = 0;
for (unsigned int cm=cs_map; cm!=0; cm>>=1) {
if ((cm & 1) == 1) {
nchips++;
}
}
#ifdef DEBUG
dbgprintf("HW_DRAM_CTL10_ADDR_PINS = %u, HW_DRAM_CTL11_COLUMN_SIZE = %u, HW_DRAM_CTL14_CS_MAP = %#03x\n", row_shift, col_shift, cs_map);
#endif
size_t nbytes = 2 * (1 << (MAXR-row_shift)) * (1 << (MAXC-col_shift)) * nchips * 4;
return nbytes;
}
bool identify() {
// TODO temporarily override abort handler to trap aborts
unsigned int chip_id = *HW_DIGCTL_CHIPID;
// TODO reset the trap
unsigned int prod_id = (chip_id >> HW_DIGCTL_CHIPID_PRODUCT_CODE_SHIFT) & HW_DIGCTL_CHIPID_PRODUCT_CODE_MASK;
unsigned int rev = chip_id & HW_DIGCTL_CHIPID_REVISION_MASK;
if (prod_id == 0x3780) {
dbgprintf("Found i.MX233 revision TA%d.\n", rev+1);
return true;
} else {
dbgputs("ERROR: Unknown device.");
return false;
}
}
int wait_for_key_press() {
ui_event_t uievent = {0};
while (true) {
if ((TestPendEvent(&uievent) || TestKeyEvent(&uievent)) && GetEvent(&uievent)) {
return uievent.key_code0;
}
}
}
void print_memory_info() {
unsigned int div_emi = (*HW_CLKCTRL_EMI) & HW_CLKCTRL_EMI_DIV_EMI_MASK;
unsigned int emifrac = ((*HW_CLKCTRL_FRAC) >> HW_CLKCTRL_FRAC_EMIFRAC_SHIFT) & HW_CLKCTRL_FRAC_EMIFRAC_MASK;
unsigned int clk_emi_khz = (18 * CLK_XTAL24M_KHZ * PLL_MULTIPLIER / emifrac) / div_emi;
unsigned int clk_emi_mhz = clk_emi_khz / 1000;
unsigned int clk_emi_khz_r = clk_emi_khz % 1000;
if (clk_emi_khz_r % 10 >= 5) {
clk_emi_khz_r++;
}
if (clk_emi_khz_r == 1000) {
clk_emi_mhz++;
clk_emi_khz_r = 0;
}
unsigned int cl2 = ((*HW_DRAM_CTL13) >> HW_DRAM_CTL13_CASLAT_LIN_SHIFT) & HW_DRAM_CTL13_CASLAT_LIN_MASK;
// TODO actually detect if the controller is in SDR or DDR mode.
dbgprintf("SDRAM type: %s %u.%03uMHz CL%u%s\n", "DDR", clk_emi_mhz, clk_emi_khz_r, cl2 / 2, (((cl2 % 2) == 0) ? "" : ".5"));
unsigned int cs_map = (*HW_DRAM_CTL14) & HW_DRAM_CTL14_CS_MAP_MASK;
dbgprintf("Chips populated:");
unsigned int chip_index = 0;
while (cs_map != 0) {
if ((cs_map & 1) == 1) {
dbgprintf(" #%d", chip_index);
}
cs_map >>= 1;
chip_index++;
}
dbgputs("");
size_t capacity = read_memory_capacity();
if ((capacity % 0x100000) != 0) {
dbgputs("WARNING: SDRAM size is not multiple of MiBs.\n");
}
dbgprintf("Total SDRAM size: %u MiB (%zu)\n", capacity / 0x100000, capacity);
dbgputs("");
}
void dump_all() {
size_t sdram_size = read_memory_capacity();
dbgprintf("Dumping SRAM of size %#zx @ %#010x to %s...\n", SRAM_SIZE, (unsigned int) SRAM_ADDR, SRAM_DUMP_FILE);
if (!mem_dump(SRAM_DUMP_FILE, SRAM_ADDR, SRAM_SIZE)) {
dbgprintf("Error writing to %s.\n", SRAM_DUMP_FILE);
}
dbgprintf("Dumping SDRAM of size %#zx @ %#010x to %s\n", sdram_size, (unsigned int) SDRAM_ADDR, SDRAM_DUMP_FILE);
if (!mem_dump(SDRAM_DUMP_FILE, SDRAM_ADDR, sdram_size)) {
dbgprintf("Error writing to %s.\n", SDRAM_DUMP_FILE);
}
/*
dbgprintf("Dumping BootROM of size %#zx @ %#010x to %s\n", BOOTROM_SIZE, (unsigned int) BOOTROM_ADDR, BOOTROM_DUMP_FILE);
if (!mem_dump(BOOTROM_DUMP_FILE, BOOTROM_ADDR, BOOTROM_SIZE)) {
dbgprintf("Error writing to %s.\n", BOOTROM_DUMP_FILE);
}
*/
dbgputs("");
}
int main() {
bool waiting_for_option = true;
bool reprint_options = true;
mutekix_console_init(NULL);
dbgputs("Muteki i.MX233 Memory Info");
if (!identify()) {
wait_for_key_press();
mutekix_console_fini();
return 0;
}
while (waiting_for_option) {
if (reprint_options) {
dbgputs("Select an option:");
dbgputs("1: Memory info");
dbgputs("2: Dump memory to file");
dbgputs("Q: Quit\n");
}
switch (wait_for_key_press()) {
case KEY_1:
print_memory_info();
reprint_options = true;
break;
case KEY_2:
dump_all();
reprint_options = true;
break;
case KEY_Q: // fall-through
case KEY_ESC:
waiting_for_option = false;
reprint_options = false;
break;
default:
reprint_options = false;
break;
}
ClearAllEvents();
}
mutekix_console_fini();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment