aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/bcm47xx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/bcm47xx')
-rw-r--r--arch/mips/bcm47xx/Kconfig11
-rw-r--r--arch/mips/bcm47xx/Makefile4
-rw-r--r--arch/mips/bcm47xx/bcm47xx_private.h15
-rw-r--r--arch/mips/bcm47xx/board.c335
-rw-r--r--arch/mips/bcm47xx/buttons.c562
-rw-r--r--arch/mips/bcm47xx/gpio.c102
-rw-r--r--arch/mips/bcm47xx/irq.c25
-rw-r--r--arch/mips/bcm47xx/leds.c591
-rw-r--r--arch/mips/bcm47xx/nvram.c187
-rw-r--r--arch/mips/bcm47xx/prom.c141
-rw-r--r--arch/mips/bcm47xx/serial.c8
-rw-r--r--arch/mips/bcm47xx/setup.c264
-rw-r--r--arch/mips/bcm47xx/sprom.c755
-rw-r--r--arch/mips/bcm47xx/time.c23
-rw-r--r--arch/mips/bcm47xx/wgt634u.c170
-rw-r--r--arch/mips/bcm47xx/workarounds.c31
16 files changed, 2634 insertions, 590 deletions
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 6210b8d8410..09cb6f7aa3d 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -2,13 +2,17 @@ if BCM47XX
config BCM47XX_SSB
bool "SSB Support for Broadcom BCM47XX"
- select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_BMIPS32_3300
select SSB
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
select SSB_EMBEDDED
select SSB_B43_PCI_BRIDGE if PCI
+ select SSB_DRIVER_PCICORE if PCI
select SSB_PCICORE_HOSTMODE if PCI
+ select SSB_DRIVER_GPIO
+ select GPIOLIB
+ select LEDS_GPIO_REGISTER
default y
help
Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
@@ -18,10 +22,15 @@ config BCM47XX_SSB
config BCM47XX_BCMA
bool "BCMA Support for Broadcom BCM47XX"
select SYS_HAS_CPU_MIPS32_R2
+ select CPU_MIPSR2_IRQ_VI
select BCMA
select BCMA_HOST_SOC
select BCMA_DRIVER_MIPS
+ select BCMA_HOST_PCI if PCI
select BCMA_DRIVER_PCI_HOSTMODE if PCI
+ select BCMA_DRIVER_GPIO
+ select GPIOLIB
+ select LEDS_GPIO_REGISTER
default y
help
Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 4add17349ff..d58c51b5e50 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,5 +3,5 @@
# under Linux.
#
-obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
-obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
+obj-y += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
+obj-y += board.o buttons.o leds.o workarounds.o
diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h
new file mode 100644
index 00000000000..0194c3b9a72
--- /dev/null
+++ b/arch/mips/bcm47xx/bcm47xx_private.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_BCM47XX_PRIVATE_H_
+#define LINUX_BCM47XX_PRIVATE_H_
+
+#include <linux/kernel.h>
+
+/* buttons.c */
+int __init bcm47xx_buttons_register(void);
+
+/* leds.c */
+void __init bcm47xx_leds_register(void);
+
+/* workarounds.c */
+void __init bcm47xx_workarounds(void);
+
+#endif
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
new file mode 100644
index 00000000000..44ab1be68c3
--- /dev/null
+++ b/arch/mips/bcm47xx/board.c
@@ -0,0 +1,335 @@
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx_nvram.h>
+
+struct bcm47xx_board_type {
+ const enum bcm47xx_board board;
+ const char *name;
+};
+
+struct bcm47xx_board_type_list1 {
+ struct bcm47xx_board_type board;
+ const char *value1;
+};
+
+struct bcm47xx_board_type_list2 {
+ struct bcm47xx_board_type board;
+ const char *value1;
+ const char *value2;
+};
+
+struct bcm47xx_board_type_list3 {
+ struct bcm47xx_board_type board;
+ const char *value1;
+ const char *value2;
+ const char *value3;
+};
+
+struct bcm47xx_board_store {
+ enum bcm47xx_board board;
+ char name[BCM47XX_BOARD_MAX_NAME];
+};
+
+/* model_name */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_model_name[] __initconst = {
+ {{BCM47XX_BOARD_DLINK_DIR130, "D-Link DIR-130"}, "DIR-130"},
+ {{BCM47XX_BOARD_DLINK_DIR330, "D-Link DIR-330"}, "DIR-330"},
+ { {0}, NULL},
+};
+
+/* model_no */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_model_no[] __initconst = {
+ {{BCM47XX_BOARD_ASUS_WL700GE, "Asus WL700"}, "WL700"},
+ { {0}, NULL},
+};
+
+/* machine_name */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_machine_name[] __initconst = {
+ {{BCM47XX_BOARD_LINKSYS_WRTSL54GS, "Linksys WRTSL54GS"}, "WRTSL54GS"},
+ { {0}, NULL},
+};
+
+/* hardware_version */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initconst = {
+ {{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RTN10U"},
+ {{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"},
+ {{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RTN12B1"},
+ {{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RTN12C1"},
+ {{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RTN12D1"},
+ {{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RTN12HP"},
+ {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16-"},
+ {{BCM47XX_BOARD_ASUS_WL320GE, "Asus WL320GE"}, "WL320G-"},
+ {{BCM47XX_BOARD_ASUS_WL330GE, "Asus WL330GE"}, "WL330GE-"},
+ {{BCM47XX_BOARD_ASUS_WL500GD, "Asus WL500GD"}, "WL500gd-"},
+ {{BCM47XX_BOARD_ASUS_WL500GPV1, "Asus WL500GP V1"}, "WL500gp-"},
+ {{BCM47XX_BOARD_ASUS_WL500GPV2, "Asus WL500GP V2"}, "WL500GPV2-"},
+ {{BCM47XX_BOARD_ASUS_WL500W, "Asus WL500W"}, "WL500gW-"},
+ {{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"},
+ {{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"},
+ {{BCM47XX_BOARD_BELKIN_F7D3301, "Belkin F7D3301"}, "F7D3301"},
+ {{BCM47XX_BOARD_BELKIN_F7D3302, "Belkin F7D3302"}, "F7D3302"},
+ {{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"},
+ {{BCM47XX_BOARD_BELKIN_F7D4302, "Belkin F7D4302"}, "F7D4302"},
+ {{BCM47XX_BOARD_BELKIN_F7D4401, "Belkin F7D4401"}, "F7D4401"},
+ { {0}, NULL},
+};
+
+/* productid */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_productid[] __initconst = {
+ {{BCM47XX_BOARD_ASUS_RTAC66U, "Asus RT-AC66U"}, "RT-AC66U"},
+ {{BCM47XX_BOARD_ASUS_RTN10, "Asus RT-N10"}, "RT-N10"},
+ {{BCM47XX_BOARD_ASUS_RTN10D, "Asus RT-N10D"}, "RT-N10D"},
+ {{BCM47XX_BOARD_ASUS_RTN15U, "Asus RT-N15U"}, "RT-N15U"},
+ {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16"},
+ {{BCM47XX_BOARD_ASUS_RTN53, "Asus RT-N53"}, "RT-N53"},
+ {{BCM47XX_BOARD_ASUS_RTN66U, "Asus RT-N66U"}, "RT-N66U"},
+ {{BCM47XX_BOARD_ASUS_WL300G, "Asus WL300G"}, "WL300g"},
+ {{BCM47XX_BOARD_ASUS_WLHDD, "Asus WLHDD"}, "WLHDD"},
+ { {0}, NULL},
+};
+
+/* ModelId */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_ModelId[] __initconst = {
+ {{BCM47XX_BOARD_DELL_TM2300, "Dell WX-5565"}, "WX-5565"},
+ {{BCM47XX_BOARD_MOTOROLA_WE800G, "Motorola WE800G"}, "WE800G"},
+ {{BCM47XX_BOARD_MOTOROLA_WR850GP, "Motorola WR850GP"}, "WR850GP"},
+ {{BCM47XX_BOARD_MOTOROLA_WR850GV2V3, "Motorola WR850G"}, "WR850G"},
+ { {0}, NULL},
+};
+
+/* melco_id or buf1falo_id */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_melco_id[] __initconst = {
+ {{BCM47XX_BOARD_BUFFALO_WBR2_G54, "Buffalo WBR2-G54"}, "29bb0332"},
+ {{BCM47XX_BOARD_BUFFALO_WHR2_A54G54, "Buffalo WHR2-A54G54"}, "290441dd"},
+ {{BCM47XX_BOARD_BUFFALO_WHR_G125, "Buffalo WHR-G125"}, "32093"},
+ {{BCM47XX_BOARD_BUFFALO_WHR_G54S, "Buffalo WHR-G54S"}, "30182"},
+ {{BCM47XX_BOARD_BUFFALO_WHR_HP_G54, "Buffalo WHR-HP-G54"}, "30189"},
+ {{BCM47XX_BOARD_BUFFALO_WLA2_G54L, "Buffalo WLA2-G54L"}, "29129"},
+ {{BCM47XX_BOARD_BUFFALO_WZR_G300N, "Buffalo WZR-G300N"}, "31120"},
+ {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54, "Buffalo WZR-RS-G54"}, "30083"},
+ {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP, "Buffalo WZR-RS-G54HP"}, "30103"},
+ { {0}, NULL},
+};
+
+/* boot_hw_model, boot_hw_ver */
+static const
+struct bcm47xx_board_type_list2 bcm47xx_board_list_boot_hw[] __initconst = {
+ /* like WRT160N v3.0 */
+ {{BCM47XX_BOARD_CISCO_M10V1, "Cisco M10"}, "M10", "1.0"},
+ /* like WRT310N v2.0 */
+ {{BCM47XX_BOARD_CISCO_M20V1, "Cisco M20"}, "M20", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_E900V1, "Linksys E900 V1"}, "E900", "1.0"},
+ /* like WRT160N v3.0 */
+ {{BCM47XX_BOARD_LINKSYS_E1000V1, "Linksys E1000 V1"}, "E100", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_E1000V2, "Linksys E1000 V2"}, "E1000", "2.0"},
+ {{BCM47XX_BOARD_LINKSYS_E1000V21, "Linksys E1000 V2.1"}, "E1000", "2.1"},
+ {{BCM47XX_BOARD_LINKSYS_E1200V2, "Linksys E1200 V2"}, "E1200", "2.0"},
+ {{BCM47XX_BOARD_LINKSYS_E2000V1, "Linksys E2000 V1"}, "Linksys E2000", "1.0"},
+ /* like WRT610N v2.0 */
+ {{BCM47XX_BOARD_LINKSYS_E3000V1, "Linksys E3000 V1"}, "E300", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_E3200V1, "Linksys E3200 V1"}, "E3200", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_E4200V1, "Linksys E4200 V1"}, "E4200", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT150NV11, "Linksys WRT150N V1.1"}, "WRT150N", "1.1"},
+ {{BCM47XX_BOARD_LINKSYS_WRT150NV1, "Linksys WRT150N V1"}, "WRT150N", "1"},
+ {{BCM47XX_BOARD_LINKSYS_WRT160NV1, "Linksys WRT160N V1"}, "WRT160N", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT160NV3, "Linksys WRT160N V3"}, "WRT160N", "3.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT300NV11, "Linksys WRT300N V1.1"}, "WRT300N", "1.1"},
+ {{BCM47XX_BOARD_LINKSYS_WRT310NV1, "Linksys WRT310N V1"}, "WRT310N", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT310NV2, "Linksys WRT310N V2"}, "WRT310N", "2.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G3GV2, "Linksys WRT54G3GV2-VF"}, "WRT54G3GV2-VF", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT610NV1, "Linksys WRT610N V1"}, "WRT610N", "1.0"},
+ {{BCM47XX_BOARD_LINKSYS_WRT610NV2, "Linksys WRT610N V2"}, "WRT610N", "2.0"},
+ { {0}, NULL},
+};
+
+/* board_id */
+static const
+struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = {
+ {{BCM47XX_BOARD_NETGEAR_WGR614V8, "Netgear WGR614 V8"}, "U12H072T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WGR614V9, "Netgear WGR614 V9"}, "U12H094T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR3300, "Netgear WNDR3300"}, "U12H093T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR3400V1, "Netgear WNDR3400 V1"}, "U12H155T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR3400V2, "Netgear WNDR3400 V2"}, "U12H187T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR3400VCNA, "Netgear WNDR3400 Vcna"}, "U12H155T01_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR3700V3, "Netgear WNDR3700 V3"}, "U12H194T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR4000, "Netgear WNDR4000"}, "U12H181T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR4500V1, "Netgear WNDR4500 V1"}, "U12H189T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNDR4500V2, "Netgear WNDR4500 V2"}, "U12H224T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR2000, "Netgear WNR2000"}, "U12H114T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "U12H136T99_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR3500U, "Netgear WNR3500U"}, "U12H136T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR3500V2, "Netgear WNR3500 V2"}, "U12H127T00_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR3500V2VC, "Netgear WNR3500 V2vc"}, "U12H127T70_NETGEAR"},
+ {{BCM47XX_BOARD_NETGEAR_WNR834BV2, "Netgear WNR834B V2"}, "U12H081T00_NETGEAR"},
+ { {0}, NULL},
+};
+
+/* boardtype, boardnum, boardrev */
+static const
+struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = {
+ {{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"},
+ {{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"},
+ {{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"},
+ {{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0101", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0467", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0708", "42", "0x10"},
+ { {0}, NULL},
+};
+
+/* boardtype, boardrev */
+static const
+struct bcm47xx_board_type_list2 bcm47xx_board_list_board_type_rev[] __initconst = {
+ {{BCM47XX_BOARD_SIEMENS_SE505V2, "Siemens SE505 V2"}, "0x0101", "0x10"},
+ { {0}, NULL},
+};
+
+static const
+struct bcm47xx_board_type bcm47xx_board_unknown[] __initconst = {
+ {BCM47XX_BOARD_UNKNOWN, "Unknown Board"},
+};
+
+static struct bcm47xx_board_store bcm47xx_board = {BCM47XX_BOARD_NO, "Unknown Board"};
+
+static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
+{
+ char buf1[30];
+ char buf2[30];
+ char buf3[30];
+ const struct bcm47xx_board_type_list1 *e1;
+ const struct bcm47xx_board_type_list2 *e2;
+ const struct bcm47xx_board_type_list3 *e3;
+
+ if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) {
+ if (!strcmp(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) {
+ if (strstarts(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) {
+ if (strstarts(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) {
+ if (strstarts(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) {
+ if (!strcmp(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) {
+ if (!strcmp(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 ||
+ bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) {
+ /* buffalo hardware, check id for specific hardware matches */
+ for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) {
+ if (!strcmp(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+ for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
+ if (!strcmp(buf1, e2->value1) &&
+ !strcmp(buf2, e2->value2))
+ return &e2->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
+ for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) {
+ if (!strcmp(buf1, e1->value1))
+ return &e1->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 &&
+ bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) {
+ for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
+ if (!strcmp(buf1, e3->value1) &&
+ !strcmp(buf2, e3->value2) &&
+ !strcmp(buf3, e3->value3))
+ return &e3->board;
+ }
+ }
+
+ if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
+ bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) == -ENOENT) {
+ for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
+ if (!strcmp(buf1, e2->value1) &&
+ !strcmp(buf2, e2->value2))
+ return &e2->board;
+ }
+ }
+ return bcm47xx_board_unknown;
+}
+
+void __init bcm47xx_board_detect(void)
+{
+ int err;
+ char buf[10];
+ const struct bcm47xx_board_type *board_detected;
+
+ if (bcm47xx_board.board != BCM47XX_BOARD_NO)
+ return;
+
+ /* check if the nvram is available */
+ err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+
+ /* init of nvram failed, probably too early now */
+ if (err == -ENXIO) {
+ return;
+ }
+
+ board_detected = bcm47xx_board_get_nvram();
+ bcm47xx_board.board = board_detected->board;
+ strlcpy(bcm47xx_board.name, board_detected->name,
+ BCM47XX_BOARD_MAX_NAME);
+}
+
+enum bcm47xx_board bcm47xx_board_get(void)
+{
+ return bcm47xx_board.board;
+}
+EXPORT_SYMBOL(bcm47xx_board_get);
+
+const char *bcm47xx_board_get_name(void)
+{
+ return bcm47xx_board.name;
+}
+EXPORT_SYMBOL(bcm47xx_board_get_name);
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
new file mode 100644
index 00000000000..49a1ce06844
--- /dev/null
+++ b/arch/mips/bcm47xx/buttons.c
@@ -0,0 +1,562 @@
+#include "bcm47xx_private.h"
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/interrupt.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx.h>
+
+/**************************************************
+ * Database
+ **************************************************/
+
+#define BCM47XX_GPIO_KEY(_gpio, _code) \
+ { \
+ .code = _code, \
+ .gpio = _gpio, \
+ .active_low = 1, \
+ }
+
+/* Asus */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn12[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(1, KEY_RESTART),
+ BCM47XX_GPIO_KEY(4, BTN_0), /* Router mode */
+ BCM47XX_GPIO_KEY(5, BTN_1), /* Repeater mode */
+ BCM47XX_GPIO_KEY(6, BTN_2), /* AP mode */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn16[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn66u[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(9, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl300g[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl320ge[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl330ge[] __initconst = {
+ BCM47XX_GPIO_KEY(2, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gd[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gpv1[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_RESTART),
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gpv2[] __initconst = {
+ BCM47XX_GPIO_KEY(2, KEY_RESTART),
+ BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500w[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+ BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl520gc[] __initconst = {
+ BCM47XX_GPIO_KEY(2, KEY_RESTART),
+ BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl520gu[] __initconst = {
+ BCM47XX_GPIO_KEY(2, KEY_RESTART),
+ BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl700ge[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_POWER), /* Hard disk power switch */
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), /* EZSetup */
+ BCM47XX_GPIO_KEY(6, KEY_COPY), /* Copy data from USB to internal disk */
+ BCM47XX_GPIO_KEY(7, KEY_RESTART), /* Hard reset */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wlhdd[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Huawei */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_huawei_e970[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Belkin */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_belkin_f7d4301[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+ BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+/* Buffalo */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr2_a54g54[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_g125[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_g54s[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_g300n[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_rs_g54[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_rs_g54hp[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+/* Dell */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dell_tm2300[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+/* D-Link */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dlink_dir130[] __initconst = {
+ BCM47XX_GPIO_KEY(3, KEY_RESTART),
+ BCM47XX_GPIO_KEY(7, KEY_UNKNOWN),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dlink_dir330[] __initconst = {
+ BCM47XX_GPIO_KEY(3, KEY_RESTART),
+ BCM47XX_GPIO_KEY(7, KEY_UNKNOWN),
+};
+
+/* Linksys */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e1000v1[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e1000v21[] __initconst = {
+ BCM47XX_GPIO_KEY(9, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(10, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e2000v1[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e3000v1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e3200v1[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_RESTART),
+ BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e4200v1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt150nv1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt150nv11[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt160nv1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt160nv3[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt300nv11[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_UNKNOWN),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt310nv1[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+ BCM47XX_GPIO_KEY(8, KEY_UNKNOWN),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WIMAX),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt610nv1[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+ BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt610nv2[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Motorola */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_we800g[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_wr850gp[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_wr850gv2v3[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_RESTART),
+};
+
+/* Netgear */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr3400v1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_RESTART),
+ BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(8, KEY_RFKILL),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr3700v3[] __initconst = {
+ BCM47XX_GPIO_KEY(2, KEY_RFKILL),
+ BCM47XX_GPIO_KEY(3, KEY_RESTART),
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr4500v1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(5, KEY_RFKILL),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wnr834bv2[] __initconst = {
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* SimpleTech */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_simpletech_simpleshare[] __initconst = {
+ BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static struct gpio_keys_platform_data bcm47xx_button_pdata;
+
+static struct platform_device bcm47xx_buttons_gpio_keys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &bcm47xx_button_pdata,
+ }
+};
+
+/* Copy data from __initconst */
+static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons,
+ size_t nbuttons)
+{
+ size_t size = nbuttons * sizeof(*buttons);
+
+ bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL);
+ if (!bcm47xx_button_pdata.buttons)
+ return -ENOMEM;
+ memcpy(bcm47xx_button_pdata.buttons, buttons, size);
+ bcm47xx_button_pdata.nbuttons = nbuttons;
+
+ return 0;
+}
+
+#define bcm47xx_copy_bdata(dev_buttons) \
+ bcm47xx_buttons_copy(dev_buttons, ARRAY_SIZE(dev_buttons));
+
+int __init bcm47xx_buttons_register(void)
+{
+ enum bcm47xx_board board = bcm47xx_board_get();
+ int err;
+
+ switch (board) {
+ case BCM47XX_BOARD_ASUS_RTN12:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn12);
+ break;
+ case BCM47XX_BOARD_ASUS_RTN16:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn16);
+ break;
+ case BCM47XX_BOARD_ASUS_RTN66U:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn66u);
+ break;
+ case BCM47XX_BOARD_ASUS_WL300G:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl300g);
+ break;
+ case BCM47XX_BOARD_ASUS_WL320GE:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl320ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WL330GE:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl330ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GD:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gd);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GPV1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv1);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GPV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv2);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500W:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500w);
+ break;
+ case BCM47XX_BOARD_ASUS_WL520GC:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gc);
+ break;
+ case BCM47XX_BOARD_ASUS_WL520GU:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gu);
+ break;
+ case BCM47XX_BOARD_ASUS_WL700GE:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl700ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WLHDD:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd);
+ break;
+
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
+ case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301);
+ break;
+
+ case BCM47XX_BOARD_BUFFALO_WHR2_A54G54:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr2_a54g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_G125:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g125);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_G54S:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g54s);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_HP_G54:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_hp_g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_G300N:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_g300n);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_RS_G54:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54hp);
+ break;
+
+ case BCM47XX_BOARD_DELL_TM2300:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_dell_tm2300);
+ break;
+
+ case BCM47XX_BOARD_DLINK_DIR130:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir130);
+ break;
+ case BCM47XX_BOARD_DLINK_DIR330:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir330);
+ break;
+
+ case BCM47XX_BOARD_HUAWEI_E970:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_huawei_e970);
+ break;
+
+ case BCM47XX_BOARD_LINKSYS_E1000V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E1000V21:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v21);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E2000V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e2000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E3000V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E3200V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3200v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E4200V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e4200v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT150NV1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT150NV11:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv11);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT160NV1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT160NV3:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv3);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt300nv11);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54g3gv2);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT610NV1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT610NV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrtsl54gs);
+ break;
+
+ case BCM47XX_BOARD_MOTOROLA_WE800G:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g);
+ break;
+ case BCM47XX_BOARD_MOTOROLA_WR850GP:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gp);
+ break;
+ case BCM47XX_BOARD_MOTOROLA_WR850GV2V3:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gv2v3);
+ break;
+
+ case BCM47XX_BOARD_NETGEAR_WNDR3400V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3400v1);
+ break;
+ case BCM47XX_BOARD_NETGEAR_WNDR3700V3:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3700v3);
+ break;
+ case BCM47XX_BOARD_NETGEAR_WNDR4500V1:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr4500v1);
+ break;
+ case BCM47XX_BOARD_NETGEAR_WNR834BV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wnr834bv2);
+ break;
+
+ case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_simpletech_simpleshare);
+ break;
+
+ default:
+ pr_debug("No buttons configuration found for this device\n");
+ return -ENOTSUPP;
+ }
+
+ if (err)
+ return -ENOMEM;
+
+ err = platform_device_register(&bcm47xx_buttons_gpio_keys);
+ if (err) {
+ pr_err("Failed to register platform device: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
deleted file mode 100644
index 5ebdf62e96b..00000000000
--- a/arch/mips/bcm47xx/gpio.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
- */
-
-#include <linux/export.h>
-#include <linux/ssb/ssb.h>
-#include <linux/ssb/ssb_driver_chipcommon.h>
-#include <linux/ssb/ssb_driver_extif.h>
-#include <asm/mach-bcm47xx/bcm47xx.h>
-#include <asm/mach-bcm47xx/gpio.h>
-
-#if (BCM47XX_CHIPCO_GPIO_LINES > BCM47XX_EXTIF_GPIO_LINES)
-static DECLARE_BITMAP(gpio_in_use, BCM47XX_CHIPCO_GPIO_LINES);
-#else
-static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
-#endif
-
-int gpio_request(unsigned gpio, const char *tag)
-{
- switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return -EINVAL;
-
- if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return -EINVAL;
-
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
-
- return 0;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
- return -EINVAL;
-
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
-
- return 0;
-#endif
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL(gpio_request);
-
-void gpio_free(unsigned gpio)
-{
- switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return;
-
- if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return;
-
- clear_bit(gpio, gpio_in_use);
- return;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
- return;
-
- clear_bit(gpio, gpio_in_use);
- return;
-#endif
- }
-}
-EXPORT_SYMBOL(gpio_free);
-
-int gpio_to_irq(unsigned gpio)
-{
- switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
- return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
- else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
- return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
- else
- return -EINVAL;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
-#endif
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 8cf3833b2d2..e0585b76ec1 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -25,10 +25,11 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <asm/setup.h>
#include <asm/irq_cpu.h>
#include <bcm47xx.h>
-void plat_irq_dispatch(void)
+asmlinkage void plat_irq_dispatch(void)
{
u32 cause;
@@ -50,6 +51,18 @@ void plat_irq_dispatch(void)
do_IRQ(6);
}
+#define DEFINE_HWx_IRQDISPATCH(x) \
+ static void bcm47xx_hw ## x ## _irqdispatch(void) \
+ { \
+ do_IRQ(x); \
+ }
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+DEFINE_HWx_IRQDISPATCH(5)
+DEFINE_HWx_IRQDISPATCH(6)
+DEFINE_HWx_IRQDISPATCH(7)
+
void __init arch_init_irq(void)
{
#ifdef CONFIG_BCM47XX_BCMA
@@ -64,4 +77,14 @@ void __init arch_init_irq(void)
}
#endif
mips_cpu_irq_init();
+
+ if (cpu_has_vint) {
+ pr_info("Setting up vectored interrupts\n");
+ set_vi_handler(2, bcm47xx_hw2_irqdispatch);
+ set_vi_handler(3, bcm47xx_hw3_irqdispatch);
+ set_vi_handler(4, bcm47xx_hw4_irqdispatch);
+ set_vi_handler(5, bcm47xx_hw5_irqdispatch);
+ set_vi_handler(6, bcm47xx_hw6_irqdispatch);
+ set_vi_handler(7, bcm47xx_hw7_irqdispatch);
+ }
}
diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c
new file mode 100644
index 00000000000..adcb547a91c
--- /dev/null
+++ b/arch/mips/bcm47xx/leds.c
@@ -0,0 +1,591 @@
+#include "bcm47xx_private.h"
+
+#include <linux/leds.h>
+#include <bcm47xx_board.h>
+
+/**************************************************
+ * Database
+ **************************************************/
+
+#define BCM47XX_GPIO_LED(_gpio, _color, _function, _active_low, \
+ _default_state) \
+ { \
+ .name = "bcm47xx:" _color ":" _function, \
+ .gpio = _gpio, \
+ .active_low = _active_low, \
+ .default_state = _default_state, \
+ }
+
+#define BCM47XX_GPIO_LED_TRIGGER(_gpio, _color, _function, _active_low, \
+ _default_trigger) \
+ { \
+ .name = "bcm47xx:" _color ":" _function, \
+ .gpio = _gpio, \
+ .active_low = _active_low, \
+ .default_state = LEDS_GPIO_DEFSTATE_OFF, \
+ .default_trigger = _default_trigger, \
+ }
+
+/* Asus */
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn12[] __initconst = {
+ BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn16[] __initconst = {
+ BCM47XX_GPIO_LED(1, "blue", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn66u[] __initconst = {
+ BCM47XX_GPIO_LED(12, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(15, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl300g[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl320ge[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(11, "unk", "link", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl330ge[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gd[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gpv1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gpv2[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500w[] __initconst = {
+ BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl520gc[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl520gu[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl700ge[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), /* Labeled "READY" (there is no "power" LED). Originally ON, flashing on USB activity. */
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wlhdd[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Belkin */
+
+static const struct gpio_led
+bcm47xx_leds_belkin_f7d4301[] __initconst = {
+ BCM47XX_GPIO_LED(10, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(11, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(12, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(13, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(14, "unk", "usb0", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(15, "unk", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Buffalo */
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr2_a54g54[] __initconst = {
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_g125[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_g54s[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_hp_g54[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_g300n[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_rs_g54[] __initconst = {
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_rs_g54hp[] __initconst = {
+ BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Dell */
+
+static const struct gpio_led
+bcm47xx_leds_dell_tm2300[] __initconst = {
+ BCM47XX_GPIO_LED(6, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+/* D-Link */
+
+static const struct gpio_led
+bcm47xx_leds_dlink_dir130[] __initconst = {
+ BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */
+ BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_dlink_dir330[] __initconst = {
+ BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */
+ BCM47XX_GPIO_LED(4, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Huawei */
+
+static const struct gpio_led
+bcm47xx_leds_huawei_e970[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Linksys */
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e1000v1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e1000v21[] __initconst = {
+ BCM47XX_GPIO_LED(5, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(6, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "amber", "wps", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(8, "blue", "wps", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e2000v1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(4, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e3000v1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e3200v1[] __initconst = {
+ BCM47XX_GPIO_LED(3, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e4200v1[] __initconst = {
+ BCM47XX_GPIO_LED(5, "white", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt150nv1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt150nv11[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt160nv1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt160nv3[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt300nv11[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt310nv1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(5, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "green", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "blue", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt610nv1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt610nv2[] __initconst = {
+ BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Motorola */
+
+static const struct gpio_led
+bcm47xx_leds_motorola_we800g[] __initconst = {
+ BCM47XX_GPIO_LED(1, "amber", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "unk", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), /* There are only 3 LEDs: Power, Wireless and Device (ethernet) */
+ BCM47XX_GPIO_LED(4, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_motorola_wr850gp[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(6, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_motorola_wr850gv2v3[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Netgear */
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wndr3400v1[] __initconst = {
+ BCM47XX_GPIO_LED(2, "green", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(7, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wndr4500v1[] __initconst = {
+ BCM47XX_GPIO_LED(1, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(2, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(8, "green", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(9, "green", "2ghz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(11, "blue", "5ghz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(14, "green", "usb2", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wnr834bv2[] __initconst = {
+ BCM47XX_GPIO_LED(2, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(3, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Siemens */
+static const struct gpio_led
+bcm47xx_leds_siemens_se505v2[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+/* SimpleTech */
+
+static const struct gpio_led
+bcm47xx_leds_simpletech_simpleshare[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "status", 1, LEDS_GPIO_DEFSTATE_OFF), /* "Ready" LED */
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static struct gpio_led_platform_data bcm47xx_leds_pdata;
+
+#define bcm47xx_set_pdata(dev_leds) do { \
+ bcm47xx_leds_pdata.leds = dev_leds; \
+ bcm47xx_leds_pdata.num_leds = ARRAY_SIZE(dev_leds); \
+} while (0)
+
+void __init bcm47xx_leds_register(void)
+{
+ enum bcm47xx_board board = bcm47xx_board_get();
+
+ switch (board) {
+ case BCM47XX_BOARD_ASUS_RTN12:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_rtn12);
+ break;
+ case BCM47XX_BOARD_ASUS_RTN16:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_rtn16);
+ break;
+ case BCM47XX_BOARD_ASUS_RTN66U:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_rtn66u);
+ break;
+ case BCM47XX_BOARD_ASUS_WL300G:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl300g);
+ break;
+ case BCM47XX_BOARD_ASUS_WL320GE:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl320ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WL330GE:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl330ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GD:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gd);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GPV1:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv1);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500GPV2:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv2);
+ break;
+ case BCM47XX_BOARD_ASUS_WL500W:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl500w);
+ break;
+ case BCM47XX_BOARD_ASUS_WL520GC:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gc);
+ break;
+ case BCM47XX_BOARD_ASUS_WL520GU:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gu);
+ break;
+ case BCM47XX_BOARD_ASUS_WL700GE:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wl700ge);
+ break;
+ case BCM47XX_BOARD_ASUS_WLHDD:
+ bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd);
+ break;
+
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
+ case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
+ bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301);
+ break;
+
+ case BCM47XX_BOARD_BUFFALO_WHR2_A54G54:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr2_a54g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_G125:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g125);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_G54S:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g54s);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WHR_HP_G54:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_hp_g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_G300N:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_g300n);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_RS_G54:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54);
+ break;
+ case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP:
+ bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54hp);
+ break;
+
+ case BCM47XX_BOARD_DELL_TM2300:
+ bcm47xx_set_pdata(bcm47xx_leds_dell_tm2300);
+ break;
+
+ case BCM47XX_BOARD_DLINK_DIR130:
+ bcm47xx_set_pdata(bcm47xx_leds_dlink_dir130);
+ break;
+ case BCM47XX_BOARD_DLINK_DIR330:
+ bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330);
+ break;
+
+ case BCM47XX_BOARD_HUAWEI_E970:
+ bcm47xx_set_pdata(bcm47xx_leds_huawei_e970);
+ break;
+
+ case BCM47XX_BOARD_LINKSYS_E1000V1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E1000V21:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v21);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E2000V1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e2000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E3000V1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e3000v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E3200V1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e3200v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_E4200V1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_e4200v1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT150NV1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT150NV11:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv11);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT160NV1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT160NV3:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv3);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt300nv11);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54g3gv2);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT610NV1:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT610NV2:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrtsl54gs);
+ break;
+
+ case BCM47XX_BOARD_MOTOROLA_WE800G:
+ bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g);
+ break;
+ case BCM47XX_BOARD_MOTOROLA_WR850GP:
+ bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gp);
+ break;
+ case BCM47XX_BOARD_MOTOROLA_WR850GV2V3:
+ bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gv2v3);
+ break;
+
+ case BCM47XX_BOARD_NETGEAR_WNDR3400V1:
+ bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr3400v1);
+ break;
+ case BCM47XX_BOARD_NETGEAR_WNDR4500V1:
+ bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr4500v1);
+ break;
+ case BCM47XX_BOARD_NETGEAR_WNR834BV2:
+ bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2);
+ break;
+
+ case BCM47XX_BOARD_SIEMENS_SE505V2:
+ bcm47xx_set_pdata(bcm47xx_leds_siemens_se505v2);
+ break;
+
+ case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
+ bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare);
+ break;
+
+ default:
+ pr_debug("No LEDs configuration found for this device\n");
+ return;
+ }
+
+ gpio_led_register_device(-1, &bcm47xx_leds_pdata);
+}
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index a84e3bb7387..2bed73a684a 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -3,98 +3,174 @@
*
* Copyright (C) 2005 Broadcom Corporation
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/ssb/ssb.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/addrspace.h>
-#include <asm/mach-bcm47xx/nvram.h>
+#include <bcm47xx_nvram.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
static char nvram_buf[NVRAM_SPACE];
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(u32 end)
+{
+ struct nvram_header *header;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+ header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]);
+ if (header->magic == NVRAM_HEADER)
+ return nvram_sizes[i];
+ }
+
+ return 0;
+}
/* Probe for NVRAM header */
-static void early_nvram_init(void)
+static int nvram_find_and_copy(u32 base, u32 lim)
{
-#ifdef CONFIG_BCM47XX_SSB
- struct ssb_mipscore *mcore_ssb;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- struct bcma_drv_cc *bcma_cc;
-#endif
struct nvram_header *header;
int i;
- u32 base = 0;
- u32 lim = 0;
u32 off;
u32 *src, *dst;
+ u32 size;
- switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- mcore_ssb = &bcm47xx_bus.ssb.mipscore;
- base = mcore_ssb->flash_window;
- lim = mcore_ssb->flash_window_size;
- break;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
- base = bcma_cc->pflash.window;
- lim = bcma_cc->pflash.window_size;
- break;
-#endif
- }
-
+ /* TODO: when nvram is on nand flash check for bad blocks first. */
off = FLASH_MIN;
while (off <= lim) {
/* Windowed flash access */
- header = (struct nvram_header *)
- KSEG1ADDR(base + off - NVRAM_SPACE);
- if (header->magic == NVRAM_HEADER)
+ size = find_nvram_size(base + off);
+ if (size) {
+ header = (struct nvram_header *)KSEG1ADDR(base + off -
+ size);
goto found;
+ }
off <<= 1;
}
/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
header = (struct nvram_header *) KSEG1ADDR(base + 4096);
- if (header->magic == NVRAM_HEADER)
+ if (header->magic == NVRAM_HEADER) {
+ size = NVRAM_SPACE;
goto found;
+ }
header = (struct nvram_header *) KSEG1ADDR(base + 1024);
- if (header->magic == NVRAM_HEADER)
+ if (header->magic == NVRAM_HEADER) {
+ size = NVRAM_SPACE;
goto found;
+ }
- return;
+ pr_err("no nvram found\n");
+ return -ENXIO;
found:
+
+ if (header->len > size)
+ pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
+ if (header->len > NVRAM_SPACE)
+ pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+ header->len, NVRAM_SPACE);
+
src = (u32 *) header;
dst = (u32 *) nvram_buf;
for (i = 0; i < sizeof(struct nvram_header); i += 4)
*dst++ = *src++;
- for (; i < header->len && i < NVRAM_SPACE; i += 4)
+ for (; i < header->len && i < NVRAM_SPACE && i < size; i += 4)
*dst++ = le32_to_cpu(*src++);
+ memset(dst, 0x0, NVRAM_SPACE - i);
+
+ return 0;
+}
+
+#ifdef CONFIG_BCM47XX_SSB
+static int nvram_init_ssb(void)
+{
+ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
+ u32 base;
+ u32 lim;
+
+ if (mcore->pflash.present) {
+ base = mcore->pflash.window;
+ lim = mcore->pflash.window_size;
+ } else {
+ pr_err("Couldn't find supported flash memory\n");
+ return -ENXIO;
+ }
+
+ return nvram_find_and_copy(base, lim);
+}
+#endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+static int nvram_init_bcma(void)
+{
+ struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc;
+ u32 base;
+ u32 lim;
+
+#ifdef CONFIG_BCMA_NFLASH
+ if (cc->nflash.boot) {
+ base = BCMA_SOC_FLASH1;
+ lim = BCMA_SOC_FLASH1_SZ;
+ } else
+#endif
+ if (cc->pflash.present) {
+ base = cc->pflash.window;
+ lim = cc->pflash.window_size;
+#ifdef CONFIG_BCMA_SFLASH
+ } else if (cc->sflash.present) {
+ base = cc->sflash.window;
+ lim = cc->sflash.size;
+#endif
+ } else {
+ pr_err("Couldn't find supported flash memory\n");
+ return -ENXIO;
+ }
+
+ return nvram_find_and_copy(base, lim);
+}
+#endif
+
+static int nvram_init(void)
+{
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return nvram_init_ssb();
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return nvram_init_bcma();
+#endif
+ }
+ return -ENXIO;
}
-int nvram_getenv(char *name, char *val, size_t val_len)
+int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
{
char *var, *value, *end, *eq;
+ int err;
if (!name)
- return NVRAM_ERR_INV_PARAM;
+ return -EINVAL;
- if (!nvram_buf[0])
- early_nvram_init();
+ if (!nvram_buf[0]) {
+ err = nvram_init();
+ if (err)
+ return err;
+ }
/* Look for name=value and return value */
var = &nvram_buf[sizeof(struct nvram_header)];
@@ -107,10 +183,29 @@ int nvram_getenv(char *name, char *val, size_t val_len)
value = eq + 1;
if ((eq - var) == strlen(name) &&
strncmp(var, name, (eq - var)) == 0) {
- snprintf(val, val_len, "%s", value);
- return 0;
+ return snprintf(val, val_len, "%s", value);
}
}
- return NVRAM_ERR_ENVNOTFOUND;
+ return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const char *name)
+{
+ int i, err;
+ char nvram_var[10];
+ char buf[30];
+
+ for (i = 0; i < 32; i++) {
+ err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+ if (err <= 0)
+ continue;
+ err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+ if (err <= 0)
+ continue;
+ if (!strcmp(name, buf))
+ return i;
+ }
+ return -ENOENT;
}
-EXPORT_SYMBOL(nvram_getenv);
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c
index f6e9063cc4c..1a03a2f4349 100644
--- a/arch/mips/bcm47xx/prom.c
+++ b/arch/mips/bcm47xx/prom.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
* Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -27,106 +28,35 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
+#include <linux/ssb/ssb_driver_chipcommon.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/smp.h>
#include <asm/bootinfo.h>
-#include <asm/fw/cfe/cfe_api.h>
-#include <asm/fw/cfe/cfe_error.h>
+#include <bcm47xx.h>
+#include <bcm47xx_board.h>
-static int cfe_cons_handle;
-const char *get_system_type(void)
-{
- return "Broadcom BCM47XX";
-}
-
-void prom_putchar(char c)
-{
- while (cfe_write(cfe_cons_handle, &c, 1) == 0)
- ;
-}
-
-static __init void prom_init_cfe(void)
-{
- uint32_t cfe_ept;
- uint32_t cfe_handle;
- uint32_t cfe_eptseal;
- int argc = fw_arg0;
- char **envp = (char **) fw_arg2;
- int *prom_vec = (int *) fw_arg3;
-
- /*
- * Check if a loader was used; if NOT, the 4 arguments are
- * what CFE gives us (handle, 0, EPT and EPTSEAL)
- */
- if (argc < 0) {
- cfe_handle = (uint32_t)argc;
- cfe_ept = (uint32_t)envp;
- cfe_eptseal = (uint32_t)prom_vec;
- } else {
- if ((int)prom_vec < 0) {
- /*
- * Old loader; all it gives us is the handle,
- * so use the "known" entrypoint and assume
- * the seal.
- */
- cfe_handle = (uint32_t)prom_vec;
- cfe_ept = 0xBFC00500;
- cfe_eptseal = CFE_EPTSEAL;
- } else {
- /*
- * Newer loaders bundle the handle/ept/eptseal
- * Note: prom_vec is in the loader's useg
- * which is still alive in the TLB.
- */
- cfe_handle = prom_vec[0];
- cfe_ept = prom_vec[2];
- cfe_eptseal = prom_vec[3];
- }
- }
-
- if (cfe_eptseal != CFE_EPTSEAL) {
- /* too early for panic to do any good */
- printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
- while (1) ;
- }
-
- cfe_init(cfe_handle, cfe_ept);
-}
+static char bcm47xx_system_type[20] = "Broadcom BCM47XX";
-static __init void prom_init_console(void)
+const char *get_system_type(void)
{
- /* Initialize CFE console */
- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
+ return bcm47xx_system_type;
}
-static __init void prom_init_cmdline(void)
+__init void bcm47xx_set_system_type(u16 chip_id)
{
- static char buf[COMMAND_LINE_SIZE] __initdata;
-
- /* Get the kernel command line from CFE */
- if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
- buf[COMMAND_LINE_SIZE - 1] = 0;
- strcpy(arcs_cmdline, buf);
- }
-
- /* Force a console handover by adding a console= argument if needed,
- * as CFE is not available anymore later in the boot process. */
- if ((strstr(arcs_cmdline, "console=")) == NULL) {
- /* Try to read the default serial port used by CFE */
- if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
- || (strncmp("uart", buf, 4)))
- /* Default to uart0 */
- strcpy(buf, "uart0");
-
- /* Compute the new command line */
- snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
- arcs_cmdline, buf[4]);
- }
+ snprintf(bcm47xx_system_type, sizeof(bcm47xx_system_type),
+ (chip_id > 0x9999) ? "Broadcom BCM%d" :
+ "Broadcom BCM%04X",
+ chip_id);
}
static __init void prom_init_mem(void)
{
unsigned long mem;
unsigned long max;
+ unsigned long off;
+ struct cpuinfo_mips *c = &current_cpu_data;
/* Figure out memory size by finding aliases.
*
@@ -139,31 +69,46 @@ static __init void prom_init_mem(void)
* BCM47XX uses 128MB for addressing the ram, if the system contains
* less that that amount of ram it remaps the ram more often into the
* available space.
- * Accessing memory after 128MB will cause an exception.
- * max contains the biggest possible address supported by the platform.
- * If the method wants to try something above we assume 128MB ram.
*/
- max = ((unsigned long)(prom_init) | ((128 << 20) - 1));
- for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
- if (((unsigned long)(prom_init) + mem) > max) {
- mem = (128 << 20);
+
+ /* Physical address, without mapping to any kernel segment */
+ off = CPHYSADDR((unsigned long)prom_init);
+
+ /* Accessing memory after 128 MiB will cause an exception */
+ max = 128 << 20;
+
+ for (mem = 1 << 20; mem < max; mem += 1 << 20) {
+ /* Loop condition may be not enough, off may be over 1 MiB */
+ if (off + mem >= max) {
+ mem = max;
printk(KERN_DEBUG "assume 128MB RAM\n");
break;
}
- if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
- *(unsigned long *)(prom_init))
+ if (!memcmp(prom_init, prom_init + mem, 32))
break;
}
+ /* Ignoring the last page when ddr size is 128M. Cached
+ * accesses to last page is causing the processor to prefetch
+ * using address above 128M stepping out of the ddr address
+ * space.
+ */
+ if (c->cputype == CPU_74K && (mem == (128 << 20)))
+ mem -= 0x1000;
+
add_memory_region(0, mem, BOOT_MEM_RAM);
}
+/*
+ * This is the first serial on the chip common core, it is at this position
+ * for sb (ssb) and ai (bcma) bus.
+ */
+#define BCM47XX_SERIAL_ADDR (SSB_ENUM_BASE + SSB_CHIPCO_UART0_DATA)
+
void __init prom_init(void)
{
- prom_init_cfe();
- prom_init_console();
- prom_init_cmdline();
prom_init_mem();
+ setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0);
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 57981e4fe2b..2f5bbd68e9a 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -31,7 +31,8 @@ static int __init uart8250_init_ssb(void)
memset(&uart8250_data, 0, sizeof(uart8250_data));
- for (i = 0; i < mcore->nr_serial_ports; i++) {
+ for (i = 0; i < mcore->nr_serial_ports &&
+ i < ARRAY_SIZE(uart8250_data) - 1; i++) {
struct plat_serial8250_port *p = &(uart8250_data[i]);
struct ssb_serial_port *ssb_port = &(mcore->serial_ports[i]);
@@ -55,14 +56,15 @@ static int __init uart8250_init_bcma(void)
memset(&uart8250_data, 0, sizeof(uart8250_data));
- for (i = 0; i < cc->nr_serial_ports; i++) {
+ for (i = 0; i < cc->nr_serial_ports &&
+ i < ARRAY_SIZE(uart8250_data) - 1; i++) {
struct plat_serial8250_port *p = &(uart8250_data[i]);
struct bcma_serial_port *bcma_port;
bcma_port = &(cc->serial_ports[i]);
p->mapbase = (unsigned int) bcma_port->regs;
p->membase = (void *) bcma_port->regs;
- p->irq = bcma_port->irq + 2;
+ p->irq = bcma_port->irq;
p->uartclk = bcma_port->baud_base;
p->regshift = bcma_port->reg_shift;
p->iotype = UPIO_MEM;
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index aab6b0c40a7..63a4b0e915d 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -3,7 +3,7 @@
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2006 Michael Buesch <m@bues.ch>
* Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
- * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,16 +26,24 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "bcm47xx_private.h"
+
#include <linux/export.h>
#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
#include <linux/bcma/bcma_soc.h>
#include <asm/bootinfo.h>
+#include <asm/idle.h>
+#include <asm/prom.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <bcm47xx.h>
-#include <asm/mach-bcm47xx/nvram.h>
+#include <bcm47xx_nvram.h>
+#include <bcm47xx_board.h>
union bcm47xx_bus bcm47xx_bus;
EXPORT_SYMBOL(bcm47xx_bus);
@@ -85,164 +93,16 @@ static void bcm47xx_machine_halt(void)
}
#ifdef CONFIG_BCM47XX_SSB
-#define READ_FROM_NVRAM(_outvar, name, buf) \
- if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
- sprom->_outvar = simple_strtoul(buf, NULL, 0);
-
-#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \
- if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \
- nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\
- sprom->_outvar = simple_strtoul(buf, NULL, 0);
-
-static inline int nvram_getprefix(const char *prefix, char *name,
- char *buf, int len)
-{
- if (prefix) {
- char key[100];
-
- snprintf(key, sizeof(key), "%s%s", prefix, name);
- return nvram_getenv(key, buf, len);
- }
-
- return nvram_getenv(name, buf, len);
-}
-
-static u32 nvram_getu32(const char *name, char *buf, int len)
-{
- int rv;
- char key[100];
- u16 var0, var1;
-
- snprintf(key, sizeof(key), "%s0", name);
- rv = nvram_getenv(key, buf, len);
- /* return 0 here so this looks like unset */
- if (rv < 0)
- return 0;
- var0 = simple_strtoul(buf, NULL, 0);
-
- snprintf(key, sizeof(key), "%s1", name);
- rv = nvram_getenv(key, buf, len);
- if (rv < 0)
- return 0;
- var1 = simple_strtoul(buf, NULL, 0);
- return var1 << 16 | var0;
-}
-
-static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
-{
- char buf[100];
- u32 boardflags;
-
- memset(sprom, 0, sizeof(struct ssb_sprom));
-
- sprom->revision = 1; /* Fallback: Old hardware does not define this. */
- READ_FROM_NVRAM(revision, "sromrev", buf);
- if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 ||
- nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0)
- nvram_parse_macaddr(buf, sprom->il0mac);
- if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0)
- nvram_parse_macaddr(buf, sprom->et0mac);
- if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0)
- nvram_parse_macaddr(buf, sprom->et1mac);
- READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
- READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
- READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf);
- READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf);
- READ_FROM_NVRAM(board_rev, "boardrev", buf);
- READ_FROM_NVRAM(country_code, "ccode", buf);
- READ_FROM_NVRAM(ant_available_a, "aa5g", buf);
- READ_FROM_NVRAM(ant_available_bg, "aa2g", buf);
- READ_FROM_NVRAM(pa0b0, "pa0b0", buf);
- READ_FROM_NVRAM(pa0b1, "pa0b1", buf);
- READ_FROM_NVRAM(pa0b2, "pa0b2", buf);
- READ_FROM_NVRAM(pa1b0, "pa1b0", buf);
- READ_FROM_NVRAM(pa1b1, "pa1b1", buf);
- READ_FROM_NVRAM(pa1b2, "pa1b2", buf);
- READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf);
- READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf);
- READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf);
- READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
- READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
- READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
- READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf);
- READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf);
- READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf);
- READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf);
- READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf);
- READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf);
- READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf);
- READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf);
- READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf);
- READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf);
- READ_FROM_NVRAM(tri2g, "tri2g", buf);
- READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
- READ_FROM_NVRAM(tri5g, "tri5g", buf);
- READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
- READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf);
- READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf);
- READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf);
- READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf);
- READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf);
- READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf);
- READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf);
- READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf);
- READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf);
- READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf);
- READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf);
- READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf);
- READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf);
- READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf);
- READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf);
- READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf);
- READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
- READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
- READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
- READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf);
- READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf);
- READ_FROM_NVRAM(bxa2g, "bxa2g", buf);
- READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf);
- READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf);
- READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
- READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
- READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
-
- sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf));
- sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf));
- sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf));
- sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf));
-
- READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf);
- READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf);
- READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf);
- READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf);
- memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24,
- sizeof(sprom->antenna_gain.ghz5));
-
- if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) {
- boardflags = simple_strtoul(buf, NULL, 0);
- if (boardflags) {
- sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
- sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
- }
- }
- if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) {
- boardflags = simple_strtoul(buf, NULL, 0);
- if (boardflags) {
- sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
- sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16;
- }
- }
-}
-
-int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
{
char prefix[10];
if (bus->bustype == SSB_BUSTYPE_PCI) {
+ memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
- bcm47xx_fill_sprom(out, prefix);
+ bcm47xx_fill_sprom(out, prefix, false);
return 0;
} else {
printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n");
@@ -251,25 +111,19 @@ int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
}
static int bcm47xx_get_invariants(struct ssb_bus *bus,
- struct ssb_init_invariants *iv)
+ struct ssb_init_invariants *iv)
{
char buf[20];
/* Fill boardinfo structure */
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
- if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
- iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0);
- else
- iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
- if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
- if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
- iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
+ bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
- bcm47xx_fill_sprom(&iv->sprom, NULL);
+ memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
+ bcm47xx_fill_sprom(&iv->sprom, NULL, false);
- if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+ if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
return 0;
@@ -281,7 +135,7 @@ static void __init bcm47xx_register_ssb(void)
char buf[100];
struct ssb_mipscore *mcore;
- err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom);
+ err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb);
if (err)
printk(KERN_WARNING "bcm47xx: someone else already registered"
" a ssb SPROM callback handler (err %d)\n", err);
@@ -292,7 +146,7 @@ static void __init bcm47xx_register_ssb(void)
panic("Failed to initialize SSB bus (err %d)", err);
mcore = &bcm47xx_bus.ssb.mipscore;
- if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+ if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
if (strstr(buf, "console=ttyS1")) {
struct ssb_serial_port port;
@@ -308,13 +162,49 @@ static void __init bcm47xx_register_ssb(void)
#endif
#ifdef CONFIG_BCM47XX_BCMA
+static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
+{
+ char prefix[10];
+ struct bcma_device *core;
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ memset(out, 0, sizeof(struct ssb_sprom));
+ snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
+ bus->host_pci->bus->number + 1,
+ PCI_SLOT(bus->host_pci->devfn));
+ bcm47xx_fill_sprom(out, prefix, false);
+ return 0;
+ case BCMA_HOSTTYPE_SOC:
+ memset(out, 0, sizeof(struct ssb_sprom));
+ core = bcma_find_core(bus, BCMA_CORE_80211);
+ if (core) {
+ snprintf(prefix, sizeof(prefix), "sb/%u/",
+ core->core_index);
+ bcm47xx_fill_sprom(out, prefix, true);
+ } else {
+ bcm47xx_fill_sprom(out, NULL, false);
+ }
+ return 0;
+ default:
+ pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n");
+ return -EINVAL;
+ }
+}
+
static void __init bcm47xx_register_bcma(void)
{
int err;
+ err = bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma);
+ if (err)
+ pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err);
+
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
if (err)
panic("Failed to initialize BCMA bus (err %d)", err);
+
+ bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
}
#endif
@@ -322,24 +212,59 @@ void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- if (c->cputype == CPU_74K) {
+ if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K)) {
printk(KERN_INFO "bcm47xx: using bcma bus\n");
#ifdef CONFIG_BCM47XX_BCMA
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
bcm47xx_register_bcma();
+ bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id);
#endif
} else {
printk(KERN_INFO "bcm47xx: using ssb bus\n");
#ifdef CONFIG_BCM47XX_SSB
bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
bcm47xx_register_ssb();
+ bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id);
#endif
}
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
pm_power_off = bcm47xx_machine_halt;
+ bcm47xx_board_detect();
+ mips_set_machine_name(bcm47xx_board_get_name());
+}
+
+static int __init bcm47xx_cpu_fixes(void)
+{
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ /* Nothing to do */
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* The BCM4706 has a problem with the CPU wait instruction.
+ * When r4k_wait or r4k_wait_irqoff is used will just hang and
+ * not return from a msleep(). Removing the cpu_wait
+ * functionality is a workaround for this problem. The BCM4716
+ * does not have this problem.
+ */
+ if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706)
+ cpu_wait = NULL;
+ break;
+#endif
+ }
+ return 0;
}
+arch_initcall(bcm47xx_cpu_fixes);
+
+static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
+ .link = 1,
+ .speed = SPEED_100,
+ .duplex = DUPLEX_FULL,
+};
static int __init bcm47xx_register_bus_complete(void)
{
@@ -355,6 +280,11 @@ static int __init bcm47xx_register_bus_complete(void)
break;
#endif
}
+ bcm47xx_buttons_register();
+ bcm47xx_leds_register();
+ bcm47xx_workarounds();
+
+ fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
return 0;
}
device_initcall(bcm47xx_register_bus_complete);
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
new file mode 100644
index 00000000000..da4cdb16844
--- /dev/null
+++ b/arch/mips/bcm47xx/sprom.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <bcm47xx.h>
+#include <bcm47xx_nvram.h>
+
+static void create_key(const char *prefix, const char *postfix,
+ const char *name, char *buf, int len)
+{
+ if (prefix && postfix)
+ snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+ else if (prefix)
+ snprintf(buf, len, "%s%s", prefix, name);
+ else if (postfix)
+ snprintf(buf, len, "%s%s", name, postfix);
+ else
+ snprintf(buf, len, "%s", name);
+}
+
+static int get_nvram_var(const char *prefix, const char *postfix,
+ const char *name, char *buf, int len, bool fallback)
+{
+ char key[40];
+ int err;
+
+ create_key(prefix, postfix, name, key, sizeof(key));
+
+ err = bcm47xx_nvram_getenv(key, buf, len);
+ if (fallback && err == -ENOENT && prefix) {
+ create_key(NULL, postfix, name, key, sizeof(key));
+ err = bcm47xx_nvram_getenv(key, buf, len);
+ }
+ return err;
+}
+
+#define NVRAM_READ_VAL(type) \
+static void nvram_read_ ## type (const char *prefix, \
+ const char *postfix, const char *name, \
+ type *val, type allset, bool fallback) \
+{ \
+ char buf[100]; \
+ int err; \
+ type var; \
+ \
+ err = get_nvram_var(prefix, postfix, name, buf, sizeof(buf), \
+ fallback); \
+ if (err < 0) \
+ return; \
+ err = kstrto ## type(strim(buf), 0, &var); \
+ if (err) { \
+ pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \
+ prefix, name, postfix, buf, err); \
+ return; \
+ } \
+ if (allset && var == allset) \
+ return; \
+ *val = var; \
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const char *prefix, const char *name,
+ u16 *val_lo, u16 *val_hi, bool fallback)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ err = kstrtou32(strim(buf), 0, &val);
+ if (err) {
+ pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+ prefix, name, buf, err);
+ return;
+ }
+ *val_lo = (val & 0x0000FFFFU);
+ *val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const char *prefix, const char *name,
+ u8 *leddc_on_time, u8 *leddc_off_time,
+ bool fallback)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ err = kstrtou32(strim(buf), 0, &val);
+ if (err) {
+ pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+ prefix, name, buf, err);
+ return;
+ }
+
+ if (val == 0xffff || val == 0xffffffff)
+ return;
+
+ *leddc_on_time = val & 0xff;
+ *leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void nvram_read_macaddr(const char *prefix, const char *name,
+ u8 val[6], bool fallback)
+{
+ char buf[100];
+ int err;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+
+ bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const char *prefix, const char *name,
+ char val[2], bool fallback)
+{
+ char buf[10];
+ int err;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ if (buf[0] == '0')
+ return;
+ if (strlen(buf) > 2) {
+ pr_warn("alpha2 is too long %s\n", buf);
+ return;
+ }
+ memcpy(val, buf, 2);
+}
+
+static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "devid", &sprom->dev_id, 0, fallback);
+ nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff, fallback);
+ nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff, fallback);
+ nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff, fallback);
+ nvram_read_u8(prefix, NULL, "ledbh3", &sprom->gpio3, 0xff, fallback);
+ nvram_read_u8(prefix, NULL, "aa2g", &sprom->ant_available_bg, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "aa5g", &sprom->ant_available_a, 0,
+ fallback);
+ nvram_read_s8(prefix, NULL, "ag0", &sprom->antenna_gain.a0, 0,
+ fallback);
+ nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0,
+ fallback);
+ nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback);
+}
+
+static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "pa0b0", &sprom->pa0b0, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa0b1", &sprom->pa0b1, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa0b2", &sprom->pa0b2, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pa0itssit", &sprom->itssi_bg, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "pa1b0", &sprom->pa1b0, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1b1", &sprom->pa1b1, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1b2", &sprom->pa1b2, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pa1itssit", &sprom->itssi_a, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0, fallback);
+}
+
+static void bcm47xx_fill_sprom_r1(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "boardflags", &sprom->boardflags_lo, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "cc", &sprom->country_code, 0, fallback);
+}
+
+static void bcm47xx_fill_sprom_r2389(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "opo", &sprom->opo, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1lob0", &sprom->pa1lob0, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1lob1", &sprom->pa1lob1, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1lob2", &sprom->pa1lob2, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1hib0", &sprom->pa1hib0, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1hib1", &sprom->pa1hib1, 0, fallback);
+ nvram_read_u16(prefix, NULL, "pa1hib2", &sprom->pa1hib2, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0,
+ fallback);
+}
+
+static void bcm47xx_fill_sprom_r389(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "bxa2g", &sprom->bxa2g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "rssisav2g", &sprom->rssisav2g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "rssismc2g", &sprom->rssismc2g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "rssismf2g", &sprom->rssismf2g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "bxa5g", &sprom->bxa5g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "rssisav5g", &sprom->rssisav5g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "rssismc5g", &sprom->rssismc5g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "rssismf5g", &sprom->rssismf5g, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tri2g", &sprom->tri2g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "tri5g", &sprom->tri5g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "tri5gl", &sprom->tri5gl, 0, fallback);
+ nvram_read_u8(prefix, NULL, "tri5gh", &sprom->tri5gh, 0, fallback);
+ nvram_read_s8(prefix, NULL, "rxpo2g", &sprom->rxpo2g, 0, fallback);
+ nvram_read_s8(prefix, NULL, "rxpo5g", &sprom->rxpo5g, 0, fallback);
+}
+
+static void bcm47xx_fill_sprom_r3(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0, fallback);
+ nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time,
+ &sprom->leddc_off_time, fallback);
+}
+
+static void bcm47xx_fill_sprom_r4589(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0, fallback);
+ nvram_read_s8(prefix, NULL, "ag2", &sprom->antenna_gain.a2, 0,
+ fallback);
+ nvram_read_s8(prefix, NULL, "ag3", &sprom->antenna_gain.a3, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txchain", &sprom->txchain, 0xf, fallback);
+ nvram_read_u8(prefix, NULL, "rxchain", &sprom->rxchain, 0xf, fallback);
+ nvram_read_u8(prefix, NULL, "antswitch", &sprom->antswitch, 0xff,
+ fallback);
+ nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time,
+ &sprom->leddc_off_time, fallback);
+}
+
+static void bcm47xx_fill_sprom_r458(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "cck2gpo", &sprom->cck2gpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "cddpo", &sprom->cddpo, 0, fallback);
+ nvram_read_u16(prefix, NULL, "stbcpo", &sprom->stbcpo, 0, fallback);
+ nvram_read_u16(prefix, NULL, "bw40po", &sprom->bw40po, 0, fallback);
+ nvram_read_u16(prefix, NULL, "bwduppo", &sprom->bwduppo, 0, fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0,
+ fallback);
+}
+
+static void bcm47xx_fill_sprom_r45(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "txpid2ga0", &sprom->txpid2g[0], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid2ga1", &sprom->txpid2g[1], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid2ga2", &sprom->txpid2g[2], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid2ga3", &sprom->txpid2g[3], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5ga0", &sprom->txpid5g[0], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5ga1", &sprom->txpid5g[1], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5ga2", &sprom->txpid5g[2], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5ga3", &sprom->txpid5g[3], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0,
+ fallback);
+}
+
+static void bcm47xx_fill_sprom_r89(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u8(prefix, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "extpagain2g",
+ &sprom->fem.ghz2.extpa_gain, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pdetrange2g",
+ &sprom->fem.ghz2.pdet_range, 0, fallback);
+ nvram_read_u8(prefix, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "extpagain5g",
+ &sprom->fem.ghz5.extpa_gain, 0, fallback);
+ nvram_read_u8(prefix, NULL, "pdetrange5g",
+ &sprom->fem.ghz5.pdet_range, 0, fallback);
+ nvram_read_u8(prefix, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tempthresh", &sprom->tempthresh, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tempoffset", &sprom->tempoffset, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "rawtempsense", &sprom->rawtempsense, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "measpower", &sprom->measpower, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tempsense_slope",
+ &sprom->tempsense_slope, 0, fallback);
+ nvram_read_u8(prefix, NULL, "tempcorrx", &sprom->tempcorrx, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "tempsense_option",
+ &sprom->tempsense_option, 0, fallback);
+ nvram_read_u8(prefix, NULL, "freqoffset_corr",
+ &sprom->freqoffset_corr, 0, fallback);
+ nvram_read_u8(prefix, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "elna2g", &sprom->elna2g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "elna5g", &sprom->elna5g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "phycal_tempdelta",
+ &sprom->phycal_tempdelta, 0, fallback);
+ nvram_read_u8(prefix, NULL, "temps_period", &sprom->temps_period, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "temps_hysteresis",
+ &sprom->temps_hysteresis, 0, fallback);
+ nvram_read_u8(prefix, NULL, "measpower1", &sprom->measpower1, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "measpower2", &sprom->measpower2, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr2ga0",
+ &sprom->rxgainerr2ga[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr2ga1",
+ &sprom->rxgainerr2ga[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr2ga2",
+ &sprom->rxgainerr2ga[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gla0",
+ &sprom->rxgainerr5gla[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gla1",
+ &sprom->rxgainerr5gla[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gla2",
+ &sprom->rxgainerr5gla[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gma0",
+ &sprom->rxgainerr5gma[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gma1",
+ &sprom->rxgainerr5gma[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gma2",
+ &sprom->rxgainerr5gma[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gha0",
+ &sprom->rxgainerr5gha[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gha1",
+ &sprom->rxgainerr5gha[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gha2",
+ &sprom->rxgainerr5gha[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gua0",
+ &sprom->rxgainerr5gua[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gua1",
+ &sprom->rxgainerr5gua[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "rxgainerr5gua2",
+ &sprom->rxgainerr5gua[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gla0",
+ &sprom->noiselvl5gla[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gla1",
+ &sprom->noiselvl5gla[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gla2",
+ &sprom->noiselvl5gla[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gma0",
+ &sprom->noiselvl5gma[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gma1",
+ &sprom->noiselvl5gma[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gma2",
+ &sprom->noiselvl5gma[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gha0",
+ &sprom->noiselvl5gha[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gha1",
+ &sprom->noiselvl5gha[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gha2",
+ &sprom->noiselvl5gha[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gua0",
+ &sprom->noiselvl5gua[0], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gua1",
+ &sprom->noiselvl5gua[1], 0, fallback);
+ nvram_read_u8(prefix, NULL, "noiselvl5gua2",
+ &sprom->noiselvl5gua[2], 0, fallback);
+ nvram_read_u8(prefix, NULL, "pcieingress_war",
+ &sprom->pcieingress_war, 0, fallback);
+}
+
+static void bcm47xx_fill_sprom_r9(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw202gpo",
+ &sprom->legofdmbw202gpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw20ul2gpo",
+ &sprom->legofdmbw20ul2gpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw205glpo",
+ &sprom->legofdmbw205glpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw20ul5glpo",
+ &sprom->legofdmbw20ul5glpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw205gmpo",
+ &sprom->legofdmbw205gmpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw20ul5gmpo",
+ &sprom->legofdmbw20ul5gmpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw205ghpo",
+ &sprom->legofdmbw205ghpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "legofdmbw20ul5ghpo",
+ &sprom->legofdmbw20ul5ghpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw20ul5glpo",
+ &sprom->mcsbw20ul5glpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw20ul5gmpo",
+ &sprom->mcsbw20ul5gmpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0,
+ fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw20ul5ghpo",
+ &sprom->mcsbw20ul5ghpo, 0, fallback);
+ nvram_read_u32(prefix, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "mcs32po", &sprom->mcs32po, 0, fallback);
+ nvram_read_u16(prefix, NULL, "legofdm40duppo",
+ &sprom->legofdm40duppo, 0, fallback);
+ nvram_read_u8(prefix, NULL, "sar2g", &sprom->sar2g, 0, fallback);
+ nvram_read_u8(prefix, NULL, "sar5g", &sprom->sar5g, 0, fallback);
+}
+
+static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ char postfix[2];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+ struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ snprintf(postfix, sizeof(postfix), "%i", i);
+ nvram_read_u8(prefix, postfix, "maxp2ga",
+ &pwr_info->maxpwr_2g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "itt2ga",
+ &pwr_info->itssi_2g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "itt5ga",
+ &pwr_info->itssi_5g, 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw0a",
+ &pwr_info->pa_2g[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw1a",
+ &pwr_info->pa_2g[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw2a",
+ &pwr_info->pa_2g[2], 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5ga",
+ &pwr_info->maxpwr_5g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5gha",
+ &pwr_info->maxpwr_5gh, 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5gla",
+ &pwr_info->maxpwr_5gl, 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw0a",
+ &pwr_info->pa_5g[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw1a",
+ &pwr_info->pa_5g[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw2a",
+ &pwr_info->pa_5g[2], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw0a",
+ &pwr_info->pa_5gl[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw1a",
+ &pwr_info->pa_5gl[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw2a",
+ &pwr_info->pa_5gl[2], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw0a",
+ &pwr_info->pa_5gh[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw1a",
+ &pwr_info->pa_5gh[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw2a",
+ &pwr_info->pa_5gh[2], 0, fallback);
+ }
+}
+
+static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ char postfix[2];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+ struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ snprintf(postfix, sizeof(postfix), "%i", i);
+ nvram_read_u16(prefix, postfix, "pa2gw3a",
+ &pwr_info->pa_2g[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw3a",
+ &pwr_info->pa_5g[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw3a",
+ &pwr_info->pa_5gl[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw3a",
+ &pwr_info->pa_5gh[3], 0, fallback);
+ }
+}
+
+static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback);
+ nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0,
+ fallback);
+
+ nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback);
+ nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0,
+ fallback);
+
+ nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback);
+ nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);
+}
+
+static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0, true);
+ nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0,
+ fallback);
+ nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0, true);
+ nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo,
+ &sprom->boardflags_hi, fallback);
+ nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo,
+ &sprom->boardflags2_hi, fallback);
+}
+
+void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ bcm47xx_fill_sprom_ethernet(sprom, prefix, fallback);
+ bcm47xx_fill_board_data(sprom, prefix, fallback);
+
+ nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0, fallback);
+
+ switch (sprom->revision) {
+ case 1:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r1(sprom, prefix, fallback);
+ break;
+ case 2:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r2389(sprom, prefix, fallback);
+ break;
+ case 3:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r2389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r3(sprom, prefix, fallback);
+ break;
+ case 4:
+ case 5:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r4589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r458(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r45(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_path_r45(sprom, prefix, fallback);
+ break;
+ case 8:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r2389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r4589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r458(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r89(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback);
+ break;
+ case 9:
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r2389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r4589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r89(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r9(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback);
+ break;
+ default:
+ pr_warn("Unsupported SPROM revision %d detected. Will extract"
+ " v1\n", sprom->revision);
+ sprom->revision = 1;
+ bcm47xx_fill_sprom_r1234589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r12389(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_r1(sprom, prefix, fallback);
+ }
+}
+
+#ifdef CONFIG_BCM47XX_SSB
+void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
+ const char *prefix)
+{
+ nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0,
+ true);
+ if (!boardinfo->vendor)
+ boardinfo->vendor = SSB_BOARDVENDOR_BCM;
+
+ nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0, true);
+}
+#endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
+ const char *prefix)
+{
+ nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0,
+ true);
+ if (!boardinfo->vendor)
+ boardinfo->vendor = SSB_BOARDVENDOR_BCM;
+
+ nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0, true);
+}
+#endif
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 536374dcba7..2c85d9254b5 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -27,10 +27,16 @@
#include <linux/ssb/ssb.h>
#include <asm/time.h>
#include <bcm47xx.h>
+#include <bcm47xx_nvram.h>
+#include <bcm47xx_board.h>
void __init plat_time_init(void)
{
unsigned long hz = 0;
+ u16 chip_id = 0;
+ char buf[10];
+ int len;
+ enum bcm47xx_board board = bcm47xx_board_get();
/*
* Use deterministic values for initial counter interrupt
@@ -43,15 +49,32 @@ void __init plat_time_init(void)
#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ chip_id = bcm47xx_bus.ssb.chip_id;
break;
#endif
#ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA:
hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
+ chip_id = bcm47xx_bus.bcma.bus.chipinfo.id;
break;
#endif
}
+ if (chip_id == 0x5354) {
+ len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
+ if (len >= 0 && !strncmp(buf, "200", 4))
+ hz = 100000000;
+ }
+
+ switch (board) {
+ case BCM47XX_BOARD_ASUS_WL520GC:
+ case BCM47XX_BOARD_ASUS_WL520GU:
+ hz = 100000000;
+ break;
+ default:
+ break;
+ }
+
if (!hz)
hz = 100000000;
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
deleted file mode 100644
index e9f9ec8d443..00000000000
--- a/arch/mips/bcm47xx/wgt634u.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/leds.h>
-#include <linux/mtd/physmap.h>
-#include <linux/ssb/ssb.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/gpio.h>
-#include <asm/mach-bcm47xx/bcm47xx.h>
-
-/* GPIO definitions for the WGT634U */
-#define WGT634U_GPIO_LED 3
-#define WGT634U_GPIO_RESET 2
-#define WGT634U_GPIO_TP1 7
-#define WGT634U_GPIO_TP2 6
-#define WGT634U_GPIO_TP3 5
-#define WGT634U_GPIO_TP4 4
-#define WGT634U_GPIO_TP5 1
-
-static struct gpio_led wgt634u_leds[] = {
- {
- .name = "power",
- .gpio = WGT634U_GPIO_LED,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
-};
-
-static struct gpio_led_platform_data wgt634u_led_data = {
- .num_leds = ARRAY_SIZE(wgt634u_leds),
- .leds = wgt634u_leds,
-};
-
-static struct platform_device wgt634u_gpio_leds = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &wgt634u_led_data,
- }
-};
-
-
-/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U
- firmware. */
-static struct mtd_partition wgt634u_partitions[] = {
- {
- .name = "cfe",
- .offset = 0,
- .size = 0x60000, /* 384k */
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
- .name = "config",
- .offset = 0x60000,
- .size = 0x20000 /* 128k */
- },
- {
- .name = "linux",
- .offset = 0x80000,
- .size = 0x140000 /* 1280k */
- },
- {
- .name = "jffs",
- .offset = 0x1c0000,
- .size = 0x620000 /* 6272k */
- },
- {
- .name = "nvram",
- .offset = 0x7e0000,
- .size = 0x20000 /* 128k */
- },
-};
-
-static struct physmap_flash_data wgt634u_flash_data = {
- .parts = wgt634u_partitions,
- .nr_parts = ARRAY_SIZE(wgt634u_partitions)
-};
-
-static struct resource wgt634u_flash_resource = {
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device wgt634u_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = { .platform_data = &wgt634u_flash_data, },
- .resource = &wgt634u_flash_resource,
- .num_resources = 1,
-};
-
-/* Platform devices */
-static struct platform_device *wgt634u_devices[] __initdata = {
- &wgt634u_flash,
- &wgt634u_gpio_leds,
-};
-
-static irqreturn_t gpio_interrupt(int irq, void *ignored)
-{
- int state;
-
- /* Interrupts are shared, check if the current one is
- a GPIO interrupt. */
- if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
- SSB_CHIPCO_IRQ_GPIO))
- return IRQ_NONE;
-
- state = gpio_get_value(WGT634U_GPIO_RESET);
-
- /* Interrupt are level triggered, revert the interrupt polarity
- to clear the interrupt. */
- gpio_polarity(WGT634U_GPIO_RESET, state);
-
- if (!state) {
- printk(KERN_INFO "Reset button pressed");
- ctrl_alt_del();
- }
-
- return IRQ_HANDLED;
-}
-
-static int __init wgt634u_init(void)
-{
- /* There is no easy way to detect that we are running on a WGT634U
- * machine. Use the MAC address as an heuristic. Netgear Inc. has
- * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
- */
- u8 *et0mac;
-
- if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
- return -ENODEV;
-
- et0mac = bcm47xx_bus.ssb.sprom.et0mac;
-
- if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
- (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
- struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
-
- printk(KERN_INFO "WGT634U machine detected.\n");
-
- if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
- gpio_interrupt, IRQF_SHARED,
- "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
- gpio_direction_input(WGT634U_GPIO_RESET);
- gpio_intmask(WGT634U_GPIO_RESET, 1);
- ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
- SSB_CHIPCO_IRQ_GPIO,
- SSB_CHIPCO_IRQ_GPIO);
- }
-
- wgt634u_flash_data.width = mcore->flash_buswidth;
- wgt634u_flash_resource.start = mcore->flash_window;
- wgt634u_flash_resource.end = mcore->flash_window
- + mcore->flash_window_size
- - 1;
- return platform_add_devices(wgt634u_devices,
- ARRAY_SIZE(wgt634u_devices));
- } else
- return -ENODEV;
-}
-
-module_init(wgt634u_init);
diff --git a/arch/mips/bcm47xx/workarounds.c b/arch/mips/bcm47xx/workarounds.c
new file mode 100644
index 00000000000..e81ce462307
--- /dev/null
+++ b/arch/mips/bcm47xx/workarounds.c
@@ -0,0 +1,31 @@
+#include "bcm47xx_private.h"
+
+#include <linux/gpio.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx.h>
+
+static void __init bcm47xx_workarounds_netgear_wnr3500l(void)
+{
+ const int usb_power = 12;
+ int err;
+
+ err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power");
+ if (err)
+ pr_err("Failed to request USB power gpio: %d\n", err);
+ else
+ gpio_free(usb_power);
+}
+
+void __init bcm47xx_workarounds(void)
+{
+ enum bcm47xx_board board = bcm47xx_board_get();
+
+ switch (board) {
+ case BCM47XX_BOARD_NETGEAR_WNR3500L:
+ bcm47xx_workarounds_netgear_wnr3500l();
+ break;
+ default:
+ /* No workaround(s) needed */
+ break;
+ }
+}