1a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM/*
2a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * This program is free software; you can redistribute it and/or
3a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * modify it under the terms of the GNU General Public
4a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * License v2 as published by the Free Software Foundation.
5a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM *
6a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * This program is distributed in the hope that it will be useful,
7a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * but WITHOUT ANY WARRANTY; without even the implied warranty of
8a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * General Public License for more details.
10a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM *
11a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * You should have received a copy of the GNU General Public
12a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * License along with this program; if not, write to the
13a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM * Boston, MA 021110-1307, USA.
15a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM */
16a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
17a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <stdio.h>
18a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <stdlib.h>
19a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <string.h>
20a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <sys/ioctl.h>
21a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <sys/types.h>
22b7c16c94b8f404a64e3b946e897f482c4b0d1bc5Mohamad Ayyash#include <sys/endian.h>
23a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <dirent.h>
24a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <sys/stat.h>
25a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <unistd.h>
26a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <fcntl.h>
27a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <libgen.h>
28a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <limits.h>
29a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include <ctype.h>
30c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev#include <errno.h>
31c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev#include <stdint.h>
32c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev#include <assert.h>
33a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
34a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include "mmc.h"
35a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM#include "mmc_cmds.h"
36c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev#include "3rdparty/hmac_sha/hmac_sha2.h"
37a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
38a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLMint read_extcsd(int fd, __u8 *ext_csd)
39a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM{
40a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	int ret = 0;
41a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	struct mmc_ioc_cmd idata;
42a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	memset(&idata, 0, sizeof(idata));
43a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	memset(ext_csd, 0, sizeof(__u8) * 512);
44a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.write_flag = 0;
45a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.opcode = MMC_SEND_EXT_CSD;
46a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.arg = 0;
47a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
48a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.blksz = 512;
49a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.blocks = 1;
50a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	mmc_ioc_cmd_set_data(idata, ext_csd);
51a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
52a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	ret = ioctl(fd, MMC_IOC_CMD, &idata);
53a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	if (ret)
54a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		perror("ioctl");
55a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
56a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	return ret;
57a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM}
58a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
59a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLMint write_extcsd_value(int fd, __u8 index, __u8 value)
60a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM{
61a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	int ret = 0;
62a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	struct mmc_ioc_cmd idata;
63a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
64a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	memset(&idata, 0, sizeof(idata));
65a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.write_flag = 1;
66a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.opcode = MMC_SWITCH;
67a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
68a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM			(index << 16) |
69a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM			(value << 8) |
70a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM			EXT_CSD_CMD_SET_NORMAL;
71a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
72a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
73a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	ret = ioctl(fd, MMC_IOC_CMD, &idata);
74a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	if (ret)
75a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		perror("ioctl");
76a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
77a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	return ret;
78a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM}
79a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
8027c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardinerint send_status(int fd, __u32 *response)
8127c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner{
8227c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	int ret = 0;
8327c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	struct mmc_ioc_cmd idata;
8427c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
8527c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	memset(&idata, 0, sizeof(idata));
8627c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	idata.opcode = MMC_SEND_STATUS;
8727c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	idata.arg = (1 << 16);
8827c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
8927c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
9027c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	ret = ioctl(fd, MMC_IOC_CMD, &idata);
9127c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	if (ret)
9227c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	perror("ioctl");
9327c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
9427c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	*response = idata.response[0];
9527c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
9627c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	return ret;
9727c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner}
9827c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
99b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ballvoid print_writeprotect_status(__u8 *ext_csd)
100b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball{
101b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	__u8 reg;
102d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	__u8 ext_csd_rev = ext_csd[EXT_CSD_REV];
103b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
104b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	/* A43: reserved [174:0] */
105b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (ext_csd_rev >= 5) {
106b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf("Boot write protection status registers"
107b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			" [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
108b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
109b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		reg = ext_csd[EXT_CSD_BOOT_WP];
110b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
111b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf(" Power ro locking: ");
112b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
113b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("not possible\n");
114b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		else
115b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("possible\n");
116b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
117b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf(" Permanent ro locking: ");
118b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
119b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("not possible\n");
120b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		else
121b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("possible\n");
122b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
123b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf(" ro lock status: ");
124b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
125b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("locked until next power on\n");
126b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
127b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("locked permanently\n");
128b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		else
129b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("not locked\n");
130b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
131b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball}
132b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
133b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ballint do_writeprotect_get(int nargs, char **argv)
134b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball{
135b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	__u8 ext_csd[512];
136b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	int fd, ret;
137b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	char *device;
138b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
1398ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball	CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
1408ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball			  exit(1));
141b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
142b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	device = argv[1];
143b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
144b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	fd = open(device, O_RDWR);
145b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (fd < 0) {
146b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		perror("open");
147b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		exit(1);
148b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
149b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
150b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	ret = read_extcsd(fd, ext_csd);
151b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (ret) {
152b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
153b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		exit(1);
154b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
155b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
156b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	print_writeprotect_status(ext_csd);
157b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
158b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	return ret;
159b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball}
160b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
161b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ballint do_writeprotect_set(int nargs, char **argv)
162b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball{
163b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	__u8 ext_csd[512], value;
164b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	int fd, ret;
165b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	char *device;
166b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
1678ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball	CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
1688ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball			  exit(1));
169b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
170b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	device = argv[1];
171b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
172b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	fd = open(device, O_RDWR);
173b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (fd < 0) {
174b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		perror("open");
175b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		exit(1);
176b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
177b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
178b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	ret = read_extcsd(fd, ext_csd);
179b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (ret) {
180b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
181b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		exit(1);
182b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
183b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
184b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	value = ext_csd[EXT_CSD_BOOT_WP] |
185b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		EXT_CSD_BOOT_WP_B_PWR_WP_EN;
186b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
187b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (ret) {
188b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		fprintf(stderr, "Could not write 0x%02x to "
189b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			"EXT_CSD[%d] in %s\n",
190b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			value, EXT_CSD_BOOT_WP, device);
191b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		exit(1);
192b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	}
193b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
194b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	return ret;
195b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball}
196b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball
197b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Dasint do_disable_512B_emulation(int nargs, char **argv)
198b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das{
199b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	__u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param;
200b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	int fd, ret;
201b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	char *device;
202b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
203b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	CHECK(nargs != 2, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n", exit(1));
204b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	device = argv[1];
205b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
206b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	fd = open(device, O_RDWR);
207b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	if (fd < 0) {
208b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		perror("open");
209b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		exit(1);
210b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	}
211b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
212b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	ret = read_extcsd(fd, ext_csd);
213b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	if (ret) {
214b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
215b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		exit(1);
216b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	}
217b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
218b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
219b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
220b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
221b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
222b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	if (native_sector_size && !data_sector_size &&
223b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	   (wr_rel_param & EN_REL_WR)) {
224b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
225b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
226b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		if (ret) {
227b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das			fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
228b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das					1, EXT_CSD_BOOT_WP, device);
229b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das			exit(1);
230b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		}
231b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		printf("MMC disable 512B emulation successful.  Now reset the device to switch to 4KB native sector mode.\n");
232b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	} else if (native_sector_size && data_sector_size) {
233b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
234b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	} else {
235b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das		printf("MMC does not support disabling 512B emulation mode.\n");
236b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	}
237b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
238b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das	return ret;
239b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das}
240b7e2599c67408c38e57e91d2426c077a4541dc8cSaugata Das
2417bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLAROint do_write_boot_en(int nargs, char **argv)
2427bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO{
2437bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	__u8 ext_csd[512];
2447bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	__u8 value = 0;
2457bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	int fd, ret;
2467bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	char *device;
2477bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	int boot_area, send_ack;
2487bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2497bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	CHECK(nargs != 4, "Usage: mmc bootpart enable <partition_number> "
2507bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO			  "<send_ack> </path/to/mmcblkX>\n", exit(1));
2517bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2527bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	/*
2537bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	 * If <send_ack> is 1, the device will send acknowledgment
2547bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	 * pattern "010" to the host when boot operation begins.
2557bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	 * If <send_ack> is 0, it won't.
2567bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	 */
2577bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	boot_area = strtol(argv[1], NULL, 10);
2587bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	send_ack = strtol(argv[2], NULL, 10);
2597bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	device = argv[3];
2607bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2617bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	fd = open(device, O_RDWR);
2627bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	if (fd < 0) {
2637bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		perror("open");
2647bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		exit(1);
2657bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	}
2667bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2677bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	ret = read_extcsd(fd, ext_csd);
2687bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	if (ret) {
2697bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
2707bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		exit(1);
2717bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	}
2727bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2737bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	value = ext_csd[EXT_CSD_PART_CONFIG];
2747bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2757bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	switch (boot_area) {
2767bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	case EXT_CSD_PART_CONFIG_ACC_BOOT0:
2777bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value |= (1 << 3);
2787bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value &= ~(3 << 4);
2797bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		break;
2807bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	case EXT_CSD_PART_CONFIG_ACC_BOOT1:
2817bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value |= (1 << 4);
2827bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value &= ~(1 << 3);
2837bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value &= ~(1 << 5);
2847bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		break;
2857bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
2867bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value |= (boot_area << 3);
2877bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		break;
2887bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	default:
2897bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		fprintf(stderr, "Cannot enable the boot area\n");
2907bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		exit(1);
2917bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	}
2927bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	if (send_ack)
2937bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value |= EXT_CSD_PART_CONFIG_ACC_ACK;
2947bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	else
2957bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
2967bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
2977bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
2987bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	if (ret) {
2997bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		fprintf(stderr, "Could not write 0x%02x to "
3007bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO			"EXT_CSD[%d] in %s\n",
3017bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO			value, EXT_CSD_PART_CONFIG, device);
3027bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO		exit(1);
3037bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	}
3047bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO	return ret;
3057bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO}
3067bd1320b2cb38f040ab5cf017d17e283496690bfGiuseppe CAVALLARO
30764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooperint do_boot_bus_conditions_set(int nargs, char **argv)
30864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper{
30964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	__u8 ext_csd[512];
31064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	__u8 value = 0;
31164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	int fd, ret;
31264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	char *device;
31364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
31464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	CHECK(nargs != 5, "Usage: mmc: bootbus set <boot_mode> "
31564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	      "<reset_boot_bus_conditions> <boot_bus_width> <device>\n",
31664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1));
31764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
31864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (strcmp(argv[1], "single_backward") == 0)
31964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0;
32064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else if (strcmp(argv[1], "single_hs") == 0)
32164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0x8;
32264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else if (strcmp(argv[1], "dual") == 0)
32364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0x10;
32464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else {
32564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		fprintf(stderr, "illegal <boot_mode> specified\n");
32664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
32764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
32864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
32964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (strcmp(argv[2], "x1") == 0)
33064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0;
33164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else if (strcmp(argv[2], "retain") == 0)
33264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0x4;
33364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else {
33464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		fprintf(stderr,
33564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper			"illegal <reset_boot_bus_conditions> specified\n");
33664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
33764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
33864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
33964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (strcmp(argv[3], "x1") == 0)
34064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0;
34164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else if (strcmp(argv[3], "x4") == 0)
34264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0x1;
34364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else if (strcmp(argv[3], "x8") == 0)
34464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		value |= 0x2;
34564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	else {
34664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		fprintf(stderr,	"illegal <boot_bus_width> specified\n");
34764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
34864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
34964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
35064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	device = argv[4];
35164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	fd = open(device, O_RDWR);
35264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (fd < 0) {
35364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		perror("open");
35464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
35564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
35664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
35764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	ret = read_extcsd(fd, ext_csd);
35864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (ret) {
35964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
36064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
36164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
36264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	printf("Changing ext_csd[BOOT_BUS_CONDITIONS] from 0x%02x to 0x%02x\n",
36364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		ext_csd[EXT_CSD_BOOT_BUS_CONDITIONS], value);
36464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
36564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	ret = write_extcsd_value(fd, EXT_CSD_BOOT_BUS_CONDITIONS, value);
36664c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	if (ret) {
36764c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		fprintf(stderr, "Could not write 0x%02x to "
36864c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper			"EXT_CSD[%d] in %s\n",
36964c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper			value, EXT_CSD_BOOT_BUS_CONDITIONS, device);
37064c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		exit(1);
37164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	}
37264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	close(fd);
37364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	return ret;
37464c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper}
37564c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper
376f74dfe23cd00894aa9f235374468e05acb793e17Chris Ballint do_hwreset(int value, int nargs, char **argv)
377f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball{
378f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	__u8 ext_csd[512];
379f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	int fd, ret;
380f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	char *device;
381f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
382f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	CHECK(nargs != 2, "Usage: mmc hwreset enable </path/to/mmcblkX>\n",
383f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			  exit(1));
384f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
385f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	device = argv[1];
386f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
387f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	fd = open(device, O_RDWR);
388f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	if (fd < 0) {
389f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		perror("open");
390f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		exit(1);
391f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	}
392f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
393f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	ret = read_extcsd(fd, ext_csd);
394f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	if (ret) {
395f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
396f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		exit(1);
397f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	}
398f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
399f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
400f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	    EXT_CSD_HW_RESET_EN) {
401f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		fprintf(stderr,
402f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			"H/W Reset is already permanently enabled on %s\n",
403f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			device);
404f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		exit(1);
405f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	}
406f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
407f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	    EXT_CSD_HW_RESET_DIS) {
408f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		fprintf(stderr,
409f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			"H/W Reset is already permanently disabled on %s\n",
410f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			device);
411f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		exit(1);
412f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	}
413f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
414f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
415f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	if (ret) {
416f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		fprintf(stderr,
417f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			"Could not write 0x%02x to EXT_CSD[%d] in %s\n",
418f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball			value, EXT_CSD_RST_N_FUNCTION, device);
419f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball		exit(1);
420f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	}
421f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
422f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	return ret;
423f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball}
424f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
425f74dfe23cd00894aa9f235374468e05acb793e17Chris Ballint do_hwreset_en(int nargs, char **argv)
426f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball{
427f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
428f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball}
429f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
430f74dfe23cd00894aa9f235374468e05acb793e17Chris Ballint do_hwreset_dis(int nargs, char **argv)
431f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball{
432f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball	return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
433f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball}
434f74dfe23cd00894aa9f235374468e05acb793e17Chris Ball
4358649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chungint do_write_bkops_en(int nargs, char **argv)
4368649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung{
4378649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	__u8 ext_csd[512], value = 0;
4388649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	int fd, ret;
4398649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	char *device;
4408649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4418649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	CHECK(nargs != 2, "Usage: mmc bkops enable </path/to/mmcblkX>\n",
4428649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung			exit(1));
4438649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4448649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	device = argv[1];
4458649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4468649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	fd = open(device, O_RDWR);
4478649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	if (fd < 0) {
4488649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		perror("open");
4498649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		exit(1);
4508649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	}
4518649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4528649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	ret = read_extcsd(fd, ext_csd);
4538649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	if (ret) {
4548649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
4558649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		exit(1);
4568649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	}
4578649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4588649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
4598649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		fprintf(stderr, "%s doesn't support BKOPS\n", device);
4608649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		exit(1);
4618649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	}
4628649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4638649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
4648649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	if (ret) {
4658649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
4668649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung			value, EXT_CSD_BKOPS_EN, device);
4678649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung		exit(1);
4688649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	}
4698649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
4708649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung	return ret;
4718649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung}
4728649651b743a5d7c290ea0f8058794f8d127736eJaehoon Chung
47327c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardinerint do_status_get(int nargs, char **argv)
47427c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner{
47527c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	__u32 response;
47627c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	int fd, ret;
47727c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	char *device;
47827c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
47927c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	CHECK(nargs != 2, "Usage: mmc status get </path/to/mmcblkX>\n",
48027c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner		exit(1));
48127c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
48227c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	device = argv[1];
48327c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
48427c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	fd = open(device, O_RDWR);
48527c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	if (fd < 0) {
48627c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner		perror("open");
48727c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner		exit(1);
48827c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	}
48927c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
49027c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	ret = send_status(fd, &response);
49127c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	if (ret) {
49227c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner		fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
49327c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner		exit(1);
49427c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	}
49527c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
49627c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	printf("SEND_STATUS response: 0x%08x\n", response);
49727c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
49827c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner	return ret;
49927c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner}
50027c357db04350b75b0fceaae8bfb9ce99c50866bBen Gardiner
5014e85023654b356511612547207a4cb643fb3db16Ben Gardinerunsigned int get_sector_count(__u8 *ext_csd)
5024e85023654b356511612547207a4cb643fb3db16Ben Gardiner{
5034e85023654b356511612547207a4cb643fb3db16Ben Gardiner	return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) |
5044e85023654b356511612547207a4cb643fb3db16Ben Gardiner	(ext_csd[EXT_CSD_SEC_COUNT_2] << 16) |
5054e85023654b356511612547207a4cb643fb3db16Ben Gardiner	(ext_csd[EXT_CSD_SEC_COUNT_1] << 8)  |
5064e85023654b356511612547207a4cb643fb3db16Ben Gardiner	ext_csd[EXT_CSD_SEC_COUNT_0];
5074e85023654b356511612547207a4cb643fb3db16Ben Gardiner}
5084e85023654b356511612547207a4cb643fb3db16Ben Gardiner
5094e85023654b356511612547207a4cb643fb3db16Ben Gardinerint is_blockaddresed(__u8 *ext_csd)
5104e85023654b356511612547207a4cb643fb3db16Ben Gardiner{
5114e85023654b356511612547207a4cb643fb3db16Ben Gardiner	unsigned int sectors = get_sector_count(ext_csd);
5124e85023654b356511612547207a4cb643fb3db16Ben Gardiner
5134e85023654b356511612547207a4cb643fb3db16Ben Gardiner	return (sectors > (2u * 1024 * 1024 * 1024) / 512);
5144e85023654b356511612547207a4cb643fb3db16Ben Gardiner}
5154e85023654b356511612547207a4cb643fb3db16Ben Gardiner
516f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardinerunsigned int get_hc_wp_grp_size(__u8 *ext_csd)
517f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner{
518f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	return ext_csd[221];
519f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner}
520f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
521f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardinerunsigned int get_hc_erase_grp_size(__u8 *ext_csd)
522f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner{
523f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	return ext_csd[224];
524f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner}
525f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
526e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardinerint set_partitioning_setting_completed(int dry_run, const char * const device,
527e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		int fd)
528e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner{
529e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	int ret;
530e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
531e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	if (dry_run) {
532e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
533e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		fprintf(stderr, "These changes will not take effect neither "
534e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner			"now nor after a power cycle\n");
535e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		return 1;
536e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	}
537e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
538e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
539e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
540e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	if (ret) {
541e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		fprintf(stderr, "Could not write 0x1 to "
542e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner			"EXT_CSD[%d] in %s\n",
543e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner			EXT_CSD_PARTITION_SETTING_COMPLETED, device);
544e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		return 1;
545e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	}
546e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
547e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	__u32 response;
548e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	ret = send_status(fd, &response);
549e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	if (ret) {
550e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		fprintf(stderr, "Could not get response to SEND_STATUS "
551e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner			"from %s\n", device);
552e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		return 1;
553e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	}
554e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
555e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	if (response & R1_SWITCH_ERROR) {
556e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
557e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner			"failed on %s\n", device);
558e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		return 1;
559e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	}
560e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
561e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
562e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		"%s SUCCESS\n", device);
563e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	fprintf(stderr, "Device power cycle needed for settings to "
564e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		"take effect.\n"
565e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		"Confirm that PARTITION_SETTING_COMPLETED bit is set "
566e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner		"using 'extcsd read' after power cycle\n");
567e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
568e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	return 0;
569e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner}
570e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner
5714afc8c81685825461677311e79059cda15fba9d8Balaji T Kint check_enhanced_area_total_limit(const char * const device, int fd)
5724afc8c81685825461677311e79059cda15fba9d8Balaji T K{
5734afc8c81685825461677311e79059cda15fba9d8Balaji T K	__u8 ext_csd[512];
5744afc8c81685825461677311e79059cda15fba9d8Balaji T K	__u32 regl;
5754afc8c81685825461677311e79059cda15fba9d8Balaji T K	unsigned long max_enh_area_sz, user_area_sz, enh_area_sz = 0;
5764afc8c81685825461677311e79059cda15fba9d8Balaji T K	unsigned long gp4_part_sz, gp3_part_sz, gp2_part_sz, gp1_part_sz;
5777891236d62ccd201054324b5298dd9529c6a764fBalaji T K	unsigned long total_sz, total_gp_user_sz;
5784afc8c81685825461677311e79059cda15fba9d8Balaji T K	unsigned int wp_sz, erase_sz;
5794afc8c81685825461677311e79059cda15fba9d8Balaji T K	int ret;
5804afc8c81685825461677311e79059cda15fba9d8Balaji T K
5814afc8c81685825461677311e79059cda15fba9d8Balaji T K	ret = read_extcsd(fd, ext_csd);
5824afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ret) {
5834afc8c81685825461677311e79059cda15fba9d8Balaji T K		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
5844afc8c81685825461677311e79059cda15fba9d8Balaji T K		exit(1);
5854afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
5864afc8c81685825461677311e79059cda15fba9d8Balaji T K	wp_sz = get_hc_wp_grp_size(ext_csd);
5874afc8c81685825461677311e79059cda15fba9d8Balaji T K	erase_sz = get_hc_erase_grp_size(ext_csd);
5884afc8c81685825461677311e79059cda15fba9d8Balaji T K
5894afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_4_2] << 16) |
5904afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_GP_SIZE_MULT_4_1] << 8) |
5914afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_GP_SIZE_MULT_4_0];
5924afc8c81685825461677311e79059cda15fba9d8Balaji T K	gp4_part_sz = 512l * regl * erase_sz * wp_sz;
5934afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_4) {
5944afc8c81685825461677311e79059cda15fba9d8Balaji T K		enh_area_sz += gp4_part_sz;
5954afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf("Enhanced GP4 Partition Size [GP_SIZE_MULT_4]: 0x%06x\n", regl);
5964afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf(" i.e. %lu KiB\n", gp4_part_sz);
5974afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
5984afc8c81685825461677311e79059cda15fba9d8Balaji T K
5994afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_3_2] << 16) |
6004afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_GP_SIZE_MULT_3_1] << 8) |
6014afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_GP_SIZE_MULT_3_0];
6024afc8c81685825461677311e79059cda15fba9d8Balaji T K	gp3_part_sz = 512l * regl * erase_sz * wp_sz;
6034afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_3) {
6044afc8c81685825461677311e79059cda15fba9d8Balaji T K		enh_area_sz += gp3_part_sz;
6054afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf("Enhanced GP3 Partition Size [GP_SIZE_MULT_3]: 0x%06x\n", regl);
6064afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf(" i.e. %lu KiB\n", gp3_part_sz);
6074afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
6084afc8c81685825461677311e79059cda15fba9d8Balaji T K
6094afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_2_2] << 16) |
6104afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_GP_SIZE_MULT_2_1] << 8) |
6114afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_GP_SIZE_MULT_2_0];
6124afc8c81685825461677311e79059cda15fba9d8Balaji T K	gp2_part_sz = 512l * regl * erase_sz * wp_sz;
6134afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_2) {
6144afc8c81685825461677311e79059cda15fba9d8Balaji T K		enh_area_sz += gp2_part_sz;
6154afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf("Enhanced GP2 Partition Size [GP_SIZE_MULT_2]: 0x%06x\n", regl);
6164afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf(" i.e. %lu KiB\n", gp2_part_sz);
6174afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
6184afc8c81685825461677311e79059cda15fba9d8Balaji T K
6194afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_1_2] << 16) |
6204afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_GP_SIZE_MULT_1_1] << 8) |
6214afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_GP_SIZE_MULT_1_0];
6224afc8c81685825461677311e79059cda15fba9d8Balaji T K	gp1_part_sz = 512l * regl * erase_sz * wp_sz;
6234afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_1) {
6244afc8c81685825461677311e79059cda15fba9d8Balaji T K		enh_area_sz += gp1_part_sz;
6254afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf("Enhanced GP1 Partition Size [GP_SIZE_MULT_1]: 0x%06x\n", regl);
6264afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf(" i.e. %lu KiB\n", gp1_part_sz);
6274afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
6284afc8c81685825461677311e79059cda15fba9d8Balaji T K
6294afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
6304afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
6314afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
6324afc8c81685825461677311e79059cda15fba9d8Balaji T K	user_area_sz = 512l * regl * erase_sz * wp_sz;
6334afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_USR) {
6344afc8c81685825461677311e79059cda15fba9d8Balaji T K		enh_area_sz += user_area_sz;
6354afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf("Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x%06x\n", regl);
6364afc8c81685825461677311e79059cda15fba9d8Balaji T K		printf(" i.e. %lu KiB\n", user_area_sz);
6374afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
6384afc8c81685825461677311e79059cda15fba9d8Balaji T K
6394afc8c81685825461677311e79059cda15fba9d8Balaji T K	regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
6404afc8c81685825461677311e79059cda15fba9d8Balaji T K		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
6414afc8c81685825461677311e79059cda15fba9d8Balaji T K		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
6424afc8c81685825461677311e79059cda15fba9d8Balaji T K	max_enh_area_sz = 512l * regl * erase_sz * wp_sz;
6434afc8c81685825461677311e79059cda15fba9d8Balaji T K	printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n", regl);
6444afc8c81685825461677311e79059cda15fba9d8Balaji T K	printf(" i.e. %lu KiB\n", max_enh_area_sz);
6454afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (enh_area_sz > max_enh_area_sz) {
6464afc8c81685825461677311e79059cda15fba9d8Balaji T K		fprintf(stderr,
6474afc8c81685825461677311e79059cda15fba9d8Balaji T K			"Programmed total enhanced size %lu KiB cannot exceed max enhanced area %lu KiB %s\n",
6484afc8c81685825461677311e79059cda15fba9d8Balaji T K			enh_area_sz, max_enh_area_sz, device);
6494afc8c81685825461677311e79059cda15fba9d8Balaji T K		return 1;
6504afc8c81685825461677311e79059cda15fba9d8Balaji T K	}
6517891236d62ccd201054324b5298dd9529c6a764fBalaji T K	total_sz = get_sector_count(ext_csd) / 2;
6527891236d62ccd201054324b5298dd9529c6a764fBalaji T K	total_gp_user_sz = gp4_part_sz + gp3_part_sz + gp2_part_sz +
6537891236d62ccd201054324b5298dd9529c6a764fBalaji T K				gp1_part_sz + user_area_sz;
6547891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (total_gp_user_sz > total_sz) {
6557891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr,
6567891236d62ccd201054324b5298dd9529c6a764fBalaji T K			"requested total partition size %lu KiB cannot exceed card capacity %lu KiB %s\n",
6577891236d62ccd201054324b5298dd9529c6a764fBalaji T K			total_gp_user_sz, total_sz, device);
6587891236d62ccd201054324b5298dd9529c6a764fBalaji T K		return 1;
6597891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
6607891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6617891236d62ccd201054324b5298dd9529c6a764fBalaji T K	return 0;
6627891236d62ccd201054324b5298dd9529c6a764fBalaji T K}
6637891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6647891236d62ccd201054324b5298dd9529c6a764fBalaji T Kint do_create_gp_partition(int nargs, char **argv)
6657891236d62ccd201054324b5298dd9529c6a764fBalaji T K{
6667891236d62ccd201054324b5298dd9529c6a764fBalaji T K	__u8 value;
6677891236d62ccd201054324b5298dd9529c6a764fBalaji T K	__u8 ext_csd[512];
6687891236d62ccd201054324b5298dd9529c6a764fBalaji T K	__u8 address;
6697891236d62ccd201054324b5298dd9529c6a764fBalaji T K	int fd, ret;
6707891236d62ccd201054324b5298dd9529c6a764fBalaji T K	char *device;
6717891236d62ccd201054324b5298dd9529c6a764fBalaji T K	int dry_run = 1;
6727891236d62ccd201054324b5298dd9529c6a764fBalaji T K	int partition, enh_attr, ext_attr;
6737891236d62ccd201054324b5298dd9529c6a764fBalaji T K	unsigned int length_kib, gp_size_mult;
6747891236d62ccd201054324b5298dd9529c6a764fBalaji T K	unsigned long align;
6757891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6767891236d62ccd201054324b5298dd9529c6a764fBalaji T K	CHECK(nargs != 7, "Usage: mmc gp create <-y|-n> <length KiB> "
6777891236d62ccd201054324b5298dd9529c6a764fBalaji T K		"<partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n", exit(1));
6787891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6797891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (!strcmp("-y", argv[1]))
6807891236d62ccd201054324b5298dd9529c6a764fBalaji T K		dry_run = 0;
6817891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6827891236d62ccd201054324b5298dd9529c6a764fBalaji T K	length_kib = strtol(argv[2], NULL, 10);
6837891236d62ccd201054324b5298dd9529c6a764fBalaji T K	partition = strtol(argv[3], NULL, 10);
6847891236d62ccd201054324b5298dd9529c6a764fBalaji T K	enh_attr = strtol(argv[4], NULL, 10);
6857891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ext_attr = strtol(argv[5], NULL, 10);
6867891236d62ccd201054324b5298dd9529c6a764fBalaji T K	device = argv[6];
6877891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6887891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (partition < 0 || partition > 4) {
6897891236d62ccd201054324b5298dd9529c6a764fBalaji T K		printf("Invalid gp parition number valid range [1-4]\n");
6907891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
6917891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
6927891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6937891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (enh_attr && ext_attr) {
6947891236d62ccd201054324b5298dd9529c6a764fBalaji T K		printf("Not allowed to set both enhanced attribute and extended attribute\n");
6957891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
6967891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
6977891236d62ccd201054324b5298dd9529c6a764fBalaji T K
6987891236d62ccd201054324b5298dd9529c6a764fBalaji T K	fd = open(device, O_RDWR);
6997891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (fd < 0) {
7007891236d62ccd201054324b5298dd9529c6a764fBalaji T K		perror("open");
7017891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7027891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7037891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7047891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = read_extcsd(fd, ext_csd);
7057891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7067891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
7077891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7087891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7097891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7107891236d62ccd201054324b5298dd9529c6a764fBalaji T K	/* assert not PARTITION_SETTING_COMPLETED */
7117891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) {
7127891236d62ccd201054324b5298dd9529c6a764fBalaji T K		printf(" Device is already partitioned\n");
7137891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7147891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7157891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7167891236d62ccd201054324b5298dd9529c6a764fBalaji T K	align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
7177891236d62ccd201054324b5298dd9529c6a764fBalaji T K	gp_size_mult = (length_kib + align/2l) / align;
7187891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7197891236d62ccd201054324b5298dd9529c6a764fBalaji T K	/* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
7207891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
7217891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7227891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write 0x1 to EXT_CSD[%d] in %s\n",
7237891236d62ccd201054324b5298dd9529c6a764fBalaji T K			EXT_CSD_ERASE_GROUP_DEF, device);
7247891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7257891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7267891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7277891236d62ccd201054324b5298dd9529c6a764fBalaji T K	value = (gp_size_mult >> 16) & 0xff;
7287891236d62ccd201054324b5298dd9529c6a764fBalaji T K	address = EXT_CSD_GP_SIZE_MULT_1_2 + (partition - 1) * 3;
7297891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, address, value);
7307891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7317891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
7327891236d62ccd201054324b5298dd9529c6a764fBalaji T K			value, address, device);
7337891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7347891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7357891236d62ccd201054324b5298dd9529c6a764fBalaji T K	value = (gp_size_mult >> 8) & 0xff;
7367891236d62ccd201054324b5298dd9529c6a764fBalaji T K	address = EXT_CSD_GP_SIZE_MULT_1_1 + (partition - 1) * 3;
7377891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, address, value);
7387891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7397891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
7407891236d62ccd201054324b5298dd9529c6a764fBalaji T K			value, address, device);
7417891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7427891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7437891236d62ccd201054324b5298dd9529c6a764fBalaji T K	value = gp_size_mult & 0xff;
7447891236d62ccd201054324b5298dd9529c6a764fBalaji T K	address = EXT_CSD_GP_SIZE_MULT_1_0 + (partition - 1) * 3;
7457891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, address, value);
7467891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7477891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
7487891236d62ccd201054324b5298dd9529c6a764fBalaji T K			value, address, device);
7497891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7507891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7517891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7527891236d62ccd201054324b5298dd9529c6a764fBalaji T K	value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
7537891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (enh_attr)
7547891236d62ccd201054324b5298dd9529c6a764fBalaji T K		value |= (1 << partition);
7557891236d62ccd201054324b5298dd9529c6a764fBalaji T K	else
7567891236d62ccd201054324b5298dd9529c6a764fBalaji T K		value &= ~(1 << partition);
7577891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7587891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
7597891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7607891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n",
7617891236d62ccd201054324b5298dd9529c6a764fBalaji T K			partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device);
7627891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7637891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7647891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7657891236d62ccd201054324b5298dd9529c6a764fBalaji T K	address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2;
7667891236d62ccd201054324b5298dd9529c6a764fBalaji T K	value = ext_csd[address];
7677891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ext_attr)
7687891236d62ccd201054324b5298dd9529c6a764fBalaji T K		value |= (ext_attr << (4 * ((partition - 1) % 2)));
7697891236d62ccd201054324b5298dd9529c6a764fBalaji T K	else
7707891236d62ccd201054324b5298dd9529c6a764fBalaji T K		value &= (0xF << (4 * ((partition % 2))));
7717891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7727891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = write_extcsd_value(fd, address, value);
7737891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret) {
7747891236d62ccd201054324b5298dd9529c6a764fBalaji T K		fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
7757891236d62ccd201054324b5298dd9529c6a764fBalaji T K			value, address, device);
7767891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7777891236d62ccd201054324b5298dd9529c6a764fBalaji T K	}
7787891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7797891236d62ccd201054324b5298dd9529c6a764fBalaji T K	ret = check_enhanced_area_total_limit(device, fd);
7807891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (ret)
7817891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7827891236d62ccd201054324b5298dd9529c6a764fBalaji T K
7837891236d62ccd201054324b5298dd9529c6a764fBalaji T K	if (!set_partitioning_setting_completed(dry_run, device, fd))
7847891236d62ccd201054324b5298dd9529c6a764fBalaji T K		exit(1);
7854afc8c81685825461677311e79059cda15fba9d8Balaji T K
7864afc8c81685825461677311e79059cda15fba9d8Balaji T K	return 0;
7874afc8c81685825461677311e79059cda15fba9d8Balaji T K}
7884afc8c81685825461677311e79059cda15fba9d8Balaji T K
789d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardinerint do_enh_area_set(int nargs, char **argv)
790d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner{
791d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	__u8 value;
792d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	__u8 ext_csd[512];
793d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	int fd, ret;
794d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	char *device;
795d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	int dry_run = 1;
796d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
797d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	unsigned long align;
798d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
799d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	CHECK(nargs != 5, "Usage: mmc enh_area set <-y|-n> <start KiB> <length KiB> "
800d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			  "</path/to/mmcblkX>\n", exit(1));
801d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
802d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (!strcmp("-y", argv[1]))
803d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		dry_run = 0;
804d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
805d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	start_kib = strtol(argv[2], NULL, 10);
806d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	length_kib = strtol(argv[3], NULL, 10);
807d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	device = argv[4];
808d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
809d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	fd = open(device, O_RDWR);
810d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (fd < 0) {
811d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		perror("open");
812d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
813d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
814d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
815d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = read_extcsd(fd, ext_csd);
816d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
817d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
818d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
819d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
820d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
821d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	/* assert ENH_ATTRIBUTE_EN */
822d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
823d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	{
824d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		printf(" Device cannot have enhanced tech.\n");
825d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
826d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
827d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
828d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	/* assert not PARTITION_SETTING_COMPLETED */
829d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
830d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	{
831d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		printf(" Device is already partitioned\n");
832d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
833d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
834d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
835d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
836d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
837d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	enh_size_mult = (length_kib + align/2l) / align;
838d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
839d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	enh_start_addr = start_kib * 1024 / (is_blockaddresed(ext_csd) ? 512 : 1);
840d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	enh_start_addr /= align;
841d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	enh_start_addr *= align;
842d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
843d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	/* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
844d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
845d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
846d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x1 to "
847d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n",
848d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ERASE_GROUP_DEF, device);
849d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
850d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
851d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
852d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	/* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
853d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = (enh_start_addr >> 24) & 0xff;
854d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
855d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
856d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
857d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
858d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_START_ADDR_3, device);
859d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
860d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
861d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = (enh_start_addr >> 16) & 0xff;
862d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
863d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
864d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
865d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
866d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_START_ADDR_2, device);
867d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
868d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
869d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = (enh_start_addr >> 8) & 0xff;
870d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
871d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
872d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
873d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
874d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_START_ADDR_1, device);
875d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
876d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
877d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = enh_start_addr & 0xff;
878d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
879d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
880d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
881d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
882d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_START_ADDR_0, device);
883d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
884d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
885d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
886d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = (enh_size_mult >> 16) & 0xff;
887d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
888d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
889d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
890d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
891d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_SIZE_MULT_2, device);
892d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
893d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
894d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = (enh_size_mult >> 8) & 0xff;
895d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
896d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
897d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
898d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
899d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_SIZE_MULT_1, device);
900d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
901d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
902d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	value = enh_size_mult & 0xff;
903d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
904d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
905d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write 0x%02x to "
906d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n", value,
907d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_ENH_SIZE_MULT_0, device);
908d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
909d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
9104afc8c81685825461677311e79059cda15fba9d8Balaji T K	value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR;
9114afc8c81685825461677311e79059cda15fba9d8Balaji T K	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
912d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	if (ret) {
913d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
914d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			"EXT_CSD[%d] in %s\n",
915d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			EXT_CSD_PARTITIONS_ATTRIBUTE, device);
916d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
917d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	}
918d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
9194afc8c81685825461677311e79059cda15fba9d8Balaji T K	ret = check_enhanced_area_total_limit(device, fd);
9204afc8c81685825461677311e79059cda15fba9d8Balaji T K	if (ret)
9214afc8c81685825461677311e79059cda15fba9d8Balaji T K		exit(1);
9224afc8c81685825461677311e79059cda15fba9d8Balaji T K
923e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	printf("Done setting ENH_USR area on %s\n", device);
924d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
925e6e84e96ac031e261bda8d441aa9c4cade144437Ben Gardiner	if (!set_partitioning_setting_completed(dry_run, device, fd))
926d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		exit(1);
927d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
928d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner	return 0;
929d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner}
930d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner
931196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardinerint do_write_reliability_set(int nargs, char **argv)
932196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner{
933196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	__u8 value;
934196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	__u8 ext_csd[512];
935196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	int fd, ret;
936196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
937196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	int dry_run = 1;
938196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	int partition;
939196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	char *device;
940196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
941196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	CHECK(nargs != 4, "Usage: mmc write_reliability set <-y|-n> "
942196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner			"<partition> </path/to/mmcblkX>\n", exit(1));
943196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
944196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (!strcmp("-y", argv[1]))
945196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		dry_run = 0;
946196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
947196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	partition = strtol(argv[2], NULL, 10);
948196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	device = argv[3];
949196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
950196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	fd = open(device, O_RDWR);
951196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (fd < 0) {
952196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		perror("open");
953196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
954196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	}
955196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
956196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	ret = read_extcsd(fd, ext_csd);
957196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (ret) {
958196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
959196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
960196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	}
961196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
962196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	/* assert not PARTITION_SETTING_COMPLETED */
963196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
964196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	{
965196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		printf(" Device is already partitioned\n");
966196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
967196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	}
968196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
969196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	/* assert HS_CTRL_REL */
970196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
971196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		printf("Cannot set write reliability parameters, WR_REL_SET is "
972196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner				"read-only\n");
973196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
974196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	}
975196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
976196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
977196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
978196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (ret) {
979196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
980196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner				value, EXT_CSD_WR_REL_SET, device);
981196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
982196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	}
983196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
984196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
985196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		value, device);
986196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
987196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	if (!set_partitioning_setting_completed(dry_run, device, fd))
988196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner		exit(1);
989196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
990196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner	return 0;
991196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner}
992196d0d29588867bed50cd28b8f03cbbb5e0e6608Ben Gardiner
993a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLMint do_read_extcsd(int nargs, char **argv)
994a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM{
995a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	__u8 ext_csd[512], ext_csd_rev, reg;
99611f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz	__u32 regl;
997a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	int fd, ret;
998a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	char *device;
999a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	const char *str;
1000a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
10018ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball	CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
10028ba4466a4ad458618282f8bdcc2706025856a9f2Chris Ball			  exit(1));
1003a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
1004a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	device = argv[1];
1005a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
1006a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	fd = open(device, O_RDWR);
1007a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	if (fd < 0) {
1008a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		perror("open");
1009a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		exit(1);
1010a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	}
1011a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
1012a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	ret = read_extcsd(fd, ext_csd);
1013a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	if (ret) {
1014a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
1015a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM		exit(1);
1016a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	}
1017a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM
1018d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	ext_csd_rev = ext_csd[EXT_CSD_REV];
1019a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1020a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	switch (ext_csd_rev) {
102164c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper	case 7:
102264c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		str = "5.0";
102364c2de8b1476c42ef9e9729b7ca0e436b5d90170Al Cooper		break;
1024a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 6:
1025a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.5";
1026a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1027a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 5:
1028a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.41";
1029a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1030a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 3:
1031a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.3";
1032a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1033a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 2:
1034a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.2";
1035a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1036a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 1:
1037a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.1";
1038a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1039a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0:
1040a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		str = "4.0";
1041a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1042a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	default:
1043a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		goto out_free;
1044a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1045a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("=============================================\n");
1046a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("  Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
1047a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("=============================================\n\n");
1048a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1049a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev < 3)
1050a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		goto out_free; /* No ext_csd */
1051a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1052a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* Parse the Extended CSD registers.
1053a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	 * Reserved bit should be read as "0" in case of spec older
1054a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	 * than A441.
1055a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	 */
1056a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	reg = ext_csd[EXT_CSD_S_CMD_SET];
1057a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
1058a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (!reg)
1059b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf(" - Standard MMC command sets\n");
1060a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1061a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	reg = ext_csd[EXT_CSD_HPI_FEATURE];
1062a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
1063a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (reg & EXT_CSD_HPI_SUPP) {
1064a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		if (reg & EXT_CSD_HPI_IMPL)
1065b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			printf("implementation based on CMD12\n");
1066a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		else
1067a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf("implementation based on CMD13\n");
1068a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1069a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1070a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
1071a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[502]);
1072a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1073a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev >= 6) {
1074a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
1075a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[501]);
1076a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
1077a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[500]);
1078a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
1079a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[499]);
1080a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1081a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
1082a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[498]);
1083a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
1084a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[497]);
1085a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Context Management Capabilities"
1086a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
1087a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
1088a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[495]);
1089a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Extended partition attribute support"
1090a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
1091a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
1092a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[248]);
1093a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
1094a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[247]);
1095a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Cache Size [CACHE_SIZE] is %d KiB\n",
1096a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[249] << 0 | (ext_csd[250] << 8) |
1097a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(ext_csd[251] << 16) | (ext_csd[252] << 24));
1098a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1099a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1100a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441: Reserved [501:247]
1101a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	    A43: reserved [246:229] */
1102a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev >= 5) {
1103a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Background operations status"
1104b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball			" [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
1105a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1106a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
1107a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1108a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("1st Initialisation Time after programmed sector"
1109a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
1110a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1111a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441: reserved [240] */
1112a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Power class for 52MHz, DDR at 3.6V"
1113a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
1114a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Power class for 52MHz, DDR at 1.95V"
1115a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
1116a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1117a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441: reserved [237-236] */
1118a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1119a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		if (ext_csd_rev >= 6) {
1120a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf("Power class for 200MHz at 3.6V"
1121a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO				" [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
1122a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf("Power class for 200MHz, at 1.95V"
1123a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO				" [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
1124a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		}
1125b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball		printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
1126a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
1127a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
1128a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441: reserved [233] */
1129a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
1130a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
1131a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[231]);
1132a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1133a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
1134a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
1135a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[230]);
1136a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
1137a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[229]);
1138a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1139a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	reg = ext_csd[EXT_CSD_BOOT_INFO];
1140a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
1141a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (reg & EXT_CSD_BOOT_INFO_ALT)
1142a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Device supports alternative boot method\n");
1143a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
1144a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Device supports dual data rate during boot\n");
1145a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
1146a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Device supports high speed timing during boot\n");
1147a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1148a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved [227] */
1149a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
1150a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
1151f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
1152f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	reg = get_hc_erase_grp_size(ext_csd);
1153a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
1154f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		reg);
1155f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	printf(" i.e. %u KiB\n", 512 * reg);
1156f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
1157a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
1158a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[223]);
1159a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
1160a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[222]);
1161f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
1162f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	reg = get_hc_wp_grp_size(ext_csd);
1163a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
1164f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		reg);
1165f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner	printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
1166f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
1167a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
1168a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
1169a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved [218] */
1170a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
1171a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved [216] */
11724e85023654b356511612547207a4cb643fb3db16Ben Gardiner
11734e85023654b356511612547207a4cb643fb3db16Ben Gardiner	unsigned int sectors =	get_sector_count(ext_csd);
11744e85023654b356511612547207a4cb643fb3db16Ben Gardiner	printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
11754e85023654b356511612547207a4cb643fb3db16Ben Gardiner	if (is_blockaddresed(ext_csd))
11764e85023654b356511612547207a4cb643fb3db16Ben Gardiner		printf(" Device is block-addressed\n");
11774e85023654b356511612547207a4cb643fb3db16Ben Gardiner	else
11784e85023654b356511612547207a4cb643fb3db16Ben Gardiner		printf(" Device is NOT block-addressed\n");
11794e85023654b356511612547207a4cb643fb3db16Ben Gardiner
1180a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved [211] */
1181a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Minimum Write Performance for 8bit:\n");
1182a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
1183a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
1184a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
1185a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
1186a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Minimum Write Performance for 4bit:\n");
1187a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
1188a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
1189a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved [204] */
1190a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Power classes registers:\n");
1191a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
1192a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
1193a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
1194a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
1195a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1196a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A43: reserved [199:198] */
1197a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev >= 5) {
1198a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Partition switching timing "
1199a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			"[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
1200a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Out-of-interrupt busy timing"
1201a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
1202a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1203a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1204a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* A441/A43: reserved	[197] [195] [193] [190] [188]
1205a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	 * [186] [184] [182] [180] [176] */
1206a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1207a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev >= 6)
1208a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
1209a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[197]);
1210a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
121164f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	/* DEVICE_TYPE in A45, CARD_TYPE in A441 */
121264f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	reg = ext_csd[196];
121364f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
121464f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
121564f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
121664f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
121764f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x04)	printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
121864f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x02)	printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
121964f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi	if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
1220a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1221a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
1222d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	/* ext_csd_rev = ext_csd[EXT_CSD_REV] (already done!!!) */
1223a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
1224a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
1225a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
1226a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
1227a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[185]);
1228a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* bus_width: ext_csd[183] not readable */
1229a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
1230a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[181]);
1231a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	reg = ext_csd[EXT_CSD_BOOT_CFG];
1232a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
12338c0c40d477db2863e2746e6a995980113f725c0dMario Schuknecht	switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
1234a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x0:
1235a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Not boot enable\n");
1236a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1237a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x1:
1238a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Boot Partition 1 enabled\n");
1239a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1240a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x2:
1241a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" Boot Partition 2 enabled\n");
1242a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1243a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x7:
1244a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" User Area Enabled for boot\n");
1245a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1246a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1247a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	switch (reg & EXT_CSD_BOOT_CFG_ACC) {
1248a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x0:
1249a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" No access to boot partition\n");
1250a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1251a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x1:
1252a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" R/W Boot Partition 1\n");
1253a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1254a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	case 0x2:
1255a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" R/W Boot Partition 2\n");
1256a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
12578c0c40d477db2863e2746e6a995980113f725c0dMario Schuknecht	case 0x3:
12588c0c40d477db2863e2746e6a995980113f725c0dMario Schuknecht		printf(" R/W Replay Protected Memory Block (RPMB)\n");
12598c0c40d477db2863e2746e6a995980113f725c0dMario Schuknecht		break;
1260a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	default:
12618c0c40d477db2863e2746e6a995980113f725c0dMario Schuknecht		printf(" Access to General Purpose partition %d\n",
1262a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(reg & EXT_CSD_BOOT_CFG_ACC) - 3);
1263a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		break;
1264a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1265a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1266a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
1267a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[178]);
1268a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
1269a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		ext_csd[177]);
1270a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	printf("High-density erase group definition"
1271d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner		" [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
1272a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1273b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	print_writeprotect_status(ext_csd);
1274a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1275b9c7a17fce190f085bb4eb6e6535a22e2c69de68Chris Ball	if (ext_csd_rev >= 5) {
1276a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441]: reserved [172] */
1277a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("User area write protection register"
1278a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [USER_WP]: 0x%02x\n", ext_csd[171]);
1279a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441]: reserved [170] */
1280a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
1281a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
12824da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner
12834da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		reg = ext_csd[EXT_CSD_WR_REL_SET];
12844da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		const char * const fast = "existing data is at risk if a power "
12854da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner				"failure occurs during a write operation";
12864da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		const char * const reliable = "the device protects existing "
12874da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner				"data if a power failure occurs during a write "
12884da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner				"operation";
1289a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Write reliability setting register"
12904da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner			" [WR_REL_SET]: 0x%02x\n", reg);
12914da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner
12924da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
12934da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		int i;
12944da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		for (i = 1; i <= 4; i++) {
12954da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner			printf(" partition %d: %s\n", i,
12964da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner				reg & (1<<i) ? reliable : fast);
12974da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		}
12984da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner
12994da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		reg = ext_csd[EXT_CSD_WR_REL_PARAM];
1300a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Write reliability parameter register"
13014da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner			" [WR_REL_PARAM]: 0x%02x\n", reg);
13024da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		if (reg & 0x01)
13034da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner			printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
13044da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner		if (reg & 0x04)
13054da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner			printf(" Device supports the enhanced def. of reliable "
13064da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner				"write\n");
13074da1c0dc8bb295993d05beebc0a6132af9713322Ben Gardiner
1308a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* sanitize_start ext_csd[165]]: not readable
1309a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		 * bkops_start ext_csd[164]]: only writable */
1310a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Enable background operations handshake"
1311a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
1312a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("H/W reset function"
1313a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
1314a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
131582bd9504b12160992309d6508dc5654b3db93c2bBen Gardiner		reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1316a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1317a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			reg);
131882bd9504b12160992309d6508dc5654b3db93c2bBen Gardiner		if (reg & EXT_CSD_PARTITIONING_EN)
1319a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf(" Device support partitioning feature\n");
1320a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		else
1321a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf(" Device NOT support partitioning feature\n");
132282bd9504b12160992309d6508dc5654b3db93c2bBen Gardiner		if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
1323a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf(" Device can have enhanced tech.\n");
1324a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		else
1325a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf(" Device cannot have enhanced tech.\n");
1326a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
132711f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz		regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
132822f2641fe6155fe9fb8b38a8ebe2093ec3e2ec11Oliver Metz			(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
132922f2641fe6155fe9fb8b38a8ebe2093ec3e2ec11Oliver Metz			ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
133022f2641fe6155fe9fb8b38a8ebe2093ec3e2ec11Oliver Metz
1331a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
133211f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz			   regl);
1333f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1334f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
133511f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz		printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
1336f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner
1337a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
1338d91d3698c6464a83b7c301eb84da109f9f94b54cBen Gardiner			ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
1339a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner		reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
1340a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Partitioning Setting"
1341a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
1342a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner			reg);
1343a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner		if (reg)
1344a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner			printf(" Device partition setting complete\n");
1345a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner		else
1346a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner			printf(" Device partition setting NOT complete\n");
1347a6cd98de8b158029ca6b9c1e961729dc83a7144cBen Gardiner
1348a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("General Purpose Partition Size\n"
1349a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
1350a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(ext_csd[153] << 8) | ext_csd[152]);
1351a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
1352a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			   (ext_csd[150] << 8) | ext_csd[149]);
1353a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
1354a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			   (ext_csd[147] << 8) | ext_csd[146]);
1355a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
1356a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			   (ext_csd[144] << 8) | ext_csd[143]);
1357a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
135811f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz		regl =	(ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
1359f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner			(ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1360f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner			ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
1361a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Enhanced User Data Area Size"
136211f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz			" [ENH_SIZE_MULT]: 0x%06x\n", regl);
136311f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz		printf(" i.e. %lu KiB\n", 512l * regl *
1364f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		       get_hc_erase_grp_size(ext_csd) *
1365f82e27a1b11e6fb52565b61827563316dcbb2cc4Ben Gardiner		       get_hc_wp_grp_size(ext_csd));
136668f490b54b53c715db06e55f9595a672d1c0690eBen Gardiner
136711f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz		regl =	(ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
136868f490b54b53c715db06e55f9595a672d1c0690eBen Gardiner			(ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
136968f490b54b53c715db06e55f9595a672d1c0690eBen Gardiner			(ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
137068f490b54b53c715db06e55f9595a672d1c0690eBen Gardiner			ext_csd[EXT_CSD_ENH_START_ADDR_0];
1371a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Enhanced User Data Start Address"
137211f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz			" [ENH_START_ADDR]: 0x%06x\n", regl);
13734e85023654b356511612547207a4cb643fb3db16Ben Gardiner		printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
137411f2ceabc4ad3f0dd568e0ce68166e4803e0615bOliver Metz				1l : 512l) * regl);
1375a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1376a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441]: reserved [135] */
1377a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Bad Block Management mode"
1378a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
1379a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* A441: reserved [133:0] */
1380a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1381a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	/* B45 */
1382a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	if (ext_csd_rev >= 6) {
1383a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		int j;
1384a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* tcase_support ext_csd[132] not readable */
1385a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
1386a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[131]);
1387a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Program CID/CSD in DDR mode support"
1388a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
1389a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			   ext_csd[130]);
1390a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1391a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		for (j = 127; j >= 64; j--)
1392a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf("Vendor Specific Fields"
1393a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO				" [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
1394a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO				j, ext_csd[j]);
1395a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1396a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
1397a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[63]);
1398a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
1399a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[62]);
1400a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
1401a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("1st initialization after disabling sector"
1402a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
1403a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[60]);
1404a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
1405a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			ext_csd[59]);
1406a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Number of addressed group to be Released"
1407a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			"[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
1408a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Exception events control"
1409a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
1410a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(ext_csd[57] << 8) | ext_csd[56]);
1411a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Exception events status"
1412a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			"[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
1413a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(ext_csd[55] << 8) | ext_csd[54]);
1414a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Extended Partitions Attribute"
1415a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
1416a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			(ext_csd[53] << 8) | ext_csd[52]);
1417a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1418a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		for (j = 51; j >= 37; j--)
1419a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			printf("Context configuration"
1420a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO				" [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
1421a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1422a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Packed command status"
1423a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
1424a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Packed command failure index"
1425a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
1426a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		printf("Power Off Notification"
1427a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO			" [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
142864f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi		printf("Control to turn the Cache ON/OFF"
142964f63a3d2693e95b45c6ba743570b3374a45043bOleg Matcovschi			" [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
1430a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/* flush_cache ext_csd[32] not readable */
1431a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO		/*Reserved [31:0] */
1432a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO	}
1433a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLARO
1434a5bf4a2030a9dcfbcebf1b647e65c1e936a56e14Giuseppe CAVALLAROout_free:
1435a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM	return ret;
1436a8bfde77e0e275070791138d60b75d1cc293daf0Johan RUDHOLM}
143721bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
143821bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardiint do_sanitize(int nargs, char **argv)
143921bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi{
144021bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	int fd, ret;
144121bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	char *device;
144221bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
144321bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
144421bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi			exit(1));
144521bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
144621bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	device = argv[1];
144721bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
144821bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	fd = open(device, O_RDWR);
144921bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	if (fd < 0) {
145021bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi		perror("open");
145121bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi		exit(1);
145221bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	}
145321bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
145421bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
145521bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	if (ret) {
145621bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
145721bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi			1, EXT_CSD_SANITIZE_START, device);
145821bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi		exit(1);
145921bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	}
146021bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
146121bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi	return ret;
146221bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
146321bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi}
146421bb473fc58366b872efe31e1da7831cad4b92faYaniv Gardi
1465c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev#define DO_IO(func, fd, buf, nbyte)					\
1466c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	({												\
1467c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ssize_t ret = 0, r;							\
1468c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		do {										\
1469c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			r = func(fd, buf + ret, nbyte - ret);	\
1470c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			if (r < 0 && errno != EINTR) {			\
1471c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				ret = -1;							\
1472c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				break;								\
1473c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			}										\
1474c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			else if (r > 0)							\
1475c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				ret += r;							\
1476c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		} while (r != 0 && (size_t)ret != nbyte);	\
1477c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev													\
1478c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ret;										\
1479c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	})
1480c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1481c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevenum rpmb_op_type {
1482c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	MMC_RPMB_WRITE_KEY = 0x01,
1483c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	MMC_RPMB_READ_CNT  = 0x02,
1484c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	MMC_RPMB_WRITE     = 0x03,
1485c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	MMC_RPMB_READ      = 0x04,
1486c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1487c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* For internal usage only, do not use it directly */
1488c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	MMC_RPMB_READ_RESP = 0x05
1489c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev};
1490c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1491c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevstruct rpmb_frame {
1492c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int8_t  stuff[196];
1493c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int8_t  key_mac[32];
1494c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int8_t  data[256];
1495c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int8_t  nonce[16];
1496c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int32_t write_counter;
1497c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int16_t addr;
1498c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int16_t block_count;
1499c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int16_t result;
1500c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int16_t req_resp;
1501c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev};
1502c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1503c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev/* Performs RPMB operation.
1504c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev *
1505c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev * @fd: RPMB device on which we should perform ioctl command
1506c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev * @frame_in: input RPMB frame, should be properly inited
1507c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev * @frame_out: output (result) RPMB frame. Caller is responsible for checking
1508c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev *             result and req_resp for output frame.
1509c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev * @out_cnt: count of outer frames. Used only for multiple blocks reading,
1510c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev *           in the other cases -EINVAL will be returned.
1511c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev */
1512c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevstatic int do_rpmb_op(int fd,
1513c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev					  const struct rpmb_frame *frame_in,
1514c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev					  struct rpmb_frame *frame_out,
1515c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev					  unsigned int out_cnt)
1516c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1517c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int err;
1518c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	u_int16_t rpmb_type;
1519c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1520c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	struct mmc_ioc_cmd ioc = {
1521c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.arg        = 0x0,
1522c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.blksz      = 512,
1523c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.blocks     = 1,
1524c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.write_flag = 1,
1525c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.opcode     = MMC_WRITE_MULTIPLE_BLOCK,
1526c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.flags      = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
1527c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.data_ptr   = (uintptr_t)frame_in
1528c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	};
1529c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1530c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (!frame_in || !frame_out || !out_cnt)
1531c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		return -EINVAL;
1532c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1533c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	rpmb_type = be16toh(frame_in->req_resp);
1534c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1535c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	switch(rpmb_type) {
1536c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	case MMC_RPMB_WRITE:
1537c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	case MMC_RPMB_WRITE_KEY:
1538c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (out_cnt != 1) {
1539c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -EINVAL;
1540c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1541c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1542c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1543c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Write request */
1544c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.write_flag |= (1<<31);
1545c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = ioctl(fd, MMC_IOC_CMD, &ioc);
1546c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (err < 0) {
1547c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -errno;
1548c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1549c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1550c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1551c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Result request */
1552c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		memset(frame_out, 0, sizeof(*frame_out));
1553c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		frame_out->req_resp = htobe16(MMC_RPMB_READ_RESP);
1554c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.write_flag = 1;
1555c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.data_ptr = (uintptr_t)frame_out;
1556c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = ioctl(fd, MMC_IOC_CMD, &ioc);
1557c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (err < 0) {
1558c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -errno;
1559c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1560c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1561c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1562c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Get response */
1563c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.write_flag = 0;
1564c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.opcode = MMC_READ_MULTIPLE_BLOCK;
1565c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = ioctl(fd, MMC_IOC_CMD, &ioc);
1566c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (err < 0) {
1567c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -errno;
1568c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1569c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1570c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1571c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		break;
1572c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	case MMC_RPMB_READ_CNT:
1573c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (out_cnt != 1) {
1574c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -EINVAL;
1575c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1576c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1577c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* fall through */
1578c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1579c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	case MMC_RPMB_READ:
1580c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Request */
1581c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = ioctl(fd, MMC_IOC_CMD, &ioc);
1582c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (err < 0) {
1583c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -errno;
1584c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1585c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1586c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1587c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Get response */
1588c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.write_flag = 0;
1589c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.opcode   = MMC_READ_MULTIPLE_BLOCK;
1590c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.blocks   = out_cnt;
1591c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ioc.data_ptr = (uintptr_t)frame_out;
1592c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = ioctl(fd, MMC_IOC_CMD, &ioc);
1593c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (err < 0) {
1594c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			err = -errno;
1595c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			goto out;
1596c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1597c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1598c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		break;
1599c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	default:
1600c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		err = -EINVAL;
1601c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		goto out;
1602c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1603c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1604c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevout:
1605c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return err;
1606c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1607c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1608c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevint do_rpmb_write_key(int nargs, char **argv)
1609c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1610c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int ret, dev_fd, key_fd;
1611c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	struct rpmb_frame frame_in = {
1612c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.req_resp = htobe16(MMC_RPMB_WRITE_KEY)
1613c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}, frame_out;
1614c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1615c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	CHECK(nargs != 3, "Usage: mmc rpmb write-key </path/to/mmcblkXrpmb> </path/to/key>\n",
1616c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1));
1617c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1618c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	dev_fd = open(argv[1], O_RDWR);
1619c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (dev_fd < 0) {
1620c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("device open");
1621c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1622c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1623c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1624c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (0 == strcmp(argv[2], "-"))
1625c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		key_fd = STDIN_FILENO;
1626c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	else {
1627c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		key_fd = open(argv[2], O_RDONLY);
1628c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (key_fd < 0) {
1629c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("can't open key file");
1630c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1631c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1632c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1633c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1634c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Read the auth key */
1635c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = DO_IO(read, key_fd, frame_in.key_mac, sizeof(frame_in.key_mac));
1636c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret < 0) {
1637c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("read the key");
1638c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1639c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	} else if (ret != sizeof(frame_in.key_mac)) {
1640c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
1641c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   (unsigned long)sizeof(frame_in.key_mac),
1642c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   ret);
1643c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1644c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1645c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1646c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Execute RPMB op */
1647c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1648c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1649c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("RPMB ioctl failed");
1650c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1651c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1652c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1653c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1654c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (frame_out.result != 0) {
1655c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("RPMB operation failed, retcode 0x%04x\n",
1656c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   be16toh(frame_out.result));
1657c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1658c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1659c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1660c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	close(dev_fd);
1661c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (key_fd != STDIN_FILENO)
1662c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		close(key_fd);
1663c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1664c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return ret;
1665c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1666c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1667c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevint rpmb_read_counter(int dev_fd, unsigned int *cnt)
1668c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1669c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int ret;
1670c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	struct rpmb_frame frame_in = {
1671c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.req_resp = htobe16(MMC_RPMB_READ_CNT)
1672c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}, frame_out;
1673c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1674c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Execute RPMB op */
1675c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1676c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1677c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("RPMB ioctl failed");
1678c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1679c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1680c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1681c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1682c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (frame_out.result != 0)
1683c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		return be16toh(frame_out.result);
1684c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1685c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	*cnt = be32toh(frame_out.write_counter);
1686c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1687c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return 0;
1688c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1689c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1690c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevint do_rpmb_read_counter(int nargs, char **argv)
1691c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1692c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int ret, dev_fd;
1693c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	unsigned int cnt;
1694c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1695c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	CHECK(nargs != 2, "Usage: mmc rpmb read-counter </path/to/mmcblkXrpmb>\n",
1696c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1));
1697c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1698c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	dev_fd = open(argv[1], O_RDWR);
1699c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (dev_fd < 0) {
1700c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("device open");
1701c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1702c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1703c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1704c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = rpmb_read_counter(dev_fd, &cnt);
1705c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1706c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1707c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1708c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("RPMB operation failed, retcode 0x%04x\n", ret);
1709c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1710c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1711c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1712c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	close(dev_fd);
1713c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1714c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	printf("Counter value: 0x%08x\n", cnt);
1715c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1716c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return ret;
1717c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1718c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1719c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevint do_rpmb_read_block(int nargs, char **argv)
1720c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1721c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int i, ret, dev_fd, data_fd, key_fd = -1;
1722c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	uint16_t addr, blocks_cnt;
1723c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	unsigned char key[32];
1724c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	struct rpmb_frame frame_in = {
1725c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.req_resp    = htobe16(MMC_RPMB_READ),
1726c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}, *frame_out_p;
1727c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1728c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	CHECK(nargs != 5 && nargs != 6, "Usage: mmc rpmb read-block </path/to/mmcblkXrpmb> <address> <blocks count> </path/to/output_file> [/path/to/key]\n",
1729c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1));
1730c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1731c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	dev_fd = open(argv[1], O_RDWR);
1732c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (dev_fd < 0) {
1733c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("device open");
1734c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1735c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1736c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1737c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Get block address */
1738c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	errno = 0;
1739c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	addr = strtol(argv[2], NULL, 0);
1740c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (errno) {
1741c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("incorrect address");
1742c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1743c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1744c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	frame_in.addr = htobe16(addr);
1745c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1746c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Get blocks count */
1747c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	errno = 0;
1748c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	blocks_cnt = strtol(argv[3], NULL, 0);
1749c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (errno) {
1750c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("incorrect blocks count");
1751c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1752c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1753c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1754c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (!blocks_cnt) {
1755c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("please, specify valid blocks count number\n");
1756c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1757c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1758c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1759c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	frame_out_p = calloc(sizeof(*frame_out_p), blocks_cnt);
1760c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (!frame_out_p) {
1761c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("can't allocate memory for RPMB outer frames\n");
1762c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1763c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1764c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1765c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Write 256b data */
1766c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (0 == strcmp(argv[4], "-"))
1767c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		data_fd = STDOUT_FILENO;
1768c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	else {
1769c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		data_fd = open(argv[4], O_WRONLY | O_CREAT | O_APPEND,
1770c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev					   S_IRUSR | S_IWUSR);
1771c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (data_fd < 0) {
1772c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("can't open output file");
1773c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1774c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1775c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1776c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1777c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Key is specified */
1778c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (nargs == 6) {
1779c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (0 == strcmp(argv[5], "-"))
1780c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			key_fd = STDIN_FILENO;
1781c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		else {
1782c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			key_fd = open(argv[5], O_RDONLY);
1783c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			if (key_fd < 0) {
1784c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				perror("can't open input key file");
1785c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				exit(1);
1786c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			}
1787c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1788c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1789c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ret = DO_IO(read, key_fd, key, sizeof(key));
1790c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (ret < 0) {
1791c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("read the key data");
1792c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1793c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		} else if (ret != sizeof(key)) {
1794c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			printf("Data must be %lu bytes length, but we read only %d, exit\n",
1795c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				   (unsigned long)sizeof(key),
1796c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				   ret);
1797c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1798c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1799c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1800c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1801c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Execute RPMB op */
1802c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = do_rpmb_op(dev_fd, &frame_in, frame_out_p, blocks_cnt);
1803c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1804c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("RPMB ioctl failed");
1805c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1806c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1807c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1808c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1809c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (frame_out_p[blocks_cnt - 1].result != 0) {
1810c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("RPMB operation failed, retcode 0x%04x\n",
1811c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   be16toh(frame_out_p[blocks_cnt - 1].result));
1812c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1813c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1814c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1815c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Do we have to verify data against key? */
1816c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (nargs == 6) {
1817c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		unsigned char mac[32];
1818c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		hmac_sha256_ctx ctx;
1819c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		struct rpmb_frame *frame_out = NULL;
1820c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1821c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		hmac_sha256_init(&ctx, key, sizeof(key));
1822c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		for (i = 0; i < blocks_cnt; i++) {
1823c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			frame_out = &frame_out_p[i];
1824c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			hmac_sha256_update(&ctx, frame_out->data,
1825c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev							   sizeof(*frame_out) -
1826c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev								   offsetof(struct rpmb_frame, data));
1827c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1828c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1829c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		hmac_sha256_final(&ctx, mac, sizeof(mac));
1830c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1831c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Impossible */
1832c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		assert(frame_out);
1833c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1834c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		/* Compare calculated MAC and MAC from last frame */
1835c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (memcmp(mac, frame_out->key_mac, sizeof(mac))) {
1836c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			printf("RPMB MAC missmatch\n");
1837c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1838c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1839c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1840c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1841c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Write data */
1842c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	for (i = 0; i < blocks_cnt; i++) {
1843c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		struct rpmb_frame *frame_out = &frame_out_p[i];
1844c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		ret = DO_IO(write, data_fd, frame_out->data, sizeof(frame_out->data));
1845c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (ret < 0) {
1846c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("write the data");
1847c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1848c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		} else if (ret != sizeof(frame_out->data)) {
1849c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			printf("Data must be %lu bytes length, but we wrote only %d, exit\n",
1850c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				   (unsigned long)sizeof(frame_out->data),
1851c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev				   ret);
1852c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1853c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1854c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1855c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1856c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	free(frame_out_p);
1857c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	close(dev_fd);
1858c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (data_fd != STDOUT_FILENO)
1859c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		close(data_fd);
1860c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (key_fd != -1 && key_fd != STDIN_FILENO)
1861c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		close(key_fd);
1862c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1863c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return ret;
1864c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1865c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1866c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaevint do_rpmb_write_block(int nargs, char **argv)
1867c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev{
1868c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	int ret, dev_fd, key_fd, data_fd;
1869c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	unsigned char key[32];
1870c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	uint16_t addr;
1871c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	unsigned int cnt;
1872c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	struct rpmb_frame frame_in = {
1873c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.req_resp    = htobe16(MMC_RPMB_WRITE),
1874c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		.block_count = htobe16(1)
1875c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}, frame_out;
1876c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1877c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	CHECK(nargs != 5, "Usage: mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>\n",
1878c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1));
1879c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1880c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	dev_fd = open(argv[1], O_RDWR);
1881c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (dev_fd < 0) {
1882c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("device open");
1883c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1884c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1885c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1886c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = rpmb_read_counter(dev_fd, &cnt);
1887c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1888c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1889c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("RPMB read counter operation failed, retcode 0x%04x\n", ret);
1890c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1891c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1892c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	frame_in.write_counter = htobe32(cnt);
1893c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1894c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Get block address */
1895c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	errno = 0;
1896c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	addr = strtol(argv[2], NULL, 0);
1897c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (errno) {
1898c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("incorrect address");
1899c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1900c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1901c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	frame_in.addr = htobe16(addr);
1902c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1903c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Read 256b data */
1904c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (0 == strcmp(argv[3], "-"))
1905c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		data_fd = STDIN_FILENO;
1906c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	else {
1907c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		data_fd = open(argv[3], O_RDONLY);
1908c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (data_fd < 0) {
1909c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("can't open input file");
1910c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1911c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1912c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1913c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1914c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = DO_IO(read, data_fd, frame_in.data, sizeof(frame_in.data));
1915c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret < 0) {
1916c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("read the data");
1917c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1918c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	} else if (ret != sizeof(frame_in.data)) {
1919c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("Data must be %lu bytes length, but we read only %d, exit\n",
1920c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   (unsigned long)sizeof(frame_in.data),
1921c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   ret);
1922c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1923c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1924c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1925c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Read the auth key */
1926c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (0 == strcmp(argv[4], "-"))
1927c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		key_fd = STDIN_FILENO;
1928c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	else {
1929c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		key_fd = open(argv[4], O_RDONLY);
1930c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		if (key_fd < 0) {
1931c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			perror("can't open key file");
1932c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			exit(1);
1933c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		}
1934c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1935c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1936c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = DO_IO(read, key_fd, key, sizeof(key));
1937c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret < 0) {
1938c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("read the key");
1939c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1940c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	} else if (ret != sizeof(key)) {
1941c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
1942c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   (unsigned long)sizeof(key),
1943c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   ret);
1944c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1945c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1946c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1947c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Calculate HMAC SHA256 */
1948c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	hmac_sha256(
1949c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		key, sizeof(key),
1950c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		frame_in.data, sizeof(frame_in) - offsetof(struct rpmb_frame, data),
1951c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		frame_in.key_mac, sizeof(frame_in.key_mac));
1952c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1953c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Execute RPMB op */
1954c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1955c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (ret != 0) {
1956c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		perror("RPMB ioctl failed");
1957c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1958c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1959c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1960c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	/* Check RPMB response */
1961c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (frame_out.result != 0) {
1962c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		printf("RPMB operation failed, retcode 0x%04x\n",
1963c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev			   be16toh(frame_out.result));
1964c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		exit(1);
1965c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	}
1966c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1967c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	close(dev_fd);
1968c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (data_fd != STDIN_FILENO)
1969c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		close(data_fd);
1970c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	if (key_fd != STDIN_FILENO)
1971c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev		close(key_fd);
1972c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev
1973c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev	return ret;
1974c6cb053ec59e7667e2140c320e2b7d5a90592a20Roman Peniaev}
1975d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1976d0b46442b50794217e53b2455c1344c548d9d088Al Cooperint do_cache_ctrl(int value, int nargs, char **argv)
1977d0b46442b50794217e53b2455c1344c548d9d088Al Cooper{
1978d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	__u8 ext_csd[512];
1979d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	int fd, ret;
1980d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	char *device;
1981d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1982d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	CHECK(nargs != 2, "Usage: mmc cache enable </path/to/mmcblkX>\n",
1983d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			  exit(1));
1984d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1985d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	device = argv[1];
1986d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1987d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	fd = open(device, O_RDWR);
1988d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	if (fd < 0) {
1989d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		perror("open");
1990d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		exit(1);
1991d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	}
1992d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1993d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	ret = read_extcsd(fd, ext_csd);
1994d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	if (ret) {
1995d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
1996d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		exit(1);
1997d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	}
1998d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
1999d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V4_5) {
2000d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		fprintf(stderr,
2001d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			"The CACHE option is only availabe on devices >= "
2002d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			"MMC 4.5 %s\n", device);
2003d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		exit(1);
2004d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	}
2005d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
2006d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	/* If the cache size is zero, this device does not have a cache */
2007d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	if (!(ext_csd[EXT_CSD_CACHE_SIZE_3] ||
2008d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			ext_csd[EXT_CSD_CACHE_SIZE_2] ||
2009d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			ext_csd[EXT_CSD_CACHE_SIZE_1] ||
2010d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			ext_csd[EXT_CSD_CACHE_SIZE_0])) {
2011d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		fprintf(stderr,
2012d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			"The CACHE option is not available on %s\n",
2013d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			device);
2014d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		exit(1);
2015d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	}
2016d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	ret = write_extcsd_value(fd, EXT_CSD_CACHE_CTRL, value);
2017d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	if (ret) {
2018d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		fprintf(stderr,
2019d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			"Could not write 0x%02x to EXT_CSD[%d] in %s\n",
2020d0b46442b50794217e53b2455c1344c548d9d088Al Cooper			value, EXT_CSD_CACHE_CTRL, device);
2021d0b46442b50794217e53b2455c1344c548d9d088Al Cooper		exit(1);
2022d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	}
2023d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
2024d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	return ret;
2025d0b46442b50794217e53b2455c1344c548d9d088Al Cooper}
2026d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
2027d0b46442b50794217e53b2455c1344c548d9d088Al Cooperint do_cache_en(int nargs, char **argv)
2028d0b46442b50794217e53b2455c1344c548d9d088Al Cooper{
2029d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	return do_cache_ctrl(1, nargs, argv);
2030d0b46442b50794217e53b2455c1344c548d9d088Al Cooper}
2031d0b46442b50794217e53b2455c1344c548d9d088Al Cooper
2032d0b46442b50794217e53b2455c1344c548d9d088Al Cooperint do_cache_dis(int nargs, char **argv)
2033d0b46442b50794217e53b2455c1344c548d9d088Al Cooper{
2034d0b46442b50794217e53b2455c1344c548d9d088Al Cooper	return do_cache_ctrl(0, nargs, argv);
2035d0b46442b50794217e53b2455c1344c548d9d088Al Cooper}
2036