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 "rt2860_io.h"
20 #include "rt2860_reg.h"
27 * RT2860_IO_EEPROM_RAISE_CLK
29 #define RT2860_IO_EEPROM_RAISE_CLK(sc, val) \
32 (val) |= RT2860_REG_EESK; \
34 rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val)); \
40 * RT2860_IO_EEPROM_LOWER_CLK
42 #define RT2860_IO_EEPROM_LOWER_CLK(sc, val) \
45 (val) &= ~RT2860_REG_EESK; \
47 rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val)); \
52 #define RT2860_IO_BYTE_CRC16(byte, crc) \
53 ((uint16_t) (((crc) << 8) ^ rt2860_io_ccitt16[(((crc) >> 8) ^ (byte)) & 255]))
56 * Static function prototypes
59 static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc
*sc
,
60 uint16_t val
, uint16_t count
);
62 static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc
*sc
);
64 static uint8_t rt2860_io_byte_rev(uint8_t byte
);
70 static const uint16_t rt2860_io_ccitt16
[] =
72 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
73 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
74 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
75 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
76 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
77 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
78 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
79 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
80 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
81 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
82 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
83 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
84 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
85 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
86 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
87 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
88 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
89 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
90 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
91 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
92 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
93 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
94 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
95 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
96 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
97 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
98 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
99 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
100 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
101 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
102 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
103 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
109 uint32_t rt2860_io_mac_read(struct rt2860_softc
*sc
, uint16_t reg
)
111 return bus_space_read_4(sc
->bst
, sc
->bsh
, reg
);
115 * rt2860_io_mac_read_multi
117 void rt2860_io_mac_read_multi(struct rt2860_softc
*sc
,
118 uint16_t reg
, void *buf
, size_t len
)
120 bus_space_read_region_1(sc
->bst
, sc
->bsh
, reg
, buf
, len
);
124 * rt2860_io_mac_write
126 void rt2860_io_mac_write(struct rt2860_softc
*sc
,
127 uint16_t reg
, uint32_t val
)
129 bus_space_write_4(sc
->bst
, sc
->bsh
, reg
, val
);
133 * rt2860_io_mac_write_multi
135 void rt2860_io_mac_write_multi(struct rt2860_softc
*sc
,
136 uint16_t reg
, const void *buf
, size_t len
)
138 bus_space_write_region_1(sc
->bst
, sc
->bsh
, reg
, buf
, len
);
142 * rt2860_io_mac_set_region_4
144 void rt2860_io_mac_set_region_4(struct rt2860_softc
*sc
,
145 uint16_t reg
, uint32_t val
, size_t len
)
149 for (i
= 0; i
< len
; i
+= sizeof(uint32_t))
150 rt2860_io_mac_write(sc
, reg
+ i
, val
);
154 * rt2860_io_eeprom_read
156 uint16_t rt2860_io_eeprom_read(struct rt2860_softc
*sc
, uint16_t addr
)
163 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
165 tmp
&= ~(RT2860_REG_EEDI
| RT2860_REG_EEDO
| RT2860_REG_EESK
);
166 tmp
|= RT2860_REG_EECS
;
168 rt2860_io_mac_write(sc
, RT2860_REG_EEPROM_CSR
, tmp
);
170 if (((sc
->mac_rev
& 0xffff0000) != 0x30710000) &&
171 ((sc
->mac_rev
& 0xffff0000) != 0x30900000) &&
172 ((sc
->mac_rev
& 0xffff0000) != 0x35720000) &&
173 ((sc
->mac_rev
& 0xffff0000) != 0x33900000))
175 RT2860_IO_EEPROM_RAISE_CLK(sc
, tmp
);
176 RT2860_IO_EEPROM_LOWER_CLK(sc
, tmp
);
179 rt2860_io_eeprom_shiftout_bits(sc
, RT2860_REG_EEOP_READ
, 3);
180 rt2860_io_eeprom_shiftout_bits(sc
, addr
, sc
->eeprom_addr_num
);
182 val
= rt2860_io_eeprom_shiftin_bits(sc
);
184 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
186 tmp
&= ~(RT2860_REG_EECS
| RT2860_REG_EEDI
);
188 rt2860_io_mac_write(sc
, RT2860_REG_EEPROM_CSR
, tmp
);
190 RT2860_IO_EEPROM_RAISE_CLK(sc
, tmp
);
191 RT2860_IO_EEPROM_LOWER_CLK(sc
, tmp
);
197 * rt2860_io_eeprom_read_multi
199 void rt2860_io_eeprom_read_multi(struct rt2860_softc
*sc
,
200 uint16_t addr
, void *buf
, size_t len
)
205 len
+= len
% sizeof(uint16_t);
212 *ptr
++ = rt2860_io_eeprom_read(sc
, addr
+ i
);
214 i
+= sizeof(uint16_t);
215 len
-= sizeof(uint16_t);
222 uint8_t rt2860_io_bbp_read(struct rt2860_softc
*sc
, uint8_t reg
)
227 for (ntries
= 0; ntries
< 100; ntries
++)
229 if (!(rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
) &
230 RT2860_REG_BBP_CSR_BUSY
))
238 printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
239 device_get_nameunit(sc
->dev
), reg
);
243 tmp
= RT2860_REG_BBP_RW_MODE_PARALLEL
|
244 RT2860_REG_BBP_CSR_BUSY
|
245 RT2860_REG_BBP_CSR_READ
|
246 ((reg
& RT2860_REG_BBP_REG_MASK
) << RT2860_REG_BBP_REG_SHIFT
);
248 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
, tmp
);
250 rt2860_io_mcu_cmd(sc
, RT2860_IO_MCU_CMD_BBP
,
251 RT2860_REG_H2M_TOKEN_NO_INTR
, 0);
255 for (ntries
= 0; ntries
< 100; ntries
++)
257 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
);
258 if (!(tmp
& RT2860_REG_BBP_CSR_BUSY
))
259 return ((tmp
>> RT2860_REG_BBP_VAL_SHIFT
) &
260 RT2860_REG_BBP_VAL_MASK
);
265 printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
266 device_get_nameunit(sc
->dev
), reg
);
272 * rt2860_io_bbp_write
274 void rt2860_io_bbp_write(struct rt2860_softc
*sc
, uint8_t reg
, uint8_t val
)
279 for (ntries
= 0; ntries
< 100; ntries
++)
281 if (!(rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
) &
282 RT2860_REG_BBP_CSR_BUSY
))
290 printf("%s: could not write to BBP through MCU: reg=0x%02x\n",
291 device_get_nameunit(sc
->dev
), reg
);
295 tmp
= RT2860_REG_BBP_RW_MODE_PARALLEL
|
296 RT2860_REG_BBP_CSR_BUSY
|
297 ((reg
& RT2860_REG_BBP_REG_MASK
) << RT2860_REG_BBP_REG_SHIFT
) |
298 ((val
& RT2860_REG_BBP_VAL_MASK
) << RT2860_REG_BBP_VAL_SHIFT
);
300 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
, tmp
);
302 rt2860_io_mcu_cmd(sc
, RT2860_IO_MCU_CMD_BBP
,
303 RT2860_REG_H2M_TOKEN_NO_INTR
, 0);
311 void rt2860_io_rf_write(struct rt2860_softc
*sc
, uint8_t reg
, uint32_t val
)
315 for (ntries
= 0; ntries
< 100; ntries
++)
316 if (!(rt2860_io_mac_read(sc
, RT2860_REG_RF_CSR_CFG0
) &
322 printf("%s: could not write to RF: reg=0x%02x\n",
323 device_get_nameunit(sc
->dev
), reg
);
327 rt2860_io_mac_write(sc
, RT2860_REG_RF_CSR_CFG0
, val
);
333 void rt2860_io_mcu_cmd(struct rt2860_softc
*sc
, uint8_t cmd
,
334 uint8_t token
, uint16_t arg
)
339 for (ntries
= 0; ntries
< 100; ntries
++)
341 if (!(rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX
) &
342 RT2860_REG_H2M_BUSY
))
350 printf("%s: could not read H2M: cmd=0x%02x\n",
351 device_get_nameunit(sc
->dev
), cmd
);
355 tmp
= RT2860_REG_H2M_BUSY
| (token
<< 16) | arg
;
357 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX
, tmp
);
358 rt2860_io_mac_write(sc
, RT2860_REG_H2M_HOST_CMD
, cmd
);
362 * rt2860_io_mcu_cmd_check
364 int rt2860_io_mcu_cmd_check(struct rt2860_softc
*sc
, uint8_t cid
)
366 uint32_t tmp
, mask
, status
;
371 for (ntries
= 0; ntries
< 200; ntries
++)
373 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX_CID
);
375 if (((cid
>> RT2860_REG_H2M_CID0_SHIFT
) & RT2860_REG_H2M_CID_MASK
) == cid
)
377 mask
= (RT2860_REG_H2M_CID_MASK
<< RT2860_REG_H2M_CID0_SHIFT
);
380 else if (((tmp
>> RT2860_REG_H2M_CID1_SHIFT
) & RT2860_REG_H2M_CID_MASK
) == cid
)
382 mask
= (RT2860_REG_H2M_CID_MASK
<< RT2860_REG_H2M_CID1_SHIFT
);
385 else if (((tmp
>> RT2860_REG_H2M_CID2_SHIFT
) & RT2860_REG_H2M_CID_MASK
) == cid
)
387 mask
= (RT2860_REG_H2M_CID_MASK
<< RT2860_REG_H2M_CID2_SHIFT
);
390 else if (((tmp
>> RT2860_REG_H2M_CID3_SHIFT
) & RT2860_REG_H2M_CID_MASK
) == cid
)
392 mask
= (RT2860_REG_H2M_CID_MASK
<< RT2860_REG_H2M_CID3_SHIFT
);
399 status
= rt2860_io_mac_read(sc
, RT2860_REG_H2M_MAILBOX_STATUS
);
405 if ((status
== 0x1) ||
407 (status
== 0x10000) ||
408 (status
== 0x1000000))
412 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX_STATUS
, 0xffffffff);
413 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX_CID
, 0xffffffff);
419 * rt2860_io_mcu_load_ucode
421 int rt2860_io_mcu_load_ucode(struct rt2860_softc
*sc
,
422 const uint8_t *ucode
, size_t len
)
427 for (i
= 0, crc
= 0xffff; i
< len
- 2; i
++)
428 crc
= RT2860_IO_BYTE_CRC16(rt2860_io_byte_rev(ucode
[i
]), crc
);
430 if (ucode
[len
- 2] != rt2860_io_byte_rev(crc
>> 8) ||
431 ucode
[len
- 1] != rt2860_io_byte_rev(crc
))
433 printf("%s: wrong microcode crc\n",
434 device_get_nameunit(sc
->dev
));
438 rt2860_io_mac_write(sc
, RT2860_REG_PBF_SYS_CTRL
, RT2860_REG_HST_PM_SEL
);
440 rt2860_io_mac_write_multi(sc
, RT2860_REG_MCU_UCODE_BASE
, ucode
, len
);
442 rt2860_io_mac_write(sc
, RT2860_REG_PBF_SYS_CTRL
, 0);
443 rt2860_io_mac_write(sc
, RT2860_REG_PBF_SYS_CTRL
, RT2860_REG_MCU_RESET
);
445 /* initialize BBP R/W access agent */
447 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX_BBP_AGENT
, 0);
448 rt2860_io_mac_write(sc
, RT2860_REG_H2M_MAILBOX
, 0);
450 for (ntries
= 0; ntries
< 1000; ntries
++)
452 if (rt2860_io_mac_read(sc
, RT2860_REG_PBF_SYS_CTRL
) &
453 RT2860_REG_MCU_READY
)
461 printf("%s: timeout waiting for MCU to initialize\n",
462 device_get_nameunit(sc
->dev
));
470 * rt2860_io_eeprom_shiftout_bits
472 static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc
*sc
,
473 uint16_t val
, uint16_t count
)
477 mask
= (1 << (count
- 1));
479 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
481 tmp
&= ~(RT2860_REG_EEDO
| RT2860_REG_EEDI
);
485 tmp
&= ~RT2860_REG_EEDI
;
488 tmp
|= RT2860_REG_EEDI
;
490 rt2860_io_mac_write(sc
, RT2860_REG_EEPROM_CSR
, tmp
);
492 RT2860_IO_EEPROM_RAISE_CLK(sc
, tmp
);
493 RT2860_IO_EEPROM_LOWER_CLK(sc
, tmp
);
498 tmp
&= ~RT2860_REG_EEDI
;
500 rt2860_io_mac_write(sc
, RT2860_REG_EEPROM_CSR
, tmp
);
504 * rt2860_io_eeprom_shiftin_bits
506 static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc
*sc
)
514 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
516 tmp
&= ~(RT2860_REG_EEDO
| RT2860_REG_EEDI
);
518 for(i
= 0; i
< 16; i
++)
522 RT2860_IO_EEPROM_RAISE_CLK(sc
, tmp
);
524 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
526 RT2860_IO_EEPROM_LOWER_CLK(sc
, tmp
);
528 tmp
&= ~RT2860_REG_EEDI
;
529 if(tmp
& RT2860_REG_EEDO
)
539 static uint8_t rt2860_io_byte_rev(uint8_t byte
)
544 for(i
= 0, tmp
= 0; ; i
++)