xref: /src/sys/contrib/dev/mediatek/mt76/mmio.c (revision fa3519d068d95f87e773d27f96e9f1e18f70075a)
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 #if defined(__linux__)
15 	val = readl(dev->mmio.regs + offset);
16 #elif defined(__FreeBSD__)
17 	val = readl((u8 *)dev->mmio.regs + offset);
18 #endif
19 	trace_reg_rr(dev, offset, val);
20 
21 	return val;
22 }
23 
24 static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val)
25 {
26 	trace_reg_wr(dev, offset, val);
27 #if defined(__linux__)
28 	writel(val, dev->mmio.regs + offset);
29 #elif defined(__FreeBSD__)
30 	writel(val, (u8 *)dev->mmio.regs + offset);
31 #endif
32 }
33 
34 static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
35 {
36 	val |= mt76_mmio_rr(dev, offset) & ~mask;
37 	mt76_mmio_wr(dev, offset, val);
38 	return val;
39 }
40 
41 static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset,
42 				 const void *data, int len)
43 {
44 	int i;
45 
46 	for (i = 0; i < ALIGN(len, 4); i += 4)
47 #if defined(__linux__)
48 		writel(get_unaligned_le32(data + i),
49 		       dev->mmio.regs + offset + i);
50 #elif defined(__FreeBSD__)
51 		writel(get_unaligned_le32((const u8 *)data + i),
52 		       (u8 *)dev->mmio.regs + offset + i);
53 #endif
54 }
55 
56 static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
57 				void *data, int len)
58 {
59 	int i;
60 
61 	for (i = 0; i < ALIGN(len, 4); i += 4)
62 #if defined(__linux__)
63 		put_unaligned_le32(readl(dev->mmio.regs + offset + i),
64 				   data + i);
65 #elif defined(__FreeBSD__)
66 		put_unaligned_le32(readl((u8 *)dev->mmio.regs + offset + i),
67 				   (u8 *)data + i);
68 #endif
69 }
70 
71 static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
72 			   const struct mt76_reg_pair *data, int len)
73 {
74 	while (len > 0) {
75 		mt76_mmio_wr(dev, data->reg, data->value);
76 		data++;
77 		len--;
78 	}
79 
80 	return 0;
81 }
82 
83 static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base,
84 			   struct mt76_reg_pair *data, int len)
85 {
86 	while (len > 0) {
87 		data->value = mt76_mmio_rr(dev, data->reg);
88 		data++;
89 		len--;
90 	}
91 
92 	return 0;
93 }
94 
95 void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
96 		       u32 clear, u32 set)
97 {
98 	unsigned long flags;
99 
100 	spin_lock_irqsave(&dev->mmio.irq_lock, flags);
101 	dev->mmio.irqmask &= ~clear;
102 	dev->mmio.irqmask |= set;
103 	if (addr) {
104 		if (mtk_wed_device_active(&dev->mmio.wed))
105 			mtk_wed_device_irq_set_mask(&dev->mmio.wed,
106 						    dev->mmio.irqmask);
107 		else
108 			mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
109 	}
110 	spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
111 }
112 EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
113 
114 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
115 {
116 	static const struct mt76_bus_ops mt76_mmio_ops = {
117 		.rr = mt76_mmio_rr,
118 		.rmw = mt76_mmio_rmw,
119 		.wr = mt76_mmio_wr,
120 		.write_copy = mt76_mmio_write_copy,
121 		.read_copy = mt76_mmio_read_copy,
122 		.wr_rp = mt76_mmio_wr_rp,
123 		.rd_rp = mt76_mmio_rd_rp,
124 		.type = MT76_BUS_MMIO,
125 	};
126 
127 	dev->bus = &mt76_mmio_ops;
128 	dev->mmio.regs = regs;
129 
130 	spin_lock_init(&dev->mmio.irq_lock);
131 }
132 EXPORT_SYMBOL_GPL(mt76_mmio_init);
133