hc
2024-03-22 a0752693d998599af469473b8dc239ef973a012f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/**
 ******************************************************************************
 *
 * @file rwnx_dini.c - Add support for dini platform
 *
 * Copyright (C) RivieraWaves 2012-2019
 *
 ******************************************************************************
 */
 
#include "rwnx_dini.h"
#include "rwnx_defs.h"
#include "rwnx_irqs.h"
#include "reg_access.h"
 
/* Config FPGA is accessed via bar0 */
#define CFPGA_DMA0_CTRL_REG             0x02C
#define CFPGA_DMA1_CTRL_REG             0x04C
#define CFPGA_DMA2_CTRL_REG             0x06C
#define CFPGA_UINTR_SRC_REG             0x0E8
#define CFPGA_UINTR_MASK_REG            0x0EC
#define CFPGA_BAR4_HIADDR_REG           0x100
#define CFPGA_BAR4_LOADDR_REG           0x104
#define CFPGA_BAR4_LOADDR_MASK_REG      0x110
#define CFPGA_BAR_TOUT                  0x120
 
#define CFPGA_DMA_CTRL_ENABLE           0x00001400
#define CFPGA_DMA_CTRL_DISABLE          0x00001000
#define CFPGA_DMA_CTRL_CLEAR            0x00001800
#define CFPGA_DMA_CTRL_REREAD_TIME_MASK (BIT(10) - 1)
 
#define CFPGA_BAR4_LOADDR_MASK_MAX      0xFF000000
 
#define CFPGA_PCIEX_IT                  0x00000001
#define CFPGA_ALL_ITS                   0x0000000F
 
/* Programmable BAR4 Window start address */
#define CPU_RAM_WINDOW_HIGH      0x00000000
#define CPU_RAM_WINDOW_LOW       0x00000000
#define AHB_BRIDGE_WINDOW_HIGH   0x00000000
#define AHB_BRIDGE_WINDOW_LOW    0x60000000
 
struct rwnx_dini {
   u8 *pci_bar0_vaddr;
   u8 *pci_bar4_vaddr;
};
 
static const u32 mv_cfg_fpga_dma_ctrl_regs[] = {
   CFPGA_DMA0_CTRL_REG,
   CFPGA_DMA1_CTRL_REG,
   CFPGA_DMA2_CTRL_REG
};
 
/* This also clears running transactions */
static void dini_dma_on(struct rwnx_dini *rwnx_dini)
{
   int i;
   u32 reread_time;
   volatile void *reg;
 
   for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
       reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
       reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
 
       writel(CFPGA_DMA_CTRL_CLEAR  | reread_time, reg);
       writel(CFPGA_DMA_CTRL_ENABLE | reread_time, reg);
   }
}
 
/* This also clears running transactions */
static void dini_dma_off(struct rwnx_dini *rwnx_dini)
{
   int i;
   u32 reread_time;
   volatile void *reg;
 
   for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
       reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
       reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
 
       writel(CFPGA_DMA_CTRL_DISABLE | reread_time, reg);
       writel(CFPGA_DMA_CTRL_CLEAR   | reread_time, reg);
   }
}
 
 
/* Configure address range for BAR4.
 * By default BAR4_LOADDR_MASK value is 0xFF000000, then there is no need to
 * change it because the addresses we need to access are covered by this mask
 */
static void dini_set_bar4_win(u32 low, u32 high, struct rwnx_dini *rwnx_dini)
{
   writel(low, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_REG);
   writel(high, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_HIADDR_REG);
   writel(CFPGA_BAR4_LOADDR_MASK_MAX,
          rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_MASK_REG);
}
 
 
/**
 * Enable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
 * and request the corresponding IRQ line
 */
int rwnx_cfpga_irq_enable(struct rwnx_hw *rwnx_hw)
{
   struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
   unsigned int cfpga_uintr_mask;
   volatile void *reg;
   int ret;
 
   /* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */
   ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, "rwnx", rwnx_hw);
   if (ret)
       return ret;
 
   reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
   cfpga_uintr_mask = readl(reg);
   writel(cfpga_uintr_mask | CFPGA_PCIEX_IT, reg);
 
   return ret;
}
 
/**
 * Disable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
 * and free the corresponding IRQ line
 */
int rwnx_cfpga_irq_disable(struct rwnx_hw *rwnx_hw)
{
   struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
   unsigned int cfpga_uintr_mask;
   volatile void *reg;
 
   reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
   cfpga_uintr_mask = readl(reg);
   writel(cfpga_uintr_mask & ~CFPGA_PCIEX_IT, reg);
 
   free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw);
 
   return 0;
}
 
