ar71xx: add support for Cisco's MR18
authorJohn Crispin <john@openwrt.org>
Sat, 12 Dec 2015 06:42:29 +0000 (06:42 +0000)
committerJohn Crispin <john@openwrt.org>
Sat, 12 Dec 2015 06:42:29 +0000 (06:42 +0000)
This patch adds support for Cisco's MR18.
Detailed instructions for the flashing the device can
be found in the OpenWrt forum thread:
<https://forum.openwrt.org/viewtopic.php?id=59248>

Signed-off-by: Chris R Blake <chrisrblake93@gmail.com>
SVN-Revision: 47878

16 files changed:
target/linux/ar71xx/base-files/etc/board.d/01_leds
target/linux/ar71xx/base-files/etc/board.d/02_network
target/linux/ar71xx/base-files/etc/diag.sh
target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
target/linux/ar71xx/base-files/lib/ar71xx.sh
target/linux/ar71xx/base-files/lib/preinit/05_set_iface_mac_ar71xx
target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh [new file with mode: 0644]
target/linux/ar71xx/base-files/lib/upgrade/platform.sh
target/linux/ar71xx/config-4.1
target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
target/linux/ar71xx/files/arch/mips/ath79/Makefile
target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c [new file with mode: 0644]
target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
target/linux/ar71xx/image/Makefile
target/linux/ar71xx/nand/config-default
target/linux/ar71xx/nand/profiles/meraki.mk [new file with mode: 0644]

index 33f8377..d4f226e 100755 (executable)
@@ -283,6 +283,10 @@ mr16)
        ucidef_set_led_wlan "wlan4" "WLAN4" "mr16:green:wifi4" "phy0tpt"
        ;;
 
+mr18)
+       ucidef_set_led_netdev "wlan0" "WLAN0" "mr18:blue:tricolor0" "wlan0"
+       ;;
+
 mr600)
        ucidef_set_led_wlan "wlan58" "WLAN58" "mr600:green:wlan58" "phy0tpt"
        ;;
index 0e77e93..11c4341 100755 (executable)
@@ -313,6 +313,7 @@ eap7660d |\
 el-mini |\
 loco-m-xw |\
 mr1750 |\
+mr18 |\
 mr600 |\
 mr600v2 |\
 mr900 |\
index 5b997e0..0e1df10 100644 (file)
@@ -152,6 +152,9 @@ get_status_led() {
        mr16)
                status_led="mr16:green:power"
                ;;
+       mr18)
+               status_led="mr18:green:tricolor0"
+               ;;
        mr600)
                status_led="mr600:orange:power"
                ;;
index b5f0588..5398e76 100644 (file)
@@ -38,6 +38,14 @@ board=$(ar71xx_board_name)
 case "$FIRMWARE" in
 "soc_wmac.eeprom")
        case $board in
+       mr18)
+               if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+                       ath9k_ubi_eeprom_extract "caldata" 4096 2048
+               else
+                       ath9k_eeprom_extract "odm-caldata" 4096 2048
+               fi
+               ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +1)
+               ;;
        r6100 | \
        wndr3700v4 | \
        wndr4300)
@@ -52,6 +60,14 @@ case "$FIRMWARE" in
 
 "pci_wmac0.eeprom")
        case $board in
+       mr18)
+               if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+                       ath9k_ubi_eeprom_extract "caldata" 20480 2048
+               else
+                       ath9k_eeprom_extract "odm-caldata" 20480 2048
+               fi
+               ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +2)
+               ;;
        wndr3700v4 | \
        wndr4300)
                ath9k_eeprom_extract "caldata" 20480 2048
@@ -62,4 +78,20 @@ case "$FIRMWARE" in
                ;;
        esac
        ;;
+
+"pci_wmac1.eeprom")
+       case $board in
+       mr18)
+               if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+                       ath9k_ubi_eeprom_extract "caldata" 36864 2048
+               else
+                       ath9k_eeprom_extract "odm-caldata" 36864 2048
+               fi
+               ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +3)
+               ;;
+       *)
+               ath9k_eeprom_die "board $board is not supported yet"
+               ;;
+       esac
+       ;;
 esac
index a112523..54e6166 100755 (executable)
@@ -551,6 +551,9 @@ ar71xx_board_detect() {
        *MR16)
                name="mr16"
                ;;
+       *MR18)
+               name="mr18"
+               ;;
        *MR600v2)
                name="mr600v2"
                ;;
