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