stlink: expose ap number and csw in memory r/w
[openocd.git] / src / target / arm_cti.c
index 75169b2eee33277647391a755615b15a7247965f..c776e9c2a5c35e967b87e494e4c8f74321eef8db 100644 (file)
 #include "target/arm_cti.h"
 #include "target/target.h"
 #include "helper/time_support.h"
+#include "helper/list.h"
+#include "helper/command.h"
 
 struct arm_cti {
-       uint32_t base;
-       struct adiv5_ap *ap;
+       struct list_head lh;
+       char *name;
+       struct adiv5_mem_ap_spot spot;
 };
 
-struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base)
+static LIST_HEAD(all_cti);
+
+const char *arm_cti_name(struct arm_cti *self)
+{
+       return self->name;
+}
+
+struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
 {
-       struct arm_cti *self = calloc(1, sizeof(struct arm_cti));
-       if (!self)
-               return NULL;
+       struct arm_cti *obj = NULL;
+       const char *name;
+       bool found = false;
+
+       name = Jim_GetString(o, NULL);
+
+       list_for_each_entry(obj, &all_cti, lh) {
+               if (!strcmp(name, obj->name)) {
+                       found = true;
+                       break;
+               }
+       }
 
-       self->base = base;
-       self->ap = ap;
-       return self;
+       if (found)
+               return obj;
+       return NULL;
 }
 
 static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value)
 {
+       struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
        uint32_t tmp;
 
        /* Read register */
-       int retval = mem_ap_read_atomic_u32(self->ap, self->base + reg, &tmp);
-       if (ERROR_OK != retval)
+       int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp);
+       if (retval != ERROR_OK)
                return retval;
 
        /* clear bitfield */
@@ -59,26 +79,28 @@ static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t
        tmp |= value & mask;
 
        /* write new value */
-       return mem_ap_write_atomic_u32(self->ap, self->base + reg, tmp);
+       return mem_ap_write_atomic_u32(ap, self->spot.base + reg, tmp);
 }
 
 int arm_cti_enable(struct arm_cti *self, bool enable)
 {
+       struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
        uint32_t val = enable ? 1 : 0;
 
-       return mem_ap_write_atomic_u32(self->ap, self->base + CTI_CTR, val);
+       return mem_ap_write_atomic_u32(ap, self->spot.base + CTI_CTR, val);
 }
 
 int arm_cti_ack_events(struct arm_cti *self, uint32_t event)
 {
+       struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
        int retval;
        uint32_t tmp;
 
-       retval = mem_ap_write_atomic_u32(self->ap, self->base + CTI_INACK, event);
+       retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event);
        if (retval == ERROR_OK) {
                int64_t then = timeval_ms();
                for (;;) {
-                       retval = mem_ap_read_atomic_u32(self->ap, self->base + CTI_TROUT_STATUS, &tmp);
+                       retval = mem_ap_read_atomic_u32(ap, self->spot.base + CTI_TROUT_STATUS, &tmp);
                        if (retval != ERROR_OK)
                                break;
                        if ((tmp & event) == 0)
@@ -112,15 +134,19 @@ int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel)
 
 int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value)
 {
-       return mem_ap_write_atomic_u32(self->ap, self->base + reg, value);
+       struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
+
+       return mem_ap_write_atomic_u32(ap, self->spot.base + reg, value);
 }
 
 int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value)
 {
-       if (p_value == NULL)
+       struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
+
+       if (!p_value)
                return ERROR_COMMAND_ARGUMENT_INVALID;
 
-       return mem_ap_read_atomic_u32(self->ap, self->base + reg, p_value);
+       return mem_ap_read_atomic_u32(ap, self->spot.base + reg, p_value);
 }
 
 int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel)
@@ -146,3 +172,409 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel)
 
        return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel));
 }
