+/**
+ * Queue transactions setting up transfer parameters for the
+ * currently selected MEM-AP. If transfer size or packing
+ * has not been probed, run the queue, read back CSW and check if the requested
+ * transfer mode is supported.
+ *
+ * @param ap The MEM-AP.
+ * @param size Transfer width in bytes. Corresponding CSW.Size will be set.
+ * @param address Transfer address, MEM-AP TAR will be set to this value.
+ * @param addrinc TAR will be autoincremented.
+ * @param pack Try to setup packed transfer.
+ * @param this_size Points to a variable set to the size of single transfer
+ * or to 4 when transferring packed bytes or halfwords
+ *
+ * @return ERROR_OK if the transaction was properly queued, else a fault code.
+ */
+static int mem_ap_setup_transfer_verify_size_packing(struct adiv5_ap *ap,
+ unsigned int size, target_addr_t address,
+ bool addrinc, bool pack, unsigned int *this_size)
+{
+ int retval;
+ uint32_t csw_size;
+
+ switch (size) {
+ case 1:
+ csw_size = CSW_8BIT;
+ break;
+ case 2:
+ csw_size = CSW_16BIT;
+ break;
+ case 4:
+ csw_size = CSW_32BIT;
+ break;
+ case 8:
+ csw_size = CSW_64BIT;
+ break;
+ case 16:
+ csw_size = CSW_128BIT;
+ break;
+ case 32:
+ csw_size = CSW_256BIT;
+ break;
+ default:
+ LOG_ERROR("Size %u not supported", size);
+ return ERROR_TARGET_SIZE_NOT_SUPPORTED;
+ }
+
+ if (!addrinc || size >= 4
+ || (ap->packed_transfers_probed && !ap->packed_transfers_supported)
+ || max_tar_block_size(ap->tar_autoincr_block, address) < 4)
+ pack = false;
+
+ uint32_t csw_addrinc = pack ? CSW_ADDRINC_PACKED :
+ addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF;
+ retval = mem_ap_setup_csw(ap, csw_size | csw_addrinc);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bool do_probe = !(ap->csw_size_probed_mask & size)
+ || (pack && !ap->packed_transfers_probed);
+ if (do_probe) {
+ uint32_t csw_readback;
+ retval = dap_queue_ap_read(ap, MEM_AP_REG_CSW(ap->dap), &csw_readback);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = dap_run(ap->dap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bool size_supported = ((csw_readback & CSW_SIZE_MASK) == csw_size);
+ LOG_DEBUG("AP#0x%" PRIx64 " probed size %u: %s", ap->ap_num, size,
+ size_supported ? "supported" : "not supported");
+ ap->csw_size_probed_mask |= size;
+ if (size_supported) {
+ ap->csw_size_supported_mask |= size;
+ if (pack && !ap->packed_transfers_probed) {
+ ap->packed_transfers_probed = true;
+ ap->packed_transfers_supported =
+ ((csw_readback & CSW_ADDRINC_MASK) == csw_addrinc);
+ LOG_DEBUG("probed packing: %s",
+ ap->packed_transfers_supported ? "supported" : "not supported");
+ }
+ }
+ }
+
+ if (!(ap->csw_size_supported_mask & size)) {
+ LOG_ERROR("Size %u not supported", size);
+ return ERROR_TARGET_SIZE_NOT_SUPPORTED;
+ }
+
+ if (pack && !ap->packed_transfers_supported)
+ return ERROR_TARGET_PACKING_NOT_SUPPORTED;
+
+ *this_size = pack ? 4 : size;
+
+ return mem_ap_setup_tar(ap, address);
+}
+
+/**
+ * Queue transactions setting up transfer parameters for the
+ * currently selected MEM-AP. If transfer size or packing
+ * has not been probed, run the queue, read back CSW and check if the requested
+ * transfer mode is supported.
+ * If packing is not supported fallback and prepare CSW for unpacked transfer.
+ *
+ * @param ap The MEM-AP.
+ * @param size Transfer width in bytes. Corresponding CSW.Size will be set.
+ * @param address Transfer address, MEM-AP TAR will be set to this value.
+ * @param addrinc TAR will be autoincremented.
+ * @param pack Try to setup packed transfer.
+ * @param this_size Points to a variable set to the size of single transfer
+ * or to 4 when transferring packed bytes or halfwords
+ *
+ * @return ERROR_OK if the transaction was properly queued, else a fault code.
+ */
+static int mem_ap_setup_transfer_verify_size_packing_fallback(struct adiv5_ap *ap,
+ unsigned int size, target_addr_t address,
+ bool addrinc, bool pack, unsigned int *this_size)
+{
+ int retval = mem_ap_setup_transfer_verify_size_packing(ap,
+ size, address,
+ addrinc, pack, this_size);
+ if (retval == ERROR_TARGET_PACKING_NOT_SUPPORTED) {
+ /* Retry without packing */
+ retval = mem_ap_setup_transfer_verify_size_packing(ap,
+ size, address,
+ addrinc, false, this_size);
+ }
+ return retval;
+}
+