emmc_read.c 3.42 KB
Newer Older
Jorge Ramirez-Ortiz's avatar
Jorge Ramirez-Ortiz committed
1
2
3
4
5
/*
 * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
6

Jorge Ramirez-Ortiz's avatar
Jorge Ramirez-Ortiz committed
7
#include <arch_helpers.h>
8

Jorge Ramirez-Ortiz's avatar
Jorge Ramirez-Ortiz committed
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
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"

#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,
		uint32_t sector_number, uint32_t count,
		HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode)
{
	EMMC_ERROR_CODE result;

	/* parameter check */
	if ((count > EMMC_RW_SECTOR_COUNT_MAX)
	    || (count == 0)
	    || ((transfer_mode != HAL_MEMCARD_DMA)
		&& (transfer_mode != HAL_MEMCARD_NOT_DMA))
	    ) {
		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM);
		return EMMC_ERR_PARAM;
	}

	/* CMD23 */
	emmc_make_nontrans_cmd(CMD23_SET_BLOCK_COUNT, count);
	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
	if (result != EMMC_SUCCESS) {
		return result;
	}
	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 */

	/* CMD18 */
	emmc_make_trans_cmd(CMD18_READ_MULTIPLE_BLOCK, sector_number,
			    buff_address_virtual,
			    count << EMMC_SECTOR_SIZE_SHIFT, HAL_MEMCARD_READ,
			    transfer_mode);
	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
	if (result != EMMC_SUCCESS) {
		return result;	/* CMD18 error code */
	}

	/* CMD13 */
	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
	if (result != EMMC_SUCCESS) {
		return result;
	}
#if RCAR_BL2_DCACHE == 1
	if (transfer_mode == HAL_MEMCARD_NOT_DMA) {
		flush_dcache_range((uint64_t) buff_address_virtual,
				   ((size_t) count << EMMC_SECTOR_SIZE_SHIFT));
	}
#endif /* RCAR_BL2_DCACHE == 1 */

	/* ready status check */
	if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0) {
		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
				      EMMC_ERR_CARD_BUSY);
		return EMMC_ERR_CARD_BUSY;
	}

	/* state check */
	if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) {
		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
				      EMMC_ERR_CARD_STATE);
		return EMMC_ERR_CARD_STATE;
	}

	return EMMC_SUCCESS;
}

EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual,
				 uint32_t sector_number,
				 uint32_t count, uint32_t feature_flags)
{
	uint32_t trans_count;
	uint32_t remain;
	EMMC_ERROR_CODE result;
	HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;

	/* parameter check */
	if (count == 0) {
		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM);
		return EMMC_ERR_PARAM;
	}

	/* state check */
	if (mmc_drv_obj.mount != TRUE) {
		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_STATE);
		return EMMC_ERR_STATE;
	}

	/* DMA? */
	if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0) {
		transfer_mode = HAL_MEMCARD_DMA;
	} else {
		transfer_mode = HAL_MEMCARD_NOT_DMA;
	}

	remain = count;
	while (remain != 0) {
		trans_count = MIN_EMMC(remain, EMMC_RW_SECTOR_COUNT_MAX);
		result =
		    emmc_multiple_block_read(buff_address_virtual,
					     sector_number, trans_count,
					     transfer_mode);
		if (result != EMMC_SUCCESS) {
			return result;
		}

		buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count);
		sector_number += trans_count;
		remain -= trans_count;
	}

	return EMMC_SUCCESS;
}