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
a59085b5
Commit
a59085b5
authored
4 years ago
by
Manish Pandey
Committed by
TrustedFirmware Code Review
4 years ago
Browse files
Options
Download
Plain Diff
Merge "drivers: renesas: rcar: eMMC driver code clean up" into integration
parents
fde125cb
a492527b
master
v2.5
v2.5-rc1
v2.5-rc0
arm_cca_v0.2
arm_cca_v0.1
No related merge requests found
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
drivers/renesas/rcar/emmc/emmc_cmd.c
+19
-18
drivers/renesas/rcar/emmc/emmc_cmd.c
drivers/renesas/rcar/emmc/emmc_config.h
+9
-29
drivers/renesas/rcar/emmc/emmc_config.h
drivers/renesas/rcar/emmc/emmc_hal.h
+413
-196
drivers/renesas/rcar/emmc/emmc_hal.h
drivers/renesas/rcar/emmc/emmc_init.c
+16
-19
drivers/renesas/rcar/emmc/emmc_init.c
drivers/renesas/rcar/emmc/emmc_interrupt.c
+4
-4
drivers/renesas/rcar/emmc/emmc_interrupt.c
drivers/renesas/rcar/emmc/emmc_mount.c
+45
-40
drivers/renesas/rcar/emmc/emmc_mount.c
drivers/renesas/rcar/emmc/emmc_read.c
+8
-7
drivers/renesas/rcar/emmc/emmc_read.c
drivers/renesas/rcar/emmc/emmc_registers.h
+126
-158
drivers/renesas/rcar/emmc/emmc_registers.h
drivers/renesas/rcar/emmc/emmc_std.h
+353
-352
drivers/renesas/rcar/emmc/emmc_std.h
drivers/renesas/rcar/emmc/emmc_utility.c
+6
-6
drivers/renesas/rcar/emmc/emmc_utility.c
with
999 additions
and
829 deletions
+999
-829
drivers/renesas/rcar/emmc/emmc_cmd.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
17
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -7,10 +7,10 @@
#include <common/debug.h>
#include "emmc_config.h"
#include "emmc_def.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_
def
.h"
#include "emmc_
std
.h"
#include "micro_delay.h"
static
void
emmc_little_to_big
(
uint8_t
*
p
,
uint32_t
value
)
...
...
@@ -22,6 +22,7 @@ static void emmc_little_to_big(uint8_t *p, uint32_t value)
p
[
1
]
=
(
uint8_t
)
(
value
>>
16
);
p
[
2
]
=
(
uint8_t
)
(
value
>>
8
);
p
[
3
]
=
(
uint8_t
)
value
;
}
static
void
emmc_softreset
(
void
)
...
...
@@ -64,7 +65,6 @@ reset:
SETR_32
(
SD_INFO2
,
SD_INFO2_CLEAR
);
SETR_32
(
SD_INFO1_MASK
,
0x00000000U
);
/* all interrupt disable */
SETR_32
(
SD_INFO2_MASK
,
SD_INFO2_CLEAR
);
/* all interrupt disable */
}
static
void
emmc_read_response
(
uint32_t
*
response
)
...
...
@@ -96,8 +96,7 @@ static EMMC_ERROR_CODE emmc_response_check(uint32_t *response,
{
HAL_MEMCARD_RESPONSE_TYPE
response_type
=
(
HAL_MEMCARD_RESPONSE_TYPE
)
(
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_RESPONSE_TYPE_MASK
);
((
HAL_MEMCARD_RESPONSE_TYPE
)
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_RESPONSE_TYPE_MASK
);
if
(
response
==
NULL
)
return
EMMC_ERR_PARAM
;
...
...
@@ -117,7 +116,7 @@ static EMMC_ERROR_CODE emmc_response_check(uint32_t *response,
}
return
EMMC_ERR_CARD_STATUS_BIT
;
}
return
EMMC_SUCCESS
;
;
return
EMMC_SUCCESS
;
}
if
(
response_type
==
HAL_MEMCARD_RESPONSE_R4
)
{
...
...
@@ -223,11 +222,11 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
state
=
ESTATE_BEGIN
;
response_type
=
(
HAL_MEMCARD_RESPONSE_TYPE
)
(
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_RESPONSE_TYPE_MASK
);
(
(
HAL_MEMCARD_RESPONSE_TYPE
)
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_RESPONSE_TYPE_MASK
);
cmd_type
=
(
HAL_MEMCARD_COMMAND_TYPE
)
(
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_COMMAND_TYPE_MASK
);
(
(
HAL_MEMCARD_COMMAND_TYPE
)
mmc_drv_obj
.
cmd_info
.
cmd
&
HAL_MEMCARD_COMMAND_TYPE_MASK
);
/* state machine */
while
((
mmc_drv_obj
.
force_terminate
!=
TRUE
)
&&
(
state
!=
ESTATE_END
))
{
...
...
@@ -427,8 +426,9 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
case
ESTATE_ACCESS_END
:
/* clear flag */
if
(
HAL_MEMCARD_DMA
==
mmc_drv_obj
.
transfer_mode
)
{
SETR_32
(
CC_EXT_MODE
,
CC_EXT_MODE_CLEAR
);
/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
if
(
mmc_drv_obj
.
transfer_mode
==
HAL_MEMCARD_DMA
)
{
/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
SETR_32
(
CC_EXT_MODE
,
CC_EXT_MODE_CLEAR
);
SETR_32
(
SD_STOP
,
0x00000000U
);
mmc_drv_obj
.
during_dma_transfer
=
FALSE
;
}
...
...
@@ -448,8 +448,9 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
case
ESTATE_TRANSFER_ERROR
:
/* The error occurred in the Data transfer. */
if
(
HAL_MEMCARD_DMA
==
mmc_drv_obj
.
transfer_mode
)
{
SETR_32
(
CC_EXT_MODE
,
CC_EXT_MODE_CLEAR
);
/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
if
(
mmc_drv_obj
.
transfer_mode
==
HAL_MEMCARD_DMA
)
{
/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
SETR_32
(
CC_EXT_MODE
,
CC_EXT_MODE_CLEAR
);
SETR_32
(
SD_STOP
,
0x00000000U
);
mmc_drv_obj
.
during_dma_transfer
=
FALSE
;
}
...
...
@@ -468,8 +469,8 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
default:
state
=
ESTATE_END
;
break
;
}
/* switch (state) */
}
/*
while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */
}
/* switch (state) */
}
/* while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */
/* force terminate */
if
(
mmc_drv_obj
.
force_terminate
==
TRUE
)
{
...
...
@@ -481,7 +482,7 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
ERROR
(
"BL2: emmc exec_cmd:EMMC_ERR_FORCE_TERMINATE
\n
"
);
emmc_softreset
();
return
EMMC_ERR_FORCE_TERMINATE
;
/* error information has already been written. */
return
EMMC_ERR_FORCE_TERMINATE
;
/* error information has already been written. */
}
/* success */
...
...
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_config.h
View file @
a59085b5
/*
* Copyright (c) 2015-20
17
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file emmc_config.h
* @brief Configuration file
*
*/
#ifndef EMMC_CONFIG_H
#define EMMC_CONFIG_H
/* ************************ HEADER (INCLUDE) SECTION *********************** */
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/** @brief MMC driver config
*/
#define EMMC_RCA 1UL
/* RCA */
#define EMMC_RW_DATA_TIMEOUT 0x40UL
/* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17) */
#define EMMC_RETRY_COUNT 0
/* how many times to try after fail. Don't change. */
#define EMMC_CMD_MAX 60UL
/* Don't change. */
/** @brief etc
*/
#define LOADIMAGE_FLAGS_DMA_ENABLE 0x00000001UL
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
/* RCA */
#define EMMC_RCA 1UL
/* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17) */
#define EMMC_RW_DATA_TIMEOUT 0x40UL
/* how many times to try after fail. Don't change. */
#define EMMC_RETRY_COUNT 0
#define EMMC_CMD_MAX 60UL
/* Don't change. */
/* ********************************* CODE ********************************** */
#define LOADIMAGE_FLAGS_DMA_ENABLE 0x00000001UL
#endif
/* EMMC_CONFIG_H */
/* ******************************** END ************************************ */
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_hal.h
View file @
a59085b5
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_init.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
18
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -32,12 +32,12 @@ EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode)
return
EMMC_SUCCESS
;
}
static
__
inline
void
emmc_set_retry_count
(
uint32_t
retry
)
static
inline
void
emmc_set_retry_count
(
uint32_t
retry
)
{
mmc_drv_obj
.
retries_after_fail
=
retry
;
}
static
__
inline
void
emmc_set_data_timeout
(
uint32_t
data_timeout
)
static
inline
void
emmc_set_data_timeout
(
uint32_t
data_timeout
)
{
mmc_drv_obj
.
data_timeout
=
data_timeout
;
}
...
...
@@ -73,7 +73,8 @@ static EMMC_ERROR_CODE emmc_dev_finalize(void)
EMMC_ERROR_CODE
result
;
uint32_t
dataL
;
/* MMC power off
/*
* MMC power off
* the power supply of eMMC device is always turning on.
* RST_n : Hi --> Low level.
*/
...
...
@@ -115,27 +116,25 @@ static EMMC_ERROR_CODE emmc_dev_init(void)
SETR_32
(
HOST_MODE
,
0x00000000U
);
/* SD_BUF access width = 64-bit */
SETR_32
(
SD_OPTION
,
0x0000C0EEU
);
/* Bus width = 1bit, timeout=MAX */
SETR_32
(
SD_CLK_CTRL
,
0x00000000U
);
/* Automatic Control
=Disable,
Clock Output
=Disable
*/
SETR_32
(
SD_CLK_CTRL
,
0x00000000U
);
/*
Disable
Automatic Control
&
Clock Output */
return
EMMC_SUCCESS
;
}
static
EMMC_ERROR_CODE
emmc_reset_controller
(
void
)
{
EMMC_ERROR_CODE
re
t
ult
;
EMMC_ERROR_CODE
re
s
ult
;
/* initialize mmc driver */
emmc_drv_init
();
/* initialize H/W */
re
t
ult
=
emmc_dev_init
();
if
(
EMMC_SUCCESS
!=
retult
)
{
return
retult
;
re
s
ult
=
emmc_dev_init
();
if
(
result
==
EMMC_SUCCESS
)
{
mmc_drv_obj
.
initialize
=
TRUE
;
}
mmc_drv_obj
.
initialize
=
TRUE
;
return
retult
;
return
result
;
}
...
...
@@ -152,14 +151,12 @@ EMMC_ERROR_CODE emmc_terminate(void)
EMMC_ERROR_CODE
rcar_emmc_init
(
void
)
{
EMMC_ERROR_CODE
re
t
ult
;
EMMC_ERROR_CODE
re
s
ult
;
re
t
ult
=
emmc_reset_controller
();
if
(
EMMC_SUCCESS
!=
retult
)
{
return
retult
;
re
s
ult
=
emmc_reset_controller
();
if
(
result
==
EMMC_SUCCESS
)
{
emmc_driver_config
()
;
}
emmc_driver_config
();
return
EMMC_SUCCESS
;
return
result
;
}
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_interrupt.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
19
, Renesas Electronics Corporation. All rights
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights
* reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
...
...
@@ -118,7 +118,7 @@ uint32_t emmc_interrupt(void)
SETR_32
(
DM_CM_INFO2
,
0x00000000U
);
/* interrupt clear */
SETR_32
(
SD_INFO2
,
(
GETR_32
(
SD_INFO2
)
&
~
SD_INFO2_BWE
));
/* DM_CM_INFO2: DMA-ch0 error occured */
/* DM_CM_INFO2: DMA-ch0 error occur
r
ed */
if
((
BIT16
&
mmc_drv_obj
.
dm_event2
)
!=
0
)
{
mmc_drv_obj
.
dma_error_flag
=
TRUE
;
}
else
{
...
...
@@ -128,13 +128,13 @@ uint32_t emmc_interrupt(void)
/* wait next interrupt */
mmc_drv_obj
.
state_machine_blocking
=
FALSE
;
}
/* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */
/* DM_CM_INFO1: DMA-ch1 transfer complete or error occur
r
ed */
else
if
((
end_bit
&
mmc_drv_obj
.
dm_event1
)
!=
0U
)
{
SETR_32
(
DM_CM_INFO1
,
0x00000000U
);
SETR_32
(
DM_CM_INFO2
,
0x00000000U
);
/* interrupt clear */
SETR_32
(
SD_INFO2
,
(
GETR_32
(
SD_INFO2
)
&
~
SD_INFO2_BRE
));
/* DM_CM_INFO2: DMA-ch1 error occured */
/* DM_CM_INFO2: DMA-ch1 error occur
r
ed */
if
((
BIT17
&
mmc_drv_obj
.
dm_event2
)
!=
0
)
{
mmc_drv_obj
.
dma_error_flag
=
TRUE
;
}
else
{
...
...
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_mount.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
19
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -8,10 +8,10 @@
#include <lib/mmio.h>
#include "emmc_config.h"
#include "emmc_def.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_
def
.h"
#include "emmc_
std
.h"
#include "micro_delay.h"
#include "rcar_def.h"
...
...
@@ -53,7 +53,7 @@ static EMMC_ERROR_CODE emmc_card_init(void)
int32_t
retry
;
uint32_t
freq
=
MMC_400KHZ
;
/* 390KHz */
EMMC_ERROR_CODE
result
;
uint32_t
result
C
alc
;
uint32_t
result
_c
alc
;
/* state check */
if
((
mmc_drv_obj
.
initialize
!=
TRUE
)
...
...
@@ -161,9 +161,12 @@ static EMMC_ERROR_CODE emmc_card_init(void)
mmc_drv_obj
.
selected
=
TRUE
;
/* card speed check */
resultCalc
=
emmc_calc_tran_speed
(
&
freq
);
/* Card spec is calculated from TRAN_SPEED(CSD). */
if
(
resultCalc
==
0
)
{
/*
* card speed check
* Card spec is calculated from TRAN_SPEED(CSD)
*/
result_calc
=
emmc_calc_tran_speed
(
&
freq
);
if
(
result_calc
==
0
)
{
emmc_write_error_info
(
EMMC_FUNCNO_CARD_INIT
,
EMMC_ERR_ILLEGAL_CARD
);
return
EMMC_ERR_ILLEGAL_CARD
;
...
...
@@ -201,7 +204,8 @@ static EMMC_ERROR_CODE emmc_card_init(void)
HAL_MEMCARD_NOT_DMA
);
result
=
emmc_exec_cmd
(
EMMC_R1_ERROR_MASK
,
mmc_drv_obj
.
response
);
if
(
result
!=
EMMC_SUCCESS
)
{
/* CMD12 is not send.
/*
* CMD12 is not send.
* If BUS initialization is failed, user must be execute Bus initialization again.
* Bus initialization is start CMD0(soft reset command).
*/
...
...
@@ -217,7 +221,7 @@ static EMMC_ERROR_CODE emmc_card_init(void)
static
EMMC_ERROR_CODE
emmc_high_speed
(
void
)
{
uint32_t
freq
;
/*
*<
High speed mode clock frequency */
uint32_t
freq
;
/* High speed mode clock frequency */
EMMC_ERROR_CODE
result
;
uint8_t
cardType
;
...
...
@@ -236,8 +240,8 @@ static EMMC_ERROR_CODE emmc_high_speed(void)
else
freq
=
MMC_20MHZ
;
/* Hi-Speed-mode selction */
if
((
MMC_52MHZ
==
freq
)
||
(
MMC_26MHZ
==
freq
))
{
/* Hi-Speed-mode sel
e
ction */
if
((
freq
==
MMC_52MHZ
)
||
(
freq
==
MMC_26MHZ
))
{
/* CMD6 */
emmc_make_nontrans_cmd
(
CMD6_SWITCH
,
EMMC_SWITCH_HS_TIMING
);
result
=
...
...
@@ -322,7 +326,8 @@ static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
return
EMMC_ERR_STATE
;
}
mmc_drv_obj
.
bus_width
=
(
HAL_MEMCARD_DATA_WIDTH
)
(
width
>>
2
);
/* 2 = 8bit, 1 = 4bit, 0 =1bit */
/* 2 = 8bit, 1 = 4bit, 0 =1bit */
mmc_drv_obj
.
bus_width
=
(
HAL_MEMCARD_DATA_WIDTH
)
(
width
>>
2
);
/* CMD6 */
emmc_make_nontrans_cmd
(
CMD6_SWITCH
,
...
...
@@ -371,7 +376,6 @@ static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
return
EMMC_SUCCESS
;
EXIT:
emmc_write_error_info
(
EMMC_FUNCNO_BUS_WIDTH
,
result
);
ERROR
(
"BL2: emmc bus_width error end
\n
"
);
return
result
;
...
...
@@ -489,82 +493,83 @@ static void emmc_get_partition_access(void)
static
uint32_t
emmc_calc_tran_speed
(
uint32_t
*
freq
)
{
const
uint32_t
unit
[
8
]
=
{
10000
,
100000
,
1000000
,
10000000
,
0
,
0
,
0
,
0
};
/**< frequency unit (1/10) */
const
uint32_t
mult
[
16
]
=
{
0
,
10
,
12
,
13
,
15
,
20
,
26
,
30
,
35
,
40
,
45
,
52
,
55
,
60
,
70
,
80
};
uint32_t
maxFreq
;
uint32_t
result
;
const
uint32_t
unit
[
8
]
=
{
10000U
,
100000U
,
1000000U
,
10000000U
,
0U
,
0U
,
0U
,
0U
};
/* frequency unit (1/10) */
const
uint32_t
mult
[
16
]
=
{
0U
,
10U
,
12U
,
13U
,
15U
,
20U
,
26U
,
30U
,
35U
,
40U
,
45U
,
52U
,
55U
,
60U
,
70U
,
80U
};
uint32_t
tran_speed
=
EMMC_CSD_TRAN_SPEED
();
uint32_t
max_freq
;
uint32_t
result
;
/* tran_speed = 0x32
/*
* tran_speed = 0x32
* unit[tran_speed&0x7] = uint[0x2] = 1000000
* mult[(tran_speed&0x78)>>3] = mult[0x30>>3] = mult[6] = 26
* 1000000 * 26 = 26000000 (26MHz)
*/
result
=
1
;
max
F
req
=
max
_f
req
=
unit
[
tran_speed
&
EMMC_TRANSPEED_FREQ_UNIT_MASK
]
*
mult
[(
tran_speed
&
EMMC_TRANSPEED_MULT_MASK
)
>>
EMMC_TRANSPEED_MULT_SHIFT
];
if
(
max
F
req
==
0
)
{
if
(
max
_f
req
==
0
)
{
result
=
0
;
}
else
if
(
MMC_FREQ_52MHZ
<=
maxFreq
)
}
else
if
(
max_freq
>=
MMC_FREQ_52MHZ
)
{
*
freq
=
MMC_52MHZ
;
else
if
(
MMC_FREQ_26MHZ
<=
maxFreq
)
}
else
if
(
max_freq
>=
MMC_FREQ_26MHZ
)
{
*
freq
=
MMC_26MHZ
;
else
if
(
MMC_FREQ_20MHZ
<=
maxFreq
)
}
else
if
(
max_freq
>=
MMC_FREQ_20MHZ
)
{
*
freq
=
MMC_20MHZ
;
else
}
else
{
*
freq
=
MMC_400KHZ
;
}
return
result
;
}
static
uint32_t
emmc_set_timeout_register_value
(
uint32_t
freq
)
{
uint32_t
timeout
C
nt
;
/* SD_OPTION - Timeout Counter */
uint32_t
timeout
_c
nt
;
/* SD_OPTION - Timeout Counter */
switch
(
freq
)
{
case
1U
:
timeout
C
nt
=
0xE0U
;
timeout
_c
nt
=
0xE0U
;
break
;
/* SDCLK * 2^27 */
case
2U
:
timeout
C
nt
=
0xE0U
;
timeout
_c
nt
=
0xE0U
;
break
;
/* SDCLK * 2^27 */
case
4U
:
timeout
C
nt
=
0xD0U
;
timeout
_c
nt
=
0xD0U
;
break
;
/* SDCLK * 2^26 */
case
8U
:
timeout
C
nt
=
0xC0U
;
timeout
_c
nt
=
0xC0U
;
break
;
/* SDCLK * 2^25 */
case
16U
:
timeout
C
nt
=
0xB0U
;
timeout
_c
nt
=
0xB0U
;
break
;
/* SDCLK * 2^24 */
case
32U
:
timeout
C
nt
=
0xA0U
;
timeout
_c
nt
=
0xA0U
;
break
;
/* SDCLK * 2^23 */
case
64U
:
timeout
C
nt
=
0x90U
;
timeout
_c
nt
=
0x90U
;
break
;
/* SDCLK * 2^22 */
case
128U
:
timeout
C
nt
=
0x80U
;
timeout
_c
nt
=
0x80U
;
break
;
/* SDCLK * 2^21 */
case
256U
:
timeout
C
nt
=
0x70U
;
timeout
_c
nt
=
0x70U
;
break
;
/* SDCLK * 2^20 */
case
512U
:
timeout
C
nt
=
0x70U
;
timeout
_c
nt
=
0x70U
;
break
;
/* SDCLK * 2^20 */
default:
timeout
C
nt
=
0xE0U
;
timeout
_c
nt
=
0xE0U
;
break
;
/* SDCLK * 2^27 */
}
return
timeout
C
nt
;
return
timeout
_c
nt
;
}
EMMC_ERROR_CODE
emmc_set_ext_csd
(
uint32_t
arg
)
...
...
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_read.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
17
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -7,15 +7,15 @@
#include <arch_helpers.h>
#include "emmc_config.h"
#include "emmc_def.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_
def
.h"
#include "emmc_
std
.h"
#define MIN_EMMC(a, b)
(((a) < (b)) ? (a) : (b))
#define EMMC_RW_SECTOR_COUNT_MAX
0x0000ffffU
#define MIN_EMMC(a, b)
(((a) < (b)) ? (a) : (b))
#define EMMC_RW_SECTOR_COUNT_MAX
0x0000ffffU
static
EMMC_ERROR_CODE
emmc_multiple_block_read
(
uint32_t
*
buff_address_virtual
,
static
EMMC_ERROR_CODE
emmc_multiple_block_read
(
uint32_t
*
buff_address_virtual
,
uint32_t
sector_number
,
uint32_t
count
,
HAL_MEMCARD_DATA_TRANSFER_MODE
transfer_mode
)
{
...
...
@@ -39,7 +39,8 @@ static EMMC_ERROR_CODE emmc_multiple_block_read (uint32_t *buff_address_virtual,
}
SETR_32
(
SD_SECCNT
,
count
);
SETR_32
(
SD_STOP
,
0x00000100
);
SETR_32
(
CC_EXT_MODE
,
(
CC_EXT_MODE_CLEAR
|
CC_EXT_MODE_DMASDRW_ENABLE
));
/* SD_BUF Read/Write DMA Transfer enable */
/* SD_BUF Read/Write DMA Transfer enable */
SETR_32
(
CC_EXT_MODE
,
(
CC_EXT_MODE_CLEAR
|
CC_EXT_MODE_DMASDRW_ENABLE
));
/* CMD18 */
emmc_make_trans_cmd
(
CMD18_READ_MULTIPLE_BLOCK
,
sector_number
,
...
...
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_registers.h
View file @
a59085b5
/*
* Copyright (c) 2015-20
18
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file emmc_registers.h
* @brief emmc boot driver is expecting this header file. HS-MMC module header file.
*
*/
#ifndef EMMC_REGISTERS_H
#define EMMC_REGISTERS_H
/* ************************ HEADER (INCLUDE) SECTION *********************** */
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* MMC channel select */
#define MMC_CH0 (0U)
/* SDHI2/MMC0 */
#define MMC_CH1 (1U)
/* SDHI3/MMC1 */
...
...
@@ -27,73 +17,71 @@
#define USE_MMC_CH (MMC_CH0)
/* R-Car H3/M3/M3N */
#endif
/* RCAR_LSI == RCAR_E3 */
#define
BIT0 (0x00000001U)
#define
BIT1 (0x00000002U)
#define
BIT2 (0x00000004U)
#define
BIT3 (0x00000008U)
#define
BIT4 (0x00000010U)
#define
BIT5 (0x00000020U)
#define
BIT6 (0x00000040U)
#define
BIT7 (0x00000080U)
#define
BIT8 (0x00000100U)
#define
BIT9 (0x00000200U)
#define
BIT10 (0x00000400U)
#define
BIT11 (0x00000800U)
#define
BIT12 (0x00001000U)
#define
BIT13 (0x00002000U)
#define
BIT14 (0x00004000U)
#define
BIT15 (0x00008000U)
#define
BIT16 (0x00010000U)
#define
BIT17 (0x00020000U)
#define
BIT18 (0x00040000U)
#define
BIT19 (0x00080000U)
#define
BIT20 (0x00100000U)
#define
BIT21 (0x00200000U)
#define
BIT22 (0x00400000U)
#define
BIT23 (0x00800000U)
#define
BIT24 (0x01000000U)
#define
BIT25 (0x02000000U)
#define
BIT26 (0x04000000U)
#define
BIT27 (0x08000000U)
#define
BIT28 (0x10000000U)
#define
BIT29 (0x20000000U)
#define
BIT30 (0x40000000U)
#define
BIT31 (0x80000000U)
/*
* @brief
Clock Pulse Generator (CPG) registers
*/
#define CPG_BASE (0xE6150000U)
#define CPG_MSTPSR3 (CPG_BASE+0x0048U)
/* M
odule stop
status
register 3 */
#define CPG_SMSTPCR3 (CPG_BASE+0x013CU)
/* System module stop
control register
3
*/
#define CPG_SD2CKCR (CPG_BASE+0x0268U)
/* SDHI
2
clock frequency control register */
#define CPG_SD3CKCR
(CPG_BASE
+
0x026CU)
/* SDHI3 clock frequency control register */
#define
CPG_CPGWPR
(CPG_BASE
+
0x0900U)
/* CPG Write Protect Register */
#define
BIT0 (0x00000001U)
#define
BIT1 (0x00000002U)
#define
BIT2 (0x00000004U)
#define
BIT3 (0x00000008U)
#define
BIT4 (0x00000010U)
#define
BIT5 (0x00000020U)
#define
BIT6 (0x00000040U)
#define
BIT7 (0x00000080U)
#define
BIT8 (0x00000100U)
#define
BIT9 (0x00000200U)
#define
BIT10 (0x00000400U)
#define
BIT11 (0x00000800U)
#define
BIT12 (0x00001000U)
#define
BIT13 (0x00002000U)
#define
BIT14 (0x00004000U)
#define
BIT15 (0x00008000U)
#define
BIT16 (0x00010000U)
#define
BIT17 (0x00020000U)
#define
BIT18 (0x00040000U)
#define
BIT19 (0x00080000U)
#define
BIT20 (0x00100000U)
#define
BIT21 (0x00200000U)
#define
BIT22 (0x00400000U)
#define
BIT23 (0x00800000U)
#define
BIT24 (0x01000000U)
#define
BIT25 (0x02000000U)
#define
BIT26 (0x04000000U)
#define
BIT27 (0x08000000U)
#define
BIT28 (0x10000000U)
#define
BIT29 (0x20000000U)
#define
BIT30 (0x40000000U)
#define
BIT31 (0x80000000U)
/* Clock Pulse Generator (CPG) registers
*/
#define CPG_BASE (0xE6150000U)
/* Module stop status register 3 */
#define CPG_MSTPSR3 (CPG_BASE + 0x0048U)
/* System m
odule stop
control
register 3 */
#define CPG_SMSTPCR3 (CPG_BASE + 0x013CU)
/* SDHI2 clock frequency
control register */
#define CPG_SD2CKCR (CPG_BASE + 0x0268U)
/* SDHI
3
clock frequency control register */
#define CPG_SD3CKCR (CPG_BASE
+
0x026CU)
/* CPG Write Protect Register */
#define
CPG_CPGWPR (CPG_BASE
+
0x0900U)
#if USE_MMC_CH == MMC_CH0
#define
CPG_SDxCKCR (CPG_SD2CKCR)
/* SDHI2/MMC0 */
#define
CPG_SDxCKCR (CPG_SD2CKCR)
/* SDHI2/MMC0 */
#else
/* USE_MMC_CH == MMC_CH0 */
#define
CPG_SDxCKCR (CPG_SD3CKCR)
/* SDHI3/MMC1 */
#define
CPG_SDxCKCR (CPG_SD3CKCR)
/* SDHI3/MMC1 */
#endif
/* USE_MMC_CH == MMC_CH0 */
/** Boot Status register
*/
/* Boot Status register */
#define MFISBTSTSR (0xE6260604U)
#define MFISBTSTSR_BOOT_PARTITION (0x00000010U)
/** brief eMMC registers
*/
#define MMC0_SD_BASE (0xEE140000U)
/* eMMC registers */
#define MMC0_SD_BASE (0xEE140000U)
#define MMC1_SD_BASE (0xEE160000U)
#if USE_MMC_CH == MMC_CH0
#define
MMC_SD_BASE (MMC0_SD_BASE)
#define
MMC_SD_BASE (MMC0_SD_BASE)
#else
/* USE_MMC_CH == MMC_CH0 */
#define
MMC_SD_BASE (MMC1_SD_BASE)
#define
MMC_SD_BASE (MMC1_SD_BASE)
#endif
/* USE_MMC_CH == MMC_CH0 */
#define SD_CMD (MMC_SD_BASE + 0x0000U)
...
...
@@ -136,125 +124,105 @@
#define DM_CM_INFO2_MASK (MMC_SD_BASE + 0x0858U)
#define DM_DTRAN_ADDR (MMC_SD_BASE + 0x0880U)
/** @brief SD_INFO1 Registers
*/
#define SD_INFO1_HPIRES 0x00010000UL
/* Response Reception Completion */
#define SD_INFO1_INFO10 0x00000400UL
/* Indicates the SDDAT3 state */
#define SD_INFO1_INFO9 0x00000200UL
/* SDDAT3 Card Insertion */
#define SD_INFO1_INFO8 0x00000100UL
/* SDDAT3 Card Removal */
#define SD_INFO1_INFO7 0x00000080UL
/* Write Protect */
#define SD_INFO1_INFO5 0x00000020UL
/* Indicates the ISDCD state */
#define SD_INFO1_INFO4 0x00000010UL
/* ISDCD Card Insertion */
#define SD_INFO1_INFO3 0x00000008UL
/* ISDCD Card Removal */
#define SD_INFO1_INFO2 0x00000004UL
/* Access end */
#define SD_INFO1_INFO0 0x00000001UL
/* Response end */
/** @brief SD_INFO2 Registers
*/
#define SD_INFO2_ILA 0x00008000UL
/* Illegal Access Error */
#define SD_INFO2_CBSY 0x00004000UL
/* Command Type Register Busy */
#define SD_INFO2_SCLKDIVEN 0x00002000UL
#define SD_INFO2_BWE 0x00000200UL
/* SD_BUF Write Enable */
#define SD_INFO2_BRE 0x00000100UL
/* SD_BUF Read Enable */
#define SD_INFO2_DAT0 0x00000080UL
/* SDDAT0 */
#define SD_INFO2_ERR6 0x00000040UL
/* Response Timeout */
#define SD_INFO2_ERR5 0x00000020UL
/* SD_BUF Illegal Read Access */
#define SD_INFO2_ERR4 0x00000010UL
/* SD_BUF Illegal Write Access */
#define SD_INFO2_ERR3 0x00000008UL
/* Data Timeout */
#define SD_INFO2_ERR2 0x00000004UL
/* END Error */
#define SD_INFO2_ERR1 0x00000002UL
/* CRC Error */
#define SD_INFO2_ERR0 0x00000001UL
/* CMD Error */
#define SD_INFO2_ALL_ERR 0x0000807FUL
#define SD_INFO2_CLEAR 0x00000800UL
/* BIT11 The write value should always be 1. HWM_0003 */
/** @brief SOFT_RST
*/
#define SOFT_RST_SDRST 0x00000001UL
/** @brief SD_CLK_CTRL
*/
/* SD_INFO1 Registers */
#define SD_INFO1_HPIRES 0x00010000UL
/* Response Reception Completion */
#define SD_INFO1_INFO10 0x00000400UL
/* Indicates the SDDAT3 state */
#define SD_INFO1_INFO9 0x00000200UL
/* SDDAT3 Card Insertion */
#define SD_INFO1_INFO8 0x00000100UL
/* SDDAT3 Card Removal */
#define SD_INFO1_INFO7 0x00000080UL
/* Write Protect */
#define SD_INFO1_INFO5 0x00000020UL
/* Indicates the ISDCD state */
#define SD_INFO1_INFO4 0x00000010UL
/* ISDCD Card Insertion */
#define SD_INFO1_INFO3 0x00000008UL
/* ISDCD Card Removal */
#define SD_INFO1_INFO2 0x00000004UL
/* Access end */
#define SD_INFO1_INFO0 0x00000001UL
/* Response end */
/* SD_INFO2 Registers */
#define SD_INFO2_ILA 0x00008000UL
/* Illegal Access Error */
#define SD_INFO2_CBSY 0x00004000UL
/* Command Type Register Busy */
#define SD_INFO2_SCLKDIVEN 0x00002000UL
#define SD_INFO2_BWE 0x00000200UL
/* SD_BUF Write Enable */
#define SD_INFO2_BRE 0x00000100UL
/* SD_BUF Read Enable */
#define SD_INFO2_DAT0 0x00000080UL
/* SDDAT0 */
#define SD_INFO2_ERR6 0x00000040UL
/* Response Timeout */
#define SD_INFO2_ERR5 0x00000020UL
/* SD_BUF Illegal Read Access */
#define SD_INFO2_ERR4 0x00000010UL
/* SD_BUF Illegal Write Access */
#define SD_INFO2_ERR3 0x00000008UL
/* Data Timeout */
#define SD_INFO2_ERR2 0x00000004UL
/* END Error */
#define SD_INFO2_ERR1 0x00000002UL
/* CRC Error */
#define SD_INFO2_ERR0 0x00000001UL
/* CMD Error */
#define SD_INFO2_ALL_ERR 0x0000807FUL
#define SD_INFO2_CLEAR 0x00000800UL
/* BIT11 write value should always be 1. HWM_0003 */
/* SOFT_RST */
#define SOFT_RST_SDRST 0x00000001UL
/* SD_CLK_CTRL */
#define SD_CLK_CTRL_SDCLKOFFEN 0x00000200UL
#define SD_CLK_CTRL_SCLKEN 0x00000100UL
#define SD_CLK_CTRL_CLKDIV_MASK 0x000000FFUL
#define SD_CLOCK_ENABLE 0x00000100UL
#define SD_CLOCK_DISABLE 0x00000000UL
#define SD_CLK_WRITE_MASK 0x000003FFUL
#define SD_CLK_CLKDIV_CLEAR_MASK 0xFFFFFF0FUL
/** @brief SD_OPTION
*/
#define SD_CLK_CTRL_SCLKEN 0x00000100UL
#define SD_CLK_CTRL_CLKDIV_MASK 0x000000FFUL
#define SD_CLOCK_ENABLE 0x00000100UL
#define SD_CLOCK_DISABLE 0x00000000UL
#define SD_CLK_WRITE_MASK 0x000003FFUL
#define SD_CLK_CLKDIV_CLEAR_MASK 0xFFFFFF0FUL
/* SD_OPTION */
#define SD_OPTION_TIMEOUT_CNT_MASK 0x000000F0UL
/** @brief MMC Clock Frequency
/*
* MMC Clock Frequency
* 200MHz * 1/x = output clock
*/
#define MMC_CLK_OFF
0UL
/* Clock output is disabled
*/
#define MMC_400KHZ
512UL
/* 200MHz * 1/512 = 390 KHz
*/
#define MMC_20MHZ
16UL
/* 200MHz * 1/16
= 12.5 MHz Normal speed mode
*/
#define MMC_26MHZ
8UL
/* 200MHz * 1/8
= 25 MHz H
igh speed
mode 26Mhz
*/
#define MMC_52MHZ
4UL
/* 200MHz * 1/4
= 50 MHz H
igh speed
mode 52Mhz
*/
#define MMC_100MHZ
2UL
/* 200MHz * 1/2
= 100 MHz
*/
#define MMC_200MHZ
1UL
/* 200MHz * 1/1
= 200 MHz
*/
#define MMC_CLK_OFF 0UL
/* Clock output is disabled */
#define MMC_400KHZ 512UL
/* 200MHz * 1/512 = 390 KHz */
#define MMC_20MHZ 16UL
/* 200MHz * 1/16 = 12.5 MHz Normal speed mode */
#define MMC_26MHZ 8UL
/* 200MHz * 1/8 = 25 MHz H
S
mode 26Mhz */
#define MMC_52MHZ 4UL
/* 200MHz * 1/4 = 50 MHz H
S
mode 52Mhz */
#define MMC_100MHZ 2UL
/* 200MHz * 1/2 = 100 MHz */
#define MMC_200MHZ 1UL
/* 200MHz * 1/1 = 200 MHz */
#define MMC_FREQ_52MHZ 52000000UL
#define MMC_FREQ_26MHZ 26000000UL
#define MMC_FREQ_20MHZ 20000000UL
/** @brief MMC Clock DIV
*/
#define MMC_SD_CLK_START 0x00000100UL
/* CLOCK On */
#define MMC_SD_CLK_STOP (~0x00000100UL)
/* CLOCK stop */
#define MMC_SD_CLK_DIV1 0x000000FFUL
/* 1/1 */
#define MMC_SD_CLK_DIV2 0x00000000UL
/* 1/2 */
#define MMC_SD_CLK_DIV4 0x00000001UL
/* 1/4 */
#define MMC_SD_CLK_DIV8 0x00000002UL
/* 1/8 */
#define MMC_SD_CLK_DIV16 0x00000004UL
/* 1/16 */
#define MMC_SD_CLK_DIV32 0x00000008UL
/* 1/32 */
#define MMC_SD_CLK_DIV64 0x00000010UL
/* 1/64 */
#define MMC_SD_CLK_DIV128 0x00000020UL
/* 1/128 */
#define MMC_SD_CLK_DIV256 0x00000040UL
/* 1/256 */
#define MMC_SD_CLK_DIV512 0x00000080UL
/* 1/512 */
/** @brief DM_CM_DTRAN_MODE
*/
#define DM_CM_DTRAN_MODE_CH0 0x00000000UL
/* CH0(downstream) */
#define DM_CM_DTRAN_MODE_CH1 0x00010000UL
/* CH1(upstream) */
/* MMC Clock DIV */
#define MMC_SD_CLK_START 0x00000100UL
/* CLOCK On */
#define MMC_SD_CLK_STOP (~0x00000100UL)
/* CLOCK stop */
#define MMC_SD_CLK_DIV1 0x000000FFUL
/* 1/1 */
#define MMC_SD_CLK_DIV2 0x00000000UL
/* 1/2 */
#define MMC_SD_CLK_DIV4 0x00000001UL
/* 1/4 */
#define MMC_SD_CLK_DIV8 0x00000002UL
/* 1/8 */
#define MMC_SD_CLK_DIV16 0x00000004UL
/* 1/16 */
#define MMC_SD_CLK_DIV32 0x00000008UL
/* 1/32 */
#define MMC_SD_CLK_DIV64 0x00000010UL
/* 1/64 */
#define MMC_SD_CLK_DIV128 0x00000020UL
/* 1/128 */
#define MMC_SD_CLK_DIV256 0x00000040UL
/* 1/256 */
#define MMC_SD_CLK_DIV512 0x00000080UL
/* 1/512 */
/* DM_CM_DTRAN_MODE */
#define DM_CM_DTRAN_MODE_CH0 0x00000000UL
/* CH0(downstream) */
#define DM_CM_DTRAN_MODE_CH1 0x00010000UL
/* CH1(upstream) */
#define DM_CM_DTRAN_MODE_BIT_WIDTH 0x00000030UL
/** @brief CC_EXT_MODE
*/
/* CC_EXT_MODE */
#define CC_EXT_MODE_DMASDRW_ENABLE 0x00000002UL
/* SD_BUF Read/Write DMA Transfer */
#define CC_EXT_MODE_CLEAR
0x00001010UL
/* BIT 12 & 4 always 1. */
#define CC_EXT_MODE_CLEAR 0x00001010UL
/* BIT 12 & 4 always 1. */
/** @brief DM_CM_INFO_MASK
*/
/* DM_CM_INFO_MASK */
#define DM_CM_INFO_MASK_CLEAR 0xFFFCFFFEUL
#define DM_CM_INFO_CH0_ENABLE 0x00010001UL
#define DM_CM_INFO_CH1_ENABLE 0x00020001UL
/** @brief DM_DTRAN_ADDR
*/
/* DM_DTRAN_ADDR */
#define DM_DTRAN_ADDR_WRITE_MASK 0xFFFFFFF8UL
/** @brief DM_CM_DTRAN_CTRL
*/
/* DM_CM_DTRAN_CTRL */
#define DM_CM_DTRAN_CTRL_START 0x00000001UL
/** @brief SYSC Registers
*/
/* SYSC Registers */
#if USE_MMC_CH == MMC_CH0
#define CPG_MSTP_MMC (BIT12)
/* SDHI2/MMC0 */
#else
/* USE_MMC_CH == MMC_CH0 */
#define CPG_MSTP_MMC (BIT11)
/* SDHI3/MMC1 */
#endif
/* USE_MMC_CH == MMC_CH0 */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
/* ********************************* CODE ********************************** */
#endif
/* EMMC_REGISTERS_H */
/* ******************************** END ************************************ */
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_std.h
View file @
a59085b5
This diff is collapsed.
Click to expand it.
drivers/renesas/rcar/emmc/emmc_utility.c
View file @
a59085b5
/*
* Copyright (c) 2015-20
17
, Renesas Electronics Corporation. All rights reserved.
* Copyright (c) 2015-20
20
, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -7,10 +7,10 @@
#include <common/debug.h>
#include "emmc_config.h"
#include "emmc_def.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_
def
.h"
#include "emmc_
std
.h"
static
const
uint32_t
cmd_reg_hw
[
EMMC_CMD_MAX
+
1
]
=
{
0x00000000
,
/* CMD0 */
...
...
@@ -97,8 +97,8 @@ uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom)
value
=
(
uint32_t
)
((
data
[
index_top
]
<<
24
)
|
(
data
[
index_top
+
1
]
<<
16
)
|
(
data
[
index_top
+
2
]
<<
8
)
|
data
[
index_top
+
3
]);
(
data
[
index_top
+
2
]
<<
8
)
|
data
[
index_top
+
3
]);
}
value
=
((
value
>>
(
bottom
&
0x07
))
&
((
1
<<
(
top
-
bottom
+
1
))
-
1
));
...
...
@@ -150,7 +150,7 @@ void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg)
mmc_drv_obj
.
response
=
&
mmc_drv_obj
.
r1_card_status
;
break
;
case
HAL_MEMCARD_RESPONSE_R1b
:
mmc_drv_obj
.
cmd_info
.
hw
|=
BIT10
;
/* bit10 = R1 busy bit */
mmc_drv_obj
.
cmd_info
.
hw
|=
BIT10
;
/* bit10 = R1 busy bit */
mmc_drv_obj
.
response
=
&
mmc_drv_obj
.
r1_card_status
;
break
;
case
HAL_MEMCARD_RESPONSE_R2
:
...
...
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