1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun Driver for the Marvell 8385 based compact flash WLAN cards.
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/moduleparam.h>
17*4882a593Smuzhiyun #include <linux/firmware.h>
18*4882a593Smuzhiyun #include <linux/netdevice.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
21*4882a593Smuzhiyun #include <pcmcia/ds.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/io.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define DRV_NAME "libertas_cs"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "decl.h"
28*4882a593Smuzhiyun #include "defs.h"
29*4882a593Smuzhiyun #include "dev.h"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /********************************************************************/
33*4882a593Smuzhiyun /* Module stuff */
34*4882a593Smuzhiyun /********************************************************************/
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
37*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
38*4882a593Smuzhiyun MODULE_LICENSE("GPL");
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /********************************************************************/
43*4882a593Smuzhiyun /* Data structures */
44*4882a593Smuzhiyun /********************************************************************/
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct if_cs_card {
47*4882a593Smuzhiyun struct pcmcia_device *p_dev;
48*4882a593Smuzhiyun struct lbs_private *priv;
49*4882a593Smuzhiyun void __iomem *iobase;
50*4882a593Smuzhiyun bool align_regs;
51*4882a593Smuzhiyun u32 model;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun enum {
56*4882a593Smuzhiyun MODEL_UNKNOWN = 0x00,
57*4882a593Smuzhiyun MODEL_8305 = 0x01,
58*4882a593Smuzhiyun MODEL_8381 = 0x02,
59*4882a593Smuzhiyun MODEL_8385 = 0x03
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static const struct lbs_fw_table fw_table[] = {
63*4882a593Smuzhiyun { MODEL_8305, "libertas/cf8305.bin", NULL },
64*4882a593Smuzhiyun { MODEL_8305, "libertas_cs_helper.fw", NULL },
65*4882a593Smuzhiyun { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
66*4882a593Smuzhiyun { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
67*4882a593Smuzhiyun { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
68*4882a593Smuzhiyun { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
69*4882a593Smuzhiyun { 0, NULL, NULL }
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/cf8305.bin");
72*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/cf8381_helper.bin");
73*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/cf8381.bin");
74*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/cf8385_helper.bin");
75*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/cf8385.bin");
76*4882a593Smuzhiyun MODULE_FIRMWARE("libertas_cs_helper.fw");
77*4882a593Smuzhiyun MODULE_FIRMWARE("libertas_cs.fw");
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /********************************************************************/
81*4882a593Smuzhiyun /* Hardware access */
82*4882a593Smuzhiyun /********************************************************************/
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /* This define enables wrapper functions which allow you
85*4882a593Smuzhiyun to dump all register accesses. You normally won't this,
86*4882a593Smuzhiyun except for development */
87*4882a593Smuzhiyun /* #define DEBUG_IO */
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun #ifdef DEBUG_IO
90*4882a593Smuzhiyun static int debug_output = 0;
91*4882a593Smuzhiyun #else
92*4882a593Smuzhiyun /* This way the compiler optimizes the printk's away */
93*4882a593Smuzhiyun #define debug_output 0
94*4882a593Smuzhiyun #endif
95*4882a593Smuzhiyun
if_cs_read8(struct if_cs_card * card,uint reg)96*4882a593Smuzhiyun static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun unsigned int val = ioread8(card->iobase + reg);
99*4882a593Smuzhiyun if (debug_output)
100*4882a593Smuzhiyun printk(KERN_INFO "inb %08x<%02x\n", reg, val);
101*4882a593Smuzhiyun return val;
102*4882a593Smuzhiyun }
if_cs_read16(struct if_cs_card * card,uint reg)103*4882a593Smuzhiyun static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun unsigned int val = ioread16(card->iobase + reg);
106*4882a593Smuzhiyun if (debug_output)
107*4882a593Smuzhiyun printk(KERN_INFO "inw %08x<%04x\n", reg, val);
108*4882a593Smuzhiyun return val;
109*4882a593Smuzhiyun }
if_cs_read16_rep(struct if_cs_card * card,uint reg,void * buf,unsigned long count)110*4882a593Smuzhiyun static inline void if_cs_read16_rep(
111*4882a593Smuzhiyun struct if_cs_card *card,
112*4882a593Smuzhiyun uint reg,
113*4882a593Smuzhiyun void *buf,
114*4882a593Smuzhiyun unsigned long count)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun if (debug_output)
117*4882a593Smuzhiyun printk(KERN_INFO "insw %08x<(0x%lx words)\n",
118*4882a593Smuzhiyun reg, count);
119*4882a593Smuzhiyun ioread16_rep(card->iobase + reg, buf, count);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
if_cs_write8(struct if_cs_card * card,uint reg,u8 val)122*4882a593Smuzhiyun static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun if (debug_output)
125*4882a593Smuzhiyun printk(KERN_INFO "outb %08x>%02x\n", reg, val);
126*4882a593Smuzhiyun iowrite8(val, card->iobase + reg);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
if_cs_write16(struct if_cs_card * card,uint reg,u16 val)129*4882a593Smuzhiyun static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun if (debug_output)
132*4882a593Smuzhiyun printk(KERN_INFO "outw %08x>%04x\n", reg, val);
133*4882a593Smuzhiyun iowrite16(val, card->iobase + reg);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
if_cs_write16_rep(struct if_cs_card * card,uint reg,const void * buf,unsigned long count)136*4882a593Smuzhiyun static inline void if_cs_write16_rep(
137*4882a593Smuzhiyun struct if_cs_card *card,
138*4882a593Smuzhiyun uint reg,
139*4882a593Smuzhiyun const void *buf,
140*4882a593Smuzhiyun unsigned long count)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun if (debug_output)
143*4882a593Smuzhiyun printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
144*4882a593Smuzhiyun reg, count);
145*4882a593Smuzhiyun iowrite16_rep(card->iobase + reg, buf, count);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /*
150*4882a593Smuzhiyun * I know that polling/delaying is frowned upon. However, this procedure
151*4882a593Smuzhiyun * with polling is needed while downloading the firmware. At this stage,
152*4882a593Smuzhiyun * the hardware does unfortunately not create any interrupts.
153*4882a593Smuzhiyun *
154*4882a593Smuzhiyun * Fortunately, this function is never used once the firmware is in
155*4882a593Smuzhiyun * the card. :-)
156*4882a593Smuzhiyun *
157*4882a593Smuzhiyun * As a reference, see the "Firmware Specification v5.1", page 18
158*4882a593Smuzhiyun * and 19. I did not follow their suggested timing to the word,
159*4882a593Smuzhiyun * but this works nice & fast anyway.
160*4882a593Smuzhiyun */
if_cs_poll_while_fw_download(struct if_cs_card * card,uint addr,u8 reg)161*4882a593Smuzhiyun static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun int i;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun for (i = 0; i < 100000; i++) {
166*4882a593Smuzhiyun u8 val = if_cs_read8(card, addr);
167*4882a593Smuzhiyun if (val == reg)
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun udelay(5);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun return -ETIME;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /*
177*4882a593Smuzhiyun * First the bitmasks for the host/card interrupt/status registers:
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun #define IF_CS_BIT_TX 0x0001
180*4882a593Smuzhiyun #define IF_CS_BIT_RX 0x0002
181*4882a593Smuzhiyun #define IF_CS_BIT_COMMAND 0x0004
182*4882a593Smuzhiyun #define IF_CS_BIT_RESP 0x0008
183*4882a593Smuzhiyun #define IF_CS_BIT_EVENT 0x0010
184*4882a593Smuzhiyun #define IF_CS_BIT_MASK 0x001f
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /*
189*4882a593Smuzhiyun * It's not really clear to me what the host status register is for. It
190*4882a593Smuzhiyun * needs to be set almost in union with "host int cause". The following
191*4882a593Smuzhiyun * bits from above are used:
192*4882a593Smuzhiyun *
193*4882a593Smuzhiyun * IF_CS_BIT_TX driver downloaded a data packet
194*4882a593Smuzhiyun * IF_CS_BIT_RX driver got a data packet
195*4882a593Smuzhiyun * IF_CS_BIT_COMMAND driver downloaded a command
196*4882a593Smuzhiyun * IF_CS_BIT_RESP not used (has some meaning with powerdown)
197*4882a593Smuzhiyun * IF_CS_BIT_EVENT driver read a host event
198*4882a593Smuzhiyun */
199*4882a593Smuzhiyun #define IF_CS_HOST_STATUS 0x00000000
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /*
202*4882a593Smuzhiyun * With the host int cause register can the host (that is, Linux) cause
203*4882a593Smuzhiyun * an interrupt in the firmware, to tell the firmware about those events:
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * IF_CS_BIT_TX a data packet has been downloaded
206*4882a593Smuzhiyun * IF_CS_BIT_RX a received data packet has retrieved
207*4882a593Smuzhiyun * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded
208*4882a593Smuzhiyun * IF_CS_BIT_RESP not used (has some meaning with powerdown)
209*4882a593Smuzhiyun * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved
210*4882a593Smuzhiyun */
211*4882a593Smuzhiyun #define IF_CS_HOST_INT_CAUSE 0x00000002
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /*
214*4882a593Smuzhiyun * The host int mask register is used to enable/disable interrupt. However,
215*4882a593Smuzhiyun * I have the suspicion that disabled interrupts are lost.
216*4882a593Smuzhiyun */
217*4882a593Smuzhiyun #define IF_CS_HOST_INT_MASK 0x00000004
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun * Used to send or receive data packets:
221*4882a593Smuzhiyun */
222*4882a593Smuzhiyun #define IF_CS_WRITE 0x00000016
223*4882a593Smuzhiyun #define IF_CS_WRITE_LEN 0x00000014
224*4882a593Smuzhiyun #define IF_CS_READ 0x00000010
225*4882a593Smuzhiyun #define IF_CS_READ_LEN 0x00000024
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun * Used to send commands (and to send firmware block) and to
229*4882a593Smuzhiyun * receive command responses:
230*4882a593Smuzhiyun */
231*4882a593Smuzhiyun #define IF_CS_CMD 0x0000001A
232*4882a593Smuzhiyun #define IF_CS_CMD_LEN 0x00000018
233*4882a593Smuzhiyun #define IF_CS_RESP 0x00000012
234*4882a593Smuzhiyun #define IF_CS_RESP_LEN 0x00000030
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun * The card status registers shows what the card/firmware actually
238*4882a593Smuzhiyun * accepts:
239*4882a593Smuzhiyun *
240*4882a593Smuzhiyun * IF_CS_BIT_TX you may send a data packet
241*4882a593Smuzhiyun * IF_CS_BIT_RX you may retrieve a data packet
242*4882a593Smuzhiyun * IF_CS_BIT_COMMAND you may send a command
243*4882a593Smuzhiyun * IF_CS_BIT_RESP you may retrieve a command response
244*4882a593Smuzhiyun * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
245*4882a593Smuzhiyun *
246*4882a593Smuzhiyun * When reading this register several times, you will get back the same
247*4882a593Smuzhiyun * results --- with one exception: the IF_CS_BIT_EVENT clear itself
248*4882a593Smuzhiyun * automatically.
249*4882a593Smuzhiyun *
250*4882a593Smuzhiyun * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because
251*4882a593Smuzhiyun * we handle this via the card int cause register.
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun #define IF_CS_CARD_STATUS 0x00000020
254*4882a593Smuzhiyun #define IF_CS_CARD_STATUS_MASK 0x7f00
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /*
257*4882a593Smuzhiyun * The card int cause register is used by the card/firmware to notify us
258*4882a593Smuzhiyun * about the following events:
259*4882a593Smuzhiyun *
260*4882a593Smuzhiyun * IF_CS_BIT_TX a data packet has successfully been sentx
261*4882a593Smuzhiyun * IF_CS_BIT_RX a data packet has been received and can be retrieved
262*4882a593Smuzhiyun * IF_CS_BIT_COMMAND not used
263*4882a593Smuzhiyun * IF_CS_BIT_RESP the firmware has a command response for us
264*4882a593Smuzhiyun * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
265*4882a593Smuzhiyun */
266*4882a593Smuzhiyun #define IF_CS_CARD_INT_CAUSE 0x00000022
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /*
269*4882a593Smuzhiyun * This is used to for handshaking with the card's bootloader/helper image
270*4882a593Smuzhiyun * to synchronize downloading of firmware blocks.
271*4882a593Smuzhiyun */
272*4882a593Smuzhiyun #define IF_CS_SQ_READ_LOW 0x00000028
273*4882a593Smuzhiyun #define IF_CS_SQ_HELPER_OK 0x10
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /*
276*4882a593Smuzhiyun * The scratch register tells us ...
277*4882a593Smuzhiyun *
278*4882a593Smuzhiyun * IF_CS_SCRATCH_BOOT_OK the bootloader runs
279*4882a593Smuzhiyun * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs
280*4882a593Smuzhiyun */
281*4882a593Smuzhiyun #define IF_CS_SCRATCH 0x0000003F
282*4882a593Smuzhiyun #define IF_CS_SCRATCH_BOOT_OK 0x00
283*4882a593Smuzhiyun #define IF_CS_SCRATCH_HELPER_OK 0x5a
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /*
286*4882a593Smuzhiyun * Used to detect ancient chips:
287*4882a593Smuzhiyun */
288*4882a593Smuzhiyun #define IF_CS_PRODUCT_ID 0x0000001C
289*4882a593Smuzhiyun #define IF_CS_CF8385_B1_REV 0x12
290*4882a593Smuzhiyun #define IF_CS_CF8381_B3_REV 0x04
291*4882a593Smuzhiyun #define IF_CS_CF8305_B1_REV 0x03
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /*
294*4882a593Smuzhiyun * Used to detect other cards than CF8385 since their revisions of silicon
295*4882a593Smuzhiyun * doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
296*4882a593Smuzhiyun */
297*4882a593Smuzhiyun #define CF8305_MANFID 0x02db
298*4882a593Smuzhiyun #define CF8305_CARDID 0x8103
299*4882a593Smuzhiyun #define CF8381_MANFID 0x02db
300*4882a593Smuzhiyun #define CF8381_CARDID 0x6064
301*4882a593Smuzhiyun #define CF8385_MANFID 0x02df
302*4882a593Smuzhiyun #define CF8385_CARDID 0x8103
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /*
305*4882a593Smuzhiyun * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
306*4882a593Smuzhiyun * that gets fixed. Currently there's no way to access it from the probe hook.
307*4882a593Smuzhiyun */
get_model(u16 manf_id,u16 card_id)308*4882a593Smuzhiyun static inline u32 get_model(u16 manf_id, u16 card_id)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun /* NOTE: keep in sync with if_cs_ids */
311*4882a593Smuzhiyun if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
312*4882a593Smuzhiyun return MODEL_8305;
313*4882a593Smuzhiyun else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
314*4882a593Smuzhiyun return MODEL_8381;
315*4882a593Smuzhiyun else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
316*4882a593Smuzhiyun return MODEL_8385;
317*4882a593Smuzhiyun return MODEL_UNKNOWN;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /********************************************************************/
321*4882a593Smuzhiyun /* I/O and interrupt handling */
322*4882a593Smuzhiyun /********************************************************************/
323*4882a593Smuzhiyun
if_cs_enable_ints(struct if_cs_card * card)324*4882a593Smuzhiyun static inline void if_cs_enable_ints(struct if_cs_card *card)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
if_cs_disable_ints(struct if_cs_card * card)329*4882a593Smuzhiyun static inline void if_cs_disable_ints(struct if_cs_card *card)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /*
335*4882a593Smuzhiyun * Called from if_cs_host_to_card to send a command to the hardware
336*4882a593Smuzhiyun */
if_cs_send_cmd(struct lbs_private * priv,u8 * buf,u16 nb)337*4882a593Smuzhiyun static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun struct if_cs_card *card = (struct if_cs_card *)priv->card;
340*4882a593Smuzhiyun int ret = -1;
341*4882a593Smuzhiyun int loops = 0;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if_cs_disable_ints(card);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /* Is hardware ready? */
346*4882a593Smuzhiyun while (1) {
347*4882a593Smuzhiyun u16 status = if_cs_read16(card, IF_CS_CARD_STATUS);
348*4882a593Smuzhiyun if (status & IF_CS_BIT_COMMAND)
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun if (++loops > 100) {
351*4882a593Smuzhiyun netdev_err(priv->dev, "card not ready for commands\n");
352*4882a593Smuzhiyun goto done;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun mdelay(1);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if_cs_write16(card, IF_CS_CMD_LEN, nb);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2);
360*4882a593Smuzhiyun /* Are we supposed to transfer an odd amount of bytes? */
361*4882a593Smuzhiyun if (nb & 1)
362*4882a593Smuzhiyun if_cs_write8(card, IF_CS_CMD, buf[nb-1]);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* "Assert the download over interrupt command in the Host
365*4882a593Smuzhiyun * status register" */
366*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* "Assert the download over interrupt command in the Card
369*4882a593Smuzhiyun * interrupt case register" */
370*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
371*4882a593Smuzhiyun ret = 0;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun done:
374*4882a593Smuzhiyun if_cs_enable_ints(card);
375*4882a593Smuzhiyun return ret;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /*
379*4882a593Smuzhiyun * Called from if_cs_host_to_card to send a data to the hardware
380*4882a593Smuzhiyun */
if_cs_send_data(struct lbs_private * priv,u8 * buf,u16 nb)381*4882a593Smuzhiyun static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun struct if_cs_card *card = (struct if_cs_card *)priv->card;
384*4882a593Smuzhiyun u16 status;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun if_cs_disable_ints(card);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun status = if_cs_read16(card, IF_CS_CARD_STATUS);
389*4882a593Smuzhiyun BUG_ON((status & IF_CS_BIT_TX) == 0);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if_cs_write16(card, IF_CS_WRITE_LEN, nb);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /* write even number of bytes, then odd byte if necessary */
394*4882a593Smuzhiyun if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2);
395*4882a593Smuzhiyun if (nb & 1)
396*4882a593Smuzhiyun if_cs_write8(card, IF_CS_WRITE, buf[nb-1]);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
399*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
400*4882a593Smuzhiyun if_cs_enable_ints(card);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * Get the command result out of the card.
405*4882a593Smuzhiyun */
if_cs_receive_cmdres(struct lbs_private * priv,u8 * data,u32 * len)406*4882a593Smuzhiyun static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun unsigned long flags;
409*4882a593Smuzhiyun int ret = -1;
410*4882a593Smuzhiyun u16 status;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* is hardware ready? */
413*4882a593Smuzhiyun status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
414*4882a593Smuzhiyun if ((status & IF_CS_BIT_RESP) == 0) {
415*4882a593Smuzhiyun netdev_err(priv->dev, "no cmd response in card\n");
416*4882a593Smuzhiyun *len = 0;
417*4882a593Smuzhiyun goto out;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun *len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
421*4882a593Smuzhiyun if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
422*4882a593Smuzhiyun netdev_err(priv->dev,
423*4882a593Smuzhiyun "card cmd buffer has invalid # of bytes (%d)\n",
424*4882a593Smuzhiyun *len);
425*4882a593Smuzhiyun goto out;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* read even number of bytes, then odd byte if necessary */
429*4882a593Smuzhiyun if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16));
430*4882a593Smuzhiyun if (*len & 1)
431*4882a593Smuzhiyun data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /* This is a workaround for a firmware that reports too much
434*4882a593Smuzhiyun * bytes */
435*4882a593Smuzhiyun *len -= 8;
436*4882a593Smuzhiyun ret = 0;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* Clear this flag again */
439*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
440*4882a593Smuzhiyun priv->dnld_sent = DNLD_RES_RECEIVED;
441*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun out:
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
if_cs_receive_data(struct lbs_private * priv)447*4882a593Smuzhiyun static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun struct sk_buff *skb = NULL;
450*4882a593Smuzhiyun u16 len;
451*4882a593Smuzhiyun u8 *data;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun len = if_cs_read16(priv->card, IF_CS_READ_LEN);
454*4882a593Smuzhiyun if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
455*4882a593Smuzhiyun netdev_err(priv->dev,
456*4882a593Smuzhiyun "card data buffer has invalid # of bytes (%d)\n",
457*4882a593Smuzhiyun len);
458*4882a593Smuzhiyun priv->dev->stats.rx_dropped++;
459*4882a593Smuzhiyun goto dat_err;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
463*4882a593Smuzhiyun if (!skb)
464*4882a593Smuzhiyun goto out;
465*4882a593Smuzhiyun skb_put(skb, len);
466*4882a593Smuzhiyun skb_reserve(skb, 2);/* 16 byte align */
467*4882a593Smuzhiyun data = skb->data;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* read even number of bytes, then odd byte if necessary */
470*4882a593Smuzhiyun if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
471*4882a593Smuzhiyun if (len & 1)
472*4882a593Smuzhiyun data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun dat_err:
475*4882a593Smuzhiyun if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
476*4882a593Smuzhiyun if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun out:
479*4882a593Smuzhiyun return skb;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
if_cs_interrupt(int irq,void * data)482*4882a593Smuzhiyun static irqreturn_t if_cs_interrupt(int irq, void *data)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun struct if_cs_card *card = data;
485*4882a593Smuzhiyun struct lbs_private *priv = card->priv;
486*4882a593Smuzhiyun u16 cause;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /* Ask card interrupt cause register if there is something for us */
489*4882a593Smuzhiyun cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
490*4882a593Smuzhiyun lbs_deb_cs("cause 0x%04x\n", cause);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (cause == 0) {
493*4882a593Smuzhiyun /* Not for us */
494*4882a593Smuzhiyun return IRQ_NONE;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (cause == 0xffff) {
498*4882a593Smuzhiyun /* Read in junk, the card has probably been removed */
499*4882a593Smuzhiyun card->priv->surpriseremoved = 1;
500*4882a593Smuzhiyun return IRQ_HANDLED;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (cause & IF_CS_BIT_RX) {
504*4882a593Smuzhiyun struct sk_buff *skb;
505*4882a593Smuzhiyun lbs_deb_cs("rx packet\n");
506*4882a593Smuzhiyun skb = if_cs_receive_data(priv);
507*4882a593Smuzhiyun if (skb)
508*4882a593Smuzhiyun lbs_process_rxed_packet(priv, skb);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun if (cause & IF_CS_BIT_TX) {
512*4882a593Smuzhiyun lbs_deb_cs("tx done\n");
513*4882a593Smuzhiyun lbs_host_to_card_done(priv);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun if (cause & IF_CS_BIT_RESP) {
517*4882a593Smuzhiyun unsigned long flags;
518*4882a593Smuzhiyun u8 i;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun lbs_deb_cs("cmd resp\n");
521*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
522*4882a593Smuzhiyun i = (priv->resp_idx == 0) ? 1 : 0;
523*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun BUG_ON(priv->resp_len[i]);
526*4882a593Smuzhiyun if_cs_receive_cmdres(priv, priv->resp_buf[i],
527*4882a593Smuzhiyun &priv->resp_len[i]);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
530*4882a593Smuzhiyun lbs_notify_command_response(priv, i);
531*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (cause & IF_CS_BIT_EVENT) {
535*4882a593Smuzhiyun u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
536*4882a593Smuzhiyun if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
537*4882a593Smuzhiyun IF_CS_BIT_EVENT);
538*4882a593Smuzhiyun lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* Clear interrupt cause */
542*4882a593Smuzhiyun if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun return IRQ_HANDLED;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /********************************************************************/
551*4882a593Smuzhiyun /* Firmware */
552*4882a593Smuzhiyun /********************************************************************/
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /*
555*4882a593Smuzhiyun * Tries to program the helper firmware.
556*4882a593Smuzhiyun *
557*4882a593Smuzhiyun * Return 0 on success
558*4882a593Smuzhiyun */
if_cs_prog_helper(struct if_cs_card * card,const struct firmware * fw)559*4882a593Smuzhiyun static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun int ret = 0;
562*4882a593Smuzhiyun int sent = 0;
563*4882a593Smuzhiyun u8 scratch;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /*
566*4882a593Smuzhiyun * This is the only place where an unaligned register access happens on
567*4882a593Smuzhiyun * the CF8305 card, therefore for the sake of speed of the driver, we do
568*4882a593Smuzhiyun * the alignment correction here.
569*4882a593Smuzhiyun */
570*4882a593Smuzhiyun if (card->align_regs)
571*4882a593Smuzhiyun scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
572*4882a593Smuzhiyun else
573*4882a593Smuzhiyun scratch = if_cs_read8(card, IF_CS_SCRATCH);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /* "If the value is 0x5a, the firmware is already
576*4882a593Smuzhiyun * downloaded successfully"
577*4882a593Smuzhiyun */
578*4882a593Smuzhiyun if (scratch == IF_CS_SCRATCH_HELPER_OK)
579*4882a593Smuzhiyun goto done;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /* "If the value is != 00, it is invalid value of register */
582*4882a593Smuzhiyun if (scratch != IF_CS_SCRATCH_BOOT_OK) {
583*4882a593Smuzhiyun ret = -ENODEV;
584*4882a593Smuzhiyun goto done;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun lbs_deb_cs("helper size %td\n", fw->size);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun /* "Set the 5 bytes of the helper image to 0" */
590*4882a593Smuzhiyun /* Not needed, this contains an ARM branch instruction */
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun for (;;) {
593*4882a593Smuzhiyun /* "the number of bytes to send is 256" */
594*4882a593Smuzhiyun int count = 256;
595*4882a593Smuzhiyun int remain = fw->size - sent;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (remain < count)
598*4882a593Smuzhiyun count = remain;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun /*
601*4882a593Smuzhiyun * "write the number of bytes to be sent to the I/O Command
602*4882a593Smuzhiyun * write length register"
603*4882a593Smuzhiyun */
604*4882a593Smuzhiyun if_cs_write16(card, IF_CS_CMD_LEN, count);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* "write this to I/O Command port register as 16 bit writes */
607*4882a593Smuzhiyun if (count)
608*4882a593Smuzhiyun if_cs_write16_rep(card, IF_CS_CMD,
609*4882a593Smuzhiyun &fw->data[sent],
610*4882a593Smuzhiyun count >> 1);
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun /*
613*4882a593Smuzhiyun * "Assert the download over interrupt command in the Host
614*4882a593Smuzhiyun * status register"
615*4882a593Smuzhiyun */
616*4882a593Smuzhiyun if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /*
619*4882a593Smuzhiyun * "Assert the download over interrupt command in the Card
620*4882a593Smuzhiyun * interrupt case register"
621*4882a593Smuzhiyun */
622*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /*
625*4882a593Smuzhiyun * "The host polls the Card Status register ... for 50 ms before
626*4882a593Smuzhiyun * declaring a failure"
627*4882a593Smuzhiyun */
628*4882a593Smuzhiyun ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
629*4882a593Smuzhiyun IF_CS_BIT_COMMAND);
630*4882a593Smuzhiyun if (ret < 0) {
631*4882a593Smuzhiyun pr_err("can't download helper at 0x%x, ret %d\n",
632*4882a593Smuzhiyun sent, ret);
633*4882a593Smuzhiyun goto done;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun if (count == 0)
637*4882a593Smuzhiyun break;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun sent += count;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun done:
643*4882a593Smuzhiyun return ret;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun
if_cs_prog_real(struct if_cs_card * card,const struct firmware * fw)647*4882a593Smuzhiyun static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun int ret = 0;
650*4882a593Smuzhiyun int retry = 0;
651*4882a593Smuzhiyun int len = 0;
652*4882a593Smuzhiyun int sent;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun lbs_deb_cs("fw size %td\n", fw->size);
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
657*4882a593Smuzhiyun IF_CS_SQ_HELPER_OK);
658*4882a593Smuzhiyun if (ret < 0) {
659*4882a593Smuzhiyun pr_err("helper firmware doesn't answer\n");
660*4882a593Smuzhiyun goto done;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun for (sent = 0; sent < fw->size; sent += len) {
664*4882a593Smuzhiyun len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
665*4882a593Smuzhiyun if (len & 1) {
666*4882a593Smuzhiyun retry++;
667*4882a593Smuzhiyun pr_info("odd, need to retry this firmware block\n");
668*4882a593Smuzhiyun } else {
669*4882a593Smuzhiyun retry = 0;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (retry > 20) {
673*4882a593Smuzhiyun pr_err("could not download firmware\n");
674*4882a593Smuzhiyun ret = -ENODEV;
675*4882a593Smuzhiyun goto done;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun if (retry) {
678*4882a593Smuzhiyun sent -= len;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun if_cs_write16(card, IF_CS_CMD_LEN, len);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if_cs_write16_rep(card, IF_CS_CMD,
685*4882a593Smuzhiyun &fw->data[sent],
686*4882a593Smuzhiyun (len+1) >> 1);
687*4882a593Smuzhiyun if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
688*4882a593Smuzhiyun if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
691*4882a593Smuzhiyun IF_CS_BIT_COMMAND);
692*4882a593Smuzhiyun if (ret < 0) {
693*4882a593Smuzhiyun pr_err("can't download firmware at 0x%x\n", sent);
694*4882a593Smuzhiyun goto done;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
699*4882a593Smuzhiyun if (ret < 0)
700*4882a593Smuzhiyun pr_err("firmware download failed\n");
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun done:
703*4882a593Smuzhiyun return ret;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
if_cs_prog_firmware(struct lbs_private * priv,int ret,const struct firmware * helper,const struct firmware * mainfw)706*4882a593Smuzhiyun static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
707*4882a593Smuzhiyun const struct firmware *helper,
708*4882a593Smuzhiyun const struct firmware *mainfw)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun struct if_cs_card *card = priv->card;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun if (ret) {
713*4882a593Smuzhiyun pr_err("failed to find firmware (%d)\n", ret);
714*4882a593Smuzhiyun return;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /* Load the firmware */
718*4882a593Smuzhiyun ret = if_cs_prog_helper(card, helper);
719*4882a593Smuzhiyun if (ret == 0 && (card->model != MODEL_8305))
720*4882a593Smuzhiyun ret = if_cs_prog_real(card, mainfw);
721*4882a593Smuzhiyun if (ret)
722*4882a593Smuzhiyun return;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun /* Now actually get the IRQ */
725*4882a593Smuzhiyun ret = request_irq(card->p_dev->irq, if_cs_interrupt,
726*4882a593Smuzhiyun IRQF_SHARED, DRV_NAME, card);
727*4882a593Smuzhiyun if (ret) {
728*4882a593Smuzhiyun pr_err("error in request_irq\n");
729*4882a593Smuzhiyun return;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /*
733*4882a593Smuzhiyun * Clear any interrupt cause that happened while sending
734*4882a593Smuzhiyun * firmware/initializing card
735*4882a593Smuzhiyun */
736*4882a593Smuzhiyun if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
737*4882a593Smuzhiyun if_cs_enable_ints(card);
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun /* And finally bring the card up */
740*4882a593Smuzhiyun priv->fw_ready = 1;
741*4882a593Smuzhiyun if (lbs_start_card(priv) != 0) {
742*4882a593Smuzhiyun pr_err("could not activate card\n");
743*4882a593Smuzhiyun free_irq(card->p_dev->irq, card);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun /********************************************************************/
749*4882a593Smuzhiyun /* Callback functions for libertas.ko */
750*4882a593Smuzhiyun /********************************************************************/
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun /* Send commands or data packets to the card */
if_cs_host_to_card(struct lbs_private * priv,u8 type,u8 * buf,u16 nb)753*4882a593Smuzhiyun static int if_cs_host_to_card(struct lbs_private *priv,
754*4882a593Smuzhiyun u8 type,
755*4882a593Smuzhiyun u8 *buf,
756*4882a593Smuzhiyun u16 nb)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun int ret = -1;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun switch (type) {
761*4882a593Smuzhiyun case MVMS_DAT:
762*4882a593Smuzhiyun priv->dnld_sent = DNLD_DATA_SENT;
763*4882a593Smuzhiyun if_cs_send_data(priv, buf, nb);
764*4882a593Smuzhiyun ret = 0;
765*4882a593Smuzhiyun break;
766*4882a593Smuzhiyun case MVMS_CMD:
767*4882a593Smuzhiyun priv->dnld_sent = DNLD_CMD_SENT;
768*4882a593Smuzhiyun ret = if_cs_send_cmd(priv, buf, nb);
769*4882a593Smuzhiyun break;
770*4882a593Smuzhiyun default:
771*4882a593Smuzhiyun netdev_err(priv->dev, "%s: unsupported type %d\n",
772*4882a593Smuzhiyun __func__, type);
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun return ret;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun
if_cs_release(struct pcmcia_device * p_dev)779*4882a593Smuzhiyun static void if_cs_release(struct pcmcia_device *p_dev)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun struct if_cs_card *card = p_dev->priv;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun free_irq(p_dev->irq, card);
784*4882a593Smuzhiyun pcmcia_disable_device(p_dev);
785*4882a593Smuzhiyun if (card->iobase)
786*4882a593Smuzhiyun ioport_unmap(card->iobase);
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun
if_cs_ioprobe(struct pcmcia_device * p_dev,void * priv_data)790*4882a593Smuzhiyun static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
793*4882a593Smuzhiyun p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun if (p_dev->resource[1]->end) {
796*4882a593Smuzhiyun pr_err("wrong CIS (check number of IO windows)\n");
797*4882a593Smuzhiyun return -ENODEV;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /* This reserves IO space but doesn't actually enable it */
801*4882a593Smuzhiyun return pcmcia_request_io(p_dev);
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
if_cs_probe(struct pcmcia_device * p_dev)804*4882a593Smuzhiyun static int if_cs_probe(struct pcmcia_device *p_dev)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun int ret = -ENOMEM;
807*4882a593Smuzhiyun unsigned int prod_id;
808*4882a593Smuzhiyun struct lbs_private *priv;
809*4882a593Smuzhiyun struct if_cs_card *card;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
812*4882a593Smuzhiyun if (!card)
813*4882a593Smuzhiyun goto out;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun card->p_dev = p_dev;
816*4882a593Smuzhiyun p_dev->priv = card;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
821*4882a593Smuzhiyun pr_err("error in pcmcia_loop_config\n");
822*4882a593Smuzhiyun goto out1;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun /*
826*4882a593Smuzhiyun * Allocate an interrupt line. Note that this does not assign
827*4882a593Smuzhiyun * a handler to the interrupt, unless the 'Handler' member of
828*4882a593Smuzhiyun * the irq structure is initialized.
829*4882a593Smuzhiyun */
830*4882a593Smuzhiyun if (!p_dev->irq)
831*4882a593Smuzhiyun goto out1;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun /* Initialize io access */
834*4882a593Smuzhiyun card->iobase = ioport_map(p_dev->resource[0]->start,
835*4882a593Smuzhiyun resource_size(p_dev->resource[0]));
836*4882a593Smuzhiyun if (!card->iobase) {
837*4882a593Smuzhiyun pr_err("error in ioport_map\n");
838*4882a593Smuzhiyun ret = -EIO;
839*4882a593Smuzhiyun goto out1;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun ret = pcmcia_enable_device(p_dev);
843*4882a593Smuzhiyun if (ret) {
844*4882a593Smuzhiyun pr_err("error in pcmcia_enable_device\n");
845*4882a593Smuzhiyun goto out2;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun /* Finally, report what we've done */
849*4882a593Smuzhiyun lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]);
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun /*
852*4882a593Smuzhiyun * Most of the libertas cards can do unaligned register access, but some
853*4882a593Smuzhiyun * weird ones cannot. That's especially true for the CF8305 card.
854*4882a593Smuzhiyun */
855*4882a593Smuzhiyun card->align_regs = false;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun card->model = get_model(p_dev->manf_id, p_dev->card_id);
858*4882a593Smuzhiyun if (card->model == MODEL_UNKNOWN) {
859*4882a593Smuzhiyun pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
860*4882a593Smuzhiyun p_dev->manf_id, p_dev->card_id);
861*4882a593Smuzhiyun ret = -ENODEV;
862*4882a593Smuzhiyun goto out2;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun /* Check if we have a current silicon */
866*4882a593Smuzhiyun prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
867*4882a593Smuzhiyun if (card->model == MODEL_8305) {
868*4882a593Smuzhiyun card->align_regs = true;
869*4882a593Smuzhiyun if (prod_id < IF_CS_CF8305_B1_REV) {
870*4882a593Smuzhiyun pr_err("8305 rev B0 and older are not supported\n");
871*4882a593Smuzhiyun ret = -ENODEV;
872*4882a593Smuzhiyun goto out2;
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
877*4882a593Smuzhiyun pr_err("8381 rev B2 and older are not supported\n");
878*4882a593Smuzhiyun ret = -ENODEV;
879*4882a593Smuzhiyun goto out2;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
883*4882a593Smuzhiyun pr_err("8385 rev B0 and older are not supported\n");
884*4882a593Smuzhiyun ret = -ENODEV;
885*4882a593Smuzhiyun goto out2;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun /* Make this card known to the libertas driver */
889*4882a593Smuzhiyun priv = lbs_add_card(card, &p_dev->dev);
890*4882a593Smuzhiyun if (IS_ERR(priv)) {
891*4882a593Smuzhiyun ret = PTR_ERR(priv);
892*4882a593Smuzhiyun goto out2;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun /* Set up fields in lbs_private */
896*4882a593Smuzhiyun card->priv = priv;
897*4882a593Smuzhiyun priv->card = card;
898*4882a593Smuzhiyun priv->hw_host_to_card = if_cs_host_to_card;
899*4882a593Smuzhiyun priv->enter_deep_sleep = NULL;
900*4882a593Smuzhiyun priv->exit_deep_sleep = NULL;
901*4882a593Smuzhiyun priv->reset_deep_sleep_wakeup = NULL;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* Get firmware */
904*4882a593Smuzhiyun ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
905*4882a593Smuzhiyun if_cs_prog_firmware);
906*4882a593Smuzhiyun if (ret) {
907*4882a593Smuzhiyun pr_err("failed to find firmware (%d)\n", ret);
908*4882a593Smuzhiyun goto out3;
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun goto out;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun out3:
914*4882a593Smuzhiyun lbs_remove_card(priv);
915*4882a593Smuzhiyun out2:
916*4882a593Smuzhiyun ioport_unmap(card->iobase);
917*4882a593Smuzhiyun out1:
918*4882a593Smuzhiyun pcmcia_disable_device(p_dev);
919*4882a593Smuzhiyun out:
920*4882a593Smuzhiyun return ret;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun
if_cs_detach(struct pcmcia_device * p_dev)924*4882a593Smuzhiyun static void if_cs_detach(struct pcmcia_device *p_dev)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun struct if_cs_card *card = p_dev->priv;
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun lbs_stop_card(card->priv);
929*4882a593Smuzhiyun lbs_remove_card(card->priv);
930*4882a593Smuzhiyun if_cs_disable_ints(card);
931*4882a593Smuzhiyun if_cs_release(p_dev);
932*4882a593Smuzhiyun kfree(card);
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun /********************************************************************/
938*4882a593Smuzhiyun /* Module initialization */
939*4882a593Smuzhiyun /********************************************************************/
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun static const struct pcmcia_device_id if_cs_ids[] = {
942*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
943*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
944*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
945*4882a593Smuzhiyun /* NOTE: keep in sync with get_model() */
946*4882a593Smuzhiyun PCMCIA_DEVICE_NULL,
947*4882a593Smuzhiyun };
948*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun static struct pcmcia_driver lbs_driver = {
951*4882a593Smuzhiyun .owner = THIS_MODULE,
952*4882a593Smuzhiyun .name = DRV_NAME,
953*4882a593Smuzhiyun .probe = if_cs_probe,
954*4882a593Smuzhiyun .remove = if_cs_detach,
955*4882a593Smuzhiyun .id_table = if_cs_ids,
956*4882a593Smuzhiyun };
957*4882a593Smuzhiyun module_pcmcia_driver(lbs_driver);
958