1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun * Marvell BT-over-SDIO driver: SDIO interface related functions.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2009, Marvell International Ltd.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This software file (the "File") is distributed by Marvell International
7*4882a593Smuzhiyun * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8*4882a593Smuzhiyun * (the "License"). You may use, redistribute and/or modify this File in
9*4882a593Smuzhiyun * accordance with the terms and conditions of the License, a copy of which
10*4882a593Smuzhiyun * is available by writing to the Free Software Foundation, Inc.,
11*4882a593Smuzhiyun * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12*4882a593Smuzhiyun * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16*4882a593Smuzhiyun * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17*4882a593Smuzhiyun * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18*4882a593Smuzhiyun * this warranty disclaimer.
19*4882a593Smuzhiyun **/
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/firmware.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/suspend.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <linux/mmc/sdio_ids.h>
26*4882a593Smuzhiyun #include <linux/mmc/sdio_func.h>
27*4882a593Smuzhiyun #include <linux/module.h>
28*4882a593Smuzhiyun #include <linux/devcoredump.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
31*4882a593Smuzhiyun #include <net/bluetooth/hci_core.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include "btmrvl_drv.h"
34*4882a593Smuzhiyun #include "btmrvl_sdio.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define VERSION "1.0"
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static struct memory_type_mapping mem_type_mapping_tbl[] = {
39*4882a593Smuzhiyun {"ITCM", NULL, 0, 0xF0},
40*4882a593Smuzhiyun {"DTCM", NULL, 0, 0xF1},
41*4882a593Smuzhiyun {"SQRAM", NULL, 0, 0xF2},
42*4882a593Smuzhiyun {"APU", NULL, 0, 0xF3},
43*4882a593Smuzhiyun {"CIU", NULL, 0, 0xF4},
44*4882a593Smuzhiyun {"ICU", NULL, 0, 0xF5},
45*4882a593Smuzhiyun {"MAC", NULL, 0, 0xF6},
46*4882a593Smuzhiyun {"EXT7", NULL, 0, 0xF7},
47*4882a593Smuzhiyun {"EXT8", NULL, 0, 0xF8},
48*4882a593Smuzhiyun {"EXT9", NULL, 0, 0xF9},
49*4882a593Smuzhiyun {"EXT10", NULL, 0, 0xFA},
50*4882a593Smuzhiyun {"EXT11", NULL, 0, 0xFB},
51*4882a593Smuzhiyun {"EXT12", NULL, 0, 0xFC},
52*4882a593Smuzhiyun {"EXT13", NULL, 0, 0xFD},
53*4882a593Smuzhiyun {"EXTLAST", NULL, 0, 0xFE},
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static const struct of_device_id btmrvl_sdio_of_match_table[] = {
57*4882a593Smuzhiyun { .compatible = "marvell,sd8897-bt" },
58*4882a593Smuzhiyun { .compatible = "marvell,sd8997-bt" },
59*4882a593Smuzhiyun { }
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
btmrvl_wake_irq_bt(int irq,void * priv)62*4882a593Smuzhiyun static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv;
65*4882a593Smuzhiyun struct device *dev = &card->func->dev;
66*4882a593Smuzhiyun struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun dev_info(dev, "wake by bt\n");
69*4882a593Smuzhiyun cfg->wake_by_bt = true;
70*4882a593Smuzhiyun disable_irq_nosync(irq);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun pm_wakeup_event(dev, 0);
73*4882a593Smuzhiyun pm_system_wakeup();
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return IRQ_HANDLED;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* This function parses device tree node using mmc subnode devicetree API.
79*4882a593Smuzhiyun * The device node is saved in card->plt_of_node.
80*4882a593Smuzhiyun * If the device tree node exists and includes interrupts attributes, this
81*4882a593Smuzhiyun * function will request platform specific wakeup interrupt.
82*4882a593Smuzhiyun */
btmrvl_sdio_probe_of(struct device * dev,struct btmrvl_sdio_card * card)83*4882a593Smuzhiyun static int btmrvl_sdio_probe_of(struct device *dev,
84*4882a593Smuzhiyun struct btmrvl_sdio_card *card)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct btmrvl_plt_wake_cfg *cfg;
87*4882a593Smuzhiyun int ret;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (!dev->of_node ||
90*4882a593Smuzhiyun !of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
91*4882a593Smuzhiyun dev_info(dev, "sdio device tree data not available\n");
92*4882a593Smuzhiyun return -1;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun card->plt_of_node = dev->of_node;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg),
98*4882a593Smuzhiyun GFP_KERNEL);
99*4882a593Smuzhiyun cfg = card->plt_wake_cfg;
100*4882a593Smuzhiyun if (cfg && card->plt_of_node) {
101*4882a593Smuzhiyun cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
102*4882a593Smuzhiyun if (!cfg->irq_bt) {
103*4882a593Smuzhiyun dev_err(dev, "fail to parse irq_bt from device tree\n");
104*4882a593Smuzhiyun cfg->irq_bt = -1;
105*4882a593Smuzhiyun } else {
106*4882a593Smuzhiyun ret = devm_request_irq(dev, cfg->irq_bt,
107*4882a593Smuzhiyun btmrvl_wake_irq_bt,
108*4882a593Smuzhiyun 0, "bt_wake", card);
109*4882a593Smuzhiyun if (ret) {
110*4882a593Smuzhiyun dev_err(dev,
111*4882a593Smuzhiyun "Failed to request irq_bt %d (%d)\n",
112*4882a593Smuzhiyun cfg->irq_bt, ret);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* Configure wakeup (enabled by default) */
116*4882a593Smuzhiyun device_init_wakeup(dev, true);
117*4882a593Smuzhiyun disable_irq(cfg->irq_bt);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* The btmrvl_sdio_remove() callback function is called
125*4882a593Smuzhiyun * when user removes this module from kernel space or ejects
126*4882a593Smuzhiyun * the card from the slot. The driver handles these 2 cases
127*4882a593Smuzhiyun * differently.
128*4882a593Smuzhiyun * If the user is removing the module, a MODULE_SHUTDOWN_REQ
129*4882a593Smuzhiyun * command is sent to firmware and interrupt will be disabled.
130*4882a593Smuzhiyun * If the card is removed, there is no need to send command
131*4882a593Smuzhiyun * or disable interrupt.
132*4882a593Smuzhiyun *
133*4882a593Smuzhiyun * The variable 'user_rmmod' is used to distinguish these two
134*4882a593Smuzhiyun * scenarios. This flag is initialized as FALSE in case the card
135*4882a593Smuzhiyun * is removed, and will be set to TRUE for module removal when
136*4882a593Smuzhiyun * module_exit function is called.
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun static u8 user_rmmod;
139*4882a593Smuzhiyun static u8 sdio_ireg;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
142*4882a593Smuzhiyun .cfg = 0x03,
143*4882a593Smuzhiyun .host_int_mask = 0x04,
144*4882a593Smuzhiyun .host_intstatus = 0x05,
145*4882a593Smuzhiyun .card_status = 0x20,
146*4882a593Smuzhiyun .sq_read_base_addr_a0 = 0x10,
147*4882a593Smuzhiyun .sq_read_base_addr_a1 = 0x11,
148*4882a593Smuzhiyun .card_fw_status0 = 0x40,
149*4882a593Smuzhiyun .card_fw_status1 = 0x41,
150*4882a593Smuzhiyun .card_rx_len = 0x42,
151*4882a593Smuzhiyun .card_rx_unit = 0x43,
152*4882a593Smuzhiyun .io_port_0 = 0x00,
153*4882a593Smuzhiyun .io_port_1 = 0x01,
154*4882a593Smuzhiyun .io_port_2 = 0x02,
155*4882a593Smuzhiyun .int_read_to_clear = false,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
158*4882a593Smuzhiyun .cfg = 0x00,
159*4882a593Smuzhiyun .host_int_mask = 0x02,
160*4882a593Smuzhiyun .host_intstatus = 0x03,
161*4882a593Smuzhiyun .card_status = 0x30,
162*4882a593Smuzhiyun .sq_read_base_addr_a0 = 0x40,
163*4882a593Smuzhiyun .sq_read_base_addr_a1 = 0x41,
164*4882a593Smuzhiyun .card_revision = 0x5c,
165*4882a593Smuzhiyun .card_fw_status0 = 0x60,
166*4882a593Smuzhiyun .card_fw_status1 = 0x61,
167*4882a593Smuzhiyun .card_rx_len = 0x62,
168*4882a593Smuzhiyun .card_rx_unit = 0x63,
169*4882a593Smuzhiyun .io_port_0 = 0x78,
170*4882a593Smuzhiyun .io_port_1 = 0x79,
171*4882a593Smuzhiyun .io_port_2 = 0x7a,
172*4882a593Smuzhiyun .int_read_to_clear = false,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = {
176*4882a593Smuzhiyun .cfg = 0x00,
177*4882a593Smuzhiyun .host_int_mask = 0x08,
178*4882a593Smuzhiyun .host_intstatus = 0x0C,
179*4882a593Smuzhiyun .card_status = 0x5C,
180*4882a593Smuzhiyun .sq_read_base_addr_a0 = 0x6C,
181*4882a593Smuzhiyun .sq_read_base_addr_a1 = 0x6D,
182*4882a593Smuzhiyun .card_revision = 0xC8,
183*4882a593Smuzhiyun .card_fw_status0 = 0x88,
184*4882a593Smuzhiyun .card_fw_status1 = 0x89,
185*4882a593Smuzhiyun .card_rx_len = 0x8A,
186*4882a593Smuzhiyun .card_rx_unit = 0x8B,
187*4882a593Smuzhiyun .io_port_0 = 0xE4,
188*4882a593Smuzhiyun .io_port_1 = 0xE5,
189*4882a593Smuzhiyun .io_port_2 = 0xE6,
190*4882a593Smuzhiyun .int_read_to_clear = true,
191*4882a593Smuzhiyun .host_int_rsr = 0x04,
192*4882a593Smuzhiyun .card_misc_cfg = 0xD8,
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
196*4882a593Smuzhiyun .cfg = 0x00,
197*4882a593Smuzhiyun .host_int_mask = 0x02,
198*4882a593Smuzhiyun .host_intstatus = 0x03,
199*4882a593Smuzhiyun .card_status = 0x50,
200*4882a593Smuzhiyun .sq_read_base_addr_a0 = 0x60,
201*4882a593Smuzhiyun .sq_read_base_addr_a1 = 0x61,
202*4882a593Smuzhiyun .card_revision = 0xbc,
203*4882a593Smuzhiyun .card_fw_status0 = 0xc0,
204*4882a593Smuzhiyun .card_fw_status1 = 0xc1,
205*4882a593Smuzhiyun .card_rx_len = 0xc2,
206*4882a593Smuzhiyun .card_rx_unit = 0xc3,
207*4882a593Smuzhiyun .io_port_0 = 0xd8,
208*4882a593Smuzhiyun .io_port_1 = 0xd9,
209*4882a593Smuzhiyun .io_port_2 = 0xda,
210*4882a593Smuzhiyun .int_read_to_clear = true,
211*4882a593Smuzhiyun .host_int_rsr = 0x01,
212*4882a593Smuzhiyun .card_misc_cfg = 0xcc,
213*4882a593Smuzhiyun .fw_dump_ctrl = 0xe2,
214*4882a593Smuzhiyun .fw_dump_start = 0xe3,
215*4882a593Smuzhiyun .fw_dump_end = 0xea,
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun static const struct btmrvl_sdio_card_reg btmrvl_reg_89xx = {
219*4882a593Smuzhiyun .cfg = 0x00,
220*4882a593Smuzhiyun .host_int_mask = 0x08,
221*4882a593Smuzhiyun .host_intstatus = 0x0c,
222*4882a593Smuzhiyun .card_status = 0x5c,
223*4882a593Smuzhiyun .sq_read_base_addr_a0 = 0xf8,
224*4882a593Smuzhiyun .sq_read_base_addr_a1 = 0xf9,
225*4882a593Smuzhiyun .card_revision = 0xc8,
226*4882a593Smuzhiyun .card_fw_status0 = 0xe8,
227*4882a593Smuzhiyun .card_fw_status1 = 0xe9,
228*4882a593Smuzhiyun .card_rx_len = 0xea,
229*4882a593Smuzhiyun .card_rx_unit = 0xeb,
230*4882a593Smuzhiyun .io_port_0 = 0xe4,
231*4882a593Smuzhiyun .io_port_1 = 0xe5,
232*4882a593Smuzhiyun .io_port_2 = 0xe6,
233*4882a593Smuzhiyun .int_read_to_clear = true,
234*4882a593Smuzhiyun .host_int_rsr = 0x04,
235*4882a593Smuzhiyun .card_misc_cfg = 0xd8,
236*4882a593Smuzhiyun .fw_dump_ctrl = 0xf0,
237*4882a593Smuzhiyun .fw_dump_start = 0xf1,
238*4882a593Smuzhiyun .fw_dump_end = 0xf8,
239*4882a593Smuzhiyun };
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
242*4882a593Smuzhiyun .helper = "mrvl/sd8688_helper.bin",
243*4882a593Smuzhiyun .firmware = "mrvl/sd8688.bin",
244*4882a593Smuzhiyun .reg = &btmrvl_reg_8688,
245*4882a593Smuzhiyun .support_pscan_win_report = false,
246*4882a593Smuzhiyun .sd_blksz_fw_dl = 64,
247*4882a593Smuzhiyun .supports_fw_dump = false,
248*4882a593Smuzhiyun };
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
251*4882a593Smuzhiyun .helper = NULL,
252*4882a593Smuzhiyun .firmware = "mrvl/sd8787_uapsta.bin",
253*4882a593Smuzhiyun .reg = &btmrvl_reg_87xx,
254*4882a593Smuzhiyun .support_pscan_win_report = false,
255*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
256*4882a593Smuzhiyun .supports_fw_dump = false,
257*4882a593Smuzhiyun };
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
260*4882a593Smuzhiyun .helper = NULL,
261*4882a593Smuzhiyun .firmware = "mrvl/sd8797_uapsta.bin",
262*4882a593Smuzhiyun .reg = &btmrvl_reg_87xx,
263*4882a593Smuzhiyun .support_pscan_win_report = false,
264*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
265*4882a593Smuzhiyun .supports_fw_dump = false,
266*4882a593Smuzhiyun };
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
269*4882a593Smuzhiyun .helper = NULL,
270*4882a593Smuzhiyun .firmware = "mrvl/sd8887_uapsta.bin",
271*4882a593Smuzhiyun .reg = &btmrvl_reg_8887,
272*4882a593Smuzhiyun .support_pscan_win_report = true,
273*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
274*4882a593Smuzhiyun .supports_fw_dump = false,
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
278*4882a593Smuzhiyun .helper = NULL,
279*4882a593Smuzhiyun .firmware = "mrvl/sd8897_uapsta.bin",
280*4882a593Smuzhiyun .reg = &btmrvl_reg_8897,
281*4882a593Smuzhiyun .support_pscan_win_report = true,
282*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
283*4882a593Smuzhiyun .supports_fw_dump = true,
284*4882a593Smuzhiyun };
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
287*4882a593Smuzhiyun .helper = NULL,
288*4882a593Smuzhiyun .firmware = "mrvl/sdsd8977_combo_v2.bin",
289*4882a593Smuzhiyun .reg = &btmrvl_reg_89xx,
290*4882a593Smuzhiyun .support_pscan_win_report = true,
291*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
292*4882a593Smuzhiyun .supports_fw_dump = true,
293*4882a593Smuzhiyun };
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
296*4882a593Smuzhiyun .helper = NULL,
297*4882a593Smuzhiyun .firmware = "mrvl/sd8987_uapsta.bin",
298*4882a593Smuzhiyun .reg = &btmrvl_reg_89xx,
299*4882a593Smuzhiyun .support_pscan_win_report = true,
300*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
301*4882a593Smuzhiyun .supports_fw_dump = true,
302*4882a593Smuzhiyun };
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
305*4882a593Smuzhiyun .helper = NULL,
306*4882a593Smuzhiyun .firmware = "mrvl/sdsd8997_combo_v4.bin",
307*4882a593Smuzhiyun .reg = &btmrvl_reg_89xx,
308*4882a593Smuzhiyun .support_pscan_win_report = true,
309*4882a593Smuzhiyun .sd_blksz_fw_dl = 256,
310*4882a593Smuzhiyun .supports_fw_dump = true,
311*4882a593Smuzhiyun };
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun static const struct sdio_device_id btmrvl_sdio_ids[] = {
314*4882a593Smuzhiyun /* Marvell SD8688 Bluetooth device */
315*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688_BT),
316*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8688 },
317*4882a593Smuzhiyun /* Marvell SD8787 Bluetooth device */
318*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT),
319*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
320*4882a593Smuzhiyun /* Marvell SD8787 Bluetooth AMP device */
321*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT_AMP),
322*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
323*4882a593Smuzhiyun /* Marvell SD8797 Bluetooth device */
324*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_BT),
325*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8797 },
326*4882a593Smuzhiyun /* Marvell SD8887 Bluetooth device */
327*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_BT),
328*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
329*4882a593Smuzhiyun /* Marvell SD8897 Bluetooth device */
330*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897_BT),
331*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
332*4882a593Smuzhiyun /* Marvell SD8977 Bluetooth device */
333*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977_BT),
334*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8977 },
335*4882a593Smuzhiyun /* Marvell SD8987 Bluetooth device */
336*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987_BT),
337*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8987 },
338*4882a593Smuzhiyun /* Marvell SD8997 Bluetooth device */
339*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997_BT),
340*4882a593Smuzhiyun .driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun { } /* Terminating entry */
343*4882a593Smuzhiyun };
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids);
346*4882a593Smuzhiyun
btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card * card)347*4882a593Smuzhiyun static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun u8 reg;
350*4882a593Smuzhiyun int ret;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
353*4882a593Smuzhiyun if (!ret)
354*4882a593Smuzhiyun card->rx_unit = reg;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun return ret;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card * card,u16 * dat)359*4882a593Smuzhiyun static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun u8 fws0, fws1;
362*4882a593Smuzhiyun int ret;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun *dat = 0;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
367*4882a593Smuzhiyun if (ret)
368*4882a593Smuzhiyun return -EIO;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
371*4882a593Smuzhiyun if (ret)
372*4882a593Smuzhiyun return -EIO;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun *dat = (((u16) fws1) << 8) | fws0;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun return 0;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card * card,u16 * dat)379*4882a593Smuzhiyun static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun u8 reg;
382*4882a593Smuzhiyun int ret;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
385*4882a593Smuzhiyun if (!ret)
386*4882a593Smuzhiyun *dat = (u16) reg << card->rx_unit;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return ret;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card * card,u8 mask)391*4882a593Smuzhiyun static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
392*4882a593Smuzhiyun u8 mask)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun int ret;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
397*4882a593Smuzhiyun if (ret) {
398*4882a593Smuzhiyun BT_ERR("Unable to enable the host interrupt!");
399*4882a593Smuzhiyun ret = -EIO;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return ret;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card * card,u8 mask)405*4882a593Smuzhiyun static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
406*4882a593Smuzhiyun u8 mask)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun u8 host_int_mask;
409*4882a593Smuzhiyun int ret;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
412*4882a593Smuzhiyun if (ret)
413*4882a593Smuzhiyun return -EIO;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun host_int_mask &= ~mask;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
418*4882a593Smuzhiyun if (ret < 0) {
419*4882a593Smuzhiyun BT_ERR("Unable to disable the host interrupt!");
420*4882a593Smuzhiyun return -EIO;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun return 0;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card * card,u8 bits)426*4882a593Smuzhiyun static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun unsigned int tries;
429*4882a593Smuzhiyun u8 status;
430*4882a593Smuzhiyun int ret;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
433*4882a593Smuzhiyun status = sdio_readb(card->func, card->reg->card_status, &ret);
434*4882a593Smuzhiyun if (ret)
435*4882a593Smuzhiyun goto failed;
436*4882a593Smuzhiyun if ((status & bits) == bits)
437*4882a593Smuzhiyun return ret;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun udelay(1);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun ret = -ETIMEDOUT;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun failed:
445*4882a593Smuzhiyun BT_ERR("FAILED! ret=%d", ret);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun return ret;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card * card,int pollnum)450*4882a593Smuzhiyun static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,
451*4882a593Smuzhiyun int pollnum)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun u16 firmwarestat;
454*4882a593Smuzhiyun int tries, ret;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* Wait for firmware to become ready */
457*4882a593Smuzhiyun for (tries = 0; tries < pollnum; tries++) {
458*4882a593Smuzhiyun sdio_claim_host(card->func);
459*4882a593Smuzhiyun ret = btmrvl_sdio_read_fw_status(card, &firmwarestat);
460*4882a593Smuzhiyun sdio_release_host(card->func);
461*4882a593Smuzhiyun if (ret < 0)
462*4882a593Smuzhiyun continue;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (firmwarestat == FIRMWARE_READY)
465*4882a593Smuzhiyun return 0;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun msleep(100);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun return -ETIMEDOUT;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
btmrvl_sdio_download_helper(struct btmrvl_sdio_card * card)473*4882a593Smuzhiyun static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun const struct firmware *fw_helper = NULL;
476*4882a593Smuzhiyun const u8 *helper = NULL;
477*4882a593Smuzhiyun int ret;
478*4882a593Smuzhiyun void *tmphlprbuf = NULL;
479*4882a593Smuzhiyun int tmphlprbufsz, hlprblknow, helperlen;
480*4882a593Smuzhiyun u8 *helperbuf;
481*4882a593Smuzhiyun u32 tx_len;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun ret = request_firmware(&fw_helper, card->helper,
484*4882a593Smuzhiyun &card->func->dev);
485*4882a593Smuzhiyun if ((ret < 0) || !fw_helper) {
486*4882a593Smuzhiyun BT_ERR("request_firmware(helper) failed, error code = %d",
487*4882a593Smuzhiyun ret);
488*4882a593Smuzhiyun ret = -ENOENT;
489*4882a593Smuzhiyun goto done;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun helper = fw_helper->data;
493*4882a593Smuzhiyun helperlen = fw_helper->size;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun BT_DBG("Downloading helper image (%d bytes), block size %d bytes",
496*4882a593Smuzhiyun helperlen, SDIO_BLOCK_SIZE);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);
501*4882a593Smuzhiyun if (!tmphlprbuf) {
502*4882a593Smuzhiyun BT_ERR("Unable to allocate buffer for helper."
503*4882a593Smuzhiyun " Terminating download");
504*4882a593Smuzhiyun ret = -ENOMEM;
505*4882a593Smuzhiyun goto done;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /* Perform helper data transfer */
511*4882a593Smuzhiyun tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE)
512*4882a593Smuzhiyun - SDIO_HEADER_LEN;
513*4882a593Smuzhiyun hlprblknow = 0;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun do {
516*4882a593Smuzhiyun ret = btmrvl_sdio_poll_card_status(card,
517*4882a593Smuzhiyun CARD_IO_READY | DN_LD_CARD_RDY);
518*4882a593Smuzhiyun if (ret < 0) {
519*4882a593Smuzhiyun BT_ERR("Helper download poll status timeout @ %d",
520*4882a593Smuzhiyun hlprblknow);
521*4882a593Smuzhiyun goto done;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* Check if there is more data? */
525*4882a593Smuzhiyun if (hlprblknow >= helperlen)
526*4882a593Smuzhiyun break;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (helperlen - hlprblknow < tx_len)
529*4882a593Smuzhiyun tx_len = helperlen - hlprblknow;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /* Little-endian */
532*4882a593Smuzhiyun helperbuf[0] = ((tx_len & 0x000000ff) >> 0);
533*4882a593Smuzhiyun helperbuf[1] = ((tx_len & 0x0000ff00) >> 8);
534*4882a593Smuzhiyun helperbuf[2] = ((tx_len & 0x00ff0000) >> 16);
535*4882a593Smuzhiyun helperbuf[3] = ((tx_len & 0xff000000) >> 24);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow],
538*4882a593Smuzhiyun tx_len);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /* Now send the data */
541*4882a593Smuzhiyun ret = sdio_writesb(card->func, card->ioport, helperbuf,
542*4882a593Smuzhiyun FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE);
543*4882a593Smuzhiyun if (ret < 0) {
544*4882a593Smuzhiyun BT_ERR("IO error during helper download @ %d",
545*4882a593Smuzhiyun hlprblknow);
546*4882a593Smuzhiyun goto done;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun hlprblknow += tx_len;
550*4882a593Smuzhiyun } while (true);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun BT_DBG("Transferring helper image EOF block");
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun memset(helperbuf, 0x0, SDIO_BLOCK_SIZE);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun ret = sdio_writesb(card->func, card->ioport, helperbuf,
557*4882a593Smuzhiyun SDIO_BLOCK_SIZE);
558*4882a593Smuzhiyun if (ret < 0) {
559*4882a593Smuzhiyun BT_ERR("IO error in writing helper image EOF block");
560*4882a593Smuzhiyun goto done;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun ret = 0;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun done:
566*4882a593Smuzhiyun kfree(tmphlprbuf);
567*4882a593Smuzhiyun release_firmware(fw_helper);
568*4882a593Smuzhiyun return ret;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card * card)571*4882a593Smuzhiyun static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun const struct firmware *fw_firmware = NULL;
574*4882a593Smuzhiyun const u8 *firmware = NULL;
575*4882a593Smuzhiyun int firmwarelen, tmpfwbufsz, ret;
576*4882a593Smuzhiyun unsigned int tries, offset;
577*4882a593Smuzhiyun u8 base0, base1;
578*4882a593Smuzhiyun void *tmpfwbuf = NULL;
579*4882a593Smuzhiyun u8 *fwbuf;
580*4882a593Smuzhiyun u16 len, blksz_dl = card->sd_blksz_fw_dl;
581*4882a593Smuzhiyun int txlen = 0, tx_blocks = 0, count = 0;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun ret = request_firmware(&fw_firmware, card->firmware,
584*4882a593Smuzhiyun &card->func->dev);
585*4882a593Smuzhiyun if ((ret < 0) || !fw_firmware) {
586*4882a593Smuzhiyun BT_ERR("request_firmware(firmware) failed, error code = %d",
587*4882a593Smuzhiyun ret);
588*4882a593Smuzhiyun ret = -ENOENT;
589*4882a593Smuzhiyun goto done;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun firmware = fw_firmware->data;
593*4882a593Smuzhiyun firmwarelen = fw_firmware->size;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
598*4882a593Smuzhiyun tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
599*4882a593Smuzhiyun if (!tmpfwbuf) {
600*4882a593Smuzhiyun BT_ERR("Unable to allocate buffer for firmware."
601*4882a593Smuzhiyun " Terminating download");
602*4882a593Smuzhiyun ret = -ENOMEM;
603*4882a593Smuzhiyun goto done;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* Ensure aligned firmware buffer */
607*4882a593Smuzhiyun fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* Perform firmware data transfer */
610*4882a593Smuzhiyun offset = 0;
611*4882a593Smuzhiyun do {
612*4882a593Smuzhiyun ret = btmrvl_sdio_poll_card_status(card,
613*4882a593Smuzhiyun CARD_IO_READY | DN_LD_CARD_RDY);
614*4882a593Smuzhiyun if (ret < 0) {
615*4882a593Smuzhiyun BT_ERR("FW download with helper poll status"
616*4882a593Smuzhiyun " timeout @ %d", offset);
617*4882a593Smuzhiyun goto done;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun /* Check if there is more data ? */
621*4882a593Smuzhiyun if (offset >= firmwarelen)
622*4882a593Smuzhiyun break;
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
625*4882a593Smuzhiyun base0 = sdio_readb(card->func,
626*4882a593Smuzhiyun card->reg->sq_read_base_addr_a0, &ret);
627*4882a593Smuzhiyun if (ret) {
628*4882a593Smuzhiyun BT_ERR("BASE0 register read failed:"
629*4882a593Smuzhiyun " base0 = 0x%04X(%d)."
630*4882a593Smuzhiyun " Terminating download",
631*4882a593Smuzhiyun base0, base0);
632*4882a593Smuzhiyun ret = -EIO;
633*4882a593Smuzhiyun goto done;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun base1 = sdio_readb(card->func,
636*4882a593Smuzhiyun card->reg->sq_read_base_addr_a1, &ret);
637*4882a593Smuzhiyun if (ret) {
638*4882a593Smuzhiyun BT_ERR("BASE1 register read failed:"
639*4882a593Smuzhiyun " base1 = 0x%04X(%d)."
640*4882a593Smuzhiyun " Terminating download",
641*4882a593Smuzhiyun base1, base1);
642*4882a593Smuzhiyun ret = -EIO;
643*4882a593Smuzhiyun goto done;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun len = (((u16) base1) << 8) | base0;
647*4882a593Smuzhiyun if (len)
648*4882a593Smuzhiyun break;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun udelay(10);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun if (!len)
654*4882a593Smuzhiyun break;
655*4882a593Smuzhiyun else if (len > BTM_UPLD_SIZE) {
656*4882a593Smuzhiyun BT_ERR("FW download failure @%d, invalid length %d",
657*4882a593Smuzhiyun offset, len);
658*4882a593Smuzhiyun ret = -EINVAL;
659*4882a593Smuzhiyun goto done;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun txlen = len;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun if (len & BIT(0)) {
665*4882a593Smuzhiyun count++;
666*4882a593Smuzhiyun if (count > MAX_WRITE_IOMEM_RETRY) {
667*4882a593Smuzhiyun BT_ERR("FW download failure @%d, "
668*4882a593Smuzhiyun "over max retry count", offset);
669*4882a593Smuzhiyun ret = -EIO;
670*4882a593Smuzhiyun goto done;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun BT_ERR("FW CRC error indicated by the helper: "
673*4882a593Smuzhiyun "len = 0x%04X, txlen = %d", len, txlen);
674*4882a593Smuzhiyun len &= ~BIT(0);
675*4882a593Smuzhiyun /* Set txlen to 0 so as to resend from same offset */
676*4882a593Smuzhiyun txlen = 0;
677*4882a593Smuzhiyun } else {
678*4882a593Smuzhiyun count = 0;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun /* Last block ? */
681*4882a593Smuzhiyun if (firmwarelen - offset < txlen)
682*4882a593Smuzhiyun txlen = firmwarelen - offset;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun tx_blocks = DIV_ROUND_UP(txlen, blksz_dl);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun memcpy(fwbuf, &firmware[offset], txlen);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun ret = sdio_writesb(card->func, card->ioport, fwbuf,
690*4882a593Smuzhiyun tx_blocks * blksz_dl);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun if (ret < 0) {
693*4882a593Smuzhiyun BT_ERR("FW download, writesb(%d) failed @%d",
694*4882a593Smuzhiyun count, offset);
695*4882a593Smuzhiyun sdio_writeb(card->func, HOST_CMD53_FIN,
696*4882a593Smuzhiyun card->reg->cfg, &ret);
697*4882a593Smuzhiyun if (ret)
698*4882a593Smuzhiyun BT_ERR("writeb failed (CFG)");
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun offset += txlen;
702*4882a593Smuzhiyun } while (true);
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun BT_INFO("FW download over, size %d bytes", offset);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun ret = 0;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun done:
709*4882a593Smuzhiyun kfree(tmpfwbuf);
710*4882a593Smuzhiyun release_firmware(fw_firmware);
711*4882a593Smuzhiyun return ret;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
btmrvl_sdio_card_to_host(struct btmrvl_private * priv)714*4882a593Smuzhiyun static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun u16 buf_len = 0;
717*4882a593Smuzhiyun int ret, num_blocks, blksz;
718*4882a593Smuzhiyun struct sk_buff *skb = NULL;
719*4882a593Smuzhiyun u32 type;
720*4882a593Smuzhiyun u8 *payload;
721*4882a593Smuzhiyun struct hci_dev *hdev = priv->btmrvl_dev.hcidev;
722*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun if (!card || !card->func) {
725*4882a593Smuzhiyun BT_ERR("card or function is NULL!");
726*4882a593Smuzhiyun ret = -EINVAL;
727*4882a593Smuzhiyun goto exit;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun /* Read the length of data to be transferred */
731*4882a593Smuzhiyun ret = btmrvl_sdio_read_rx_len(card, &buf_len);
732*4882a593Smuzhiyun if (ret < 0) {
733*4882a593Smuzhiyun BT_ERR("read rx_len failed");
734*4882a593Smuzhiyun ret = -EIO;
735*4882a593Smuzhiyun goto exit;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun blksz = SDIO_BLOCK_SIZE;
739*4882a593Smuzhiyun num_blocks = DIV_ROUND_UP(buf_len, blksz);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (buf_len <= SDIO_HEADER_LEN
742*4882a593Smuzhiyun || (num_blocks * blksz) > ALLOC_BUF_SIZE) {
743*4882a593Smuzhiyun BT_ERR("invalid packet length: %d", buf_len);
744*4882a593Smuzhiyun ret = -EINVAL;
745*4882a593Smuzhiyun goto exit;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun /* Allocate buffer */
749*4882a593Smuzhiyun skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_KERNEL);
750*4882a593Smuzhiyun if (!skb) {
751*4882a593Smuzhiyun BT_ERR("No free skb");
752*4882a593Smuzhiyun ret = -ENOMEM;
753*4882a593Smuzhiyun goto exit;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) {
757*4882a593Smuzhiyun skb_put(skb, (unsigned long) skb->data &
758*4882a593Smuzhiyun (BTSDIO_DMA_ALIGN - 1));
759*4882a593Smuzhiyun skb_pull(skb, (unsigned long) skb->data &
760*4882a593Smuzhiyun (BTSDIO_DMA_ALIGN - 1));
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun payload = skb->data;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun ret = sdio_readsb(card->func, payload, card->ioport,
766*4882a593Smuzhiyun num_blocks * blksz);
767*4882a593Smuzhiyun if (ret < 0) {
768*4882a593Smuzhiyun BT_ERR("readsb failed: %d", ret);
769*4882a593Smuzhiyun ret = -EIO;
770*4882a593Smuzhiyun goto exit;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
774*4882a593Smuzhiyun * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor)
775*4882a593Smuzhiyun */
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun buf_len = payload[0];
778*4882a593Smuzhiyun buf_len |= payload[1] << 8;
779*4882a593Smuzhiyun buf_len |= payload[2] << 16;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (buf_len > blksz * num_blocks) {
782*4882a593Smuzhiyun BT_ERR("Skip incorrect packet: hdrlen %d buffer %d",
783*4882a593Smuzhiyun buf_len, blksz * num_blocks);
784*4882a593Smuzhiyun ret = -EIO;
785*4882a593Smuzhiyun goto exit;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun type = payload[3];
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun switch (type) {
791*4882a593Smuzhiyun case HCI_ACLDATA_PKT:
792*4882a593Smuzhiyun case HCI_SCODATA_PKT:
793*4882a593Smuzhiyun case HCI_EVENT_PKT:
794*4882a593Smuzhiyun hci_skb_pkt_type(skb) = type;
795*4882a593Smuzhiyun skb_put(skb, buf_len);
796*4882a593Smuzhiyun skb_pull(skb, SDIO_HEADER_LEN);
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun if (type == HCI_EVENT_PKT) {
799*4882a593Smuzhiyun if (btmrvl_check_evtpkt(priv, skb))
800*4882a593Smuzhiyun hci_recv_frame(hdev, skb);
801*4882a593Smuzhiyun } else {
802*4882a593Smuzhiyun hci_recv_frame(hdev, skb);
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun hdev->stat.byte_rx += buf_len;
806*4882a593Smuzhiyun break;
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun case MRVL_VENDOR_PKT:
809*4882a593Smuzhiyun hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
810*4882a593Smuzhiyun skb_put(skb, buf_len);
811*4882a593Smuzhiyun skb_pull(skb, SDIO_HEADER_LEN);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun if (btmrvl_process_event(priv, skb))
814*4882a593Smuzhiyun hci_recv_frame(hdev, skb);
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun hdev->stat.byte_rx += buf_len;
817*4882a593Smuzhiyun break;
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun default:
820*4882a593Smuzhiyun BT_ERR("Unknown packet type:%d", type);
821*4882a593Smuzhiyun BT_ERR("hex: %*ph", blksz * num_blocks, payload);
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun kfree_skb(skb);
824*4882a593Smuzhiyun skb = NULL;
825*4882a593Smuzhiyun break;
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun exit:
829*4882a593Smuzhiyun if (ret) {
830*4882a593Smuzhiyun hdev->stat.err_rx++;
831*4882a593Smuzhiyun kfree_skb(skb);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun return ret;
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun
btmrvl_sdio_process_int_status(struct btmrvl_private * priv)837*4882a593Smuzhiyun static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun ulong flags;
840*4882a593Smuzhiyun u8 ireg;
841*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
844*4882a593Smuzhiyun ireg = sdio_ireg;
845*4882a593Smuzhiyun sdio_ireg = 0;
846*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun sdio_claim_host(card->func);
849*4882a593Smuzhiyun if (ireg & DN_LD_HOST_INT_STATUS) {
850*4882a593Smuzhiyun if (priv->btmrvl_dev.tx_dnld_rdy)
851*4882a593Smuzhiyun BT_DBG("tx_done already received: "
852*4882a593Smuzhiyun " int_status=0x%x", ireg);
853*4882a593Smuzhiyun else
854*4882a593Smuzhiyun priv->btmrvl_dev.tx_dnld_rdy = true;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if (ireg & UP_LD_HOST_INT_STATUS)
858*4882a593Smuzhiyun btmrvl_sdio_card_to_host(priv);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun sdio_release_host(card->func);
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun return 0;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun
btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card * card,u8 * ireg)865*4882a593Smuzhiyun static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun struct btmrvl_adapter *adapter = card->priv->adapter;
868*4882a593Smuzhiyun int ret;
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE);
871*4882a593Smuzhiyun if (ret) {
872*4882a593Smuzhiyun BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret);
873*4882a593Smuzhiyun return ret;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun *ireg = adapter->hw_regs[card->reg->host_intstatus];
877*4882a593Smuzhiyun BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg);
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun return 0;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card * card,u8 * ireg)882*4882a593Smuzhiyun static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun int ret;
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun *ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
887*4882a593Smuzhiyun if (ret) {
888*4882a593Smuzhiyun BT_ERR("sdio_readb: read int status failed: %d", ret);
889*4882a593Smuzhiyun return ret;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun if (*ireg) {
893*4882a593Smuzhiyun /*
894*4882a593Smuzhiyun * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
895*4882a593Smuzhiyun * Clear the interrupt status register and re-enable the
896*4882a593Smuzhiyun * interrupt.
897*4882a593Smuzhiyun */
898*4882a593Smuzhiyun BT_DBG("int_status = 0x%x", *ireg);
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS |
901*4882a593Smuzhiyun UP_LD_HOST_INT_STATUS),
902*4882a593Smuzhiyun card->reg->host_intstatus, &ret);
903*4882a593Smuzhiyun if (ret) {
904*4882a593Smuzhiyun BT_ERR("sdio_writeb: clear int status failed: %d", ret);
905*4882a593Smuzhiyun return ret;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun return 0;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun
btmrvl_sdio_interrupt(struct sdio_func * func)912*4882a593Smuzhiyun static void btmrvl_sdio_interrupt(struct sdio_func *func)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun struct btmrvl_private *priv;
915*4882a593Smuzhiyun struct btmrvl_sdio_card *card;
916*4882a593Smuzhiyun ulong flags;
917*4882a593Smuzhiyun u8 ireg = 0;
918*4882a593Smuzhiyun int ret;
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun card = sdio_get_drvdata(func);
921*4882a593Smuzhiyun if (!card || !card->priv) {
922*4882a593Smuzhiyun BT_ERR("sbi_interrupt(%p) card or priv is NULL, card=%p",
923*4882a593Smuzhiyun func, card);
924*4882a593Smuzhiyun return;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun priv = card->priv;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun if (priv->surprise_removed)
930*4882a593Smuzhiyun return;
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun if (card->reg->int_read_to_clear)
933*4882a593Smuzhiyun ret = btmrvl_sdio_read_to_clear(card, &ireg);
934*4882a593Smuzhiyun else
935*4882a593Smuzhiyun ret = btmrvl_sdio_write_to_clear(card, &ireg);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun if (ret)
938*4882a593Smuzhiyun return;
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
941*4882a593Smuzhiyun sdio_ireg |= ireg;
942*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun btmrvl_interrupt(priv);
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
btmrvl_sdio_register_dev(struct btmrvl_sdio_card * card)947*4882a593Smuzhiyun static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
948*4882a593Smuzhiyun {
949*4882a593Smuzhiyun struct sdio_func *func;
950*4882a593Smuzhiyun u8 reg;
951*4882a593Smuzhiyun int ret;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun if (!card || !card->func) {
954*4882a593Smuzhiyun BT_ERR("Error: card or function is NULL!");
955*4882a593Smuzhiyun ret = -EINVAL;
956*4882a593Smuzhiyun goto failed;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun func = card->func;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun sdio_claim_host(func);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun ret = sdio_enable_func(func);
964*4882a593Smuzhiyun if (ret) {
965*4882a593Smuzhiyun BT_ERR("sdio_enable_func() failed: ret=%d", ret);
966*4882a593Smuzhiyun ret = -EIO;
967*4882a593Smuzhiyun goto release_host;
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun ret = sdio_claim_irq(func, btmrvl_sdio_interrupt);
971*4882a593Smuzhiyun if (ret) {
972*4882a593Smuzhiyun BT_ERR("sdio_claim_irq failed: ret=%d", ret);
973*4882a593Smuzhiyun ret = -EIO;
974*4882a593Smuzhiyun goto disable_func;
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE);
978*4882a593Smuzhiyun if (ret) {
979*4882a593Smuzhiyun BT_ERR("cannot set SDIO block size");
980*4882a593Smuzhiyun ret = -EIO;
981*4882a593Smuzhiyun goto release_irq;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun reg = sdio_readb(func, card->reg->io_port_0, &ret);
985*4882a593Smuzhiyun if (ret < 0) {
986*4882a593Smuzhiyun ret = -EIO;
987*4882a593Smuzhiyun goto release_irq;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun card->ioport = reg;
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun reg = sdio_readb(func, card->reg->io_port_1, &ret);
993*4882a593Smuzhiyun if (ret < 0) {
994*4882a593Smuzhiyun ret = -EIO;
995*4882a593Smuzhiyun goto release_irq;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun card->ioport |= (reg << 8);
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun reg = sdio_readb(func, card->reg->io_port_2, &ret);
1001*4882a593Smuzhiyun if (ret < 0) {
1002*4882a593Smuzhiyun ret = -EIO;
1003*4882a593Smuzhiyun goto release_irq;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun card->ioport |= (reg << 16);
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun if (card->reg->int_read_to_clear) {
1011*4882a593Smuzhiyun reg = sdio_readb(func, card->reg->host_int_rsr, &ret);
1012*4882a593Smuzhiyun if (ret < 0) {
1013*4882a593Smuzhiyun ret = -EIO;
1014*4882a593Smuzhiyun goto release_irq;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret);
1017*4882a593Smuzhiyun if (ret < 0) {
1018*4882a593Smuzhiyun ret = -EIO;
1019*4882a593Smuzhiyun goto release_irq;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun reg = sdio_readb(func, card->reg->card_misc_cfg, &ret);
1023*4882a593Smuzhiyun if (ret < 0) {
1024*4882a593Smuzhiyun ret = -EIO;
1025*4882a593Smuzhiyun goto release_irq;
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret);
1028*4882a593Smuzhiyun if (ret < 0) {
1029*4882a593Smuzhiyun ret = -EIO;
1030*4882a593Smuzhiyun goto release_irq;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun sdio_set_drvdata(func, card);
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun sdio_release_host(func);
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun return 0;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun release_irq:
1041*4882a593Smuzhiyun sdio_release_irq(func);
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun disable_func:
1044*4882a593Smuzhiyun sdio_disable_func(func);
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun release_host:
1047*4882a593Smuzhiyun sdio_release_host(func);
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun failed:
1050*4882a593Smuzhiyun return ret;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun
btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card * card)1053*4882a593Smuzhiyun static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card)
1054*4882a593Smuzhiyun {
1055*4882a593Smuzhiyun if (card && card->func) {
1056*4882a593Smuzhiyun sdio_claim_host(card->func);
1057*4882a593Smuzhiyun sdio_release_irq(card->func);
1058*4882a593Smuzhiyun sdio_disable_func(card->func);
1059*4882a593Smuzhiyun sdio_release_host(card->func);
1060*4882a593Smuzhiyun sdio_set_drvdata(card->func, NULL);
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun return 0;
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun
btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card * card)1066*4882a593Smuzhiyun static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun int ret;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun if (!card || !card->func)
1071*4882a593Smuzhiyun return -EINVAL;
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun sdio_claim_host(card->func);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE);
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun btmrvl_sdio_get_rx_unit(card);
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun sdio_release_host(card->func);
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun return ret;
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card * card)1084*4882a593Smuzhiyun static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card)
1085*4882a593Smuzhiyun {
1086*4882a593Smuzhiyun int ret;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun if (!card || !card->func)
1089*4882a593Smuzhiyun return -EINVAL;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun sdio_claim_host(card->func);
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE);
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun sdio_release_host(card->func);
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun return ret;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
btmrvl_sdio_host_to_card(struct btmrvl_private * priv,u8 * payload,u16 nb)1100*4882a593Smuzhiyun static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
1101*4882a593Smuzhiyun u8 *payload, u16 nb)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
1104*4882a593Smuzhiyun int ret = 0;
1105*4882a593Smuzhiyun int blksz;
1106*4882a593Smuzhiyun int i = 0;
1107*4882a593Smuzhiyun u8 *buf = NULL;
1108*4882a593Smuzhiyun void *tmpbuf = NULL;
1109*4882a593Smuzhiyun int tmpbufsz;
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun if (!card || !card->func) {
1112*4882a593Smuzhiyun BT_ERR("card or function is NULL!");
1113*4882a593Smuzhiyun return -EINVAL;
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun blksz = DIV_ROUND_UP(nb, SDIO_BLOCK_SIZE) * SDIO_BLOCK_SIZE;
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun buf = payload;
1119*4882a593Smuzhiyun if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1) ||
1120*4882a593Smuzhiyun nb < blksz) {
1121*4882a593Smuzhiyun tmpbufsz = ALIGN_SZ(blksz, BTSDIO_DMA_ALIGN) +
1122*4882a593Smuzhiyun BTSDIO_DMA_ALIGN;
1123*4882a593Smuzhiyun tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL);
1124*4882a593Smuzhiyun if (!tmpbuf)
1125*4882a593Smuzhiyun return -ENOMEM;
1126*4882a593Smuzhiyun buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN);
1127*4882a593Smuzhiyun memcpy(buf, payload, nb);
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun sdio_claim_host(card->func);
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun do {
1133*4882a593Smuzhiyun /* Transfer data to card */
1134*4882a593Smuzhiyun ret = sdio_writesb(card->func, card->ioport, buf,
1135*4882a593Smuzhiyun blksz);
1136*4882a593Smuzhiyun if (ret < 0) {
1137*4882a593Smuzhiyun i++;
1138*4882a593Smuzhiyun BT_ERR("i=%d writesb failed: %d", i, ret);
1139*4882a593Smuzhiyun BT_ERR("hex: %*ph", nb, payload);
1140*4882a593Smuzhiyun ret = -EIO;
1141*4882a593Smuzhiyun if (i > MAX_WRITE_IOMEM_RETRY)
1142*4882a593Smuzhiyun goto exit;
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun } while (ret);
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun priv->btmrvl_dev.tx_dnld_rdy = false;
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun exit:
1149*4882a593Smuzhiyun sdio_release_host(card->func);
1150*4882a593Smuzhiyun kfree(tmpbuf);
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun return ret;
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
btmrvl_sdio_download_fw(struct btmrvl_sdio_card * card)1155*4882a593Smuzhiyun static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
1156*4882a593Smuzhiyun {
1157*4882a593Smuzhiyun int ret;
1158*4882a593Smuzhiyun u8 fws0;
1159*4882a593Smuzhiyun int pollnum = MAX_POLL_TRIES;
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun if (!card || !card->func) {
1162*4882a593Smuzhiyun BT_ERR("card or function is NULL!");
1163*4882a593Smuzhiyun return -EINVAL;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun if (!btmrvl_sdio_verify_fw_download(card, 1)) {
1167*4882a593Smuzhiyun BT_DBG("Firmware already downloaded!");
1168*4882a593Smuzhiyun return 0;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun sdio_claim_host(card->func);
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun /* Check if other function driver is downloading the firmware */
1174*4882a593Smuzhiyun fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
1175*4882a593Smuzhiyun if (ret) {
1176*4882a593Smuzhiyun BT_ERR("Failed to read FW downloading status!");
1177*4882a593Smuzhiyun ret = -EIO;
1178*4882a593Smuzhiyun goto done;
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun if (fws0) {
1181*4882a593Smuzhiyun BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun /* Give other function more time to download the firmware */
1184*4882a593Smuzhiyun pollnum *= 10;
1185*4882a593Smuzhiyun } else {
1186*4882a593Smuzhiyun if (card->helper) {
1187*4882a593Smuzhiyun ret = btmrvl_sdio_download_helper(card);
1188*4882a593Smuzhiyun if (ret) {
1189*4882a593Smuzhiyun BT_ERR("Failed to download helper!");
1190*4882a593Smuzhiyun ret = -EIO;
1191*4882a593Smuzhiyun goto done;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun if (btmrvl_sdio_download_fw_w_helper(card)) {
1196*4882a593Smuzhiyun BT_ERR("Failed to download firmware!");
1197*4882a593Smuzhiyun ret = -EIO;
1198*4882a593Smuzhiyun goto done;
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun /*
1203*4882a593Smuzhiyun * winner or not, with this test the FW synchronizes when the
1204*4882a593Smuzhiyun * module can continue its initialization
1205*4882a593Smuzhiyun */
1206*4882a593Smuzhiyun if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
1207*4882a593Smuzhiyun BT_ERR("FW failed to be active in time!");
1208*4882a593Smuzhiyun ret = -ETIMEDOUT;
1209*4882a593Smuzhiyun goto done;
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun sdio_release_host(card->func);
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun return 0;
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun done:
1217*4882a593Smuzhiyun sdio_release_host(card->func);
1218*4882a593Smuzhiyun return ret;
1219*4882a593Smuzhiyun }
1220*4882a593Smuzhiyun
btmrvl_sdio_wakeup_fw(struct btmrvl_private * priv)1221*4882a593Smuzhiyun static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
1224*4882a593Smuzhiyun int ret = 0;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun if (!card || !card->func) {
1227*4882a593Smuzhiyun BT_ERR("card or function is NULL!");
1228*4882a593Smuzhiyun return -EINVAL;
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun sdio_claim_host(card->func);
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun sdio_release_host(card->func);
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun BT_DBG("wake up firmware");
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun return ret;
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun
btmrvl_sdio_dump_regs(struct btmrvl_private * priv)1242*4882a593Smuzhiyun static void btmrvl_sdio_dump_regs(struct btmrvl_private *priv)
1243*4882a593Smuzhiyun {
1244*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
1245*4882a593Smuzhiyun int ret = 0;
1246*4882a593Smuzhiyun unsigned int reg, reg_start, reg_end;
1247*4882a593Smuzhiyun char buf[256], *ptr;
1248*4882a593Smuzhiyun u8 loop, func, data;
1249*4882a593Smuzhiyun int MAX_LOOP = 2;
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun btmrvl_sdio_wakeup_fw(priv);
1252*4882a593Smuzhiyun sdio_claim_host(card->func);
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun for (loop = 0; loop < MAX_LOOP; loop++) {
1255*4882a593Smuzhiyun memset(buf, 0, sizeof(buf));
1256*4882a593Smuzhiyun ptr = buf;
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun if (loop == 0) {
1259*4882a593Smuzhiyun /* Read the registers of SDIO function0 */
1260*4882a593Smuzhiyun func = loop;
1261*4882a593Smuzhiyun reg_start = 0;
1262*4882a593Smuzhiyun reg_end = 9;
1263*4882a593Smuzhiyun } else {
1264*4882a593Smuzhiyun func = 2;
1265*4882a593Smuzhiyun reg_start = 0;
1266*4882a593Smuzhiyun reg_end = 0x09;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ",
1270*4882a593Smuzhiyun func, reg_start, reg_end);
1271*4882a593Smuzhiyun for (reg = reg_start; reg <= reg_end; reg++) {
1272*4882a593Smuzhiyun if (func == 0)
1273*4882a593Smuzhiyun data = sdio_f0_readb(card->func, reg, &ret);
1274*4882a593Smuzhiyun else
1275*4882a593Smuzhiyun data = sdio_readb(card->func, reg, &ret);
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun if (!ret) {
1278*4882a593Smuzhiyun ptr += sprintf(ptr, "%02x ", data);
1279*4882a593Smuzhiyun } else {
1280*4882a593Smuzhiyun ptr += sprintf(ptr, "ERR");
1281*4882a593Smuzhiyun break;
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun BT_INFO("%s", buf);
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun sdio_release_host(card->func);
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun /* This function read/write firmware */
1292*4882a593Smuzhiyun static enum
btmrvl_sdio_rdwr_firmware(struct btmrvl_private * priv,u8 doneflag)1293*4882a593Smuzhiyun rdwr_status btmrvl_sdio_rdwr_firmware(struct btmrvl_private *priv,
1294*4882a593Smuzhiyun u8 doneflag)
1295*4882a593Smuzhiyun {
1296*4882a593Smuzhiyun struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
1297*4882a593Smuzhiyun int ret, tries;
1298*4882a593Smuzhiyun u8 ctrl_data = 0;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
1301*4882a593Smuzhiyun &ret);
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun if (ret) {
1304*4882a593Smuzhiyun BT_ERR("SDIO write err");
1305*4882a593Smuzhiyun return RDWR_STATUS_FAILURE;
1306*4882a593Smuzhiyun }
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
1309*4882a593Smuzhiyun ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
1310*4882a593Smuzhiyun &ret);
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun if (ret) {
1313*4882a593Smuzhiyun BT_ERR("SDIO read err");
1314*4882a593Smuzhiyun return RDWR_STATUS_FAILURE;
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun if (ctrl_data == FW_DUMP_DONE)
1318*4882a593Smuzhiyun break;
1319*4882a593Smuzhiyun if (doneflag && ctrl_data == doneflag)
1320*4882a593Smuzhiyun return RDWR_STATUS_DONE;
1321*4882a593Smuzhiyun if (ctrl_data != FW_DUMP_HOST_READY) {
1322*4882a593Smuzhiyun BT_INFO("The ctrl reg was changed, re-try again!");
1323*4882a593Smuzhiyun sdio_writeb(card->func, FW_DUMP_HOST_READY,
1324*4882a593Smuzhiyun card->reg->fw_dump_ctrl, &ret);
1325*4882a593Smuzhiyun if (ret) {
1326*4882a593Smuzhiyun BT_ERR("SDIO write err");
1327*4882a593Smuzhiyun return RDWR_STATUS_FAILURE;
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun usleep_range(100, 200);
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun if (ctrl_data == FW_DUMP_HOST_READY) {
1334*4882a593Smuzhiyun BT_ERR("Fail to pull ctrl_data");
1335*4882a593Smuzhiyun return RDWR_STATUS_FAILURE;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun return RDWR_STATUS_SUCCESS;
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun /* This function dump sdio register and memory data */
btmrvl_sdio_coredump(struct device * dev)1342*4882a593Smuzhiyun static void btmrvl_sdio_coredump(struct device *dev)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun struct sdio_func *func = dev_to_sdio_func(dev);
1345*4882a593Smuzhiyun struct btmrvl_sdio_card *card;
1346*4882a593Smuzhiyun struct btmrvl_private *priv;
1347*4882a593Smuzhiyun int ret = 0;
1348*4882a593Smuzhiyun unsigned int reg, reg_start, reg_end;
1349*4882a593Smuzhiyun enum rdwr_status stat;
1350*4882a593Smuzhiyun u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
1351*4882a593Smuzhiyun u8 dump_num = 0, idx, i, read_reg, doneflag = 0;
1352*4882a593Smuzhiyun u32 memory_size, fw_dump_len = 0;
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun card = sdio_get_drvdata(func);
1355*4882a593Smuzhiyun priv = card->priv;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun /* dump sdio register first */
1358*4882a593Smuzhiyun btmrvl_sdio_dump_regs(priv);
1359*4882a593Smuzhiyun
1360*4882a593Smuzhiyun if (!card->supports_fw_dump) {
1361*4882a593Smuzhiyun BT_ERR("Firmware dump not supported for this card!");
1362*4882a593Smuzhiyun return;
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
1366*4882a593Smuzhiyun struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun if (entry->mem_ptr) {
1369*4882a593Smuzhiyun vfree(entry->mem_ptr);
1370*4882a593Smuzhiyun entry->mem_ptr = NULL;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun entry->mem_size = 0;
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun btmrvl_sdio_wakeup_fw(priv);
1376*4882a593Smuzhiyun sdio_claim_host(card->func);
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun BT_INFO("== btmrvl firmware dump start ==");
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
1381*4882a593Smuzhiyun if (stat == RDWR_STATUS_FAILURE)
1382*4882a593Smuzhiyun goto done;
1383*4882a593Smuzhiyun
1384*4882a593Smuzhiyun reg = card->reg->fw_dump_start;
1385*4882a593Smuzhiyun /* Read the number of the memories which will dump */
1386*4882a593Smuzhiyun dump_num = sdio_readb(card->func, reg, &ret);
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun if (ret) {
1389*4882a593Smuzhiyun BT_ERR("SDIO read memory length err");
1390*4882a593Smuzhiyun goto done;
1391*4882a593Smuzhiyun }
1392*4882a593Smuzhiyun
1393*4882a593Smuzhiyun /* Read the length of every memory which will dump */
1394*4882a593Smuzhiyun for (idx = 0; idx < dump_num; idx++) {
1395*4882a593Smuzhiyun struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
1398*4882a593Smuzhiyun if (stat == RDWR_STATUS_FAILURE)
1399*4882a593Smuzhiyun goto done;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun memory_size = 0;
1402*4882a593Smuzhiyun reg = card->reg->fw_dump_start;
1403*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1404*4882a593Smuzhiyun read_reg = sdio_readb(card->func, reg, &ret);
1405*4882a593Smuzhiyun if (ret) {
1406*4882a593Smuzhiyun BT_ERR("SDIO read err");
1407*4882a593Smuzhiyun goto done;
1408*4882a593Smuzhiyun }
1409*4882a593Smuzhiyun memory_size |= (read_reg << i*8);
1410*4882a593Smuzhiyun reg++;
1411*4882a593Smuzhiyun }
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun if (memory_size == 0) {
1414*4882a593Smuzhiyun BT_INFO("Firmware dump finished!");
1415*4882a593Smuzhiyun sdio_writeb(card->func, FW_DUMP_READ_DONE,
1416*4882a593Smuzhiyun card->reg->fw_dump_ctrl, &ret);
1417*4882a593Smuzhiyun if (ret) {
1418*4882a593Smuzhiyun BT_ERR("SDIO Write MEMDUMP_FINISH ERR");
1419*4882a593Smuzhiyun goto done;
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun break;
1422*4882a593Smuzhiyun }
1423*4882a593Smuzhiyun
1424*4882a593Smuzhiyun BT_INFO("%s_SIZE=0x%x", entry->mem_name, memory_size);
1425*4882a593Smuzhiyun entry->mem_ptr = vzalloc(memory_size + 1);
1426*4882a593Smuzhiyun entry->mem_size = memory_size;
1427*4882a593Smuzhiyun if (!entry->mem_ptr) {
1428*4882a593Smuzhiyun BT_ERR("Vzalloc %s failed", entry->mem_name);
1429*4882a593Smuzhiyun goto done;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun fw_dump_len += (strlen("========Start dump ") +
1433*4882a593Smuzhiyun strlen(entry->mem_name) +
1434*4882a593Smuzhiyun strlen("========\n") +
1435*4882a593Smuzhiyun (memory_size + 1) +
1436*4882a593Smuzhiyun strlen("\n========End dump========\n"));
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun dbg_ptr = entry->mem_ptr;
1439*4882a593Smuzhiyun end_ptr = dbg_ptr + memory_size;
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun doneflag = entry->done_flag;
1442*4882a593Smuzhiyun BT_INFO("Start %s output, please wait...",
1443*4882a593Smuzhiyun entry->mem_name);
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun do {
1446*4882a593Smuzhiyun stat = btmrvl_sdio_rdwr_firmware(priv, doneflag);
1447*4882a593Smuzhiyun if (stat == RDWR_STATUS_FAILURE)
1448*4882a593Smuzhiyun goto done;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun reg_start = card->reg->fw_dump_start;
1451*4882a593Smuzhiyun reg_end = card->reg->fw_dump_end;
1452*4882a593Smuzhiyun for (reg = reg_start; reg <= reg_end; reg++) {
1453*4882a593Smuzhiyun *dbg_ptr = sdio_readb(card->func, reg, &ret);
1454*4882a593Smuzhiyun if (ret) {
1455*4882a593Smuzhiyun BT_ERR("SDIO read err");
1456*4882a593Smuzhiyun goto done;
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun if (dbg_ptr < end_ptr)
1459*4882a593Smuzhiyun dbg_ptr++;
1460*4882a593Smuzhiyun else
1461*4882a593Smuzhiyun BT_ERR("Allocated buffer not enough");
1462*4882a593Smuzhiyun }
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun if (stat != RDWR_STATUS_DONE) {
1465*4882a593Smuzhiyun continue;
1466*4882a593Smuzhiyun } else {
1467*4882a593Smuzhiyun BT_INFO("%s done: size=0x%tx",
1468*4882a593Smuzhiyun entry->mem_name,
1469*4882a593Smuzhiyun dbg_ptr - entry->mem_ptr);
1470*4882a593Smuzhiyun break;
1471*4882a593Smuzhiyun }
1472*4882a593Smuzhiyun } while (1);
1473*4882a593Smuzhiyun }
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun BT_INFO("== btmrvl firmware dump end ==");
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun done:
1478*4882a593Smuzhiyun sdio_release_host(card->func);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun if (fw_dump_len == 0)
1481*4882a593Smuzhiyun return;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun fw_dump_data = vzalloc(fw_dump_len+1);
1484*4882a593Smuzhiyun if (!fw_dump_data) {
1485*4882a593Smuzhiyun BT_ERR("Vzalloc fw_dump_data fail!");
1486*4882a593Smuzhiyun return;
1487*4882a593Smuzhiyun }
1488*4882a593Smuzhiyun fw_dump_ptr = fw_dump_data;
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun /* Dump all the memory data into single file, a userspace script will
1491*4882a593Smuzhiyun * be used to split all the memory data to multiple files
1492*4882a593Smuzhiyun */
1493*4882a593Smuzhiyun BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump start");
1494*4882a593Smuzhiyun for (idx = 0; idx < dump_num; idx++) {
1495*4882a593Smuzhiyun struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun if (entry->mem_ptr) {
1498*4882a593Smuzhiyun strcpy(fw_dump_ptr, "========Start dump ");
1499*4882a593Smuzhiyun fw_dump_ptr += strlen("========Start dump ");
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun strcpy(fw_dump_ptr, entry->mem_name);
1502*4882a593Smuzhiyun fw_dump_ptr += strlen(entry->mem_name);
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun strcpy(fw_dump_ptr, "========\n");
1505*4882a593Smuzhiyun fw_dump_ptr += strlen("========\n");
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
1508*4882a593Smuzhiyun fw_dump_ptr += entry->mem_size;
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun strcpy(fw_dump_ptr, "\n========End dump========\n");
1511*4882a593Smuzhiyun fw_dump_ptr += strlen("\n========End dump========\n");
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun vfree(mem_type_mapping_tbl[idx].mem_ptr);
1514*4882a593Smuzhiyun mem_type_mapping_tbl[idx].mem_ptr = NULL;
1515*4882a593Smuzhiyun }
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun /* fw_dump_data will be free in device coredump release function
1519*4882a593Smuzhiyun * after 5 min
1520*4882a593Smuzhiyun */
1521*4882a593Smuzhiyun dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL);
1522*4882a593Smuzhiyun BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end");
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun
btmrvl_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)1525*4882a593Smuzhiyun static int btmrvl_sdio_probe(struct sdio_func *func,
1526*4882a593Smuzhiyun const struct sdio_device_id *id)
1527*4882a593Smuzhiyun {
1528*4882a593Smuzhiyun int ret = 0;
1529*4882a593Smuzhiyun struct btmrvl_private *priv = NULL;
1530*4882a593Smuzhiyun struct btmrvl_sdio_card *card = NULL;
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
1533*4882a593Smuzhiyun id->vendor, id->device, id->class, func->num);
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
1536*4882a593Smuzhiyun if (!card)
1537*4882a593Smuzhiyun return -ENOMEM;
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun card->func = func;
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun if (id->driver_data) {
1542*4882a593Smuzhiyun struct btmrvl_sdio_device *data = (void *) id->driver_data;
1543*4882a593Smuzhiyun card->helper = data->helper;
1544*4882a593Smuzhiyun card->firmware = data->firmware;
1545*4882a593Smuzhiyun card->reg = data->reg;
1546*4882a593Smuzhiyun card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
1547*4882a593Smuzhiyun card->support_pscan_win_report = data->support_pscan_win_report;
1548*4882a593Smuzhiyun card->supports_fw_dump = data->supports_fw_dump;
1549*4882a593Smuzhiyun }
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun if (btmrvl_sdio_register_dev(card) < 0) {
1552*4882a593Smuzhiyun BT_ERR("Failed to register BT device!");
1553*4882a593Smuzhiyun return -ENODEV;
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun
1556*4882a593Smuzhiyun /* Disable the interrupts on the card */
1557*4882a593Smuzhiyun btmrvl_sdio_disable_host_int(card);
1558*4882a593Smuzhiyun
1559*4882a593Smuzhiyun if (btmrvl_sdio_download_fw(card)) {
1560*4882a593Smuzhiyun BT_ERR("Downloading firmware failed!");
1561*4882a593Smuzhiyun ret = -ENODEV;
1562*4882a593Smuzhiyun goto unreg_dev;
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun btmrvl_sdio_enable_host_int(card);
1566*4882a593Smuzhiyun
1567*4882a593Smuzhiyun /* Device tree node parsing and platform specific configuration*/
1568*4882a593Smuzhiyun btmrvl_sdio_probe_of(&func->dev, card);
1569*4882a593Smuzhiyun
1570*4882a593Smuzhiyun priv = btmrvl_add_card(card);
1571*4882a593Smuzhiyun if (!priv) {
1572*4882a593Smuzhiyun BT_ERR("Initializing card failed!");
1573*4882a593Smuzhiyun ret = -ENODEV;
1574*4882a593Smuzhiyun goto disable_host_int;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun card->priv = priv;
1578*4882a593Smuzhiyun
1579*4882a593Smuzhiyun /* Initialize the interface specific function pointers */
1580*4882a593Smuzhiyun priv->hw_host_to_card = btmrvl_sdio_host_to_card;
1581*4882a593Smuzhiyun priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
1582*4882a593Smuzhiyun priv->hw_process_int_status = btmrvl_sdio_process_int_status;
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun if (btmrvl_register_hdev(priv)) {
1585*4882a593Smuzhiyun BT_ERR("Register hdev failed!");
1586*4882a593Smuzhiyun ret = -ENODEV;
1587*4882a593Smuzhiyun goto disable_host_int;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun return 0;
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun disable_host_int:
1593*4882a593Smuzhiyun btmrvl_sdio_disable_host_int(card);
1594*4882a593Smuzhiyun unreg_dev:
1595*4882a593Smuzhiyun btmrvl_sdio_unregister_dev(card);
1596*4882a593Smuzhiyun return ret;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
btmrvl_sdio_remove(struct sdio_func * func)1599*4882a593Smuzhiyun static void btmrvl_sdio_remove(struct sdio_func *func)
1600*4882a593Smuzhiyun {
1601*4882a593Smuzhiyun struct btmrvl_sdio_card *card;
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun if (func) {
1604*4882a593Smuzhiyun card = sdio_get_drvdata(func);
1605*4882a593Smuzhiyun if (card) {
1606*4882a593Smuzhiyun /* Send SHUTDOWN command & disable interrupt
1607*4882a593Smuzhiyun * if user removes the module.
1608*4882a593Smuzhiyun */
1609*4882a593Smuzhiyun if (user_rmmod) {
1610*4882a593Smuzhiyun btmrvl_send_module_cfg_cmd(card->priv,
1611*4882a593Smuzhiyun MODULE_SHUTDOWN_REQ);
1612*4882a593Smuzhiyun btmrvl_sdio_disable_host_int(card);
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun BT_DBG("unregister dev");
1616*4882a593Smuzhiyun card->priv->surprise_removed = true;
1617*4882a593Smuzhiyun btmrvl_sdio_unregister_dev(card);
1618*4882a593Smuzhiyun btmrvl_remove_card(card->priv);
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun }
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun
btmrvl_sdio_suspend(struct device * dev)1623*4882a593Smuzhiyun static int btmrvl_sdio_suspend(struct device *dev)
1624*4882a593Smuzhiyun {
1625*4882a593Smuzhiyun struct sdio_func *func = dev_to_sdio_func(dev);
1626*4882a593Smuzhiyun struct btmrvl_sdio_card *card;
1627*4882a593Smuzhiyun struct btmrvl_private *priv;
1628*4882a593Smuzhiyun mmc_pm_flag_t pm_flags;
1629*4882a593Smuzhiyun struct hci_dev *hcidev;
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun if (func) {
1632*4882a593Smuzhiyun pm_flags = sdio_get_host_pm_caps(func);
1633*4882a593Smuzhiyun BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func),
1634*4882a593Smuzhiyun pm_flags);
1635*4882a593Smuzhiyun if (!(pm_flags & MMC_PM_KEEP_POWER)) {
1636*4882a593Smuzhiyun BT_ERR("%s: cannot remain alive while suspended",
1637*4882a593Smuzhiyun sdio_func_id(func));
1638*4882a593Smuzhiyun return -ENOSYS;
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun card = sdio_get_drvdata(func);
1641*4882a593Smuzhiyun if (!card || !card->priv) {
1642*4882a593Smuzhiyun BT_ERR("card or priv structure is not valid");
1643*4882a593Smuzhiyun return 0;
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun } else {
1646*4882a593Smuzhiyun BT_ERR("sdio_func is not specified");
1647*4882a593Smuzhiyun return 0;
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun /* Enable platform specific wakeup interrupt */
1651*4882a593Smuzhiyun if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0 &&
1652*4882a593Smuzhiyun device_may_wakeup(dev)) {
1653*4882a593Smuzhiyun card->plt_wake_cfg->wake_by_bt = false;
1654*4882a593Smuzhiyun enable_irq(card->plt_wake_cfg->irq_bt);
1655*4882a593Smuzhiyun enable_irq_wake(card->plt_wake_cfg->irq_bt);
1656*4882a593Smuzhiyun }
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun priv = card->priv;
1659*4882a593Smuzhiyun priv->adapter->is_suspending = true;
1660*4882a593Smuzhiyun hcidev = priv->btmrvl_dev.hcidev;
1661*4882a593Smuzhiyun BT_DBG("%s: SDIO suspend", hcidev->name);
1662*4882a593Smuzhiyun hci_suspend_dev(hcidev);
1663*4882a593Smuzhiyun
1664*4882a593Smuzhiyun if (priv->adapter->hs_state != HS_ACTIVATED) {
1665*4882a593Smuzhiyun if (btmrvl_enable_hs(priv)) {
1666*4882a593Smuzhiyun BT_ERR("HS not activated, suspend failed!");
1667*4882a593Smuzhiyun /* Disable platform specific wakeup interrupt */
1668*4882a593Smuzhiyun if (card->plt_wake_cfg &&
1669*4882a593Smuzhiyun card->plt_wake_cfg->irq_bt >= 0 &&
1670*4882a593Smuzhiyun device_may_wakeup(dev)) {
1671*4882a593Smuzhiyun disable_irq_wake(card->plt_wake_cfg->irq_bt);
1672*4882a593Smuzhiyun disable_irq(card->plt_wake_cfg->irq_bt);
1673*4882a593Smuzhiyun }
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyun priv->adapter->is_suspending = false;
1676*4882a593Smuzhiyun return -EBUSY;
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun priv->adapter->is_suspending = false;
1681*4882a593Smuzhiyun priv->adapter->is_suspended = true;
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun /* We will keep the power when hs enabled successfully */
1684*4882a593Smuzhiyun if (priv->adapter->hs_state == HS_ACTIVATED) {
1685*4882a593Smuzhiyun BT_DBG("suspend with MMC_PM_KEEP_POWER");
1686*4882a593Smuzhiyun return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
1687*4882a593Smuzhiyun }
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun BT_DBG("suspend without MMC_PM_KEEP_POWER");
1690*4882a593Smuzhiyun return 0;
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun
btmrvl_sdio_resume(struct device * dev)1693*4882a593Smuzhiyun static int btmrvl_sdio_resume(struct device *dev)
1694*4882a593Smuzhiyun {
1695*4882a593Smuzhiyun struct sdio_func *func = dev_to_sdio_func(dev);
1696*4882a593Smuzhiyun struct btmrvl_sdio_card *card;
1697*4882a593Smuzhiyun struct btmrvl_private *priv;
1698*4882a593Smuzhiyun mmc_pm_flag_t pm_flags;
1699*4882a593Smuzhiyun struct hci_dev *hcidev;
1700*4882a593Smuzhiyun
1701*4882a593Smuzhiyun if (func) {
1702*4882a593Smuzhiyun pm_flags = sdio_get_host_pm_caps(func);
1703*4882a593Smuzhiyun BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func),
1704*4882a593Smuzhiyun pm_flags);
1705*4882a593Smuzhiyun card = sdio_get_drvdata(func);
1706*4882a593Smuzhiyun if (!card || !card->priv) {
1707*4882a593Smuzhiyun BT_ERR("card or priv structure is not valid");
1708*4882a593Smuzhiyun return 0;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun } else {
1711*4882a593Smuzhiyun BT_ERR("sdio_func is not specified");
1712*4882a593Smuzhiyun return 0;
1713*4882a593Smuzhiyun }
1714*4882a593Smuzhiyun priv = card->priv;
1715*4882a593Smuzhiyun
1716*4882a593Smuzhiyun if (!priv->adapter->is_suspended) {
1717*4882a593Smuzhiyun BT_DBG("device already resumed");
1718*4882a593Smuzhiyun return 0;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun priv->hw_wakeup_firmware(priv);
1722*4882a593Smuzhiyun priv->adapter->hs_state = HS_DEACTIVATED;
1723*4882a593Smuzhiyun hcidev = priv->btmrvl_dev.hcidev;
1724*4882a593Smuzhiyun BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name);
1725*4882a593Smuzhiyun priv->adapter->is_suspended = false;
1726*4882a593Smuzhiyun BT_DBG("%s: SDIO resume", hcidev->name);
1727*4882a593Smuzhiyun hci_resume_dev(hcidev);
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun /* Disable platform specific wakeup interrupt */
1730*4882a593Smuzhiyun if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0 &&
1731*4882a593Smuzhiyun device_may_wakeup(dev)) {
1732*4882a593Smuzhiyun disable_irq_wake(card->plt_wake_cfg->irq_bt);
1733*4882a593Smuzhiyun disable_irq(card->plt_wake_cfg->irq_bt);
1734*4882a593Smuzhiyun if (card->plt_wake_cfg->wake_by_bt)
1735*4882a593Smuzhiyun /* Undo our disable, since interrupt handler already
1736*4882a593Smuzhiyun * did this.
1737*4882a593Smuzhiyun */
1738*4882a593Smuzhiyun enable_irq(card->plt_wake_cfg->irq_bt);
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun return 0;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun static const struct dev_pm_ops btmrvl_sdio_pm_ops = {
1745*4882a593Smuzhiyun .suspend = btmrvl_sdio_suspend,
1746*4882a593Smuzhiyun .resume = btmrvl_sdio_resume,
1747*4882a593Smuzhiyun };
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun static struct sdio_driver bt_mrvl_sdio = {
1750*4882a593Smuzhiyun .name = "btmrvl_sdio",
1751*4882a593Smuzhiyun .id_table = btmrvl_sdio_ids,
1752*4882a593Smuzhiyun .probe = btmrvl_sdio_probe,
1753*4882a593Smuzhiyun .remove = btmrvl_sdio_remove,
1754*4882a593Smuzhiyun .drv = {
1755*4882a593Smuzhiyun .owner = THIS_MODULE,
1756*4882a593Smuzhiyun .coredump = btmrvl_sdio_coredump,
1757*4882a593Smuzhiyun .pm = &btmrvl_sdio_pm_ops,
1758*4882a593Smuzhiyun }
1759*4882a593Smuzhiyun };
1760*4882a593Smuzhiyun
btmrvl_sdio_init_module(void)1761*4882a593Smuzhiyun static int __init btmrvl_sdio_init_module(void)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun if (sdio_register_driver(&bt_mrvl_sdio) != 0) {
1764*4882a593Smuzhiyun BT_ERR("SDIO Driver Registration Failed");
1765*4882a593Smuzhiyun return -ENODEV;
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun
1768*4882a593Smuzhiyun /* Clear the flag in case user removes the card. */
1769*4882a593Smuzhiyun user_rmmod = 0;
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun return 0;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun
btmrvl_sdio_exit_module(void)1774*4882a593Smuzhiyun static void __exit btmrvl_sdio_exit_module(void)
1775*4882a593Smuzhiyun {
1776*4882a593Smuzhiyun /* Set the flag as user is removing this module. */
1777*4882a593Smuzhiyun user_rmmod = 1;
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun sdio_unregister_driver(&bt_mrvl_sdio);
1780*4882a593Smuzhiyun }
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun module_init(btmrvl_sdio_init_module);
1783*4882a593Smuzhiyun module_exit(btmrvl_sdio_exit_module);
1784*4882a593Smuzhiyun
1785*4882a593Smuzhiyun MODULE_AUTHOR("Marvell International Ltd.");
1786*4882a593Smuzhiyun MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
1787*4882a593Smuzhiyun MODULE_VERSION(VERSION);
1788*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1789*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
1790*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8688.bin");
1791*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
1792*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
1793*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
1794*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
1795*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sdsd8977_combo_v2.bin");
1796*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sd8987_uapsta.bin");
1797*4882a593Smuzhiyun MODULE_FIRMWARE("mrvl/sdsd8997_combo_v4.bin");
1798