Created
March 5, 2023 23:06
-
-
Save dogtopus/5c6c54b7d7ee9926bb2bcde02d4eaa26 to your computer and use it in GitHub Desktop.
Besta RTOS i.MX233 memory info+dumper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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:\\[email protected]"; | |
const char SDRAM_DUMP_FILE[] = "C:\\[email protected]"; | |
//const char BOOTROM_DUMP_FILE[] = "C:\\[email protected]"; | |
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