how to get the physical address of an MTD flash device on GNU/Linux? - Page 1
Forum section: electronics / general

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 03:15:31 am
content: The router has a 128Mbyte parallel bus flash.I can't figure out the memory map from the kernel driver source.Specifically I can't figure out exactly what physical address the MTD flash is mapped toGiven a running kernel that sees the flash and populates /dev/mtd*is there a way to figure it out without having to go crazy on layers and layers of unclear sources?

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 03:16:56 am
content: (I'm writing a standalone bootloader)

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 28, 2025, 05:47:04 am
content: dmesg(boot log) from a working Linux kernel, booted withoutquietand withloglevel=8, should tell it IIRC.If this is Mikrotik RB532A, then seev2.6.32/arch/mips/rb532/devices.c:plat_setup_devices(), which shows thatnand_slot0_resstart address isreadl(IDT434_REG_BASE + DEV2BASE = 0x18010020), I believe (based onv2.6.32/arch/mips/include/asm/mac-rc32434/rb.h); i.e. described at physical address 0x18010020. It makes sense that the 64 MiB (0x04000000 bytes) range is aligned, which leaves you with only 64 possible start addresses; and that because we know the RouterBOOT firmware is in ROM (and not Flash), 0x18000000 is the start address for the ROM region. For a number of reasons, I believe the four (SRAM, Flash, ROM, dual-port memory) 64 MiB ranges are mapped at 0x10000000–0x13FFFFFF, 0x14000000–0x17FFFFFF, 0x18000000–0x1BFFFFFF, and 0x1C000000–0x1FFFFFFF. Having the full IDT/Renesas RC32434 SoC documentation (for RB532/RB532A) would be quite handy here. I've only seen the 54-page datasheet, and it only says it has glue logic for SRAM, Flash, ROM, dual-port memory, with four chip selects and a 26-bit address bus (64 M).)

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 12:38:48 pm
content: Quote from: Nominal Animal on January 28, 2025, 05:47:04 amUnfortunately, it only tells about- the chip- the partitions (which are hard-coded into the kernel)- but not where the MTD is mapped.QuoteCode:RouterBOOT-2.8What do you want to configure?d - boot delayk - boot keys - serial consoleo - boot deviceu - cpu modef - try cpu frequencyc - keep cpu frequencyr - reset configuratione - format nandg - upgrade firmware <-------------i - board infop - boot protocolt - do memory testingx - exit setupyour choice:The RouterBOOT firmware shows a menu with options.Acording to option "g - update firmware", the rom0 should be "flash".Oherwise how could it be reprogrammed to be updated?(my speculation)

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 12:41:26 pm
content: Code:/** Boot loader, RouterBOOT, 1Mbit Flash chip* Attention, this information may not be correct!!!*/This is the note I wrote in the "romdump" moduleIn the future I'll also implement a de-assembly to do somereverse engineeringof (parts of) the firmwareJust because i'm tired of sending emails to the Mikrotik technical department about the various quirksthat their firmware manifests and never having answers.After all, I started writing the bootloader because i can't boot kernels bigger than 8Mbyte,neither from CF, nor from tftpboot, and i get strange messages that don't make any senseLike "out of range" (wtf?!?), when the firmware should have a window of at least 32Mbyte on the ram!Think my bootloader can alread load from serial (srec-load) up to 62Mbyte in ram without any problem!Anyway, rom0 is not the problem, I am ready to dump its contents.Code:RouterBOOT booter 2.8RouterBoard 532ACPU frequency: 399 MHzMemory size: 64 MBPress any key within 2 seconds to enter setup..trying bootp protocol... OKGot IP address: 192.168.1.41resolved mac address 00:02:8A:26:B2:1Ctransfer started transfer ok, time=0.05ssetting up elf image... OKjumping to kernel codemy-mon/mips, v0.1, Jan 2025sys_mem: 00000000..03fffffc 64Mapp_mem: 00400000..0047fffc 512k# helphelp heverregshaltresetmemmd5 md5memsize szmemdump mdrom0dump ro0dmemtest mtmemedit meload-srec lo19# rom0dump1fc00000: 00 00 00 00 00 00 00 00 07 00 00 10 00 00 00 00 | ................1fc00010: 00 00 00 00 00 b0 00 00 00 10 00 00 00 00 01 00 | ................1fc00020: 00 c0 01 00 00 10 00 00 00 68 80 40 00 00 00 00 | .........h.@....1fc00030: 00 60 02 40 00 00 00 00 18 00 01 3c 24 10 41 00 | .`.@.......<$.A.1fc00040: 40 10 01 3c 25 10 41 00 00 60 82 40 00 00 00 00 | @..<%.A..`.@....1fc00050: 00 80 03 40 00 00 00 00 ff ff 01 3c f8 ff 21 34 | ...@.......<..!41fc00060: 24 18 61 00 03 00 63 34 00 80 83 40 00 00 00 00 | $.a...c4...@....1fc00070: eb 04 11 04 00 00 00 00 c0 bf 08 3c 9c 00 08 25 | ...........<...%1fc00080: ff 1f 01 3c ff ff 21 34 24 40 01 01 00 80 01 3c | ...<..!4$@.....<1fc00090: 25 40 01 01 09 f8 00 01 00 00 00 00 03 b8 08 3c | %@.............<1fc000a0: 3c 00 00 ad 16 01 00 10 00 00 00 00 00 00 00 00 | <...............1fc000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................1fc000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................1fc000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 12:42:17 pm
content: The problems I have is all about the MTD flashCode:Routerboard 532 Flash LayoutLayer0 Hynix HY27UF081G2M Nand Flash 128MiBLayer1 mtd0 kernel mtd1 rootfsSize 4MiB 124MiBName Routerboard NAND boot rootfsfilesystem YAFFS2 YAFFS2

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 12:53:32 pm
content: Code:NAND device: Manufacturer ID: 0xad, Chip ID: 0xf1 (Hynix NAND 128MiB 3,3V 8-bit)Scanning device for bad blocksBad eraseblock 92 at 0x000000b80000Creating 2 MTD partitions on "gen_nand":0x000000000000-0x000000400000 : "Routerboard NAND boot"0x000000400000-0x000008000000 : "rootfs"kernel 2.6.32

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 10:57:20 pm
content: I fixed a cache issue and made further progress with the development mappingeth0 is integrated SoC, the Mon seems to receive the mac-addr correctly.Code:# devinfo eth00x18060000..0x18063fff kseg1 size=0x00004000 eth0Code:# memdump.u32 eth0 0x1000 8420e8f01 0000000c 420e8f01 0000000c 420e8f01 0000000c 420e8f01 0000000cThe right macaddr is 00:0C:42:0E:8F:01

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 11:08:36 pm
content: Code:Board Info:Board type: 532AFirmware version: 2.8CPU frequency: 399 MHzMemory size: 64 MBeth1 MAC address: 00:0C:42:0E:8F:01eth2 MAC address: 00:0C:42:0E:8F:02eth3 MAC address: 00:0C:42:0E:8F:03

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 11:17:12 pm
content: Quote from: Nominal Animal on January 28, 2025, 05:47:04 amI understand the coce for { serial, eth0, gpio }, and I can see them as expected, but I don't understand the code for the MTD NAND flash.It looks like it's not a linearly mapped parallel device but rather something accessed via a registers (like with hard drives).That lines about latch is not clear for me ...I have to download the datasheet.

author: DiTBho
author_rank: Super Contributor
timestamp: January 28, 2025, 11:48:39 pm
content: Hynix HY27UF081G2Mmtd-HY27UF081G2M.PDF(481.49 kB - downloaded 97 times.)

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 29, 2025, 12:53:23 am
content: Do you have the IDT/Renesas Reference Manual for the IDT/Renesas 79RC32H435 SoC as used on the RB532A?Renesas has the 54-page datasheet freely available, but the larger User Reference Manual (here) requires registration. I bet it describes how the external memory is mapped/used.

author: DiTBho
author_rank: Super Contributor
timestamp: January 29, 2025, 01:22:41 am
content: Quote from: Nominal Animal on January 29, 2025, 12:53:23 amNo i don't have. But I am willing to register there in order to download the UM.Anyway, it's classic MIPS design, and my mon has no problem addressing { ram, rom0, eth0, gpio, wdt }.They are all managed in kseg1-space, so { uncached, not mapped to the TLB }.This stuff works.The problem is the MTD chip.According to its datasheet, the Hynix HY27UF081G2M has a complex fsm to multiplex address and data.

author: DiTBho
author_rank: Super Contributor
timestamp: January 29, 2025, 01:37:51 am
content: Note the level of complexity.mtd needs special handling, just to let you read its contents.And then you have Yaffs to handle its contents as a file system.I would need that mtd flash (mtd1 specifically)to load a kernel, and to save environment datalike u-boot basically does.Personally, I hate Yaffs' code quite a bit.So, I think I'll pause this idea, and go ahead with CF and eth0 as boot devicesand let a working legacy GNU/Linux kernel (2.6.32) put my bootloader into mtd0.

author: DiTBho
author_rank: Super Contributor
timestamp: January 29, 2025, 01:53:35 am
content: Code:/** KSEG1 addresses are uncached and are not translated by the MMU.* KSEG1 is the only memory region that can be used at reset* because the MMU and caches on MIPS CPUs must be configured by the boot code,* which must be placed in KSEG1.* KSEG1 0xa0000000* KSEG1ADDR(a) ( ((a) bitwiseAnd 0x1fffffffU) bitwiseOr KSEG1)** KSEG0 provides an address region for the kernel that is cached,* but not mapped by the MMU.* KSEG0 0x80000000* KSEG0ADDR(a) ( ((a) bitwiseAnd 0x1fffffffU) bitwiseOr KSEG0)*** KSEG2 is used for kernel mode code that is mapped by the MMU and cached.** KUSEG is used for user mode code that is mapped by the MMU and cached.**/(app/mem.c, my notes)Code:# devinfo0x00000000..0x03ffffff to_kseg1 size=0x04000000 ram0x1fc00000..0x1fffffff to_kseg1 size=0x00400000 rom00x18010020..0x1801002f to_kseg1 size=0x00000010 mtd_latch0x18058000..0x1805ffff to_kseg1 size=0x00008000 uart00x18030030..0x1803003f to_kseg1 size=0x00000010 watchdog0x18060000..0x180603ff to_kseg1 size=0x00000400 eth00x18a10800..0x18a1080f to_kseg1 size=0x00000010 CF0x18050000..0x1805000f to_kseg1 size=0x00000010 gpio0x18080000..0x1808ffff to_kseg1 size=0x00010000 pciThe addresses you see here must all be translated to the kseg1 region.Above you see how to do it with a macro.The dev-sizes, except the ram one which is correct, need to be reviewed.

author: DiTBho
author_rank: Super Contributor
timestamp: January 29, 2025, 02:49:27 pm
content: Code:#include <linux/init.h>#include <linux/mtd/nand.h>#include <linux/mtd/mtd.h>#include <linux/mtd/partitions.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/bootinfo.h>#define IDT434_REG_BASE ((volatile void *) KSEG1ADDR(0x18000000))#define GPIOF 0x050000#define GPIOC 0x050004#define GPIOD 0x050008#define GPIO_RDY (1 << 0x08)#define GPIO_WPX (1 << 0x09)#define GPIO_ALE (1 << 0x0a)#define GPIO_CLE (1 << 0x0b)#define DEV2BASE 0x010020#define LO_WPX (1 << 0)#define LO_ALE (1 << 1)#define LO_CLE (1 << 2)#define LO_CEX (1 << 3)#define LO_FOFF (1 << 5)#define LO_SPICS (1 << 6)#define LO_ULED (1 << 7)#define MEM32(x) *((volatile unsigned *) (x))static void __iomem *p_nand;extern void changeLatchU5(unsigned char orMask, unsigned char nandMask);static int rb500_dev_ready(struct mtd_info *mtd){return MEM32(IDT434_REG_BASE + GPIOD) & GPIO_RDY;}/** hardware specific access to control-lines** ctrl:* NAND_CLE: bit 2 -> bit 3* NAND_ALE: bit 3 -> bit 2*/static void rbmips_hwcontrol500(struct mtd_info *mtd, int cmd,unsigned int ctrl){struct nand_chip *chip = mtd->priv;unsigned char orbits, nandbits;if (ctrl & NAND_CTRL_CHANGE) {orbits = (ctrl & NAND_CLE) << 1;orbits |= (ctrl & NAND_ALE) >> 1;nandbits = (~ctrl & NAND_CLE) << 1;nandbits |= (~ctrl & NAND_ALE) >> 1;changeLatchU5(orbits, nandbits);}if (cmd != NAND_CMD_NONE)writeb(cmd, chip->IO_ADDR_W);}static struct mtd_partition partition_info[] = {{name:"RouterBoard NAND Boot",offset:0,size:4 * 1024 * 1024},{name:"RouterBoard NAND Main",offset:MTDPART_OFS_NXTBLK,size:MTDPART_SIZ_FULL}};static struct mtd_info rmtd;static struct nand_chip rnand;static unsigned init_ok = 0;unsigned get_rbnand_block_size(void){if (init_ok)return rmtd.writesize;elsereturn 0;}EXPORT_SYMBOL(get_rbnand_block_size);int __init rbmips_init(void){int *b;memset(&rmtd, 0, sizeof(rmtd));memset(&rnand, 0, sizeof(rnand));printk("RB500 nand\n");changeLatchU5(LO_FOFF | LO_CEX,LO_ULED | LO_ALE | LO_CLE | LO_WPX);rnand.cmd_ctrl = rbmips_hwcontrol500;rnand.dev_ready = rb500_dev_ready;rnand.IO_ADDR_W = (unsigned char *)KSEG1ADDR(MEM32(IDT434_REG_BASE + DEV2BASE));rnand.IO_ADDR_R = rnand.IO_ADDR_W;p_nand = (void __iomem *) ioremap((void *) 0x18a20000, 0x1000);if (!p_nand) {printk("RBnand Unable ioremap buffer");return -ENXIO;}rnand.ecc.mode = NAND_ECC_SOFT;rnand.chip_delay = 25;rnand.options |= NAND_NO_AUTOINCR;rmtd.priv = &rnand;b = (int *) KSEG1ADDR(0x18010020);printk("dev2base 0x%08x mask 0x%08x c 0x%08x tc 0x%08x\n", b,b, b, b);if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)&& nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) {printk("RBxxx nand device not found\n");iounmap((void *) p_nand);return -ENXIO;}add_mtd_partitions(&rmtd, partition_info, 2);init_ok = 1;return 0;}module_init(rbmips_init);(driver/mtd/rbmipsnand.c)This is the old mtd_nand driver used in kernels < 2.6.23Not mainline, external patch.See, that bloody nand chip needs latch support + GPIO support to operate.

author: DiTBho
author_rank: Super Contributor
timestamp: January 30, 2025, 11:37:27 pm
content: Code:# cf_infoChecking for any CF drive ...Sent IDENTIFY .. ready# devdump cf_buff 0 51200000000: 84 8a 07 ae 00 00 00 10 00 00 02 40 00 3f 00 1e | ...........@.?..00000010: 3d 20 00 00 54 53 53 32 30 30 33 32 30 38 30 36 | = ..TSS20032080600000020: 30 36 30 32 32 38 34 31 00 02 00 02 00 04 32 30 | 06022841......2000000030: 30 37 31 31 31 36 43 46 20 31 47 42 20 20 20 20 | 071116CF 1GB00000040: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |00000050: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 80 01 | ..00000060: 00 00 02 00 00 00 02 00 00 00 00 03 07 ae 00 10 | ................00000070: 00 3f 3d 20 00 1e 01 00 3d 20 00 1e 00 00 00 00 | .?= ....= ......00000080: 00 03 00 00 00 00 00 78 00 78 00 00 00 00 00 00 | .......x.x......00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000000a0: 00 00 00 00 00 01 00 00 00 02 00 01 00 00 00 02 | ................000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000140: 00 00 00 00 00 00 04 92 00 1b 00 00 00 00 00 00 | ................00000150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................I had little time today, but I made some progress.I implemented the low-level part of the CF-pATA driverwhich is not documented, and has a few weird things.Seems working, I mean ...GNU/Linux identifies the Compact Flash on /dev/sda as "CF 1GB"Code:# cat /sys/block/sda/device/modelCF 1GBThe SoC doesn't come with any built-in ATA driver.However, for absurd reasons there seems to be a pATA controller somehow connected to the SoCwhich operates in "legacy mode", it's memory mapped, and exports a 512byte buffer at each disk command.The data is 16bit BigEndian, while the CPU is LittleEndian, so {byte0, byte1} need to be swapped {byte1, byte0}I still have to clean up the various modules, but now the machine_restart vector also works.Code:# restartbye byeRouterBOOT booter 2.8RouterBoard 532ACPU frequency: 399 MHzMemory size: 64 MB...

author: DiTBho
author_rank: Super Contributor
timestamp: January 30, 2025, 11:43:45 pm
content: I followedthiswebpage, ATA_PIO_Mode (legacy mode)Adapted to my use-case.