bcm53xx: add support for the PCIe controller

This patch adds support for the PCIe controller
In addition to the PCIe controller a sprom is now provided by a device
tree driver to bcma from some nvram.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@40880 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Hauke Mehrtens 2014-05-29 19:25:40 +00:00
parent 139153ff6c
commit ae61421afa
16 changed files with 2598 additions and 91 deletions

View File

@ -40,6 +40,8 @@ CONFIG_B53=y
# CONFIG_B53_MMAP_DRIVER is not set
# CONFIG_B53_PHY_DRIVER is not set
CONFIG_B53_SRAB_DRIVER=y
CONFIG_BCM47XX_NVRAM=y
CONFIG_BCM53XX_SPROM=y
CONFIG_BCMA=y
CONFIG_BCMA_BLOCKIO=y
CONFIG_BCMA_DEBUG=y
@ -188,6 +190,8 @@ CONFIG_OUTER_CACHE_SYNC=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_PCI=y
CONFIG_PCI_BCMA=y
CONFIG_PCI_DOMAINS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
# CONFIG_PL310_ERRATA_588369 is not set

View File

@ -0,0 +1,270 @@
From bd489dfe8c0d7495645cbc8b8c283217ba816fab Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 4 May 2014 16:35:42 +0200
Subject: [PATCH 02/15] bcm47xx: move the nvram header file into common space
Moving mach-bcm47xx/bcm47xx_nvram.h makes it possible to reuse this
header on the arm bcm47xx (BCM5301X) devices. This way a driver gets
the correct functions to access the nvram depending on the SoC it boots
for.
---
arch/mips/bcm47xx/board.c | 2 +-
arch/mips/bcm47xx/nvram.c | 2 +-
arch/mips/bcm47xx/setup.c | 2 +-
arch/mips/bcm47xx/sprom.c | 2 +-
arch/mips/bcm47xx/time.c | 2 +-
arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 53 ------------------
drivers/net/ethernet/broadcom/b44.c | 8 +--
drivers/net/ethernet/broadcom/bgmac.c | 2 +-
drivers/ssb/driver_chipcommon_pmu.c | 6 +-
include/linux/bcm47xx_nvram.h | 65 ++++++++++++++++++++++
10 files changed, 73 insertions(+), 71 deletions(-)
delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
create mode 100644 include/linux/bcm47xx_nvram.h
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -2,7 +2,7 @@
#include <linux/export.h>
#include <linux/string.h>
#include <bcm47xx_board.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
struct bcm47xx_board_type {
const enum bcm47xx_board board;
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -17,7 +17,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/addrspace.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
static char nvram_buf[NVRAM_SPACE];
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -42,7 +42,7 @@
#include <asm/reboot.h>
#include <asm/time.h>
#include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
#include <bcm47xx_board.h>
union bcm47xx_bus bcm47xx_bus;
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -27,7 +27,7 @@
*/
#include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
static void create_key(const char *prefix, const char *postfix,
const char *name, char *buf, int len)
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -27,7 +27,7 @@
#include <linux/ssb/ssb.h>
#include <asm/time.h>
#include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
#include <bcm47xx_board.h>
void __init plat_time_init(void)
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2005, Broadcom Corporation
- * Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
- *
- * 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.
- */
-
-#ifndef __BCM47XX_NVRAM_H
-#define __BCM47XX_NVRAM_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-struct nvram_header {
- u32 magic;
- u32 len;
- u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
- u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
- u32 config_ncdl; /* ncdl values for memc */
-};
-
-#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
-#define NVRAM_VERSION 1
-#define NVRAM_HEADER_SIZE 20
-#define NVRAM_SPACE 0x8000
-
-#define FLASH_MIN 0x00020000 /* Minimum flash size */
-
-#define NVRAM_MAX_VALUE_LEN 255
-#define NVRAM_MAX_PARAM_LEN 64
-
-extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len);
-
-static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
-{
- if (strchr(buf, ':'))
- sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
- &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
- &macaddr[5]);
- else if (strchr(buf, '-'))
- sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
- &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
- &macaddr[5]);
- else
- printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
-}
-
-int bcm47xx_nvram_gpio_pin(const char *name);
-
-#endif /* __BCM47XX_NVRAM_H */
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -31,6 +31,7 @@
#include <linux/ssb/ssb.h>
#include <linux/slab.h>
#include <linux/phy.h>
+#include <linux/bcm47xx_nvram.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44
__b44_set_flow_ctrl(bp, pause_enab);
}
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
static void b44_wap54g10_workaround(struct b44 *bp)
{
char buf[20];
@@ -429,11 +428,6 @@ static void b44_wap54g10_workaround(stru
error:
pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
}
-#else
-static inline void b44_wap54g10_workaround(struct b44 *bp)
-{
-}
-#endif
static int b44_setup_phy(struct b44 *bp)
{
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/b53.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -13,9 +13,7 @@
#include <linux/ssb/ssb_driver_chipcommon.h>
#include <linux/delay.h>
#include <linux/export.h>
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
-#endif
+#include <linux/bcm47xx_nvram.h>
#include "ssb_private.h"
@@ -320,11 +318,9 @@ static void ssb_pmu_pll_init(struct ssb_
u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
if (bus->bustype == SSB_BUSTYPE_SSB) {
-#ifdef CONFIG_BCM47XX
char buf[20];
if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
crystalfreq = simple_strtoul(buf, NULL, 0);
-#endif
}
switch (bus->chip_id) {
--- /dev/null
+++ b/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2005, Broadcom Corporation
+ * Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef __BCM47XX_NVRAM_H
+#define __BCM47XX_NVRAM_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+struct nvram_header {
+ u32 magic;
+ u32 len;
+ u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+ u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
+ u32 config_ncdl; /* ncdl values for memc */
+};
+
+#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
+#define NVRAM_VERSION 1
+#define NVRAM_HEADER_SIZE 20
+#define NVRAM_SPACE 0x8000
+
+#define FLASH_MIN 0x00020000 /* Minimum flash size */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#ifdef CONFIG_BCM47XX
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+
+int bcm47xx_nvram_gpio_pin(const char *name);
+#else
+static inline int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
+{
+ return -ENXIO;
+}
+
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
+{
+ return -ENXIO;
+}
+#endif
+
+static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+{
+ if (strchr(buf, ':'))
+ sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else if (strchr(buf, '-'))
+ sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else
+ pr_warn("Can not parse mac address: %s\n", buf);
+}
+#endif /* __BCM47XX_NVRAM_H */

View File

@ -0,0 +1,520 @@
From 60a413ed5bc7917f1612df441240f458163b10c1 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 3 May 2014 22:54:59 +0200
Subject: [PATCH 03/15] bcm47xx-nvram: add new nvram driver with dt support
This adds a new nvrm driver which uses device tree to provide nvram
access to other drivers. You have to specify the memory ranges where
the flash chip is mapped and this driver will search there for some
nvram and parse it. Other drivers can use this driver to access the
device nvram. The nvram is used to store board configurations like the
mac address and also for configuration values in the vendor firmware.
---
arch/mips/bcm47xx/board.c | 36 +++---
arch/mips/bcm47xx/nvram.c | 7 +-
arch/mips/bcm47xx/setup.c | 4 +-
arch/mips/bcm47xx/sprom.c | 4 +-
arch/mips/bcm47xx/time.c | 2 +-
drivers/misc/Kconfig | 5 +
drivers/misc/Makefile | 1 +
drivers/misc/bcm47xx-nvram.c | 211 ++++++++++++++++++++++++++++++++++
drivers/net/ethernet/broadcom/b44.c | 2 +-
drivers/net/ethernet/broadcom/bgmac.c | 4 +-
drivers/ssb/driver_chipcommon_pmu.c | 2 +-
include/linux/bcm47xx_nvram.h | 16 ++-
12 files changed, 259 insertions(+), 35 deletions(-)
create mode 100644 drivers/misc/bcm47xx-nvram.c
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -196,50 +196,50 @@ static __init const struct bcm47xx_board
const struct bcm47xx_board_type_list2 *e2;
const struct bcm47xx_board_type_list3 *e3;
- if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "melco_id", buf1, sizeof(buf1)) >= 0 ||
+ bcm47xx_nvram_getenv(NULL, "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))
@@ -247,8 +247,8 @@ static __init const struct bcm47xx_board
}
}
- if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
- bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+ if (bcm47xx_nvram_getenv(NULL, "boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv(NULL, "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))
@@ -256,16 +256,16 @@ static __init const struct bcm47xx_board
}
}
- if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
+ if (bcm47xx_nvram_getenv(NULL, "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) {
+ if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv(NULL, "boardnum", buf2, sizeof(buf2)) >= 0 &&
+ bcm47xx_nvram_getenv(NULL, "boardrev", buf3, sizeof(buf3)) >= 0) {
for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
if (!strcmp(buf1, e3->value1) &&
!strcmp(buf2, e3->value2) &&
@@ -286,7 +286,7 @@ void __init bcm47xx_board_detect(void)
return;
/* check if the nvram is available */
- err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+ err = bcm47xx_nvram_getenv(NULL, "boardtype", buf, sizeof(buf));
/* init of nvram failed, probably too early now */
if (err == -ENXIO) {
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -158,7 +158,8 @@ static int nvram_init(void)
return -ENXIO;
}
-int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+ size_t val_len)
{
char *var, *value, *end, *eq;
int err;
@@ -190,7 +191,7 @@ int bcm47xx_nvram_getenv(char *name, cha
}
EXPORT_SYMBOL(bcm47xx_nvram_getenv);
-int bcm47xx_nvram_gpio_pin(const char *name)
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
{
int i, err;
char nvram_var[10];
@@ -200,7 +201,7 @@ int bcm47xx_nvram_gpio_pin(const char *n
err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
if (err <= 0)
continue;
- err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+ err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
if (err <= 0)
continue;
if (!strcmp(name, buf))
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -123,7 +123,7 @@ static int bcm47xx_get_invariants(struct
memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom(&iv->sprom, NULL, false);
- if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+ if (bcm47xx_nvram_getenv(NULL, "cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
return 0;
@@ -146,7 +146,7 @@ static void __init bcm47xx_register_ssb(
panic("Failed to initialize SSB bus (err %d)", err);
mcore = &bcm47xx_bus.ssb.mipscore;
- if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+ if (bcm47xx_nvram_getenv(NULL, "kernel_args", buf, sizeof(buf)) >= 0) {
if (strstr(buf, "console=ttyS1")) {
struct ssb_serial_port port;
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -50,10 +50,10 @@ static int get_nvram_var(const char *pre
create_key(prefix, postfix, name, key, sizeof(key));
- err = bcm47xx_nvram_getenv(key, buf, len);
+ err = bcm47xx_nvram_getenv(NULL, key, buf, len);
if (fallback && err == -ENOENT && prefix) {
create_key(NULL, postfix, name, key, sizeof(key));
- err = bcm47xx_nvram_getenv(key, buf, len);
+ err = bcm47xx_nvram_getenv(NULL, key, buf, len);
}
return err;
}
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -61,7 +61,7 @@ void __init plat_time_init(void)
}
if (chip_id == 0x5354) {
- len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
+ len = bcm47xx_nvram_getenv(NULL, "clkfreq", buf, sizeof(buf));
if (len >= 0 && !strncmp(buf, "200", 4))
hz = 100000000;
}
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,11 @@ config SRAM
the genalloc API. It is supposed to be used for small on-chip SRAM
areas found on many SoCs.
+config BCM47XX_NVRAM
+ tristate "BCM47XX nvram driver"
+ help
+ This adds support for the brcm47xx nvram driver.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lat
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
+obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx-nvram.o
--- /dev/null
+++ b/drivers/misc/bcm47xx-nvram.c
@@ -0,0 +1,211 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 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.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bcm47xx_nvram.h>
+
+struct bcm47xx_nvram {
+ size_t nvram_len;
+ char *nvram_buf;
+};
+
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+ struct nvram_header *header;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+ header = (struct nvram_header *)(end - nvram_sizes[i]);
+ if (header->magic == NVRAM_HEADER)
+ return nvram_sizes[i];
+ }
+
+ return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(struct device *dev, void __iomem *base,
+ size_t len, char **nvram_buf,
+ size_t *nvram_len)
+{
+ struct nvram_header *header;
+ int i;
+ u32 off;
+ u32 *src, *dst;
+ u32 size;
+
+ /* TODO: when nvram is on nand flash check for bad blocks first. */
+ off = FLASH_MIN;
+ while (off <= len) {
+ /* Windowed flash access */
+ size = find_nvram_size(base + off);
+ if (size) {
+ header = (struct nvram_header *)(base + off - size);
+ goto found;
+ }
+ off <<= 1;
+ }
+
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+ header = (struct nvram_header *)(base + 4096);
+ if (header->magic == NVRAM_HEADER) {
+ size = NVRAM_SPACE;
+ goto found;
+ }
+
+ header = (struct nvram_header *)(base + 1024);
+ if (header->magic == NVRAM_HEADER) {
+ size = NVRAM_SPACE;
+ goto found;
+ }
+
+ *nvram_buf = NULL;
+ *nvram_len = 0;
+ 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");
+ *nvram_len = min_t(u32, header->len, size);
+
+ *nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
+ if (!*nvram_buf)
+ return -ENOMEM;
+
+ src = (u32 *) header;
+ dst = (u32 *) *nvram_buf;
+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
+ *dst++ = *src++;
+ for (; i < *nvram_len; i += 4)
+ *dst++ = le32_to_cpu(*src++);
+
+ return 0;
+}
+
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val, size_t val_len)
+{
+ char *var, *value, *end, *eq;
+ struct bcm47xx_nvram *nvram;
+
+ if (!dev)
+ return -ENODEV;
+
+ nvram = dev_get_drvdata(dev);
+
+ if (!name || !nvram || !nvram->nvram_len)
+ return -EINVAL;
+
+ /* Look for name=value and return value */
+ var = nvram->nvram_buf + sizeof(struct nvram_header);
+ end = nvram->nvram_buf + nvram->nvram_len - 2;
+ end[0] = end[1] = '\0';
+ for (; *var; var = value + strlen(value) + 1) {
+ eq = strchr(var, '=');
+ if (!eq)
+ break;
+ value = eq + 1;
+ if ((eq - var) == strlen(name) &&
+ strncmp(var, name, (eq - var)) == 0) {
+ return snprintf(val, val_len, "%s", value);
+ }
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
+{
+ int i, err;
+ char nvram_var[10];
+ char buf[30];
+
+ if (!dev)
+ return -ENODEV;
+
+ for (i = 0; i < 32; i++) {
+ err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+ if (err <= 0)
+ continue;
+ err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
+ if (err <= 0)
+ continue;
+ if (!strcmp(name, buf))
+ return i;
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+static int bcm47xx_nvram_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct bcm47xx_nvram *nvram;
+ int err;
+ struct resource flash_mem;
+ void __iomem *mmio;
+
+ /* Alloc */
+ nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+ if (!nvram)
+ return -ENOMEM;
+
+ err = of_address_to_resource(np, 0, &flash_mem);
+ if (err)
+ return err;
+
+ mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
+ if (!mmio)
+ return -ENOMEM;
+
+ err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem), &nvram->nvram_buf, &nvram->nvram_len);
+ if (err)
+ goto err_unmap_mmio;
+
+ platform_set_drvdata(pdev, nvram);
+
+err_unmap_mmio:
+ iounmap(mmio);
+ return err;
+}
+
+static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
+ { .compatible = "brcm,bcm47xx-nvram", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_nvram_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bcm47xx-nvram",
+ .of_match_table = bcm47xx_nvram_of_match_table,
+ /* driver unloading/unbinding currently not supported */
+ .suppress_bind_attrs = true,
+ },
+ .probe = bcm47xx_nvram_probe,
+};
+module_platform_driver(bcm47xx_nvram_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPLv2");
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -411,7 +411,7 @@ static void b44_wap54g10_workaround(stru
* see https://dev.openwrt.org/ticket/146
* check and reset bit "isolate"
*/
- if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
+ if (bcm47xx_nvram_getenv(NULL, "boardnum", buf, sizeof(buf)) < 0)
return;
if (simple_strtoul(buf, NULL, 0) == 2) {
err = __b44_readphy(bp, 0, MII_BMCR, &val);
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -974,7 +974,7 @@ static void bgmac_chip_reset(struct bgma
BGMAC_CHIPCTL_1_IF_TYPE_MII;
char buf[4];
- if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
+ if (bcm47xx_nvram_getenv(NULL, "et_swtype", buf, sizeof(buf)) > 0) {
if (kstrtou8(buf, 0, &et_swtype))
bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
buf);
@@ -1534,7 +1534,7 @@ static int bgmac_probe(struct bcma_devic
}
bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
- if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+ if (bcm47xx_nvram_getenv(NULL, "et0_no_txint", NULL, 0) == 0)
bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
/* TODO: reset the external phy. Specs are needed */
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -319,7 +319,7 @@ static void ssb_pmu_pll_init(struct ssb_
if (bus->bustype == SSB_BUSTYPE_SSB) {
char buf[20];
- if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
+ if (bcm47xx_nvram_getenv(NULL, "xtalfreq", buf, sizeof(buf)) >= 0)
crystalfreq = simple_strtoul(buf, NULL, 0);
}
--- a/include/linux/bcm47xx_nvram.h
+++ b/include/linux/bcm47xx_nvram.h
@@ -15,6 +15,8 @@
#include <linux/types.h>
#include <linux/kernel.h>
+struct device;
+
struct nvram_header {
u32 magic;
u32 len;
@@ -33,17 +35,21 @@ struct nvram_header {
#define NVRAM_MAX_VALUE_LEN 255
#define NVRAM_MAX_PARAM_LEN 64
-#ifdef CONFIG_BCM47XX
-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+#if defined(CONFIG_BCM47XX) || defined(CONFIG_BCM47XX_NVRAM)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+ size_t val_len);
-int bcm47xx_nvram_gpio_pin(const char *name);
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name);
#else
-static inline int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
+static inline int bcm47xx_nvram_getenv(const struct device *dev,
+ const char *name, char *val,
+ size_t val_len)
{
return -ENXIO;
}
-static inline int bcm47xx_nvram_gpio_pin(const char *name)
+static inline int bcm47xx_nvram_gpio_pin(const struct device *dev,
+ const char *name)
{
return -ENXIO;
}

View File

@ -0,0 +1,667 @@
From b113f9d3e140f18e63cbf3408b3dcde372242dc8 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 4 May 2014 13:19:20 +0200
Subject: [PATCH 04/15] bcm53xx-sprom: add sprom driver
This driver needs an nvram driver and fetches the sprom values from the
sprom and provides it to any other driver. The calibration data for the
wifi chip the mac address and some more board description data is
stores in the sprom.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/misc/Kconfig | 5 +
drivers/misc/Makefile | 1 +
drivers/misc/bcm53xx-sprom.c | 625 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 631 insertions(+)
create mode 100644 drivers/misc/bcm53xx-sprom.c
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -520,6 +520,11 @@ config BCM47XX_NVRAM
help
This adds support for the brcm47xx nvram driver.
+config BCM53XX_SPROM
+ tristate "BCM53XX sprom driver"
+ help
+ This adds support for the brcm53xx sprom driver.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx-nvram.o
+obj-$(CONFIG_BCM53XX_SPROM) += bcm53xx-sprom.o
--- /dev/null
+++ b/drivers/misc/bcm53xx-sprom.c
@@ -0,0 +1,625 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 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.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/bcm47xx_nvram.h>
+
+struct bcm53xx_sprom_fill {
+ const char *prefix;
+ bool fallback;
+ int (*getenv)(const struct bcm53xx_sprom_fill *fill, const char *name, char *val, size_t val_len);
+ const void *priv;
+};
+
+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 struct bcm53xx_sprom_fill *fill, const char *postfix,
+ const char *name, char *buf, int len)
+{
+ char key[40];
+ int err;
+
+ create_key(fill->prefix, postfix, name, key, sizeof(key));
+
+ err = fill->getenv(fill, key, buf, len);
+ if (fill->fallback && err == -ENOENT && fill->prefix) {
+ create_key(NULL, postfix, name, key, sizeof(key));
+ err = fill->getenv(fill, key, buf, len);
+ }
+ return err;
+}
+
+#define NVRAM_READ_VAL(type) \
+static void nvram_read_ ## type (const struct bcm53xx_sprom_fill *fill, \
+ const char *postfix, const char *name, \
+ type *val, type allset) \
+{ \
+ char buf[100]; \
+ int err; \
+ type var; \
+ \
+ err = get_nvram_var(fill, postfix, name, buf, sizeof(buf)); \
+ 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", \
+ fill->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 struct bcm53xx_sprom_fill *fill, const char *name,
+ u16 *val_lo, u16 *val_hi)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+ 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",
+ fill->prefix, name, buf, err);
+ return;
+ }
+ *val_lo = (val & 0x0000FFFFU);
+ *val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const struct bcm53xx_sprom_fill *fill, const char *name,
+ u8 *leddc_on_time, u8 *leddc_off_time)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+ 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",
+ fill->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 struct bcm53xx_sprom_fill *fill, const char *name,
+ u8 val[6])
+{
+ char buf[100];
+ int err;
+
+ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+ if (err < 0)
+ return;
+
+ bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const struct bcm53xx_sprom_fill *fill, const char *name,
+ char val[2])
+{
+ char buf[10];
+ int err;
+
+ err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+ 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 bcm53xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
+ nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
+ nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
+ nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
+ nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
+ nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
+ nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
+ nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
+ nvram_read_alpha2(fill, "ccode", sprom->alpha2);
+}
+
+static void bcm53xx_sprom_fill_r12389(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u16(fill, NULL, "pa0b0", &sprom->pa0b0, 0);
+ nvram_read_u16(fill, NULL, "pa0b1", &sprom->pa0b1, 0);
+ nvram_read_u16(fill, NULL, "pa0b2", &sprom->pa0b2, 0);
+ nvram_read_u8(fill, NULL, "pa0itssit", &sprom->itssi_bg, 0);
+ nvram_read_u8(fill, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
+ nvram_read_u16(fill, NULL, "pa1b0", &sprom->pa1b0, 0);
+ nvram_read_u16(fill, NULL, "pa1b1", &sprom->pa1b1, 0);
+ nvram_read_u16(fill, NULL, "pa1b2", &sprom->pa1b2, 0);
+ nvram_read_u8(fill, NULL, "pa1itssit", &sprom->itssi_a, 0);
+ nvram_read_u8(fill, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
+}
+
+static void bcm53xx_sprom_fill_r1(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u16(fill, NULL, "boardflags", &sprom->boardflags_lo, 0);
+ nvram_read_u8(fill, NULL, "cc", &sprom->country_code, 0);
+}
+
+static void bcm53xx_sprom_fill_r2389(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "opo", &sprom->opo, 0);
+ nvram_read_u16(fill, NULL, "pa1lob0", &sprom->pa1lob0, 0);
+ nvram_read_u16(fill, NULL, "pa1lob1", &sprom->pa1lob1, 0);
+ nvram_read_u16(fill, NULL, "pa1lob2", &sprom->pa1lob2, 0);
+ nvram_read_u16(fill, NULL, "pa1hib0", &sprom->pa1hib0, 0);
+ nvram_read_u16(fill, NULL, "pa1hib1", &sprom->pa1hib1, 0);
+ nvram_read_u16(fill, NULL, "pa1hib2", &sprom->pa1hib2, 0);
+ nvram_read_u8(fill, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
+ nvram_read_u8(fill, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
+}
+
+static void bcm53xx_sprom_fill_r389(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "bxa2g", &sprom->bxa2g, 0);
+ nvram_read_u8(fill, NULL, "rssisav2g", &sprom->rssisav2g, 0);
+ nvram_read_u8(fill, NULL, "rssismc2g", &sprom->rssismc2g, 0);
+ nvram_read_u8(fill, NULL, "rssismf2g", &sprom->rssismf2g, 0);
+ nvram_read_u8(fill, NULL, "bxa5g", &sprom->bxa5g, 0);
+ nvram_read_u8(fill, NULL, "rssisav5g", &sprom->rssisav5g, 0);
+ nvram_read_u8(fill, NULL, "rssismc5g", &sprom->rssismc5g, 0);
+ nvram_read_u8(fill, NULL, "rssismf5g", &sprom->rssismf5g, 0);
+ nvram_read_u8(fill, NULL, "tri2g", &sprom->tri2g, 0);
+ nvram_read_u8(fill, NULL, "tri5g", &sprom->tri5g, 0);
+ nvram_read_u8(fill, NULL, "tri5gl", &sprom->tri5gl, 0);
+ nvram_read_u8(fill, NULL, "tri5gh", &sprom->tri5gh, 0);
+ nvram_read_s8(fill, NULL, "rxpo2g", &sprom->rxpo2g, 0);
+ nvram_read_s8(fill, NULL, "rxpo5g", &sprom->rxpo5g, 0);
+}
+
+static void bcm53xx_sprom_fill_r3(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+ nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+ &sprom->leddc_off_time);
+}
+
+static void bcm53xx_sprom_fill_r4589(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+ nvram_read_s8(fill, NULL, "ag2", &sprom->antenna_gain.a2, 0);
+ nvram_read_s8(fill, NULL, "ag3", &sprom->antenna_gain.a3, 0);
+ nvram_read_u8(fill, NULL, "txchain", &sprom->txchain, 0xf);
+ nvram_read_u8(fill, NULL, "rxchain", &sprom->rxchain, 0xf);
+ nvram_read_u8(fill, NULL, "antswitch", &sprom->antswitch, 0xff);
+ nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+ &sprom->leddc_off_time);
+}
+
+static void bcm53xx_sprom_fill_r458(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u16(fill, NULL, "cck2gpo", &sprom->cck2gpo, 0);
+ nvram_read_u32(fill, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
+ nvram_read_u32(fill, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
+ nvram_read_u32(fill, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
+ nvram_read_u32(fill, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
+ nvram_read_u16(fill, NULL, "cddpo", &sprom->cddpo, 0);
+ nvram_read_u16(fill, NULL, "stbcpo", &sprom->stbcpo, 0);
+ nvram_read_u16(fill, NULL, "bw40po", &sprom->bw40po, 0);
+ nvram_read_u16(fill, NULL, "bwduppo", &sprom->bwduppo, 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
+ nvram_read_u16(fill, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
+ nvram_read_u16(fill, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
+ nvram_read_u16(fill, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
+ nvram_read_u16(fill, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
+}
+
+static void bcm53xx_sprom_fill_r45(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
+ nvram_read_u8(fill, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
+ nvram_read_u8(fill, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
+ nvram_read_u8(fill, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
+ nvram_read_u8(fill, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
+ nvram_read_u8(fill, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
+ nvram_read_u8(fill, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
+ nvram_read_u8(fill, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
+ nvram_read_u8(fill, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
+ nvram_read_u8(fill, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
+ nvram_read_u8(fill, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
+ nvram_read_u8(fill, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
+ nvram_read_u8(fill, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
+ nvram_read_u8(fill, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
+ nvram_read_u8(fill, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
+ nvram_read_u8(fill, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
+}
+
+static void bcm53xx_sprom_fill_r89(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u8(fill, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
+ nvram_read_u8(fill, NULL, "extpagain2g", &sprom->fem.ghz2.extpa_gain, 0);
+ nvram_read_u8(fill, NULL, "pdetrange2g", &sprom->fem.ghz2.pdet_range, 0);
+ nvram_read_u8(fill, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
+ nvram_read_u8(fill, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
+ nvram_read_u8(fill, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
+ nvram_read_u8(fill, NULL, "extpagain5g", &sprom->fem.ghz5.extpa_gain, 0);
+ nvram_read_u8(fill, NULL, "pdetrange5g", &sprom->fem.ghz5.pdet_range, 0);
+ nvram_read_u8(fill, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
+ nvram_read_u8(fill, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
+ nvram_read_u8(fill, NULL, "tempthresh", &sprom->tempthresh, 0);
+ nvram_read_u8(fill, NULL, "tempoffset", &sprom->tempoffset, 0);
+ nvram_read_u16(fill, NULL, "rawtempsense", &sprom->rawtempsense, 0);
+ nvram_read_u8(fill, NULL, "measpower", &sprom->measpower, 0);
+ nvram_read_u8(fill, NULL, "tempsense_slope", &sprom->tempsense_slope, 0);
+ nvram_read_u8(fill, NULL, "tempcorrx", &sprom->tempcorrx, 0);
+ nvram_read_u8(fill, NULL, "tempsense_option", &sprom->tempsense_option, 0);
+ nvram_read_u8(fill, NULL, "freqoffset_corr", &sprom->freqoffset_corr, 0);
+ nvram_read_u8(fill, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
+ nvram_read_u8(fill, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
+ nvram_read_u8(fill, NULL, "elna2g", &sprom->elna2g, 0);
+ nvram_read_u8(fill, NULL, "elna5g", &sprom->elna5g, 0);
+ nvram_read_u8(fill, NULL, "phycal_tempdelta", &sprom->phycal_tempdelta, 0);
+ nvram_read_u8(fill, NULL, "temps_period", &sprom->temps_period, 0);
+ nvram_read_u8(fill, NULL, "temps_hysteresis", &sprom->temps_hysteresis, 0);
+ nvram_read_u8(fill, NULL, "measpower1", &sprom->measpower1, 0);
+ nvram_read_u8(fill, NULL, "measpower2", &sprom->measpower2, 0);
+ nvram_read_u8(fill, NULL, "rxgainerr2ga0", &sprom->rxgainerr2ga[0], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr2ga1", &sprom->rxgainerr2ga[1], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr2ga2", &sprom->rxgainerr2ga[2], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gla0", &sprom->rxgainerr5gla[0], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gla1", &sprom->rxgainerr5gla[1], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gla2", &sprom->rxgainerr5gla[2], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gma0", &sprom->rxgainerr5gma[0], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gma1", &sprom->rxgainerr5gma[1], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gma2", &sprom->rxgainerr5gma[2], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gha0", &sprom->rxgainerr5gha[0], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gha1", &sprom->rxgainerr5gha[1], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gha2", &sprom->rxgainerr5gha[2], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gua0", &sprom->rxgainerr5gua[0], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gua1", &sprom->rxgainerr5gua[1], 0);
+ nvram_read_u8(fill, NULL, "rxgainerr5gua2", &sprom->rxgainerr5gua[2], 0);
+ nvram_read_u8(fill, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
+ nvram_read_u8(fill, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
+ nvram_read_u8(fill, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gla0", &sprom->noiselvl5gla[0], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gla1", &sprom->noiselvl5gla[1], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gla2", &sprom->noiselvl5gla[2], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gma0", &sprom->noiselvl5gma[0], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gma1", &sprom->noiselvl5gma[1], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gma2", &sprom->noiselvl5gma[2], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gha0", &sprom->noiselvl5gha[0], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gha1", &sprom->noiselvl5gha[1], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gha2", &sprom->noiselvl5gha[2], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gua0", &sprom->noiselvl5gua[0], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gua1", &sprom->noiselvl5gua[1], 0);
+ nvram_read_u8(fill, NULL, "noiselvl5gua2", &sprom->noiselvl5gua[2], 0);
+ nvram_read_u8(fill, NULL, "pcieingress_war", &sprom->pcieingress_war, 0);
+}
+
+static void bcm53xx_sprom_fill_r9(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u16(fill, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
+ nvram_read_u16(fill, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw202gpo", &sprom->legofdmbw202gpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw20ul2gpo", &sprom->legofdmbw20ul2gpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw205glpo", &sprom->legofdmbw205glpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw20ul5glpo", &sprom->legofdmbw20ul5glpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw205gmpo", &sprom->legofdmbw205gmpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw20ul5gmpo", &sprom->legofdmbw20ul5gmpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw205ghpo", &sprom->legofdmbw205ghpo, 0);
+ nvram_read_u32(fill, NULL, "legofdmbw20ul5ghpo", &sprom->legofdmbw20ul5ghpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw20ul5glpo", &sprom->mcsbw20ul5glpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw20ul5gmpo", &sprom->mcsbw20ul5gmpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw20ul5ghpo", &sprom->mcsbw20ul5ghpo, 0);
+ nvram_read_u32(fill, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
+ nvram_read_u16(fill, NULL, "mcs32po", &sprom->mcs32po, 0);
+ nvram_read_u16(fill, NULL, "legofdm40duppo", &sprom->legofdm40duppo, 0);
+ nvram_read_u8(fill, NULL, "sar2g", &sprom->sar2g, 0);
+ nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+}
+
+static void bcm53xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ 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(fill, postfix, "maxp2ga", &pwr_info->maxpwr_2g, 0);
+ nvram_read_u8(fill, postfix, "itt2ga", &pwr_info->itssi_2g, 0);
+ nvram_read_u8(fill, postfix, "itt5ga", &pwr_info->itssi_5g, 0);
+ nvram_read_u16(fill, postfix, "pa2gw0a", &pwr_info->pa_2g[0], 0);
+ nvram_read_u16(fill, postfix, "pa2gw1a", &pwr_info->pa_2g[1], 0);
+ nvram_read_u16(fill, postfix, "pa2gw2a", &pwr_info->pa_2g[2], 0);
+ nvram_read_u8(fill, postfix, "maxp5ga", &pwr_info->maxpwr_5g, 0);
+ nvram_read_u8(fill, postfix, "maxp5gha", &pwr_info->maxpwr_5gh, 0);
+ nvram_read_u8(fill, postfix, "maxp5gla", &pwr_info->maxpwr_5gl, 0);
+ nvram_read_u16(fill, postfix, "pa5gw0a", &pwr_info->pa_5g[0], 0);
+ nvram_read_u16(fill, postfix, "pa5gw1a", &pwr_info->pa_5g[1], 0);
+ nvram_read_u16(fill, postfix, "pa5gw2a", &pwr_info->pa_5g[2], 0);
+ nvram_read_u16(fill, postfix, "pa5glw0a", &pwr_info->pa_5gl[0], 0);
+ nvram_read_u16(fill, postfix, "pa5glw1a", &pwr_info->pa_5gl[1], 0);
+ nvram_read_u16(fill, postfix, "pa5glw2a", &pwr_info->pa_5gl[2], 0);
+ nvram_read_u16(fill, postfix, "pa5ghw0a", &pwr_info->pa_5gh[0], 0);
+ nvram_read_u16(fill, postfix, "pa5ghw1a", &pwr_info->pa_5gh[1], 0);
+ nvram_read_u16(fill, postfix, "pa5ghw2a", &pwr_info->pa_5gh[2], 0);
+ }
+}
+
+static void bcm53xx_sprom_fill_path_r45(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ 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(fill, postfix, "pa2gw3a", &pwr_info->pa_2g[3], 0);
+ nvram_read_u16(fill, postfix, "pa5gw3a", &pwr_info->pa_5g[3], 0);
+ nvram_read_u16(fill, postfix, "pa5glw3a", &pwr_info->pa_5gl[3], 0);
+ nvram_read_u16(fill, postfix, "pa5ghw3a", &pwr_info->pa_5gh[3], 0);
+ }
+}
+
+static void bcm53xx_sprom_fill_ethernet(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_macaddr(fill, "et0macaddr", sprom->et0mac);
+ nvram_read_u8(fill, NULL, "et0mdcport", &sprom->et0mdcport, 0);
+ nvram_read_u8(fill, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
+
+ nvram_read_macaddr(fill, "et1macaddr", sprom->et1mac);
+ nvram_read_u8(fill, NULL, "et1mdcport", &sprom->et1mdcport, 0);
+ nvram_read_u8(fill, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
+
+ nvram_read_macaddr(fill, "macaddr", sprom->il0mac);
+ nvram_read_macaddr(fill, "il0macaddr", sprom->il0mac);
+}
+
+static void bcm53xx_sprom_fill_board_data(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ nvram_read_u16(fill, NULL, "boardrev", &sprom->board_rev, 0);
+ nvram_read_u16(fill, NULL, "boardnum", &sprom->board_num, 0);
+ nvram_read_u16(fill, NULL, "boardtype", &sprom->board_type, 0);
+ nvram_read_u32_2(fill, "boardflags", &sprom->boardflags_lo,
+ &sprom->boardflags_hi);
+ nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+ &sprom->boardflags2_hi);
+}
+
+static void bcm53xx_sprom_fill(struct ssb_sprom *sprom,
+ const struct bcm53xx_sprom_fill *fill)
+{
+ bcm53xx_sprom_fill_ethernet(sprom, fill);
+ bcm53xx_sprom_fill_board_data(sprom, fill);
+
+ nvram_read_u8(fill, NULL, "sromrev", &sprom->revision, 0);
+
+ switch (sprom->revision) {
+ case 1:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r1(sprom, fill);
+ break;
+ case 2:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r2389(sprom, fill);
+ break;
+ case 3:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r2389(sprom, fill);
+ bcm53xx_sprom_fill_r389(sprom, fill);
+ bcm53xx_sprom_fill_r3(sprom, fill);
+ break;
+ case 4:
+ case 5:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r4589(sprom, fill);
+ bcm53xx_sprom_fill_r458(sprom, fill);
+ bcm53xx_sprom_fill_r45(sprom, fill);
+ bcm53xx_sprom_fill_path_r4589(sprom, fill);
+ bcm53xx_sprom_fill_path_r45(sprom, fill);
+ break;
+ case 8:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r2389(sprom, fill);
+ bcm53xx_sprom_fill_r389(sprom, fill);
+ bcm53xx_sprom_fill_r4589(sprom, fill);
+ bcm53xx_sprom_fill_r458(sprom, fill);
+ bcm53xx_sprom_fill_r89(sprom, fill);
+ bcm53xx_sprom_fill_path_r4589(sprom, fill);
+ break;
+ case 9:
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r2389(sprom, fill);
+ bcm53xx_sprom_fill_r389(sprom, fill);
+ bcm53xx_sprom_fill_r4589(sprom, fill);
+ bcm53xx_sprom_fill_r89(sprom, fill);
+ bcm53xx_sprom_fill_r9(sprom, fill);
+ bcm53xx_sprom_fill_path_r4589(sprom, fill);
+ break;
+ default:
+ pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+ sprom->revision);
+ sprom->revision = 1;
+ bcm53xx_sprom_fill_r1234589(sprom, fill);
+ bcm53xx_sprom_fill_r12389(sprom, fill);
+ bcm53xx_sprom_fill_r1(sprom, fill);
+ }
+}
+
+static int bcm53xx_sprom_getenv(const struct bcm53xx_sprom_fill *fill,
+ const char *name, char *val, size_t val_len)
+{
+ const struct platform_device *nvram_dev = fill->priv;
+
+ return bcm47xx_nvram_getenv(&nvram_dev->dev, name, val, val_len);
+};
+
+static int bcm53xx_sprom_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ssb_sprom *sprom;
+ const phandle *handle;
+ struct device_node *nvram_node;
+ struct platform_device *nvram_dev;
+ struct bcm53xx_sprom_fill fill;
+
+ /* Alloc */
+ sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
+ if (!sprom)
+ return -ENOMEM;
+
+ handle = of_get_property(np, "nvram", NULL);
+ if (!handle)
+ return -ENOMEM;
+
+ nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
+ if (!nvram_node)
+ return -ENOMEM;
+
+ nvram_dev = of_find_device_by_node(nvram_node);
+ if (!nvram_dev)
+ return -ENOMEM;
+
+ fill.prefix = NULL;
+ fill.fallback = false;
+ fill.getenv = bcm53xx_sprom_getenv;
+ fill.priv = nvram_dev;
+
+ bcm53xx_sprom_fill(sprom, &fill);
+
+ platform_set_drvdata(pdev, sprom);
+
+ return 0;
+}
+
+static const struct of_device_id bcm53xx_sprom_of_match_table[] = {
+ { .compatible = "brcm,bcm53xx-sprom", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm53xx_sprom_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bcm53xx-sprom",
+ .of_match_table = bcm53xx_sprom_of_match_table,
+ /* driver unloading/unbinding currently not supported */
+ .suppress_bind_attrs = true,
+ },
+ .probe = bcm53xx_sprom_probe,
+};
+module_platform_driver(bcm53xx_sprom_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPLv2");

View File

@ -1,15 +1,15 @@
From c046c19fc8f1af7cf253fea5b0253143c159948a Mon Sep 17 00:00:00 2001
From bb5d497aeceb8d9f36a1d990538389b54748dfcd Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 6 Jan 2014 23:29:15 +0100
Subject: [PATCH 6/8] bcma: register bcma as device tree driver
Subject: [PATCH 05/15] bcma: register bcma as device tree driver
This driver is used by the bcm53xx ARM SoC code.Now it is possible to
give the address of the chipcommon core in device tree.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/host_soc.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/bcma/bcma.h | 2 ++
drivers/bcma/host_soc.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/bcma/bcma.h | 2 ++
2 files changed, 72 insertions(+)
--- a/drivers/bcma/host_soc.c

View File

@ -1,10 +1,12 @@
From 06a21484198df9a4d34fe5062878d3bf4fc14340 Mon Sep 17 00:00:00 2001
From 3e59da41882a408064cd23f4c9124a7938bdb91f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 9 Jan 2014 19:40:14 +0100
Subject: [PATCH 7/8] bcma: get irqs from dt
Subject: [PATCH 06/15] bcma: get irqs from dt
If bcma was registered with device tree it will search for some nodes
with the irq number and add it to the core configuration.
---
drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
--- a/drivers/bcma/main.c

View File

@ -0,0 +1,88 @@
From 5d94449a92e4121b408e7cb8931a47984135eeea Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 4 May 2014 14:34:31 +0200
Subject: [PATCH 07/15] bcma: get sprom from devicetree
This patch make it possible to device an sprom provider in device tree
and get the sprom from this driver. Every time there is such a provider
it gets asked for a sprom.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/sprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
@@ -46,6 +48,46 @@ int bcma_arch_register_fallback_sprom(in
return 0;
}
+#ifdef CONFIG_OF
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+ struct ssb_sprom *out)
+{
+ const phandle *handle;
+ struct device_node *sprom_node;
+ struct platform_device *sprom_dev;
+ struct ssb_sprom *sprom;
+
+ if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
+ return -ENOENT;
+
+ handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
+ if (!handle)
+ return -ENOENT;
+
+ sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
+ if (!sprom_node)
+ return -ENOENT;
+
+ sprom_dev = of_find_device_by_node(sprom_node);
+ if (!sprom_dev)
+ return -ENOENT;
+
+ sprom = platform_get_drvdata(sprom_dev);
+ if (!sprom)
+ return -ENOENT;
+
+ memcpy(out, sprom, sizeof(*out));
+
+ return 0;
+}
+#else
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+ struct ssb_sprom *out)
+{
+ return -ENOENT;
+}
+#endif
+
static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
struct ssb_sprom *out)
{
@@ -553,7 +595,14 @@ int bcma_sprom_get(struct bcma_bus *bus)
u16 *sprom;
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
SSB_SPROMSIZE_WORDS_R10, };
- int i, err = 0;
+ int i, err;
+
+ err = bcma_fill_sprom_with_dt(bus, &bus->sprom);
+ if (err == 0) {
+ bcma_info(bus, "Found sprom from device tree provider\n");
+ return 0;
+ }
+ err = 0;
if (!bus->drv_cc.core)
return -EOPNOTSUPP;

View File

@ -1,59 +1,74 @@
From 22b90bcf616578abe09845c72317ce53312f7faf Mon Sep 17 00:00:00 2001
From 23bcd5e7cb2aaee48ba8b2351f032a230d948b6f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 25 Jan 2014 17:03:07 +0100
Subject: [PATCH 8/8] ARM: BCM5301X: register bcma bus
Subject: [PATCH 08/15] ARM: BCM5301X: register bcma bus
---
arch/arm/boot/dts/bcm4708.dtsi | 43 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -31,4 +31,47 @@
@@ -31,4 +31,62 @@
};
};
+ nvram0: nvram@0 {
+ compatible = "brcm,bcm47xx-nvram";
+ reg = <0x1c000000 0x01000000>;
+ };
+
+ sprom0: sprom@0 {
+ compatible = "brcm,bcm53xx-sprom";
+ nvram = <&nvram0>;
+ };
+
+ aix@18000000 {
+ compatible = "brcm,bus-aix";
+ reg = <0x18000000 0x1000>;
+ ranges = <0x00000000 0x18000000 0x00100000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ sprom = <&sprom0>;
+
+ usb2@0 {
+ compatible = "brcm,northstar-usb2";
+ reg = <0x18021000 0x1000>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ usb3@0 {
+ compatible = "brcm,northstar-usb3";
+ reg = <0x18023000 0x1000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gmac@0 {
+ compatible = "brcm,northstar-gmac";
+ reg = <0x18024000 0x1000>;
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gmac@1 {
+ compatible = "brcm,northstar-gmac";
+ reg = <0x18025000 0x1000>;
+ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gmac@2 {
+ compatible = "brcm,northstar-gmac";
+ reg = <0x18026000 0x1000>;
+ interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gmac@3 {
+ compatible = "brcm,northstar-gmac";
+ reg = <0x18027000 0x1000>;
+ interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ pcie@0 {
+ reg = <0x18012000 0x1000>;
+ interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ pcie@1 {
+ reg = <0x18013000 0x1000>;
+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
};

View File

@ -0,0 +1,32 @@
From f8ea60bbaf880d8d8d99fde3b5155f472e00141f Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 12 May 2014 20:16:39 +0200
Subject: [PATCH 09/15] bcma: only map wrap if it is not null
The chipcommon B core does not have a wrap address and it would fail here.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/scan.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -421,10 +421,13 @@ static int bcma_get_next_core(struct bcm
core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
if (!core->io_addr)
return -ENOMEM;
- core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
- if (!core->io_wrap) {
- iounmap(core->io_addr);
- return -ENOMEM;
+ if (core->wrap) {
+ core->io_wrap = ioremap_nocache(core->wrap,
+ BCMA_CORE_SIZE);
+ if (!core->io_wrap) {
+ iounmap(core->io_addr);
+ return -ENOMEM;
+ }
}
}
return 0;

View File

@ -0,0 +1,71 @@
From 9317024aa1d8df94d3b021bc23b57f02a435e96c Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 12 May 2014 21:57:53 +0200
Subject: [PATCH 10/15] bcma: store more alternative addresses
Each core could have more than one alternative address. There are cores
with 8 alternative addresses for different functions. The PHY control
in the Chip common B core is done through the 2. alternative address
and not the first one.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/scan.c | 9 +++++----
drivers/usb/host/bcma-hcd.c | 2 +-
include/linux/bcma/bcma.h | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -276,7 +276,7 @@ static int bcma_get_next_core(struct bcm
struct bcma_device *core)
{
u32 tmp;
- u8 i, j;
+ u8 i, j, k;
s32 cia, cib;
u8 ports[2], wrappers[2];
@@ -367,6 +367,7 @@ static int bcma_get_next_core(struct bcm
core->addr = tmp;
/* get & parse slave ports */
+ k = 0;
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
@@ -376,9 +377,9 @@ static int bcma_get_next_core(struct bcm
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
break;
- } else {
- if (i == 0 && j == 0)
- core->addr1 = tmp;
+ } else if (k < 8) {
+ core->addr_s[k] = tmp;
+ k++;
}
}
}
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -237,7 +237,7 @@ static int bcma_hcd_probe(struct bcma_de
bcma_hcd_init_chip(dev);
/* In AI chips EHCI is addrspace 0, OHCI is 1 */
- ohci_addr = dev->addr1;
+ ohci_addr = dev->addr_s[0];
if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
&& chipinfo->rev == 0)
ohci_addr = 0x18009000;
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -263,7 +263,7 @@ struct bcma_device {
u8 core_unit;
u32 addr;
- u32 addr1;
+ u32 addr_s[8];
u32 wrap;
void __iomem *io_addr;

View File

@ -0,0 +1,180 @@
From 6c0df4a483e41ef129caa8948b3bcde7f91de197 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 12 May 2014 20:33:15 +0200
Subject: [PATCH 11/15] bcma: add support for chipcommon B core
This core is used on BCM4708 to configure the PCIe and USB3 PHYs and it
contains the addresses to the Device Management unit. This will be used
by the PCIe driver first.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/Makefile | 1 +
drivers/bcma/bcma_private.h | 4 ++
drivers/bcma/driver_chipcommon_b.c | 59 +++++++++++++++++++++++++++++
drivers/bcma/main.c | 10 +++++
drivers/bcma/scan.c | 1 +
include/linux/bcma/bcma.h | 1 +
include/linux/bcma/bcma_driver_chipcommon.h | 8 ++++
7 files changed, 84 insertions(+)
create mode 100644 drivers/bcma/driver_chipcommon_b.c
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,5 +1,6 @@
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y += driver_chipcommon_b.o
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
bcma-y += driver_pci.o
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -50,6 +50,10 @@ void bcma_chipco_serial_init(struct bcma
extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
+/* driver_chipcommon_b.c */
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
+
/* driver_chipcommon_pmu.c */
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon_b.c
@@ -0,0 +1,59 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon B Unit driver
+ *
+ * Copyright 2011, 2014, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/export.h>
+#include <linux/bcma/bcma.h>
+
+static bool bcma_wait_reg(void __iomem *addr, u32 mask, u32 value,
+ int timeout)
+{
+ unsigned long deadline = jiffies + timeout;
+ u32 val;
+
+ do {
+ val = readl(addr);
+ if ((val & mask) == value)
+ return true;
+ cpu_relax();
+ udelay(10);
+ } while (!time_after_eq(jiffies, deadline));
+
+ pr_warn("Timeout waiting for register %p!\n", addr);
+
+ return false;
+}
+
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
+{
+ writel(offset, ccb->mii + 0x00);
+ bcma_wait_reg(ccb->mii + 0x00, 0x0100, 0x0000, 100);
+ writel(value, ccb->mii + 0x04);
+ bcma_wait_reg(ccb->mii + 0x00, 0x0100, 0x0000, 100);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
+
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb)
+{
+ if (ccb->setup_done)
+ return 0;
+
+ ccb->setup_done = 1;
+ ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE);
+ if (!ccb->mii)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb)
+{
+ if (ccb->mii)
+ iounmap(ccb->mii);
+}
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -164,6 +164,7 @@ static int bcma_register_cores(struct bc
switch (core->id.id) {
case BCMA_CORE_4706_CHIPCOMMON:
case BCMA_CORE_CHIPCOMMON:
+ case BCMA_CORE_CHIPCOMMON_B:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
case BCMA_CORE_MIPS_74K:
@@ -300,6 +301,13 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_chipcommon_init(&bus->drv_cc);
}
+ /* Init CC core */
+ core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON_B);
+ if (core) {
+ bus->drv_cc_b.core = core;
+ bcma_core_chipcommon_b_init(&bus->drv_cc_b);
+ }
+
/* Init MIPS core */
core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
if (core) {
@@ -347,6 +355,8 @@ void bcma_bus_unregister(struct bcma_bus
else if (err)
bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
+ bcma_core_chipcommon_b_free(&bus->drv_cc_b);
+
cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -314,6 +314,7 @@ static int bcma_get_next_core(struct bcm
/* Some specific cores don't need wrappers */
switch (core->id.id) {
case BCMA_CORE_4706_MAC_GBIT_COMMON:
+ case BCMA_CORE_CHIPCOMMON_B:
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
break;
default:
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -334,6 +334,7 @@ struct bcma_bus {
u8 num;
struct bcma_drv_cc drv_cc;
+ struct bcma_drv_cc_b drv_cc_b;
struct bcma_drv_pci drv_pci[2];
struct bcma_drv_mips drv_mips;
struct bcma_drv_gmac_cmn drv_gmac_cmn;
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -644,6 +644,12 @@ struct bcma_drv_cc {
#endif
};
+struct bcma_drv_cc_b {
+ struct bcma_device *core;
+ u8 setup_done:1;
+ void __iomem *mii;
+};
+
/* Register access */
#define bcma_cc_read32(cc, offset) \
bcma_read32((cc)->core, offset)
@@ -699,4 +705,6 @@ extern void bcma_pmu_spuravoid_pllupdate
extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value);
+
#endif /* LINUX_BCMA_DRIVER_CC_H_ */

View File

@ -0,0 +1,29 @@
From ea422113a5d2778347db6136d95f45a50e2f2d29 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 29 May 2014 20:54:15 +0200
Subject: [PATCH 13/15] pci: do not probe too early
Probing is done before the PCIe bridge is fully activated and the
address spaces does not get assigned to the PCIe devices. Without the
address space the driver can not register to this device. With this
patch the driver reregistration is done later.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/pci/probe.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1912,7 +1912,10 @@ struct pci_bus *pci_scan_root_bus(struct
if (!found)
pci_bus_update_busn_res_end(b, max);
- pci_bus_add_devices(b);
+ /* this should be done in arch/arm/kernel/bios32.c, because the
+ resources for the PCI devices are initilized later and doing
+ it here will fail. */
+ /* pci_bus_add_devices(b); */
return b;
}
EXPORT_SYMBOL(pci_scan_root_bus);

View File

@ -0,0 +1,24 @@
From a0d83e0ad20f6dde0a71ed07da12ca3be8bbdc01 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 18 May 2014 17:15:24 +0200
Subject: [PATCH 12/15] bcma: add PCI IDs for more devices
This adds the PCI IDs for the BCM4360 and BCM43227.
Both devices were found on a Netgear R6250 with a BCM4708 ARM SoC.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/bcma/host_pci.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -280,6 +280,8 @@ static const struct pci_device_id bcma_p
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);

View File

@ -0,0 +1,645 @@
From 7475eee716d11f487076f78f26a6e403c06d0c76 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 12 May 2014 11:55:20 +0200
Subject: [PATCH 14/15] pcie2-bcma: add new PCIe2 driver for bcma
This driver supports the PCIe controller found on the BCM4708 and
similar SoCs. The controller itself is automatically detected by bcma.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
arch/arm/mach-bcm/Kconfig | 1 +
drivers/pci/host/Kconfig | 7 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pcie2-bcma.c | 594 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 603 insertions(+)
create mode 100644 drivers/pci/host/pcie2-bcma.c
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -45,6 +45,7 @@ config ARCH_BCM_5301X
select ARM_GLOBAL_TIMER
select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
select MIGHT_HAVE_PCI
+ select PCI_DOMAINS if PCI
help
Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -33,4 +33,11 @@ config PCI_RCAR_GEN2
There are 3 internal PCI controllers available with a single
built-in EHCI/OHCI host controller present on each one.
+config PCI_BCMA
+ bool "BCMA PCIe2 host controller"
+ depends on BCMA && OF
+ help
+ Say Y here if you want to support a simple generic PCI host
+ controller, such as the one emulated by kvmtool.
+
endmenu
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_BCMA) += pcie2-bcma.o
--- /dev/null
+++ b/drivers/pci/host/pcie2-bcma.c
@@ -0,0 +1,594 @@
+/*
+ * Northstar PCI-Express driver
+ * Only supports Root-Complex (RC) mode
+ *
+ * Notes:
+ * PCI Domains are being used to identify the PCIe port 1:1.
+ *
+ * Only MEM access is supported, PAX does not support IO.
+ *
+ * TODO:
+ * MSI interrupts,
+ * DRAM > 128 MBytes (e.g. DMA zones)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/bcma/bcma.h>
+
+#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
+
+/*
+ * Register offset definitions
+ */
+#define SOC_PCIE_CONTROL 0x000 /* a.k.a. CLK_CONTROL reg */
+#define SOC_PCIE_PM_STATUS 0x008
+#define SOC_PCIE_PM_CONTROL 0x00c /* in EP mode only ! */
+
+#define SOC_PCIE_EXT_CFG_ADDR 0x120
+#define SOC_PCIE_EXT_CFG_DATA 0x124
+#define SOC_PCIE_CFG_ADDR 0x1f8
+#define SOC_PCIE_CFG_DATA 0x1fc
+
+#define SOC_PCIE_SYS_RC_INTX_EN 0x330
+#define SOC_PCIE_SYS_RC_INTX_CSR 0x334
+#define SOC_PCIE_SYS_HOST_INTR_EN 0x344
+#define SOC_PCIE_SYS_HOST_INTR_CSR 0x348
+
+#define SOC_PCIE_HDR_OFF 0x400 /* 256 bytes per function */
+
+/* 32-bit 4KB in-bound mapping windows for Function 0..3, n=0..7 */
+#define SOC_PCIE_SYS_IMAP0(f, n) (0xc00 + ((f) << 9)((n) << 2))
+/* 64-bit in-bound mapping windows for func 0..3 */
+#define SOC_PCIE_SYS_IMAP1(f) (0xc80 + ((f) << 3))
+#define SOC_PCIE_SYS_IMAP2(f) (0xcc0 + ((f) << 3))
+/* 64-bit in-bound address range n=0..2 */
+#define SOC_PCIE_SYS_IARR(n) (0xd00 + ((n) << 3))
+/* 64-bit out-bound address filter n=0..2 */
+#define SOC_PCIE_SYS_OARR(n) (0xd20 + ((n) << 3))
+/* 64-bit out-bound mapping windows n=0..2 */
+#define SOC_PCIE_SYS_OMAP(n) (0xd40 + ((n) << 3))
+
+#define BCM4360_D11AC_ID 0x43a0
+#define BCM4360_D11AC2G_ID 0x43a1
+#define BCM4360_D11AC5G_ID 0x43a2
+#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */
+#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */
+#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */
+
+static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ struct pci_sys_data *sys = pdev->sysdata;
+ struct bcma_device *bdev = sys->private_data;
+
+ return bdev->irq;
+}
+
+static u32 bcma_pcie2_cfg_base(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where)
+{
+ int slot = PCI_SLOT(devfn);
+ int fn = PCI_FUNC(devfn);
+ u32 addr_reg;
+
+ if (busno == 0) {
+ if (slot >= 1)
+ return 0;
+ bcma_write32(bdev, SOC_PCIE_EXT_CFG_ADDR, where & 0xffc);
+ return SOC_PCIE_EXT_CFG_DATA;
+ } else {
+ if (fn > 1)
+ return 0;
+ addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
+ (where & 0xffc) | (1 & 0x3);
+
+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, addr_reg);
+ return SOC_PCIE_CFG_DATA;
+ }
+}
+
+static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where, int size)
+{
+ u32 base;
+ u32 data_reg;
+
+ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
+
+ if (!base)
+ return ~0UL;
+
+ data_reg = bcma_read32(bdev, base);
+
+ /* NS: CLASS field is R/O, and set to wrong 0x200 value */
+ if (busno == 0 && devfn == 0) {
+ /*
+ * RC's class is 0x0280, but Linux PCI driver needs 0x604
+ * for a PCIe bridge. So we must fixup the class code
+ * to 0x604 here.
+ */
+ if ((where & 0xffc) == PCI_CLASS_REVISION) {
+ data_reg &= 0xff;
+ data_reg |= 0x604 << 16;
+ }
+ }
+ /* HEADER_TYPE=00 indicates the port in EP mode */
+
+ if (size == 4) {
+ return data_reg;
+ } else {
+ u32 mask = (1 << (size * 8)) - 1;
+ int shift = (where % 4) * 8;
+ return (data_reg >> shift) & mask;
+ }
+}
+
+static void bcma_pcie2_write_config(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where, int size,
+ u32 val)
+{
+ u32 base;
+ u32 data_reg;
+
+ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
+
+ if (!base)
+ return;
+
+ if (size < 4) {
+ u32 mask = (1 << (size * 8)) - 1;
+ int shift = (where % 4) * 8;
+ data_reg = bcma_read32(bdev, base);
+ data_reg &= ~(mask << shift);
+ data_reg |= (val & mask) << shift;
+ } else {
+ data_reg = val;
+ }
+
+ bcma_write32(bdev, base, data_reg);
+}
+
+static u8 bcma_pcie2_read_config8(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where)
+{
+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 1);
+}
+
+static u16 bcma_pcie2_read_config16(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where)
+{
+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 2);
+}
+
+static u32 bcma_pcie2_read_config32(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where)
+{
+ return bcma_pcie2_read_config(bdev, busno, devfn, where, 4);
+}
+
+static void bcma_pcie2_write_config8(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where, u8 val)
+{
+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 1, val);
+}
+
+static void bcma_pcie2_write_config16(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where, u16 val)
+{
+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 2, val);
+}
+
+static void bcma_pcie2_write_config32(struct bcma_device *bdev, int busno,
+ unsigned int devfn, int where, u32 val)
+{
+ return bcma_pcie2_write_config(bdev, busno, devfn, where, 4, val);
+}
+
+static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ struct bcma_device *bdev = sys->private_data;
+
+ *val = bcma_pcie2_read_config(bdev, bus->number, devfn, where, size);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int bcma_pcie2_write_config_pci(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ struct bcma_device *bdev = sys->private_data;
+
+ bcma_pcie2_write_config(bdev, bus->number, devfn, where, size, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Check link status, return 0 if link is up in RC mode,
+ * otherwise return non-zero
+ */
+static int bcma_pcie2_check_link(struct bcma_device *bdev, u32 allow_gen2)
+{
+ u32 devfn = 0;
+ u8 tmp8;
+ u32 tmp32;
+
+ tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xdc);
+ tmp32 &= ~0xf;
+ if (allow_gen2)
+ tmp32 |= 2;
+ else {
+ /* force PCIE GEN1 */
+ tmp32 |= 1;
+ }
+ bcma_pcie2_write_config32(bdev, 0, devfn, 0xdc, tmp32);
+
+ /* See if the port is in EP mode, indicated by header type 00 */
+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_HEADER_TYPE);
+ if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
+ dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
+ bdev->core_unit);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Initializte the PCIe controller
+ */
+static void bcma_pcie2_hw_init(struct bcma_device *bdev)
+{
+ u32 devfn = 0;
+ u32 tmp32;
+ u16 tmp16;
+
+ /* Change MPS and MRRS to 512 */
+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, 0x4d4);
+ tmp16 &= ~7;
+ tmp16 |= 2;
+ bcma_pcie2_write_config16(bdev, 0, devfn, 0x4d4, tmp16);
+
+ tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xb4);
+ tmp32 &= ~((7 << 12) | (7 << 5));
+ tmp32 |= (2 << 12) | (2 << 5);
+ bcma_pcie2_write_config32(bdev, 0, devfn, 0xb4, tmp32);
+
+ /* Turn-on Root-Complex (RC) mode, from reset defailt of EP */
+
+ /* The mode is set by straps, can be overwritten via DMU
+ register <cru_straps_control> bit 5, "1" means RC
+ */
+
+ /* Send a downstream reset */
+ bcma_write32(bdev, SOC_PCIE_CONTROL, 0x3);
+ udelay(250);
+ bcma_write32(bdev, SOC_PCIE_CONTROL, 0x1);
+ mdelay(250);
+
+ /* TBD: take care of PM, check we're on */
+}
+
+/*
+ * Setup the address translation
+ */
+static void bcma_pcie2_map_init(struct bcma_device *bdev)
+{
+ unsigned size, i;
+ u32 addr;
+
+ /*
+ * NOTE:
+ * All PCI-to-CPU address mapping are 1:1 for simplicity
+ */
+
+ /* Outbound address translation setup */
+ size = SZ_128M;
+ addr = bdev->addr_s[0];
+ BUG_ON(!addr);
+ BUG_ON(addr & ((1 << 25) - 1)); /* 64MB alignment */
+
+ for (i = 0; i < 3; i++) {
+ const unsigned win_size = SZ_64M;
+ /* 64-bit LE regs, write low word, high is 0 at reset */
+ bcma_write32(bdev, SOC_PCIE_SYS_OMAP(i), addr);
+ bcma_write32(bdev, SOC_PCIE_SYS_OARR(i), addr|0x1);
+ addr += win_size;
+ if (size >= win_size)
+ size -= win_size;
+ if (size == 0)
+ break;
+ }
+ WARN_ON(size > 0);
+
+ /*
+ * Inbound address translation setup
+ * Northstar only maps up to 128 MiB inbound, DRAM could be up to 1 GiB.
+ *
+ * For now allow access to entire DRAM, assuming it is less than 128MiB,
+ * otherwise DMA bouncing mechanism may be required.
+ * Also consider DMA mask to limit DMA physical address
+ */
+ size = SZ_128M;
+ addr = PHYS_OFFSET;
+
+ size >>= 20; /* In MB */
+ size &= 0xff; /* Size is an 8-bit field */
+
+ WARN_ON(size == 0);
+ /* 64-bit LE regs, write low word, high is 0 at reset */
+ bcma_write32(bdev, SOC_PCIE_SYS_IMAP1(0), addr | 0x1);
+ bcma_write32(bdev, SOC_PCIE_SYS_IARR(1), addr | size);
+
+#ifdef CONFIG_SPARSEMEM
+ addr = PHYS_OFFSET2;
+ bcma_write32(bdev, SOC_PCIE_SYS_IMAP2(0), addr | 0x1);
+ bcma_write32(bdev, SOC_PCIE_SYS_IARR(2), addr | size);
+#endif
+}
+
+/*
+ * Setup PCIE Host bridge
+ */
+static void bcma_pcie2_bridge_init(struct bcma_device *bdev)
+{
+ u32 devfn = 0;
+ u8 tmp8;
+ u16 tmp16;
+
+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_PRIMARY_BUS, 0);
+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SECONDARY_BUS, 1);
+ bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS, 4);
+
+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_PRIMARY_BUS);
+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SECONDARY_BUS);
+ tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS);
+
+ /* MEM_BASE, MEM_LIM require 1MB alignment */
+ BUG_ON((bdev->addr_s[0] >> 16) & 0xf);
+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_BASE,
+ bdev->addr_s[0] >> 16);
+ BUG_ON(((bdev->addr_s[0] + SZ_128M) >> 16) & 0xf);
+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT,
+ (bdev->addr_s[0] + SZ_128M) >> 16);
+
+ /* These registers are not supported on the NS */
+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_BASE_UPPER16, 0);
+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_LIMIT_UPPER16, 0);
+
+ /* Force class to that of a Bridge */
+ bcma_pcie2_write_config16(bdev, 0, devfn, PCI_CLASS_DEVICE,
+ PCI_CLASS_BRIDGE_PCI);
+
+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_CLASS_DEVICE);
+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_BASE);
+ tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT);
+}
+
+static int bcma_pcie2_allow_gen2_rc(struct bcma_device *bdev)
+{
+ u32 vendorid, devid, chipid, chiprev;
+ u32 val, bar;
+ void __iomem *base;
+ int allow = 1;
+
+ /* Read PCI vendor/device ID's */
+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x0);
+ val = bcma_read32(bdev, SOC_PCIE_CFG_DATA);
+ vendorid = val & 0xffff;
+ devid = val >> 16;
+ if (vendorid == PCI_VENDOR_ID_BROADCOM &&
+ (devid == BCMA_CHIP_ID_BCM4360 || devid == BCM4360_D11AC_ID ||
+ devid == BCM4360_D11AC2G_ID || devid == BCM4360_D11AC5G_ID ||
+ devid == BCM4352_D11AC_ID || devid == BCM4352_D11AC2G_ID ||
+ devid == BCM4352_D11AC5G_ID)) {
+ /* Config BAR0 */
+ bar = bdev->addr_s[0];
+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x10);
+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, bar);
+ /* Config BAR0 window to access chipc */
+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x80);
+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, SI_ENUM_BASE);
+
+ /* Enable memory resource */
+ bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x4);
+ val = bcma_read32(bdev, SOC_PCIE_CFG_DATA);
+ val |= PCI_COMMAND_MEMORY;
+ bcma_write32(bdev, SOC_PCIE_CFG_DATA, val);
+ /* Enable memory and bus master */
+ bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
+
+ /* Read CHIP ID */
+ base = ioremap(bar, 0x1000);
+ val = __raw_readl(base);
+ iounmap(base);
+ chipid = val & 0xffff;
+ chiprev = (val >> 16) & 0xf;
+ if ((chipid == BCMA_CHIP_ID_BCM4360 ||
+ chipid == BCMA_CHIP_ID_BCM43460 ||
+ chipid == BCMA_CHIP_ID_BCM4352) && (chiprev < 3))
+ allow = 0;
+ }
+ return allow;
+}
+
+static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
+{
+ /* PCIE PLL block register (base 0x8000) */
+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x57fe8000);
+ /* Check PCIE PLL lock status */
+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x67c60000);
+}
+
+/* To improve PCIE phy jitter */
+static void bcma_pcie2_improve_phy_jitter(struct bcma_bus *bus, int phyaddr)
+{
+ u32 val;
+
+ /* Change blkaddr */
+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x1f << 18) |
+ (2 << 16) | (0x863 << 4);
+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
+
+ /* Write 0x0190 to 0x13 regaddr */
+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x13 << 18) |
+ (2 << 16) | 0x0190;
+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
+
+ /* Write 0x0191 to 0x19 regaddr */
+ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x19 << 18) |
+ (2 << 16) | 0x0191;
+ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
+}
+
+static int bcma_pcie2_setup(int nr, struct pci_sys_data *sys)
+{
+ struct bcma_device *bdev = sys->private_data;
+ struct bcma_bus *bus = bdev->bus;
+ struct resource *res;
+ struct bcma_device *arm_core;
+ u32 cru_straps_ctrl;
+ int allow_gen2, linkfail;
+ int phyaddr;
+
+ if (bdev->core_unit == 2) {
+ arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9);
+ cru_straps_ctrl = bcma_read32(arm_core, 0x2a0);
+
+ /* 3rd PCIE is not selected */
+ if (cru_straps_ctrl & 0x10)
+ return -ENODEV;
+
+ bcma_pcie2_3rd_init(bus);
+ phyaddr = 0xf;
+ } else {
+ phyaddr = bdev->core_unit;
+ }
+ bcma_pcie2_improve_phy_jitter(bus, phyaddr);
+
+ /* create mem resource */
+ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ dev_info(&bdev->dev, "requesting resource at 0x%x failed\n",
+ bdev->addr_s[0]);
+ return -EINVAL;
+ }
+ res->start = bdev->addr_s[0];
+ res->end = res->start + SZ_128M - 1;
+ res->name = "PCIe Configuration Space";
+ res->flags = IORESOURCE_MEM;
+
+ pci_add_resource(&sys->resources, res);
+
+ /* This PCIe controller does not support IO Mem, so use a dummy one. */
+ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ dev_info(&bdev->dev, "requesting resource at 0x%x failed\n",
+ bdev->addr_s[0]);
+ return -EINVAL;
+ }
+ res->start = bdev->addr_s[0];
+ res->end = res->start + SZ_128M - 1;
+ res->name = "PCIe Configuration Space";
+ res->flags = IORESOURCE_IO;
+
+ pci_add_resource(&sys->resources, res);
+
+ for (allow_gen2 = 0; allow_gen2 <= 1; allow_gen2++) {
+ bcma_pcie2_hw_init(bdev);
+ bcma_pcie2_map_init(bdev);
+
+ /*
+ * Skip inactive ports -
+ * will need to change this for hot-plugging
+ */
+ linkfail = bcma_pcie2_check_link(bdev, allow_gen2);
+ if (linkfail)
+ break;
+
+ bcma_pcie2_bridge_init(bdev);
+
+ if (allow_gen2 == 0) {
+ if (bcma_pcie2_allow_gen2_rc(bdev) == 0)
+ break;
+ dev_info(&bdev->dev, "switching to GEN2\n");
+ }
+ }
+
+ if (linkfail)
+ return -1;
+
+ return 1;
+}
+
+/*
+ * Methods for accessing configuration registers
+ */
+static struct pci_ops bcma_pcie2_ops = {
+ .read = bcma_pcie2_read_config_pci,
+ .write = bcma_pcie2_write_config_pci,
+};
+
+static int bcma_pcie2_probe(struct bcma_device *bdev)
+{
+ struct hw_pci hw;
+
+ dev_info(&bdev->dev, "scanning bus\n");
+
+ hw = (struct hw_pci) {
+ .nr_controllers = 1,
+ .domain = bdev->core_unit,
+ .private_data = (void **)&bdev,
+ .setup = bcma_pcie2_setup,
+ .map_irq = bcma_pcie2_map_irq,
+ .ops = &bcma_pcie2_ops,
+ };
+
+ /* Announce this port to ARM/PCI common code */
+ pci_common_init_dev(&bdev->dev, &hw);
+
+ /* Setup virtual-wire interrupts */
+ bcma_write32(bdev, SOC_PCIE_SYS_RC_INTX_EN, 0xf);
+
+ /* Enable memory and bus master */
+ bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
+
+ return 0;
+}
+
+static const struct bcma_device_id bcma_pcie2_table[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bcma_pcie2_table);
+
+static struct bcma_driver bcma_pcie2_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = bcma_pcie2_table,
+ .probe = bcma_pcie2_probe,
+};
+
+static int __init bcma_pcie2_init(void)
+{
+ return bcma_driver_register(&bcma_pcie2_driver);
+}
+module_init(bcma_pcie2_init);
+
+static void __exit bcma_pcie2_exit(void)
+{
+ bcma_driver_unregister(&bcma_pcie2_driver);
+}
+module_exit(bcma_pcie2_exit);
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("PCIe Gen2 driver for BCMA");
+MODULE_LICENSE("GPLv2");

View File

@ -1,73 +0,0 @@
These are some hackish patches to make the Ethernet driver work somehow
on this arm core.
The flash driver is not working, so we removed the nvram reading, this
should be changed after we have a flash driver.
The mdelay(1) is a ugly workaround for this arm chip, this seams to be a dma problem.
The PHY says it is not connected by default, just ignore it.
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -131,7 +131,7 @@ config BNX2X_SRIOV
config BGMAC
tristate "BCMA bus GBit core support"
- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
+ depends on BCMA_HOST_SOC && HAS_DMA
select PHYLIB
---help---
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -17,7 +17,11 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/b53.h>
+#ifdef CONFIG_BCM47XX
#include <bcm47xx_nvram.h>
+#else
+#define bcm47xx_nvram_getenv(a, b, c) -1
+#endif
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
@@ -1452,7 +1456,7 @@ static int bgmac_probe(struct bcma_devic
int err;
/* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
- if (core->core_unit > 1) {
+ if (core->core_unit > 0) {
pr_err("Unsupported core_unit %d\n", core->core_unit);
return -ENOTSUPP;
}
@@ -1487,8 +1491,7 @@ static int bgmac_probe(struct bcma_devic
}
bgmac->cmn = core->bus->drv_gmac_cmn.core;
- bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
- sprom->et0phyaddr;
+ bgmac->phyaddr = BGMAC_PHY_NOREGS; // core->core_unit ? sprom->et1phyaddr : sprom->et0phyaddr;
bgmac->phyaddr &= BGMAC_PHY_MASK;
if (bgmac->phyaddr == BGMAC_PHY_MASK) {
bgmac_err(bgmac, "No PHY found\n");
@@ -1540,8 +1543,7 @@ static int bgmac_probe(struct bcma_devic
/* TODO: reset the external phy. Specs are needed */
bgmac_phy_reset(bgmac);
- bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
- BGMAC_BFL_ENETROBO);
+ bgmac->has_robosw = 1;
if (bgmac->has_robosw)
bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -898,7 +898,7 @@ int genphy_update_link(struct phy_device
return status;
if ((status & BMSR_LSTATUS) == 0)
- phydev->link = 0;
+ phydev->link = 1;
else
phydev->link = 1;

View File

@ -0,0 +1,33 @@
From 0bd576e93a188fd3aab769b622fb3d35fa9bc7a7 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 3 May 2014 19:55:38 +0200
Subject: [PATCH 15/15] bgmac: some fixes to get bgmac work
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/Kconfig | 2 +-
drivers/net/phy/phy_device.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -131,7 +131,7 @@ config BNX2X_SRIOV
config BGMAC
tristate "BCMA bus GBit core support"
- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
+ depends on BCMA_HOST_SOC && HAS_DMA
select PHYLIB
---help---
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -898,7 +898,7 @@ int genphy_update_link(struct phy_device
return status;
if ((status & BMSR_LSTATUS) == 0)
- phydev->link = 0;
+ phydev->link = 1;
else
phydev->link = 1;