mt76: add usb implementation of {wr,rd}_rp
Add USB implementation for read and write reg pair routines. The actual implementation can use mcu related routines according to MCU state Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
db0f04f324
commit
f1638c7cd6
7 changed files with 149 additions and 83 deletions
|
@ -650,6 +650,14 @@ int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
|
||||||
int cmd, bool wait_resp);
|
int cmd, bool wait_resp);
|
||||||
int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
|
int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
|
||||||
int cmd, bool wait_resp);
|
int cmd, bool wait_resp);
|
||||||
|
int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
const struct mt76_reg_pair *data, int n);
|
||||||
|
int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
struct mt76_reg_pair *data, int n);
|
||||||
|
int mt76u_wr_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
const struct mt76_reg_pair *data, int n);
|
||||||
|
int mt76u_rd_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
struct mt76_reg_pair *data, int n);
|
||||||
void mt76u_mcu_fw_reset(struct mt76_dev *dev);
|
void mt76u_mcu_fw_reset(struct mt76_dev *dev);
|
||||||
int mt76u_mcu_init_rx(struct mt76_dev *dev);
|
int mt76u_mcu_init_rx(struct mt76_dev *dev);
|
||||||
void mt76u_mcu_deinit(struct mt76_dev *dev);
|
void mt76u_mcu_deinit(struct mt76_dev *dev);
|
||||||
|
|
|
@ -154,8 +154,9 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
|
||||||
mt76_wr(dev, MT_USB_DMA_CFG, val);
|
mt76_wr(dev, MT_USB_DMA_CFG, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RANDOM_WRITE(dev, tab) \
|
#define RANDOM_WRITE(dev, tab) \
|
||||||
mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, tab, ARRAY_SIZE(tab));
|
mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_WLAN, \
|
||||||
|
tab, ARRAY_SIZE(tab))
|
||||||
|
|
||||||
static int mt76x0_init_bbp(struct mt76x0_dev *dev)
|
static int mt76x0_init_bbp(struct mt76x0_dev *dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -78,79 +78,6 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val)
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
|
|
||||||
const struct mt76_reg_pair *data, int n)
|
|
||||||
{
|
|
||||||
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
int cnt, i, ret;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cnt = min(max_vals_per_cmd, n);
|
|
||||||
|
|
||||||
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
|
|
||||||
if (!skb)
|
|
||||||
return -ENOMEM;
|
|
||||||
skb_reserve(skb, MT_DMA_HDR_LEN);
|
|
||||||
|
|
||||||
for (i = 0; i < cnt; i++) {
|
|
||||||
skb_put_le32(skb, base + data[i].reg);
|
|
||||||
skb_put_le32(skb, data[i].value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_WRITE,
|
|
||||||
cnt == n);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return mt76x0_write_reg_pairs(dev, base, data + cnt, n - cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
|
|
||||||
struct mt76_reg_pair *data, int n)
|
|
||||||
{
|
|
||||||
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
|
|
||||||
struct mt76_usb *usb = &dev->mt76.usb;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
int cnt, i, ret;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cnt = min(max_vals_per_cmd, n);
|
|
||||||
if (cnt != n)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
|
|
||||||
if (!skb)
|
|
||||||
return -ENOMEM;
|
|
||||||
skb_reserve(skb, MT_DMA_HDR_LEN);
|
|
||||||
|
|
||||||
for (i = 0; i < cnt; i++) {
|
|
||||||
skb_put_le32(skb, base + data[i].reg);
|
|
||||||
skb_put_le32(skb, data[i].value);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&usb->mcu.mutex);
|
|
||||||
|
|
||||||
usb->mcu.rp = data;
|
|
||||||
usb->mcu.rp_len = n;
|
|
||||||
usb->mcu.base = base;
|
|
||||||
usb->mcu.burst = false;
|
|
||||||
|
|
||||||
ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_READ,
|
|
||||||
true);
|
|
||||||
|
|
||||||
usb->mcu.rp = NULL;
|
|
||||||
|
|
||||||
mutex_unlock(&usb->mcu.mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
|
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
|
||||||
const u32 *data, int n)
|
const u32 *data, int n)
|
||||||
{
|
{
|
||||||
|
|
|
@ -126,10 +126,6 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev);
|
||||||
#define mt76_rmw_field(_dev, _reg, _field, _val) \
|
#define mt76_rmw_field(_dev, _reg, _field, _val) \
|
||||||
mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
|
mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
|
||||||
|
|
||||||
int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
|
|
||||||
const struct mt76_reg_pair *data, int len);
|
|
||||||
int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
|
|
||||||
struct mt76_reg_pair *data, int len);
|
|
||||||
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
|
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
|
||||||
const u32 *data, int n);
|
const u32 *data, int n);
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val)
|
||||||
.value = val,
|
.value = val,
|
||||||
};
|
};
|
||||||
|
|
||||||
return mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
|
return mt76u_wr_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1);
|
||||||
} else {
|
} else {
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
return mt76x0_rf_csr_wr(dev, offset, val);
|
return mt76x0_rf_csr_wr(dev, offset, val);
|
||||||
|
@ -135,7 +135,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset)
|
||||||
.reg = offset,
|
.reg = offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = mt76x0_read_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
|
ret = mt76u_rd_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1);
|
||||||
val = pair.value;
|
val = pair.value;
|
||||||
} else {
|
} else {
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
|
@ -175,8 +175,9 @@ rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RF_RANDOM_WRITE(dev, tab) \
|
#define RF_RANDOM_WRITE(dev, tab) \
|
||||||
mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));
|
mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_RF, \
|
||||||
|
tab, ARRAY_SIZE(tab))
|
||||||
|
|
||||||
int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev)
|
int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,6 +186,60 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mt76u_single_wr);
|
EXPORT_SYMBOL_GPL(mt76u_single_wr);
|
||||||
|
|
||||||
|
static int
|
||||||
|
mt76u_req_wr_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
const struct mt76_reg_pair *data, int len)
|
||||||
|
{
|
||||||
|
struct mt76_usb *usb = &dev->usb;
|
||||||
|
|
||||||
|
mutex_lock(&usb->usb_ctrl_mtx);
|
||||||
|
while (len > 0) {
|
||||||
|
__mt76u_wr(dev, base + data->reg, data->value);
|
||||||
|
len--;
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
mutex_unlock(&usb->usb_ctrl_mtx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mt76u_wr_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
const struct mt76_reg_pair *data, int n)
|
||||||
|
{
|
||||||
|
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
|
||||||
|
return mt76u_mcu_wr_rp(dev, base, data, n);
|
||||||
|
else
|
||||||
|
return mt76u_req_wr_rp(dev, base, data, n);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mt76u_wr_rp);
|
||||||
|
|
||||||
|
static int
|
||||||
|
mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
struct mt76_usb *usb = &dev->usb;
|
||||||
|
|
||||||
|
mutex_lock(&usb->usb_ctrl_mtx);
|
||||||
|
while (len > 0) {
|
||||||
|
data->value = __mt76u_rr(dev, base + data->reg);
|
||||||
|
len--;
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
mutex_unlock(&usb->usb_ctrl_mtx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mt76u_rd_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
struct mt76_reg_pair *data, int n)
|
||||||
|
{
|
||||||
|
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
|
||||||
|
return mt76u_mcu_rd_rp(dev, base, data, n);
|
||||||
|
else
|
||||||
|
return mt76u_req_rd_rp(dev, base, data, n);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mt76u_rd_rp);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mt76u_set_endpoints(struct usb_interface *intf,
|
mt76u_set_endpoints(struct usb_interface *intf,
|
||||||
struct mt76_usb *usb)
|
struct mt76_usb *usb)
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
|
#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
|
||||||
|
|
||||||
|
#define MT_INBAND_PACKET_MAX_LEN 192
|
||||||
|
|
||||||
struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len)
|
struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
@ -178,6 +180,83 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg);
|
EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg);
|
||||||
|
|
||||||
|
static inline void skb_put_le32(struct sk_buff *skb, u32 val)
|
||||||
|
{
|
||||||
|
put_unaligned_le32(val, skb_put(skb, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
const struct mt76_reg_pair *data, int n)
|
||||||
|
{
|
||||||
|
const int CMD_RANDOM_WRITE = 12;
|
||||||
|
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int cnt, i, ret;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cnt = min(max_vals_per_cmd, n);
|
||||||
|
|
||||||
|
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
skb_reserve(skb, MT_DMA_HDR_LEN);
|
||||||
|
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
skb_put_le32(skb, base + data[i].reg);
|
||||||
|
skb_put_le32(skb, data[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return mt76u_mcu_wr_rp(dev, base, data + cnt, n - cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base,
|
||||||
|
struct mt76_reg_pair *data, int n)
|
||||||
|
{
|
||||||
|
const int CMD_RANDOM_READ = 10;
|
||||||
|
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
|
||||||
|
struct mt76_usb *usb = &dev->usb;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int cnt, i, ret;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cnt = min(max_vals_per_cmd, n);
|
||||||
|
if (cnt != n)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
skb_reserve(skb, MT_DMA_HDR_LEN);
|
||||||
|
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
skb_put_le32(skb, base + data[i].reg);
|
||||||
|
skb_put_le32(skb, data[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&usb->mcu.mutex);
|
||||||
|
|
||||||
|
usb->mcu.rp = data;
|
||||||
|
usb->mcu.rp_len = n;
|
||||||
|
usb->mcu.base = base;
|
||||||
|
usb->mcu.burst = false;
|
||||||
|
|
||||||
|
ret = __mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true);
|
||||||
|
|
||||||
|
usb->mcu.rp = NULL;
|
||||||
|
|
||||||
|
mutex_unlock(&usb->mcu.mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void mt76u_mcu_fw_reset(struct mt76_dev *dev)
|
void mt76u_mcu_fw_reset(struct mt76_dev *dev)
|
||||||
{
|
{
|
||||||
mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
|
mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
|
||||||
|
|
Loading…
Reference in a new issue