2 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <linux/kernel.h>
19 #include <linux/firmware.h>
20 #include <linux/delay.h>
22 #include "mt76x02_mcu.h"
24 int mt76x02_mcu_msg_send(struct mt76_dev
*mdev
, int cmd
, const void *data
,
25 int len
, bool wait_resp
)
27 struct mt76x02_dev
*dev
= container_of(mdev
, struct mt76x02_dev
, mt76
);
28 unsigned long expires
= jiffies
+ HZ
;
34 skb
= mt76x02_mcu_msg_alloc(data
, len
);
38 mutex_lock(&mdev
->mmio
.mcu
.mutex
);
40 seq
= ++mdev
->mmio
.mcu
.msg_seq
& 0xf;
42 seq
= ++mdev
->mmio
.mcu
.msg_seq
& 0xf;
44 tx_info
= MT_MCU_MSG_TYPE_CMD
|
45 FIELD_PREP(MT_MCU_MSG_CMD_TYPE
, cmd
) |
46 FIELD_PREP(MT_MCU_MSG_CMD_SEQ
, seq
) |
47 FIELD_PREP(MT_MCU_MSG_PORT
, CPU_TX_PORT
) |
48 FIELD_PREP(MT_MCU_MSG_LEN
, skb
->len
);
50 ret
= mt76_tx_queue_skb_raw(dev
, MT_TXQ_MCU
, skb
, tx_info
);
56 bool check_seq
= false;
58 skb
= mt76_mcu_get_response(&dev
->mt76
, expires
);
61 "MCU message %d (seq %d) timed out\n", cmd
,
68 rxfce
= (u32
*) skb
->cb
;
70 if (seq
== FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ
, *rxfce
))
79 mutex_unlock(&mdev
->mmio
.mcu
.mutex
);
83 EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send
);
85 int mt76x02_mcu_function_select(struct mt76x02_dev
*dev
, enum mcu_function func
,
91 } __packed
__aligned(4) msg
= {
92 .id
= cpu_to_le32(func
),
93 .value
= cpu_to_le32(val
),
100 return mt76_mcu_send_msg(dev
, CMD_FUN_SET_OP
, &msg
, sizeof(msg
), wait
);
102 EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select
);
104 int mt76x02_mcu_set_radio_state(struct mt76x02_dev
*dev
, bool on
)
109 } __packed
__aligned(4) msg
= {
110 .mode
= cpu_to_le32(on
? RADIO_ON
: RADIO_OFF
),
111 .level
= cpu_to_le32(0),
114 return mt76_mcu_send_msg(dev
, CMD_POWER_SAVING_OP
, &msg
, sizeof(msg
), false);
116 EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state
);
118 int mt76x02_mcu_calibrate(struct mt76x02_dev
*dev
, int type
, u32 param
)
123 } __packed
__aligned(4) msg
= {
124 .id
= cpu_to_le32(type
),
125 .value
= cpu_to_le32(param
),
127 bool is_mt76x2e
= mt76_is_mmio(dev
) && is_mt76x2(dev
);
131 mt76_rmw(dev
, MT_MCU_COM_REG0
, BIT(31), 0);
133 ret
= mt76_mcu_send_msg(dev
, CMD_CALIBRATION_OP
, &msg
, sizeof(msg
),
139 WARN_ON(!mt76_poll_msec(dev
, MT_MCU_COM_REG0
,
140 BIT(31), BIT(31), 100)))
145 EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate
);
147 int mt76x02_mcu_cleanup(struct mt76x02_dev
*dev
)
151 mt76_wr(dev
, MT_MCU_INT_LEVEL
, 1);
152 usleep_range(20000, 30000);
154 while ((skb
= skb_dequeue(&dev
->mt76
.mmio
.mcu
.res_q
)) != NULL
)
159 EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup
);
161 void mt76x02_set_ethtool_fwver(struct mt76x02_dev
*dev
,
162 const struct mt76x02_fw_header
*h
)
164 u16 bld
= le16_to_cpu(h
->build_ver
);
165 u16 ver
= le16_to_cpu(h
->fw_ver
);
167 snprintf(dev
->mt76
.hw
->wiphy
->fw_version
,
168 sizeof(dev
->mt76
.hw
->wiphy
->fw_version
),
170 (ver
>> 12) & 0xf, (ver
>> 8) & 0xf, ver
& 0xf, bld
);
172 EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver
);