This patch adds platform machine support for the D-Link DIR-632-A1.
Currently eth1 is not supported as the ag71xx driver does not work with the
AR7242 at least for all the configurations I have tested for this board.

With this patch and the preceding patches, the DIR-632-A1 is fully usable for
all use cases that do not require a separate WAN port.  Tested succesfully:
LEDs, 2x switches, wireless, eth0, USB2.


Signed-off-by: Andrew McDonnell <b...@andrewmcdonnell.net>
---
 .../ar71xx/files/arch/mips/ath79/mach-dir-632-a1.c |  391 ++++++++++++++++++++
 1 files changed, 391 insertions(+), 0 deletions(-)

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-632-a1.c
b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-632-a1.c
new file mode 100644
index 0000000..8744abf
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-632-a1.c
@@ -0,0 +1,391 @@
+/*
+ *  D-Link DIR-632 rev. A1 board support
+ *
+ *  Copyright (C) 2013 Andrew McDonnell <b...@andrewmcdonnell.net>
+ *  Copyright (C) 2010-2012 Gabor Juhos <juh...@openwrt.org>
+ *
+ *  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/device.h>
+#include <linux/platform_device.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/ar8216_platform.h>
+#include "common.h"
+#include "dev-common.h"
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-ap9x-pci.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+/* Set the following to zero to have a look at actual RAM when trying to find
MAC addresses, etc. */
+#define DEBUG_CHECK_MEMORY_CONTENTS 1
+
+  /* Various in-memory items of interest:
+   *
+   * Memory     Flash     Description
+   * 1f040000   040000    u-boot environment variables
+   * 1ffb0004   7b0004    ASCII MAC address matching the case sticker.
+   *                      I suspect this is 'fixed' when you first execute
+   *                      setenv mac= in u-boot (which I inadvertently did)
+   *                      (mtd "MAC" partition)
+   * 1ffe0000   7e0000    NVRAM  (area prefix: "HSLF")
+   *                      (partway through factory mtd "LP" partition)
+   * 1fff0000   7f0000    Hardware MAC address for eth0, according to source
+   *                      code of DD-WRT and zRouter, except this MAC address
+   *                      is _different_ to the stickered MAC address.
+   *                      (mtd "ART" partition)
+   * 1fff0006   7f0006    Hardware MAC address for eth1, according to source
+   *                      code of DD-WRT and zRouter, except this MAC address
+   *                      is set to ff:ff:ff:ff:ff:ff in my router.
+   * 1ff10000   7f1000    PCI EEPROM - "calibration data"
+   * 1ff1010c   7f110c    PCI EEPROM - WLAN mac address reported in DD-WRT
+   *                      In my board this is set to 00:00:22:22:22:22
+   *                      Which happens to be the same as the NVRAM value
+   *                      ath_hwaddr
+   */
+
+/* Network architecture:
+ *
+ * eth0 --> 8309 switch - LAN
+ * eth1 --> S26 switch - WAN
+ * wlan0 --> PCI ath9k driver
+ */
+
+#define ADDR_UBOOT   0x1f040000
+#define ADDR_AMAC    0x1ffb0000
+#define ADDR_NVRAM   0x1ffe0000
+#define ADDR_HMAC    0x1fff0000
+#define ADDR_PCIBASE 0x1fff0000
+#define ADDR_EEPROM  0x1fff1000
+
+#define EEPROM_WLAN_MAC_OFFSET 0x10c
+
+#define NVRAM_SIZE 0x10000
+
+#define DIR632_MAC0_OFFSET     0
+#define DIR632_MAC1_OFFSET     6
+
+#define DIR632_AMAC_OFFSET     4
+
+/*
+
+ Known LED and GPIO Definitions, derived from
+
+ 
http://zrouter.org/projects/zrouter/repository/entry/boards/D-Link/DIR-632/GPIO
+
http://zrouter.org/projects/zrouter/repository/entry/boards/D-Link/DIR-632/board.hints
+
+ and from practical experimentation using the DD-WRT generic_leds and testing
+
+GPIO LED
+ 0     LED     WPS (blue)
+ 1     LED     STATUS (bicolour: orange)
+ 6     LED     STATUS (bicolour: green)
+ 7     LED     WAN (bicolour: orange)
+ 8     BUTTON Reset
+ 9     UART
+ 10    UART
+ 11    LED     USB (green)
+ 12 BUTTON WPS
+ 13 Test point TP3
+ 14 Test point TP4
+ 15 Test point TP5
+ 17    LED     WAN (bicolour: green)
+
+Additionally, the ATH9k has GPIO, specified for the LED in platform data
+
+ 0  LED, WLAN (green)
+
+*/
+
+#define DIR_632_A1_GPIO_LED_WPS                        0
+#define DIR_632_A1_GPIO_LED_POWER_AMBER                1
+#define DIR_632_A1_GPIO_LED_POWER_GREEN                6
+#define DIR_632_A1_GPIO_LED_WAN_AMBER          7
+#define DIR_632_A1_GPIO_LED_USB                11
+#define DIR_632_A1_GPIO_LED_WAN_GREEN          17
+
+#define DIR_632_A1_WLAN_GPIO_LED                       0
+
+#define DIR_632_A1_GPIO_BTN_RESET              8
+#define DIR_632_A1_GPIO_BTN_WPS                        12
+
+#define DIR_632_A1_KEYS_POLL_INTERVAL          20      /* msecs */
+#define DIR_632_A1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_632_A1_KEYS_POLL_INTERVAL)
+
+static struct gpio_led dir_632_a1_leds_gpio[] __initdata = {
+       {
+               .name           = "d-link:blue:wps",
+               .gpio           = DIR_632_A1_GPIO_LED_WPS,
+               .active_low     = 1,
+       }, {
+               .name           = "d-link:amber:power",
+               .gpio           = DIR_632_A1_GPIO_LED_POWER_AMBER,
+    .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+       }, {
+               .name           = "d-link:green:power",
+               .gpio           = DIR_632_A1_GPIO_LED_POWER_GREEN,
+       }, {
+               .name           = "d-link:amber:wan",
+               .gpio           = DIR_632_A1_GPIO_LED_WAN_AMBER,
+       }, {
+               .name           = "d-link:green:wan",
+               .gpio           = DIR_632_A1_GPIO_LED_WAN_GREEN,
+               .active_low     = 1,
+       }, {
+               .name           = "d-link:green:usb",
+               .gpio           = DIR_632_A1_GPIO_LED_USB,
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_button dir_632_a1_gpio_keys[] __initdata = {
+       {
+               .desc           = "reset", // tested OK, using  cat 
/sys/kernel/debug/gpio/
+               .type           = EV_KEY,
+               .code           = KEY_RESTART,
+               .debounce_interval = DIR_632_A1_KEYS_DEBOUNCE_INTERVAL,
+               .gpio           = DIR_632_A1_GPIO_BTN_RESET,  /* Note, zrouter 
flags is 0x4a1, if
this doesnt work ... */
+               .active_low     = 1,
+       }, {
+               .desc           = "wps",  // tested OK, using  cat 
/sys/kernel/debug/gpio/
+               .type           = EV_KEY,
+               .code           = KEY_WPS_BUTTON,
+               .debounce_interval = DIR_632_A1_KEYS_DEBOUNCE_INTERVAL,
+               .gpio           = DIR_632_A1_GPIO_BTN_WPS,    /* Note, zrouter 
flags is 0x4a1, if
this doesnt work ... */
+               .active_low     = 1,
+       }
+};
+
+/* At 0x1000 in the upper 64K of memory of my DIR632 is PCI EEPROM information.
+ * However DD-WRT does a scan at the start of each 0x1000 of the entire 64k,
+ * so we do just in case. */
+static void *dir_632_a1_get_eeprom_caldata(int slot)
+{
+  u8 *base;
+  for (base=(u8 *)KSEG1ADDR(0x1f000000);base<(u8
*)KSEG1ADDR(0x1ffff000);base+=0x1000) {
+    u32 *cal = (u32 *)base;
+    if (*cal==0xa55a0000 || *cal==0x5aa50000) {
+      /* protection bit is always zero on inflash devices, so we can use for
match it */
+      if (slot) {
+        base+=0x4000;
+      }
+      pr_info("dir632: found PCI EEPROM for slot %d at %p\n",slot,base);
+      return base;
+    }
+  }
+  return NULL;
+}
+
+static int is_mac_all_ones(u8* mac) {
+  return !memcmp(mac,"\xff\xff\xff\xff\xff\xff",6);
+}
+
+static int is_mac_all_zeros(u8* mac) {
+  return !memcmp(mac,"\x0\x0\x0\x0\x0\x0",6);
+}
+
+static int is_mac_ok(u8* mac) {
+  return !is_mac_all_zeros(mac) && !is_mac_all_ones(mac) &&
memcmp(mac,"\x08\x0\x0\x0\x0\x0",6);
+}
+
+static struct flash_platform_data dir_632_a1_flash = {
+  .type           = "mx25l6405d",
+};
+
+/*
+ * Platform initialisation for the DIR-632-A1 mainboard.
+ *
+ * Here we set platform-specific data for each device that may be loaded later.
+ *
+ * This router has:
+ * (a) AG7240 ethernet
+ *     eth0: connected to RTL8309G, physically to 8-port switch
+ *     eth1: connected vi internal S26 switch to WAN port
+ * (b) mdio port - bus used to control the switches (I think)
+ * (c) ath9k wireless - on PCI bus
+ * (d) USB2
+ * (e) serial port
+ * (f) GPIO - buttons - WPS button and Reset button, of course with OpenWRT
+ *            you can change these to whatever you want
+ * (g) GPIO - leds - 8 switch LEDS controlled by ag7240 driver
+ *                 - power/status - can be green or orange in factory firmware
+ *                 - WAN - can be green or orange in factory firmware
+ *                 - WLAN - green - controlled by ath9k driver
+ *                 - WPS - blue
+ *                 - USB - green
+ * (h) Watchdog timer
+ * The board also has two extra placeholders for other LEDS so it hopefully
+ * will be possible to buzz these out and use them as spare GPIO in the future
+ * (i) Flash - SPI controlled flash, 8MB
+ *
+ * MAC addresses:
+ *
+ * The factory firmware reads an ASCII MAC address from the MAC partition
+ * and seems to assign it to all ports.  Note that DD-WRT reads the wireless 
MAC
+ * 00:00:22:22:22:22 from the ART partition in the Atheros PCI 'eeprom' data
+ * (see http://wiki.openwrt.org/doc/howto/restore_art_partition )
+ * so it appears that D-link just ignore this and replace it with the stickered
+ * MAC as well.
+ *
+ * However a _different_ MAC is binary encoded in the start of the ART 
partition
+ * and this us assigned to eth0 and eth1 by uboot!
+ *
+ * So I am not really sure what the correct algorithm is for selecting all 
this!
+ *
+ * Looking at other similar boards, whoever ported them to OpenWRT chose to
+ * do different things...
+ */
+static void __init dir_632_a1_setup(void)
+{
+
+  const char *nvram = (char *)KSEG1ADDR(ADDR_NVRAM);
+       u8 *ee = (u8 *)KSEG1ADDR(ADDR_PCIBASE);   /* PCI Cal data - will be set 
by
getCalData() */
+  u8 mac_buffer[6];
+       u8 *wmac = NULL; /* This may end up with a MAC address to pass through 
to
ath9k for it to use instead of PCI calibration data */
+  u8 *art = (u8 *)KSEG1ADDR(ADDR_HMAC);      /* Early-hardware MAC addresses */
+
+#if DEBUG_CHECK_MEMORY_CONTENTS
+  print_hex_dump(KERN_DEBUG, "uboot args: ", DUMP_PREFIX_ADDRESS, 16, 1,
(u8*)KSEG1ADDR(ADDR_UBOOT), 64, true);
+  print_hex_dump(KERN_DEBUG, "nvram:      ", DUMP_PREFIX_ADDRESS, 16, 1,
(u8*)KSEG1ADDR(ADDR_NVRAM), 64, true);
+  print_hex_dump(KERN_DEBUG, "art:        ", DUMP_PREFIX_ADDRESS, 16, 1,
(u8*)KSEG1ADDR(ADDR_HMAC), 64, true);
+  print_hex_dump(KERN_DEBUG, "pci eeprom: ", DUMP_PREFIX_ADDRESS, 16, 1,
(u8*)KSEG1ADDR(ADDR_EEPROM), 64, true);
+  print_hex_dump(KERN_DEBUG, "boxmac    : ", DUMP_PREFIX_ADDRESS, 16, 1,
(u8*)KSEG1ADDR(ADDR_AMAC), 64, true);
+#endif
+
+  /* Depending on the factory firmware prior usage, there may be a MAC
address for the WLAN */
+  if (ath79_nvram_parse_mac_addr(nvram, NVRAM_SIZE,"ath0_hwaddr=",
mac_buffer) == 0) {
+    wmac = mac_buffer;
+    pr_debug("dir_632_a1_setup(): NVRAM ath0_hwaddr=%pM", wmac);
+  }
+
+  if (mac_pton( (char*) ((u8*)KSEG1ADDR(ADDR_AMAC)+DIR632_AMAC_OFFSET),
mac_buffer)) {
+    if (!(is_mac_all_ones(mac_buffer) || is_mac_all_zeros(mac_buffer))) {
+      // use this instead for WLAN and for Eth? what is the desired behaviour?
+      // for now apply to WLAN
+      wmac = mac_buffer;
+      pr_debug("dir_632_a1_setup(): ASCII (uboot-set) mac=%pM", wmac);
+    }
+  }
+
+       ath79_init_mac(ath79_eth0_data.mac_addr, art + DIR632_MAC0_OFFSET, 0);
+  pr_info("DIR-632-A1 using eth0 mac=%pM\n", ath79_eth0_data.mac_addr);
+
+       ath79_register_mdio(0, 0);
+       ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+  /* For the moment, eth1 has been left out, because the driver doesnt work
on this router. */
+
+  ath79_eth0_data.reset_bit = AR71XX_RESET_GE0_MAC;
+  ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII; /* The dir632 is
limited to 100Mb */
+       ath79_eth0_data.speed = SPEED_100;
+       ath79_eth0_data.duplex = DUPLEX_FULL;
+  /* PHY mask is a bitshifted E 0..31 corresponding to the PHY E 0..31
+   * which connects the switch to the ethernet device via the specified mdio
port.
+   */
+  ath79_eth0_data.phy_mask = BIT(8);
+  ath79_eth0_data.tx_ring_size = 80; /* Tweak the ring sizes to match DD-WRT */
+  ath79_eth0_data.rx_ring_size = 252;
+  ath79_register_eth(0);
+
+  /* The flash is a mx25l6405d 8-pin SPI flash */
+  ath79_register_m25p80(&dir_632_a1_flash);
+
+  /*
+   * Further GPIO information.
+   *
+   * Some GPIO can be repurposed / enabled / disabled
+   *
+   * AR7240_GPIO_FUNCTION_UART_EN
+   *            --> enable a Uart on 9,10 (set 9 as RxIn and 10 as TxOut)
+   *
+   * AR7240_GPIO_FUNCTION_SPI_CS_0_EN|AR7240_GPIO_FUNCTION_SPI_CS_1_EN
+   *            --> enable SPI CS0/CS1 on GPIO0/1 - but we have tested LEDs /
buttons
+   *                so this is not in use; we can also assume this has already
+   *                been disabled as a function by default by now...
+   * AR71XX_GPIO_FUNC_STEREO_EN
+   *            --> enable sound on 6,7,8,11 - but we have tested LEDs / 
buttons
+   *                so this is not in use; we can also assume this has already
+   *                been disabled as a function by default by now...
+   *
+   * D-link refers to reset on GPIO12 as 'jumpstart'
+   * D-link _also_ refers to AR7240_GPIO_RESET on GPIO21 in its WDT
implementatoin
+   * it looks like if a FACTORY_RESET ioctl is called then if this line is
+   * asserted in a 4second time window then a factory reset is also done...
+   * not sure how this interacts with 'JUMPSTART' (reset) because I cant find
+   * a second factory reset button pin on the board...
+   * Does this mean is that there are actually >= 22 GPIO (not 20)
+   * for AR7242 ...?
+   *
+   * I buzzed out the following as well:
+   *
+   *  TP3 --> connected to GPIO15
+   *
+   * At boot: GPIO_2=1 (stuck), GPIO_10=1 (stuck)
+   *
+   * OpenWRT sets AR724X_GPIO_FUNC_UART_EN in dev_common
+   */
+
+       ath79_gpio_function_enable(AR724X_GPIO_FUNC_JTAG_DISABLE); // Make LEDs 
on
GPIO6/7 work
+
+       ath79_gpio_function_disable(
+            AR71XX_GPIO_FUNC_STEREO_EN |
+            AR724X_GPIO_FUNCTION_CLK_OBS6_ENABLE | // disabled in D-link GPL
sources
+            AR724X_GPIO_FUNC_UART_RTS_CTS_EN |     // disabled in D-link GPL
sources
+            AR724X_GPIO_FUNCTION_PCIEPHY_TST_EN |  // disabled in D-link GPL
sources
+            AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+                                   AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+                                   AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+                                   AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+                                   AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+       ath79_register_leds_gpio(-1, ARRAY_SIZE(dir_632_a1_leds_gpio),
+                                dir_632_a1_leds_gpio);
+
+       ath79_register_gpio_keys_polled(-1, DIR_632_A1_KEYS_POLL_INTERVAL,
+                                       ARRAY_SIZE(dir_632_a1_gpio_keys),
+                                       dir_632_a1_gpio_keys);
+
+  /* We have usb2 */
+  ath79_register_usb();
+
+  /* Pass on data for the WLAN PCI device: */
+       ee = dir_632_a1_get_eeprom_caldata(0);
+       if (ee && !wmac) {
+    /* If no value in NVRAM for wireless, check if there is a valid MAC address
+     * in the PCI EEPROM. If so, and it is valid we do nothing.
+     * If not valid, then look in the ART instead for an address to pass
along. */
+    if (!is_mac_ok(ee+EEPROM_WLAN_MAC_OFFSET)) {
+               pr_warn("Found empty wireless MAC address in calibration 
dataset, leave
the responsibility to the driver to use the correct one.\n");
+               wmac = ee - 0x1000;  /* This implies the possibility in this 
architecture
that there could be a second PCI slot and the MAC is 0x1000 below it... */
+         }
+    /* Check the value in the ART is valid before allowing it to be used. For
some reason we don't check 08:00:00:00:00:00 */
+    if (wmac && (is_mac_all_ones(wmac) || is_mac_all_zeros(wmac))) {
+      pr_warn("Found empty wireless MAC address in ART, leave the
responsibility to the driver to use the correct one\n");
+               wmac = NULL;
+         }     
+       }
+  if (wmac) {
+    pr_info("DIR-632-A1 user set wmac=%pM\n", wmac);
+  }
+
+  /* inform the ath9k which of its GPIO the WLAN LED is on */
+  ap9x_pci_setup_wmac_led_pin(0, DIR_632_A1_WLAN_GPIO_LED);
+
+  /* inform the ath9k what wmac to use and where to find its radio cal data */
+  /* also initialises PCI bus */
+       ap91_pci_init(ee, wmac);
+
+  /* uart, gpio base and wdt are init from ath79/setup.c */
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_632_A1, "DIR-632-A1", "D-Link DIR-632 rev. A1",
+            dir_632_a1_setup);
+
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to