+static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp)
+{
+ struct arm *arm = target_to_arm(target);
+ struct arm_dpm *dpm = arm->dpm;
+ int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ if (bp->length < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (!dpm->bpwp_enable)
+ return retval;
+
+ /* FIXME we need a generic solution for software breakpoints. */
+ if (bp->type == BKPT_SOFT)
+ LOG_DEBUG("using HW bkpt, not SW...");
+
+ for (unsigned i = 0; i < dpm->nbp; i++) {
+ if (!dpm->dbp[i].bp) {
+ retval = dpm_bpwp_setup(dpm, &dpm->dbp[i].bpwp,
+ bp->address, bp->length);
+ if (retval == ERROR_OK)
+ dpm->dbp[i].bp = bp;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp)
+{
+ struct arm *arm = target_to_arm(target);
+ struct arm_dpm *dpm = arm->dpm;
+ int retval = ERROR_COMMAND_SYNTAX_ERROR;
+
+ for (unsigned i = 0; i < dpm->nbp; i++) {
+ if (dpm->dbp[i].bp == bp) {
+ dpm->dbp[i].bp = NULL;
+ dpm->dbp[i].bpwp.dirty = true;
+
+ /* hardware is updated in write_dirty_registers() */
+ retval = ERROR_OK;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t,
+ struct watchpoint *wp)
+{
+ int retval;
+ struct dpm_wp *dwp = dpm->dwp + index_t;
+ uint32_t control;
+
+ /* this hardware doesn't support data value matching or masking */
+ if (wp->value || wp->mask != ~(uint32_t)0) {
+ LOG_DEBUG("watchpoint values and masking not supported");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ retval = dpm_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length);
+ if (retval != ERROR_OK)
+ return retval;
+
+ control = dwp->bpwp.control;
+ switch (wp->rw) {
+ case WPT_READ:
+ control |= 1 << 3;
+ break;
+ case WPT_WRITE:
+ control |= 2 << 3;
+ break;
+ case WPT_ACCESS:
+ control |= 3 << 3;
+ break;
+ }
+ dwp->bpwp.control = control;
+
+ dpm->dwp[index_t].wp = wp;
+
+ return retval;
+}