static int rwnx_dini_platform_enable(struct rwnx_hw *rwnx_hw)
{
   struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
 
#ifdef CONFIG_RWNX_SDM
   writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
#endif
 
   dini_dma_on(rwnx_dini);
   return rwnx_cfpga_irq_enable(rwnx_hw);
}
 
static int rwnx_dini_platform_disable(struct rwnx_hw *rwnx_hw)
{
   struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
   int ret;
 
   ret = rwnx_cfpga_irq_disable(rwnx_hw);
   dini_dma_off(rwnx_dini);
   return ret;
}
 
static void rwnx_dini_platform_deinit(struct rwnx_plat *rwnx_plat)
{
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
 
   pci_disable_device(rwnx_plat->pci_dev);
   iounmap(rwnx_dini->pci_bar0_vaddr);
   iounmap(rwnx_dini->pci_bar4_vaddr);
   pci_release_regions(rwnx_plat->pci_dev);
 
   kfree(rwnx_plat);
}
 
static u8 *rwnx_dini_get_address(struct rwnx_plat *rwnx_plat, int addr_name,
                                unsigned int offset)
{
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
 
   if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name))
       return NULL;
 
   if (addr_name == RWNX_ADDR_CPU)
       dini_set_bar4_win(CPU_RAM_WINDOW_LOW, CPU_RAM_WINDOW_HIGH, rwnx_dini);
   else
       dini_set_bar4_win(AHB_BRIDGE_WINDOW_LOW, AHB_BRIDGE_WINDOW_HIGH, rwnx_dini);
 
   return rwnx_dini->pci_bar4_vaddr + offset;
}
 
static void rwnx_dini_ack_irq(struct rwnx_plat *rwnx_plat)
{
   struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
 
   writel(CFPGA_ALL_ITS, rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_SRC_REG);
}
 
static const u32 rwnx_dini_config_reg[] = {
   NXMAC_DEBUG_PORT_SEL_ADDR,
   SYSCTRL_DIAG_CONF_ADDR,
   RF_V6_DIAGPORT_CONF1_ADDR,
   RF_v6_PHYDIAG_CONF1_ADDR,
};
 
static int rwnx_dini_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list)
{
   if (!list)
       return 0;
 
   *list = rwnx_dini_config_reg;
   return ARRAY_SIZE(rwnx_dini_config_reg);
}
 
/**
 * rwnx_dini_platform_init - Initialize the DINI platform
 *
 * @pci_dev PCI device
 * @rwnx_plat Pointer on struct rwnx_stat * to be populated
 *
 * @return 0 on success, < 0 otherwise
 *
 * Allocate and initialize a rwnx_plat structure for the dini platform.
 */
int rwnx_dini_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat)
{
   struct rwnx_dini *rwnx_dini;
   u16 pci_cmd;
   int ret = 0;
 
   *rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_dini),
                       GFP_KERNEL);
   if (!*rwnx_plat)
       return -ENOMEM;
 
   rwnx_dini = (struct rwnx_dini *)(*rwnx_plat)->priv;
 
   /* Hotplug fixups */
   pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
   pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
   pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
   pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
 
   ret = pci_enable_device(pci_dev);
   if (ret) {
       dev_err(&(pci_dev->dev), "pci_enable_device failed\n");
       goto out_enable;
   }
 
   pci_set_master(pci_dev);
 
   ret = pci_request_regions(pci_dev, KBUILD_MODNAME);
   if (ret) {
       dev_err(&(pci_dev->dev), "pci_request_regions failed\n");
       goto out_request;
   }
 
   rwnx_dini->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0);
   if (!rwnx_dini->pci_bar0_vaddr) {
       dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0);
       ret = -ENOMEM;
       goto out_bar0;
   }
   rwnx_dini->pci_bar4_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 4);
   if (!rwnx_dini->pci_bar4_vaddr) {
       dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 4);
       ret = -ENOMEM;
       goto out_bar4;
   }
 
   (*rwnx_plat)->enable = rwnx_dini_platform_enable;
   (*rwnx_plat)->disable = rwnx_dini_platform_disable;
   (*rwnx_plat)->deinit = rwnx_dini_platform_deinit;
   (*rwnx_plat)->get_address = rwnx_dini_get_address;
   (*rwnx_plat)->ack_irq = rwnx_dini_ack_irq;
   (*rwnx_plat)->get_config_reg = rwnx_dini_get_config_reg;
 
#ifdef CONFIG_RWNX_SDM
   writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
#endif
 
   return 0;
 
out_bar4:
   iounmap(rwnx_dini->pci_bar0_vaddr);
out_bar0:
   pci_release_regions(pci_dev);
out_request:
   pci_disable_device(pci_dev);
out_enable:
   kfree(*rwnx_plat);
   return ret;
}