1*73b01e57SJeff Chen /* SPDX-License-Identifier: GPL-2.0-only */
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen * NXP Wireless LAN device driver: SDIO specific definitions
4*73b01e57SJeff Chen *
5*73b01e57SJeff Chen * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen */
7*73b01e57SJeff Chen
8*73b01e57SJeff Chen #ifndef _NXPWIFI_SDIO_H
9*73b01e57SJeff Chen #define _NXPWIFI_SDIO_H
10*73b01e57SJeff Chen
11*73b01e57SJeff Chen #include "main.h"
12*73b01e57SJeff Chen
13*73b01e57SJeff Chen #define IW61X_SDIO_FW_NAME "nxp/sd_w61x_v1.bin.se"
14*73b01e57SJeff Chen
15*73b01e57SJeff Chen #define BLOCK_MODE 1
16*73b01e57SJeff Chen #define BYTE_MODE 0
17*73b01e57SJeff Chen
18*73b01e57SJeff Chen #define NXPWIFI_SDIO_IO_PORT_MASK 0xfffff
19*73b01e57SJeff Chen
20*73b01e57SJeff Chen #define NXPWIFI_SDIO_BYTE_MODE_MASK 0x80000000
21*73b01e57SJeff Chen
22*73b01e57SJeff Chen #define NXPWIFI_MAX_FUNC2_REG_NUM 13
23*73b01e57SJeff Chen #define NXPWIFI_SDIO_SCRATCH_SIZE 10
24*73b01e57SJeff Chen
25*73b01e57SJeff Chen #define SDIO_MPA_ADDR_BASE 0x1000
26*73b01e57SJeff Chen
27*73b01e57SJeff Chen #define CMD_PORT_UPLD_INT_MASK (0x1U << 6)
28*73b01e57SJeff Chen #define CMD_PORT_DNLD_INT_MASK (0x1U << 7)
29*73b01e57SJeff Chen #define HOST_TERM_CMD53 (0x1U << 2)
30*73b01e57SJeff Chen #define REG_PORT 0
31*73b01e57SJeff Chen #define MEM_PORT 0x10000
32*73b01e57SJeff Chen
33*73b01e57SJeff Chen #define CMD53_NEW_MODE (0x1U << 0)
34*73b01e57SJeff Chen #define CMD_PORT_RD_LEN_EN (0x1U << 2)
35*73b01e57SJeff Chen #define CMD_PORT_AUTO_EN (0x1U << 0)
36*73b01e57SJeff Chen #define CMD_PORT_SLCT 0x8000
37*73b01e57SJeff Chen #define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U)
38*73b01e57SJeff Chen #define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U)
39*73b01e57SJeff Chen
40*73b01e57SJeff Chen #define NXPWIFI_MP_AGGR_BSIZE_32K (32768)
41*73b01e57SJeff Chen /* we leave one block of 256 bytes for DMA alignment*/
42*73b01e57SJeff Chen #define NXPWIFI_MP_AGGR_BSIZE_MAX (65280)
43*73b01e57SJeff Chen
44*73b01e57SJeff Chen /* Misc. Config Register : Auto Re-enable interrupts */
45*73b01e57SJeff Chen #define AUTO_RE_ENABLE_INT BIT(4)
46*73b01e57SJeff Chen
47*73b01e57SJeff Chen /* Host Control Registers : Configuration */
48*73b01e57SJeff Chen #define CONFIGURATION_REG 0x00
49*73b01e57SJeff Chen /* Host Control Registers : Host power up */
50*73b01e57SJeff Chen #define HOST_POWER_UP (0x1U << 1)
51*73b01e57SJeff Chen
52*73b01e57SJeff Chen /* Host Control Registers : Upload host interrupt mask */
53*73b01e57SJeff Chen #define UP_LD_HOST_INT_MASK (0x1U)
54*73b01e57SJeff Chen /* Host Control Registers : Download host interrupt mask */
55*73b01e57SJeff Chen #define DN_LD_HOST_INT_MASK (0x2U)
56*73b01e57SJeff Chen
57*73b01e57SJeff Chen /* Host Control Registers : Upload host interrupt status */
58*73b01e57SJeff Chen #define UP_LD_HOST_INT_STATUS (0x1U)
59*73b01e57SJeff Chen /* Host Control Registers : Download host interrupt status */
60*73b01e57SJeff Chen #define DN_LD_HOST_INT_STATUS (0x2U)
61*73b01e57SJeff Chen
62*73b01e57SJeff Chen /* Host Control Registers : Host interrupt status */
63*73b01e57SJeff Chen #define CARD_INT_STATUS_REG 0x28
64*73b01e57SJeff Chen
65*73b01e57SJeff Chen /* Card Control Registers : Card I/O ready */
66*73b01e57SJeff Chen #define CARD_IO_READY (0x1U << 3)
67*73b01e57SJeff Chen /* Card Control Registers : Download card ready */
68*73b01e57SJeff Chen #define DN_LD_CARD_RDY (0x1U << 0)
69*73b01e57SJeff Chen
70*73b01e57SJeff Chen /* Max retry number of CMD53 write */
71*73b01e57SJeff Chen #define MAX_WRITE_IOMEM_RETRY 2
72*73b01e57SJeff Chen
73*73b01e57SJeff Chen /* SDIO Tx aggregation in progress ? */
74*73b01e57SJeff Chen #define MP_TX_AGGR_IN_PROGRESS(a) ((a)->mpa_tx.pkt_cnt > 0)
75*73b01e57SJeff Chen
76*73b01e57SJeff Chen /* SDIO Tx aggregation buffer room for next packet ? */
77*73b01e57SJeff Chen #define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ({ \
78*73b01e57SJeff Chen typeof(a) (_a) = a; \
79*73b01e57SJeff Chen (((_a)->mpa_tx.buf_len + (len)) <= (_a)->mpa_tx.buf_size); \
80*73b01e57SJeff Chen })
81*73b01e57SJeff Chen
82*73b01e57SJeff Chen /* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
83*73b01e57SJeff Chen #define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \
84*73b01e57SJeff Chen typeof(a) (_a) = (a); \
85*73b01e57SJeff Chen typeof(pkt_len) (_pkt_len) = pkt_len; \
86*73b01e57SJeff Chen typeof(port) (_port) = port; \
87*73b01e57SJeff Chen memmove(&(_a)->mpa_tx.buf[(_a)->mpa_tx.buf_len], \
88*73b01e57SJeff Chen payload, (_pkt_len)); \
89*73b01e57SJeff Chen (_a)->mpa_tx.buf_len += (_pkt_len); \
90*73b01e57SJeff Chen if (!(_a)->mpa_tx.pkt_cnt) \
91*73b01e57SJeff Chen (_a)->mpa_tx.start_port = (_port); \
92*73b01e57SJeff Chen if ((_a)->mpa_tx.start_port <= (_port)) \
93*73b01e57SJeff Chen (_a)->mpa_tx.ports |= (1 << ((_a)->mpa_tx.pkt_cnt)); \
94*73b01e57SJeff Chen else \
95*73b01e57SJeff Chen (_a)->mpa_tx.ports |= (1 << ((_a)->mpa_tx.pkt_cnt + 1 + \
96*73b01e57SJeff Chen ((_a)->max_ports - \
97*73b01e57SJeff Chen (_a)->mp_end_port))); \
98*73b01e57SJeff Chen (_a)->mpa_tx.pkt_cnt++; \
99*73b01e57SJeff Chen } while (0)
100*73b01e57SJeff Chen
101*73b01e57SJeff Chen /* SDIO Tx aggregation limit ? */
102*73b01e57SJeff Chen #define MP_TX_AGGR_PKT_LIMIT_REACHED(a) ({ \
103*73b01e57SJeff Chen typeof(a) (_a) = a; \
104*73b01e57SJeff Chen ((_a)->mpa_tx.pkt_cnt == (_a)->mpa_tx.pkt_aggr_limit); \
105*73b01e57SJeff Chen })
106*73b01e57SJeff Chen
107*73b01e57SJeff Chen /* Reset SDIO Tx aggregation buffer parameters */
108*73b01e57SJeff Chen #define MP_TX_AGGR_BUF_RESET(a) do { \
109*73b01e57SJeff Chen typeof(a) (_a) = (a); \
110*73b01e57SJeff Chen (_a)->mpa_tx.pkt_cnt = 0; \
111*73b01e57SJeff Chen (_a)->mpa_tx.buf_len = 0; \
112*73b01e57SJeff Chen (_a)->mpa_tx.ports = 0; \
113*73b01e57SJeff Chen (_a)->mpa_tx.start_port = 0; \
114*73b01e57SJeff Chen } while (0)
115*73b01e57SJeff Chen
116*73b01e57SJeff Chen /* SDIO Rx aggregation limit ? */
117*73b01e57SJeff Chen #define MP_RX_AGGR_PKT_LIMIT_REACHED(a) ({ \
118*73b01e57SJeff Chen typeof(a) (_a) = a; \
119*73b01e57SJeff Chen ((_a)->mpa_rx.pkt_cnt == (_a)->mpa_rx.pkt_aggr_limit); \
120*73b01e57SJeff Chen })
121*73b01e57SJeff Chen
122*73b01e57SJeff Chen /* SDIO Rx aggregation in progress ? */
123*73b01e57SJeff Chen #define MP_RX_AGGR_IN_PROGRESS(a) ((a)->mpa_rx.pkt_cnt > 0)
124*73b01e57SJeff Chen
125*73b01e57SJeff Chen /* SDIO Rx aggregation buffer room for next packet ? */
126*73b01e57SJeff Chen #define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) ({ \
127*73b01e57SJeff Chen typeof(a) (_a) = a; \
128*73b01e57SJeff Chen ((((_a)->mpa_rx.buf_len + (rx_len))) <= (_a)->mpa_rx.buf_size); \
129*73b01e57SJeff Chen })
130*73b01e57SJeff Chen
131*73b01e57SJeff Chen /* Reset SDIO Rx aggregation buffer parameters */
132*73b01e57SJeff Chen #define MP_RX_AGGR_BUF_RESET(a) do { \
133*73b01e57SJeff Chen typeof(a) (_a) = (a); \
134*73b01e57SJeff Chen (_a)->mpa_rx.pkt_cnt = 0; \
135*73b01e57SJeff Chen (_a)->mpa_rx.buf_len = 0; \
136*73b01e57SJeff Chen (_a)->mpa_rx.ports = 0; \
137*73b01e57SJeff Chen (_a)->mpa_rx.start_port = 0; \
138*73b01e57SJeff Chen } while (0)
139*73b01e57SJeff Chen
140*73b01e57SJeff Chen /* data structure for SDIO MPA TX */
141*73b01e57SJeff Chen struct nxpwifi_sdio_mpa_tx {
142*73b01e57SJeff Chen /* multiport tx aggregation buffer pointer */
143*73b01e57SJeff Chen u8 *buf;
144*73b01e57SJeff Chen u32 buf_len;
145*73b01e57SJeff Chen u32 pkt_cnt;
146*73b01e57SJeff Chen u32 ports;
147*73b01e57SJeff Chen u16 start_port;
148*73b01e57SJeff Chen u8 enabled;
149*73b01e57SJeff Chen u32 buf_size;
150*73b01e57SJeff Chen u32 pkt_aggr_limit;
151*73b01e57SJeff Chen };
152*73b01e57SJeff Chen
153*73b01e57SJeff Chen struct nxpwifi_sdio_mpa_rx {
154*73b01e57SJeff Chen u8 *buf;
155*73b01e57SJeff Chen u32 buf_len;
156*73b01e57SJeff Chen u32 pkt_cnt;
157*73b01e57SJeff Chen u32 ports;
158*73b01e57SJeff Chen u16 start_port;
159*73b01e57SJeff Chen u32 *len_arr;
160*73b01e57SJeff Chen u8 enabled;
161*73b01e57SJeff Chen u32 buf_size;
162*73b01e57SJeff Chen u32 pkt_aggr_limit;
163*73b01e57SJeff Chen };
164*73b01e57SJeff Chen
165*73b01e57SJeff Chen int nxpwifi_bus_register(void);
166*73b01e57SJeff Chen void nxpwifi_bus_unregister(void);
167*73b01e57SJeff Chen
168*73b01e57SJeff Chen struct nxpwifi_sdio_card_reg {
169*73b01e57SJeff Chen u8 start_rd_port;
170*73b01e57SJeff Chen u8 start_wr_port;
171*73b01e57SJeff Chen u8 base_0_reg;
172*73b01e57SJeff Chen u8 base_1_reg;
173*73b01e57SJeff Chen u8 poll_reg;
174*73b01e57SJeff Chen u8 host_int_enable;
175*73b01e57SJeff Chen u8 host_int_rsr_reg;
176*73b01e57SJeff Chen u8 host_int_status_reg;
177*73b01e57SJeff Chen u8 host_int_mask_reg;
178*73b01e57SJeff Chen u8 host_strap_reg;
179*73b01e57SJeff Chen u8 host_strap_mask;
180*73b01e57SJeff Chen u8 host_strap_value;
181*73b01e57SJeff Chen u8 status_reg_0;
182*73b01e57SJeff Chen u8 status_reg_1;
183*73b01e57SJeff Chen u8 sdio_int_mask;
184*73b01e57SJeff Chen u32 data_port_mask;
185*73b01e57SJeff Chen u8 io_port_0_reg;
186*73b01e57SJeff Chen u8 io_port_1_reg;
187*73b01e57SJeff Chen u8 io_port_2_reg;
188*73b01e57SJeff Chen u8 max_mp_regs;
189*73b01e57SJeff Chen u8 rd_bitmap_l;
190*73b01e57SJeff Chen u8 rd_bitmap_u;
191*73b01e57SJeff Chen u8 rd_bitmap_1l;
192*73b01e57SJeff Chen u8 rd_bitmap_1u;
193*73b01e57SJeff Chen u8 wr_bitmap_l;
194*73b01e57SJeff Chen u8 wr_bitmap_u;
195*73b01e57SJeff Chen u8 wr_bitmap_1l;
196*73b01e57SJeff Chen u8 wr_bitmap_1u;
197*73b01e57SJeff Chen u8 rd_len_p0_l;
198*73b01e57SJeff Chen u8 rd_len_p0_u;
199*73b01e57SJeff Chen u8 card_misc_cfg_reg;
200*73b01e57SJeff Chen u8 card_cfg_2_1_reg;
201*73b01e57SJeff Chen u8 cmd_rd_len_0;
202*73b01e57SJeff Chen u8 cmd_rd_len_1;
203*73b01e57SJeff Chen u8 cmd_rd_len_2;
204*73b01e57SJeff Chen u8 cmd_rd_len_3;
205*73b01e57SJeff Chen u8 cmd_cfg_0;
206*73b01e57SJeff Chen u8 cmd_cfg_1;
207*73b01e57SJeff Chen u8 cmd_cfg_2;
208*73b01e57SJeff Chen u8 cmd_cfg_3;
209*73b01e57SJeff Chen u8 fw_dump_host_ready;
210*73b01e57SJeff Chen u8 fw_dump_ctrl;
211*73b01e57SJeff Chen u8 fw_dump_start;
212*73b01e57SJeff Chen u8 fw_dump_end;
213*73b01e57SJeff Chen u8 func1_dump_reg_start;
214*73b01e57SJeff Chen u8 func1_dump_reg_end;
215*73b01e57SJeff Chen u8 func1_scratch_reg;
216*73b01e57SJeff Chen u8 func1_spec_reg_num;
217*73b01e57SJeff Chen u8 func1_spec_reg_table[NXPWIFI_MAX_FUNC2_REG_NUM];
218*73b01e57SJeff Chen };
219*73b01e57SJeff Chen
220*73b01e57SJeff Chen struct sdio_mmc_card {
221*73b01e57SJeff Chen struct sdio_func *func;
222*73b01e57SJeff Chen struct nxpwifi_adapter *adapter;
223*73b01e57SJeff Chen
224*73b01e57SJeff Chen struct completion fw_done;
225*73b01e57SJeff Chen const char *firmware;
226*73b01e57SJeff Chen const char *firmware_sdiouart;
227*73b01e57SJeff Chen const struct nxpwifi_sdio_card_reg *reg;
228*73b01e57SJeff Chen u8 max_ports;
229*73b01e57SJeff Chen u8 mp_agg_pkt_limit;
230*73b01e57SJeff Chen u16 tx_buf_size;
231*73b01e57SJeff Chen u32 mp_tx_agg_buf_size;
232*73b01e57SJeff Chen u32 mp_rx_agg_buf_size;
233*73b01e57SJeff Chen
234*73b01e57SJeff Chen u32 mp_rd_bitmap;
235*73b01e57SJeff Chen u32 mp_wr_bitmap;
236*73b01e57SJeff Chen
237*73b01e57SJeff Chen u16 mp_end_port;
238*73b01e57SJeff Chen u32 mp_data_port_mask;
239*73b01e57SJeff Chen
240*73b01e57SJeff Chen u8 curr_rd_port;
241*73b01e57SJeff Chen u8 curr_wr_port;
242*73b01e57SJeff Chen
243*73b01e57SJeff Chen u8 *mp_regs;
244*73b01e57SJeff Chen bool can_dump_fw;
245*73b01e57SJeff Chen bool fw_dump_enh;
246*73b01e57SJeff Chen bool can_ext_scan;
247*73b01e57SJeff Chen
248*73b01e57SJeff Chen struct nxpwifi_sdio_mpa_tx mpa_tx;
249*73b01e57SJeff Chen struct nxpwifi_sdio_mpa_rx mpa_rx;
250*73b01e57SJeff Chen
251*73b01e57SJeff Chen struct work_struct work;
252*73b01e57SJeff Chen unsigned long work_flags;
253*73b01e57SJeff Chen };
254*73b01e57SJeff Chen
255*73b01e57SJeff Chen struct nxpwifi_sdio_device {
256*73b01e57SJeff Chen const char *firmware;
257*73b01e57SJeff Chen const char *firmware_sdiouart;
258*73b01e57SJeff Chen const struct nxpwifi_sdio_card_reg *reg;
259*73b01e57SJeff Chen u8 max_ports;
260*73b01e57SJeff Chen u8 mp_agg_pkt_limit;
261*73b01e57SJeff Chen u16 tx_buf_size;
262*73b01e57SJeff Chen u32 mp_tx_agg_buf_size;
263*73b01e57SJeff Chen u32 mp_rx_agg_buf_size;
264*73b01e57SJeff Chen bool can_dump_fw;
265*73b01e57SJeff Chen bool fw_dump_enh;
266*73b01e57SJeff Chen bool can_ext_scan;
267*73b01e57SJeff Chen };
268*73b01e57SJeff Chen
269*73b01e57SJeff Chen /* .cmdrsp_complete handler
270*73b01e57SJeff Chen */
nxpwifi_sdio_cmdrsp_complete(struct nxpwifi_adapter * adapter,struct sk_buff * skb)271*73b01e57SJeff Chen static inline int nxpwifi_sdio_cmdrsp_complete(struct nxpwifi_adapter *adapter,
272*73b01e57SJeff Chen struct sk_buff *skb)
273*73b01e57SJeff Chen {
274*73b01e57SJeff Chen dev_kfree_skb_any(skb);
275*73b01e57SJeff Chen return 0;
276*73b01e57SJeff Chen }
277*73b01e57SJeff Chen
278*73b01e57SJeff Chen /* .event_complete handler
279*73b01e57SJeff Chen */
nxpwifi_sdio_event_complete(struct nxpwifi_adapter * adapter,struct sk_buff * skb)280*73b01e57SJeff Chen static inline int nxpwifi_sdio_event_complete(struct nxpwifi_adapter *adapter,
281*73b01e57SJeff Chen struct sk_buff *skb)
282*73b01e57SJeff Chen {
283*73b01e57SJeff Chen dev_kfree_skb_any(skb);
284*73b01e57SJeff Chen return 0;
285*73b01e57SJeff Chen }
286*73b01e57SJeff Chen
287*73b01e57SJeff Chen static inline bool
mp_rx_aggr_port_limit_reached(struct sdio_mmc_card * card)288*73b01e57SJeff Chen mp_rx_aggr_port_limit_reached(struct sdio_mmc_card *card)
289*73b01e57SJeff Chen {
290*73b01e57SJeff Chen u8 tmp;
291*73b01e57SJeff Chen
292*73b01e57SJeff Chen if (card->curr_rd_port < card->mpa_rx.start_port) {
293*73b01e57SJeff Chen tmp = card->mp_end_port >> 1;
294*73b01e57SJeff Chen
295*73b01e57SJeff Chen if (((card->max_ports - card->mpa_rx.start_port) +
296*73b01e57SJeff Chen card->curr_rd_port) >= tmp)
297*73b01e57SJeff Chen return true;
298*73b01e57SJeff Chen }
299*73b01e57SJeff Chen
300*73b01e57SJeff Chen if ((card->curr_rd_port - card->mpa_rx.start_port) >=
301*73b01e57SJeff Chen (card->mp_end_port >> 1))
302*73b01e57SJeff Chen return true;
303*73b01e57SJeff Chen
304*73b01e57SJeff Chen return false;
305*73b01e57SJeff Chen }
306*73b01e57SJeff Chen
307*73b01e57SJeff Chen static inline bool
mp_tx_aggr_port_limit_reached(struct sdio_mmc_card * card)308*73b01e57SJeff Chen mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card)
309*73b01e57SJeff Chen {
310*73b01e57SJeff Chen u16 tmp;
311*73b01e57SJeff Chen
312*73b01e57SJeff Chen if (card->curr_wr_port < card->mpa_tx.start_port) {
313*73b01e57SJeff Chen tmp = card->mp_end_port >> 1;
314*73b01e57SJeff Chen
315*73b01e57SJeff Chen if (((card->max_ports - card->mpa_tx.start_port) +
316*73b01e57SJeff Chen card->curr_wr_port) >= tmp)
317*73b01e57SJeff Chen return true;
318*73b01e57SJeff Chen }
319*73b01e57SJeff Chen
320*73b01e57SJeff Chen if ((card->curr_wr_port - card->mpa_tx.start_port) >=
321*73b01e57SJeff Chen (card->mp_end_port >> 1))
322*73b01e57SJeff Chen return true;
323*73b01e57SJeff Chen
324*73b01e57SJeff Chen return false;
325*73b01e57SJeff Chen }
326*73b01e57SJeff Chen
327*73b01e57SJeff Chen /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
mp_rx_aggr_setup(struct sdio_mmc_card * card,u16 rx_len,u8 port)328*73b01e57SJeff Chen static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card,
329*73b01e57SJeff Chen u16 rx_len, u8 port)
330*73b01e57SJeff Chen {
331*73b01e57SJeff Chen card->mpa_rx.buf_len += rx_len;
332*73b01e57SJeff Chen
333*73b01e57SJeff Chen if (!card->mpa_rx.pkt_cnt)
334*73b01e57SJeff Chen card->mpa_rx.start_port = port;
335*73b01e57SJeff Chen
336*73b01e57SJeff Chen card->mpa_rx.ports |= (1 << port);
337*73b01e57SJeff Chen card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = rx_len;
338*73b01e57SJeff Chen card->mpa_rx.pkt_cnt++;
339*73b01e57SJeff Chen }
340*73b01e57SJeff Chen #endif /* _NXPWIFI_SDIO_H */
341