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