aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bcma
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2011-06-01 20:08:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-06-03 15:01:07 -0400
commit27f18dc2dafe66a93c7101fc94201b8c83903597 (patch)
tree4600db64c653cfc74d427fc26b7f94ef8fb5db28 /drivers/bcma
parent4da909e7b572b561d8150f9d41b04bcfff386222 (diff)
bcma: read SPROM and extract MAC from it
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>
Diffstat (limited to 'drivers/bcma')
-rw-r--r--drivers/bcma/Makefile2
-rw-r--r--drivers/bcma/bcma_private.h3
-rw-r--r--drivers/bcma/main.c7
-rw-r--r--drivers/bcma/sprom.c162
4 files changed, 173 insertions, 1 deletions
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 0d56245bcb7..cde0182bd1d 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,4 +1,4 @@
1bcma-y += main.o scan.o core.o 1bcma-y += main.o scan.o core.o sprom.o
2bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o 2bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
3bcma-y += driver_pci.o 3bcma-y += driver_pci.o
4bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o 4bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 2f72e9c585f..12a75ab3dd2 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -19,6 +19,9 @@ extern void bcma_bus_unregister(struct bcma_bus *bus);
19/* scan.c */ 19/* scan.c */
20int bcma_bus_scan(struct bcma_bus *bus); 20int bcma_bus_scan(struct bcma_bus *bus);
21 21
22/* sprom.c */
23int bcma_sprom_get(struct bcma_bus *bus);
24
22#ifdef CONFIG_BCMA_HOST_PCI 25#ifdef CONFIG_BCMA_HOST_PCI
23/* host_pci.c */ 26/* host_pci.c */
24extern int __init bcma_host_pci_init(void); 27extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index a2f6b187927..11e96dc6011 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -146,6 +146,13 @@ int bcma_bus_register(struct bcma_bus *bus)
146 bcma_core_pci_init(&bus->drv_pci); 146 bcma_core_pci_init(&bus->drv_pci);
147 } 147 }
148 148
149 /* Try to get SPROM */
150 err = bcma_sprom_get(bus);
151 if (err) {
152 pr_err("Failed to get SPROM: %d\n", err);
153 return -ENOENT;
154 }
155
149 /* Register found cores */ 156 /* Register found cores */
150 bcma_register_cores(bus); 157 bcma_register_cores(bus);
151 158
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
new file mode 100644
index 00000000000..ffbb0e32e92
--- /dev/null
+++ b/drivers/bcma/sprom.c
@@ -0,0 +1,162 @@
1/*
2 * Broadcom specific AMBA
3 * SPROM reading
4 *
5 * Licensed under the GNU/GPL. See COPYING for details.
6 */
7
8#include "bcma_private.h"
9
10#include <linux/bcma/bcma.h>
11#include <linux/bcma/bcma_regs.h>
12#include <linux/pci.h>
13#include <linux/io.h>
14#include <linux/dma-mapping.h>
15#include <linux/slab.h>
16
17#define SPOFF(offset) ((offset) / sizeof(u16))
18
19/**************************************************
20 * R/W ops.
21 **************************************************/
22
23static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
24{
25 int i;
26 for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
27 sprom[i] = bcma_read16(bus->drv_cc.core,
28 BCMA_CC_SPROM + (i * 2));
29}
30
31/**************************************************
32 * Validation.
33 **************************************************/
34
35static inline u8 bcma_crc8(u8 crc, u8 data)
36{
37 /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
38 static const u8 t[] = {
39 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
40 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
41 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
42 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
43 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
44 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
45 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
46 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
47 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
48 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
49 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
50 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
51 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
52 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
53 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
54 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
55 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
56 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
57 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
58 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
59 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
60 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
61 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
62 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
63 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
64 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
65 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
66 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
67 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
68 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
69 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
70 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
71 };
72 return t[crc ^ data];
73}
74
75static u8 bcma_sprom_crc(const u16 *sprom)
76{
77 int word;
78 u8 crc = 0xFF;
79
80 for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
81 crc = bcma_crc8(crc, sprom[word] & 0x00FF);
82 crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
83 }
84 crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
85 crc ^= 0xFF;
86
87 return crc;
88}
89
90static int bcma_sprom_check_crc(const u16 *sprom)
91{
92 u8 crc;
93 u8 expected_crc;
94 u16 tmp;
95
96 crc = bcma_sprom_crc(sprom);
97 tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
98 expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
99 if (crc != expected_crc)
100 return -EPROTO;
101
102 return 0;
103}
104
105static int bcma_sprom_valid(const u16 *sprom)
106{
107 u16 revision;
108 int err;
109
110 err = bcma_sprom_check_crc(sprom);
111 if (err)
112 return err;
113
114 revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
115 if (revision != 8) {
116 pr_err("Unsupported SPROM revision: %d\n", revision);
117 return -ENOENT;
118 }
119
120 return 0;
121}
122
123/**************************************************
124 * SPROM extraction.
125 **************************************************/
126
127static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
128{
129 u16 v;
130 int i;
131
132 for (i = 0; i < 3; i++) {
133 v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
134 *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
135 }
136}
137
138int bcma_sprom_get(struct bcma_bus *bus)
139{
140 u16 *sprom;
141 int err = 0;
142
143 if (!bus->drv_cc.core)
144 return -EOPNOTSUPP;
145
146 sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
147 GFP_KERNEL);
148 if (!sprom)
149 return -ENOMEM;
150
151 bcma_sprom_read(bus, sprom);
152
153 err = bcma_sprom_valid(sprom);
154 if (err)
155 goto out;
156
157 bcma_sprom_extract_r8(bus, sprom);
158
159out:
160 kfree(sprom);
161 return err;
162}