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