From: David B. <dbr...@us...> - 2009-12-19 22:34:42
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via 3ac2a440419a52752a5e11eba8ab2722a1fe73bf (commit) via 28f8e9dfb7bfaf87957c95790c3ffe5d9fbd8834 (commit) via abe8b43755fdbc4fe92b966c48b367159deff226 (commit) via 64934d9204dc854d40893634a66e29ece09ad578 (commit) via e25819645ee2beb0818a79006eed9c9cedaaf5bb (commit) via 9abad965ab358c1d598f1354842967cad637b284 (commit) via bfadd79965cc448a75b4f51abaf9523c4ec0ae26 (commit) from 3f18900b19f49a84ba9df56f2e089c255e610011 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3ac2a440419a52752a5e11eba8ab2722a1fe73bf Author: Dean Glazeski <dn...@gm...> Date: Wed Dec 9 12:40:54 2009 -0600 AT91SAM9 NAND flash driver. This creates the TCL interface for configuring an AT91SAM9 NAND flash controller and implements the necessary functions to correctly work with a NAND flash device connected to the chip. This includes updates to the driver list and the Makefile.am to support building the driver and also houses the documentation update in openocd.texi. Signed-off-by: David Brownell <dbr...@us...> diff --git a/doc/openocd.texi b/doc/openocd.texi index d9cb4ea..4244a1e 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4812,6 +4812,41 @@ As noted above, the @command{nand device} command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. +@deffn {NAND Driver} at91sam9 +This driver handles the NAND controllers found on AT91SAM9 family chips from +Atmel. It takes two extra parameters: address of the NAND chip; +address of the ECC controller. +@example +nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 +@end example +AT91SAM9 chips support single-bit ECC hardware. The @code{write_page} and +@code{read_page} methods are used to utilize the ECC hardware unless they are +disabled by using the @command{nand raw_access} command. There are four +additional commands that are needed to fully configure the AT91SAM9 NAND +controller. Two are optional; most boards use the same wiring for ALE/CLE: +@deffn Command {at91sam9 cle} num addr_line +Configure the address line used for latching commands. The @var{num} +parameter is the value shown by @command{nand list}. +@end deffn +@deffn Command {at91sam9 ale} num addr_line +Configure the address line used for latching addresses. The @var{num} +parameter is the value shown by @command{nand list}. +@end deffn + +For the next two commands, it is assumed that the pins have already been +properly configured for input or output. +@deffn Command {at91sam9 rdy_busy} num pio_base_addr pin +Configure the RDY/nBUSY input from the NAND device. The @var{num} +parameter is the value shown by @command{nand list}. @var{pio_base_addr} +is the base address of the PIO controller and @var{pin} is the pin number. +@end deffn +@deffn Command {at91sam9 ce} num pio_base_addr pin +Configure the chip enable input to the NAND device. The @var{num} +parameter is the value shown by @command{nand list}. @var{pio_base_addr} +is the base address of the PIO controller and @var{pin} is the pin number. +@end deffn +@end deffn + @deffn {NAND Driver} davinci This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. diff --git a/src/flash/nand/Makefile.am b/src/flash/nand/Makefile.am index f3033b8..bb9998e 100644 --- a/src/flash/nand/Makefile.am +++ b/src/flash/nand/Makefile.am @@ -24,7 +24,8 @@ NAND_DRIVERS = \ s3c2410.c \ s3c2412.c \ s3c2440.c \ - s3c2443.c + s3c2443.c \ + at91sam9.c noinst_HEADERS = \ arm_io.h \ diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c new file mode 100644 index 0000000..7cfd763 --- /dev/null +++ b/src/flash/nand/at91sam9.c @@ -0,0 +1,750 @@ +/* + * Copyright (C) 2009 by Dean Glazeski + * dn...@gm... + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <target/arm.h> +#include <helper/log.h> +#include "imp.h" +#include "arm_io.h" + +#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */ +#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */ +#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */ +#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */ +#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */ +#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */ +#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */ + +/** + * Representation of a pin on an AT91SAM9 chip. + */ +struct at91sam9_pin { + /** Target this pin is on. */ + struct target *target; + + /** Address of the PIO controller. */ + uint32_t pioc; + + /** Pin number. */ + uint32_t num; +}; + +/** + * Private data for the controller that is stored in the NAND device structure. + */ +struct at91sam9_nand { + /** Target the NAND is attached to. */ + struct target *target; + + /** Address of the ECC controller for NAND. */ + uint32_t ecc; + + /** Address data is written to. */ + uint32_t data; + + /** Address commands are written to. */ + uint32_t cmd; + + /** Address addresses are written to. */ + uint32_t addr; + + /** I/O structure for hosted reads/writes. */ + struct arm_nand_data io; + + /** Pin representing the ready/~busy line. */ + struct at91sam9_pin busy; + + /** Pin representing the chip enable. */ + struct at91sam9_pin ce; +}; + +/** + * Checks if the target is halted and prints an error message if it isn't. + * + * @param target Target to be checked. + * @param label String label for where function is called from. + * @return True if the target is halted. + */ +static int at91sam9_halted(struct target *target, const char *label) +{ + if (target->state == TARGET_HALTED) + return true; + + LOG_ERROR("Target must be halted to use NAND controller (%s)", label); + return false; +} + +/** + * Initialize the AT91SAM9 NAND controller. + * + * @param nand NAND device the controller is attached to. + * @return Success or failure of initialization. + */ +static int at91sam9_init(struct nand_device *nand) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + + if (!at91sam9_halted(target, "init")) { + return ERROR_NAND_OPERATION_FAILED; + } + + return ERROR_OK; +} + +/** + * Enable NAND device attached to a controller. + * + * @param info NAND controller information for controlling NAND device. + * @return Success or failure of the enabling. + */ +static int at91sam9_enable(struct at91sam9_nand *info) +{ + struct target *target = info->target; + + return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num); +} + +/** + * Disable NAND device attached to a controller. + * + * @param info NAND controller information for controlling NAND device. + * @return Success or failure of the disabling. + */ +static int at91sam9_disable(struct at91sam9_nand *info) +{ + struct target *target = info->target; + + return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num); +} + +/** + * Send a command to the NAND device. + * + * @param nand NAND device to write the command to. + * @param command Command to be written. + * @return Success or failure of writing the command. + */ +static int at91sam9_command(struct nand_device *nand, uint8_t command) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + + if (!at91sam9_halted(target, "command")) { + return ERROR_NAND_OPERATION_FAILED; + } + + at91sam9_enable(info); + + return target_write_u8(target, info->cmd, command); +} + +/** + * Reset the AT91SAM9 NAND controller. + * + * @param nand NAND device to be reset. + * @return Success or failure of reset. + */ +static int at91sam9_reset(struct nand_device *nand) +{ + struct at91sam9_nand *info = nand->controller_priv; + + if (!at91sam9_halted(info->target, "reset")) { + return ERROR_NAND_OPERATION_FAILED; + } + + return at91sam9_disable(info); +} + +/** + * Send an address to the NAND device attached to an AT91SAM9 NAND controller. + * + * @param nand NAND device to send the address to. + * @param address Address to be sent. + * @return Success or failure of sending the address. + */ +static int at91sam9_address(struct nand_device *nand, uint8_t address) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + + if (!at91sam9_halted(info->target, "address")) { + return ERROR_NAND_OPERATION_FAILED; + } + + return target_write_u8(target, info->addr, address); +} + +/** + * Read data directly from the NAND device attached to an AT91SAM9 NAND + * controller. + * + * @param nand NAND device to read from. + * @param data Pointer to where the data should be put. + * @return Success or failure of reading the data. + */ +static int at91sam9_read_data(struct nand_device *nand, void *data) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + + if (!at91sam9_halted(info->target, "read data")) { + return ERROR_NAND_OPERATION_FAILED; + } + + return target_read_u8(target, info->data, data); +} + +/** + * Write data directly to the NAND device attached to an AT91SAM9 NAND + * controller. + * + * @param nand NAND device to be written to. + * @param data Data to be written. + * @return Success or failure of the data write. + */ +static int at91sam9_write_data(struct nand_device *nand, uint16_t data) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + + if (!at91sam9_halted(target, "write data")) { + return ERROR_NAND_OPERATION_FAILED; + } + + return target_write_u8(target, info->data, data); +} + +/** + * Determine if the NAND device is ready by looking at the ready/~busy pin. + * + * @param nand NAND device to check. + * @param timeout Time in milliseconds to wait for NAND to be ready. + * @return True if the NAND is ready in the timeout period. + */ +static int at91sam9_nand_ready(struct nand_device *nand, int timeout) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + uint32_t status; + + if (!at91sam9_halted(target, "nand ready")) { + return 0; + } + + do { + target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status); + + if (status & (1 << info->busy.num)) { + return 1; + } + + alive_sleep(1); + } while (timeout-- > 0); + + return 0; +} + +/** + * Read a block of data from the NAND device attached to an AT91SAM9. This + * utilizes the ARM hosted NAND read function. + * + * @param nand NAND device to read from. + * @param data Pointer to where the read data should be placed. + * @param size Size of the data being read. + * @return Success or failure of the hosted read. + */ +static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct arm_nand_data *io = &info->io; + int status; + + if (!at91sam9_halted(info->target, "read block")) { + return ERROR_NAND_OPERATION_FAILED; + } + + io->chunk_size = nand->page_size; + status = arm_nandread(io, data, size); + + return status; +} + +/** + * Write a block of data to a NAND device attached to an AT91SAM9. This uses + * the ARM hosted write function to write the data. + * + * @param nand NAND device to write to. + * @param data Data to be written to device. + * @param size Size of the data being written. + * @return Success or failure of the hosted write. + */ +static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct arm_nand_data *io = &info->io; + int status; + + if (!at91sam9_halted(info->target, "write block")) { + return ERROR_NAND_OPERATION_FAILED; + } + + io->chunk_size = nand->page_size; + status = arm_nandwrite(io, data, size); + + return status; +} + +/** + * Initialize the ECC controller on the AT91SAM9. + * + * @param target Target to configure ECC on. + * @param info NAND controller information for where the ECC is. + * @return Success or failure of initialization. + */ +static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) +{ + if (!info->ecc) { + LOG_ERROR("ECC controller address must be set when not reading raw NAND data"); + return ERROR_NAND_OPERATION_FAILED; + } + + // reset ECC parity registers + return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1); +} + +/** + * Initialize an area for the OOB based on whether a user is requesting the OOB + * data. This determines the size of the OOB and allocates the space in case + * the user has not requested the OOB data. + * + * @param nand NAND device we are creating an OOB for. + * @param oob Pointer to the user supplied OOB area. + * @param size Size of the OOB. + * @return Pointer to an area to store OOB data. + */ +static uint8_t * at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size) +{ + if (!oob) { + // user doesn't want OOB, allocate it + if (nand->page_size == 512) { + *size = 16; + } else if (nand->page_size == 2048) { + *size = 64; + } + + oob = malloc(*size); + if (!oob) { + LOG_ERROR("Unable to allocate space for OOB"); + } + + memset(oob, 0xFF, *size); + } + + return oob; +} + +/** + * Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC + * controller on chip. This makes an attempt to correct any errors that are + * encountered while reading the page of data. + * + * @param nand NAND device to read from + * @param page Page to be read. + * @param data Pointer to where data should be read to. + * @param data_size Size of the data to be read. + * @param oob Pointer to where OOB data should be read to. + * @param oob_size Size of the OOB data to be read. + * @return Success or failure of reading the NAND page. + */ +static int at91sam9_read_page(struct nand_device *nand, uint32_t page, + uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +{ + int retval; + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + uint8_t *oob_data; + uint32_t status; + + retval = at91sam9_ecc_init(target, info); + if (ERROR_OK != retval) { + return retval; + } + + retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); + if (ERROR_OK != retval) { + return retval; + } + + if (data) { + retval = nand_read_data_page(nand, data, data_size); + if (ERROR_OK != retval) { + return retval; + } + } + + oob_data = at91sam9_oob_init(nand, oob, &oob_size); + retval = nand_read_data_page(nand, oob_data, oob_size); + if (ERROR_OK == retval && data) { + target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status); + if (status & 1) { + LOG_ERROR("Error detected!"); + if (status & 4) { + LOG_ERROR("Multiple errors encountered; unrecoverable!"); + } else { + // attempt recovery + uint32_t parity; + + target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); + uint32_t word = (parity & 0x0000FFF0) >> 4; + uint32_t bit = parity & 0x0F; + + data[word] ^= (0x1) << bit; + LOG_INFO("Data word %d, bit %d corrected.", word, bit); + } + } + + if (status & 2) { + // we could write back correct ECC data + LOG_ERROR("Error in ECC bytes detected"); + } + } + + if (!oob) { + // if it wasn't asked for, free it + free(oob_data); + } + + return retval; +} + +/** + * Write a page of data including 1-bit ECC information to a NAND device + * attached to an AT91SAM9 controller. If there is OOB data to be written, + * this will ignore the computed ECC from the ECC controller. + * + * @param nand NAND device to write to. + * @param page Page to write. + * @param data Pointer to data being written. + * @param data_size Size of the data being written. + * @param oob Pointer to OOB data being written. + * @param oob_size Size of the OOB data. + * @return Success or failure of the page write. + */ +static int at91sam9_write_page(struct nand_device *nand, uint32_t page, + uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +{ + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = info->target; + int retval; + uint8_t *oob_data = oob; + uint32_t parity, nparity; + + retval = at91sam9_ecc_init(target, info); + if (ERROR_OK != retval) { + return retval; + } + + retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); + if (ERROR_OK != retval) { + return retval; + } + + if (data) { + retval = nand_write_data_page(nand, data, data_size); + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write data to NAND device"); + return retval; + } + } + + oob_data = at91sam9_oob_init(nand, oob, &oob_size); + + if (!oob) { + // no OOB given, so read in the ECC parity from the ECC controller + target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); + target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity); + + oob_data[0] = (uint8_t) parity; + oob_data[1] = (uint8_t) (parity >> 8); + oob_data[2] = (uint8_t) nparity; + oob_data[3] = (uint8_t) (nparity >> 8); + } + + retval = nand_write_data_page(nand, oob_data, oob_size); + + if (!oob) { + free(oob_data); + } + + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write OOB data to NAND"); + return retval; + } + + retval = nand_write_finish(nand); + + return retval; +} + +/** + * Handle the initial NAND device command for AT91SAM9 controllers. This + * initializes much of the controller information struct to be ready for future + * reads and writes. + */ +NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command) +{ + struct target *target = NULL; + unsigned long chip = 0, ecc = 0; + struct at91sam9_nand *info = NULL; + + LOG_DEBUG("AT91SAM9 NAND Device Command\n"); + + if (CMD_ARGC < 3 || CMD_ARGC > 4) { + LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]); + return ERROR_NAND_OPERATION_FAILED; + } + + target = get_target(CMD_ARGV[1]); + if (!target) { + LOG_ERROR("invalid target: %s", CMD_ARGV[1]); + return ERROR_NAND_OPERATION_FAILED; + } + + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); + if (chip == 0) { + LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]); + return ERROR_NAND_OPERATION_FAILED; + } + + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc); + if (ecc == 0) { + LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]); + return ERROR_NAND_OPERATION_FAILED; + } + } + + info = calloc(1, sizeof(*info)); + if (!info) { + LOG_ERROR("unable to allocate space for controller private data"); + return ERROR_NAND_OPERATION_FAILED; + } + + info->target = target; + info->data = chip; + info->cmd = chip | (1 << 22); + info->addr = chip | (1 << 21); + info->ecc = ecc; + + nand->controller_priv = info; + info->io.target = target; + info->io.data = info->data; + info->io.op = ARM_NAND_NONE; + + return ERROR_OK; +} + +/** + * Handle the AT91SAM9 CLE command for specifying the address line to use for + * writing commands to a NAND device. + */ +COMMAND_HANDLER(handle_at91sam9_cle_command) +{ + struct nand_device *nand = NULL; + struct at91sam9_nand *info = NULL; + unsigned num, address_line; + + if (CMD_ARGC != 2) { + command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command"); + return ERROR_OK; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); + nand = get_nand_device_by_num(num); + if (!nand) { + command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + return ERROR_OK; + } + + info = nand->controller_priv; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); + info->cmd = info->data | (1 << address_line); + + return ERROR_OK; +} + +/** + * Handle the AT91SAM9 ALE command for specifying the address line to use for + * writing addresses to the NAND device. + */ +COMMAND_HANDLER(handle_at91sam9_ale_command) +{ + struct nand_device *nand = NULL; + struct at91sam9_nand *info = NULL; + unsigned num, address_line; + + if (CMD_ARGC != 2) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); + nand = get_nand_device_by_num(num); + if (!nand) { + command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + info = nand->controller_priv; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); + info->addr = info->data | (1 << address_line); + + return ERROR_OK; +} + +/** + * Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the + * RDY/~BUSY line from the NAND device. + */ +COMMAND_HANDLER(handle_at91sam9_rdy_busy_command) +{ + struct nand_device *nand = NULL; + struct at91sam9_nand *info = NULL; + unsigned num, base_pioc, pin_num; + + if (CMD_ARGC != 3) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); + nand = get_nand_device_by_num(num); + if (!nand) { + command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + info = nand->controller_priv; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); + info->busy.pioc = base_pioc; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); + info->busy.num = pin_num; + + return ERROR_OK; +} + +/** + * Handle the AT91SAM9 CE command for specifying the pin that is used to enable + * or disable the NAND device. + */ +COMMAND_HANDLER(handle_at91sam9_ce_command) +{ + struct nand_device *nand = NULL; + struct at91sam9_nand *info = NULL; + unsigned num, base_pioc, pin_num; + + if (CMD_ARGC != 3) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); + nand = get_nand_device_by_num(num); + if (!nand) { + command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + info = nand->controller_priv; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); + info->ce.pioc = base_pioc; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); + info->ce.num = pin_num; + + return ERROR_OK; +} + +static const struct command_registration at91sam9_sub_command_handlers[] = { + { + .name = "cle", + .handler = handle_at91sam9_cle_command, + .mode = COMMAND_CONFIG, + .help = "set command latch enable address line (default is 22)", + .usage = "<device_id> <address_line>", + }, + { + .name = "ale", + .handler = handle_at91sam9_ale_command, + .mode = COMMAND_CONFIG, + .help = "set address latch enable address line (default is 21)", + .usage = "<device_id> <address_line>", + }, + { + .name = "rdy_busy", + .handler = handle_at91sam9_rdy_busy_command, + .mode = COMMAND_CONFIG, + .help = "set the input pin connected to RDY/~BUSY signal (no default)", + .usage = "<device_id> <base_pioc> <pin_num>", + }, + { + .name = "ce", + .handler = handle_at91sam9_ce_command, + .mode = COMMAND_CONFIG, + .help = "set the output pin connected to chip enable signal (no default)", + .usage = "<device_id> <base_pioc> <pin_num>", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration at91sam9_command_handler[] = { + { + .name = "at91sam9", + .mode = COMMAND_ANY, + .help = "AT91SAM9 NAND flash controller commands", + .chain = at91sam9_sub_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +/** + * Structure representing the AT91SAM9 NAND controller. + */ +struct nand_flash_controller at91sam9_nand_controller = { + .name = "at91sam9", + .nand_device_command = at91sam9_nand_device_command, + .commands = at91sam9_command_handler, + .init = at91sam9_init, + .command = at91sam9_command, + .reset = at91sam9_reset, + .address = at91sam9_address, + .read_data = at91sam9_read_data, + .write_data = at91sam9_write_data, + .nand_ready = at91sam9_nand_ready, + .read_block_data = at91sam9_read_block_data, + .write_block_data = at91sam9_write_block_data, + .read_page = at91sam9_read_page, + .write_page = at91sam9_write_page, +}; diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index 1ccc4f4..0e174b2 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -37,6 +37,7 @@ extern struct nand_flash_controller s3c2412_nand_controller; extern struct nand_flash_controller s3c2440_nand_controller; extern struct nand_flash_controller s3c2443_nand_controller; extern struct nand_flash_controller imx31_nand_flash_controller; +extern struct nand_flash_controller at91sam9_nand_controller; /* extern struct nand_flash_controller boundary_scan_nand_controller; */ @@ -51,6 +52,7 @@ static struct nand_flash_controller *nand_flash_controllers[] = &s3c2440_nand_controller, &s3c2443_nand_controller, &imx31_nand_flash_controller, + &at91sam9_nand_controller, /* &boundary_scan_nand_controller, */ NULL }; commit 28f8e9dfb7bfaf87957c95790c3ffe5d9fbd8834 Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:24:59 2009 -0800 oocd_trace buildfixes Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/target/oocd_trace.c b/src/target/oocd_trace.c index b9615bc..2533c40 100644 --- a/src/target/oocd_trace.c +++ b/src/target/oocd_trace.c @@ -238,21 +238,21 @@ static int oocd_trace_start_capture(struct etm_context *etm_ctx) uint32_t control = 0x1; /* 0x1: enabled */ uint32_t trigger_count; - if (((etm_ctx->portmode & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL) - || ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) + if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL) + || ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) { LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } - if ((etm_ctx->portmode & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK) + if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK) { control |= 0x2; /* half rate clock, capture at twice the clock rate */ } /* OpenOCD + trace holds up to 16 million samples, * but trigger counts is set in multiples of 16 */ - trigger_count = (1048576 * etm_ctx->trigger_percent) / 100; + trigger_count = (1048576 * /* trigger_percent */ 50) / 100; /* capturing always starts at address zero */ oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0); commit abe8b43755fdbc4fe92b966c48b367159deff226 Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:09:19 2009 -0800 ETM: add "etm trigger_debug" command In conjunction with manual register setup, this lets the ETM trigger cause entry to debug state. It should make it easier to test and bugfix the ETM code, by enabling non-trace usage and isolating bugs specific to thef ETM support. (One current issue being that trace data collection using the ETB doesn't yet behave.) For example, many ARM9 cores with an ETM should be able to implement four more (simple) breakpoints and two more (simple) watchpoints than the EmbeddedICE supports. Or, they should be able to support complex breakpoints, incorporating ETM sequencer, counters, and/or subroutine entry/exit criteria int criteria used to trigger debug entry. Signed-off-by: David Brownell <dbr...@us...> diff --git a/NEWS b/NEWS index efcf8f6..e122912 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,7 @@ Target Layer: - Exposed DWT registers like cycle counter ETM, ETB - "trigger_percent" command moved ETM --> ETB + - "etm trigger_debug" command added Flash Layer: 'flash bank' and 'nand device' take <bank_name> as first argument. diff --git a/doc/openocd.texi b/doc/openocd.texi index bb3e51a..d9cb4ea 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5512,6 +5512,17 @@ trace stream without an image of the code. @end itemize @end deffn +@deffn Command {etm trigger_debug} (@option{enable}|@option{disable}) +Displays whether ETM triggering debug entry (like a breakpoint) is +enabled or disabled, after optionally modifying that configuration. +The default behaviour is @option{disable}. +Any change takes effect after the next @command{etm start}. + +By using script commands to configure ETM registers, you can make the +processor enter debug state automatically when certain conditions, +more complex than supported by the breakpoint hardware, happen. +@end deffn + @subsection ETM Trace Operation After setting up the ETM, you can use it to collect data. diff --git a/src/target/etm.c b/src/target/etm.c index a506d1c..d22bc40 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -446,12 +446,15 @@ int etm_setup(struct target *target) etm_ctrl_value = (etm_ctrl_value & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK + & ~ETM_CTRL_DBGRQ & ~ETM_PORT_CLOCK_MASK) | etm_ctx->control; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); + etm_ctx->control = etm_ctrl_value; + if ((retval = jtag_execute_queue()) != ERROR_OK) return retval; @@ -1338,8 +1341,6 @@ COMMAND_HANDLER(handle_etm_tracemode_command) if (!etm_ctrl_reg) return ERROR_FAIL; - etm_get_reg(etm_ctrl_reg); - etm->control &= ~TRACEMODE_MASK; etm->control |= tracemode & TRACEMODE_MASK; @@ -2016,6 +2017,56 @@ COMMAND_HANDLER(handle_etm_stop_command) return ERROR_OK; } +COMMAND_HANDLER(handle_etm_trigger_debug_command) +{ + struct target *target; + struct arm *arm; + struct etm_context *etm; + + target = get_current_target(CMD_CTX); + arm = target_to_arm(target); + if (!is_arm(arm)) + { + command_print(CMD_CTX, "ETM: %s isn't an ARM", + target_name(target)); + return ERROR_FAIL; + } + + etm = arm->etm; + if (!etm) + { + command_print(CMD_CTX, "ETM: no ETM configured for %s", + target_name(target)); + return ERROR_FAIL; + } + + if (CMD_ARGC == 1) { + struct reg *etm_ctrl_reg; + bool dbgrq; + + etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); + if (!etm_ctrl_reg) + return ERROR_FAIL; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], dbgrq); + if (dbgrq) + etm->control |= ETM_CTRL_DBGRQ; + else + etm->control &= ~ETM_CTRL_DBGRQ; + + /* etm->control will be written to hardware + * the next time an "etm start" is issued. + */ + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); + } + + command_print(CMD_CTX, "ETM: %s debug halt", + (etm->control & ETM_CTRL_DBGRQ) + ? "triggers" + : "does not trigger"); + return ERROR_OK; +} + COMMAND_HANDLER(handle_etm_analyze_command) { struct target *target; @@ -2112,10 +2163,17 @@ static const struct command_registration etm_exec_command_handlers[] = { .help = "stop ETM trace collection", }, { + .name = "trigger_debug", + .handler = handle_etm_trigger_debug_command, + .mode = COMMAND_EXEC, + .help = "enable/disable debug entry on trigger", + .usage = "(enable | disable)", + }, + { .name = "analyze", - .handler = &handle_etm_analyze_command, + .handler = handle_etm_analyze_command, .mode = COMMAND_EXEC, - .help = "anaylze collected ETM trace", + .help = "analyze collected ETM trace", }, { .name = "image", commit 64934d9204dc854d40893634a66e29ece09ad578 Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:07:26 2009 -0800 ETM: more ETM_CTRL bit cleanup Change handling of the CYCLE_ACCURATE, BRANCH_OUTPUT, and TRACE_* flags; also the CONTEXTID size values. - Convert to symbols matching the actual register bits, instead of some random *other* bits (and then correcting that abuse). - Get rid of a now-needless enum. - Keep those values in etm->control, and remove etm->tracemode. These values all affect the trace data that's recorded by a trace pod or in the ETB. I modified the file format used to dump ETB data; since it's fairly clear nobody can use this mechanism now, this can't cause anyone trouble. Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/target/etm.c b/src/target/etm.c index aaa0219..a506d1c 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1059,7 +1059,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * ctx->data_half = old_data_half; } - if (ctx->tracemode & ETMV1_TRACE_ADDR) + if (ctx->control & ETM_CTRL_TRACE_ADDR) { uint8_t packet; int shift = 0; @@ -1081,7 +1081,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * } } - if (ctx->tracemode & ETMV1_TRACE_DATA) + if (ctx->control & ETM_CTRL_TRACE_DATA) { if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) { @@ -1141,7 +1141,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * /* if the trace was captured with cycle accurate tracing enabled, * output the number of cycles since the last executed instruction */ - if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + if (ctx->control & ETM_CTRL_CYCLE_ACCURATE) { snprintf(cycles_text, 32, " (%i %s)", (int)cycles, @@ -1178,13 +1178,13 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, /* what parts of data access are traced? */ if (strcmp(CMD_ARGV[0], "none") == 0) - tracemode = ETMV1_TRACE_NONE; + tracemode = 0; else if (strcmp(CMD_ARGV[0], "data") == 0) - tracemode = ETMV1_TRACE_DATA; + tracemode = ETM_CTRL_TRACE_DATA; else if (strcmp(CMD_ARGV[0], "address") == 0) - tracemode = ETMV1_TRACE_ADDR; + tracemode = ETM_CTRL_TRACE_ADDR; else if (strcmp(CMD_ARGV[0], "all") == 0) - tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + tracemode = ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR; else { command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[0]); @@ -1196,16 +1196,16 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, switch (context_id) { case 0: - tracemode |= ETMV1_CONTEXTID_NONE; + tracemode |= ETM_CTRL_CONTEXTID_NONE; break; case 8: - tracemode |= ETMV1_CONTEXTID_8; + tracemode |= ETM_CTRL_CONTEXTID_8; break; case 16: - tracemode |= ETMV1_CONTEXTID_16; + tracemode |= ETM_CTRL_CONTEXTID_16; break; case 32: - tracemode |= ETMV1_CONTEXTID_32; + tracemode |= ETM_CTRL_CONTEXTID_32; break; default: command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[1]); @@ -1215,12 +1215,12 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, bool etmv1_cycle_accurate; COMMAND_PARSE_ENABLE(CMD_ARGV[2], etmv1_cycle_accurate); if (etmv1_cycle_accurate) - tracemode |= ETMV1_CYCLE_ACCURATE; + tracemode |= ETM_CTRL_CYCLE_ACCURATE; bool etmv1_branch_output; COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output); if (etmv1_branch_output) - tracemode |= ETMV1_BRANCH_OUTPUT; + tracemode |= ETM_CTRL_BRANCH_OUTPUT; /* IGNORED: * - CPRT tracing (coprocessor register transfers) @@ -1249,7 +1249,7 @@ COMMAND_HANDLER(handle_etm_tracemode_command) return ERROR_FAIL; } - uint32_t tracemode = etm->tracemode; + uint32_t tracemode = etm->control; switch (CMD_ARGC) { @@ -1272,39 +1272,39 @@ COMMAND_HANDLER(handle_etm_tracemode_command) command_print(CMD_CTX, "current tracemode configuration:"); - switch (tracemode & ETMV1_TRACE_MASK) + switch (tracemode & ETM_CTRL_TRACE_MASK) { - case ETMV1_TRACE_NONE: + default: command_print(CMD_CTX, "data tracing: none"); break; - case ETMV1_TRACE_DATA: + case ETM_CTRL_TRACE_DATA: command_print(CMD_CTX, "data tracing: data only"); break; - case ETMV1_TRACE_ADDR: + case ETM_CTRL_TRACE_ADDR: command_print(CMD_CTX, "data tracing: address only"); break; - case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: + case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: command_print(CMD_CTX, "data tracing: address and data"); break; } - switch (tracemode & ETMV1_CONTEXTID_MASK) + switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { - case ETMV1_CONTEXTID_NONE: + case ETM_CTRL_CONTEXTID_NONE: command_print(CMD_CTX, "contextid tracing: none"); break; - case ETMV1_CONTEXTID_8: + case ETM_CTRL_CONTEXTID_8: command_print(CMD_CTX, "contextid tracing: 8 bit"); break; - case ETMV1_CONTEXTID_16: + case ETM_CTRL_CONTEXTID_16: command_print(CMD_CTX, "contextid tracing: 16 bit"); break; - case ETMV1_CONTEXTID_32: + case ETM_CTRL_CONTEXTID_32: command_print(CMD_CTX, "contextid tracing: 32 bit"); break; } - if (tracemode & ETMV1_CYCLE_ACCURATE) + if (tracemode & ETM_CTRL_CYCLE_ACCURATE) { command_print(CMD_CTX, "cycle-accurate tracing enabled"); } @@ -1313,7 +1313,7 @@ COMMAND_HANDLER(handle_etm_tracemode_command) command_print(CMD_CTX, "cycle-accurate tracing disabled"); } - if (tracemode & ETMV1_BRANCH_OUTPUT) + if (tracemode & ETM_CTRL_BRANCH_OUTPUT) { command_print(CMD_CTX, "full branch address output enabled"); } @@ -1322,8 +1322,15 @@ COMMAND_HANDLER(handle_etm_tracemode_command) command_print(CMD_CTX, "full branch address output disabled"); } +#define TRACEMODE_MASK ( \ + ETM_CTRL_CONTEXTID_MASK \ + | ETM_CTRL_BRANCH_OUTPUT \ + | ETM_CTRL_CYCLE_ACCURATE \ + | ETM_CTRL_TRACE_MASK \ + ) + /* only update ETM_CTRL register if tracemode changed */ - if (etm->tracemode != tracemode) + if ((etm->control & TRACEMODE_MASK) != tracemode) { struct reg *etm_ctrl_reg; @@ -1333,13 +1340,11 @@ COMMAND_HANDLER(handle_etm_tracemode_command) etm_get_reg(etm_ctrl_reg); - buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); - buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); - buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); - buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); - etm_store_reg(etm_ctrl_reg); + etm->control &= ~TRACEMODE_MASK; + etm->control |= tracemode & TRACEMODE_MASK; - etm->tracemode = tracemode; + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); + etm_store_reg(etm_ctrl_reg); /* invalidate old trace data */ etm->capture_status = TRACE_IDLE; @@ -1351,6 +1356,8 @@ COMMAND_HANDLER(handle_etm_tracemode_command) etm->trace_depth = 0; } +#undef TRACEMODE_MASK + return ERROR_OK; } @@ -1825,7 +1832,6 @@ COMMAND_HANDLER(handle_etm_dump_command) fileio_write_u32(&file, etm_ctx->capture_status); fileio_write_u32(&file, etm_ctx->control); - fileio_write_u32(&file, etm_ctx->tracemode); fileio_write_u32(&file, etm_ctx->trace_depth); for (i = 0; i < etm_ctx->trace_depth; i++) @@ -1897,7 +1903,6 @@ COMMAND_HANDLER(handle_etm_load_command) uint32_t tmp; fileio_read_u32(&file, &tmp); etm_ctx->capture_status = tmp; fileio_read_u32(&file, &tmp); etm_ctx->control = tmp; - fileio_read_u32(&file, &tmp); etm_ctx->tracemode = tmp; fileio_read_u32(&file, &etm_ctx->trace_depth); } etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); diff --git a/src/target/etm.h b/src/target/etm.h index e4d4685..8a482c1 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -89,7 +89,10 @@ enum ETM_CTRL_POWERDOWN = (1 << 0), ETM_CTRL_MONITOR_CPRT = (1 << 1), - // bits 3:2 == trace type (ETMV1_TRACE_* << 2) + /* bits 3:2 == trace type */ + ETM_CTRL_TRACE_DATA = (1 << 2), + ETM_CTRL_TRACE_ADDR = (2 << 2), + ETM_CTRL_TRACE_MASK = (3 << 2), /* Port width (bits 21 and 6:4) */ ETM_PORT_4BIT = 0x00, @@ -116,7 +119,11 @@ enum ETM_PORT_CLOCK_MASK = (1 << 13), // bits 15:14 == context ID size used in tracing - // ETMV1_CONTEXTID_* << 8 + ETM_CTRL_CONTEXTID_NONE = (0 << 14), + ETM_CTRL_CONTEXTID_8 = (1 << 14), + ETM_CTRL_CONTEXTID_16 = (2 << 14), + ETM_CTRL_CONTEXTID_32 = (3 << 14), + ETM_CTRL_CONTEXTID_MASK = (3 << 14), /* Port modes -- bits 17:16, tied to clocking mode */ ETM_PORT_NORMAL = (0 << 16), @@ -127,24 +134,6 @@ enum // bits 31:18 defined in v3.0 and later (e.g. ARM11+) }; -enum -{ - /* Data trace */ - ETMV1_TRACE_NONE = 0x00, - ETMV1_TRACE_DATA = 0x01, - ETMV1_TRACE_ADDR = 0x02, - ETMV1_TRACE_MASK = 0x03, - /* ContextID */ - ETMV1_CONTEXTID_NONE = 0x00, - ETMV1_CONTEXTID_8 = 0x10, - ETMV1_CONTEXTID_16 = 0x20, - ETMV1_CONTEXTID_32 = 0x30, - ETMV1_CONTEXTID_MASK = 0x30, - /* Misc */ - ETMV1_CYCLE_ACCURATE = 0x100, - ETMV1_BRANCH_OUTPUT = 0x200 -}; - /* forward-declare ETM context */ struct etm_context; @@ -187,7 +176,6 @@ struct etm_context struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ uint32_t control; /* shadow of ETM_CTRL */ - uint32_t tracemode; /* type of info trace contains */ int /*arm_state*/ core_state; /* current core state */ struct image *image; /* source for target opcodes */ uint32_t pipe_index; /* current trace cycle */ commit e25819645ee2beb0818a79006eed9c9cedaaf5bb Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:07:25 2009 -0800 ETM: start cleaning up ETM_CTRL bit handling Provide better comments for the ETM_CTRL bits; use the correct bit for half/full clock mode; and define a few more of the bits available from the earliest ETM versions. The new bit defintions use ETM_CTRL_* names to match their register (instead of ETM_PORT_* or ETMV1_*). For clarity, and better matching to docs, they are defined with bitshifting not pre-computed masks. Stop abusing typdefs for ETM_CTRL values; such values are not limited to the enumerated set of individual bit values. Rename etm->portmode to etm->control ... and start morphing it into a single generic shadow of ETM_CTRL. Eventually etm->tracemode should vanish, so we can just write etm->control to ETM_CTRL. Restore an "if" that somehow got dropped. Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/target/etb.c b/src/target/etb.c index a789777..fb2dd60 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -579,9 +579,9 @@ static int etb_read_trace(struct etm_context *etm_ctx) free(etm_ctx->trace_data); } - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) etm_ctx->trace_depth = num_frames * 3; - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) etm_ctx->trace_depth = num_frames * 2; else etm_ctx->trace_depth = num_frames; @@ -590,7 +590,7 @@ static int etb_read_trace(struct etm_context *etm_ctx) for (i = 0, j = 0; i < num_frames; i++) { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; @@ -636,7 +636,7 @@ static int etb_read_trace(struct etm_context *etm_ctx) j += 3; } - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; @@ -699,9 +699,9 @@ static int etb_start_capture(struct etm_context *etm_ctx) uint32_t etb_ctrl_value = 0x1; uint32_t trigger_count; - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) + if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) { LOG_ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; @@ -709,7 +709,7 @@ static int etb_start_capture(struct etm_context *etm_ctx) etb_ctrl_value |= 0x2; } - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) { + if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) { LOG_ERROR("ETB: can't run in multiplexed mode"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } diff --git a/src/target/etm.c b/src/target/etm.c index fff9494..aaa0219 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -435,10 +435,10 @@ int etm_setup(struct target *target) /* initialize some ETM control register settings */ etm_get_reg(etm_ctrl_reg); - etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size); + etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, 32); /* clear the ETM powerdown bit (0) */ - etm_ctrl_value &= ~0x1; + etm_ctrl_value &= ~ETM_CTRL_POWERDOWN; /* configure port width (21,6:4), mode (13,17:16) and * for older modules clocking (13) @@ -447,9 +447,9 @@ int etm_setup(struct target *target) & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) - | etm_ctx->portmode; + | etm_ctx->control; - buf_set_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size, etm_ctrl_value); + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); if ((retval = jtag_execute_queue()) != ERROR_OK) @@ -727,7 +727,8 @@ static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) continue; } - if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) + /* FIXME there are more port widths than these... */ + if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) { if (ctx->data_half == 0) { @@ -741,7 +742,7 @@ static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) ctx->data_index++; } } - else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + else if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_index++; @@ -1171,9 +1172,9 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * } static COMMAND_HELPER(handle_etm_tracemode_command_update, - etmv1_tracemode_t *mode) + uint32_t *mode) { - etmv1_tracemode_t tracemode; + uint32_t tracemode; /* what parts of data access are traced? */ if (strcmp(CMD_ARGV[0], "none") == 0) @@ -1218,6 +1219,7 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, bool etmv1_branch_output; COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output); + if (etmv1_branch_output) tracemode |= ETMV1_BRANCH_OUTPUT; /* IGNORED: @@ -1247,7 +1249,7 @@ COMMAND_HANDLER(handle_etm_tracemode_command) return ERROR_FAIL; } - etmv1_tracemode_t tracemode = etm->tracemode; + uint32_t tracemode = etm->tracemode; switch (CMD_ARGC) { @@ -1356,7 +1358,7 @@ COMMAND_HANDLER(handle_etm_config_command) { struct target *target; struct arm *arm; - etm_portmode_t portmode = 0x0; + uint32_t portmode = 0x0; struct etm_context *etm_ctx; int i; @@ -1495,7 +1497,7 @@ COMMAND_HANDLER(handle_etm_config_command) etm_ctx->target = target; etm_ctx->trace_data = NULL; - etm_ctx->portmode = portmode; + etm_ctx->control = portmode; etm_ctx->core_state = ARM_STATE_ARM; arm->etm = etm_ctx; @@ -1822,7 +1824,7 @@ COMMAND_HANDLER(handle_etm_dump_command) } fileio_write_u32(&file, etm_ctx->capture_status); - fileio_write_u32(&file, etm_ctx->portmode); + fileio_write_u32(&file, etm_ctx->control); fileio_write_u32(&file, etm_ctx->tracemode); fileio_write_u32(&file, etm_ctx->trace_depth); @@ -1894,7 +1896,7 @@ COMMAND_HANDLER(handle_etm_load_command) { uint32_t tmp; fileio_read_u32(&file, &tmp); etm_ctx->capture_status = tmp; - fileio_read_u32(&file, &tmp); etm_ctx->portmode = tmp; + fileio_read_u32(&file, &tmp); etm_ctx->control = tmp; fileio_read_u32(&file, &tmp); etm_ctx->tracemode = tmp; fileio_read_u32(&file, &etm_ctx->trace_depth); } diff --git a/src/target/etm.h b/src/target/etm.h index 78a5996..e4d4685 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -78,9 +78,20 @@ struct etm_reg struct arm_jtag *jtag_info; }; -typedef enum +/* Subset of ETM_CTRL bit assignments. Many of these + * control the configuration of trace output, which + * hooks up either to ETB or to an external device. + * + * NOTE that these have evolved since the ~v1.3 defns ... + */ +enum { - /* Port width */ + ETM_CTRL_POWERDOWN = (1 << 0), + ETM_CTRL_MONITOR_CPRT = (1 << 1), + + // bits 3:2 == trace type (ETMV1_TRACE_* << 2) + + /* Port width (bits 21 and 6:4) */ ETM_PORT_4BIT = 0x00, ETM_PORT_8BIT = 0x10, ETM_PORT_16BIT = 0x20, @@ -91,18 +102,32 @@ typedef enum ETM_PORT_1BIT = 0x00 | (1 << 21), ETM_PORT_2BIT = 0x10 | (1 << 21), ETM_PORT_WIDTH_MASK = 0x70 | (1 << 21), - /* Port modes */ - ETM_PORT_NORMAL = 0x00000, - ETM_PORT_MUXED = 0x10000, - ETM_PORT_DEMUXED = 0x20000, - ETM_PORT_MODE_MASK = 0x30000, - /* Clocking modes */ - ETM_PORT_FULL_CLOCK = 0x0000, - ETM_PORT_HALF_CLOCK = 0x1000, - ETM_PORT_CLOCK_MASK = 0x1000, -} etm_portmode_t; -typedef enum + ETM_CTRL_FIFOFULL_STALL = (1 << 7), + ETM_CTRL_BRANCH_OUTPUT = (1 << 8), + ETM_CTRL_DBGRQ = (1 << 9), + ETM_CTRL_ETM_PROG = (1 << 10), + ETM_CTRL_ETMEN = (1 << 11), + ETM_CTRL_CYCLE_ACCURATE = (1 << 12), + + /* Clocking modes -- up to v2.1, bit 13 */ + ETM_PORT_FULL_CLOCK = (0 << 13), + ETM_PORT_HALF_CLOCK = (1 << 13), + ETM_PORT_CLOCK_MASK = (1 << 13), + + // bits 15:14 == context ID size used in tracing + // ETMV1_CONTEXTID_* << 8 + + /* Port modes -- bits 17:16, tied to clocking mode */ + ETM_PORT_NORMAL = (0 << 16), + ETM_PORT_MUXED = (1 << 16), + ETM_PORT_DEMUXED = (2 << 16), + ETM_PORT_MODE_MASK = (3 << 16), + + // bits 31:18 defined in v3.0 and later (e.g. ARM11+) +}; + +enum { /* Data trace */ ETMV1_TRACE_NONE = 0x00, @@ -118,7 +143,7 @@ typedef enum /* Misc */ ETMV1_CYCLE_ACCURATE = 0x100, ETMV1_BRANCH_OUTPUT = 0x200 -} etmv1_tracemode_t; +}; /* forward-declare ETM context */ struct etm_context; @@ -161,8 +186,8 @@ struct etm_context trace_status_t capture_status; /* current state of capture run */ struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ - etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */ - etmv1_tracemode_t tracemode; /* type of info trace contains */ + uint32_t control; /* shadow of ETM_CTRL */ + uint32_t tracemode; /* type of info trace contains */ int /*arm_state*/ core_state; /* current core state */ struct image *image; /* source for target opcodes */ uint32_t pipe_index; /* current trace cycle */ commit 9abad965ab358c1d598f1354842967cad637b284 Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:06:46 2009 -0800 ETM trigger_percent becomes an ETB command This command was misplaced; it's not generic to all traceport drivers, only the ETB supports this kind of configuration. So move it, and update the relevant documentation. Signed-off-by: David Brownell <dbr...@us...> diff --git a/NEWS b/NEWS index 67778ef..efcf8f6 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,8 @@ Target Layer: - watchpoint support Cortex-M3 - Exposed DWT registers like cycle counter + ETM, ETB + - "trigger_percent" command moved ETM --> ETB Flash Layer: 'flash bank' and 'nand device' take <bank_name> as first argument. diff --git a/doc/openocd.texi b/doc/openocd.texi index cda5be3..bb3e51a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5512,28 +5512,6 @@ trace stream without an image of the code. @end itemize @end deffn -@deffn Command {etm trigger_percent} [percent] -This displays, or optionally changes, the trace port driver's -behavior after the ETM's configured @emph{trigger} event fires. -It controls how much more trace data is saved after the (single) -trace trigger becomes active. - -@itemize -@item The default corresponds to @emph{trace around} usage, -recording 50 percent data before the event and the rest -afterwards. -@item The minimum value of @var{percent} is 2 percent, -recording almost exclusively data before the trigger. -Such extreme @emph{trace before} usage can help figure out -what caused that event to happen. -@item The maximum value of @var{percent} is 100 percent, -recording data almost exclusively after the event. -This extreme @emph{trace after} usage might help sort out -how the event caused trouble. -@end itemize -@c REVISIT allow "break" too -- enter debug mode. -@end deffn - @subsection ETM Trace Operation After setting up the ETM, you can use it to collect data. @@ -5617,6 +5595,28 @@ to use on-chip ETB memory. Associates the ETM for @var{target} with the ETB at @var{etb_tap}. You can see the ETB registers using the @command{reg} command. @end deffn +@deffn Command {etb trigger_percent} [percent] +This displays, or optionally changes, ETB behavior after the +ETM's configured @emph{trigger} event fires. +It controls how much more trace data is saved after the (single) +trace trigger becomes active. + +@itemize +@item The default corresponds to @emph{trace around} usage, +recording 50 percent data before the event and the rest +afterwards. +@item The minimum value of @var{percent} is 2 percent, +recording almost exclusively data before the trigger. +Such extreme @emph{trace before} usage can help figure out +what caused that event to happen. +@item The maximum value of @var{percent} is 100 percent, +recording data almost exclusively after the event. +This extreme @emph{trace after} usage might help sort out +how the event caused trouble. +@end itemize +@c REVISIT allow "break" too -- enter debug mode. +@end deffn + @end deffn @deffn {Trace Port Driver} oocd_trace diff --git a/src/target/etb.c b/src/target/etb.c index 3113eca..a789777 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -402,12 +402,63 @@ COMMAND_HANDLER(handle_etb_config_command) return ERROR_OK; } +COMMAND_HANDLER(handle_etb_trigger_percent_command) +{ + struct target *target; + struct arm *arm; + struct etm_context *etm; + struct etb *etb; + + target = get_current_target(CMD_CTX); + arm = target_to_arm(target); + if (!is_arm(arm)) + { + command_print(CMD_CTX, "ETB: current target isn't an ARM"); + return ERROR_FAIL; + } + + etm = arm->etm; + if (!etm) { + command_print(CMD_CTX, "ETB: target has no ETM configured"); + return ERROR_FAIL; + } + if (etm->capture_driver != &etb_capture_driver) { + command_print(CMD_CTX, "ETB: target not using ETB"); + return ERROR_FAIL; + } + etb = arm->etm->capture_driver_priv; + + if (CMD_ARGC > 0) { + uint32_t new_value; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value); + if ((new_value < 2) || (new_value > 100)) + command_print(CMD_CTX, + "valid percentages are 2%% to 100%%"); + else + etb->trigger_percent = (unsigned) new_value; + } + + command_print(CMD_CTX, "%d percent of tracebuffer fills after trigger", + etb->trigger_percent); + + return ERROR_OK; +} + static const struct command_registration etb_config_command_handlers[] = { { .name = "config", .handler = &handle_etb_config_command, .mode = COMMAND_CONFIG, - .usage = "<target> <tap>", + .usage = "target tap", + }, + { + .name = "trigger_percent", + .handler = &handle_etb_trigger_percent_command, + .mode = COMMAND_EXEC, + .help = "percent of trace buffer to be filled " + "after the trigger occurs", + .usage = "[percent]", }, COMMAND_REGISTRATION_DONE }; @@ -435,6 +486,8 @@ static int etb_init(struct etm_context *etm_ctx) etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + etb->trigger_percent = 50; + return ERROR_OK; } @@ -661,7 +714,7 @@ static int etb_start_capture(struct etm_context *etm_ctx) return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } - trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; + trigger_count = (etb->ram_depth * etb->trigger_percent) / 100; etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); diff --git a/src/target/etb.h b/src/target/etb.h index 49385ee..dfffb68 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -44,6 +44,9 @@ struct etb /* ETB parameters */ uint32_t ram_depth; uint32_t ram_width; + + /** how much trace buffer to fill after trigger */ + unsigned trigger_percent; }; struct etb_reg diff --git a/src/target/etm.c b/src/target/etm.c index 9cb647c..fff9494 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1494,7 +1494,6 @@ COMMAND_HANDLER(handle_etm_config_command) } etm_ctx->target = target; - etm_ctx->trigger_percent = 50; etm_ctx->trace_data = NULL; etm_ctx->portmode = portmode; etm_ctx->core_state = ARM_STATE_ARM; @@ -1923,47 +1922,6 @@ COMMAND_HANDLER(handle_etm_load_command) return ERROR_OK; } -COMMAND_HANDLER(handle_etm_trigger_percent_command) -{ - struct target *target; - struct arm *arm; - struct etm_context *etm_ctx; - - target = get_current_target(CMD_CTX); - arm = target_to_arm(target); - if (!is_arm(arm)) - { - command_print(CMD_CTX, "ETM: current target isn't an ARM"); - return ERROR_FAIL; - } - - etm_ctx = arm->etm; - if (!etm_ctx) - { - command_print(CMD_CTX, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) - { - uint32_t new_value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value); - - if ((new_value < 2) || (new_value > 100)) - { - command_print(CMD_CTX, "valid settings are 2%% to 100%%"); - } - else - { - etm_ctx->trigger_percent = new_value; - } - } - - command_print(CMD_CTX, "%i percent of the tracebuffer reserved for after the trigger", ((int)(etm_ctx->trigger_percent))); - - return ERROR_OK; -} - COMMAND_HANDLER(handle_etm_start_command) { struct target *target; @@ -2129,13 +2087,6 @@ static const struct command_registration etm_exec_command_handlers[] = { .help = "display info about the current target's ETM", }, { - .name = "trigger_percent", - .handler = &handle_etm_trigger_percent_command, - .mode = COMMAND_EXEC, - .help = "amount (<percent>) of trace buffer " - "to be filled after the trigger occured", - }, - { .name = "status", .handler = &handle_etm_status_command, .mode = COMMAND_EXEC, diff --git a/src/target/etm.h b/src/target/etm.h index 5b4d5e1..78a5996 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -158,7 +158,6 @@ struct etm_context struct reg_cache *reg_cache; /* ETM register cache */ struct etm_capture_driver *capture_driver; /* driver used to access ETM data */ void *capture_driver_priv; /* capture driver private data */ - uint32_t trigger_percent; /* how much trace buffer to fill after trigger */ trace_status_t capture_status; /* current state of capture run */ struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ commit bfadd79965cc448a75b4f51abaf9523c4ec0ae26 Author: David Brownell <dbr...@us...> Date: Sat Dec 19 13:01:30 2009 -0800 NEWS: mention libftdi 0.17 diff --git a/NEWS b/NEWS index 2d01f00..67778ef 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,8 @@ Documentation: Build and Release: Use --enable-doxygen-pdf to build PDF developer documentation. + Consider upgrading to libftdi 0.17 if you use that library; it + includes bugfixes which improve FT2232H support. For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that ----------------------------------------------------------------------- Summary of changes: NEWS | 5 + doc/openocd.texi | 84 ++++-- s... [truncated message content] |