1 // SPDX-License-Identifier: ISC
3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
7 #include <linux/kernel.h>
8 #include <linux/firmware.h>
9 #include <linux/delay.h>
11 #include "mt76x02_mcu.h"
13 int mt76x02_mcu_parse_response(struct mt76_dev
*mdev
, int cmd
,
14 struct sk_buff
*skb
, int seq
)
16 struct mt76x02_dev
*dev
= container_of(mdev
, struct mt76x02_dev
, mt76
);
21 "MCU message %d (seq %d) timed out\n", cmd
,
27 rxfce
= (u32
*)skb
->cb
;
28 if (seq
!= FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ
, *rxfce
))
33 EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response
);
35 int mt76x02_mcu_msg_send(struct mt76_dev
*mdev
, int cmd
, const void *data
,
36 int len
, bool wait_resp
)
38 struct mt76x02_dev
*dev
= container_of(mdev
, struct mt76x02_dev
, mt76
);
39 unsigned long expires
= jiffies
+ HZ
;
48 skb
= mt76_mcu_msg_alloc(mdev
, data
, len
);
52 mutex_lock(&mdev
->mcu
.mutex
);
54 seq
= ++mdev
->mcu
.msg_seq
& 0xf;
56 seq
= ++mdev
->mcu
.msg_seq
& 0xf;
58 tx_info
= MT_MCU_MSG_TYPE_CMD
|
59 FIELD_PREP(MT_MCU_MSG_CMD_TYPE
, cmd
) |
60 FIELD_PREP(MT_MCU_MSG_CMD_SEQ
, seq
) |
61 FIELD_PREP(MT_MCU_MSG_PORT
, CPU_TX_PORT
) |
62 FIELD_PREP(MT_MCU_MSG_LEN
, skb
->len
);
64 ret
= mt76_tx_queue_skb_raw(dev
, mdev
->q_mcu
[MT_MCUQ_WM
], skb
, tx_info
);
69 skb
= mt76_mcu_get_response(&dev
->mt76
, expires
);
70 ret
= mt76x02_mcu_parse_response(mdev
, cmd
, skb
, seq
);
77 mutex_unlock(&mdev
->mcu
.mutex
);
81 EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send
);
83 int mt76x02_mcu_function_select(struct mt76x02_dev
*dev
, enum mcu_function func
,
89 } __packed
__aligned(4) msg
= {
90 .id
= cpu_to_le32(func
),
91 .value
= cpu_to_le32(val
),
98 return mt76_mcu_send_msg(&dev
->mt76
, CMD_FUN_SET_OP
, &msg
,
101 EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select
);
103 int mt76x02_mcu_set_radio_state(struct mt76x02_dev
*dev
, bool on
)
108 } __packed
__aligned(4) msg
= {
109 .mode
= cpu_to_le32(on
? RADIO_ON
: RADIO_OFF
),
110 .level
= cpu_to_le32(0),
113 return mt76_mcu_send_msg(&dev
->mt76
, CMD_POWER_SAVING_OP
, &msg
,
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
->mt76
) && is_mt76x2(dev
);
131 mt76_rmw(dev
, MT_MCU_COM_REG0
, BIT(31), 0);
133 ret
= mt76_mcu_send_msg(&dev
->mt76
, CMD_CALIBRATION_OP
, &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
.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
);