index 92b3765..a9f4bf5 100644 (file)
@@ -29,6 +29,10 @@ preinit_set_mac_address() {
                dir-615-i1)
                        fetch_mac_from_mtd nvram sys_lan_mac sys_wan_mac
                        ;;
+               mr18)
+                       mac_lan=$(mtd_get_mac_binary_ubi board-config 102)
+                       [ -n "$mac_lan" ] && ifconfig eth0 hw ether "$mac_lan"
+                       ;;
                r6100)
                        mac_lan=$(mtd_get_mac_binary caldata 0)
                        [ -n "$mac_lan" ] && ifconfig eth1 hw ether "$mac_lan"
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh b/target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh
new file mode 100644 (file)
index 0000000..fe78e9f
--- /dev/null
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 Chris Blake <chrisrblake93@gmail.com>
+#
+# Custom upgrade script for Meraki NAND devices (ex. MR18)
+# Based on dir825.sh and stock nand functions
+#
+. /lib/ar71xx.sh
+. /lib/functions.sh
+. /lib/upgrade/nand.sh
+
+get_magic_at() {
+       local mtddev=$1
+       local pos=$2
+       dd bs=1 count=2 skip=$pos if=$mtddev 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+mr18_is_caldata_valid() {
+       local mtddev=$1
+       local magic
+
+       magic=$(get_magic_at $mtddev 4096)
+       [ "$magic" != "0202" ] && return 0
+
+       magic=$(get_magic_at $mtddev 20480)
+       [ "$magic" != "0202" ] && return 0
+
+       magic=$(get_magic_at $mtddev 36864)
+       [ "$magic" != "0202" ] && return 0
+
+       return 1
+}
+
+merakinand_copy_caldata() {
+       local cal_src=$1
+       local cal_dst=$2
+       local ubidev=$( nand_find_ubi $CI_UBIPART )
+       local board_name="$(cat /tmp/sysinfo/board_name)"
+       local rootfs_size="$(ubinfo /dev/ubi0 -N rootfs_data | grep "Size" | awk '{ print $6 }')"
+
+       # Setup partitions using board name, in case of future platforms
+       case "$board_name" in
+       "mr18")
+               # Src is MTD
+               mtd_src=$(find_mtd_chardev $cal_src)
+               [ -n "$mtd_src" ] || {
+                       echo "no mtd device found for partition $cal_src"
+                       exit 1
+               }
+
+               # Dest is UBI
+               # TODO: possibly add create (hard to do when rootfs_data is expanded & mounted)
+               # Would need to be done from ramdisk
+               mtd_dst="$(nand_find_volume $ubidev $cal_dst)"
+               [ -n "$mtd_dst" ] || {
+                       echo "no ubi device found for partition $cal_dst"
+                       exit 1
+               }
+
+               mr18_is_caldata_valid "$mtd_src" && {
+                       echo "no valid calibration data found in $cal_src"
+                       exit 1
+               }
+
+               mr18_is_caldata_valid "/dev/$mtd_dst" && {
+                       echo "Copying calibration data from $cal_src to $cal_dst..."
+                       dd if="$mtd_src" of=/tmp/caldata.tmp 2>/dev/null
+                       ubiupdatevol "/dev/$mtd_dst" /tmp/caldata.tmp
+                       rm /tmp/caldata.tmp
+                       sync
+               }
+               return 0
+               ;;
+       *)
+               echo "Unsupported device $board_name";
+               return 1
+               ;;
+       esac
+}
+
+merakinand_do_kernel_check() {
+       local board_name="$1"
+       local tar_file="$2"
+       local image_magic_word=`(tar xf $tar_file sysupgrade-$board_name/kernel -O 2>/dev/null | dd bs=1 count=4 skip=0 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"')`
+
+       # What is our kernel magic string?
+       case "$board_name" in
+       "mr18")
+               [ "$image_magic_word" == "8e73ed8a" ] && {
+                       echo "pass" && return 0
+               }
+               ;;
+       esac
+
+       exit 1
+}
+
+merakinand_do_platform_check() {
+       local board_name="$1"
+       local tar_file="$2"
+       local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+       local file_type="$(identify_tar $2 sysupgrade-$board_name/root)"
+       local kernel_magic="$(merakinand_do_kernel_check $1 $2)"
+
+       case "$board_name" in
+       "mr18")
+               [ "$control_length" = 0 -o "$file_type" != "squashfs" -o "$kernel_magic" != "pass" ] && {
+                       echo "Invalid sysupgrade file for $board_name"
+                       return 1
+               }
+               ;;
+       *)
+               echo "Unsupported device $board_name";
+               return 1
+               ;;
+       esac
+
+       return 0
+}
+
+merakinand_do_upgrade() {
+       local tar_file="$1"
+       local board_name="$(cat /tmp/sysinfo/board_name)"
+
+       # Do we need to do any platform tweaks?
+       case "$board_name" in
+       "mr18")
+               # Check and create UBI caldata if it's invalid
+               merakinand_copy_caldata "odm-caldata" "caldata"
+               nand_do_upgrade $1
+               ;;
+       *)
+               echo "Unsupported device $board_name";
+               exit 1
+               ;;
+       esac
+}
index 5ec4499..bb64ef8 100755 (executable)
@@ -434,6 +434,10 @@ platform_check_image() {
                }
                return 0
                ;;
