-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathsiutils.c
10248 lines (8860 loc) · 269 KB
/
siutils.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Misc utility routines for accessing chip-specific features
* of the SiliconBackplane-based Broadcom chips.
*
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <typedefs.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmdevs.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <sbgci.h>
#ifndef BCMSDIO
#include <pcie_core.h>
#endif
#if !defined(BCMDONGLEHOST)
#include <pci_core.h>
#include <nicpci.h>
#include <bcmnvram.h>
#include <bcmsrom.h>
#include <hndtcam.h>
#endif /* !defined(BCMDONGLEHOST) */
#ifdef BCMPCIEDEV
#include <pcieregsoffs.h>
#include <pciedev.h>
#endif /* BCMPCIEDEV */
#include <pcicfg.h>
#include <sbpcmcia.h>
#include <sbsysmem.h>
#include <sbsocram.h>
#if defined(BCMECICOEX) || !defined(BCMDONGLEHOST)
#include <bcmotp.h>
#endif /* BCMECICOEX || !BCMDONGLEHOST */
#ifdef BCMSDIO
#include <bcmsdh.h>
#include <sdio.h>
#include <sbsdio.h>
#include <sbhnddma.h>
#include <sbsdpcmdev.h>
#include <bcmsdpcm.h>
#endif /* BCMSDIO */
#include <hndpmu.h>
#ifdef BCMSPI
#include <spid.h>
#endif /* BCMSPI */
#if !defined(BCMDONGLEHOST) && !defined(BCM_BOOTLOADER) && defined(SR_ESSENTIALS)
#include <saverestore.h>
#endif
#include <dhd_config.h>
#ifdef BCM_SDRBL
#include <hndcpu.h>
#endif /* BCM_SDRBL */
#ifdef HNDGCI
#include <hndgci.h>
#endif /* HNDGCI */
#ifdef DONGLEBUILD
#include <hnd_gci.h>
#endif /* DONGLEBUILD */
#include <hndlhl.h>
#include <hndoobr.h>
#include <lpflags.h>
#ifdef BCM_SFLASH
#include <sflash.h>
#endif
#ifdef BCM_SH_SFLASH
#include <sh_sflash.h>
#endif
#ifdef BCMGCISHM
#include <hnd_gcishm.h>
#endif
#include "siutils_priv.h"
#include "sbhndarm.h"
#include <hndchipc.h>
#ifdef SECI_UART
/* Defines the set of GPIOs to be used for SECI UART if not specified in NVRAM */
/* For further details on each ppin functionality please refer to PINMUX table in
* Top level architecture of BCMXXXX Chip
*/
#define DEFAULT_SECI_UART_PINMUX 0x08090a0b
static bool force_seci_clk = 0;
#endif /* SECI_UART */
#define XTAL_FREQ_26000KHZ 26000
#define XTAL_FREQ_59970KHZ 59970
#define WCI2_UART_RX_BUF_SIZE 64
/**
* A set of PMU registers is clocked in the ILP domain, which has an implication on register write
* behavior: if such a register is written, it takes multiple ILP clocks for the PMU block to absorb
* the write. During that time the 'SlowWritePending' bit in the PMUStatus register is set.
*/
#define PMUREGS_ILP_SENSITIVE(regoff) \
((regoff) == OFFSETOF(pmuregs_t, pmutimer) || \
(regoff) == OFFSETOF(pmuregs_t, pmuwatchdog) || \
(regoff) == OFFSETOF(pmuregs_t, res_req_timer))
#define CHIPCREGS_ILP_SENSITIVE(regoff) \
((regoff) == OFFSETOF(chipcregs_t, pmutimer) || \
(regoff) == OFFSETOF(chipcregs_t, pmuwatchdog) || \
(regoff) == OFFSETOF(chipcregs_t, res_req_timer))
#define GCI_FEM_CTRL_WAR 0x11111111
#ifndef AXI_TO_VAL
#define AXI_TO_VAL 19
#endif /* AXI_TO_VAL */
#ifndef AXI_TO_VAL_25
/*
* Increase BP timeout for fast clock and short PCIe timeouts
* New timeout: 2 ** 25 cycles
*/
#define AXI_TO_VAL_25 25
#endif /* AXI_TO_VAL_25 */
#define si_srpwr_domain_mask(rval, mask) \
(((rval) >> SRPWR_STATUS_SHIFT) & (mask))
/* local prototypes */
#if !defined(BCMDONGLEHOST)
static void si_43012_lp_enable(si_t *sih);
#endif /* !defined(BCMDONGLEHOST) */
static int32 si_alloc_wrapper(si_info_t *sii);
static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
uint bustype, void *sdh, char **vars, uint *varsz);
static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh);
static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
uint *origidx, volatile const void *regs);
#if !defined(BCMDONGLEHOST)
static void si_nvram_process(si_info_t *sii, char *pvars);
/* dev path concatenation util */
static char *si_devpathvar(const si_t *sih, char *var, int len, const char *name);
static char *si_pcie_devpathvar(const si_t *sih, char *var, int len, const char *name);
static bool _si_clkctl_cc(si_info_t *sii, uint mode);
static bool si_ispcie(const si_info_t *sii);
static uint sysmem_banksize(const si_info_t *sii, sysmemregs_t *r, uint8 idx);
static uint socram_banksize(const si_info_t *sii, sbsocramregs_t *r, uint8 idx, uint8 mtype);
static uint8 si_gci_get_chipctrlreg_ringidx_base8(uint32 pin, uint32 *regidx, uint32 *pos);
static void si_gci_gpio_chipcontrol(si_t *si, uint8 gpoi, uint8 opt);
static void si_gci_enable_gpioint(si_t *sih, bool enable);
#if defined(BCMECICOEX) || defined(SECI_UART)
static chipcregs_t * seci_set_core(si_t *sih, uint32 *origidx, bool *fast);
#endif
#endif /* !defined(BCMDONGLEHOST) */
static void si_gci_get_chipctrlreg_ringidx_base4(uint32 pin, uint32 *regidx, uint32 *pos);
static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff);
static void si_oob_war_BT_F1(si_t *sih);
#if defined(DONGLEBUILD)
#if !defined(NVSRCX)
static char * si_getkvars(void);
static int si_getkvarsz(void);
#endif
#endif /* DONGLEBUILD */
#if defined(BCMLTECOEX) && !defined(WLTEST)
static void si_wci2_rxfifo_intr_handler_process(si_t *sih, uint32 intstatus);
#endif /* BCMLTECOEX && !WLTEST */
/* global variable to indicate reservation/release of gpio's */
static uint32 si_gpioreservation = 0;
#if !defined(BCMDONGLEHOST)
/* global variable to indicate GCI reset is done */
static bool gci_reset_done = FALSE;
#endif
/* global flag to prevent shared resources from being initialized multiple times in si_attach() */
static bool si_onetimeinit = FALSE;
#ifdef SR_DEBUG
static const uint32 si_power_island_test_array[] = {
0x0000, 0x0001, 0x0010, 0x0011,
0x0100, 0x0101, 0x0110, 0x0111,
0x1000, 0x1001, 0x1010, 0x1011,
0x1100, 0x1101, 0x1110, 0x1111
};
#endif /* SR_DEBUG */
/* 4360 pcie2 WAR */
int do_4360_pcie2_war = 0;
/* global kernel resource */
static si_info_t ksii;
static si_cores_info_t ksii_cores_info;
#ifndef BCMDONGLEHOST
static const char rstr_rmin[] = "rmin";
static const char rstr_rmax[] = "rmax";
static const char rstr_lhl_ps_mode[] = "lhl_ps_mode";
static const char rstr_ext_wakeup_dis[] = "ext_wakeup_dis";
#if defined(BCMSRTOPOFF) && !defined(BCMSRTOPOFF_DISABLED)
static const char rstr_srtopoff_enab[] = "srtopoff_enab";
#endif
#endif /* BCMDONGLEHOST */
static uint32 wd_msticks; /**< watchdog timer ticks normalized to ms */
#ifdef DONGLEBUILD
/**
* As si_kattach goes thru full srom initialisation same can be used
* for all subsequent calls
*/
#if !defined(NVSRCX)
static char *
si_getkvars(void)
{
return (ksii.vars);
}
static int
si_getkvarsz(void)
{
return (ksii.varsz);
}
#endif /* !defined(NVSRCX) */
#endif /* DONGLEBUILD */
/** Returns the backplane address of the chipcommon core for a particular chip */
uint32
si_enum_base(uint devid)
{
return SI_ENUM_BASE_DEFAULT;
}
/**
* Allocate an si handle. This function may be called multiple times.
*
* devid - pci device id (used to determine chip#)
* osh - opaque OS handle
* regs - virtual address of initial core registers
* bustype - pci/sb/sdio/etc
* vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this
* function set 'vars' to NULL, making dereferencing of this parameter undesired.
* varsz - pointer to int to return the size of the vars
*/
si_t *
si_attach(uint devid, osl_t *osh, volatile void *regs,
uint bustype, void *sdh, char **vars, uint *varsz)
{
si_info_t *sii;
SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__));
/* alloc si_info_t */
/* freed after ucode download for firmware builds */
if ((sii = MALLOCZ_NOPERSIST(osh, sizeof(si_info_t))) == NULL) {
SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
return (NULL);
}
#ifdef BCMDVFS
if (BCMDVFS_ENAB() && si_dvfs_info_init((si_t *)sii, osh) == NULL) {
SI_ERROR(("si_dvfs_info_init failed\n"));
return (NULL);
}
#endif /* BCMDVFS */
if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
MFREE(osh, sii, sizeof(si_info_t));
return (NULL);
}
sii->vars = vars ? *vars : NULL;
sii->varsz = varsz ? *varsz : 0;
#if defined(BCM_SH_SFLASH) && !defined(BCM_SH_SFLASH_DISABLED)
sh_sflash_attach(osh, (si_t *)sii);
#endif
SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__));
return (si_t *)sii;
}
/** generic kernel variant of si_attach(). Is not called for Linux WLAN NIC builds. */
si_t *
si_kattach(osl_t *osh)
{
static bool ksii_attached = FALSE;
si_cores_info_t *cores_info;
if (!ksii_attached) {
void *regs = NULL;
const uint device_id = BCM4710_DEVICE_ID; // pick an arbitrary default device_id
regs = REG_MAP(si_enum_base(device_id), SI_CORE_SIZE); // map physical to virtual
cores_info = (si_cores_info_t *)&ksii_cores_info;
ksii.cores_info = cores_info;
/* Use osh as the deciding factor if the memory management
* system has been initialized. Pass non-NULL vars & varsz only
* if memory management has been initialized. Otherwise MALLOC()
* will fail/crash.
*/
#if defined(BCMDONGLEHOST)
ASSERT(osh);
#endif
if (si_doattach(&ksii, device_id, osh, regs,
SI_BUS, NULL,
osh != SI_OSH ? &(ksii.vars) : NULL,
osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) {
SI_ERROR(("si_kattach: si_doattach failed\n"));
REG_UNMAP(regs);
return NULL;
}
REG_UNMAP(regs);
/* save ticks normalized to ms for si_watchdog_ms() */
if (PMUCTL_ENAB(&ksii.pub)) {
/* based on 32KHz ILP clock */
wd_msticks = 32;
} else {
#if !defined(BCMDONGLEHOST)
if (CCREV(ksii.pub.ccrev) < 18)
wd_msticks = si_clock(&ksii.pub) / 1000;
else
wd_msticks = si_alp_clock(&ksii.pub) / 1000;
#else
wd_msticks = ALP_CLOCK / 1000;
#endif /* !defined(BCMDONGLEHOST) */
}
ksii_attached = TRUE;
SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n",
CCREV(ksii.pub.ccrev), wd_msticks));
}
return &ksii.pub;
}
static bool
si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
{
BCM_REFERENCE(sdh);
BCM_REFERENCE(devid);
#if !defined(BCMDONGLEHOST)
/* kludge to enable the clock on the 4306 which lacks a slowclock */
if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii))
si_clkctl_xtal(&sii->pub, XTAL|PLL, ON);
#endif /* !defined(BCMDONGLEHOST) */
#if defined(BCMSDIO) && defined(BCMDONGLEHOST) && !defined(BCMSDIOLITE)
/* PR 39902, 43618, 44891, 41539 -- avoid backplane accesses that may
* cause SDIO clock requests before a stable ALP clock. Originally had
* this later (just before srom_var_init() below) to guarantee ALP for
* CIS read, but due to these PRs moving it here before backplane use.
*/
/* As it precedes any backplane access, can't check chipid; but may
* be able to qualify with devid if underlying SDIO allows. But should
* be ok for all our SDIO (4318 doesn't support clock and pullup regs,
* but the access attempts don't seem to hurt.) Might elimiante the
* the need for ALP for CIS at all if underlying SDIO uses CMD53...
*/
if (BUSTYPE(bustype) == SDIO_BUS) {
int err;
uint8 clkset;
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
if (!err) {
uint8 clkval;
/* If register supported, wait for ALPAvail and then force ALP */
clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) == clkset) {
SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n",
clkval));
return FALSE;
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
clkset, &err);
/* PR 40613: account for possible ALP delay */
OSL_DELAY(65);
}
}
/* Also, disable the extra SDIO pull-ups */
bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
}
#ifdef BCMSPI
/* Avoid backplane accesses before wake-wlan (i.e. htavail) for spi.
* F1 read accesses may return correct data but with data-not-available dstatus bit set.
*/
if (BUSTYPE(bustype) == SPI_BUS) {
int err;
uint32 regdata;
/* wake up wlan function :WAKE_UP goes as HT_AVAIL request in hardware */
regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL);
SI_MSG(("F0 REG0 rd = 0x%x\n", regdata));
regdata |= WAKE_UP;
bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err);
/* It takes time for wakeup to take effect. */
OSL_DELAY(100000);
}
#endif /* BCMSPI */
#endif /* BCMSDIO && BCMDONGLEHOST && !BCMSDIOLITE */
return TRUE;
}
/* note: this function is used by dhd */
uint32
si_get_pmu_reg_addr(si_t *sih, uint32 offset)
{
si_info_t *sii = SI_INFO(sih);
uint32 pmuaddr = INVALID_ADDR;
uint origidx = 0;
SI_MSG(("si_get_pmu_reg_addr: pmu access, offset: %x\n", offset));
if (!(sii->pub.cccaps & CC_CAP_PMU)) {
goto done;
}
if (AOB_ENAB(&sii->pub)) {
uint pmucoreidx;
pmuregs_t *pmu;
SI_MSG(("si_get_pmu_reg_addr: AOBENAB: %x\n", offset));
origidx = sii->curidx;
pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0);
pmu = si_setcoreidx(&sii->pub, pmucoreidx);
/* note: this function is used by dhd and possible 64 bit compilation needs
* a cast to (unsigned long) for avoiding a compilation error.
*/
pmuaddr = (uint32)(uintptr)((volatile uint8*)pmu + offset);
si_setcoreidx(sih, origidx);
} else
pmuaddr = SI_ENUM_BASE(sih) + offset;
done:
SI_MSG(("%s: addrRET: %x\n", __FUNCTION__, pmuaddr));
return pmuaddr;
}
static bool
si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
uint *origidx, volatile const void *regs)
{
const si_cores_info_t *cores_info = sii->cores_info;
bool pci, pcie, pcie_gen2 = FALSE;
uint i;
uint pciidx, pcieidx, pcirev, pcierev;
#if defined(AXI_TIMEOUTS_NIC) || defined(AXI_TIMEOUTS)
/* first, enable backplane timeouts */
si_slave_wrapper_add(&sii->pub);
#endif
sii->curidx = 0;
cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
ASSERT((uintptr)cc);
/* get chipcommon rev */
sii->pub.ccrev = (int)si_corerev(&sii->pub);
/* get chipcommon chipstatus */
if (CCREV(sii->pub.ccrev) >= 11)
sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
/* get chipcommon capabilites */
sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
/* get chipcommon extended capabilities */
if (CCREV(sii->pub.ccrev) >= 35) /* PR77565 */
sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
/* get pmu rev and caps */
if (sii->pub.cccaps & CC_CAP_PMU) {
if (AOB_ENAB(&sii->pub)) {
uint pmucoreidx;
pmuregs_t *pmu;
pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0);
if (!GOODIDX(pmucoreidx, sii->numcores)) {
SI_ERROR(("si_buscore_setup: si_findcoreidx failed\n"));
return FALSE;
}
pmu = si_setcoreidx(&sii->pub, pmucoreidx);
sii->pub.pmucaps = R_REG(sii->osh, &pmu->pmucapabilities);
si_setcoreidx(&sii->pub, SI_CC_IDX);
sii->pub.gcirev = si_corereg(&sii->pub, GCI_CORE_IDX(&sii->pub),
GCI_OFFSETOF(&sii->pub, gci_corecaps0), 0, 0) & GCI_CAP0_REV_MASK;
if (GCIREV(sii->pub.gcirev) >= 9) {
#if !defined(BCMQT) && !defined(BCMFPGA)
sii->pub.lhlrev = si_corereg(&sii->pub, GCI_CORE_IDX(&sii->pub),
OFFSETOF(gciregs_t, lhl_core_capab_adr), 0, 0) &
LHL_CAP_REV_MASK;
#endif /* !defined(BCMQT && !defined(BCMFPGA */
} else {
sii->pub.lhlrev = NOREV;
}
} else
sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
}
SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n",
CCREV(sii->pub.ccrev), sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev,
sii->pub.pmucaps));
/* figure out bus/orignal core idx */
/* note for PCI_BUS the buscoretype variable is setup in ai_scan() */
if (BUSTYPE(sii->pub.bustype) != PCI_BUS) {
sii->pub.buscoretype = NODEV_CORE_ID;
}
sii->pub.buscorerev = NOREV;
sii->pub.buscoreidx = BADIDX;
pci = pcie = FALSE;
pcirev = pcierev = NOREV;
pciidx = pcieidx = BADIDX;
/* This loop can be optimized */
for (i = 0; i < sii->numcores; i++) {
uint cid, crev;
si_setcoreidx(&sii->pub, i);
cid = si_coreid(&sii->pub);
crev = si_corerev(&sii->pub);
/* Display cores found */
if (CHIPTYPE(sii->pub.socitype) != SOCI_NCI) {
SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x size:%x regs 0x%p\n",
i, cid, crev, cores_info->coresba[i], cores_info->coresba_size[i],
OSL_OBFUSCATE_BUF(cores_info->regs[i])));
}
if (BUSTYPE(bustype) == SI_BUS) {
/* now look at the chipstatus register to figure the pacakge */
/* this shoudl be a general change to cover all teh chips */
/* this also shoudl validate the build where the dongle is built */
/* for SDIO but downloaded on PCIE dev */
#ifdef BCMPCIEDEV_ENABLED
if (cid == PCIE2_CORE_ID) {
pcieidx = i;
pcierev = crev;
pcie = TRUE;
pcie_gen2 = TRUE;
}
#endif
/* rest fill it up here */
} else if (BUSTYPE(bustype) == PCI_BUS) {
if (cid == PCI_CORE_ID) {
pciidx = i;
pcirev = crev;
pci = TRUE;
} else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) {
pcieidx = i;
pcierev = crev;
pcie = TRUE;
if (cid == PCIE2_CORE_ID)
pcie_gen2 = TRUE;
}
}
#ifdef BCMSDIO
else if (((BUSTYPE(bustype) == SDIO_BUS) ||
(BUSTYPE(bustype) == SPI_BUS)) &&
(cid == SDIOD_CORE_ID)) {
sii->pub.buscorerev = (int16)crev;
sii->pub.buscoretype = (uint16)cid;
sii->pub.buscoreidx = (uint16)i;
}
#endif /* BCMSDIO */
/* find the core idx before entering this func. */
if (CHIPTYPE(sii->pub.socitype) == SOCI_NCI) {
if (regs == sii->curmap) {
*origidx = i;
}
} else {
/* find the core idx before entering this func. */
if ((savewin && (savewin == cores_info->coresba[i])) ||
(regs == cores_info->regs[i])) {
*origidx = i;
}
}
}
#if !defined(BCMDONGLEHOST)
if (pci && pcie) {
if (si_ispcie(sii))
pci = FALSE;
else
pcie = FALSE;
}
#endif /* !defined(BCMDONGLEHOST) */
#if defined(PCIE_FULL_DONGLE)
if (pcie) {
if (pcie_gen2)
sii->pub.buscoretype = PCIE2_CORE_ID;
else
sii->pub.buscoretype = PCIE_CORE_ID;
sii->pub.buscorerev = (int16)pcierev;
sii->pub.buscoreidx = (uint16)pcieidx;
}
BCM_REFERENCE(pci);
BCM_REFERENCE(pcirev);
BCM_REFERENCE(pciidx);
#else
if (pci) {
sii->pub.buscoretype = PCI_CORE_ID;
sii->pub.buscorerev = (int16)pcirev;
sii->pub.buscoreidx = (uint16)pciidx;
} else if (pcie) {
if (pcie_gen2)
sii->pub.buscoretype = PCIE2_CORE_ID;
else
sii->pub.buscoretype = PCIE_CORE_ID;
sii->pub.buscorerev = (int16)pcierev;
sii->pub.buscoreidx = (uint16)pcieidx;
}
#endif /* defined(PCIE_FULL_DONGLE) */
SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
sii->pub.buscorerev));
#if !defined(BCMDONGLEHOST)
/* fixup necessary chip/core configurations */
if (BUSTYPE(sii->pub.bustype) == PCI_BUS) {
if (SI_FAST(sii)) {
if (!sii->pch &&
((sii->pch = (void *)(uintptr)pcicore_init(&sii->pub, sii->osh,
(volatile void *)PCIEREGS(sii))) == NULL))
return FALSE;
}
if (si_pci_fixcfg(&sii->pub)) {
SI_ERROR(("si_buscore_setup: si_pci_fixcfg failed\n"));
return FALSE;
}
}
#endif /* !defined(BCMDONGLEHOST) */
#if defined(BCMSDIO) && defined(BCMDONGLEHOST)
/* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
* already running.
*/
if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
si_core_disable(&sii->pub, 0);
}
#endif /* BCMSDIO && BCMDONGLEHOST */
/* return to the original core */
si_setcoreidx(&sii->pub, *origidx);
return TRUE;
}
#if !defined(BCMDONGLEHOST) /* if not a DHD build */
static const char rstr_boardvendor[] = "boardvendor";
static const char rstr_boardtype[] = "boardtype";
#if defined(BCMPCIEDEV_SROM_FORMAT)
static const char rstr_subvid[] = "subvid";
#endif /* defined(BCMPCIEDEV_SROM_FORMAT) */
#ifdef BCMSDIO
static const char rstr_manfid[] = "manfid";
#endif
static const char rstr_prodid[] = "prodid";
static const char rstr_boardrev[] = "boardrev";
static const char rstr_boardflags[] = "boardflags";
static const char rstr_boardflags4[] = "boardflags4";
static const char rstr_xtalfreq[] = "xtalfreq";
static const char rstr_muxenab[] = "muxenab";
static const char rstr_gpiopulldown[] = "gpdn";
static const char rstr_devid[] = "devid";
static const char rstr_wl0id[] = "wl0id";
static const char rstr_devpathD[] = "devpath%d";
static const char rstr_D_S[] = "%d:%s";
static const char rstr_swdenab[] = "swdenable";
static const char rstr_spurconfig[] = "spurconfig";
static const char rstr_lpflags[] = "lpflags";
static const char rstr_armclk[] = "armclk";
static const char rstr_rfldo3p3_cap_war[] = "rfldo3p3_cap_war";
#if defined(SECI_UART)
static const char rstr_fuart_pup_rx_cts[] = "fuart_pup_rx_cts";
#endif /* defined(SECI_UART) */
static uint32
si_fixup_vid_overrides(si_info_t *sii, char *pvars, uint32 conf_vid)
{
BCM_REFERENCE(pvars);
if ((sii->pub.boardvendor != VENDOR_APPLE)) {
return conf_vid;
}
switch (sii->pub.boardtype)
{
/* Check for the SROM value */
case BCM94360X51P2:
case BCM94360X29C:
case BCM94360X29CP2:
case BCM94360X51:
case BCM943602X87:
case BCM943602X238D:
/* Take the PCIe configuration space subsystem ID */
sii->pub.boardtype = (conf_vid >> 16) & 0xffff;
break;
default:
/* Do nothing */
break;
}
return conf_vid;
}
static void
si_nvram_process(si_info_t *sii, char *pvars)
{
uint w = 0;
/* get boardtype and boardrev */
switch (BUSTYPE(sii->pub.bustype)) {
case PCI_BUS:
/* do a pci config read to get subsystem id and subvendor id */
w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(uint32));
/* Let nvram variables override subsystem Vend/ID */
if ((sii->pub.boardvendor = (uint16)si_getdevpathintvar(&sii->pub,
rstr_boardvendor)) == 0) {
#ifdef BCMHOSTVARS
if ((w & 0xffff) == 0)
sii->pub.boardvendor = VENDOR_BROADCOM;
else
#endif /* BCMHOSTVARS */
sii->pub.boardvendor = w & 0xffff;
} else {
SI_ERROR(("Overriding boardvendor: 0x%x instead of 0x%x\n",
sii->pub.boardvendor, w & 0xffff));
}
if ((sii->pub.boardtype = (uint16)si_getdevpathintvar(&sii->pub, rstr_boardtype))
== 0) {
if ((sii->pub.boardtype = getintvar(pvars, rstr_boardtype)) == 0)
sii->pub.boardtype = (w >> 16) & 0xffff;
} else {
SI_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n",
sii->pub.boardtype, (w >> 16) & 0xffff));
}
/* Override high priority fixups */
si_fixup_vid_overrides(sii, pvars, w);
break;
#ifdef BCMSDIO
case SDIO_BUS:
sii->pub.boardvendor = getintvar(pvars, rstr_manfid);
sii->pub.boardtype = getintvar(pvars, rstr_prodid);
break;
case SPI_BUS:
sii->pub.boardvendor = VENDOR_BROADCOM;
sii->pub.boardtype = QT4710_BOARD;
break;
#endif
case SI_BUS:
#ifdef BCMPCIEDEV_SROM_FORMAT
if (BCMPCIEDEV_ENAB() && si_is_sprom_available(&sii->pub) && pvars &&
getvar(pvars, rstr_subvid)) {
sii->pub.boardvendor = getintvar(pvars, rstr_subvid);
} else
#endif
sii->pub.boardvendor = VENDOR_BROADCOM;
if (pvars == NULL || ((sii->pub.boardtype = getintvar(pvars, rstr_prodid)) == 0))
if ((sii->pub.boardtype = getintvar(pvars, rstr_boardtype)) == 0)
sii->pub.boardtype = 0xffff;
if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) {
/* do a pci config read to get subsystem id and subvendor id */
w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(uint32));
sii->pub.boardvendor = w & 0xffff;
sii->pub.boardtype = (w >> 16) & 0xffff;
}
break;
default:
break;
}
if (sii->pub.boardtype == 0) {
SI_ERROR(("si_doattach: unknown board type\n"));
ASSERT(sii->pub.boardtype);
}
sii->pub.lpflags = getintvar(pvars, rstr_lpflags);
sii->pub.boardrev = getintvar(pvars, rstr_boardrev);
sii->pub.boardflags = getintvar(pvars, rstr_boardflags);
#ifdef BCM_SDRBL
sii->pub.boardflags2 |= ((!CHIP_HOSTIF_USB(&(sii->pub))) ? ((si_arm_sflags(&(sii->pub))
& SISF_SDRENABLE) ? BFL2_SDR_EN:0):
(((uint)getintvar(pvars, "boardflags2")) & BFL2_SDR_EN));
#endif /* BCM_SDRBL */
sii->pub.boardflags4 = getintvar(pvars, rstr_boardflags4);
}
#endif /* !defined(BCMDONGLEHOST) */
#if defined(CONFIG_XIP) && defined(BCMTCAM)
extern uint8 patch_pair;
#endif /* CONFIG_XIP && BCMTCAM */
#if !defined(BCMDONGLEHOST)
typedef struct {
uint8 uart_tx;
uint32 uart_rx;
} si_mux_uartopt_t;
/* note: each index corr to MUXENAB43012_HOSTWAKE_MASK > shift - 1 */
static const uint8 mux43012_hostwakeopt[] = {
CC_PIN_GPIO_00
};
static const si_mux_uartopt_t mux_uartopt[] = {
{CC_PIN_GPIO_00, CC_PIN_GPIO_01},
{CC_PIN_GPIO_05, CC_PIN_GPIO_04},
{CC_PIN_GPIO_15, CC_PIN_GPIO_14},
};
/* note: each index corr to MUXENAB_DEF_HOSTWAKE mask >> shift - 1 */
static const uint8 mux_hostwakeopt[] = {
CC_PIN_GPIO_00,
};
#ifdef SECI_UART
#define NUM_SECI_UART_GPIOS 4
static bool fuart_pullup_rx_cts_enab = FALSE;
static bool fast_uart_init = FALSE;
static uint32 fast_uart_tx;
static uint32 fast_uart_functionsel;
static uint32 fast_uart_pup;
static uint32 fast_uart_rx;
static uint32 fast_uart_cts_in;
#endif /* SECI_UART */
void
si_swdenable(si_t *sih, uint32 swdflag)
{
/* FIXME Need a more generic test for SWD instead of check on specific chipid */
switch (CHIPID(sih->chip)) {
case BCM4369_CHIP_GRPID:
case BCM4362_CHIP_GRPID:
if (swdflag) {
/* Enable ARM debug clk, which is required for the ARM debug
* unit to operate
*/
si_pmu_chipcontrol(sih, PMU_CHIPCTL5, (1 << ARMCR4_DBG_CLK_BIT),
(1 << ARMCR4_DBG_CLK_BIT));
/* Force HT clock in Chipcommon. The HT clock is required for backplane
* access via SWD
*/
si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), CCS_FORCEHT,
CCS_FORCEHT);
/* Set TAP_SEL so that ARM is the first and the only TAP on the TAP chain.
* Must do a chip reset to clear this bit
*/
si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, jtagctrl),
JCTRL_TAPSEL_BIT, JCTRL_TAPSEL_BIT);
SI_MSG(("si_swdenable: set arm_dbgclk, ForceHTClock and tap_sel bit\n"));
}
break;
default:
/* swdenable specified for an unsupported chip */
ASSERT(0);
break;
}
}
/** want to have this available all the time to switch mux for debugging */
void
si_muxenab(si_t *sih, uint32 w)
{
uint32 chipcontrol, pmu_chipcontrol;
pmu_chipcontrol = si_pmu_chipcontrol(sih, 1, 0, 0);
chipcontrol = si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, chipcontrol),
0, 0);
switch (CHIPID(sih->chip)) {
case BCM4360_CHIP_ID:
case BCM43460_CHIP_ID:
case BCM4352_CHIP_ID:
case BCM43526_CHIP_ID:
CASE_BCM43602_CHIP:
if (w & MUXENAB_UART)
chipcontrol |= CCTRL4360_UART_MODE;
break;
case BCM43012_CHIP_ID:
case BCM43013_CHIP_ID:
case BCM43014_CHIP_ID:
/*
* 0x10 : use GPIO0 as host wake up pin
* 0x20 ~ 0xf0: Reserved
*/
if (w & MUXENAB43012_HOSTWAKE_MASK) {
uint8 hostwake = 0;
uint8 hostwake_ix = MUXENAB43012_GETIX(w, HOSTWAKE);
if (hostwake_ix >
sizeof(mux43012_hostwakeopt)/sizeof(mux43012_hostwakeopt[0]) - 1) {
SI_ERROR(("si_muxenab: wrong index %d for hostwake\n",
hostwake_ix));
break;
}
hostwake = mux43012_hostwakeopt[hostwake_ix];
si_gci_set_functionsel(sih, hostwake, CC_FNSEL_MISC1);
}
break;
case BCM4381_CHIP_GRPID:
case BCM4383_CHIP_GRPID:
case BCM4385_CHIP_GRPID:
case BCM4387_CHIP_GRPID:
if (w & MUXENAB_DEF_UART_MASK) {
uint32 uart_rx = 0, uart_tx = 0;
uint8 uartopt_idx = (w & MUXENAB_DEF_UART_MASK) - 1;
uint8 uartopt_size = sizeof(mux_uartopt)/sizeof(mux_uartopt[0]);
if (uartopt_idx < uartopt_size) {
uart_rx = mux_uartopt[uartopt_idx].uart_rx;
uart_tx = mux_uartopt[uartopt_idx].uart_tx;
#ifdef BOOTLOADER_CONSOLE_OUTPUT
uart_rx = 0;
uart_tx = 1;
#endif
if (CHIPREV(sih->chiprev) >= 3) {
si_gci_set_functionsel(sih, uart_rx, CC_FNSEL_GPIO1);
si_gci_set_functionsel(sih, uart_tx, CC_FNSEL_GPIO1);
} else {
si_gci_set_functionsel(sih, uart_rx, CC_FNSEL_GPIO0);
si_gci_set_functionsel(sih, uart_tx, CC_FNSEL_GPIO0);
}
} else {
SI_MSG(("si_muxenab: Invalid uart OTP setting\n"));
}
}
if (w & MUXENAB_DEF_HOSTWAKE_MASK) {
uint8 hostwake = 0;
/*
* SDIO
* 0x10 : use GPIO0 as host wake up pin
*/
uint8 hostwake_ix = MUXENAB_DEF_GETIX(w, HOSTWAKE);
if (hostwake_ix > (sizeof(mux_hostwakeopt) /
sizeof(mux_hostwakeopt[0]) - 1)) {
SI_ERROR(("si_muxenab: wrong index %d for hostwake\n",
hostwake_ix));
break;
}
hostwake = mux_hostwakeopt[hostwake_ix];
si_gci_set_functionsel(sih, hostwake, CC_FNSEL_GPIO0);
}