3 * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include "rt2870_io.h"
20 #include "rt2870_reg.h"
26 #define RT2870_IO_USB_REQ_MCU_CNTL 0x1
27 #define RT2870_IO_USB_REQ_MAC_WRITE_MULTI 0x2
28 #define RT2870_IO_USB_REQ_MAC_READ_MULTI 0x7
29 #define RT2870_IO_USB_REQ_EEPROM_READ_MULTI 0x9
31 #define RT2870_IO_USB_VALUE_MCU_RESET 0x1
32 #define RT2870_IO_USB_VALUE_MCU_RUN 0x8
34 #define RT2870_IO_BYTE_CRC16(byte, crc) \
35 ((uint16_t) (((crc) << 8) ^ rt2870_io_ccitt16[(((crc) >> 8) ^ (byte)) & 255]))
38 * Static function prototypes
41 static int rt2870_io_vendor_req(struct rt2870_softc
*sc
,
42 uint8_t reqtype
, uint8_t req
, uint16_t value
, uint16_t index
,
43 void *buf
, uint16_t len
);
45 static uint8_t rt2870_io_byte_rev(uint8_t byte
);
51 static const uint16_t rt2870_io_ccitt16
[] =
53 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
54 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
55 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
56 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
57 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
58 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
59 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
60 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
61 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
62 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
63 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
64 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
65 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
66 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
67 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
68 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
69 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
70 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
71 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
72 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
73 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
74 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
75 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
76 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
77 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
78 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
79 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
80 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
81 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
82 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
83 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
84 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
90 uint32_t rt2870_io_mac_read(struct rt2870_softc
*sc
, uint16_t reg
)
94 rt2870_io_mac_read_multi(sc
, reg
, &val
, sizeof(val
));
100 * rt2870_io_mac_read_multi
102 void rt2870_io_mac_read_multi(struct rt2870_softc
*sc
,
103 uint16_t reg
, void *buf
, size_t len
)
107 error
= rt2870_io_vendor_req(sc
, UT_READ_VENDOR_DEVICE
,
108 RT2870_IO_USB_REQ_MAC_READ_MULTI
, 0, reg
, buf
, len
);
110 printf("%s: could not multi read MAC register: reg=0x%04x, error=%s\n",
111 device_get_nameunit(sc
->dev
), reg
, usbd_errstr(error
));
115 * rt2870_io_mac_write
117 void rt2870_io_mac_write(struct rt2870_softc
*sc
,
118 uint16_t reg
, uint32_t val
)
124 rt2870_io_mac_write_multi(sc
, reg
, &tmp
, sizeof(uint32_t));
128 * rt2870_io_mac_write_multi
130 void rt2870_io_mac_write_multi(struct rt2870_softc
*sc
,
131 uint16_t reg
, const void *buf
, size_t len
)
136 len
+= len
% sizeof(uint16_t);
143 error
= rt2870_io_vendor_req(sc
, UT_WRITE_VENDOR_DEVICE
,
144 RT2870_IO_USB_REQ_MAC_WRITE_MULTI
, *ptr
++, reg
+ i
, NULL
, 0);
146 i
+= sizeof(uint16_t);
147 len
-= sizeof(uint16_t);
148 } while (len
> 0 && error
== 0);
151 printf("%s: could not multi write MAC register: reg=0x%04x, error=%s\n",
152 device_get_nameunit(sc
->dev
), reg
, usbd_errstr(error
));
156 * rt2870_io_mac_set_region_4
158 void rt2870_io_mac_set_region_4(struct rt2870_softc
*sc
,
159 uint16_t reg
, uint32_t val
, size_t len
)
163 for (i
= 0; i
< len
; i
+= sizeof(uint32_t))
164 rt2870_io_mac_write(sc
, reg
+ i
, val
);
168 * rt2870_io_eeprom_read
170 uint16_t rt2870_io_eeprom_read(struct rt2870_softc
*sc
, uint16_t addr
)
174 rt2870_io_eeprom_read_multi(sc
, addr
, &val
, sizeof(val
));
180 * rt2870_io_eeprom_read_multi
182 void rt2870_io_eeprom_read_multi(struct rt2870_softc
*sc
,
183 uint16_t addr
, void *buf
, size_t len
)
187 error
= rt2870_io_vendor_req(sc
, UT_READ_VENDOR_DEVICE
,
188 RT2870_IO_USB_REQ_EEPROM_READ_MULTI
, 0, addr
, buf
, len
);
190 printf("%s: could not multi read EEPROM: addr=0x%04x, error=%s\n",
191 device_get_nameunit(sc
->dev
), addr
, usbd_errstr(error
));
197 uint8_t rt2870_io_bbp_read(struct rt2870_softc
*sc
, uint8_t reg
)
202 for (ntries
= 0; ntries
< 10; ntries
++)
203 if (!(rt2870_io_mac_read(sc
, RT2870_REG_BBP_CSR_CFG
) &
204 RT2870_REG_BBP_CSR_BUSY
))
209 printf("%s: could not read BBP: reg=0x%02x\n",
210 device_get_nameunit(sc
->dev
), reg
);
214 val
= RT2870_REG_BBP_CSR_BUSY
|
215 RT2870_REG_BBP_CSR_READ
|
216 ((reg
& RT2870_REG_BBP_REG_MASK
) << RT2870_REG_BBP_REG_SHIFT
);
218 rt2870_io_mac_write(sc
, RT2870_REG_BBP_CSR_CFG
, val
);
220 for (ntries
= 0; ntries
< 10; ntries
++)
222 val
= rt2870_io_mac_read(sc
, RT2870_REG_BBP_CSR_CFG
);
223 if (!(val
& RT2870_REG_BBP_CSR_BUSY
))
224 return ((val
>> RT2870_REG_BBP_VAL_SHIFT
) &
225 RT2870_REG_BBP_VAL_MASK
);
230 printf("%s: could not read BBP: reg=0x%02x\n",
231 device_get_nameunit(sc
->dev
), reg
);
237 * rt2870_io_bbp_write
239 void rt2870_io_bbp_write(struct rt2870_softc
*sc
, uint8_t reg
, uint8_t val
)
244 for (ntries
= 0; ntries
< 10; ntries
++)
245 if (!(rt2870_io_mac_read(sc
, RT2870_REG_BBP_CSR_CFG
) &
246 RT2870_REG_BBP_CSR_BUSY
))
251 printf("%s: could not write to BBP: reg=0x%02x\n",
252 device_get_nameunit(sc
->dev
), reg
);
256 tmp
= RT2870_REG_BBP_CSR_BUSY
|
257 ((reg
& RT2870_REG_BBP_REG_MASK
) << RT2870_REG_BBP_REG_SHIFT
) |
258 ((val
& RT2870_REG_BBP_VAL_MASK
) << RT2870_REG_BBP_VAL_SHIFT
);
260 rt2870_io_mac_write(sc
, RT2870_REG_BBP_CSR_CFG
, tmp
);
266 void rt2870_io_rf_write(struct rt2870_softc
*sc
, uint8_t reg
, uint32_t val
)
270 for (ntries
= 0; ntries
< 10; ntries
++)
271 if (!(rt2870_io_mac_read(sc
, RT2870_REG_RF_CSR_CFG0
) &
277 printf("%s: could not write to RF: reg=0x%02x\n",
278 device_get_nameunit(sc
->dev
), reg
);
282 rt2870_io_mac_write(sc
, RT2870_REG_RF_CSR_CFG0
, val
);
288 void rt2870_io_mcu_cmd(struct rt2870_softc
*sc
, uint8_t cmd
,
289 uint8_t token
, uint16_t arg
)
294 for (ntries
= 0; ntries
< 100; ntries
++)
296 if (!(rt2870_io_mac_read(sc
, RT2870_REG_H2M_MAILBOX
) &
297 RT2870_REG_H2M_BUSY
))
305 printf("%s: could not read H2M: cmd=0x%02x\n",
306 device_get_nameunit(sc
->dev
), cmd
);
310 tmp
= RT2870_REG_H2M_BUSY
| (token
<< 16) | arg
;
312 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX
, tmp
);
313 rt2870_io_mac_write(sc
, RT2870_REG_H2M_HOST_CMD
, cmd
);
317 * rt2870_io_mcu_load_ucode
319 int rt2870_io_mcu_load_ucode(struct rt2870_softc
*sc
,
320 const uint8_t *ucode
, size_t len
)
322 int i
, error
, ntries
;
325 for (i
= 0, crc
= 0xffff; i
< len
- 2; i
++)
326 crc
= RT2870_IO_BYTE_CRC16(rt2870_io_byte_rev(ucode
[i
]), crc
);
328 if (ucode
[len
- 2] != rt2870_io_byte_rev(crc
>> 8) ||
329 ucode
[len
- 1] != rt2870_io_byte_rev(crc
))
331 printf("%s: wrong microcode crc\n",
332 device_get_nameunit(sc
->dev
));
336 rt2870_io_mac_write_multi(sc
, RT2870_REG_MCU_UCODE_BASE
, ucode
, len
);
338 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX_CID
, 0xffffffff);
339 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX_STATUS
, 0xffffffff);
341 error
= rt2870_io_vendor_req(sc
, UT_WRITE_VENDOR_DEVICE
,
342 RT2870_IO_USB_REQ_MCU_CNTL
, RT2870_IO_USB_VALUE_MCU_RUN
, 0, NULL
, 0);
345 printf("%s: could not run firmware: error=%s\n",
346 device_get_nameunit(sc
->dev
), usbd_errstr(error
));
350 for (ntries
= 0; ntries
< 1000; ntries
++)
352 if (rt2870_io_mac_read(sc
, RT2870_REG_PBF_SYS_CTRL
) &
353 RT2870_REG_MCU_READY
)
361 printf("%s: timeout waiting for MCU to initialize\n",
362 device_get_nameunit(sc
->dev
));
370 * rt2870_io_mcu_reset
372 int rt2870_io_mcu_reset(struct rt2870_softc
*sc
)
374 return rt2870_io_vendor_req(sc
, UT_WRITE_VENDOR_DEVICE
,
375 RT2870_IO_USB_REQ_MCU_CNTL
, RT2870_IO_USB_VALUE_MCU_RESET
, 0, NULL
, 0);
379 * rt2870_io_vendor_req
381 static int rt2870_io_vendor_req(struct rt2870_softc
*sc
,
382 uint8_t reqtype
, uint8_t req
, uint16_t value
, uint16_t index
,
383 void *buf
, uint16_t len
)
385 struct usb_device_request usb_req
;
389 for (ntries
= 0; ntries
< 10; ntries
++)
391 usb_req
.bmRequestType
= reqtype
;
392 usb_req
.bRequest
= req
;
393 USETW(usb_req
.wValue
, value
);
394 USETW(usb_req
.wIndex
, index
);
395 USETW(usb_req
.wLength
, len
);
397 error
= usbd_do_request_flags(sc
->usb_dev
, &sc
->lock
, &usb_req
, buf
,
411 static uint8_t rt2870_io_byte_rev(uint8_t byte
)
416 for(i
= 0, tmp
= 0; ; i
++)