Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
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
5735057d
Unverified
Commit
5735057d
authored
6 years ago
by
Antonio Niño Díaz
Committed by
GitHub
6 years ago
Browse files
Options
Download
Plain Diff
Merge pull request #1796 from grandpaul/rpi3-sdhost-driver
RPi3 SDHost driver
parents
0d845356
92d2f491
master
v2.5
v2.5-rc1
v2.5-rc0
v2.4
v2.4-rc2
v2.4-rc1
v2.4-rc0
v2.3
v2.3-rc2
v2.3-rc1
v2.3-rc0
v2.2
v2.2-rc2
v2.2-rc1
v2.2-rc0
v2.1
v2.1-rc1
v2.1-rc0
arm_cca_v0.2
arm_cca_v0.1
No related merge requests found
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
drivers/rpi3/sdhost/rpi3_sdhost.c
+689
-0
drivers/rpi3/sdhost/rpi3_sdhost.c
include/drivers/rpi3/sdhost/rpi3_sdhost.h
+124
-0
include/drivers/rpi3/sdhost/rpi3_sdhost.h
maintainers.rst
+4
-0
maintainers.rst
plat/rpi3/include/platform_def.h
+2
-0
plat/rpi3/include/platform_def.h
plat/rpi3/platform.mk
+3
-0
plat/rpi3/platform.mk
plat/rpi3/rpi3_bl2_setup.c
+22
-0
plat/rpi3/rpi3_bl2_setup.c
plat/rpi3/rpi3_hw.h
+6
-0
plat/rpi3/rpi3_hw.h
with
850 additions
and
0 deletions
+850
-0
drivers/rpi3/sdhost/rpi3_sdhost.c
0 → 100644
View file @
5735057d
/*
* Copyright (c) 2019, Linaro Limited
* Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <drivers/delay_timer.h>
#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
#include <drivers/mmc.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
#include <errno.h>
#include <string.h>
static
void
rpi3_sdhost_initialize
(
void
);
static
int
rpi3_sdhost_send_cmd
(
struct
mmc_cmd
*
cmd
);
static
int
rpi3_sdhost_set_ios
(
unsigned
int
clk
,
unsigned
int
width
);
static
int
rpi3_sdhost_prepare
(
int
lba
,
uintptr_t
buf
,
size_t
size
);
static
int
rpi3_sdhost_read
(
int
lba
,
uintptr_t
buf
,
size_t
size
);
static
int
rpi3_sdhost_write
(
int
lba
,
uintptr_t
buf
,
size_t
size
);
static
const
struct
mmc_ops
rpi3_sdhost_ops
=
{
.
init
=
rpi3_sdhost_initialize
,
.
send_cmd
=
rpi3_sdhost_send_cmd
,
.
set_ios
=
rpi3_sdhost_set_ios
,
.
prepare
=
rpi3_sdhost_prepare
,
.
read
=
rpi3_sdhost_read
,
.
write
=
rpi3_sdhost_write
,
};
static
struct
rpi3_sdhost_params
rpi3_sdhost_params
;
/**
* Wait for command being processed.
*
* This function waits the command being processed. It compares
* the ENABLE flag of the HC_COMMAND register. When ENABLE flag disappeared
* it means the command is processed by the SDHOST.
* The timeout is currently 1000*100 us = 100 ms.
*
* @return 0: command finished. 1: command timed out.
*/
static
int
rpi3_sdhost_waitcommand
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
volatile
int
timeout
=
1000
;
while
((
mmio_read_32
(
reg_base
+
HC_COMMAND
)
&
HC_CMD_ENABLE
)
&&
(
--
timeout
>
0
))
{
udelay
(
100
);
}
return
((
timeout
>
0
)
?
0
:
(
-
(
ETIMEDOUT
)));
}
/**
* Send the command and argument to the SDHOST
*
* This function will wait for the previous command finished. And then
* clear any error status of previous command. And then
* send out the command and args. The command will be turned on the ENABLE
* flag before sending out.
*/
static
void
send_command_raw
(
unsigned
int
cmd
,
unsigned
int
arg
)
{
unsigned
int
status
;
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
/* wait for previous command finish */
rpi3_sdhost_waitcommand
();
/* clean error status */
status
=
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
);
if
(
status
&
HC_HSTST_MASK_ERROR_ALL
)
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
status
);
/* recording the command */
rpi3_sdhost_params
.
current_cmd
=
cmd
&
HC_CMD_COMMAND_MASK
;
/* send the argument and command */
mmio_write_32
(
reg_base
+
HC_ARGUMENT
,
arg
);
mmio_write_32
(
reg_base
+
HC_COMMAND
,
cmd
|
HC_CMD_ENABLE
);
}
/**
* Send the command and argument to the SDHOST, decorated with control
* flags.
*
* This function will use send_command_raw to send the commands to SDHOST.
* But before sending it will decorate the command with control flags specific
* to SDHOST.
*/
static
void
send_command_decorated
(
unsigned
int
cmd
,
unsigned
int
arg
)
{
unsigned
int
cmd_flags
=
0
;
switch
(
cmd
&
HC_CMD_COMMAND_MASK
)
{
case
MMC_CMD
(
0
):
cmd_flags
|=
HC_CMD_RESPONSE_NONE
;
break
;
case
MMC_ACMD
(
51
):
cmd_flags
|=
HC_CMD_READ
;
break
;
case
MMC_CMD
(
8
):
case
MMC_CMD
(
11
):
case
MMC_CMD
(
17
):
case
MMC_CMD
(
18
):
cmd_flags
|=
HC_CMD_READ
;
break
;
case
MMC_CMD
(
20
):
case
MMC_CMD
(
24
):
case
MMC_CMD
(
25
):
cmd_flags
|=
HC_CMD_WRITE
;
break
;
case
MMC_CMD
(
12
):
cmd_flags
|=
HC_CMD_BUSY
;
break
;
default:
break
;
}
send_command_raw
(
cmd
|
cmd_flags
,
arg
);
}
/**
* drains the FIFO on DATA port
*
* This function drains any data left in the DATA port.
*/
static
void
rpi3_drain_fifo
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
volatile
int
timeout
=
100000
;
rpi3_sdhost_waitcommand
();
while
(
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
)
&
HC_HSTST_HAVEDATA
)
{
mmio_read_32
(
reg_base
+
HC_DATAPORT
);
udelay
(
100
);
}
while
(
1
)
{
uint32_t
edm
,
fsm
;
edm
=
mmio_read_32
(
reg_base
+
HC_DEBUG
);
fsm
=
edm
&
HC_DBG_FSM_MASK
;
if
((
fsm
==
HC_DBG_FSM_IDENTMODE
)
||
(
fsm
==
HC_DBG_FSM_DATAMODE
))
break
;
if
((
fsm
==
HC_DBG_FSM_READWAIT
)
||
(
fsm
==
HC_DBG_FSM_WRITESTART1
)
||
(
fsm
==
HC_DBG_FSM_READDATA
))
{
mmio_write_32
(
reg_base
+
HC_DEBUG
,
edm
|
HC_DBG_FORCE_DATA_MODE
);
break
;
}
if
(
--
timeout
<=
0
)
{
ERROR
(
"rpi3_sdhost: %s cannot recover stat
\n
"
,
__func__
);
return
;
}
}
}
/**
* Dump SDHOST registers
*/
static
void
rpi3_sdhost_print_regs
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
INFO
(
"rpi3_sdhost: HC_COMMAND: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_COMMAND
));
INFO
(
"rpi3_sdhost: HC_ARGUMENT: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_ARGUMENT
));
INFO
(
"rpi3_sdhost: HC_TIMEOUTCOUNTER: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_TIMEOUTCOUNTER
));
INFO
(
"rpi3_sdhost: HC_CLOCKDIVISOR: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_CLOCKDIVISOR
));
INFO
(
"rpi3_sdhost: HC_RESPONSE_0: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_RESPONSE_0
));
INFO
(
"rpi3_sdhost: HC_RESPONSE_1: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_RESPONSE_1
));
INFO
(
"rpi3_sdhost: HC_RESPONSE_2: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_RESPONSE_2
));
INFO
(
"rpi3_sdhost: HC_RESPONSE_3: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_RESPONSE_3
));
INFO
(
"rpi3_sdhost: HC_HOSTSTATUS: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
));
INFO
(
"rpi3_sdhost: HC_POWER: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_POWER
));
INFO
(
"rpi3_sdhost: HC_DEBUG: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_DEBUG
));
INFO
(
"rpi3_sdhost: HC_HOSTCONFIG: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_HOSTCONFIG
));
INFO
(
"rpi3_sdhost: HC_BLOCKSIZE: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_BLOCKSIZE
));
INFO
(
"rpi3_sdhost: HC_BLOCKCOUNT: 0x%08x
\n
"
,
mmio_read_32
(
reg_base
+
HC_BLOCKCOUNT
));
}
/**
* Reset SDHOST
*/
static
void
rpi3_sdhost_reset
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
unsigned
int
dbg
;
uint32_t
tmp1
;
mmio_write_32
(
reg_base
+
HC_POWER
,
0
);
mmio_write_32
(
reg_base
+
HC_COMMAND
,
0
);
mmio_write_32
(
reg_base
+
HC_ARGUMENT
,
0
);
mmio_write_32
(
reg_base
+
HC_TIMEOUTCOUNTER
,
HC_TIMEOUT_DEFAULT
);
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
0
);
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
HC_HSTST_RESET
);
mmio_write_32
(
reg_base
+
HC_HOSTCONFIG
,
0
);
mmio_write_32
(
reg_base
+
HC_BLOCKSIZE
,
0
);
mmio_write_32
(
reg_base
+
HC_BLOCKCOUNT
,
0
);
dbg
=
mmio_read_32
(
reg_base
+
HC_DEBUG
);
dbg
&=
~
((
HC_DBG_FIFO_THRESH_MASK
<<
HC_DBG_FIFO_THRESH_READ_SHIFT
)
|
(
HC_DBG_FIFO_THRESH_MASK
<<
HC_DBG_FIFO_THRESH_WRITE_SHIFT
));
dbg
|=
(
HC_FIFO_THRESH_READ
<<
HC_DBG_FIFO_THRESH_READ_SHIFT
)
|
(
HC_FIFO_THRESH_WRITE
<<
HC_DBG_FIFO_THRESH_WRITE_SHIFT
);
mmio_write_32
(
reg_base
+
HC_DEBUG
,
dbg
);
mdelay
(
250
);
mmio_write_32
(
reg_base
+
HC_POWER
,
1
);
mdelay
(
250
);
rpi3_sdhost_params
.
clk_rate
=
0
;
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
HC_CLOCKDIVISOR_MAXVAL
);
tmp1
=
mmio_read_32
(
reg_base
+
HC_HOSTCONFIG
);
mmio_write_32
(
reg_base
+
HC_HOSTCONFIG
,
tmp1
|
HC_HSTCF_INT_BUSY
);
}
static
void
rpi3_sdhost_initialize
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
assert
((
rpi3_sdhost_params
.
reg_base
&
MMC_BLOCK_MASK
)
==
0
);
rpi3_sdhost_reset
();
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
HC_CLOCKDIVISOR_PREFERVAL
);
udelay
(
300
);
}
static
int
rpi3_sdhost_send_cmd
(
struct
mmc_cmd
*
cmd
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
int
err
=
0
;
uint32_t
cmd_idx
;
uint32_t
cmd_arg
;
uint32_t
cmd_flags
=
0
;
uint32_t
intmask
;
/* Wait for the command done */
err
=
rpi3_sdhost_waitcommand
();
if
(
err
!=
0
)
{
WARN
(
"previous command not done yet
\n
"
);
return
err
;
}
cmd_idx
=
cmd
->
cmd_idx
&
HC_CMD_COMMAND_MASK
;
if
(
cmd_idx
==
MMC_CMD
(
17
))
cmd_idx
=
MMC_CMD
(
18
);
cmd_arg
=
cmd
->
cmd_arg
;
if
(
cmd_idx
==
MMC_ACMD
(
51
))
{
/* if previous cmd send to SDHOST is not MMC_CMD(55).
* It means this MMC_ACMD(51) is a resend.
* And we must also resend MMC_CMD(55) in this case
*/
if
(
rpi3_sdhost_params
.
current_cmd
!=
MMC_CMD
(
55
))
{
send_command_decorated
(
MMC_CMD
(
55
),
rpi3_sdhost_params
.
sdcard_rca
<<
RCA_SHIFT_OFFSET
);
rpi3_sdhost_params
.
mmc_app_cmd
=
1
;
rpi3_sdhost_waitcommand
();
/* Also we need to call prepare to clean the buffer */
rpi3_sdhost_prepare
(
0
,
(
uintptr_t
)
NULL
,
8
);
}
}
/* We ignore MMC_CMD(12) sending from the TF-A's MMC driver
* because we send MMC_CMD(12) by ourselves.
*/
if
(
cmd_idx
==
MMC_CMD
(
12
))
return
0
;
if
((
cmd
->
resp_type
&
MMC_RSP_136
)
&&
(
cmd
->
resp_type
&
MMC_RSP_BUSY
))
{
ERROR
(
"rpi3_sdhost: unsupported response type!
\n
"
);
return
-
(
EOPNOTSUPP
);
}
if
(
cmd
->
resp_type
&
MMC_RSP_48
&&
cmd
->
resp_type
!=
MMC_RESPONSE_R2
)
{
/* 48-bit command
* We don't need to set any flags here because it is default.
*/
}
else
if
(
cmd
->
resp_type
&
MMC_RSP_136
)
{
/* 136-bit command */
cmd_flags
|=
HC_CMD_RESPONSE_LONG
;
}
else
{
/* no respond command */
cmd_flags
|=
HC_CMD_RESPONSE_NONE
;
}
rpi3_sdhost_params
.
cmdbusy
=
0
;
if
(
cmd
->
resp_type
&
MMC_RSP_BUSY
)
{
cmd_flags
|=
HC_CMD_BUSY
;
rpi3_sdhost_params
.
cmdbusy
=
1
;
}
if
(
rpi3_sdhost_params
.
mmc_app_cmd
)
{
switch
(
cmd_idx
)
{
case
MMC_ACMD
(
41
):
if
(
cmd_arg
==
OCR_HCS
)
cmd_arg
|=
OCR_3_3_3_4
;
break
;
default:
break
;
}
rpi3_sdhost_params
.
mmc_app_cmd
=
0
;
}
if
(
cmd_idx
==
MMC_CMD
(
55
))
rpi3_sdhost_params
.
mmc_app_cmd
=
1
;
send_command_decorated
(
cmd_idx
|
cmd_flags
,
cmd_arg
);
intmask
=
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
);
if
(
rpi3_sdhost_params
.
cmdbusy
&&
(
intmask
&
HC_HSTST_INT_BUSY
))
{
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
HC_HSTST_INT_BUSY
);
rpi3_sdhost_params
.
cmdbusy
=
0
;
}
if
(
!
(
cmd_flags
&
HC_CMD_RESPONSE_NONE
))
{
err
=
rpi3_sdhost_waitcommand
();
if
(
err
!=
0
)
ERROR
(
"rpi3_sdhost: cmd cannot be finished
\n
"
);
}
cmd
->
resp_data
[
0
]
=
mmio_read_32
(
reg_base
+
HC_RESPONSE_0
);
cmd
->
resp_data
[
1
]
=
mmio_read_32
(
reg_base
+
HC_RESPONSE_1
);
cmd
->
resp_data
[
2
]
=
mmio_read_32
(
reg_base
+
HC_RESPONSE_2
);
cmd
->
resp_data
[
3
]
=
mmio_read_32
(
reg_base
+
HC_RESPONSE_3
);
if
(
mmio_read_32
(
reg_base
+
HC_COMMAND
)
&
HC_CMD_FAILED
)
{
uint32_t
sdhsts
=
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
);
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
HC_HSTST_MASK_ERROR_ALL
);
if
(
!
(
sdhsts
&
HC_HSTST_ERROR_CRC7
)
||
(
cmd_idx
!=
MMC_ACMD
(
51
)))
{
if
(
sdhsts
&
HC_HSTST_TIMEOUT_CMD
)
{
ERROR
(
"rpi3_sdhost: timeout status 0x%x
\n
"
,
sdhsts
);
err
=
-
(
ETIMEDOUT
);
}
else
{
ERROR
(
"rpi3_sdhost: unknown err, cmd = 0x%x
\n
"
,
mmio_read_32
(
reg_base
+
HC_COMMAND
));
ERROR
(
"rpi3_sdhost status: 0x%x
\n
"
,
sdhsts
);
err
=
-
(
EILSEQ
);
}
}
}
if
((
!
err
)
&&
(
cmd_idx
==
MMC_CMD
(
3
)))
{
/* we keep the RCA in case to send MMC_CMD(55) ourselves */
rpi3_sdhost_params
.
sdcard_rca
=
(
cmd
->
resp_data
[
0
]
&
0xFFFF0000U
)
>>
16
;
}
return
err
;
}
static
int
rpi3_sdhost_set_clock
(
unsigned
int
clk
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
uint32_t
max_clk
=
250000000
;
uint32_t
div
;
if
(
clk
<
100000
)
{
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
HC_CLOCKDIVISOR_MAXVAL
);
return
0
;
}
div
=
max_clk
/
clk
;
if
(
div
<
2
)
div
=
2
;
if
((
max_clk
/
div
)
>
clk
)
div
++
;
div
-=
2
;
if
(
div
>
HC_CLOCKDIVISOR_MAXVAL
)
div
=
HC_CLOCKDIVISOR_MAXVAL
;
rpi3_sdhost_params
.
clk_rate
=
max_clk
/
(
div
+
2
);
rpi3_sdhost_params
.
ns_per_fifo_word
=
(
1000000000
/
rpi3_sdhost_params
.
clk_rate
)
*
8
;
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
div
);
return
0
;
}
static
int
rpi3_sdhost_set_ios
(
unsigned
int
clk
,
unsigned
int
width
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
uint32_t
tmp1
;
rpi3_sdhost_set_clock
(
clk
);
VERBOSE
(
"rpi3_sdhost: Changing clock to %dHz for data mode
\n
"
,
clk
);
if
(
width
!=
MMC_BUS_WIDTH_4
&&
width
!=
MMC_BUS_WIDTH_1
)
{
ERROR
(
"rpi3_sdhost: width %d not supported
\n
"
,
width
);
return
-
(
EOPNOTSUPP
);
}
rpi3_sdhost_params
.
bus_width
=
width
;
tmp1
=
mmio_read_32
(
reg_base
+
HC_HOSTCONFIG
);
tmp1
&=
~
(
HC_HSTCF_EXTBUS_4BIT
);
if
(
rpi3_sdhost_params
.
bus_width
==
MMC_BUS_WIDTH_4
)
tmp1
|=
HC_HSTCF_EXTBUS_4BIT
;
mmio_write_32
(
reg_base
+
HC_HOSTCONFIG
,
tmp1
);
tmp1
=
mmio_read_32
(
reg_base
+
HC_HOSTCONFIG
);
mmio_write_32
(
reg_base
+
HC_HOSTCONFIG
,
tmp1
|
HC_HSTCF_SLOW_CARD
|
HC_HSTCF_INTBUS_WIDE
);
return
0
;
}
static
int
rpi3_sdhost_prepare
(
int
lba
,
uintptr_t
buf
,
size_t
size
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
size_t
blocks
;
size_t
blocksize
;
if
(
size
<
512
)
{
blocksize
=
size
;
blocks
=
1
;
}
else
{
blocksize
=
512
;
blocks
=
size
/
blocksize
;
if
(
size
%
blocksize
!=
0
)
blocks
++
;
}
rpi3_drain_fifo
();
mmio_write_32
(
reg_base
+
HC_BLOCKSIZE
,
blocksize
);
mmio_write_32
(
reg_base
+
HC_BLOCKCOUNT
,
blocks
);
udelay
(
100
);
return
0
;
}
static
int
rpi3_sdhost_read
(
int
lba
,
uintptr_t
buf
,
size_t
size
)
{
int
err
=
0
;
uint32_t
*
buf1
=
((
uint32_t
*
)
buf
);
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
int
timeout
=
100000
;
int
remaining_words
=
0
;
for
(
int
i
=
0
;
i
<
size
/
4
;
i
++
)
{
volatile
int
t
=
timeout
;
uint32_t
hsts_err
;
while
((
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
)
&
HC_HSTST_HAVEDATA
)
==
0
)
{
if
(
t
==
0
)
{
ERROR
(
"rpi3_sdhost: fifo timeout after %dus
\n
"
,
timeout
);
err
=
-
(
ETIMEDOUT
);
break
;
}
t
--
;
udelay
(
10
);
}
if
(
t
==
0
)
break
;
uint32_t
data
=
mmio_read_32
(
reg_base
+
HC_DATAPORT
);
hsts_err
=
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
)
&
HC_HSTST_MASK_ERROR_ALL
;
if
(
hsts_err
)
{
ERROR
(
"rpi3_sdhost: transfer FIFO word %d: 0x%x
\n
"
,
i
,
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
));
rpi3_sdhost_print_regs
();
err
=
-
(
EILSEQ
);
/* clean the error status */
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
hsts_err
);
}
if
(
buf1
)
buf1
[
i
]
=
data
;
/* speeding up if the remaining words are still a lot */
remaining_words
=
(
mmio_read_32
(
reg_base
+
HC_DEBUG
)
>>
4
)
&
HC_DBG_FIFO_THRESH_MASK
;
if
(
remaining_words
>=
7
)
continue
;
/* delay. slowing down the read process */
udelay
(
100
);
}
/* We decide to stop by ourselves.
* It is because MMC_CMD(18) -> MMC_CMD(13) -> MMC_CMD(12)
* doesn't work for RPi3 SDHost.
*/
if
(
rpi3_sdhost_params
.
current_cmd
==
MMC_CMD
(
18
))
send_command_decorated
(
MMC_CMD
(
12
),
0
);
if
(
err
==
-
(
EILSEQ
))
{
const
int
max_retries
=
20
;
int
r
;
rpi3_sdhost_params
.
crc_err_retries
++
;
if
(
rpi3_sdhost_params
.
crc_err_retries
<
max_retries
)
{
/* retries if there's an CRC error */
r
=
rpi3_sdhost_prepare
(
lba
,
buf
,
size
);
send_command_decorated
(
MMC_CMD
(
18
),
lba
);
r
=
rpi3_sdhost_read
(
lba
,
buf
,
size
);
if
(
r
==
0
)
err
=
0
;
}
}
return
err
;
}
static
int
rpi3_sdhost_write
(
int
lba
,
uintptr_t
buf
,
size_t
size
)
{
uint32_t
*
buf1
=
((
uint32_t
*
)
buf
);
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
int
err
=
0
;
int
remaining_words
=
0
;
for
(
int
i
=
0
;
i
<
size
/
4
;
i
++
)
{
uint32_t
hsts_err
;
uint32_t
data
=
buf1
[
i
];
uint32_t
dbg
;
uint32_t
fsm_state
;
mmio_write_32
(
reg_base
+
HC_DATAPORT
,
data
);
dbg
=
mmio_read_32
(
reg_base
+
HC_DEBUG
);
fsm_state
=
dbg
&
HC_DBG_FSM_MASK
;
if
(
fsm_state
!=
HC_DBG_FSM_WRITEDATA
&&
fsm_state
!=
HC_DBG_FSM_WRITESTART1
&&
fsm_state
!=
HC_DBG_FSM_WRITESTART2
&&
fsm_state
!=
HC_DBG_FSM_WRITECRC
&&
fsm_state
!=
HC_DBG_FSM_WRITEWAIT1
&&
fsm_state
!=
HC_DBG_FSM_WRITEWAIT2
)
{
hsts_err
=
mmio_read_32
(
reg_base
+
HC_HOSTSTATUS
)
&
HC_HSTST_MASK_ERROR_ALL
;
if
(
hsts_err
)
err
=
-
(
EILSEQ
);
}
/* speeding up if the remaining words are not many */
remaining_words
=
(
mmio_read_32
(
reg_base
+
HC_DEBUG
)
>>
4
)
&
HC_DBG_FIFO_THRESH_MASK
;
if
(
remaining_words
<=
4
)
continue
;
udelay
(
100
);
}
/* We decide to stop by ourselves.
* It is because MMC_CMD(25) -> MMC_CMD(13) -> MMC_CMD(12)
* doesn't work for RPi3 SDHost.
*/
if
(
rpi3_sdhost_params
.
current_cmd
==
MMC_CMD
(
25
))
send_command_decorated
(
MMC_CMD
(
12
),
0
);
return
err
;
}
void
rpi3_sdhost_init
(
struct
rpi3_sdhost_params
*
params
,
struct
mmc_device_info
*
mmc_dev_info
)
{
assert
((
params
!=
0
)
&&
((
params
->
reg_base
&
MMC_BLOCK_MASK
)
==
0
));
memcpy
(
&
rpi3_sdhost_params
,
params
,
sizeof
(
struct
rpi3_sdhost_params
));
/* backup GPIO 48 to 53 configurations */
for
(
int
i
=
48
;
i
<=
53
;
i
++
)
{
rpi3_sdhost_params
.
gpio48_pinselect
[
i
-
48
]
=
rpi3_gpio_get_select
(
i
);
VERBOSE
(
"rpi3_sdhost: Original GPIO state %d: %d
\n
"
,
i
,
rpi3_sdhost_params
.
gpio48_pinselect
[
i
-
48
]);
}
/* setting pull resistors for 48 to 53.
* GPIO 48 (SD_CLK) to GPIO_PULL_UP
* GPIO 49 (SD_CMD) to GPIO_PULL_NONE
* GPIO 50 (SD_D0) to GPIO_PULL_NONE
* GPIO 51 (SD_D1) to GPIO_PULL_NONE
* GPIO 52 (SD_D2) to GPIO_PULL_NONE
* GPIO 53 (SD_D3) to GPIO_PULL_NONE
*/
gpio_set_pull
(
48
,
GPIO_PULL_UP
);
for
(
int
i
=
49
;
i
<=
53
;
i
++
)
gpio_set_pull
(
i
,
GPIO_PULL_NONE
);
/* Set pin 48-53 to alt-0. It means route SDHOST to card slot */
for
(
int
i
=
48
;
i
<=
53
;
i
++
)
rpi3_gpio_set_select
(
i
,
RPI3_GPIO_FUNC_ALT0
);
mmc_init
(
&
rpi3_sdhost_ops
,
params
->
clk_rate
,
params
->
bus_width
,
params
->
flags
,
mmc_dev_info
);
}
void
rpi3_sdhost_stop
(
void
)
{
uintptr_t
reg_base
=
rpi3_sdhost_params
.
reg_base
;
VERBOSE
(
"rpi3_sdhost: Shutting down: drain FIFO out
\n
"
);
rpi3_drain_fifo
();
VERBOSE
(
"rpi3_sdhost: Shutting down: slowing down the clock
\n
"
);
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
HC_CLOCKDIVISOR_SLOWVAL
);
udelay
(
500
);
VERBOSE
(
"rpi3_sdhost: Shutting down: put SDHost into idle state
\n
"
);
send_command_decorated
(
MMC_CMD
(
0
),
0
);
udelay
(
500
);
mmio_write_32
(
reg_base
+
HC_COMMAND
,
0
);
mmio_write_32
(
reg_base
+
HC_ARGUMENT
,
0
);
mmio_write_32
(
reg_base
+
HC_TIMEOUTCOUNTER
,
HC_TIMEOUT_IDLE
);
mmio_write_32
(
reg_base
+
HC_CLOCKDIVISOR
,
HC_CLOCKDIVISOR_STOPVAL
);
udelay
(
100
);
mmio_write_32
(
reg_base
+
HC_POWER
,
0
);
mmio_write_32
(
reg_base
+
HC_HOSTCONFIG
,
0
);
mmio_write_32
(
reg_base
+
HC_BLOCKSIZE
,
0x400
);
mmio_write_32
(
reg_base
+
HC_BLOCKCOUNT
,
0
);
mmio_write_32
(
reg_base
+
HC_HOSTSTATUS
,
0x7f8
);
mmio_write_32
(
reg_base
+
HC_COMMAND
,
0
);
mmio_write_32
(
reg_base
+
HC_ARGUMENT
,
0
);
udelay
(
100
);
/* Restore the pinmux to original state */
for
(
int
i
=
48
;
i
<=
53
;
i
++
)
{
rpi3_gpio_set_select
(
i
,
rpi3_sdhost_params
.
gpio48_pinselect
[
i
-
48
]);
}
/* Must reset the pull resistors for u-boot to work.
* GPIO 48 (SD_CLK) to GPIO_PULL_NONE
* GPIO 49 (SD_CMD) to GPIO_PULL_UP
* GPIO 50 (SD_D0) to GPIO_PULL_UP
* GPIO 51 (SD_D1) to GPIO_PULL_UP
* GPIO 52 (SD_D2) to GPIO_PULL_UP
* GPIO 53 (SD_D3) to GPIO_PULL_UP
*/
gpio_set_pull
(
48
,
GPIO_PULL_NONE
);
for
(
int
i
=
49
;
i
<=
53
;
i
++
)
gpio_set_pull
(
i
,
GPIO_PULL_UP
);
}
This diff is collapsed.
Click to expand it.
include/drivers/rpi3/sdhost/rpi3_sdhost.h
0 → 100644
View file @
5735057d
/*
* Copyright (c) 2019, Linaro Limited
* Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RPI3_SDHOST_H
#define RPI3_SDHOST_H
#include <drivers/mmc.h>
#include <stdint.h>
#include <platform_def.h>
struct
rpi3_sdhost_params
{
uintptr_t
reg_base
;
uint32_t
clk_rate
;
uint32_t
bus_width
;
uint32_t
flags
;
uint32_t
current_cmd
;
uint8_t
cmdbusy
;
uint8_t
mmc_app_cmd
;
uint32_t
ns_per_fifo_word
;
uint32_t
crc_err_retries
;
uint32_t
sdcard_rca
;
uint32_t
gpio48_pinselect
[
6
];
};
void
rpi3_sdhost_init
(
struct
rpi3_sdhost_params
*
params
,
struct
mmc_device_info
*
mmc_dev_info
);
void
rpi3_sdhost_stop
(
void
);
/* Registers */
#define HC_COMMAND 0x00
/* Command and flags */
#define HC_ARGUMENT 0x04
#define HC_TIMEOUTCOUNTER 0x08
#define HC_CLOCKDIVISOR 0x0c
#define HC_RESPONSE_0 0x10
#define HC_RESPONSE_1 0x14
#define HC_RESPONSE_2 0x18
#define HC_RESPONSE_3 0x1c
#define HC_HOSTSTATUS 0x20
#define HC_POWER 0x30
#define HC_DEBUG 0x34
#define HC_HOSTCONFIG 0x38
#define HC_BLOCKSIZE 0x3c
#define HC_DATAPORT 0x40
#define HC_BLOCKCOUNT 0x50
/* Flags for HC_COMMAND register */
#define HC_CMD_ENABLE 0x8000
#define HC_CMD_FAILED 0x4000
#define HC_CMD_BUSY 0x0800
#define HC_CMD_RESPONSE_NONE 0x0400
#define HC_CMD_RESPONSE_LONG 0x0200
#define HC_CMD_WRITE 0x0080
#define HC_CMD_READ 0x0040
#define HC_CMD_COMMAND_MASK 0x003f
#define HC_CLOCKDIVISOR_MAXVAL 0x07ff
#define HC_CLOCKDIVISOR_PREFERVAL 0x027b
#define HC_CLOCKDIVISOR_SLOWVAL 0x0148
#define HC_CLOCKDIVISOR_STOPVAL 0x01fb
/* Flags for HC_HOSTSTATUS register */
#define HC_HSTST_HAVEDATA 0x0001
#define HC_HSTST_ERROR_FIFO 0x0008
#define HC_HSTST_ERROR_CRC7 0x0010
#define HC_HSTST_ERROR_CRC16 0x0020
#define HC_HSTST_TIMEOUT_CMD 0x0040
#define HC_HSTST_TIMEOUT_DATA 0x0080
#define HC_HSTST_INT_BLOCK 0x0200
#define HC_HSTST_INT_BUSY 0x0400
#define HC_HSTST_RESET 0xffff
#define HC_HSTST_MASK_ERROR_DATA (HC_HSTST_ERROR_FIFO | \
HC_HSTST_ERROR_CRC7 | \
HC_HSTST_ERROR_CRC16 | \
HC_HSTST_TIMEOUT_DATA)
#define HC_HSTST_MASK_ERROR_ALL (HC_HSTST_MASK_ERROR_DATA | \
HC_HSTST_TIMEOUT_CMD)
/* Flags for HC_HOSTCONFIG register */
#define HC_HSTCF_INTBUS_WIDE 0x0002
#define HC_HSTCF_EXTBUS_4BIT 0x0004
#define HC_HSTCF_SLOW_CARD 0x0008
#define HC_HSTCF_INT_DATA 0x0010
#define HC_HSTCF_INT_BLOCK 0x0100
#define HC_HSTCF_INT_BUSY 0x0400
/* Flags for HC_DEBUG register */
#define HC_DBG_FIFO_THRESH_WRITE_SHIFT 9
#define HC_DBG_FIFO_THRESH_READ_SHIFT 14
#define HC_DBG_FIFO_THRESH_MASK 0x001f
#define HC_DBG_FSM_MASK 0xf
#define HC_DBG_FSM_IDENTMODE 0x0
#define HC_DBG_FSM_DATAMODE 0x1
#define HC_DBG_FSM_READDATA 0x2
#define HC_DBG_FSM_WRITEDATA 0x3
#define HC_DBG_FSM_READWAIT 0x4
#define HC_DBG_FSM_READCRC 0x5
#define HC_DBG_FSM_WRITECRC 0x6
#define HC_DBG_FSM_WRITEWAIT1 0x7
#define HC_DBG_FSM_POWERDOWN 0x8
#define HC_DBG_FSM_POWERUP 0x9
#define HC_DBG_FSM_WRITESTART1 0xa
#define HC_DBG_FSM_WRITESTART2 0xb
#define HC_DBG_FSM_GENPULSES 0xc
#define HC_DBG_FSM_WRITEWAIT2 0xd
#define HC_DBG_FSM_STARTPOWDOWN 0xf
#define HC_DBG_FORCE_DATA_MODE 0x40000
/* Settings */
#define HC_FIFO_SIZE 16
#define HC_FIFO_THRESH_READ 4
#define HC_FIFO_THRESH_WRITE 4
#define HC_TIMEOUT_DEFAULT 0x00f00000
#define HC_TIMEOUT_IDLE 0x00a00000
#endif
/* RPI3_SDHOST_H */
This diff is collapsed.
Click to expand it.
maintainers.rst
View file @
5735057d
...
...
@@ -169,8 +169,12 @@ Raspberry Pi 3 platform port
----------------------------
:M: Antonio Niño Díaz <antonio.ninodiaz@arm.com>
:G: `antonio-nino-diaz-arm`_
:M: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
:G: `grandpaul`_
:F: docs/plat/rpi3.rst
:F: plat/rpi3/
:F: drivers/rpi3/
:F: include/drivers/rpi3/
Renesas rcar-gen3 platform port
-------------------------------
...
...
This diff is collapsed.
Click to expand it.
plat/rpi3/include/platform_def.h
View file @
5735057d
...
...
@@ -244,6 +244,8 @@
#define MAX_IO_DEVICES U(3)
#define MAX_IO_HANDLES U(4)
#define MAX_IO_BLOCK_DEVICES U(1)
/*
* Serial-related constants.
*/
...
...
This diff is collapsed.
Click to expand it.
plat/rpi3/platform.mk
View file @
5735057d
...
...
@@ -31,6 +31,9 @@ BL2_SOURCES += common/desc_image_load.c \
drivers/delay_timer/delay_timer.c
\
drivers/delay_timer/generic_delay_timer.c
\
drivers/rpi3/gpio/rpi3_gpio.c
\
drivers/io/io_block.c
\
drivers/mmc/mmc.c
\
drivers/rpi3/sdhost/rpi3_sdhost.c
\
plat/common/aarch64/platform_mp_stack.S
\
plat/rpi3/aarch64/plat_helpers.S
\
plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
\
...
...
This diff is collapsed.
Click to expand it.
plat/rpi3/rpi3_bl2_setup.c
View file @
5735057d
...
...
@@ -17,6 +17,7 @@
#include <lib/xlat_tables/xlat_tables_defs.h>
#include <drivers/generic_delay_timer.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
#include "rpi3_private.h"
...
...
@@ -34,6 +35,21 @@ static void rpi3_gpio_setup(void)
rpi3_gpio_init
(
&
params
);
}
/* Data structure which holds the MMC info */
static
struct
mmc_device_info
mmc_info
;
static
void
rpi3_sdhost_setup
(
void
)
{
struct
rpi3_sdhost_params
params
;
memset
(
&
params
,
0
,
sizeof
(
struct
rpi3_sdhost_params
));
params
.
reg_base
=
RPI3_SDHOST_BASE
;
params
.
bus_width
=
MMC_BUS_WIDTH_4
;
params
.
clk_rate
=
392464
;
mmc_info
.
mmc_dev_type
=
MMC_IS_SD_HC
;
rpi3_sdhost_init
(
&
params
,
&
mmc_info
);
}
/*******************************************************************************
* BL1 has passed the extents of the trusted SRAM that should be visible to BL2
* in x0. This memory layout is sitting at the base of the free trusted SRAM.
...
...
@@ -57,6 +73,9 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* Setup the BL2 memory layout */
bl2_tzram_layout
=
*
mem_layout
;
/* Setup SDHost driver */
rpi3_sdhost_setup
();
plat_rpi3_io_setup
();
}
...
...
@@ -122,6 +141,9 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
/* BL33 expects to receive the primary CPU MPID (through r0) */
bl_mem_params
->
ep_info
.
args
.
arg0
=
0xffff
&
read_mpidr
();
bl_mem_params
->
ep_info
.
spsr
=
rpi3_get_spsr_for_bl33_entry
();
/* Shutting down the SDHost driver to let BL33 drives SDHost.*/
rpi3_sdhost_stop
();
break
;
default:
...
...
This diff is collapsed.
Click to expand it.
plat/rpi3/rpi3_hw.h
View file @
5735057d
...
...
@@ -89,6 +89,12 @@
#define RPI3_IO_GPIO_OFFSET ULL(0x00200000)
#define RPI3_GPIO_BASE (RPI3_IO_BASE + RPI3_IO_GPIO_OFFSET)
/*
* SDHost controller
*/
#define RPI3_IO_SDHOST_OFFSET ULL(0x00202000)
#define RPI3_SDHOST_BASE (RPI3_IO_BASE + RPI3_IO_SDHOST_OFFSET)
/*
* Local interrupt controller
*/
...
...
This diff is collapsed.
Click to expand it.
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
Menu
Projects
Groups
Snippets
Help