+       mr18)
+               merakinand_do_platform_check $board $1
+               return $?;
+               ;;
        nbg6716 | \
        r6100 | \
        wndr3700v4 | \
@@ -494,6 +498,9 @@ platform_pre_upgrade() {
        wndr4300 )
                nand_do_upgrade "$1"
                ;;
+       mr18)
+               merakinand_do_upgrade "$1"
+               ;;
        esac
 }
 
index e21581d..0e8b4a4 100644 (file)
@@ -91,6 +91,7 @@ CONFIG_ATH79_MACH_MC_MAC1200R=y
 CONFIG_ATH79_MACH_MR12=y
 CONFIG_ATH79_MACH_MR16=y
 CONFIG_ATH79_MACH_MR1750=y
+CONFIG_ATH79_MACH_MR18=y
 CONFIG_ATH79_MACH_MR600=y
 CONFIG_ATH79_MACH_MR900=y
 CONFIG_ATH79_MACH_MYNET_N600=y
index 43ffa70..2b62d89 100644 (file)
@@ -853,6 +853,17 @@ config ATH79_MACH_MR16
        select ATH79_DEV_M25P80
        select ATH79_DEV_WMAC
 
+config ATH79_MACH_MR18
+       bool "Meraki MR18 board support"
+       select SOC_QCA955X
+       select ATH79_DEV_AP9X_PCI if PCI
+       select ATH79_DEV_ETH
+       select ATH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_NFC
+       select ATH79_DEV_WMAC
+       select LEDS_NU801
+
 config ATH79_MACH_MR600
        bool "OpenMesh MR600 board support"
        select SOC_AR934X
index b001876..f9c5b8f 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_ATH79_MACH_HORNET_UB)    += mach-hornet-ub.o
 obj-$(CONFIG_ATH79_MACH_MC_MAC1200R)     += mach-mc-mac1200r.o
 obj-$(CONFIG_ATH79_MACH_MR12)          += mach-mr12.o
 obj-$(CONFIG_ATH79_MACH_MR16)          += mach-mr16.o
