blob: 9fecc756c728b6811a7d25e8004ea22fb33209ba [file] [log] [blame]
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <string>
#include <android-base/logging.h>
#if !defined(ARCH_X86)
#include "mmc-mtk-ioctl.h"
#include "ufs-mtk-ioctl.h"
#include <sys/ioctl.h>
#endif
#include "boot_region_control_private.h"
extern "C"{
#include "mtk_ioctl.h"
}
namespace android {
namespace bootable {
#if !defined(ARCH_X86)
static bool mmc_read_extcsd(int fd, uint8_t *ext_csd)
{
struct mmc_ioc_cmd mmc_ioctl_cmd;
memset(ext_csd, 0, sizeof(uint8_t) * 512);
memset(&mmc_ioctl_cmd, 0, sizeof(mmc_ioctl_cmd));
mmc_ioctl_cmd.blocks = 1;
mmc_ioctl_cmd.blksz = 512;
mmc_ioctl_cmd.opcode = MMC_SEND_EXT_CSD;
mmc_ioctl_cmd.flags = MMC_CMD_ADTC | MMC_RSP_R1;
mmc_ioc_cmd_set_data(mmc_ioctl_cmd, ext_csd);
if (ioctl(fd, MMC_IOC_CMD, &mmc_ioctl_cmd)) {
LOG(ERROR) << "ioctl error, mmc_read_extcsd fail";
return false;
}
return true;
}
static bool mmc_switch_bootpart(int fd, uint8_t *ext_csd, uint8_t bootpart)
{
struct mmc_ioc_cmd mmc_ioctl_cmd;
uint8_t val;
val = (ext_csd[EXT_CSD_PART_CONFIG] & ~(0x38)) | (bootpart << 3);
memset(&mmc_ioctl_cmd, 0, sizeof(mmc_ioctl_cmd));
mmc_ioctl_cmd.opcode = MMC_SWITCH;
mmc_ioctl_cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24)
| (EXT_CSD_PART_CONFIG << 16)
| val << 8
| EXT_CSD_CMD_SET_NORMAL;
mmc_ioctl_cmd.flags = MMC_CMD_AC | MMC_RSP_R1B;
mmc_ioc_cmd_set_data(mmc_ioctl_cmd, ext_csd);
if (ioctl(fd, MMC_IOC_CMD, &mmc_ioctl_cmd)) {
LOG(ERROR) << "ioctl error, mmc_switch_bootpart fail";
return false;
}
return true;
}
static bool emmc_set_active_boot_part(int bootpart)
{
uint8_t ext_csd[512];
uint8_t cur_bootpart;
int ret = true;
int fd= open("/dev/block/mmcblk0", O_RDWR);
if (fd < 0) {
LOG(ERROR) << "open /dev/block/mmcblk0 fail";
return false;
}
if (!mmc_read_extcsd(fd, ext_csd)) {
LOG(ERROR) << "Could not read EXT_CSD";
close(fd);
ret = false;
} else {
/* check current boot part */
cur_bootpart = (ext_csd[EXT_CSD_PART_CONFIG] >> 3) & 0x7;
if (cur_bootpart != bootpart) {
if (!mmc_switch_bootpart(fd, ext_csd, bootpart)) {
LOG(ERROR) << "Could not switch boot part";
ret = false;
}
}
close(fd);
}
return ret;
}
static bool ufs_set_active_boot_part(int boot)
{
struct ufs_ioctl_query_data idata;
unsigned char buf[1];
int fd, ret = true;
fd = open("/dev/block/sdc", O_RDWR);
if (fd < 0) {
printf("%s: open device failed, err: %d\n", __func__, fd);
return false;
}
buf[0] = boot; /* 1: BootLU A, 2: BootLU B */
idata.opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
idata.idn = QUERY_ATTR_IDN_BOOT_LUN_EN;
idata.idx = 0;
idata.buf_ptr = &buf[0];
idata.buf_byte = 1;
if (ioctl(fd, UFS_IOCTL_QUERY, &idata) < 0) {
LOG(ERROR) << "ufs_set boot_part old fail";
ret = ioctrl_w_attr("/dev/ufs-bsg0", QUERY_ATTR_IDN_BOOT_LUN_EN, 0, 0, boot);
}
close(fd);
return ret;
}
bool BootControlExt::SetBootRegionSlot(unsigned int slot) {
int boot_part = 0;
LOG(ERROR) << "setActiveBootSlot SetBootRegionSlot " << slot;
/* slot 0 is A , slot 1 is B */
if (slot >= 2) {
LOG(ERROR) << "Wrong Slot value " << slot;
return 0;
}
if(slot)
boot_part = 2;
else
boot_part = 1;
if (!ufs_set_active_boot_part(boot_part))
if (!emmc_set_active_boot_part(boot_part))
return false;
return true;
}
#else
bool BootControlExt::SetBootRegionSlot(unsigned int slot) {
return true;
}
#endif //#if !defined(ARCH_X86)
}
}