blob: 956e74228cb7f3d82be4dc39e09141090b95676e [file] [log] [blame]
/*
* This file is part of the flashrom project.
* It handles everything related to status registers of the JEDEC family 25.
*
* Copyright (C) 2007, 2008, 2009, 2010 Carl-Daniel Hailfinger
* Copyright (C) 2008 coresystems GmbH
* Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
* Copyright (C) 2012 Stefan Tauner
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "flash.h"
#include "programmer.h"
#include "chipdrivers.h"
#include "spi.h"
static int opaque_restore_status(struct flashctx *flash, uint8_t status)
{
msg_cdbg("restoring chip status (0x%02x)\n", status);
return flash->mst->opaque.write_register(flash, STATUS1, status);
}
/* A common block protection disable that tries to unset the status register bits masked by 0x3C. */
int opaque_disable_blockprotect(struct flashctx *flash)
{
uint8_t status;
int result;
const uint8_t bp_mask = 0x3C;
const uint8_t lock_mask = 0;
const uint8_t wp_mask = 0;
const uint8_t unprotect_mask = 0xFF;
int ret = flash->mst->opaque.read_register(flash, STATUS1, &status);
if (ret)
return ret;
if ((status & bp_mask) == 0) {
msg_cdbg2("Block protection is disabled.\n");
return 0;
}
/* Restore status register content upon exit in finalize_flash_access(). */
register_chip_restore(opaque_restore_status, flash, status);
msg_cdbg("Some block protection in effect, disabling... ");
if ((status & lock_mask) != 0) {
msg_cdbg("\n\tNeed to disable the register lock first... ");
if (wp_mask != 0 && (status & wp_mask) == 0) {
msg_cerr("Hardware protection is active, disabling write protection is impossible.\n");
return 1;
}
/* All bits except the register lock bit (often called SPRL, SRWD, WPEN) are readonly. */
result = flash->mst->opaque.write_register(flash, STATUS1, status & ~lock_mask);
if (result) {
msg_cerr("Could not write status register 1.\n");
return result;
}
ret = flash->mst->opaque.read_register(flash, STATUS1, &status);
if (ret)
return ret;
if ((status & lock_mask) != 0) {
msg_cerr("Unsetting lock bit(s) failed.\n");
return 1;
}
msg_cdbg("done.\n");
}
/* Global unprotect. Make sure to mask the register lock bit as well. */
result = flash->mst->opaque.write_register(flash, STATUS1, status & ~(bp_mask | lock_mask) & unprotect_mask);
if (result) {
msg_cerr("Could not write status register 1.\n");
return result;
}
ret = flash->mst->opaque.read_register(flash, STATUS1, &status);
if (ret)
return ret;
if ((status & bp_mask) != 0) {
msg_cerr("Block protection could not be disabled!\n");
if (flash->chip->printlock)
flash->chip->printlock(flash);
return 1;
}
msg_cdbg("disabled.\n");
return 0;
}