2 * Copyright 2008, Freescale Semiconductor, Inc
5 * Based vaguely on the Linux code
7 * SPDX-License-Identifier: GPL-2.0+
14 #include <linux/math64.h>
15 #include "mmc_private.h"
17 static ulong
mmc_erase_t(struct mmc
*mmc
, ulong start
, lbaint_t blkcnt
)
21 int err
, start_cmd
, end_cmd
;
23 if (mmc
->high_capacity
) {
24 end
= start
+ blkcnt
- 1;
26 end
= (start
+ blkcnt
- 1) * mmc
->write_bl_len
;
27 start
*= mmc
->write_bl_len
;
31 start_cmd
= SD_CMD_ERASE_WR_BLK_START
;
32 end_cmd
= SD_CMD_ERASE_WR_BLK_END
;
34 start_cmd
= MMC_CMD_ERASE_GROUP_START
;
35 end_cmd
= MMC_CMD_ERASE_GROUP_END
;
38 cmd
.cmdidx
= start_cmd
;
40 cmd
.resp_type
= MMC_RSP_R1
;
42 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
49 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
53 cmd
.cmdidx
= MMC_CMD_ERASE
;
54 cmd
.cmdarg
= MMC_ERASE_ARG
;
55 cmd
.resp_type
= MMC_RSP_R1b
;
57 err
= mmc_send_cmd(mmc
, &cmd
, NULL
);
64 puts("mmc erase failed\n");
68 unsigned long mmc_berase(struct blk_desc
*block_dev
, lbaint_t start
,
71 int dev_num
= block_dev
->dev
;
73 u32 start_rem
, blkcnt_rem
;
74 struct mmc
*mmc
= find_mmc_device(dev_num
);
75 lbaint_t blk
= 0, blk_r
= 0;
81 err
= mmc_select_hwpart(dev_num
, block_dev
->hwpart
);
86 * We want to see if the requested start or total block count are
87 * unaligned. We discard the whole numbers and only care about the
90 err
= div_u64_rem(start
, mmc
->erase_grp_size
, &start_rem
);
91 err
= div_u64_rem(blkcnt
, mmc
->erase_grp_size
, &blkcnt_rem
);
92 if (start_rem
|| blkcnt_rem
)
93 printf("\n\nCaution! Your devices Erase group is 0x%x\n"
94 "The erase range would be change to "
95 "0x" LBAF
"~0x" LBAF
"\n\n",
96 mmc
->erase_grp_size
, start
& ~(mmc
->erase_grp_size
- 1),
97 ((start
+ blkcnt
+ mmc
->erase_grp_size
)
98 & ~(mmc
->erase_grp_size
- 1)) - 1);
100 while (blk
< blkcnt
) {
101 blk_r
= ((blkcnt
- blk
) > mmc
->erase_grp_size
) ?
102 mmc
->erase_grp_size
: (blkcnt
- blk
);
103 err
= mmc_erase_t(mmc
, start
+ blk
, blk_r
);
109 /* Waiting for the ready status */
110 if (mmc_send_status(mmc
, timeout
))
117 static ulong
mmc_write_blocks(struct mmc
*mmc
, lbaint_t start
,
118 lbaint_t blkcnt
, const void *src
)
121 struct mmc_data data
;
124 if ((start
+ blkcnt
) > mmc
->block_dev
.lba
) {
125 printf("MMC: block number 0x" LBAF
" exceeds max(0x" LBAF
")\n",
126 start
+ blkcnt
, mmc
->block_dev
.lba
);
132 else if (blkcnt
== 1)
133 cmd
.cmdidx
= MMC_CMD_WRITE_SINGLE_BLOCK
;
135 cmd
.cmdidx
= MMC_CMD_WRITE_MULTIPLE_BLOCK
;
137 if (mmc
->high_capacity
)
140 cmd
.cmdarg
= start
* mmc
->write_bl_len
;
142 cmd
.resp_type
= MMC_RSP_R1
;
145 data
.blocks
= blkcnt
;
146 data
.blocksize
= mmc
->write_bl_len
;
147 data
.flags
= MMC_DATA_WRITE
;
149 if (mmc_send_cmd(mmc
, &cmd
, &data
)) {
150 printf("mmc write failed\n");
154 /* SPI multiblock writes terminate using a special
155 * token, not a STOP_TRANSMISSION request.
157 if (!mmc_host_is_spi(mmc
) && blkcnt
> 1) {
158 cmd
.cmdidx
= MMC_CMD_STOP_TRANSMISSION
;
160 cmd
.resp_type
= MMC_RSP_R1b
;
161 if (mmc_send_cmd(mmc
, &cmd
, NULL
)) {
162 printf("mmc fail to send stop cmd\n");
167 /* Waiting for the ready status */
168 if (mmc_send_status(mmc
, timeout
))
174 ulong
mmc_bwrite(struct blk_desc
*block_dev
, lbaint_t start
, lbaint_t blkcnt
,
177 int dev_num
= block_dev
->dev
;
178 lbaint_t cur
, blocks_todo
= blkcnt
;
181 struct mmc
*mmc
= find_mmc_device(dev_num
);
185 err
= mmc_select_hwpart(dev_num
, block_dev
->hwpart
);
189 if (mmc_set_blocklen(mmc
, mmc
->write_bl_len
))
193 cur
= (blocks_todo
> mmc
->cfg
->b_max
) ?
194 mmc
->cfg
->b_max
: blocks_todo
;
195 if (mmc_write_blocks(mmc
, start
, cur
, src
) != cur
)
199 src
+= cur
* mmc
->write_bl_len
;
200 } while (blocks_todo
> 0);