bcma: read SPROM and extract MAC from it
authorRafał Miłecki <zajec5@gmail.com>
Thu, 2 Jun 2011 00:08:51 +0000 (02:08 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 3 Jun 2011 19:01:07 +0000 (15:01 -0400)
In case of BCMA cards SPROM is located in the ChipCommon core, it is
not mapped as separated host window. So far we have met only SPROMs rev
8.
SPROM layout seems to be the same as for SSB buses, so we decided to
share SPROM struct and some defines.
For now we extract MAC address only, this can be improved of course.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/bcma/Makefile
drivers/bcma/bcma_private.h
drivers/bcma/main.c
drivers/bcma/sprom.c [new file with mode: 0644]
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h

index 0d56245bcb79776657315ac6b3620d6abbfd2173..cde0182bd1dcdb4b1d680b8b3fac1e60840c4956 100644 (file)
@@ -1,4 +1,4 @@
-bcma-y                                 += main.o scan.o core.o
+bcma-y                                 += main.o scan.o core.o sprom.o
 bcma-y                                 += driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y                                 += driver_pci.o
 bcma-$(CONFIG_BCMA_HOST_PCI)           += host_pci.o
index 2f72e9c585fd966514d8b3598f3e9b5fb0db8519..12a75ab3dd239b503a84826ec5ba7e8d935accd1 100644 (file)
@@ -19,6 +19,9 @@ extern void bcma_bus_unregister(struct bcma_bus *bus);
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
 
+/* sprom.c */
+int bcma_sprom_get(struct bcma_bus *bus);
+
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
 extern int __init bcma_host_pci_init(void);
index a2f6b1879273442d151745aa7e8b526caab40248..11e96dc6011afcc89dd2e72d93a6898b15a97e60 100644 (file)
@@ -146,6 +146,13 @@ int bcma_bus_register(struct bcma_bus *bus)
                bcma_core_pci_init(&bus->drv_pci);
        }
 
+       /* Try to get SPROM */
+       err = bcma_sprom_get(bus);
+       if (err) {
+               pr_err("Failed to get SPROM: %d\n", err);
+               return -ENOENT;
+       }
+
        /* Register found cores */
        bcma_register_cores(bus);
 
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
new file mode 100644 (file)
index 0000000..ffbb0e3
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Broadcom specific AMBA
+ * SPROM reading
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#define SPOFF(offset)  ((offset) / sizeof(u16))
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
+{
+       int i;
+       for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+               sprom[i] = bcma_read16(bus->drv_cc.core,
+                                      BCMA_CC_SPROM + (i * 2));
+}
+
+/**************************************************
+ * Validation.
+ **************************************************/
+
+static inline u8 bcma_crc8(u8 crc, u8 data)
+{
+       /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
+       static const u8 t[] = {
+               0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+               0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+               0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+               0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+               0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+               0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+               0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+               0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+               0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+               0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+               0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+               0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+               0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+               0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+               0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+               0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+               0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+               0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+               0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+               0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+               0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+               0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+               0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+               0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+               0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+               0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+               0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+               0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+               0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+               0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+               0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+               0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+       };
+       return t[crc ^ data];
+}
+
+static u8 bcma_sprom_crc(const u16 *sprom)
+{
+       int word;
+       u8 crc = 0xFF;
+
+       for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
+               crc = bcma_crc8(crc, sprom[word] & 0x00FF);
+               crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+       }
+       crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
+       crc ^= 0xFF;
+
+       return crc;
+}
+
+static int bcma_sprom_check_crc(const u16 *sprom)
+{
+       u8 crc;
+       u8 expected_crc;
+       u16 tmp;
+
+       crc = bcma_sprom_crc(sprom);
+       tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
+       expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+       if (crc != expected_crc)
+               return -EPROTO;
+
+       return 0;
+}
+
+static int bcma_sprom_valid(const u16 *sprom)
+{
+       u16 revision;
+       int err;
+
+       err = bcma_sprom_check_crc(sprom);
+       if (err)
+               return err;
+
+       revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
+       if (revision != 8) {
+               pr_err("Unsupported SPROM revision: %d\n", revision);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+/**************************************************
+ * SPROM extraction.
+ **************************************************/
+
+static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
+{
+       u16 v;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+       }
+}
+
+int bcma_sprom_get(struct bcma_bus *bus)
+{
+       u16 *sprom;
+       int err = 0;
+
+       if (!bus->drv_cc.core)
+               return -EOPNOTSUPP;
+
+       sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+                       GFP_KERNEL);
+       if (!sprom)
+               return -ENOMEM;
+
+       bcma_sprom_read(bus, sprom);
+
+       err = bcma_sprom_valid(sprom);
+       if (err)
+               goto out;
+
+       bcma_sprom_extract_r8(bus, sprom);
+
+out:
+       kfree(sprom);
+       return err;
+}
index 27a27a79bea39548841f7e0c09f474f587db9584..6ff080eac0b21e403100c85c6141f67d3811fbeb 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/bcma/bcma_driver_chipcommon.h>
 #include <linux/bcma/bcma_driver_pci.h>
+#include <linux/ssb/ssb.h> /* SPROM sharing */
 
 #include "bcma_regs.h"
 
@@ -187,6 +188,10 @@ struct bcma_bus {
 
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_pci drv_pci;
+
+       /* We decided to share SPROM struct with SSB as long as we do not need
+        * any hacks for BCMA. This simplifies drivers code. */
+       struct ssb_sprom sprom;
 };
 
 extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
index 083c3b6cd5ce71e64c369bc9472ad2dfca4e2ba4..9c5b69fc985a1fbfb3e6d44e3afe9209c5f2aaef 100644 (file)
 #define BCMA_CC_REGCTL_DATA            0x065C
 #define BCMA_CC_PLLCTL_ADDR            0x0660
 #define BCMA_CC_PLLCTL_DATA            0x0664
+#define BCMA_CC_SPROM                  0x0830 /* SPROM beginning */
 
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)