diff --git a/src/platforms/hosted/jlink.c b/src/platforms/hosted/jlink.c index caf8bf9..d1d1220 100644 --- a/src/platforms/hosted/jlink.c +++ b/src/platforms/hosted/jlink.c @@ -40,14 +40,19 @@ #define USB_VID_SEGGER_0105 0x0105 #define USB_VID_SEGGER_1020 0x1020 +static uint32_t emu_caps; +static uint32_t emu_speed_kHz; +static uint16_t emu_min_divisor; +static uint16_t emu_current_divisor; + static void jlink_print_caps(bmp_info_t *info) { uint8_t cmd[1] = {CMD_GET_CAPS}; uint8_t res[4]; send_recv(info->usb_link, cmd, 1, res, sizeof(res)); - uint32_t caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); - DEBUG_INFO("Caps %" PRIx32 "\n", caps); - if (caps & JLINK_CAP_GET_HW_VERSION) { + emu_caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); + DEBUG_INFO("Caps %" PRIx32 "\n", emu_caps); + if (emu_caps & JLINK_CAP_GET_HW_VERSION) { uint8_t cmd[1] = {CMD_GET_HW_VERSION}; send_recv(info->usb_link, cmd, 1, NULL, 0); send_recv(info->usb_link, NULL, 0, res, sizeof(res)); @@ -57,13 +62,15 @@ static void jlink_print_caps(bmp_info_t *info) } static void jlink_print_speed(bmp_info_t *info) { - uint8_t cmd[1] = {CMD_GET_SPEED}; + uint8_t cmd[1] = {CMD_GET_SPEEDS}; uint8_t res[6]; send_recv(info->usb_link, cmd, 1, res, sizeof(res)); - uint32_t speed = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); - double freq_mhz = speed / 1000000.0; - uint16_t divisor = res[4] | (res[5] << 8); - DEBUG_INFO("Emulator speed %3.1f MHz, Mindiv %d\n", freq_mhz, divisor); + emu_speed_kHz = (res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24)) / + 1000; + emu_min_divisor = res[4] | (res[5] << 8); + DEBUG_INFO("Emulator speed %d kHz, Mindiv %d%s\n", emu_speed_kHz, + emu_min_divisor, + (emu_caps & JLINK_CAP_GET_SPEEDS) ? "" : ", fixed"); } static void jlink_print_version(bmp_info_t *info) @@ -98,8 +105,8 @@ static void jlink_print_interfaces(bmp_info_t *info) static void jlink_info(bmp_info_t *info) { jlink_print_version(info); - jlink_print_speed(info); jlink_print_caps(info); + jlink_print_speed(info); jlink_print_interfaces(info); } @@ -214,7 +221,7 @@ int jlink_init(bmp_info_t *info) const char *jlink_target_voltage(bmp_info_t *info) { uint8_t cmd[1] = {CMD_GET_HW_STATUS}; - uint8_t res[8]; + uint8_t res[8]; send_recv(info->usb_link, cmd, 1, res, sizeof(res)); uint16_t mVolt = res[0] | (res[1] << 8); static char ret[7]; @@ -238,3 +245,27 @@ bool jlink_srst_get_val(bmp_info_t *info) { send_recv(info->usb_link, cmd, 1, res, sizeof(res)); return !(res[6]); } + +void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq) +{ + if (!(emu_caps & JLINK_CAP_GET_SPEEDS)) + return; + if (!info->is_jtag) + return; + uint16_t freq_kHz = freq /1000; + uint16_t divisor = (emu_speed_kHz + freq_kHz - 1) / freq_kHz; + if (divisor < emu_min_divisor) + divisor = emu_min_divisor; + emu_current_divisor = divisor; + uint16_t speed_kHz = emu_speed_kHz / divisor; + uint8_t cmd[3] = {CMD_SET_SPEED, speed_kHz & 0xff, speed_kHz >> 8}; + DEBUG_WARN("Set Speed %d\n", speed_kHz); + send_recv(info->usb_link, cmd, 3, NULL, 0); +} + +uint32_t jlink_max_frequency_get(bmp_info_t *info) +{ + if ((emu_caps & JLINK_CAP_GET_SPEEDS) && (info->is_jtag)) + return (emu_speed_kHz * 1000L)/ emu_current_divisor; + return FREQ_FIXED; +} diff --git a/src/platforms/hosted/jlink.h b/src/platforms/hosted/jlink.h index c79b868..5504c67 100644 --- a/src/platforms/hosted/jlink.h +++ b/src/platforms/hosted/jlink.h @@ -24,8 +24,9 @@ /** @cond PRIVATE */ #define CMD_GET_VERSION 0x01 +#define CMD_SET_SPEED 0x05 #define CMD_GET_HW_STATUS 0x07 -#define CMD_GET_SPEED 0xc0 +#define CMD_GET_SPEEDS 0xc0 #define CMD_GET_SELECT_IF 0xc7 #define CMD_HW_JTAG3 0xcf #define CMD_HW_RESET0 0xdc @@ -37,7 +38,8 @@ #define JLINK_IF_GET_ACTIVE 0xfe #define JLINK_IF_GET_AVAILABLE 0xff -#define JLINK_CAP_GET_HW_VERSION 2 +#define JLINK_CAP_GET_SPEEDS (1 << 9) +#define JLINK_CAP_GET_HW_VERSION (1 << 1) #define JLINK_IF_JTAG 1 #define JLINK_IF_SWD 2 @@ -53,13 +55,54 @@ int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc) {return 0;}; const char *jlink_target_voltage(bmp_info_t *info) {return "ERROR";}; void jlink_srst_set_val(bmp_info_t *info, bool assert) {}; bool jlink_srst_get_val(bmp_info_t *info) {return true;}; +void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {}; +uint32_t jlink_max_frequency_get(bmp_info_t *info) {return 0;}; # pragma GCC diagnostic pop #else +/** Device capabilities. (from openocd*/ +enum jaylink_device_capability { + /** Device supports retrieval of the hardware version. */ + JAYLINK_DEV_CAP_GET_HW_VERSION = 1, + /** Device supports adaptive clocking. */ + JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING = 3, + /** Device supports reading configuration data. */ + JAYLINK_DEV_CAP_READ_CONFIG = 4, + /** Device supports writing configuration data. */ + JAYLINK_DEV_CAP_WRITE_CONFIG = 5, + /** Device supports retrieval of target interface speeds. */ + JAYLINK_DEV_CAP_GET_SPEEDS = 9, + /** Device supports retrieval of free memory size. */ + JAYLINK_DEV_CAP_GET_FREE_MEMORY = 11, + /** Device supports retrieval of hardware information. */ + JAYLINK_DEV_CAP_GET_HW_INFO = 12, + /** Device supports the setting of the target power supply. */ + JAYLINK_DEV_CAP_SET_TARGET_POWER = 13, + /** Device supports target interface selection. */ + JAYLINK_DEV_CAP_SELECT_TIF = 17, + /** Device supports retrieval of counter values. */ + JAYLINK_DEV_CAP_GET_COUNTERS = 19, + /** Device supports capturing of SWO trace data. */ + JAYLINK_DEV_CAP_SWO = 23, + /** Device supports file I/O operations. */ + JAYLINK_DEV_CAP_FILE_IO = 26, + /** Device supports registration of connections. */ + JAYLINK_DEV_CAP_REGISTER = 27, + /** Device supports retrieval of extended capabilities. */ + JAYLINK_DEV_CAP_GET_EXT_CAPS = 31, + /** Device supports EMUCOM. */ + JAYLINK_DEV_CAP_EMUCOM = 33, + /** Device supports ethernet connectivity. */ + JAYLINK_DEV_CAP_ETHERNET = 38 +}; + + int jlink_init(bmp_info_t *info); int jlink_swdp_scan(bmp_info_t *info); int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc); const char *jlink_target_voltage(bmp_info_t *info); void jlink_srst_set_val(bmp_info_t *info, bool assert); bool jlink_srst_get_val(bmp_info_t *info); +void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq); +uint32_t jlink_max_frequency_get(bmp_info_t *info); #endif #endif diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 9b1638e..5e55603 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -339,10 +339,21 @@ void platform_max_frequency_set(uint32_t freq) case BMP_TYPE_STLINKV2: stlink_max_frequency_set(&info, freq); break; + case BMP_TYPE_JLINK: + jlink_max_frequency_set(&info, freq); + break; default: DEBUG_WARN("Setting max SWJ frequency not yet implemented\n"); break; } + uint32_t max_freq = platform_max_frequency_get(); + if (max_freq == FREQ_FIXED) + DEBUG_INFO("Device has fixed frequency for %s\n", + (info.is_jtag) ? "JTAG" : "SWD" ); + else + DEBUG_INFO("Speed set to %7.4f MHz for %s\n", + platform_max_frequency_get() / 1000000.0, + (info.is_jtag) ? "JTAG" : "SWD" ); } uint32_t platform_max_frequency_get(void) @@ -357,6 +368,8 @@ uint32_t platform_max_frequency_get(void) return libftdi_max_frequency_get(); case BMP_TYPE_STLINKV2: return stlink_max_frequency_get(&info); + case BMP_TYPE_JLINK: + return jlink_max_frequency_get(&info); default: DEBUG_WARN("Reading max SWJ frequency not yet implemented\n"); break;