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: %s\n",
111 device_get_nameunit(sc
->dev
), 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: %s\n",
152 device_get_nameunit(sc
->dev
), 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: %s\n",
191 device_get_nameunit(sc
->dev
), 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\n",
210 device_get_nameunit(sc
->dev
));
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\n", device_get_nameunit(sc
->dev
));
236 * rt2870_io_bbp_write
238 void rt2870_io_bbp_write(struct rt2870_softc
*sc
, uint8_t reg
, uint8_t val
)
243 for (ntries
= 0; ntries
< 10; ntries
++)
244 if (!(rt2870_io_mac_read(sc
, RT2870_REG_BBP_CSR_CFG
) &
245 RT2870_REG_BBP_CSR_BUSY
))
250 printf("%s: could not write to BBP\n",
251 device_get_nameunit(sc
->dev
));
255 tmp
= RT2870_REG_BBP_CSR_BUSY
|
256 ((reg
& RT2870_REG_BBP_REG_MASK
) << RT2870_REG_BBP_REG_SHIFT
) |
257 ((val
& RT2870_REG_BBP_VAL_MASK
) << RT2870_REG_BBP_VAL_SHIFT
);
259 rt2870_io_mac_write(sc
, RT2870_REG_BBP_CSR_CFG
, tmp
);
265 void rt2870_io_rf_write(struct rt2870_softc
*sc
, uint8_t reg
, uint32_t val
)
269 for (ntries
= 0; ntries
< 10; ntries
++)
270 if (!(rt2870_io_mac_read(sc
, RT2870_REG_RF_CSR_CFG0
) &
276 printf("%s: could not write to RF\n",
277 device_get_nameunit(sc
->dev
));
281 rt2870_io_mac_write(sc
, RT2870_REG_RF_CSR_CFG0
, val
);
287 void rt2870_io_mcu_cmd(struct rt2870_softc
*sc
, uint8_t cmd
,
288 uint8_t token
, uint16_t arg
)
293 for (ntries
= 0; ntries
< 100; ntries
++)
295 if (!(rt2870_io_mac_read(sc
, RT2870_REG_H2M_MAILBOX
) &
296 RT2870_REG_H2M_BUSY
))
304 printf("%s: could not read H2M\n",
305 device_get_nameunit(sc
->dev
));
309 tmp
= RT2870_REG_H2M_BUSY
| (token
<< 16) | arg
;
311 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX
, tmp
);
312 rt2870_io_mac_write(sc
, RT2870_REG_H2M_HOST_CMD
, cmd
);
316 * rt2870_io_mcu_load_ucode
318 int rt2870_io_mcu_load_ucode(struct rt2870_softc
*sc
,
319 const uint8_t *ucode
, size_t len
)
321 int i
, error
, ntries
;
324 for (i
= 0, crc
= 0xffff; i
< len
- 2; i
++)
325 crc
= RT2870_IO_BYTE_CRC16(rt2870_io_byte_rev(ucode
[i
]), crc
);
327 if (ucode
[len
- 2] != rt2870_io_byte_rev(crc
>> 8) ||
328 ucode
[len
- 1] != rt2870_io_byte_rev(crc
))
330 printf("%s: wrong microcode crc\n",
331 device_get_nameunit(sc
->dev
));
335 rt2870_io_mac_write_multi(sc
, RT2870_REG_MCU_UCODE_BASE
, ucode
, len
);
337 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX_CID
, 0xffffffff);
338 rt2870_io_mac_write(sc
, RT2870_REG_H2M_MAILBOX_STATUS
, 0xffffffff);
340 error
= rt2870_io_vendor_req(sc
, UT_WRITE_VENDOR_DEVICE
,
341 RT2870_IO_USB_REQ_MCU_CNTL
, RT2870_IO_USB_VALUE_MCU_RUN
, 0, NULL
, 0);
344 printf("%s: could not run firmware: %s\n",
345 device_get_nameunit(sc
->dev
), usbd_errstr(error
));
349 for (ntries
= 0; ntries
< 1000; ntries
++)
351 if (rt2870_io_mac_read(sc
, RT2870_REG_PBF_SYS_CTRL
) &
352 RT2870_REG_MCU_READY
)
360 printf("%s: timeout waiting for MCU to initialize\n",
361 device_get_nameunit(sc
->dev
));
369 * rt2870_io_mcu_reset
371 int rt2870_io_mcu_reset(struct rt2870_softc
*sc
)
373 return rt2870_io_vendor_req(sc
, UT_WRITE_VENDOR_DEVICE
,
374 RT2870_IO_USB_REQ_MCU_CNTL
, RT2870_IO_USB_VALUE_MCU_RESET
, 0, NULL
, 0);
378 * rt2870_io_vendor_req
380 static int rt2870_io_vendor_req(struct rt2870_softc
*sc
,
381 uint8_t reqtype
, uint8_t req
, uint16_t value
, uint16_t index
,
382 void *buf
, uint16_t len
)
384 usb_device_request_t usb_req
;
388 for (ntries
= 0; ntries
< 10; ntries
++)
390 usb_req
.bmRequestType
= reqtype
;
391 usb_req
.bRequest
= req
;
392 USETW(usb_req
.wValue
, value
);
393 USETW(usb_req
.wIndex
, index
);
394 USETW(usb_req
.wLength
, len
);
396 error
= usbd_do_request(sc
->usb_dev
, &usb_req
, buf
);
409 static uint8_t rt2870_io_byte_rev(uint8_t byte
)
414 for(i
= 0, tmp
= 0; ; i
++)