+
+static uint32_t cti_regs[28];
+
+static const struct {
+       uint32_t offset;
+       const char *label;
+       uint32_t *p_val;
+} cti_names[] = {
+       { CTI_CTR,              "CTR",          &cti_regs[0] },
+       { CTI_GATE,             "GATE",         &cti_regs[1] },
+       { CTI_INEN0,    "INEN0",        &cti_regs[2] },
+       { CTI_INEN1,    "INEN1",        &cti_regs[3] },
+       { CTI_INEN2,    "INEN2",        &cti_regs[4] },
+       { CTI_INEN3,    "INEN3",        &cti_regs[5] },
+       { CTI_INEN4,    "INEN4",        &cti_regs[6] },
+       { CTI_INEN5,    "INEN5",        &cti_regs[7] },
+       { CTI_INEN6,    "INEN6",        &cti_regs[8] },
+       { CTI_INEN7,    "INEN7",        &cti_regs[9] },
+       { CTI_INEN8,    "INEN8",        &cti_regs[10] },
+       { CTI_OUTEN0,   "OUTEN0",       &cti_regs[11] },
+       { CTI_OUTEN1,   "OUTEN1",       &cti_regs[12] },
+       { CTI_OUTEN2,   "OUTEN2",       &cti_regs[13] },
+       { CTI_OUTEN3,   "OUTEN3",       &cti_regs[14] },
+       { CTI_OUTEN4,   "OUTEN4",       &cti_regs[15] },
+       { CTI_OUTEN5,   "OUTEN5",       &cti_regs[16] },
+       { CTI_OUTEN6,   "OUTEN6",       &cti_regs[17] },
+       { CTI_OUTEN7,   "OUTEN7",       &cti_regs[18] },
+       { CTI_OUTEN8,   "OUTEN8",       &cti_regs[19] },
+       { CTI_TRIN_STATUS,      "TRIN", &cti_regs[20] },
+       { CTI_TROUT_STATUS,     "TROUT", &cti_regs[21] },
+       { CTI_CHIN_STATUS,      "CHIN", &cti_regs[22] },
+       { CTI_CHOU_STATUS,      "CHOUT", &cti_regs[23] },
+       { CTI_APPSET,   "APPSET",       &cti_regs[24] },
+       { CTI_APPCLEAR, "APPCLR",       &cti_regs[25] },
+       { CTI_APPPULSE, "APPPULSE",     &cti_regs[26] },
+       { CTI_INACK,    "INACK",        &cti_regs[27] },
+};
+
+static int cti_find_reg_offset(const char *name)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(cti_names); i++) {
+               if (!strcmp(name, cti_names[i].label))
+                       return cti_names[i].offset;
+       }
+
+       LOG_ERROR("unknown CTI register %s", name);
+       return -1;
+}
+
+int arm_cti_cleanup_all(void)
+{
+       struct arm_cti *obj, *tmp;
+
+       list_for_each_entry_safe(obj, tmp, &all_cti, lh) {
+               free(obj->name);
+               free(obj);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_cti_dump)
+{
+       struct arm_cti *cti = CMD_DATA;
+       struct adiv5_ap *ap = dap_ap(cti->spot.dap, cti->spot.ap_num);
+       int retval = ERROR_OK;
+
+       for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++)
+               retval = mem_ap_read_u32(ap,
+                               cti->spot.base + cti_names[i].offset, cti_names[i].p_val);
+
+       if (retval == ERROR_OK)
+               retval = dap_run(ap->dap);
+
+       if (retval != ERROR_OK)
+               return JIM_ERR;
+
+       for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++)
+               command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32,
+                               cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val);
+
+       return JIM_OK;
+}
+
+COMMAND_HANDLER(handle_cti_enable)
+{
+       struct arm_cti *cti = CMD_DATA;
+       bool on_off;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
+
+       return arm_cti_enable(cti, on_off);
+}
+
+COMMAND_HANDLER(handle_cti_testmode)
+{
+       struct arm_cti *cti = CMD_DATA;
+       bool on_off;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
+
+       return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0);
+}
+
+COMMAND_HANDLER(handle_cti_write)
+{
+       struct arm_cti *cti = CMD_DATA;
+       int offset;
+       uint32_t value;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       offset = cti_find_reg_offset(CMD_ARGV[0]);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+       return arm_cti_write_reg(cti, offset, value);
+}
+
+COMMAND_HANDLER(handle_cti_read)
+{
+       struct arm_cti *cti = CMD_DATA;
+       int offset;
+       int retval;
+       uint32_t value;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       offset = cti_find_reg_offset(CMD_ARGV[0]);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       retval = arm_cti_read_reg(cti, offset, &value);
+       if (retval != ERROR_OK)
+               return retval;
+
+       command_print(CMD, "0x%08"PRIx32, value);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_cti_ack)
+{
+       struct arm_cti *cti = CMD_DATA;
+       uint32_t event;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event);
+
+       int retval = arm_cti_ack_events(cti, 1 << event);
+
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_cti_channel)
+{
+       struct arm_cti *cti = CMD_DATA;
+       int retval = ERROR_OK;
+       uint32_t ch_num;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num);
+
+       if (!strcmp(CMD_ARGV[1], "gate"))
+               retval = arm_cti_gate_channel(cti, ch_num);
+       else if (!strcmp(CMD_ARGV[1], "ungate"))
+               retval = arm_cti_ungate_channel(cti, ch_num);
+       else if (!strcmp(CMD_ARGV[1], "pulse"))
+               retval = arm_cti_pulse_channel(cti, ch_num);
+       else if (!strcmp(CMD_ARGV[1], "set"))
+               retval = arm_cti_set_channel(cti, ch_num);
+       else if (!strcmp(CMD_ARGV[1], "clear"))
+               retval = arm_cti_clear_channel(cti, ch_num);
+       else {
+               command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static const struct command_registration cti_instance_command_handlers[] = {
+       {
+               .name  = "dump",
+               .mode  = COMMAND_EXEC,
+               .handler = handle_cti_dump,
+               .help  = "dump CTI registers",
+               .usage = "",
+       },
+       {
+               .name = "enable",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_enable,
+               .help = "enable or disable the CTI",
+               .usage = "'on'|'off'",
+       },
+       {
+               .name = "testmode",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_testmode,
+               .help = "enable or disable integration test mode",
+               .usage = "'on'|'off'",
+       },
+       {
+               .name = "write",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_write,
+               .help = "write to a CTI register",
+               .usage = "register_name value",
+       },
+       {
+               .name = "read",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_read,
+               .help = "read a CTI register",
+               .usage = "register_name",
+       },
+       {
+               .name = "ack",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_ack,
+               .help = "acknowledge a CTI event",
+               .usage = "event",
+       },
+       {
+               .name = "channel",
+               .mode = COMMAND_EXEC,
+               .handler = handle_cti_channel,
+               .help = "do an operation on one CTI channel, possible operations: "
+                               "gate, ungate, set, clear and pulse",
+               .usage = "channel_number operation",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti)
+{
+       /* parse config or cget options ... */
+       while (goi->argc > 0) {
+               int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi);
+               if (e != JIM_OK)
+                       return e;
+       }
+
+       if (!cti->spot.dap) {
+               Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
+               return JIM_ERR;
+       }
+
+       return JIM_OK;
+}
+static int cti_create(struct jim_getopt_info *goi)
+{
+       struct command_context *cmd_ctx;
+       static struct arm_cti *cti;
+       Jim_Obj *new_cmd;
+       Jim_Cmd *cmd;
+       const char *cp;
+       int e;
+
+       cmd_ctx = current_command_context(goi->interp);
+       assert(cmd_ctx);
+
+       if (goi->argc < 3) {
+               Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
+               return JIM_ERR;
+       }
+       /* COMMAND */
+       jim_getopt_obj(goi, &new_cmd);
+       /* does this command exist? */
+       cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE);
+       if (cmd) {
+               cp = Jim_GetString(new_cmd, NULL);
+               Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
+               return JIM_ERR;
+       }
+
+       /* Create it */
+       cti = calloc(1, sizeof(*cti));
+       if (!cti)
+               return JIM_ERR;
+
+       adiv5_mem_ap_spot_init(&cti->spot);
+
+       /* Do the rest as "configure" options */
+       goi->isconfigure = 1;
+       e = cti_configure(goi, cti);
+       if (e != JIM_OK) {
+               free(cti);
+               return e;
+       }
+
+       cp = Jim_GetString(new_cmd, NULL);
+       cti->name = strdup(cp);
+
+       /* now - create the new cti name command */
+       const struct command_registration cti_subcommands[] = {
+               {
+                       .chain = cti_instance_command_handlers,
+               },
+               COMMAND_REGISTRATION_DONE
+       };
+       const struct command_registration cti_commands[] = {
+               {
+                       .name = cp,
+                       .mode = COMMAND_ANY,
+                       .help = "cti instance command group",
+                       .usage = "",
+                       .chain = cti_subcommands,
+               },
+               COMMAND_REGISTRATION_DONE
+       };
+       e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti);
+       if (e != ERROR_OK)
+               return JIM_ERR;
+
+       list_add_tail(&cti->lh, &all_cti);
+
+       return JIM_OK;
+}
+
+static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       struct jim_getopt_info goi;
+       jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
+       if (goi.argc < 2) {
+               Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
+                       "<name> [<cti_options> ...]");
+               return JIM_ERR;
+       }
+       return cti_create(&goi);
+}
+
+static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       struct arm_cti *obj;
+
+       if (argc != 1) {
+               Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
+               return JIM_ERR;
+       }
+       Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+       list_for_each_entry(obj, &all_cti, lh) {
+               Jim_ListAppendElement(interp, Jim_GetResult(interp),
+                       Jim_NewStringObj(interp, obj->name, -1));
+       }
+       return JIM_OK;
+}
+
+
+static const struct command_registration cti_subcommand_handlers[] = {
+       {
+               .name = "create",
+               .mode = COMMAND_ANY,
+               .jim_handler = jim_cti_create,
+               .usage = "name '-chain-position' name [options ...]",
+               .help = "Creates a new CTI object",
+       },
+       {
+               .name = "names",
+               .mode = COMMAND_ANY,
+               .jim_handler = jim_cti_names,
+               .usage = "",
+               .help = "Lists all registered CTI objects by name",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration cti_command_handlers[] = {
+       {
+               .name = "cti",
+               .mode = COMMAND_CONFIG,
+               .help = "CTI commands",
+               .chain = cti_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int cti_register_commands(struct command_context *cmd_ctx)
+{
+       return register_commands(cmd_ctx, NULL, cti_command_handlers);
+}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)