2 * Copyright 2008, Freescale Semiconductor, Inc
5 * Based vaguely on the Linux code
7 * SPDX-License-Identifier: GPL-2.0+
13 #include "mmc_private.h"
15 static ulong
mmc_erase_t(struct mmc
*mmc
, ulong start
, lbaint_t blkcnt
)
19 int err
, start_cmd
, end_cmd
;
21 if (mmc
->high_capacity
) {
22 end
= start
+ blkcnt
- 1;
24 end
= (start
+ blkcnt
- 1) * mmc
->write_bl_len
;
25 start
*= mmc
->write_bl_len
;
29 start_cmd
= SD_CMD_ERASE_WR_BLK_START
;
30 end_cmd
= SD_CMD_ERASE_WR_BLK_END
;
32 start_cmd
= MMC_CMD_ERASE_GROUP_START
;
33 end_cmd
= MMC_CMD_ERASE_GROUP_END
;
36 cmd
.cmdidx
= start_cmd
;
38 cmd
.resp_type
= MMC_RSP_R1
;
40 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
47 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
51 cmd
.cmdidx
= MMC_CMD_ERASE
;
52 cmd
.cmdarg
= SECURE_ERASE
;
53 cmd
.resp_type
= MMC_RSP_R1b
;
55 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
62 puts("mmc erase failed\n");
66 unsigned long mmc_berase(int dev_num
, lbaint_t start
, lbaint_t blkcnt
)
69 struct mmc
*mmc
= find_mmc_device(dev_num
);
70 lbaint_t blk
= 0, blk_r
= 0;
76 if ((start
% mmc
->erase_grp_size
) || (blkcnt
% mmc
->erase_grp_size
))
77 printf("\n\nCaution! Your devices Erase group is 0x%x\n"
78 "The erase range would be change to "
79 "0x" LBAF
"~0x" LBAF
"\n\n",
80 mmc
->erase_grp_size
, start
& ~(mmc
->erase_grp_size
- 1),
81 ((start
+ blkcnt
+ mmc
->erase_grp_size
)
82 & ~(mmc
->erase_grp_size
- 1)) - 1);
84 while (blk
< blkcnt
) {
85 blk_r
= ((blkcnt
- blk
) > mmc
->erase_grp_size
) ?
86 mmc
->erase_grp_size
: (blkcnt
- blk
);
87 err
= mmc_erase_t(mmc
, start
+ blk
, blk_r
);
93 /* Waiting for the ready status */
94 if (mmc_send_status(mmc
, timeout
))
101 static ulong
mmc_write_blocks(struct mmc
*mmc
, lbaint_t start
,
102 lbaint_t blkcnt
, const void *src
)
105 struct mmc_data data
;
108 if ((start
+ blkcnt
) > mmc
->block_dev
.lba
) {
109 printf("MMC: block number 0x" LBAF
" exceeds max(0x" LBAF
")\n",
110 start
+ blkcnt
, mmc
->block_dev
.lba
);
116 else if (blkcnt
== 1)
117 cmd
.cmdidx
= MMC_CMD_WRITE_SINGLE_BLOCK
;
119 cmd
.cmdidx
= MMC_CMD_WRITE_MULTIPLE_BLOCK
;
121 if (mmc
->high_capacity
)
124 cmd
.cmdarg
= start
* mmc
->write_bl_len
;
126 cmd
.resp_type
= MMC_RSP_R1
;
129 data
.blocks
= blkcnt
;
130 data
.blocksize
= mmc
->write_bl_len
;
131 data
.flags
= MMC_DATA_WRITE
;
133 if (mmc_send_cmd(mmc
, &cmd
, &data
)) {
134 printf("mmc write failed\n");
138 /* SPI multiblock writes terminate using a special
139 * token, not a STOP_TRANSMISSION request.
141 if (!mmc_host_is_spi(mmc
) && blkcnt
> 1) {
142 cmd
.cmdidx
= MMC_CMD_STOP_TRANSMISSION
;
144 cmd
.resp_type
= MMC_RSP_R1b
;
145 if (mmc_send_cmd(mmc
, &cmd
, NULL
)) {
146 printf("mmc fail to send stop cmd\n");
151 /* Waiting for the ready status */
152 if (mmc_send_status(mmc
, timeout
))
158 ulong
mmc_bwrite(int dev_num
, lbaint_t start
, lbaint_t blkcnt
, const void *src
)
160 lbaint_t cur
, blocks_todo
= blkcnt
;
162 struct mmc
*mmc
= find_mmc_device(dev_num
);
166 if (mmc_set_blocklen(mmc
, mmc
->write_bl_len
))
170 cur
= (blocks_todo
> mmc
->b_max
) ? mmc
->b_max
: blocks_todo
;
171 if (mmc_write_blocks(mmc
, start
, cur
, src
) != cur
)
175 src
+= cur
* mmc
->write_bl_len
;
176 } while (blocks_todo
> 0);