--- a/arch/mips/ath79/dev-wmac.c +++ b/arch/mips/ath79/dev-wmac.c @@ -165,6 +165,137 @@ static void qca955x_wmac_setup(void) ath79_wmac_data.is_clk_25mhz = true; } +static bool __init +ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data) +{ + int timeout = 1000; + u32 val; + + __raw_readl(base + AR9300_OTP_BASE + (4 * addr)); + while (timeout--) { + val = __raw_readl(base + AR9300_OTP_STATUS); + if ((val & AR9300_OTP_STATUS_TYPE) == AR9300_OTP_STATUS_VALID) + break; + + udelay(10); + } + + if (!timeout) + return false; + + *data = __raw_readl(base + AR9300_OTP_READ_DATA); + return true; +} + +static bool __init +ar93xx_wmac_otp_read(void __iomem *base, int addr, u8 *dest, int len) +{ + u32 data; + int i; + + for (i = 0; i < len; i++) { + int offset = 8 * ((addr - i) % 4); + + if (!ar93xx_wmac_otp_read_word(base, (addr - i) / 4, &data)) + return false; + + dest[i] = (data >> offset) & 0xff; + } + + return true; +} + +static bool __init +ar93xx_wmac_otp_uncompress(void __iomem *base, int addr, int len, u8 *dest, + int dest_start, int dest_len) +{ + int dest_bytes = 0; + int offset = 0; + int end = addr - len; + u8 hdr[2]; + + while (addr > end) { + if (!ar93xx_wmac_otp_read(base, addr, hdr, 2)) + return false; + + addr -= 2; + offset += hdr[0]; + + if (offset <= dest_start + dest_len && + offset + len >= dest_start) { + int data_offset = 0; + int dest_offset = 0; + int copy_len; + + if (offset < dest_start) + data_offset = dest_start - offset; + else + dest_offset = offset - dest_start; + + copy_len = len - data_offset; + if (copy_len > dest_len - dest_offset) + copy_len = dest_len - dest_offset; + + ar93xx_wmac_otp_read(base, addr - data_offset, + dest + dest_offset, + copy_len); + + dest_bytes += copy_len; + } + addr -= hdr[1]; + } + return !!dest_bytes; +} + +bool __init ar93xx_wmac_read_mac_address(u8 *dest) +{ + void __iomem *base; + bool ret = false; + int addr = 0x1ff; + unsigned int len; + u32 hdr_u32; + u8 *hdr = (u8 *) &hdr_u32; + u8 mac[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06 }; + int mac_start = 2, mac_end = 8; + + BUG_ON(!soc_is_ar933x() && !soc_is_ar934x()); + base = ioremap_nocache(AR933X_WMAC_BASE, AR933X_WMAC_SIZE); + while (addr > sizeof(hdr)) { + if (!ar93xx_wmac_otp_read(base, addr, hdr, sizeof(hdr))) + break; + + if (hdr_u32 == 0 || hdr_u32 == ~0) + break; + + len = (hdr[1] << 4) | (hdr[2] >> 4); + addr -= 4; + + switch (hdr[0] >> 5) { + case 0: + if (len < mac_end) + break; + + ar93xx_wmac_otp_read(base, addr - mac_start, mac, 6); + ret = true; + break; + case 3: + ret |= ar93xx_wmac_otp_uncompress(base, addr, len, mac, + mac_start, 6); + break; + default: + break; + } + + addr -= len + 2; + } + + iounmap(base); + if (ret) + memcpy(dest, mac, 6); + + return ret; +} + void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr) { if (soc_is_ar913x()) --- a/arch/mips/ath79/dev-wmac.h +++ b/arch/mips/ath79/dev-wmac.h @@ -14,5 +14,6 @@ void ath79_register_wmac(u8 *cal_data, u8 *mac_addr); void ath79_register_wmac_simple(void); +bool ar93xx_wmac_read_mac_address(u8 *dest); #endif /* _ATH79_DEV_WMAC_H */ --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -113,6 +113,14 @@ #define QCA955X_EHCI1_BASE 0x1b400000 #define QCA955X_EHCI_SIZE 0x1000 +#define AR9300_OTP_BASE 0x14000 +#define AR9300_OTP_STATUS 0x15f18 +#define AR9300_OTP_STATUS_TYPE 0x7 +#define AR9300_OTP_STATUS_VALID 0x4 +#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 +#define AR9300_OTP_STATUS_SM_BUSY 0x1 +#define AR9300_OTP_READ_DATA 0x15f1c + /* * DDR_CTRL block */ .2&id=75b5f4a6b45e5e901ff6ec33310c5c19bbb5dd47'>brcm63xx/patches-3.1/008-usb-ehci-support.patch
blob: e7f1f47309e6cd3af2cf4c9a90069048bb56e918 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117