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