xref: /linux/drivers/net/wireless/mediatek/mt76/mmio.c (revision 8f7aa3d3c7323f4ca2768a9e74ebbe359c4f8f88)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
4  */
5 
6 #include "mt76.h"
7 #include "dma.h"
8 #include "trace.h"
9 
10 static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
11 {
12 	u32 val;
13 
14 	val = readl(dev->mmio.regs + offset);
15 	trace_reg_rr(dev, offset, val);
16 
17 	return val;
18 }
19 
20 static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val)
21 {
22 	trace_reg_wr(dev, offset, val);
23 	writel(val, dev->mmio.regs + offset);
24 }
25 
26 static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
27 {
28 	val |= mt76_mmio_rr(dev, offset) & ~mask;
29 	mt76_mmio_wr(dev, offset, val);
30 	return val;
31 }
32 
33 static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset,
34 				 const void *data, int len)
35 {
36 	int i;
37 
38 	for (i = 0; i < ALIGN(len, 4); i += 4)
39 		writel(get_unaligned_le32(data + i),
40 		       dev->mmio.regs + offset + i);
41 }
42 
43 static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
44 				void *data, int len)
45 {
46 	int i;
47 
48 	for (i = 0; i < ALIGN(len, 4); i += 4)
49 		put_unaligned_le32(readl(dev->mmio.regs + offset + i),
50 				   data + i);
51 }
52 
53 static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
54 			   const struct mt76_reg_pair *data, int len)
55 {
56 	while (len > 0) {
57 		mt76_mmio_wr(dev, data->reg, data->value);
58 		data++;
59 		len--;
60 	}
61 
62 	return 0;
63 }
64 
65 static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base,
66 			   struct mt76_reg_pair *data, int len)
67 {
68 	while (len > 0) {
69 		data->value = mt76_mmio_rr(dev, data->reg);
70 		data++;
71 		len--;
72 	}
73 
74 	return 0;
75 }
76 
77 void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
78 		       u32 clear, u32 set)
79 {
80 	unsigned long flags;
81 
82 	spin_lock_irqsave(&dev->mmio.irq_lock, flags);
83 	dev->mmio.irqmask &= ~clear;
84 	dev->mmio.irqmask |= set;
85 	if (addr) {
86 		if (mtk_wed_device_active(&dev->mmio.wed))
87 			mtk_wed_device_irq_set_mask(&dev->mmio.wed,
88 						    dev->mmio.irqmask);
89 		else
90 			mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
91 	}
92 	spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
93 }
94 EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
95 
96 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
97 {
98 	static const struct mt76_bus_ops mt76_mmio_ops = {
99 		.rr = mt76_mmio_rr,
100 		.rmw = mt76_mmio_rmw,
101 		.wr = mt76_mmio_wr,
102 		.write_copy = mt76_mmio_write_copy,
103 		.read_copy = mt76_mmio_read_copy,
104 		.wr_rp = mt76_mmio_wr_rp,
105 		.rd_rp = mt76_mmio_rd_rp,
106 		.type = MT76_BUS_MMIO,
107 	};
108 
109 	dev->bus = &mt76_mmio_ops;
110 	dev->mmio.regs = regs;
111 
112 	spin_lock_init(&dev->mmio.irq_lock);
113 }
114 EXPORT_SYMBOL_GPL(mt76_mmio_init);
115