1/*
2 * Copyright (c) 2011 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/* ***** SDIO interface chip backplane handle functions ***** */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/types.h>
21#include <linux/netdevice.h>
22#include <linux/mmc/card.h>
23#include <linux/ssb/ssb_regs.h>
24#include <linux/bcma/bcma.h>
25
26#include <chipcommon.h>
27#include <brcm_hw_ids.h>
28#include <brcmu_wifi.h>
29#include <brcmu_utils.h>
30#include <soc.h>
31#include "dhd_dbg.h"
32#include "sdio_host.h"
33#include "sdio_chip.h"
34
35/* chip core base & ramsize */
36/* bcm4329 */
37/* SDIO device core, ID 0x829 */
38#define BCM4329_CORE_BUS_BASE		0x18011000
39/* internal memory core, ID 0x80e */
40#define BCM4329_CORE_SOCRAM_BASE	0x18003000
41/* ARM Cortex M3 core, ID 0x82a */
42#define BCM4329_CORE_ARM_BASE		0x18002000
43#define BCM4329_RAMSIZE			0x48000
44
45#define	SBCOREREV(sbidh) \
46	((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
47	  ((sbidh) & SSB_IDHIGH_RCLO))
48
49/* SOC Interconnect types (aka chip types) */
50#define SOCI_SB		0
51#define SOCI_AI		1
52
53/* EROM CompIdentB */
54#define CIB_REV_MASK		0xff000000
55#define CIB_REV_SHIFT		24
56
57#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
58/* SDIO Pad drive strength to select value mappings */
59struct sdiod_drive_str {
60	u8 strength;	/* Pad Drive Strength in mA */
61	u8 sel;		/* Chip-specific select value */
62};
63/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
64static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
65	{32, 0x6},
66	{26, 0x7},
67	{22, 0x4},
68	{16, 0x5},
69	{12, 0x2},
70	{8, 0x3},
71	{4, 0x0},
72	{0, 0x1}
73};
74
75u8
76brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
77{
78	u8 idx;
79
80	for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
81		if (coreid == ci->c_inf[idx].id)
82			return idx;
83
84	return BRCMF_MAX_CORENUM;
85}
86
87static u32
88brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
89		      struct chip_info *ci, u16 coreid)
90{
91	u32 regdata;
92	u8 idx;
93
94	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
95
96	regdata = brcmf_sdcard_reg_read(sdiodev,
97			CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
98	return SBCOREREV(regdata);
99}
100
101static u32
102brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
103		      struct chip_info *ci, u16 coreid)
104{
105	u8 idx;
106
107	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
108
109	return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
110}
111
112static bool
113brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
114		       struct chip_info *ci, u16 coreid)
115{
116	u32 regdata;
117	u8 idx;
118
119	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
120
121	regdata = brcmf_sdcard_reg_read(sdiodev,
122			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
123	regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
124		    SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
125	return (SSB_TMSLOW_CLOCK == regdata);
126}
127
128static bool
129brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
130		       struct chip_info *ci, u16 coreid)
131{
132	u32 regdata;
133	u8 idx;
134	bool ret;
135
136	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
137
138	regdata = brcmf_sdcard_reg_read(sdiodev,
139					ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
140	ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
141
142	regdata = brcmf_sdcard_reg_read(sdiodev,
143					ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
144					4);
145	ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
146
147	return ret;
148}
149
150static void
151brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
152			  struct chip_info *ci, u16 coreid)
153{
154	u32 regdata;
155	u8 idx;
156
157	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
158
159	regdata = brcmf_sdcard_reg_read(sdiodev,
160		CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
161	if (regdata & SSB_TMSLOW_RESET)
162		return;
163
164	regdata = brcmf_sdcard_reg_read(sdiodev,
165		CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
166	if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
167		/*
168		 * set target reject and spin until busy is clear
169		 * (preserve core-specific bits)
170		 */
171		regdata = brcmf_sdcard_reg_read(sdiodev,
172			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
173		brcmf_sdcard_reg_write(sdiodev,
174				CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
175				4, regdata | SSB_TMSLOW_REJECT);
176
177		regdata = brcmf_sdcard_reg_read(sdiodev,
178			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
179		udelay(1);
180		SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
181			CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
182			SSB_TMSHIGH_BUSY), 100000);
183
184		regdata = brcmf_sdcard_reg_read(sdiodev,
185			CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
186		if (regdata & SSB_TMSHIGH_BUSY)
187			brcmf_dbg(ERROR, "core state still busy\n");
188
189		regdata = brcmf_sdcard_reg_read(sdiodev,
190			CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
191		if (regdata & SSB_IDLOW_INITIATOR) {
192			regdata = brcmf_sdcard_reg_read(sdiodev,
193				CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
194				SSB_IMSTATE_REJECT;
195			brcmf_sdcard_reg_write(sdiodev,
196				CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
197				regdata);
198			regdata = brcmf_sdcard_reg_read(sdiodev,
199				CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
200			udelay(1);
201			SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
202				CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
203				SSB_IMSTATE_BUSY), 100000);
204		}
205
206		/* set reset and reject while enabling the clocks */
207		brcmf_sdcard_reg_write(sdiodev,
208			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
209			(SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
210			SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
211		regdata = brcmf_sdcard_reg_read(sdiodev,
212			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
213		udelay(10);
214
215		/* clear the initiator reject bit */
216		regdata = brcmf_sdcard_reg_read(sdiodev,
217			CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
218		if (regdata & SSB_IDLOW_INITIATOR) {
219			regdata = brcmf_sdcard_reg_read(sdiodev,
220				CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
221				~SSB_IMSTATE_REJECT;
222			brcmf_sdcard_reg_write(sdiodev,
223				CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
224				regdata);
225		}
226	}
227
228	/* leave reset and reject asserted */
229	brcmf_sdcard_reg_write(sdiodev,
230		CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
231		(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
232	udelay(1);
233}
234
235static void
236brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
237			  struct chip_info *ci, u16 coreid)
238{
239	u8 idx;
240	u32 regdata;
241
242	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
243
244	/* if core is already in reset, just return */
245	regdata = brcmf_sdcard_reg_read(sdiodev,
246					ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
247					4);
248	if ((regdata & BCMA_RESET_CTL_RESET) != 0)
249		return;
250
251	brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
252			       4, 0);
253	regdata = brcmf_sdcard_reg_read(sdiodev,
254					ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
255	udelay(10);
256
257	brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
258			       4, BCMA_RESET_CTL_RESET);
259	udelay(1);
260}
261
262static void
263brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
264			struct chip_info *ci, u16 coreid)
265{
266	u32 regdata;
267	u8 idx;
268
269	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
270
271	/*
272	 * Must do the disable sequence first to work for
273	 * arbitrary current core state.
274	 */
275	brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
276
277	/*
278	 * Now do the initialization sequence.
279	 * set reset while enabling the clock and
280	 * forcing them on throughout the core
281	 */
282	brcmf_sdcard_reg_write(sdiodev,
283			CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
284			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
285	regdata = brcmf_sdcard_reg_read(sdiodev,
286				CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
287	udelay(1);
288
289	/* clear any serror */
290	regdata = brcmf_sdcard_reg_read(sdiodev,
291				CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
292	if (regdata & SSB_TMSHIGH_SERR)
293		brcmf_sdcard_reg_write(sdiodev,
294			CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
295
296	regdata = brcmf_sdcard_reg_read(sdiodev,
297				CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
298	if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
299		brcmf_sdcard_reg_write(sdiodev,
300			CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
301			regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
302
303	/* clear reset and allow it to propagate throughout the core */
304	brcmf_sdcard_reg_write(sdiodev,
305		CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
306		SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
307	regdata = brcmf_sdcard_reg_read(sdiodev,
308				CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
309	udelay(1);
310
311	/* leave clock enabled */
312	brcmf_sdcard_reg_write(sdiodev,
313			       CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
314			       4, SSB_TMSLOW_CLOCK);
315	regdata = brcmf_sdcard_reg_read(sdiodev,
316				CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
317	udelay(1);
318}
319
320static void
321brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
322			struct chip_info *ci, u16 coreid)
323{
324	u8 idx;
325	u32 regdata;
326
327	idx = brcmf_sdio_chip_getinfidx(ci, coreid);
328
329	/* must disable first to work for arbitrary current core state */
330	brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
331
332	/* now do initialization sequence */
333	brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
334			       4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
335	regdata = brcmf_sdcard_reg_read(sdiodev,
336					ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
337	brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
338			       4, 0);
339	udelay(1);
340
341	brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
342			       4, BCMA_IOCTL_CLK);
343	regdata = brcmf_sdcard_reg_read(sdiodev,
344					ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
345	udelay(1);
346}
347
348static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
349				       struct chip_info *ci, u32 regs)
350{
351	u32 regdata;
352
353	/*
354	 * Get CC core rev
355	 * Chipid is assume to be at offset 0 from regs arg
356	 * For different chiptypes or old sdio hosts w/o chipcommon,
357	 * other ways of recognition should be added here.
358	 */
359	ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
360	ci->c_inf[0].base = regs;
361	regdata = brcmf_sdcard_reg_read(sdiodev,
362			CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
363	ci->chip = regdata & CID_ID_MASK;
364	ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
365	ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
366
367	brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
368
369	/* Address of cores for new chips should be added here */
370	switch (ci->chip) {
371	case BCM4329_CHIP_ID:
372		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
373		ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
374		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
375		ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
376		ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
377		ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
378		ci->ramsize = BCM4329_RAMSIZE;
379		break;
380	case BCM4330_CHIP_ID:
381		ci->c_inf[0].wrapbase = 0x18100000;
382		ci->c_inf[0].cib = 0x27004211;
383		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
384		ci->c_inf[1].base = 0x18002000;
385		ci->c_inf[1].wrapbase = 0x18102000;
386		ci->c_inf[1].cib = 0x07004211;
387		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
388		ci->c_inf[2].base = 0x18004000;
389		ci->c_inf[2].wrapbase = 0x18104000;
390		ci->c_inf[2].cib = 0x0d080401;
391		ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
392		ci->c_inf[3].base = 0x18003000;
393		ci->c_inf[3].wrapbase = 0x18103000;
394		ci->c_inf[3].cib = 0x03004211;
395		ci->ramsize = 0x48000;
396		break;
397	default:
398		brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
399		return -ENODEV;
400	}
401
402	switch (ci->socitype) {
403	case SOCI_SB:
404		ci->iscoreup = brcmf_sdio_sb_iscoreup;
405		ci->corerev = brcmf_sdio_sb_corerev;
406		ci->coredisable = brcmf_sdio_sb_coredisable;
407		ci->resetcore = brcmf_sdio_sb_resetcore;
408		break;
409	case SOCI_AI:
410		ci->iscoreup = brcmf_sdio_ai_iscoreup;
411		ci->corerev = brcmf_sdio_ai_corerev;
412		ci->coredisable = brcmf_sdio_ai_coredisable;
413		ci->resetcore = brcmf_sdio_ai_resetcore;
414		break;
415	default:
416		brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
417		return -ENODEV;
418	}
419
420	return 0;
421}
422
423static int
424brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
425{
426	int err = 0;
427	u8 clkval, clkset;
428
429	/* Try forcing SDIO core to do ALPAvail request only */
430	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
431	brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
432			       SBSDIO_FUNC1_CHIPCLKCSR,	clkset, &err);
433	if (err) {
434		brcmf_dbg(ERROR, "error writing for HT off\n");
435		return err;
436	}
437
438	/* If register supported, wait for ALPAvail and then force ALP */
439	/* This may take up to 15 milliseconds */
440	clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
441				       SBSDIO_FUNC1_CHIPCLKCSR, NULL);
442
443	if ((clkval & ~SBSDIO_AVBITS) != clkset) {
444		brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
445			  clkset, clkval);
446		return -EACCES;
447	}
448
449	SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
450				SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
451			!SBSDIO_ALPAV(clkval)),
452			PMU_MAX_TRANSITION_DLY);
453	if (!SBSDIO_ALPAV(clkval)) {
454		brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
455			  clkval);
456		return -EBUSY;
457	}
458
459	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
460	brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
461			       SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
462	udelay(65);
463
464	/* Also, disable the extra SDIO pull-ups */
465	brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
466			       SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
467
468	return 0;
469}
470
471static void
472brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
473			     struct chip_info *ci)
474{
475	/* get chipcommon rev */
476	ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
477
478	/* get chipcommon capabilites */
479	ci->c_inf[0].caps =
480		brcmf_sdcard_reg_read(sdiodev,
481		CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
482
483	/* get pmu caps & rev */
484	if (ci->c_inf[0].caps & CC_CAP_PMU) {
485		ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
486			CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
487		ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
488	}
489
490	ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
491
492	brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
493		  ci->c_inf[0].rev, ci->pmurev,
494		  ci->c_inf[1].rev, ci->c_inf[1].id);
495
496	/*
497	 * Make sure any on-chip ARM is off (in case strapping is wrong),
498	 * or downloaded code was already running.
499	 */
500	ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
501}
502
503int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
504			   struct chip_info **ci_ptr, u32 regs)
505{
506	int ret;
507	struct chip_info *ci;
508
509	brcmf_dbg(TRACE, "Enter\n");
510
511	/* alloc chip_info_t */
512	ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
513	if (!ci)
514		return -ENOMEM;
515
516	ret = brcmf_sdio_chip_buscoreprep(sdiodev);
517	if (ret != 0)
518		goto err;
519
520	ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
521	if (ret != 0)
522		goto err;
523
524	brcmf_sdio_chip_buscoresetup(sdiodev, ci);
525
526	brcmf_sdcard_reg_write(sdiodev,
527		CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
528	brcmf_sdcard_reg_write(sdiodev,
529		CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
530
531	*ci_ptr = ci;
532	return 0;
533
534err:
535	kfree(ci);
536	return ret;
537}
538
539void
540brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
541{
542	brcmf_dbg(TRACE, "Enter\n");
543
544	kfree(*ci_ptr);
545	*ci_ptr = NULL;
546}
547
548static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
549{
550	const char *fmt;
551
552	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
553	snprintf(buf, len, fmt, chipid);
554	return buf;
555}
556
557void
558brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
559				  struct chip_info *ci, u32 drivestrength)
560{
561	struct sdiod_drive_str *str_tab = NULL;
562	u32 str_mask = 0;
563	u32 str_shift = 0;
564	char chn[8];
565
566	if (!(ci->c_inf[0].caps & CC_CAP_PMU))
567		return;
568
569	switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
570	case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
571		str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
572		str_mask = 0x00003800;
573		str_shift = 11;
574		break;
575	default:
576		brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
577			  brcmf_sdio_chip_name(ci->chip, chn, 8),
578			  ci->chiprev, ci->pmurev);
579		break;
580	}
581
582	if (str_tab != NULL) {
583		u32 drivestrength_sel = 0;
584		u32 cc_data_temp;
585		int i;
586
587		for (i = 0; str_tab[i].strength != 0; i++) {
588			if (drivestrength >= str_tab[i].strength) {
589				drivestrength_sel = str_tab[i].sel;
590				break;
591			}
592		}
593
594		brcmf_sdcard_reg_write(sdiodev,
595			CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
596			4, 1);
597		cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
598			CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
599		cc_data_temp &= ~str_mask;
600		drivestrength_sel <<= str_shift;
601		cc_data_temp |= drivestrength_sel;
602		brcmf_sdcard_reg_write(sdiodev,
603			CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
604			4, cc_data_temp);
605
606		brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
607			  drivestrength, cc_data_temp);
608	}
609}
610