+obj-$(CONFIG_ATH79_MACH_MR18)          += mach-mr18.o
 obj-$(CONFIG_ATH79_MACH_MR1750)                += mach-mr1750.o
 obj-$(CONFIG_ATH79_MACH_MR600)         += mach-mr600.o
 obj-$(CONFIG_ATH79_MACH_MR900)         += mach-mr900.o
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c
new file mode 100644 (file)
index 0000000..a24cb3f
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  Cisco Meraki MR18 board support
+ *
+ *  Copyright (C) 2015 Chris Blake <chrisrblake93@gmail.com>
+ *  Copyright (C) 2015 Christian Lamparter <chunkeey@googlemail.com>
+ *  Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ *
+ *  Based on Cisco Meraki GPL Release r23-20150601 MR18 Device Config
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/platform/ar934x_nfc.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/leds-nu801.h>
+#include <linux/pci.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MR18_GPIO_LED_POWER_WHITE    18
+#define MR18_GPIO_LED_POWER_ORANGE    21
+
+#define MR18_GPIO_BTN_RESET    17
+#define MR18_KEYS_POLL_INTERVAL    20  /* msecs */
+#define MR18_KEYS_DEBOUNCE_INTERVAL  (3 * MR18_KEYS_POLL_INTERVAL)
+
+#define MR18_WAN_PHYADDR    3
+
+/* used for eth calibration */
+#define MR18_OTP_BASE                  (AR71XX_APB_BASE + 0x130000)
+#define MR18_OTP_SIZE                  (0x2000) /* just a guess */
+#define MR18_OTP_MEM_0_REG             (0x0000)
+#define MR18_OTP_INTF2_REG             (0x1008)
+#define MR18_OTP_STATUS0_REG           (0x1018)
+#define MR18_OTP_STATUS0_EFUSE_VALID   BIT(2)
+
+#define MR18_OTP_STATUS1_REG           (0x101c)
+#define MR18_OTP_LDO_CTRL_REG          (0x1024)
+#define MR18_OTP_LDO_STATUS_REG                (0x102c)
+#define MR18_OTP_LDO_STATUS_POWER_ON   BIT(0)
+
+static struct gpio_led MR18_leds_gpio[] __initdata = {
+       {
+               .name = "mr18:white:power",
+               .gpio = MR18_GPIO_LED_POWER_WHITE,
+               .active_low  = 1,
+       }, {
+               .name = "mr18:orange:power",
+               .gpio = MR18_GPIO_LED_POWER_ORANGE,
+               .active_low  = 0,
+       },
+};
+
+static struct gpio_keys_button MR18_gpio_keys[] __initdata = {
+       {
+               .desc = "reset",
+               .type = EV_KEY,
+               .code = KEY_RESTART,
+               .debounce_interval = MR18_KEYS_DEBOUNCE_INTERVAL,
+               .gpio    = MR18_GPIO_BTN_RESET,
+               .active_low  = 1,
+       },
+};
+
+static struct led_nu801_template tricolor_led_template = {
+       .device_name = "mr18",
+       .name = "tricolor",
+       .num_leds = 1,
+       .cki = 11,
+       .sdi = 12,
+       .lei = -1,
+       .ndelay = 500,
+       .init_brightness = {
+               LED_OFF,
+               LED_OFF,
+               LED_OFF,
+       },
+       .default_trigger = "none",
+       .led_colors = { "red", "green", "blue" },
+};
+
+static struct led_nu801_platform_data tricolor_led_data = {
+       .num_controllers = 1,
+       .template = &tricolor_led_template,
+};
+
+static struct platform_device tricolor_leds = {
+       .name = "leds-nu801",
+       .id = -1,
+       .dev.platform_data = &tricolor_led_data,
+};
+
+static int mr18_extract_sgmii_res_cal(void)
+{
+       void __iomem *base;
+       unsigned int reversed_sgmii_value;
+
+       unsigned int otp_value, otp_per_val, rbias_per, read_data;
+       unsigned int rbias_pos_or_neg;
+       unsigned int sgmii_res_cal_value;
+       int res_cal_val;
+
+       base = ioremap_nocache(MR18_OTP_BASE, MR18_OTP_SIZE);
+       if (!base)
+               return -EIO;
+
+       __raw_writel(0x7d, base + MR18_OTP_INTF2_REG);
+       __raw_writel(0x00, base + MR18_OTP_LDO_CTRL_REG);
+
+       while (__raw_readl(base + MR18_OTP_LDO_STATUS_REG) &
+               MR18_OTP_LDO_STATUS_POWER_ON);
+
+       __raw_readl(base + MR18_OTP_MEM_0_REG + 4);
+
+       while (!(__raw_readl(base + MR18_OTP_STATUS0_REG) &
+               MR18_OTP_STATUS0_EFUSE_VALID));
+
+       read_data = __raw_readl(base + MR18_OTP_STATUS1_REG);
+
+       iounmap(base);
+
+       if (!(read_data & 0x1fff))
+               return -ENODEV;
+
+       if (read_data & 0x00001000)
+               otp_value = (read_data & 0xfc0) >> 6;
+       else
+               otp_value = read_data & 0x3f;
+
+       if (otp_value > 31) {
+               otp_per_val = 63 - otp_value;
+               rbias_pos_or_neg = 1;
+       } else {
+               otp_per_val = otp_value;
+               rbias_pos_or_neg = 0;
+       }
+
+       rbias_per = otp_per_val * 15;
+
+       if (rbias_pos_or_neg == 1)
+               res_cal_val = (rbias_per + 34) / 21;
+       else if (rbias_per > 34)
+               res_cal_val = -((rbias_per - 34) / 21);
+       else
+               res_cal_val = (34 - rbias_per) / 21;
+
+       sgmii_res_cal_value = (8 + res_cal_val) & 0xf;
+
+       reversed_sgmii_value  = (sgmii_res_cal_value & 8) >> 3;
+       reversed_sgmii_value |= (sgmii_res_cal_value & 4) >> 1;
+       reversed_sgmii_value |= (sgmii_res_cal_value & 2) << 1;
+       reversed_sgmii_value |= (sgmii_res_cal_value & 1) << 3;
+       printk(KERN_INFO "SGMII cal value = 0x%x\n", reversed_sgmii_value);
+       return reversed_sgmii_value;
+}
+
+#define QCA955X_PLL_ETH_SGMII_SERDES_REG               0x004c
+#define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT       BIT(2)
+#define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK                BIT(1)
+#define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL            BIT(0)
+
+#define QCA955X_GMAC_REG_SGMII_SERDES                  0x0018
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION           BIT(23)
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK      0xf
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT     23
+#define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS                BIT(15)
+
+static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value)
+{
+       void __iomem *ethbase, *pllbase;
+       u32 t;
+
+       ethbase = ioremap_nocache(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+       pllbase = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+       /* To Check the locking of the SGMII PLL */
+       t = __raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES);
+       t &= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK <<
+              QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT);
+       t |= (sgmii_value & QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK) <<
+            QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT;
+       __raw_writel(t, ethbase + QCA955X_GMAC_REG_SGMII_SERDES);
+
+       __raw_writel(QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT |
+                    QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK |
+                    QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL,
+                    pllbase + QCA955X_PLL_ETH_SGMII_SERDES_REG);
+
+       ath79_device_reset_clear(QCA955X_RESET_SGMII_ANALOG);
+       ath79_device_reset_clear(QCA955X_RESET_SGMII);
+
+       while (!(__raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES) &
+               QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS));
+
+       iounmap(ethbase);
+       iounmap(pllbase);
+}
+
+static struct ath9k_platform_data pci_main_wifi_data = {
+       .led_pin = -1,
+};
+static struct ath9k_platform_data pci_scan_wifi_data = {
+       .led_pin = -1,
+};
+
+static int mr18_dual_pci_plat_dev_init(struct pci_dev *dev)
+{
+       /* The PCIE devices are attached to different busses but they
+        * both share the same slot number. Checking the PCI_SLOT vals
+        * does not work.
+        */
+       switch (dev->bus->number) {
+       case 0:
+               dev->dev.platform_data = &pci_main_wifi_data;
+               break;
+       case 1:
+               dev->dev.platform_data = &pci_scan_wifi_data;
+               break;
+       }
+
+       return 0;
+}
+
+static void __init mr18_setup(void)
+{
+       int res;
+
+       /* NAND */
+       ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_SOFT_BCH);
+       ath79_register_nfc();
+
+       /* even though, the PHY is connected via RGMII,
+        * the SGMII/SERDES PLLs need to be calibrated and locked.
+        * Or else, the PHY won't be working for this platfrom.
+        *
+        * Figuring this out took such a long time, that we want to
+        * point this quirk out, before someone wants to remove it.
+        */
+       res = mr18_extract_sgmii_res_cal();
+       if (res >= 0) {
+               /* Setup SoC Eth Config */
+               ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN |
+                       (3 << QCA955X_ETH_CFG_RXD_DELAY_SHIFT) |
+                       (3 << QCA955X_ETH_CFG_RDV_DELAY_SHIFT));
+
+               /* MDIO Interface */
+               ath79_register_mdio(0, 0x0);
+
+               mr18_setup_qca955x_eth_serdes_cal(res);
+
+               /* GMAC0 is connected to an Atheros AR8035-A */
+               ath79_init_mac(ath79_eth0_data.mac_addr, NULL, 0);
+               ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+               ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+               ath79_eth0_data.phy_mask = BIT(MR18_WAN_PHYADDR);
+               ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+               ath79_eth0_pll_data.pll_100 = 0xa0000101;
+               ath79_eth0_pll_data.pll_10 = 0x80001313;
+               ath79_register_eth(0);
+       } else {
+               printk(KERN_ERR "failed to read EFUSE for ethernet cal\n");
+       }
+
+       /* LEDs and Buttons */
+       platform_device_register(&tricolor_leds);
+       ath79_register_leds_gpio(-1, ARRAY_SIZE(MR18_leds_gpio),
+                                MR18_leds_gpio);
+       ath79_register_gpio_keys_polled(-1, MR18_KEYS_POLL_INTERVAL,
+                                       ARRAY_SIZE(MR18_gpio_keys),
+                                       MR18_gpio_keys);
+
+       /* Clear RTC reset (Needed by SoC WiFi) */
+       ath79_device_reset_clear(QCA955X_RESET_RTC);
+
+       /* WiFi */
+       ath79_register_wmac_simple();
+
+       pci_main_wifi_data.eeprom_name = "pci_wmac0.eeprom";
+       pci_scan_wifi_data.eeprom_name = "pci_wmac1.eeprom";
+       ath79_pci_set_plat_dev_init(mr18_dual_pci_plat_dev_init);
+       ath79_register_pci();
+}
+MIPS_MACHINE(ATH79_MACH_MR18, "MR18", "Meraki MR18", mr18_setup);
index 550d927..2ea772d 100644 (file)
@@ -87,6 +87,7 @@ enum ath79_mach_type {
        ATH79_MACH_HORNET_UB,           /* ALFA Networks Hornet-UB */
        ATH79_MACH_MR12,                /* Cisco Meraki MR12 */
        ATH79_MACH_MR16,                /* Cisco Meraki MR16 */
+       ATH79_MACH_MR18,                /* Cisco Meraki MR18 */
        ATH79_MACH_MR1750,              /* OpenMesh MR1750 */
        ATH79_MACH_MR600V2,             /* OpenMesh MR600v2 */
        ATH79_MACH_MR600,               /* OpenMesh MR600 */
index 78be345..e197ed3 100644 (file)
@@ -1986,6 +1986,14 @@ Image/Build/CyberTANLZMA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
 Image/Build/CyberTANLZMA=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
 
 
+define Build/MerakiNAND
+       -$(STAGING_DIR_HOST)/bin/mkmerakifw \
+               -B $(BOARDNAME) -s \
+               -i $@ \
+               -o $@.new
+       @mv $@.new $@
+endef
+
 Image/Build/Netgear/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
 
 define Image/Build/Netgear/buildkernel
@@ -2426,6 +2434,19 @@ $(eval $(call MultiProfile,Madwifi,EAP7660D WP543))
 endif # ifeq ($(SUBTARGET),generic)
 
 ifeq ($(SUBTARGET),nand)
+
+define Device/mr18
+  BOARDNAME = MR18
+  BLOCKSIZE := 64k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = ar934x-nfc:512k(nandloader)ro,8M(kernel),8M(recovery),113664k(ubi),128k@130944k(odm-caldata)ro
+  IMAGES := sysupgrade.tar
+  KERNEL := kernel-bin | patch-cmdline | MerakiNAND
+  KERNEL_INITRAMFS := kernel-bin | patch-cmdline | MerakiNAND
+  IMAGE/sysupgrade.tar := sysupgrade-nand
+endef
+TARGET_DEVICES += mr18
+
 $(eval $(call SingleProfile,NetgearNAND,64k,WNDR3700V4,wndr3700v4,WNDR3700_V4,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR3700v4,"",-H 29763948+128+128,wndr4300))
 $(eval $(call SingleProfile,NetgearNAND,64k,WNDR4300V1,wndr4300,WNDR4300,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR4300,"",-H 29763948+0+128+128+2x2+3x3,wndr4300))
 $(eval $(call SingleProfile,NetgearNAND,64k,R6100,r6100,R6100,ttyS0,115200,$$(r6100_mtdlayout),0x36303030,R6100,"",-H 29764434+0+128+128+2x2+2x2,wndr4300))
index 50b6dbe..05f52af 100644 (file)
@@ -91,6 +91,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_AR934X=y
 CONFIG_MTD_NAND_AR934X_HW_ECC=y
 CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_ECC_BCH=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_SM_COMMON is not set
 # CONFIG_MTD_SPLIT_SEAMA_FW is not set
diff --git a/target/linux/ar71xx/nand/profiles/meraki.mk b/target/linux/ar71xx/nand/profiles/meraki.mk
new file mode 100644 (file)
index 0000000..2c848c9
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2014-2015 Chris Blake (chrisrblake93@gmail.com)
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/MR18
+       NAME:=Meraki MR18
+       PACKAGES:=kmod-spi-gpio kmod-ath9k
+endef
+
+define Profile/MR18/description
+       Package set optimized for the Cisco Meraki MR18 Access Point.
+endef
+
+$(eval $(call Profile,MR18))