ar71xx: build image for the TL-MR3220 v2
[openwrt.git] / 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 @@ -139,6 +139,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   */