Root/target/linux/ar71xx/patches-3.6/523-MIPS-ath79-OTP-support.patch

1--- a/arch/mips/ath79/dev-wmac.c
2+++ b/arch/mips/ath79/dev-wmac.c
3@@ -156,6 +156,137 @@ static void qca955x_wmac_setup(void)
4         ath79_wmac_data.is_clk_25mhz = true;
5 }
6 
7+static bool __init
8+ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data)
9+{
10+ int timeout = 1000;
11+ u32 val;
12+
13+ __raw_readl(base + AR9300_OTP_BASE + (4 * addr));
14+ while (timeout--) {
15+ val = __raw_readl(base + AR9300_OTP_STATUS);
16+ if ((val & AR9300_OTP_STATUS_TYPE) == AR9300_OTP_STATUS_VALID)
17+ break;
18+
19+ udelay(10);
20+ }
21+
22+ if (!timeout)
23+ return false;
24+
25+ *data = __raw_readl(base + AR9300_OTP_READ_DATA);
26+ return true;
27+}
28+
29+static bool __init
30+ar93xx_wmac_otp_read(void __iomem *base, int addr, u8 *dest, int len)
31+{
32+ u32 data;
33+ int i;
34+
35+ for (i = 0; i < len; i++) {
36+ int offset = 8 * ((addr - i) % 4);
37+
38+ if (!ar93xx_wmac_otp_read_word(base, (addr - i) / 4, &data))
39+ return false;
40+
41+ dest[i] = (data >> offset) & 0xff;
42+ }
43+
44+ return true;
45+}
46+
47+static bool __init
48+ar93xx_wmac_otp_uncompress(void __iomem *base, int addr, int len, u8 *dest,
49+ int dest_start, int dest_len)
50+{
51+ int dest_bytes = 0;
52+ int offset = 0;
53+ int end = addr - len;
54+ u8 hdr[2];
55+
56+ while (addr > end) {
57+ if (!ar93xx_wmac_otp_read(base, addr, hdr, 2))
58+ return false;
59+
60+ addr -= 2;
61+ offset += hdr[0];
62+
63+ if (offset <= dest_start + dest_len &&
64+ offset + len >= dest_start) {
65+ int data_offset = 0;
66+ int dest_offset = 0;
67+ int copy_len;
68+
69+ if (offset < dest_start)
70+ data_offset = dest_start - offset;
71+ else
72+ dest_offset = offset - dest_start;
73+
74+ copy_len = len - data_offset;
75+ if (copy_len > dest_len - dest_offset)
76+ copy_len = dest_len - dest_offset;
77+
78+ ar93xx_wmac_otp_read(base, addr - data_offset,
79+ dest + dest_offset,
80+ copy_len);
81+
82+ dest_bytes += copy_len;
83+ }
84+ addr -= hdr[1];
85+ }
86+ return !!dest_bytes;
87+}
88+
89+bool __init ar93xx_wmac_read_mac_address(u8 *dest)
90+{
91+ void __iomem *base;
92+ bool ret = false;
93+ int addr = 0x1ff;
94+ unsigned int len;
95+ u32 hdr_u32;
96+ u8 *hdr = (u8 *) &hdr_u32;
97+ u8 mac[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06 };
98+ int mac_start = 2, mac_end = 8;
99+
100+ BUG_ON(!soc_is_ar933x() && !soc_is_ar934x());
101+ base = ioremap_nocache(AR933X_WMAC_BASE, AR933X_WMAC_SIZE);
102+ while (addr > sizeof(hdr)) {
103+ if (!ar93xx_wmac_otp_read(base, addr, hdr, sizeof(hdr)))
104+ break;
105+
106+ if (hdr_u32 == 0 || hdr_u32 == ~0)
107+ break;
108+
109+ len = (hdr[1] << 4) | (hdr[2] >> 4);
110+ addr -= 4;
111+
112+ switch (hdr[0] >> 5) {
113+ case 0:
114+ if (len < mac_end)
115+ break;
116+
117+ ar93xx_wmac_otp_read(base, addr - mac_start, mac, 6);
118+ ret = true;
119+ break;
120+ case 3:
121+ ret |= ar93xx_wmac_otp_uncompress(base, addr, len, mac,
122+ mac_start, 6);
123+ break;
124+ default:
125+ break;
126+ }
127+
128+ addr -= len + 2;
129+ }
130+
131+ iounmap(base);
132+ if (ret)
133+ memcpy(dest, mac, 6);
134+
135+ return ret;
136+}
137+
138 void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
139 {
140     if (soc_is_ar913x())
141--- a/arch/mips/ath79/dev-wmac.h
142+++ b/arch/mips/ath79/dev-wmac.h
143@@ -14,5 +14,6 @@
144 
145 void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
146 void ath79_register_wmac_simple(void);
147+bool ar93xx_wmac_read_mac_address(u8 *dest);
148 
149 #endif /* _ATH79_DEV_WMAC_H */
150--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
151+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
152@@ -113,6 +113,14 @@
153 #define QCA955X_EHCI1_BASE 0x1b400000
154 #define QCA955X_EHCI_SIZE 0x200
155 
156+#define AR9300_OTP_BASE 0x14000
157+#define AR9300_OTP_STATUS 0x15f18
158+#define AR9300_OTP_STATUS_TYPE 0x7
159+#define AR9300_OTP_STATUS_VALID 0x4
160+#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
161+#define AR9300_OTP_STATUS_SM_BUSY 0x1
162+#define AR9300_OTP_READ_DATA 0x15f1c
163+
164 /*
165  * DDR_CTRL block
166  */
167

Archive Download this file



interactive