xref: /linux/drivers/net/wireless/mediatek/mt76/mmio.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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 
mt76_mmio_rr(struct mt76_dev * dev,u32 offset)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 
mt76_mmio_wr(struct mt76_dev * dev,u32 offset,u32 val)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 
mt76_mmio_rmw(struct mt76_dev * dev,u32 offset,u32 mask,u32 val)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 
mt76_mmio_write_copy(struct mt76_dev * dev,u32 offset,const void * data,int len)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 + 4 <= len; i += 4)
39 		writel(get_unaligned_le32(data + i),
40 		       dev->mmio.regs + offset + i);
41 
42 	if (i < len) {
43 		u8 tmp[4] = {};
44 
45 		memcpy(tmp, data + i, len - i);
46 		writel(get_unaligned_le32(tmp), dev->mmio.regs + offset + i);
47 	}
48 }
49 
mt76_mmio_read_copy(struct mt76_dev * dev,u32 offset,void * data,int len)50 static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
51 				void *data, int len)
52 {
53 	int i;
54 
55 	for (i = 0; i + 4 <= len; i += 4)
56 		put_unaligned_le32(readl(dev->mmio.regs + offset + i),
57 				   data + i);
58 
59 	if (i < len) {
60 		u8 tmp[4];
61 
62 		put_unaligned_le32(readl(dev->mmio.regs + offset + i), tmp);
63 		memcpy(data + i, tmp, len - i);
64 	}
65 }
66 
mt76_mmio_wr_rp(struct mt76_dev * dev,u32 base,const struct mt76_reg_pair * data,int len)67 static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
68 			   const struct mt76_reg_pair *data, int len)
69 {
70 	while (len > 0) {
71 		mt76_mmio_wr(dev, data->reg, data->value);
72 		data++;
73 		len--;
74 	}
75 
76 	return 0;
77 }
78 
mt76_mmio_rd_rp(struct mt76_dev * dev,u32 base,struct mt76_reg_pair * data,int len)79 static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base,
80 			   struct mt76_reg_pair *data, int len)
81 {
82 	while (len > 0) {
83 		data->value = mt76_mmio_rr(dev, data->reg);
84 		data++;
85 		len--;
86 	}
87 
88 	return 0;
89 }
90 
mt76_set_irq_mask(struct mt76_dev * dev,u32 addr,u32 clear,u32 set)91 void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
92 		       u32 clear, u32 set)
93 {
94 	unsigned long flags;
95 
96 	spin_lock_irqsave(&dev->mmio.irq_lock, flags);
97 	dev->mmio.irqmask &= ~clear;
98 	dev->mmio.irqmask |= set;
99 	if (addr) {
100 		if (mtk_wed_device_active(&dev->mmio.wed))
101 			mtk_wed_device_irq_set_mask(&dev->mmio.wed,
102 						    dev->mmio.irqmask);
103 		else
104 			mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
105 	}
106 	spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
107 }
108 EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
109 
mt76_mmio_init(struct mt76_dev * dev,void __iomem * regs)110 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
111 {
112 	static const struct mt76_bus_ops mt76_mmio_ops = {
113 		.rr = mt76_mmio_rr,
114 		.rmw = mt76_mmio_rmw,
115 		.wr = mt76_mmio_wr,
116 		.write_copy = mt76_mmio_write_copy,
117 		.read_copy = mt76_mmio_read_copy,
118 		.wr_rp = mt76_mmio_wr_rp,
119 		.rd_rp = mt76_mmio_rd_rp,
120 		.type = MT76_BUS_MMIO,
121 	};
122 
123 	dev->bus = &mt76_mmio_ops;
124 	dev->mmio.regs = regs;
125 
126 	spin_lock_init(&dev->mmio.irq_lock);
127 }
128 EXPORT_SYMBOL_GPL(mt76_mmio_init);
129