forked from Hongqin-Li/rpi-os
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathemmc.c
1900 lines (1624 loc) · 53.4 KB
/
emmc.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
//
// emmc.cpp
//
// Provides an interface to the EMMC controller and commands for interacting
// with an sd card
//
// Copyright (C) 2013 by John Cronin <jncronin@tysos.org>
//
// Modified for Circle by R. Stange
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// References:
//
// PLSS - SD Group Physical Layer Simplified Specification ver 3.00
// HCSS - SD Group Host Controller Simplified Specification ver 3.00
//
// Broadcom BCM2835 ARM Peripherals Guide
//
#include "mbox.h"
#include "base.h"
#include "sdhost.h"
#include "emmc.h"
#include "string.h"
#include "console.h"
/* External Mass Media Controller. */
#define ARM_EMMC_BASE (MMIO_BASE + 0x300000)
/* External Mass Media Controller 2(Raspberry Pi 4 only). */
#define ARM_EMMC2_BASE (MMIO_BASE + 0x340000)
/* Configuration options */
/*
* According to the BCM2835 ARM Peripherals Guide the EMMC STATUS register
* should not be used for polling. The original driver does not meet this
* specification in this point but the modified driver should do so.
* Define EMMC_POLL_STATUS_REG if you want the original function!
*/
//#define EMMC_POLL_STATUS_REG
// Enable 1.8V support
//#define SD_1_8V_SUPPORT
// Enable High Speed/SDR25 mode
//#define SD_HIGH_SPEED
// Enable 4-bit support
#define SD_4BIT_DATA
// SD Clock Frequencies (in Hz)
#define SD_CLOCK_ID 400000
#define SD_CLOCK_NORMAL 25000000
#define SD_CLOCK_HIGH 50000000
#define SD_CLOCK_100 100000000
#define SD_CLOCK_208 208000000
/*
* Enable SDXC maximum performance mode.
* Requires 150 mA power so disabled on the RPi for now.
*/
#define SDXC_MAXIMUM_PERFORMANCE
#ifndef USE_SDHOST
/* Enable card interrupts. */
//#define SD_CARD_INTERRUPTS
/* Allow old sdhci versions (may cause errors), required for QEMU. */
#define EMMC_ALLOW_OLD_SDHCI
#if RASPI <= 3
#define EMMC_BASE ARM_EMMC_BASE
#else
#define EMMC_BASE ARM_EMMC2_BASE
#endif
#define EMMC_ARG2 (EMMC_BASE + 0x00)
#define EMMC_BLKSIZECNT (EMMC_BASE + 0x04)
#define EMMC_ARG1 (EMMC_BASE + 0x08)
#define EMMC_CMDTM (EMMC_BASE + 0x0C)
#define EMMC_RESP0 (EMMC_BASE + 0x10)
#define EMMC_RESP1 (EMMC_BASE + 0x14)
#define EMMC_RESP2 (EMMC_BASE + 0x18)
#define EMMC_RESP3 (EMMC_BASE + 0x1C)
#define EMMC_DATA (EMMC_BASE + 0x20)
#define EMMC_STATUS (EMMC_BASE + 0x24)
#define EMMC_CONTROL0 (EMMC_BASE + 0x28)
#define EMMC_CONTROL1 (EMMC_BASE + 0x2C)
#define EMMC_INTERRUPT (EMMC_BASE + 0x30)
#define EMMC_IRPT_MASK (EMMC_BASE + 0x34)
#define EMMC_IRPT_EN (EMMC_BASE + 0x38)
#define EMMC_CONTROL2 (EMMC_BASE + 0x3C)
#define EMMC_CAPABILITIES_0 (EMMC_BASE + 0x40)
#define EMMC_CAPABILITIES_1 (EMMC_BASE + 0x44)
#define EMMC_FORCE_IRPT (EMMC_BASE + 0x50)
#define EMMC_BOOT_TIMEOUT (EMMC_BASE + 0x70)
#define EMMC_DBG_SEL (EMMC_BASE + 0x74)
#define EMMC_EXRDFIFO_CFG (EMMC_BASE + 0x80)
#define EMMC_EXRDFIFO_EN (EMMC_BASE + 0x84)
#define EMMC_TUNE_STEP (EMMC_BASE + 0x88)
#define EMMC_TUNE_STEPS_STD (EMMC_BASE + 0x8C)
#define EMMC_TUNE_STEPS_DDR (EMMC_BASE + 0x90)
#define EMMC_SPI_INT_SPT (EMMC_BASE + 0xF0)
#define EMMC_SLOTISR_VER (EMMC_BASE + 0xFC)
#endif
#define SD_CMD_INDEX(a) ((a) << 24)
#define SD_CMD_TYPE_NORMAL 0
#define SD_CMD_TYPE_SUSPEND (1 << 22)
#define SD_CMD_TYPE_RESUME (2 << 22)
#define SD_CMD_TYPE_ABORT (3 << 22)
#define SD_CMD_TYPE_MASK (3 << 22)
#define SD_CMD_ISDATA (1 << 21)
#define SD_CMD_IXCHK_EN (1 << 20)
#define SD_CMD_CRCCHK_EN (1 << 19)
#define SD_CMD_RSPNS_TYPE_NONE 0 // For no response
#define SD_CMD_RSPNS_TYPE_136 (1 << 16) // For response R2 (with CRC), R3,4 (no CRC)
#define SD_CMD_RSPNS_TYPE_48 (2 << 16) // For responses R1, R5, R6, R7 (with CRC)
#define SD_CMD_RSPNS_TYPE_48B (3 << 16) // For responses R1b, R5b (with CRC)
#define SD_CMD_RSPNS_TYPE_MASK (3 << 16)
#define SD_CMD_MULTI_BLOCK (1 << 5)
#define SD_CMD_DAT_DIR_HC 0
#define SD_CMD_DAT_DIR_CH (1 << 4)
#define SD_CMD_AUTO_CMD_EN_NONE 0
#define SD_CMD_AUTO_CMD_EN_CMD12 (1 << 2)
#define SD_CMD_AUTO_CMD_EN_CMD23 (2 << 2)
#define SD_CMD_BLKCNT_EN (1 << 1)
#define SD_CMD_DMA 1
#ifndef USE_SDHOST
#define SD_ERR_CMD_TIMEOUT 0
#define SD_ERR_CMD_CRC 1
#define SD_ERR_CMD_END_BIT 2
#define SD_ERR_CMD_INDEX 3
#define SD_ERR_DATA_TIMEOUT 4
#define SD_ERR_DATA_CRC 5
#define SD_ERR_DATA_END_BIT 6
#define SD_ERR_CURRENT_LIMIT 7
#define SD_ERR_AUTO_CMD12 8
#define SD_ERR_ADMA 9
#define SD_ERR_TUNING 10
#define SD_ERR_RSVD 11
#define SD_ERR_MASK_CMD_TIMEOUT (1 << (16 + SD_ERR_CMD_TIMEOUT))
#define SD_ERR_MASK_CMD_CRC (1 << (16 + SD_ERR_CMD_CRC))
#define SD_ERR_MASK_CMD_END_BIT (1 << (16 + SD_ERR_CMD_END_BIT))
#define SD_ERR_MASK_CMD_INDEX (1 << (16 + SD_ERR_CMD_INDEX))
#define SD_ERR_MASK_DATA_TIMEOUT (1 << (16 + SD_ERR_CMD_TIMEOUT))
#define SD_ERR_MASK_DATA_CRC (1 << (16 + SD_ERR_CMD_CRC))
#define SD_ERR_MASK_DATA_END_BIT (1 << (16 + SD_ERR_CMD_END_BIT))
#define SD_ERR_MASK_CURRENT_LIMIT (1 << (16 + SD_ERR_CMD_CURRENT_LIMIT))
#define SD_ERR_MASK_AUTO_CMD12 (1 << (16 + SD_ERR_CMD_AUTO_CMD12))
#define SD_ERR_MASK_ADMA (1 << (16 + SD_ERR_CMD_ADMA))
#define SD_ERR_MASK_TUNING (1 << (16 + SD_ERR_CMD_TUNING))
#define SD_COMMAND_COMPLETE 1
#define SD_TRANSFER_COMPLETE (1 << 1)
#define SD_BLOCK_GAP_EVENT (1 << 2)
#define SD_DMA_INTERRUPT (1 << 3)
#define SD_BUFFER_WRITE_READY (1 << 4)
#define SD_BUFFER_READ_READY (1 << 5)
#define SD_CARD_INSERTION (1 << 6)
#define SD_CARD_REMOVAL (1 << 7)
#define SD_CARD_INTERRUPT (1 << 8)
#endif
#define SD_RESP_NONE SD_CMD_RSPNS_TYPE_NONE
#define SD_RESP_R1 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN)
#define SD_RESP_R1b (SD_CMD_RSPNS_TYPE_48B | SD_CMD_CRCCHK_EN)
#define SD_RESP_R2 (SD_CMD_RSPNS_TYPE_136 | SD_CMD_CRCCHK_EN)
#define SD_RESP_R3 SD_CMD_RSPNS_TYPE_48
#define SD_RESP_R4 SD_CMD_RSPNS_TYPE_136
#define SD_RESP_R5 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN)
#define SD_RESP_R5b (SD_CMD_RSPNS_TYPE_48B | SD_CMD_CRCCHK_EN)
#define SD_RESP_R6 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN)
#define SD_RESP_R7 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN)
#define SD_DATA_READ (SD_CMD_ISDATA | SD_CMD_DAT_DIR_CH)
#define SD_DATA_WRITE (SD_CMD_ISDATA | SD_CMD_DAT_DIR_HC)
#define SD_CMD_RESERVED(a) 0xffffffff
#define SUCCESS(self) (self->last_cmd_success)
#define FAIL(self) (self->last_cmd_success == 0)
#ifndef USE_SDHOST
#define TIMEOUT(self) (FAIL(self) && (self->last_error == 0))
#define CMD_TIMEOUT(self) (FAIL(self) && (self->last_error & (1 << 16)))
#define CMD_CRC(self) (FAIL(self) && (self->last_error & (1 << 17)))
#define CMD_END_BIT(self) (FAIL(self) && (self->last_error & (1 << 18)))
#define CMD_INDEX(self) (FAIL(self) && (self->last_error & (1 << 19)))
#define DATA_TIMEOUT(self) (FAIL(self) && (self->last_error & (1 << 20)))
#define DATA_CRC(self) (FAIL(self) && (self->last_error & (1 << 21)))
#define DATA_END_BIT(self) (FAIL(self) && (self->last_error & (1 << 22)))
#define CURRENT_LIMIT(self) (FAIL(self) && (self->last_error & (1 << 23)))
#define ACMD12_ERROR(self) (FAIL(self) && (self->last_error & (1 << 24)))
#define ADMA_ERROR(self) (FAIL(self) && (self->last_error & (1 << 25)))
#define TUNING_ERROR(self) (FAIL(self) && (self->last_error & (1 << 26)))
#else
#define TIMEOUT(self) (FAIL(self) && self->last_error == ETIMEDOUT)
#endif
#define SD_VER_UNKNOWN 0
#define SD_VER_1 1
#define SD_VER_1_1 2
#define SD_VER_2 3
#define SD_VER_3 4
#define SD_VER_4 5
const char *sd_versions[] = {
"unknown",
"1.0 or 1.01",
"1.10",
"2.00",
"3.0x",
"4.xx"
};
#ifndef USE_SDHOST
const char *err_irpts[] = {
"CMD_TIMEOUT",
"CMD_CRC",
"CMD_END_BIT",
"CMD_INDEX",
"DATA_TIMEOUT",
"DATA_CRC",
"DATA_END_BIT",
"CURRENT_LIMIT",
"AUTO_CMD12",
"ADMA",
"TUNING",
"RSVD"
};
#endif
const uint32_t sd_commands[] = {
SD_CMD_INDEX(0),
SD_CMD_RESERVED(1),
SD_CMD_INDEX(2) | SD_RESP_R2,
SD_CMD_INDEX(3) | SD_RESP_R6,
SD_CMD_INDEX(4),
SD_CMD_INDEX(5) | SD_RESP_R4,
SD_CMD_INDEX(6) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_INDEX(7) | SD_RESP_R1b,
SD_CMD_INDEX(8) | SD_RESP_R7,
SD_CMD_INDEX(9) | SD_RESP_R2,
SD_CMD_INDEX(10) | SD_RESP_R2,
SD_CMD_INDEX(11) | SD_RESP_R1,
SD_CMD_INDEX(12) | SD_RESP_R1b | SD_CMD_TYPE_ABORT,
SD_CMD_INDEX(13) | SD_RESP_R1,
SD_CMD_RESERVED(14),
SD_CMD_INDEX(15),
SD_CMD_INDEX(16) | SD_RESP_R1,
SD_CMD_INDEX(17) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_INDEX(18) | SD_RESP_R1 | SD_DATA_READ | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN | SD_CMD_AUTO_CMD_EN_CMD12, // SD_CMD_AUTO_CMD_EN_CMD12 not in original driver
SD_CMD_INDEX(19) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_INDEX(20) | SD_RESP_R1b,
SD_CMD_RESERVED(21),
SD_CMD_RESERVED(22),
SD_CMD_INDEX(23) | SD_RESP_R1,
SD_CMD_INDEX(24) | SD_RESP_R1 | SD_DATA_WRITE,
SD_CMD_INDEX(25) | SD_RESP_R1 | SD_DATA_WRITE | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN | SD_CMD_AUTO_CMD_EN_CMD12, // SD_CMD_AUTO_CMD_EN_CMD12 not in original driver
SD_CMD_RESERVED(26),
SD_CMD_INDEX(27) | SD_RESP_R1 | SD_DATA_WRITE,
SD_CMD_INDEX(28) | SD_RESP_R1b,
SD_CMD_INDEX(29) | SD_RESP_R1b,
SD_CMD_INDEX(30) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_RESERVED(31),
SD_CMD_INDEX(32) | SD_RESP_R1,
SD_CMD_INDEX(33) | SD_RESP_R1,
SD_CMD_RESERVED(34),
SD_CMD_RESERVED(35),
SD_CMD_RESERVED(36),
SD_CMD_RESERVED(37),
SD_CMD_INDEX(38) | SD_RESP_R1b,
SD_CMD_RESERVED(39),
SD_CMD_RESERVED(40),
SD_CMD_RESERVED(41),
SD_CMD_RESERVED(42) | SD_RESP_R1,
SD_CMD_RESERVED(43),
SD_CMD_RESERVED(44),
SD_CMD_RESERVED(45),
SD_CMD_RESERVED(46),
SD_CMD_RESERVED(47),
SD_CMD_RESERVED(48),
SD_CMD_RESERVED(49),
SD_CMD_RESERVED(50),
SD_CMD_RESERVED(51),
SD_CMD_RESERVED(52),
SD_CMD_RESERVED(53),
SD_CMD_RESERVED(54),
SD_CMD_INDEX(55) | SD_RESP_R1,
SD_CMD_INDEX(56) | SD_RESP_R1 | SD_CMD_ISDATA,
SD_CMD_RESERVED(57),
SD_CMD_RESERVED(58),
SD_CMD_RESERVED(59),
SD_CMD_RESERVED(60),
SD_CMD_RESERVED(61),
SD_CMD_RESERVED(62),
SD_CMD_RESERVED(63)
};
const uint32_t sd_acommands[] = {
SD_CMD_RESERVED(0),
SD_CMD_RESERVED(1),
SD_CMD_RESERVED(2),
SD_CMD_RESERVED(3),
SD_CMD_RESERVED(4),
SD_CMD_RESERVED(5),
SD_CMD_INDEX(6) | SD_RESP_R1,
SD_CMD_RESERVED(7),
SD_CMD_RESERVED(8),
SD_CMD_RESERVED(9),
SD_CMD_RESERVED(10),
SD_CMD_RESERVED(11),
SD_CMD_RESERVED(12),
SD_CMD_INDEX(13) | SD_RESP_R1,
SD_CMD_RESERVED(14),
SD_CMD_RESERVED(15),
SD_CMD_RESERVED(16),
SD_CMD_RESERVED(17),
SD_CMD_RESERVED(18),
SD_CMD_RESERVED(19),
SD_CMD_RESERVED(20),
SD_CMD_RESERVED(21),
SD_CMD_INDEX(22) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_INDEX(23) | SD_RESP_R1,
SD_CMD_RESERVED(24),
SD_CMD_RESERVED(25),
SD_CMD_RESERVED(26),
SD_CMD_RESERVED(27),
SD_CMD_RESERVED(28),
SD_CMD_RESERVED(29),
SD_CMD_RESERVED(30),
SD_CMD_RESERVED(31),
SD_CMD_RESERVED(32),
SD_CMD_RESERVED(33),
SD_CMD_RESERVED(34),
SD_CMD_RESERVED(35),
SD_CMD_RESERVED(36),
SD_CMD_RESERVED(37),
SD_CMD_RESERVED(38),
SD_CMD_RESERVED(39),
SD_CMD_RESERVED(40),
SD_CMD_INDEX(41) | SD_RESP_R3,
SD_CMD_INDEX(42) | SD_RESP_R1,
SD_CMD_RESERVED(43),
SD_CMD_RESERVED(44),
SD_CMD_RESERVED(45),
SD_CMD_RESERVED(46),
SD_CMD_RESERVED(47),
SD_CMD_RESERVED(48),
SD_CMD_RESERVED(49),
SD_CMD_RESERVED(50),
SD_CMD_INDEX(51) | SD_RESP_R1 | SD_DATA_READ,
SD_CMD_RESERVED(52),
SD_CMD_RESERVED(53),
SD_CMD_RESERVED(54),
SD_CMD_RESERVED(55),
SD_CMD_RESERVED(56),
SD_CMD_RESERVED(57),
SD_CMD_RESERVED(58),
SD_CMD_RESERVED(59),
SD_CMD_RESERVED(60),
SD_CMD_RESERVED(61),
SD_CMD_RESERVED(62),
SD_CMD_RESERVED(63)
};
// The actual command indices
#define GO_IDLE_STATE 0
#define ALL_SEND_CID 2
#define SEND_RELATIVE_ADDR 3
#define SET_DSR 4
#define IO_SET_OP_COND 5
#define SWITCH_FUNC 6
#define SELECT_CARD 7
#define DESELECT_CARD 7
#define SELECT_DESELECT_CARD 7
#define SEND_IF_COND 8
#define SEND_CSD 9
#define SEND_CID 10
#define VOLTAGE_SWITCH 11
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define SEND_TUNING_BLOCK 19
#define SPEED_CLASS_CONTROL 20
#define SET_BLOCK_COUNT 23
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define PROGRAM_CSD 27
#define SET_WRITE_PROT 28
#define CLR_WRITE_PROT 29
#define SEND_WRITE_PROT 30
#define ERASE_WR_BLK_START 32
#define ERASE_WR_BLK_END 33
#define ERASE 38
#define LOCK_UNLOCK 42
#define APP_CMD 55
#define GEN_CMD 56
#define IS_APP_CMD 0x80000000
#define ACMD(a) (a | IS_APP_CMD)
#define SET_BUS_WIDTH (6 | IS_APP_CMD)
#define SD_STATUS (13 | IS_APP_CMD)
#define SEND_NUM_WR_BLOCKS (22 | IS_APP_CMD)
#define SET_WR_BLK_ERASE_COUNT (23 | IS_APP_CMD)
#define SD_SEND_OP_COND (41 | IS_APP_CMD)
#define SET_CLR_CARD_DETECT (42 | IS_APP_CMD)
#define SEND_SCR (51 | IS_APP_CMD)
#ifndef USE_SDHOST
#define SD_RESET_CMD (1 << 25)
#define SD_RESET_DAT (1 << 26)
#define SD_RESET_ALL (1 << 24)
#define SD_GET_CLOCK_DIVIDER_FAIL 0xffffffff
#endif
#define SD_BLOCK_SIZE 512
static int emmc_ensure_data_mode(struct emmc *self);
static int emmc_do_data_command(struct emmc *self, int is_write,
uint8_t * buf, size_t buf_size,
uint32_t block_no);
static size_t emmc_do_read(struct emmc *self, uint8_t * buf,
size_t buf_size, uint32_t block_no);
static size_t emmc_do_write(struct emmc *self, uint8_t * buf,
size_t buf_size, uint32_t block_no);
static int emmc_card_init(struct emmc *self);
static int emmc_card_reset(struct emmc *self);
static int emmc_issue_command(struct emmc *self, uint32_t cmd,
uint32_t arg, int timeout);
static void emmc_issue_command_int(struct emmc *self, uint32_t reg,
uint32_t arg, int timeout);
static inline uint32_t
be2le32(uint32_t x)
{
return ((x & 0x000000FF) << 24)
| ((x & 0x0000FF00) << 8)
| ((x & 0x00FF0000) >> 8)
| ((x & 0xFF000000) >> 24);
}
void
emmc_intr(struct emmc *self)
{
#ifdef USE_SDHOST
sdhost_intr(&self->host);
#endif
}
void
emmc_clear_interrupt()
{
uint32_t irpts = get32(EMMC_INTERRUPT);
debug("irpts: 0x%x", irpts);
put32(EMMC_INTERRUPT, irpts);
}
int
emmc_init(struct emmc *self, void (*sleep_fn)(void *), void *sleep_arg)
{
#ifndef USE_SDHOST
#if RASPI == 3
// TODO: Initialize gpio on pi3
#elif RASPI == 4
// Disable 1.8V supply.
// if (mbox_set_gpio_state(MBOX_EXP_GPIO_BASE + 4, 0) < 0) {
// error("failed to set gpio state");
// return -1;
// }
// delayus(5000);
#endif
#else
if (!sdhost_init(&self->host, sleep_fn, sleep_arg)) {
return -1;
}
#endif
if (emmc_card_init(self) != 0) {
return -1;
}
return 0;
}
size_t
emmc_read(struct emmc *self, void *buf, size_t cnt)
{
if (self->ull_offset % SD_BLOCK_SIZE != 0) {
return -1;
}
uint32_t nblock = self->ull_offset / SD_BLOCK_SIZE;
if (emmc_do_read(self, (uint8_t *) buf, cnt, nblock) != cnt) {
return -1;
}
return cnt;
}
size_t
emmc_write(struct emmc *self, void *buf, size_t cnt)
{
if (self->ull_offset % SD_BLOCK_SIZE != 0) {
return -1;
}
uint32_t nblock = self->ull_offset / SD_BLOCK_SIZE;
if (emmc_do_write(self, (uint8_t *) buf, cnt, nblock) != cnt) {
return -1;
}
return cnt;
}
uint64_t
emmc_seek(struct emmc *self, uint64_t off)
{
self->ull_offset = off;
return off;
}
#ifndef USE_SDHOST
static int
emmc_power_on()
{
if (mbox_set_power_state(MBOX_DEVICE_SDCARD, 1, 1) != 1) {
error("failed to power on sd card");
return -1;
}
return 0;
}
static void
emmc_power_off()
{
// Power off the SD card.
uint32_t control0 = get32(EMMC_CONTROL0);
// Set SD Bus Power bit off in Power Control Register
control0 &= ~(1 << 8);
put32(EMMC_CONTROL0, control0);
}
static int
emmc_timeout_wait(uint64_t reg, uint32_t mask, int value, uint64_t us)
{
uint64_t start = timestamp();
uint64_t dt = us * (timerfreq() / 1000000);
do {
if ((get32(reg) & mask) ? value : !value) {
return 0;
}
} while (timestamp() - start < dt);
return -1;
}
/* Get the current base clock rate in Hz. */
static uint32_t
emmc_get_base_clock()
{
#if RASPI <= 3
uint32_t clock_id = MBOX_CLOCK_EMMC;
#else
uint32_t clock_id = MBOX_CLOCK_EMMC2;
#endif
uint32_t rate = mbox_get_clock_rate(clock_id);
if (rate < 0) {
error("failed to get clock rate");
return 0;
}
debug("base clock rate is %u Hz", rate);
return rate;
}
// Set the clock dividers to generate a target value
static uint32_t
emmc_get_clock_divider(uint32_t base_clock, uint32_t target_rate)
{
// TODO: implement use of preset value registers
uint32_t targetted_divisor = 1;
if (target_rate <= base_clock) {
targetted_divisor = base_clock / target_rate;
if (base_clock % target_rate) {
targetted_divisor--;
}
}
// Decide on the clock mode to use
// Currently only 10-bit divided clock mode is supported
#ifndef EMMC_ALLOW_OLD_SDHCI
if (self->hci_ver >= 2) {
#endif
// HCI version 3 or greater supports 10-bit divided clock mode
// This requires a power-of-two divider
// Find the first bit set
int divisor = -1;
for (int first_bit = 31; first_bit >= 0; first_bit--) {
uint32_t bit_test = (1 << first_bit);
if (targetted_divisor & bit_test) {
divisor = first_bit;
targetted_divisor &= ~bit_test;
if (targetted_divisor) {
// The divisor is not a power-of-two, increase it
divisor++;
}
break;
}
}
if (divisor == -1) {
divisor = 31;
}
if (divisor >= 32) {
divisor = 31;
}
if (divisor != 0) {
divisor = (1 << (divisor - 1));
}
if (divisor >= 0x400) {
divisor = 0x3ff;
}
uint32_t freq_select = divisor & 0xff;
uint32_t upper_bits = (divisor >> 8) & 0x3;
uint32_t ret = (freq_select << 8) | (upper_bits << 6) | (0 << 5);
int denominator = 1;
if (divisor != 0) {
denominator = divisor * 2;
}
int actual_clock = base_clock / denominator;
debug
("base_clock: %d, target_rate: %d, divisor: 0x%x, actual_clock: %d, ret: 0x%x",
base_clock, target_rate, divisor, actual_clock, ret);
return ret;
#ifndef EMMC_ALLOW_OLD_SDHCI
} else {
error("unsupported host version");
return SD_GET_CLOCK_DIVIDER_FAIL;
}
#endif
}
// Switch the clock rate whilst running
static int
emmc_switch_clock_rate(uint32_t base_clock, uint32_t target_rate)
{
// Decide on an appropriate divider
uint32_t divider = emmc_get_clock_divider(base_clock, target_rate);
if (divider == SD_GET_CLOCK_DIVIDER_FAIL) {
debug("failed to get a valid divider for target rate %d Hz",
target_rate);
return -1;
}
// Wait for the command inhibit (CMD and DAT) bits to clear
while (get32(EMMC_STATUS) & 3) {
delayus(1000);
}
// Set the SD clock off
uint32_t control1 = get32(EMMC_CONTROL1);
control1 &= ~(1 << 2);
put32(EMMC_CONTROL1, control1);
delayus(2000);
// Write the new divider
control1 &= ~0xffe0; // Clear old setting + clock generator select
control1 |= divider;
put32(EMMC_CONTROL1, control1);
delayus(2000);
// Enable the SD clock
control1 |= (1 << 2);
put32(EMMC_CONTROL1, control1);
delayus(2000);
trace("set clock rate to %d Hz successfully", target_rate);
return 0;
}
static int
emmc_reset_cmd()
{
uint32_t control1 = get32(EMMC_CONTROL1);
control1 |= SD_RESET_CMD;
put32(EMMC_CONTROL1, control1);
if (emmc_timeout_wait(EMMC_CONTROL1, SD_RESET_CMD, 0, 1000000) < 0) {
error("CMD line did not reset properly");
return -1;
}
return 0;
}
int
emmc_reset_dat()
{
uint32_t control1 = get32(EMMC_CONTROL1);
control1 |= SD_RESET_DAT;
put32(EMMC_CONTROL1, control1);
if (emmc_timeout_wait(EMMC_CONTROL1, SD_RESET_DAT, 0, 1000000) < 0) {
error("DAT line did not reset properly");
return -1;
}
return 0;
}
void
emmc_issue_command_int(struct emmc *self, uint32_t cmd_reg,
uint32_t argument, int timeout)
{
self->last_cmd_reg = cmd_reg;
self->last_cmd_success = 0;
// This is as per HCSS 3.7.1.1/3.7.2.2
#ifdef EMMC_POLL_STATUS_REG
// Check Command Inhibit
while (get32(EMMC_STATUS) & 1) {
delayus(1000);
}
// Is the command with busy?
if ((cmd_reg & SD_CMD_RSPNS_TYPE_MASK) == SD_CMD_RSPNS_TYPE_48B) {
// With busy
// Is is an abort command?
if ((cmd_reg & SD_CMD_TYPE_MASK) != SD_CMD_TYPE_ABORT) {
// Not an abort command
// Wait for the data line to be free
while (get32(EMMC_STATUS) & 2) {
delayus(1000);
}
}
}
#endif
// Set block size and block count
// For now, block size = 512 bytes, block count = 1,
if (self->blocks_to_transfer > 0xffff) {
debug("blocks_to_transfer too great (%d)",
self->blocks_to_transfer);
self->last_cmd_success = 0;
return;
}
uint32_t blksizecnt =
self->block_size | (self->blocks_to_transfer << 16);
put32(EMMC_BLKSIZECNT, blksizecnt);
// Set argument 1 reg
put32(EMMC_ARG1, argument);
// Set command reg
put32(EMMC_CMDTM, cmd_reg);
// delayus(2000);
// Wait for command complete interrupt
emmc_timeout_wait(EMMC_INTERRUPT, 0x8001, 1, timeout);
uint32_t irpts = get32(EMMC_INTERRUPT);
// Clear command complete status
put32(EMMC_INTERRUPT, 0xffff0001);
// Test for errors
if ((irpts & 0xffff0001) != 1) {
warn("rrror occured whilst waiting for command complete interrupt");
self->last_error = irpts & 0xffff0000;
self->last_interrupt = irpts;
return;
}
// delayus(2000);
// Get response data
switch (cmd_reg & SD_CMD_RSPNS_TYPE_MASK) {
case SD_CMD_RSPNS_TYPE_48:
case SD_CMD_RSPNS_TYPE_48B:
self->last_r0 = get32(EMMC_RESP0);
break;
case SD_CMD_RSPNS_TYPE_136:
self->last_r0 = get32(EMMC_RESP0);
self->last_r1 = get32(EMMC_RESP1);
self->last_r2 = get32(EMMC_RESP2);
self->last_r3 = get32(EMMC_RESP3);
break;
}
// If with data, wait for the appropriate interrupt
if (cmd_reg & SD_CMD_ISDATA) {
uint32_t wr_irpt;
int is_write = 0;
if (cmd_reg & SD_CMD_DAT_DIR_CH) {
wr_irpt = (1 << 5); // read
} else {
is_write = 1;
wr_irpt = (1 << 4); // write
}
if (self->blocks_to_transfer > 1) {
trace("multi-block transfer");
}
assert(((uint64_t) self->buf & 3) == 0);
uint32_t *pData = (uint32_t *) self->buf;
for (int nBlock = 0; nBlock < self->blocks_to_transfer; nBlock++) {
emmc_timeout_wait(EMMC_INTERRUPT, wr_irpt | 0x8000, 1,
timeout);
irpts = get32(EMMC_INTERRUPT);
put32(EMMC_INTERRUPT, 0xffff0000 | wr_irpt);
if ((irpts & (0xffff0000 | wr_irpt)) != wr_irpt) {
warn("error occured whilst waiting for data ready interrupt");
self->last_error = irpts & 0xffff0000;
self->last_interrupt = irpts;
return;
}
// Transfer the block
assert(self->block_size <= 1024); // internal FIFO size of EMMC
size_t length = self->block_size;
assert((length & 3) == 0);
if (is_write) {
for (; length > 0; length -= 4) {
put32(EMMC_DATA, *pData++);
}
} else {
for (; length > 0; length -= 4) {
*pData++ = get32(EMMC_DATA);
}
}
}
trace("block transfer complete");
}
// Wait for transfer complete (set if read/write transfer or with busy)
if ((cmd_reg & SD_CMD_RSPNS_TYPE_MASK) == SD_CMD_RSPNS_TYPE_48B
|| (cmd_reg & SD_CMD_ISDATA)) {
#ifdef EMMC_POLL_STATUS_REG
// First check command inhibit (DAT) is not already 0
if ((get32(EMMC_STATUS) & 2) == 0) {
put32(EMMC_INTERRUPT, 0xffff0002);
} else
#endif
{
emmc_timeout_wait(EMMC_INTERRUPT, 0x8002, 1, timeout);
irpts = get32(EMMC_INTERRUPT);
put32(EMMC_INTERRUPT, 0xffff0002);
// Handle the case where both data timeout and transfer complete
// are set - transfer complete overrides data timeout: HCSS 2.2.17
if (((irpts & 0xffff0002) != 2)
&& ((irpts & 0xffff0002) != 0x100002)) {
warn("error occured whilst waiting for transfer complete interrupt");
self->last_error = irpts & 0xffff0000;
self->last_interrupt = irpts;
return;
}
put32(EMMC_INTERRUPT, 0xffff0002);
}
}
// Return success
self->last_cmd_success = 1;
}
/* Handle a card interrupt. */
void
emmc_handle_card_interrupt(struct emmc *self)
{
uint32_t status = get32(EMMC_STATUS);
trace("status: 0x%x", status);
// Get the card status
if (self->card_rca) {
emmc_issue_command_int(self, sd_commands[SEND_STATUS],
self->card_rca << 16, 500000);
if (FAIL(self)) {
warn("unable to get card status");
} else {
trace("card status: 0x%x", self->last_r0);
}
} else {
debug("no card currently selected");
}
}
void
emmc_handle_interrupts(struct emmc *self)
{
uint32_t irpts = get32(EMMC_INTERRUPT);
uint32_t reset_mask = 0;
if (irpts & SD_COMMAND_COMPLETE) {
trace("spurious command complete interrupt");
reset_mask |= SD_COMMAND_COMPLETE;
}
if (irpts & SD_TRANSFER_COMPLETE) {
trace("spurious transfer complete interrupt");
reset_mask |= SD_TRANSFER_COMPLETE;
}
if (irpts & SD_BLOCK_GAP_EVENT) {
trace("spurious block gap event interrupt");
reset_mask |= SD_BLOCK_GAP_EVENT;
}
if (irpts & SD_DMA_INTERRUPT) {
trace("spurious DMA interrupt");
reset_mask |= SD_DMA_INTERRUPT;
}
if (irpts & SD_BUFFER_WRITE_READY) {
trace("spurious buffer write ready interrupt");
reset_mask |= SD_BUFFER_WRITE_READY;
emmc_reset_dat();
}
if (irpts & SD_BUFFER_READ_READY) {
trace("spurious buffer read ready interrupt");
reset_mask |= SD_BUFFER_READ_READY;
emmc_reset_dat();
}
if (irpts & SD_CARD_INSERTION) {
trace("card insertion detected");
reset_mask |= SD_CARD_INSERTION;
}
if (irpts & SD_CARD_REMOVAL) {
trace("card removal detected");
reset_mask |= SD_CARD_REMOVAL;
self->card_removal = 1;
}
if (irpts & SD_CARD_INTERRUPT) {
trace("card interrupt detected");
emmc_handle_card_interrupt(self);