Yes, I finally got these Groove 52HPn radios working!
It turns out that when Mikrotik dropped the NAND flash, they also swapped out the previous 128K w25x10 NOR flash with a 16MB w25q128 flash chip.
Normally, the flash driver would auto-detect the larger flash chip based on the JEDEC id, but the current mach-rb91x.c defines the flash chip as a 64K pm25lv512 which doesn't have any JEDEC id so the flash driver couldn't auto-detect the flash chip.
However, a more difficult problem was building a kernel image for NOR flash which the Mikrotik routerboot could recognize. Mikrotik routerboot only recognizes yaffs file systems, and the Linux yaffs driver only understands NAND flash, not NOR flash! Mikrotik evidently uses custom patches to their yaffs driver which requires a non-standard 1K block size with 16-byte OOB data written between each NOR flash block.
After much searching, I found that LEDE includes support for many SPI NOR flash based Mikrotik devices, although they don't yet support the 52HPn. However, LEDE includes a new tool named kernel2minor (ie. kernel to Mikrotik NOR). This tool takes a standard compressed Linux kernel and creates a properly aligned yaffs image which can be written to either NAND or NOR flash on Mikrotik devices. This tool eliminates the need for a yaffs2 driver in the Linux kernel to just write the silly Mikrotik kernel image!
Below are my patches to the mach-rb91x.c driver to handle the Groove 52HPn routers. Note that I haven't tested these changes for compatibility with the previously supported rb711 board, however I don't think I broke anything unless it actually uses a 64K pm25lv512 without a JEDEC id. I have a hunch that this board probably uses a flash chip which does support JEDEC.
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
index 75382be..0fd03ff 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
@@ -41,14 +42,6 @@
#include "pci.h"
#include "routerboot.h"
-#define RB_ROUTERBOOT_OFFSET 0x0000
-#define RB_ROUTERBOOT_MIN_SIZE 0xb000
-#define RB_HARD_CFG_SIZE 0x1000
-#define RB_BIOS_OFFSET 0xd000
-#define RB_BIOS_SIZE 0x1000
-#define RB_SOFT_CFG_OFFSET 0xf000
-#define RB_SOFT_CFG_SIZE 0x1000
-
#define RB91X_FLAG_USB BIT(0)
#define RB91X_FLAG_PCIE BIT(1)
@@ -94,26 +87,37 @@ struct rb_board_info {
static struct mtd_partition rb711gr100_spi_partitions[] = {
{
.name = "routerboot",
- .offset = RB_ROUTERBOOT_OFFSET,
+ .offset = 0,
+ .size = 0x0e000,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "hard_config",
- .size = RB_HARD_CFG_SIZE,
- .mask_flags = MTD_WRITEABLE,
- }, {
- .name = "bios",
- .offset = RB_BIOS_OFFSET,
- .size = RB_BIOS_SIZE,
+ .offset = 0x0e000,
+ .size = 0x01000,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "soft_config",
- .size = RB_SOFT_CFG_SIZE,
- }
+ .offset = 0x0f000,
+ .size = 0x01000,
+ }, {
+ .name = "kernel",
+ .offset = 0x020000,
+ .size = 0x180000,
+ }, {
+ .name = "rootfs",
+ .offset = 0x1a0000,
+ .size = 0x180000,
+ }, {
+ .name = "ubifs",
+ .offset = 0x320000,
+ .size = MTDPART_SIZ_FULL
+ },
};
static struct flash_platform_data rb711gr100_spi_flash_data = {
+ .type = "m25p05",
.parts = rb711gr100_spi_partitions,
- .nr_parts = ARRAY_SIZE(rb711gr100_spi_partitions),
+ .nr_parts = 3,
};
static int rb711gr100_gpio_latch_gpios[AR934X_GPIO_COUNT] __initdata = {
@@ -223,12 +227,25 @@ static struct gpio_led rb711gr100_leds[] __initdata = {
},
};
+static struct at803x_platform_data rb91x_at803x_data = {
+ .disable_smarteee = 1,
+ .enable_rgmii_rx_delay = 1,
+ .enable_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info rb91x_mdio0_info[] = {
+ {
+ .bus_id = "ag71xx-mdio.0",
+ .phy_addr = 0,
+ .platform_data = &rb91x_at803x_data,
+ },
+};
+
static void __init rb711gr100_init_partitions(const struct rb_info *info)
{
rb711gr100_spi_partitions[0].size = info->hard_cfg_offs;
rb711gr100_spi_partitions[1].offset = info->hard_cfg_offs;
-
- rb711gr100_spi_partitions[3].offset = info->soft_cfg_offs;
+ rb711gr100_spi_partitions[2].offset = info->soft_cfg_offs;
}
void __init rb711gr100_wlan_init(void)
@@ -293,10 +310,14 @@ static void __init rb711gr100_setup(void)
ARRAY_SIZE(rb711gr100_spi_info));
ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+ AR934X_ETH_CFG_RXD_DELAY |
AR934X_ETH_CFG_SW_ONLY_MODE);
ath79_register_mdio(0, 0x0);
+ mdiobus_register_board_info(rb91x_mdio0_info,
+ ARRAY_SIZE(rb91x_mdio0_info));
+
ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
ath79_eth0_data.phy_mask = BIT(0);
@@ -328,3 +349,69 @@ static void __init rb711gr100_setup(void)
}
MIPS_MACHINE_NONAME(ATH79_MACH_RB_711GR100, "711Gr100", rb711gr100_setup);
+
+static struct gpio_led rbgroove_leds_gpio[] __initdata = {
+ {
+ .name = "rbgroove:wlan:1",
+ .gpio = 0,
+ .active_low = 0,
+ }, {
+ .name = "rbgroove:wlan:2",
+ .gpio = 1,
+ .active_low = 0,
+ }, {
+ .name = "rbgroove:wlan:3",
+ .gpio = 2,
+ .active_low = 0,
+ }
+};
+
+static int nand_disabled;
+
+static int __init no_nand(char *str)
+{
+ nand_disabled = 1;
+ return 0;
+}
+
+early_param("no-nand", no_nand);
+
+static void __init rbgroove_setup(void)
+{
+ const struct rb_info *info;
+
+ info = rb_init_info((void *) KSEG1ADDR(0x1f000000), 0x20000);
+ if (!info)
+ return;
+
+ rb711gr100_init_partitions(info);
+ if (nand_disabled) {
+ printk(KERN_NOTICE "using SPI flash for root\n");
+ rb711gr100_spi_flash_data.nr_parts = ARRAY_SIZE(rb711gr100_spi_partitions);
+ }
+ ath79_register_spi(&rb711gr100_spi_data, rb711gr100_spi_info, 1);
+
+ ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_MII_GMAC0);
+
+ ath79_register_mdio(0, 0x0);
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+ ath79_eth0_data.phy_mask = BIT(0);
+
+ ath79_register_eth(0);
+ rb711gr100_wlan_init();
+
+ if (!nand_disabled) {
+ printk(KERN_NOTICE "using NAND flash for root\n");
+ platform_device_register_data(NULL, "rb91x-nand", -1,
+ &rb711gr100_nand_data,
+ sizeof(rb711gr100_nand_data));
+ }
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(rbgroove_leds_gpio),
+ rbgroove_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_GROOVE, "groove-52", "MikroTik 52HPn",
+ rbgroove_setup);