📄 bbu_mmc.s
字号:
; frequency that was saved in r4 (which is in KHz).
;
ldr r0, =2000 ; 2,000 is equal to 20 MHz in r4
cmp r4, r0 ; Is the card capable of 20 MHz?
mov r3, #0 ; Set clock to 19.5 MHz
str r3, [r1, #BBU_MMC_CLKRT_offset] ; Update clock rate register
;
;*******************************************************************************
;
; The next command is the SWITCH command and switches the card from 1-bit
; data transfer mode to 4-bit data transfer mode. Set bit 8 in location
; BBU_MMC_CMDAT_value so future data transfers occur in 4-bit mode.
; MMC cards use CMD6 while SD cards use ACMD6 command (and the data is
; different!)
;
; mov r0, #0 ; No data
; mov r1, #55 ; APP_CMD Command (CMD055)
; ldr r2, =bbu_MiscBuffer ; Address where data goes
; bl BBU_MMC_Cmd ; Send out command
; cmp r0, #0xFF ; Error detected?
; beq %F40 ; Yes - return to caller
; ldr r0, =0x03B70100 ; Data to set 4-bit transfer mode
; mov r1, #6 ; CMD06 - SWITCH command
; ldr r2, =bbu_MiscBuffer ; Address where data goes
; bl BBU_MMC_Cmd ; Send out command
; ldr r0, =BBU_MMC_CMDAT_value ; Address of data to be ORred
; mov r1, #0x100 ; Bit 8 enables 4 bit transfers
; str r1, [r0] ; Update this memory location
; mov r0, #0x1 ; Set up for a short delay
; bl BBU_msWait ; Delay r0 milliseconds
;
;*******************************************************************************
;
;
; Exit path
;
ldr r3, =BBU_MMC_CT ; Card type storage location
strh r6, [r3] ; Save the card type here
mov r0, r6 ; Copy card type into r0
mov r1, r5 ; Byte count is copied into r1
40 ldmfd sp!, {r2-r6, pc} ; Restore used registers and return to caller
ENDFUNC
BBU_MMC_FREQ DCD 0 ; Maximum card freq saved here (in 10KZ units)
BBU_RCA DCD 0 ; SD card relative address is saved here.
BBU_MMC_EGS DCW 0 ; Erase Group Size
BBU_MMC_CT DCW 0 ; Card type is saved here
BBU_MMC_MUL DCB 0,10,12,13,15,20,25,30,35,40,45,50,55,60,70,80 ; 16 multipliers
ALIGN 4
;
;*********************************************************************************
;
; ***************
; * *
; * BBU_MMC_Cmd *
; * *
; ***************
;
; This subroutine sends a command and sends/receives data as required
; by the command number that is evoked. Any CMD data that comes back is
; saved in the raw order in which it came in (for now) So the order may
; look a little goofy as the data comes in to the controller MSB to LSB
; so when BBU reads a 6 byte string from the MMC the byte order is:
; 1, 0, 3, 2, 5, 4. Byte 0 is a status byte so the actual data starts
; in byte 1 and goes to byte 4.
;
; PARAMETER PASSING:
;
; INPUT - r0 = Data to be sent out with command
; r1 = MMC command number (if bit 6 is set, set the INIT bit in command register)
; r2 = pointer to data to be sent or buffer to receive data
; (NOTE: pointer not required for all commands)
;
; COMMAND OUTPUT FORMAT:
;
; 48 bits as follows:
;
; Bit pos: 47 46 [45:40] [39:8] [7:1] 0
; Width: 1 1 6 32 7 1
; Value: 0 1 x x x 1
; Description: start transmit command argument crc7 end
; : bit bit index bit
;
;
; NOTE: A 32 bit status word is returend by most commands. The raw data
; is located starting at the address in r2 but the bytes need to
; be rearanged to get them in the right order to form the status
; word. Dat is sent MSB first in 16 bit words. The first 8 bits
; sent are other control bits (in offset 0x1) so they are skipped.
;
; +------------+------------+------------+------------+
; | bits 31:24 | bits 23:16 | bits 15:08 | bits 07:00 | MMC Satus Word
; +------------+------------+------------+------------+
; | offset 0x0 | offset 0x3 | offset 0x2 | offset 0x5 | Offset from r2
; +------------+------------+------------+------------+
;
; OUTPUT - r0 = 0xFF for BBU detected error. Otherwise...
; r0 = contents of MMC_STAT register
; r1 = base address of MMC controller being used
;
BBU_MMC_Cmd FUNCTION
stmfd sp!, {r2-r7, lr} ; Save used registers
ldr r4, =BBU_MMC_lastInit ; Address where # of last MMC port initialized is
ldrb r5, [r4] ; Fetch MMC # last initialized
ldr r3, =BBU_MMC1_PHYSICAL_BASE ; Load base address for MMC1 controller
cmp r5, #2 ; Was MMC2 the last MMC initialized?
ldreq r3, =BBU_MMC2_PHYSICAL_BASE ; YES - Load base address for MMC2 controller
;
; Make sure the clock is stopped (it may (should) be stopped already)
;
mov r4, #BBU_stop_clk ; Set the stop clock bit
str r4, [r3, #BBU_MMC_STRPCL_offset] ; Stop the clock
5 ldr r4, [r3, #BBU_MMC_STAT_offset] ; Get the status
ands r4, r4, #BBU_clk_en ; Test the clock enable bit
bne %B5 ; Loop until clock is stopped
;
; Fill registers with user supplied data
;
and r6, r1, #0x40 ; Save out init bit
and r7, r1, #0x3F ; Save off bits 5:0
strb r1, [r3, #BBU_MMC_CMD_offset] ; Place command in register
mov r1, r0, LSR #16 ; r1 = MSW of data to be sent with command
strh r1, [r3, #BBU_MMC_ARGH_offset] ; place in MSW
ldr r1, =0xFFFF ; Set up mask word
and r0, r0, r1 ; Extract LSW of command
strh r0, [r3, #BBU_MMC_ARGL_offset] ; place in LSW
;
; If command is doing a data transfer, the DATA_EN bit (bit #2) in the
; MMC_CMDAT register needs to be set.
;
ldr r0, =MMC_DTC ; List of commands that have data transfers
7 ldrb r1, [r0], #1 ; fetch a command number
cmp r1, r7 ; Do the commands match?
orreq r6, r6, #0x4 ; Yes - set DATA_EN bit
cmp r1, #0 ; At end of the list?
beq %F8 ; Yes - take normal exit path
b %B7 ; Get another command number from the list
;
; Figure out how the RES_TYPE bits are to be set based on the user supplied
; command number. (See description in table below).
;
8 ldr r4, =MMC_RESULT ; Get address of lookup table
mov r5, r7, LSR #2 ; Divide command number by 4 and put in r5
add r4, r4, r5 ; Add r5 offset to desired fetch byte
ldrb r5, [r4] ; Fetch the desired byte
mov r4, r7, LSL #1 ; Multiply command number by 2
and r4, r4, #0x6 ; Only save off bits 2:1
mov r5, r5, LSR r4 ; Shift right by r4 bits
ands r5, r5, #0x3 ; Save off bits 1:0
;
; Write the MMC_CMDAT register to process the command
;
orr r6, r6, r5 ; Set the RES_TYPE bits as required
ldr r4, =BBU_MMC_CMDAT_value ; Address of other bits to be set
ldr r0, [r4] ; Get this data
orr r6, r6, r0 ; Or in any other bits needed
str r6, [r3, #BBU_MMC_CMDAT_offset] ; Write the CMDAT register
;
; Start the clock
;
mov r4, #BBU_strt_clk ; Set the start clock bit
str r4, [r3, #BBU_MMC_STRPCL_offset] ; Stop the clock
;
; Spin on MMC_RXFIFO_RD_REQ bit and read data when it becomes available.
; Monitor DATA_TRAN_DONE (and time out) bit to know when transfer is done.
;
mov r6, #0x100000 ; Time out setting
10 ldr r0, [r3, #BBU_MMC_STAT_offset] ; Get MMC_STATUS register contents
ands r1, r0, #BBU_end_cmd_res ; Is command and response sequence done?
bne %F15 ; Yes - get data
subs r6, r6, #1 ; No - Decrement time out counter
bne %B10 ; Loop until timed out.
mov r0, #0xFF ; Timed out - set the error code...
b %F22 ; ... and take the exit path
;
; Check result time out bit
;
15 ldr r0, [r3, #BBU_MMC_STAT_offset] ; Get MMC_STATUS register contents
ands r1, r0, #BBU_time_out_res ; Is the result time out bit set?
movne r0, #0xFF ; Yes - set all the bits high
bne %F22 ; ... and return to caller
;
; No error - Service the FIFO. The number of bytes expected depends on the
; setting of MMC_CMDAT bits 1:0 as definded in the table at the end of this
; subroutine.
;
ldr r1, [r3, #BBU_MMC_CMDAT_offset] ; Get contents of CMDAT register
ands r1, r1, #3 ; Test bits 1:0
moveq r0, #0 ; Load with zero if no response expected
streq r0, [r2] ; Store in buffer
beq %F20 ; and exit
;
; If the code got here - we are expecting 6 0r 17 bytes to be returned
; Register is 16 bits wide so BBU reads using word (16-bit) commands.
;
mov r4, #3 ; Set bytes expected count to 6/2 bytes
cmp r1, #2 ; If type 2 response expected...
moveq r4, #9 ; ...then expect 17/2 bytes to come back
17 ldrh r0, [r3, #BBU_MMC_RES_FIFO_offset] ; Fetch a word of data
strh r0, [r2], #2 ; Store data & increment pointer
subs r4, r4, #1 ; Decrement byte transfered count
bne %B17 ; Loop until all the data is transfered
;
; If this is a command that is expecting data, the clock needs to
; continue running to clock the data into (or out of) the MMC
;
ldr r1, [r3, #BBU_MMC_CMDAT_offset] ; Get contents of CMDAT register
ands r1, r1, #0x4 ; Is the DATA_EN bit set?
bne %F24 ; Yes - just exit (for now)
;
; Fetch status and return to caller
;
20 ldr r0, [r3, #BBU_MMC_STAT_offset] ; Get status
;
; Stop the clock and return
;
22 mov r4, #BBU_stop_clk ; Set the stop clock bit
str r4, [r3, #BBU_MMC_STRPCL_offset] ; Stop the clock
24 mov r1, r3 ; Return controller base address
ldmfd sp!, {r2-r7, pc} ; Restore registers and return
;
; **** MMC RES_TYPE lookup table ****
;
; Different MMC commands result in different responses from the MMC which
; the controller needs to be aware of. The following lookup table is used
; to configure the controller for the type of command that was issued by setting
; the RES_TYPE[1] and RES_TYPE[0] bits in the MMC_CMDAT register. The table
; makes it easier for the user (one less thing to worry about). The RES_TYPE
; bits are set as follows:
;
; 0b00 = No response expected
; 0b01 = r1, r4, r5 response of 6 bytes
; 0b10 = r2 response of 17 bytes
; 0b11 = r3 response of 6 bytes
;
; Since there are only two bits required per command, they are packed in the
; table so each byte covers 4 commands starting with command zero at the
; LSBs and working up through memory to command number 63. NOTE: any reserved
; commands in this range are coded with 0b00 for the response.
;
MMC_RESULT DCB 0x6C, 0x44, 0x68, 0x15 ; Commands 0-15
DCB 0x15, 0x41, 0x55, 0x15 ; Commands 16-31
DCB 0x50, 0x55, 0x0D, 0x00 ; Commands 32-47
DCB 0x00, 0x40, 0x01, 0x00 ; Commands 48-63
;
; The following command numbers have data transfers associated with them
; and need the CLK line to continue to toggle for the data transfer.
; The command value 0x0 marks the end of the list.
;
MMC_DTC DCB 17, 24, 38, 0 ; Data Transfer Commands list
ALIGN 4
BBU_MMC_CSD DCD 0,0,0,0 ; MMC - CSD register 128 bits
BBU_MMC_lastInit DCB 0 ; Number of last MMC port initalized
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -