Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
b19269a6
Unverified
Commit
b19269a6
authored
Jul 12, 2018
by
Dimitris Papastamos
Committed by
GitHub
Jul 12, 2018
Browse files
Merge pull request #1432 from Yann-lms/mmc_framework
[RFC] Add MMC framework
parents
6e779ace
ad71d45e
Changes
2
Hide whitespace changes
Inline
Side-by-side
drivers/mmc/mmc.c
0 → 100644
View file @
b19269a6
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* Define a simple and generic interface to access eMMC and SD-card devices. */
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <mmc.h>
#include <stdbool.h>
#include <string.h>
#include <utils.h>
#define MMC_DEFAULT_MAX_RETRIES 5
#define SEND_OP_COND_MAX_RETRIES 100
#define MULT_BY_512K_SHIFT 19
static
const
struct
mmc_ops
*
ops
;
static
unsigned
int
mmc_ocr_value
;
static
struct
mmc_csd_emmc
mmc_csd
;
static
unsigned
char
mmc_ext_csd
[
512
]
__aligned
(
4
);
static
unsigned
int
mmc_flags
;
static
struct
mmc_device_info
*
mmc_dev_info
;
static
unsigned
int
rca
;
static
const
unsigned
char
tran_speed_base
[
16
]
=
{
0
,
10
,
12
,
13
,
15
,
20
,
26
,
30
,
35
,
40
,
45
,
52
,
55
,
60
,
70
,
80
};
static
const
unsigned
char
sd_tran_speed_base
[
16
]
=
{
0
,
10
,
12
,
13
,
15
,
20
,
25
,
30
,
35
,
40
,
45
,
50
,
55
,
60
,
70
,
80
};
static
bool
is_cmd23_enabled
(
void
)
{
return
((
mmc_flags
&
MMC_FLAG_CMD23
)
!=
0U
);
}
static
int
mmc_send_cmd
(
unsigned
int
idx
,
unsigned
int
arg
,
unsigned
int
r_type
,
unsigned
int
*
r_data
)
{
struct
mmc_cmd
cmd
;
int
ret
;
zeromem
(
&
cmd
,
sizeof
(
struct
mmc_cmd
));
cmd
.
cmd_idx
=
idx
;
cmd
.
cmd_arg
=
arg
;
cmd
.
resp_type
=
r_type
;
ret
=
ops
->
send_cmd
(
&
cmd
);
if
((
ret
==
0
)
&&
(
r_data
!=
NULL
))
{
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
*
r_data
=
cmd
.
resp_data
[
i
];
r_data
++
;
}
}
if
(
ret
!=
0
)
{
VERBOSE
(
"Send command %u error: %d
\n
"
,
idx
,
ret
);
}
return
ret
;
}
static
int
mmc_device_state
(
void
)
{
int
retries
=
MMC_DEFAULT_MAX_RETRIES
;
unsigned
int
resp_data
[
4
];
do
{
int
ret
;
if
(
retries
==
0
)
{
ERROR
(
"CMD13 failed after %d retries
\n
"
,
MMC_DEFAULT_MAX_RETRIES
);
return
-
EIO
;
}
ret
=
mmc_send_cmd
(
MMC_CMD
(
13
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
1
),
&
resp_data
[
0
]);
if
(
ret
!=
0
)
{
return
ret
;
}
if
((
resp_data
[
0
]
&
STATUS_SWITCH_ERROR
)
!=
0U
)
{
return
-
EIO
;
}
retries
--
;
}
while
((
resp_data
[
0
]
&
STATUS_READY_FOR_DATA
)
==
0U
);
return
MMC_GET_STATE
(
resp_data
[
0
]);
}
static
int
mmc_set_ext_csd
(
unsigned
int
ext_cmd
,
unsigned
int
value
)
{
int
ret
;
ret
=
mmc_send_cmd
(
MMC_CMD
(
6
),
EXTCSD_WRITE_BYTES
|
EXTCSD_CMD
(
ext_cmd
)
|
EXTCSD_VALUE
(
value
)
|
EXTCSD_CMD_SET_NORMAL
,
0
,
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
ret
;
}
}
while
(
ret
==
MMC_STATE_PRG
);
return
0
;
}
static
int
mmc_sd_switch
(
unsigned
int
bus_width
)
{
int
ret
;
int
retries
=
MMC_DEFAULT_MAX_RETRIES
;
unsigned
int
scr
[
2
]
=
{
0
};
unsigned
int
bus_width_arg
=
0
;
ret
=
ops
->
prepare
(
0
,
(
uintptr_t
)
&
scr
,
sizeof
(
scr
));
if
(
ret
!=
0
)
{
return
ret
;
}
/* CMD55: Application Specific Command */
ret
=
mmc_send_cmd
(
MMC_CMD
(
55
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
/* ACMD51: SEND_SCR */
do
{
ret
=
mmc_send_cmd
(
MMC_ACMD
(
51
),
0
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
((
ret
!=
0
)
&&
(
retries
==
0
))
{
ERROR
(
"ACMD51 failed after %d retries (ret=%d)
\n
"
,
MMC_DEFAULT_MAX_RETRIES
,
ret
);
return
ret
;
}
retries
--
;
}
while
(
ret
!=
0
);
ret
=
ops
->
read
(
0
,
(
uintptr_t
)
&
scr
,
sizeof
(
scr
));
if
(
ret
!=
0
)
{
return
ret
;
}
if
(((
scr
[
0
]
&
SD_SCR_BUS_WIDTH_4
)
!=
0U
)
&&
(
bus_width
==
MMC_BUS_WIDTH_4
))
{
bus_width_arg
=
2
;
}
/* CMD55: Application Specific Command */
ret
=
mmc_send_cmd
(
MMC_CMD
(
55
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
/* ACMD6: SET_BUS_WIDTH */
ret
=
mmc_send_cmd
(
MMC_ACMD
(
6
),
bus_width_arg
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
ret
;
}
}
while
(
ret
==
MMC_STATE_PRG
);
return
0
;
}
static
int
mmc_set_ios
(
unsigned
int
clk
,
unsigned
int
bus_width
)
{
int
ret
;
unsigned
int
width
=
bus_width
;
if
(
mmc_dev_info
->
mmc_dev_type
!=
MMC_IS_EMMC
)
{
if
(
width
==
MMC_BUS_WIDTH_8
)
{
WARN
(
"Wrong bus config for SD-card, force to 4
\n
"
);
width
=
MMC_BUS_WIDTH_4
;
}
ret
=
mmc_sd_switch
(
width
);
if
(
ret
!=
0
)
{
return
ret
;
}
}
else
if
(
mmc_csd
.
spec_vers
==
4U
)
{
ret
=
mmc_set_ext_csd
(
CMD_EXTCSD_BUS_WIDTH
,
(
unsigned
int
)
width
);
if
(
ret
!=
0
)
{
return
ret
;
}
}
else
{
VERBOSE
(
"Wrong MMC type or spec version
\n
"
);
}
return
ops
->
set_ios
(
clk
,
width
);
}
static
int
mmc_fill_device_info
(
void
)
{
unsigned
long
long
c_size
;
unsigned
int
speed_idx
;
unsigned
int
nb_blocks
;
unsigned
int
freq_unit
;
int
ret
;
struct
mmc_csd_sd_v2
*
csd_sd_v2
;
switch
(
mmc_dev_info
->
mmc_dev_type
)
{
case
MMC_IS_EMMC
:
mmc_dev_info
->
block_size
=
MMC_BLOCK_SIZE
;
ret
=
ops
->
prepare
(
0
,
(
uintptr_t
)
&
mmc_ext_csd
,
sizeof
(
mmc_ext_csd
));
if
(
ret
!=
0
)
{
return
ret
;
}
/* MMC CMD8: SEND_EXT_CSD */
ret
=
mmc_send_cmd
(
MMC_CMD
(
8
),
0
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
ret
=
ops
->
read
(
0
,
(
uintptr_t
)
&
mmc_ext_csd
,
sizeof
(
mmc_ext_csd
));
if
(
ret
!=
0
)
{
return
ret
;
}
nb_blocks
=
(
mmc_ext_csd
[
CMD_EXTCSD_SEC_CNT
]
<<
0
)
|
(
mmc_ext_csd
[
CMD_EXTCSD_SEC_CNT
+
1
]
<<
8
)
|
(
mmc_ext_csd
[
CMD_EXTCSD_SEC_CNT
+
2
]
<<
16
)
|
(
mmc_ext_csd
[
CMD_EXTCSD_SEC_CNT
+
3
]
<<
24
);
mmc_dev_info
->
device_size
=
(
unsigned
long
long
)
nb_blocks
*
mmc_dev_info
->
block_size
;
break
;
case
MMC_IS_SD
:
/*
* Use the same mmc_csd struct, as required fields here
* (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
*/
mmc_dev_info
->
block_size
=
BIT_32
(
mmc_csd
.
read_bl_len
);
c_size
=
((
unsigned
long
long
)
mmc_csd
.
c_size_high
<<
2U
)
|
(
unsigned
long
long
)
mmc_csd
.
c_size_low
;
assert
(
c_size
!=
0xFFFU
);
mmc_dev_info
->
device_size
=
(
c_size
+
1U
)
*
BIT_64
(
mmc_csd
.
c_size_mult
+
2U
)
*
mmc_dev_info
->
block_size
;
break
;
case
MMC_IS_SD_HC
:
assert
(
mmc_csd
.
csd_structure
==
1U
);
mmc_dev_info
->
block_size
=
MMC_BLOCK_SIZE
;
/* Need to use mmc_csd_sd_v2 struct */
csd_sd_v2
=
(
struct
mmc_csd_sd_v2
*
)
&
mmc_csd
;
c_size
=
((
unsigned
long
long
)
csd_sd_v2
->
c_size_high
<<
16
)
|
(
unsigned
long
long
)
csd_sd_v2
->
c_size_low
;
mmc_dev_info
->
device_size
=
(
c_size
+
1U
)
<<
MULT_BY_512K_SHIFT
;
break
;
default:
ret
=
-
EINVAL
;
break
;
}
if
(
ret
!=
0
)
{
return
ret
;
}
speed_idx
=
(
mmc_csd
.
tran_speed
&
CSD_TRAN_SPEED_MULT_MASK
)
>>
CSD_TRAN_SPEED_MULT_SHIFT
;
assert
(
speed_idx
>
0U
);
if
(
mmc_dev_info
->
mmc_dev_type
==
MMC_IS_EMMC
)
{
mmc_dev_info
->
max_bus_freq
=
tran_speed_base
[
speed_idx
];
}
else
{
mmc_dev_info
->
max_bus_freq
=
sd_tran_speed_base
[
speed_idx
];
}
freq_unit
=
mmc_csd
.
tran_speed
&
CSD_TRAN_SPEED_UNIT_MASK
;
while
(
freq_unit
!=
0U
)
{
mmc_dev_info
->
max_bus_freq
*=
10U
;
--
freq_unit
;
}
mmc_dev_info
->
max_bus_freq
*=
10000U
;
return
0
;
}
static
int
sd_send_op_cond
(
void
)
{
int
retries
=
SEND_OP_COND_MAX_RETRIES
;
unsigned
int
resp_data
[
4
];
do
{
int
ret
;
if
(
retries
==
0
)
{
ERROR
(
"ACMD41 failed after %d retries
\n
"
,
SEND_OP_COND_MAX_RETRIES
);
return
-
EIO
;
}
/* CMD55: Application Specific Command */
ret
=
mmc_send_cmd
(
MMC_CMD
(
55
),
0
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
/* ACMD41: SD_SEND_OP_COND */
ret
=
mmc_send_cmd
(
MMC_ACMD
(
41
),
OCR_HCS
,
MMC_RESPONSE_R
(
3
),
&
resp_data
[
0
]);
if
(
ret
!=
0
)
{
return
ret
;
}
retries
--
;
}
while
((
resp_data
[
0
]
&
OCR_POWERUP
)
==
0U
);
mmc_ocr_value
=
resp_data
[
0
];
if
((
mmc_ocr_value
&
OCR_HCS
)
!=
0U
)
{
mmc_dev_info
->
mmc_dev_type
=
MMC_IS_SD_HC
;
}
else
{
mmc_dev_info
->
mmc_dev_type
=
MMC_IS_SD
;
}
return
0
;
}
static
int
mmc_send_op_cond
(
void
)
{
int
ret
;
int
retries
=
SEND_OP_COND_MAX_RETRIES
;
unsigned
int
resp_data
[
4
];
/* CMD0: reset to IDLE */
ret
=
mmc_send_cmd
(
MMC_CMD
(
0
),
0
,
0
,
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
do
{
if
(
retries
==
0
)
{
ERROR
(
"CMD1 failed after %d retries
\n
"
,
SEND_OP_COND_MAX_RETRIES
);
return
-
EIO
;
}
/* CMD1: get OCR register (SEND_OP_COND) */
ret
=
mmc_send_cmd
(
MMC_CMD
(
1
),
OCR_SECTOR_MODE
|
OCR_VDD_MIN_2V7
|
OCR_VDD_MIN_1V7
,
MMC_RESPONSE_R
(
3
),
&
resp_data
[
0
]);
if
(
ret
!=
0
)
{
return
ret
;
}
retries
--
;
}
while
((
resp_data
[
0
]
&
OCR_POWERUP
)
==
0U
);
mmc_ocr_value
=
resp_data
[
0
];
return
0
;
}
static
int
mmc_enumerate
(
unsigned
int
clk
,
unsigned
int
bus_width
)
{
int
ret
;
unsigned
int
resp_data
[
4
];
ops
->
init
();
/* CMD0: reset to IDLE */
ret
=
mmc_send_cmd
(
MMC_CMD
(
0
),
0
,
0
,
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
/* CMD8: Send Interface Condition Command */
ret
=
mmc_send_cmd
(
MMC_CMD
(
8
),
VHS_2_7_3_6_V
|
CMD8_CHECK_PATTERN
,
MMC_RESPONSE_R
(
7
),
&
resp_data
[
0
]);
if
((
ret
==
0
)
&&
((
resp_data
[
0
]
&
0xffU
)
==
CMD8_CHECK_PATTERN
))
{
ret
=
sd_send_op_cond
();
}
else
{
ret
=
mmc_send_op_cond
();
}
if
(
ret
!=
0
)
{
return
ret
;
}
/* CMD2: Card Identification */
ret
=
mmc_send_cmd
(
MMC_CMD
(
2
),
0
,
MMC_RESPONSE_R
(
2
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
/* CMD3: Set Relative Address */
if
(
mmc_dev_info
->
mmc_dev_type
==
MMC_IS_EMMC
)
{
rca
=
MMC_FIX_RCA
;
ret
=
mmc_send_cmd
(
MMC_CMD
(
3
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
}
else
{
ret
=
mmc_send_cmd
(
MMC_CMD
(
3
),
0
,
MMC_RESPONSE_R
(
6
),
&
resp_data
[
0
]);
if
(
ret
!=
0
)
{
return
ret
;
}
rca
=
(
resp_data
[
0
]
&
0xFFFF0000U
)
>>
16
;
}
/* CMD9: CSD Register */
ret
=
mmc_send_cmd
(
MMC_CMD
(
9
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
2
),
&
resp_data
[
0
]);
if
(
ret
!=
0
)
{
return
ret
;
}
memcpy
(
&
mmc_csd
,
&
resp_data
,
sizeof
(
resp_data
));
/* CMD7: Select Card */
ret
=
mmc_send_cmd
(
MMC_CMD
(
7
),
rca
<<
RCA_SHIFT_OFFSET
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
ret
;
}
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
ret
;
}
}
while
(
ret
!=
MMC_STATE_TRAN
);
ret
=
mmc_fill_device_info
();
if
(
ret
!=
0
)
{
return
ret
;
}
return
mmc_set_ios
(
clk
,
bus_width
);
}
size_t
mmc_read_blocks
(
unsigned
int
lba
,
uintptr_t
buf
,
size_t
size
)
{
int
ret
;
unsigned
int
cmd_idx
,
cmd_arg
;
assert
((
ops
!=
NULL
)
&&
(
ops
->
read
!=
NULL
)
&&
(
size
!=
0U
)
&&
((
size
&
MMC_BLOCK_MASK
)
==
0U
));
ret
=
ops
->
prepare
(
lba
,
buf
,
size
);
if
(
ret
!=
0
)
{
return
0
;
}
if
(
is_cmd23_enabled
())
{
/* Set block count */
ret
=
mmc_send_cmd
(
MMC_CMD
(
23
),
size
/
MMC_BLOCK_SIZE
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
cmd_idx
=
MMC_CMD
(
18
);
}
else
{
if
(
size
>
MMC_BLOCK_SIZE
)
{
cmd_idx
=
MMC_CMD
(
18
);
}
else
{
cmd_idx
=
MMC_CMD
(
17
);
}
}
if
(((
mmc_ocr_value
&
OCR_ACCESS_MODE_MASK
)
==
OCR_BYTE_MODE
)
&&
(
mmc_dev_info
->
mmc_dev_type
!=
MMC_IS_SD_HC
))
{
cmd_arg
=
lba
*
MMC_BLOCK_SIZE
;
}
else
{
cmd_arg
=
lba
;
}
ret
=
mmc_send_cmd
(
cmd_idx
,
cmd_arg
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
ret
=
ops
->
read
(
lba
,
buf
,
size
);
if
(
ret
!=
0
)
{
return
0
;
}
/* Wait buffer empty */
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
0
;
}
}
while
((
ret
!=
MMC_STATE_TRAN
)
&&
(
ret
!=
MMC_STATE_DATA
));
if
(
!
is_cmd23_enabled
()
&&
(
size
>
MMC_BLOCK_SIZE
))
{
ret
=
mmc_send_cmd
(
MMC_CMD
(
12
),
0
,
0
,
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
}
return
size
;
}
size_t
mmc_write_blocks
(
unsigned
int
lba
,
const
uintptr_t
buf
,
size_t
size
)
{
int
ret
;
unsigned
int
cmd_idx
,
cmd_arg
;
assert
((
ops
!=
NULL
)
&&
(
ops
->
write
!=
NULL
)
&&
(
size
!=
0U
)
&&
((
buf
&
MMC_BLOCK_MASK
)
==
0U
)
&&
((
size
&
MMC_BLOCK_MASK
)
==
0U
));
ret
=
ops
->
prepare
(
lba
,
buf
,
size
);
if
(
ret
!=
0
)
{
return
0
;
}
if
(
is_cmd23_enabled
())
{
/* Set block count */
ret
=
mmc_send_cmd
(
MMC_CMD
(
23
),
size
/
MMC_BLOCK_SIZE
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
cmd_idx
=
MMC_CMD
(
25
);
}
else
{
if
(
size
>
MMC_BLOCK_SIZE
)
{
cmd_idx
=
MMC_CMD
(
25
);
}
else
{
cmd_idx
=
MMC_CMD
(
24
);
}
}
if
((
mmc_ocr_value
&
OCR_ACCESS_MODE_MASK
)
==
OCR_BYTE_MODE
)
{
cmd_arg
=
lba
*
MMC_BLOCK_SIZE
;
}
else
{
cmd_arg
=
lba
;
}
ret
=
mmc_send_cmd
(
cmd_idx
,
cmd_arg
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
ret
=
ops
->
write
(
lba
,
buf
,
size
);
if
(
ret
!=
0
)
{
return
0
;
}
/* Wait buffer empty */
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
0
;
}
}
while
((
ret
!=
MMC_STATE_TRAN
)
&&
(
ret
!=
MMC_STATE_RCV
));
if
(
!
is_cmd23_enabled
()
&&
(
size
>
MMC_BLOCK_SIZE
))
{
ret
=
mmc_send_cmd
(
MMC_CMD
(
12
),
0
,
0
,
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
}
return
size
;
}
size_t
mmc_erase_blocks
(
unsigned
int
lba
,
size_t
size
)
{
int
ret
;
assert
(
ops
!=
NULL
);
assert
((
size
!=
0U
)
&&
((
size
&
MMC_BLOCK_MASK
)
==
0U
));
ret
=
mmc_send_cmd
(
MMC_CMD
(
35
),
lba
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
ret
=
mmc_send_cmd
(
MMC_CMD
(
36
),
lba
+
(
size
/
MMC_BLOCK_SIZE
)
-
1U
,
MMC_RESPONSE_R
(
1
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
ret
=
mmc_send_cmd
(
MMC_CMD
(
38
),
lba
,
MMC_RESPONSE_R
(
0x1B
),
NULL
);
if
(
ret
!=
0
)
{
return
0
;
}
do
{
ret
=
mmc_device_state
();
if
(
ret
<
0
)
{
return
0
;
}
}
while
(
ret
!=
MMC_STATE_TRAN
);
return
size
;
}
static
inline
void
mmc_rpmb_enable
(
void
)
{
mmc_set_ext_csd
(
CMD_EXTCSD_PARTITION_CONFIG
,
PART_CFG_BOOT_PARTITION1_ENABLE
|
PART_CFG_PARTITION1_ACCESS
);
}
static
inline
void
mmc_rpmb_disable
(
void
)
{
mmc_set_ext_csd
(
CMD_EXTCSD_PARTITION_CONFIG
,
PART_CFG_BOOT_PARTITION1_ENABLE
);
}
size_t
mmc_rpmb_read_blocks
(
unsigned
int
lba
,
uintptr_t
buf
,
size_t
size
)
{
size_t
size_read
;
mmc_rpmb_enable
();
size_read
=
mmc_read_blocks
(
lba
,
buf
,
size
);
mmc_rpmb_disable
();
return
size_read
;
}
size_t
mmc_rpmb_write_blocks
(
unsigned
int
lba
,
const
uintptr_t
buf
,
size_t
size
)
{
size_t
size_written
;
mmc_rpmb_enable
();
size_written
=
mmc_write_blocks
(
lba
,
buf
,
size
);
mmc_rpmb_disable
();
return
size_written
;
}
size_t
mmc_rpmb_erase_blocks
(
unsigned
int
lba
,
size_t
size
)
{
size_t
size_erased
;
mmc_rpmb_enable
();
size_erased
=
mmc_erase_blocks
(
lba
,
size
);
mmc_rpmb_disable
();
return
size_erased
;
}
int
mmc_init
(
const
struct
mmc_ops
*
ops_ptr
,
unsigned
int
clk
,
unsigned
int
width
,
unsigned
int
flags
,
struct
mmc_device_info
*
device_info
)
{
assert
((
ops_ptr
!=
NULL
)
&&
(
ops_ptr
->
init
!=
NULL
)
&&
(
ops_ptr
->
send_cmd
!=
NULL
)
&&
(
ops_ptr
->
set_ios
!=
NULL
)
&&
(
ops_ptr
->
prepare
!=
NULL
)
&&
(
ops_ptr
->
read
!=
NULL
)
&&
(
ops_ptr
->
write
!=
NULL
)
&&
(
device_info
!=
NULL
)
&&
(
clk
!=
0
)
&&
((
width
==
MMC_BUS_WIDTH_1
)
||
(
width
==
MMC_BUS_WIDTH_4
)
||
(
width
==
MMC_BUS_WIDTH_8
)
||
(
width
==
MMC_BUS_WIDTH_DDR_4
)
||
(
width
==
MMC_BUS_WIDTH_DDR_8
)));
ops
=
ops_ptr
;
mmc_flags
=
flags
;
mmc_dev_info
=
device_info
;
return
mmc_enumerate
(
clk
,
width
);
}
include/drivers/mmc.h
0 → 100644
View file @
b19269a6
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __MMC_H__
#define __MMC_H__
#include <stdint.h>
#include <utils_def.h>
#define MMC_BLOCK_SIZE U(512)
#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - U(1))
#define MMC_BOOT_CLK_RATE (400 * 1000)
#define MMC_CMD(_x) U(_x)
#define MMC_ACMD(_x) U(_x)
#define OCR_POWERUP BIT(31)
#define OCR_HCS BIT(30)
#define OCR_BYTE_MODE (U(0) << 29)
#define OCR_SECTOR_MODE (U(2) << 29)
#define OCR_ACCESS_MODE_MASK (U(3) << 29)
#define OCR_3_5_3_6 BIT(23)
#define OCR_3_4_3_5 BIT(22)
#define OCR_3_3_3_4 BIT(21)
#define OCR_3_2_3_3 BIT(20)
#define OCR_3_1_3_2 BIT(19)
#define OCR_3_0_3_1 BIT(18)
#define OCR_2_9_3_0 BIT(17)
#define OCR_2_8_2_9 BIT(16)
#define OCR_2_7_2_8 BIT(15)
#define OCR_VDD_MIN_2V7 GENMASK(23, 15)
#define OCR_VDD_MIN_2V0 GENMASK(14, 8)
#define OCR_VDD_MIN_1V7 BIT(7)
#define MMC_RESPONSE_R(_x) U(_x)
/* Value randomly chosen for eMMC RCA, it should be > 1 */
#define MMC_FIX_RCA 6
#define RCA_SHIFT_OFFSET 16
#define CMD_EXTCSD_PARTITION_CONFIG 179
#define CMD_EXTCSD_BUS_WIDTH 183
#define CMD_EXTCSD_HS_TIMING 185
#define CMD_EXTCSD_SEC_CNT 212
#define PART_CFG_BOOT_PARTITION1_ENABLE (U(1) << 3)
#define PART_CFG_PARTITION1_ACCESS (U(1) << 0)
/* Values in EXT CSD register */
#define MMC_BUS_WIDTH_1 U(0)
#define MMC_BUS_WIDTH_4 U(1)
#define MMC_BUS_WIDTH_8 U(2)
#define MMC_BUS_WIDTH_DDR_4 U(5)
#define MMC_BUS_WIDTH_DDR_8 U(6)
#define MMC_BOOT_MODE_BACKWARD (U(0) << 3)
#define MMC_BOOT_MODE_HS_TIMING (U(1) << 3)
#define MMC_BOOT_MODE_DDR (U(2) << 3)
#define EXTCSD_SET_CMD (U(0) << 24)
#define EXTCSD_SET_BITS (U(1) << 24)
#define EXTCSD_CLR_BITS (U(2) << 24)
#define EXTCSD_WRITE_BYTES (U(3) << 24)
#define EXTCSD_CMD(x) (((x) & 0xff) << 16)
#define EXTCSD_VALUE(x) (((x) & 0xff) << 8)
#define EXTCSD_CMD_SET_NORMAL U(1)
#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0)
#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3)
#define CSD_TRAN_SPEED_MULT_SHIFT 3
#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9)
#define STATUS_READY_FOR_DATA BIT(8)
#define STATUS_SWITCH_ERROR BIT(7)
#define MMC_GET_STATE(x) (((x) >> 9) & 0xf)
#define MMC_STATE_IDLE 0
#define MMC_STATE_READY 1
#define MMC_STATE_IDENT 2
#define MMC_STATE_STBY 3
#define MMC_STATE_TRAN 4
#define MMC_STATE_DATA 5
#define MMC_STATE_RCV 6
#define MMC_STATE_PRG 7
#define MMC_STATE_DIS 8
#define MMC_STATE_BTST 9
#define MMC_STATE_SLP 10
#define MMC_FLAG_CMD23 (U(1) << 0)
#define CMD8_CHECK_PATTERN U(0xAA)
#define VHS_2_7_3_6_V BIT(8)
#define SD_SCR_BUS_WIDTH_1 BIT(8)
#define SD_SCR_BUS_WIDTH_4 BIT(10)
struct
mmc_cmd
{
unsigned
int
cmd_idx
;
unsigned
int
cmd_arg
;
unsigned
int
resp_type
;
unsigned
int
resp_data
[
4
];
};
struct
mmc_ops
{
void
(
*
init
)(
void
);
int
(
*
send_cmd
)(
struct
mmc_cmd
*
cmd
);
int
(
*
set_ios
)(
unsigned
int
clk
,
unsigned
int
width
);
int
(
*
prepare
)(
int
lba
,
uintptr_t
buf
,
size_t
size
);
int
(
*
read
)(
int
lba
,
uintptr_t
buf
,
size_t
size
);
int
(
*
write
)(
int
lba
,
const
uintptr_t
buf
,
size_t
size
);
};
struct
mmc_csd_emmc
{
unsigned
int
not_used
:
1
;
unsigned
int
crc
:
7
;
unsigned
int
ecc
:
2
;
unsigned
int
file_format
:
2
;
unsigned
int
tmp_write_protect
:
1
;
unsigned
int
perm_write_protect
:
1
;
unsigned
int
copy
:
1
;
unsigned
int
file_format_grp
:
1
;
unsigned
int
reserved_1
:
5
;
unsigned
int
write_bl_partial
:
1
;
unsigned
int
write_bl_len
:
4
;
unsigned
int
r2w_factor
:
3
;
unsigned
int
default_ecc
:
2
;
unsigned
int
wp_grp_enable
:
1
;
unsigned
int
wp_grp_size
:
5
;
unsigned
int
erase_grp_mult
:
5
;
unsigned
int
erase_grp_size
:
5
;
unsigned
int
c_size_mult
:
3
;
unsigned
int
vdd_w_curr_max
:
3
;
unsigned
int
vdd_w_curr_min
:
3
;
unsigned
int
vdd_r_curr_max
:
3
;
unsigned
int
vdd_r_curr_min
:
3
;
unsigned
int
c_size_low
:
2
;
unsigned
int
c_size_high
:
10
;
unsigned
int
reserved_2
:
2
;
unsigned
int
dsr_imp
:
1
;
unsigned
int
read_blk_misalign
:
1
;
unsigned
int
write_blk_misalign
:
1
;
unsigned
int
read_bl_partial
:
1
;
unsigned
int
read_bl_len
:
4
;
unsigned
int
ccc
:
12
;
unsigned
int
tran_speed
:
8
;
unsigned
int
nsac
:
8
;
unsigned
int
taac
:
8
;
unsigned
int
reserved_3
:
2
;
unsigned
int
spec_vers
:
4
;
unsigned
int
csd_structure
:
2
;
};
struct
mmc_csd_sd_v2
{
unsigned
int
not_used
:
1
;
unsigned
int
crc
:
7
;
unsigned
int
reserved_1
:
2
;
unsigned
int
file_format
:
2
;
unsigned
int
tmp_write_protect
:
1
;
unsigned
int
perm_write_protect
:
1
;
unsigned
int
copy
:
1
;
unsigned
int
file_format_grp
:
1
;
unsigned
int
reserved_2
:
5
;
unsigned
int
write_bl_partial
:
1
;
unsigned
int
write_bl_len
:
4
;
unsigned
int
r2w_factor
:
3
;
unsigned
int
reserved_3
:
2
;
unsigned
int
wp_grp_enable
:
1
;
unsigned
int
wp_grp_size
:
7
;
unsigned
int
sector_size
:
7
;
unsigned
int
erase_block_en
:
1
;
unsigned
int
reserved_4
:
1
;
unsigned
int
c_size_low
:
16
;
unsigned
int
c_size_high
:
6
;
unsigned
int
reserved_5
:
6
;
unsigned
int
dsr_imp
:
1
;
unsigned
int
read_blk_misalign
:
1
;
unsigned
int
write_blk_misalign
:
1
;
unsigned
int
read_bl_partial
:
1
;
unsigned
int
read_bl_len
:
4
;
unsigned
int
ccc
:
12
;
unsigned
int
tran_speed
:
8
;
unsigned
int
nsac
:
8
;
unsigned
int
taac
:
8
;
unsigned
int
reserved_6
:
6
;
unsigned
int
csd_structure
:
2
;
};
enum
mmc_device_type
{
MMC_IS_EMMC
,
MMC_IS_SD
,
MMC_IS_SD_HC
,
};
struct
mmc_device_info
{
unsigned
long
long
device_size
;
/* Size of device in bytes */
unsigned
int
block_size
;
/* Block size in bytes */
unsigned
int
max_bus_freq
;
/* Max bus freq in Hz */
enum
mmc_device_type
mmc_dev_type
;
/* Type of MMC */
};
size_t
mmc_read_blocks
(
unsigned
int
lba
,
uintptr_t
buf
,
size_t
size
);
size_t
mmc_write_blocks
(
unsigned
int
lba
,
const
uintptr_t
buf
,
size_t
size
);
size_t
mmc_erase_blocks
(
unsigned
int
lba
,
size_t
size
);
size_t
mmc_rpmb_read_blocks
(
unsigned
int
lba
,
uintptr_t
buf
,
size_t
size
);
size_t
mmc_rpmb_write_blocks
(
unsigned
int
lba
,
const
uintptr_t
buf
,
size_t
size
);
size_t
mmc_rpmb_erase_blocks
(
unsigned
int
lba
,
size_t
size
);
int
mmc_init
(
const
struct
mmc_ops
*
ops_ptr
,
unsigned
int
clk
,
unsigned
int
width
,
unsigned
int
flags
,
struct
mmc_device_info
*
device_info
);
#endif
/* __MMC_H__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment