+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2013 by Andrey Yurovsky *
* Andrey Yurovsky <yurovsky@gmail.com> *
- * *
- * 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; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * 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. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "imp.h"
+#include <jtag/jtag.h>
+#include <target/cortex_m.h>
+
/* At this time, the SAM4L Flash is available in these capacities:
* ATSAM4Lx4xx: 256KB (512 pages)
* ATSAM4Lx2xx: 128KB (256 pages)
* ATSAM4Lx8xx: 512KB (1024 pages)
*/
-/* There are 16 lockable regions regardless of overall capacity. The number
+/* There are 16 lockable regions regardless of overall capacity. The number
* of pages per sector is therefore dependant on capacity. */
#define SAM4L_NUM_SECTORS 16
/* Locations in memory map */
-#define SAM4L_FLASH 0x00000000 /* Flash region */
+#define SAM4L_FLASH ((uint32_t)0x00000000) /* Flash region */
#define SAM4L_FLASH_USER 0x00800000 /* Flash user page region */
#define SAM4L_FLASHCALW 0x400A0000 /* Flash controller */
#define SAM4L_CHIPID 0x400E0740 /* Chip Identification */
#define SAM4L_FMCD_CMDKEY 0xA5UL /* 'key' to issue commands, see 14.10.2 */
+
+/* SMAP registers and bits */
+#define SMAP_BASE 0x400A3000
+
+#define SMAP_SCR (SMAP_BASE + 8)
+#define SMAP_SCR_HCR (1 << 1)
+
+
struct sam4l_chip_info {
uint32_t id;
uint32_t exid;
uint32_t page_size;
int num_pages;
int sector_size;
- int pages_per_sector;
+ unsigned int pages_per_sector;
bool probed;
struct target *target;
- struct sam4l_info *next;
};
-static struct sam4l_info *sam4l_chips;
static int sam4l_flash_wait_until_ready(struct target *target)
{
FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command)
{
- struct sam4l_info *chip = sam4l_chips;
-
- while (chip) {
- if (chip->target == bank->target)
- break;
- chip = chip->next;
- }
-
- if (!chip) {
- /* Create a new chip */
- chip = calloc(1, sizeof(*chip));
- if (!chip)
- return ERROR_FAIL;
-
- chip->target = bank->target;
- chip->probed = false;
-
- bank->driver_priv = chip;
-
- /* Insert it into the chips list (at head) */
- chip->next = sam4l_chips;
- sam4l_chips = chip;
- }
-
if (bank->base != SAM4L_FLASH) {
- LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32
+ LOG_ERROR("Address " TARGET_ADDR_FMT
+ " invalid bank address (try 0x%08" PRIx32
"[at91sam4l series] )",
bank->base, SAM4L_FLASH);
return ERROR_FAIL;
}
+ struct sam4l_info *chip;
+ chip = calloc(1, sizeof(*chip));
+ if (!chip) {
+ LOG_ERROR("No memory for flash bank chip info");
+ return ERROR_FAIL;
+ }
+
+ chip->target = bank->target;
+ chip->probed = false;
+
+ bank->driver_priv = chip;
+
return ERROR_OK;
}
/* Issue a quick page read to verify that we've erased this page */
res = sam4l_flash_command(bank->target, SAM4L_FCMD_QPR, pn);
if (res != ERROR_OK) {
- LOG_ERROR("Quick page read %d failed", pn);
+ LOG_ERROR("Quick page read %" PRIu32 " failed", pn);
return res;
}
chip->flash_kb = 512;
break;
default:
- LOG_ERROR("Unknown flash size (chip ID is %08X), assuming 128K", id);
+ LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id);
chip->flash_kb = 128;
break;
}
/* Fill out the sector information: all SAM4L sectors are the same size and
* there is always a fixed number of them. */
- for (int i = 0; i < bank->num_sectors; i++) {
+ for (unsigned int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].size = chip->sector_size;
bank->sectors[i].offset = i * chip->sector_size;
/* mark as unknown */
/* Done */
chip->probed = true;
- LOG_INFO("SAM4L MCU: %s (Rev %c) (%uKB Flash with %d %dB pages, %uKB RAM)",
- chip->details ? chip->details->name : "unknown", 'A' + (id & 0xF),
+ LOG_INFO("SAM4L MCU: %s (Rev %c) (%" PRIu32 "KB Flash with %d %" PRIu32 "B pages, %" PRIu32 "KB RAM)",
+ chip->details ? chip->details->name : "unknown", (char)('A' + (id & 0xF)),
chip->flash_kb, chip->num_pages, chip->page_size, chip->ram_kb);
return ERROR_OK;
return res;
st >>= 16; /* There are 16 lock region bits in the upper half word */
- for (int i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_protected = !!(st & (1<<i));
+ for (unsigned int i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = !!(st & (1<<i));
return ERROR_OK;
}
-static int sam4l_protect(struct flash_bank *bank, int set, int first, int last)
+static int sam4l_protect(struct flash_bank *bank, int set, unsigned int first,
+ unsigned int last)
{
- struct sam4l_info *chip = sam4l_chips;
+ struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
/* Make sure the pages make sense. */
if (first >= bank->num_sectors || last >= bank->num_sectors) {
- LOG_ERROR("Protect range %d - %d not valid (%d sectors total)", first, last,
+ LOG_ERROR("Protect range %u - %u not valid (%u sectors total)", first, last,
bank->num_sectors);
return ERROR_FAIL;
}
/* Try to lock or unlock each sector in the range. This is done by locking
* a region containing one page in that sector, we arbitrarily choose the 0th
* page in the sector. */
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
int res;
res = sam4l_flash_command(bank->target,
return ERROR_OK;
}
-static int sam4l_erase(struct flash_bank *bank, int first, int last)
+static int sam4l_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
{
int ret;
struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
/* Make sure the pages make sense. */
if (first >= bank->num_sectors || last >= bank->num_sectors) {
- LOG_ERROR("Erase range %d - %d not valid (%d sectors total)", first, last,
+ LOG_ERROR("Erase range %u - %u not valid (%u sectors total)", first, last,
bank->num_sectors);
return ERROR_FAIL;
}
return ret;
}
} else {
- LOG_DEBUG("Erasing sectors %d through %d...\n", first, last);
+ LOG_DEBUG("Erasing sectors %u through %u...\n", first, last);
/* For each sector... */
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
/* For each page in that sector... */
- for (int j = 0; j < chip->pages_per_sector; j++) {
- int pn = i * chip->pages_per_sector + j;
+ for (unsigned int j = 0; j < chip->pages_per_sector; j++) {
+ unsigned int pn = i * chip->pages_per_sector + j;
bool is_erased = false;
/* Issue the page erase */
ret = sam4l_flash_command(bank->target, SAM4L_FCMD_EP, pn);
if (ret != ERROR_OK) {
- LOG_ERROR("Erasing page %d failed", pn);
+ LOG_ERROR("Erasing page %u failed", pn);
return ret;
}
return ret;
if (!is_erased) {
- LOG_DEBUG("Page %d was not erased.", pn);
+ LOG_DEBUG("Page %u was not erased.", pn);
return ERROR_FAIL;
}
}
-
- /* This sector is definitely erased. */
- bank->sectors[i].is_erased = 1;
}
}
{
int res;
+ LOG_DEBUG("sam4l_write_page address=%08" PRIx32, address);
+
/* Clear the page buffer before we write to it */
res = sam4l_flash_command(target, SAM4L_FCMD_CPB, -1);
if (res != ERROR_OK) {
if (!pg)
return ERROR_FAIL;
+ LOG_DEBUG("sam4l_write_page_partial address=%08" PRIx32 " nb=%08" PRIx32, address, nb);
+
assert(page_offset + nb < chip->page_size);
assert((address % chip->page_size) == 0);
uint32_t nb = 0;
struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
+ LOG_DEBUG("sam4l_write offset=%08" PRIx32 " count=%08" PRIx32, offset, count);
+
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
/* There's at least one aligned page to write out. */
if (count >= chip->page_size) {
+ assert(chip->page_size > 0);
int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0);
for (int i = 0; i < np; i++) {
if (count >= chip->page_size) {
res = sam4l_write_page(chip, bank->target,
- bank->base + (i * chip->page_size),
+ bank->base + offset,
buffer + (i * chip->page_size));
/* Advance one page */
offset += chip->page_size;
count -= chip->page_size;
} else {
res = sam4l_write_page_partial(chip, bank,
- bank->base + (i * chip->page_size),
+ bank->base + offset,
buffer + (i * chip->page_size), 0, count);
/* We're done after this. */
offset += count;
return ERROR_OK;
}
-COMMAND_HANDLER(sam4l_handle_info_command)
+
+COMMAND_HANDLER(sam4l_handle_reset_deassert)
{
- return ERROR_OK;
+ struct target *target = get_current_target(CMD_CTX);
+ int retval = ERROR_OK;
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ /* If the target has been unresponsive before, try to re-establish
+ * communication now - CPU is held in reset by DSU, DAP is working */
+ if (!target_was_examined(target))
+ target_examine_one(target);
+ target_poll(target);
+
+ /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
+ * so we just release reset held by SMAP
+ *
+ * n_RESET (srst) clears the DP, so reenable debug and set vector catch here
+ *
+ * After vectreset SMAP release is not needed however makes no harm
+ */
+ if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
+ retval = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
+ if (retval == ERROR_OK)
+ retval = target_write_u32(target, DCB_DEMCR,
+ TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
+ /* do not return on error here, releasing SMAP reset is more important */
+ }
+
+ int retval2 = target_write_u32(target, SMAP_SCR, SMAP_SCR_HCR);
+ if (retval2 != ERROR_OK)
+ return retval2;
+
+ return retval;
}
static const struct command_registration at91sam4l_exec_command_handlers[] = {
{
- .name = "info",
- .handler = sam4l_handle_info_command,
+ .name = "smap_reset_deassert",
+ .handler = sam4l_handle_reset_deassert,
.mode = COMMAND_EXEC,
- .help = "Print information about the current at91sam4l chip"
- "and its flash configuration.",
+ .help = "deassert internal reset held by SMAP",
+ .usage = "",
},
COMMAND_REGISTRATION_DONE
};
+
static const struct command_registration at91sam4l_command_handlers[] = {
{
.name = "at91sam4l",
COMMAND_REGISTRATION_DONE
};
-struct flash_driver at91sam4l_flash = {
+const struct flash_driver at91sam4l_flash = {
.name = "at91sam4l",
.commands = at91sam4l_command_handlers,
.flash_bank_command = sam4l_flash_bank_command,
.auto_probe = sam4l_probe,
.erase_check = default_flash_blank_check,
.protect_check = sam4l_protect_check,
+ .free_driver_priv = default_flash_free_driver_priv,
};