diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig index 690af9040e29b2..0cc163f9ad44dd 100644 --- a/drivers/jtag/Kconfig +++ b/drivers/jtag/Kconfig @@ -3,7 +3,7 @@ menuconfig JTAG help This provides basic core functionality support for JTAG class devices. Hardware that is equipped with a JTAG microcontroller can be - supported by using this drivers interfaces. + supported by using this driver's interfaces. This driver exposes a set of IOCTLs to the user space for the following commands: SDR: Performs an IEEE 1149.1 Data Register scan diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c index 11fc4bf7bdbd14..99875f34b3dbf8 100644 --- a/drivers/jtag/jtag-aspeed.c +++ b/drivers/jtag/jtag-aspeed.c @@ -71,7 +71,7 @@ #define ASPEED_JTAG_SW_MODE_TDIO BIT(16) /* ASPEED_JTAG_TCK : TCK Control */ -#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(10, 0) +#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(11, 0) #define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK) /* ASPEED_JTAG_EC : Controller set for go to IDLE */ @@ -248,8 +248,8 @@ static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg) static void aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg) { #ifdef DEBUG_JTAG - dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n", - regnames[reg], val); + dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n", regnames[reg], + val); #endif writel(val, aspeed_jtag->reg_base + reg); } @@ -272,7 +272,6 @@ static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq) if (div > ASPEED_JTAG_TCK_DIVISOR_MASK) div = ASPEED_JTAG_TCK_DIVISOR_MASK; tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK); - dev_dbg(aspeed_jtag->dev, "aspeed_jtag_freq_set: tck_val = 0x%08x\n", tck_val); aspeed_jtag_write(aspeed_jtag, (tck_val & ~ASPEED_JTAG_TCK_DIVISOR_MASK) | div, ASPEED_JTAG_TCK); @@ -377,10 +376,6 @@ static inline void aspeed_jtag_master_26xx(struct aspeed_jtag *aspeed_jtag) if (aspeed_jtag->mode & JTAG_XFER_HW_MODE) { aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); - aspeed_jtag_write(aspeed_jtag, - reg_val | ASPEED_JTAG_GBLCTRL_ENG_MODE_EN | - ASPEED_JTAG_GBLCTRL_ENG_OUT_EN, - ASPEED_JTAG_GBLCTRL); } else { aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN | @@ -424,9 +419,9 @@ static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode) aspeed_jtag->llops->master_enable(aspeed_jtag); break; case JTAG_CONTROL_MODE: - if (jtag_mode->mode == JTAG_MASTER_OUTPUT_DISABLE) + if (jtag_mode->mode == JTAG_CONTROLLER_OUTPUT_DISABLE) aspeed_jtag->llops->output_disable(aspeed_jtag); - else if (jtag_mode->mode == JTAG_MASTER_MODE) + else if (jtag_mode->mode == JTAG_CONTROLLER_MODE) aspeed_jtag->llops->master_enable(aspeed_jtag); break; default: @@ -596,9 +591,6 @@ static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag, from = from_state; to = end_state; - if (from == JTAG_STATE_CURRENT) - from = aspeed_jtag->current_state; - for (i = 0; i < _tms_cycle_lookup[from][to].count; i++) aspeed_jtag_tck_cycle(aspeed_jtag, ((_tms_cycle_lookup[from][to].tmsbits @@ -634,6 +626,10 @@ static int aspeed_jtag_status_set(struct jtag *jtag, struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); int i; + if (tapstate->from == JTAG_STATE_CURRENT) + tapstate->from = aspeed_jtag->current_state; + if (tapstate->endstate == JTAG_STATE_CURRENT) + tapstate->endstate = aspeed_jtag->current_state; #ifdef DEBUG_JTAG dev_dbg(aspeed_jtag->dev, "Set TAP state: %s\n", end_status_str[tapstate->endstate]); @@ -672,7 +668,6 @@ static int aspeed_jtag_shctrl_tms_mask(enum jtag_tapstate from, u32 start_shift, u32 end_shift, u32 *tms_mask) { - // _tms_cycle_lookup[16][4].count u32 pre_tms = start_shift ? _tms_cycle_lookup[from][to].count : 0; u32 post_tms = end_shift ? _tms_cycle_lookup[there][endstate].count : 0; u32 tms_value = start_shift ? _tms_cycle_lookup[from][to].tmsbits : 0; @@ -681,6 +676,7 @@ static int aspeed_jtag_shctrl_tms_mask(enum jtag_tapstate from, << pre_tms : 0; if (pre_tms > GENMASK(2, 0) || post_tms > GENMASK(2, 0)) { + pr_err("pre/port tms count is greater than hw limit"); return -EINVAL; } *tms_mask = start_shift | ASPEED_JTAG_SHCTRL_PRE_TMS(pre_tms) | @@ -692,7 +688,8 @@ static int aspeed_jtag_shctrl_tms_mask(enum jtag_tapstate from, static void aspeed_jtag_set_tap_state_hw2(struct aspeed_jtag *aspeed_jtag, struct jtag_tap_state *tapstate) { - u32 reg_val; + u32 reg_val, execute_tck; + u32 tck = tapstate->tck; /* x TMS high + 1 TMS low */ if (tapstate->reset || tapstate->endstate == JTAG_STATE_TLRESET) { @@ -710,20 +707,14 @@ static void aspeed_jtag_set_tap_state_hw2(struct aspeed_jtag *aspeed_jtag, while (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & ASPEED_JTAG_GBLCTRL_FORCE_TMS) ; aspeed_jtag->current_state = JTAG_STATE_TLRESET; - } else if (tapstate->endstate == JTAG_STATE_IDLE && - aspeed_jtag->current_state != JTAG_STATE_IDLE) { - /* Always go to RTI, do not wait for shift operation */ - aspeed_jtag_set_tap_state(aspeed_jtag, - aspeed_jtag->current_state, - JTAG_STATE_IDLE); - aspeed_jtag->current_state = JTAG_STATE_IDLE; - } else { + } else { aspeed_jtag_set_tap_state(aspeed_jtag, aspeed_jtag->current_state, tapstate->endstate); } /* Run TCK */ - if (tapstate->tck) { + while (tck) { + execute_tck = tck > GENMASK(9, 0) ? GENMASK(9, 0) : tck; /* Disable sw mode */ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_PADCTRL0); @@ -732,14 +723,15 @@ static void aspeed_jtag_set_tap_state_hw2(struct aspeed_jtag *aspeed_jtag, aspeed_jtag_write(aspeed_jtag, reg_val | ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | ASPEED_JTAG_GBLCTRL_STSHIFT(0) | - ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(tapstate->tck), + ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(execute_tck), ASPEED_JTAG_GBLCTRL); aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SHCTRL_STSHIFT_EN | - ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(tapstate->tck), + ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(execute_tck), ASPEED_JTAG_SHCTRL); aspeed_jtag_wait_shift_complete(aspeed_jtag); + tck -= execute_tck; } } @@ -748,6 +740,10 @@ static int aspeed_jtag_status_set_26xx(struct jtag *jtag, { struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + if (tapstate->from == JTAG_STATE_CURRENT) + tapstate->from = aspeed_jtag->current_state; + if (tapstate->endstate == JTAG_STATE_CURRENT) + tapstate->endstate = aspeed_jtag->current_state; #ifdef DEBUG_JTAG dev_dbg(aspeed_jtag->dev, "Set TAP state: status %s from %s to %s\n", end_status_str[aspeed_jtag->current_state], @@ -1163,10 +1159,6 @@ static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, exit = JTAG_STATE_EXIT1DR; exitx = JTAG_STATE_EXIT1IR; } - if (aspeed_jtag->current_state == JTAG_STATE_CURRENT) { - dev_warn(aspeed_jtag->dev, "STATE_CURRENT is requested, assigning to State %u", aspeed_jtag->status); - aspeed_jtag->current_state = aspeed_jtag->status; - } #ifdef DEBUG_JTAG dev_dbg(aspeed_jtag->dev, "HW2 JTAG SHIFT %s, length %d status %s from %s to %s then %s pad 0x%x\n", @@ -1176,6 +1168,7 @@ static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, end_status_str[shift], end_status_str[xfer->endstate], xfer->padding); #endif + if (aspeed_jtag->current_state == shift) { start_shift = 0; } else { @@ -1259,10 +1252,7 @@ static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, * Transmit bytes that were not equals to column length * and after the transfer go to Pause IR/DR. */ - dev_dbg(aspeed_jtag->dev, - "SHCTRL_TMS_MASK -- current state %u, shift %u, exit %u, endstate %u\n", - aspeed_jtag->current_state, shift, exit, endstate - ); + ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, endstate, start_shift, 0, &tms_mask); if (ret) @@ -1285,10 +1275,6 @@ static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, /* * Read bytes equals to column length */ - dev_dbg(aspeed_jtag->dev, - "SHCTRL_TMS_MASK -- current state %u, shift %u, exit %u, endstate %u\n", - aspeed_jtag->current_state, shift, exit, endstate - ); shift_bits = remain_xfer; ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, endstate, start_shift, end_shift, diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c index fd94ab2b8e00e6..01030098f914ea 100644 --- a/drivers/jtag/jtag.c +++ b/drivers/jtag/jtag.c @@ -23,7 +23,7 @@ struct jtag { struct miscdevice miscdev; const struct jtag_ops *ops; int id; - unsigned long priv[0]; + unsigned long *priv; }; static DEFINE_IDA(jtag_ida); @@ -111,51 +111,22 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (copy_from_user(&xfer, (const void __user *)arg, sizeof(struct jtag_xfer))) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: copy from user Failed size 0x%lx \n", - sizeof(struct jtag_xfer)); return -EFAULT; - } if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error bad length 0x%x \n", - xfer.length); return -EINVAL; - } if (xfer.type > JTAG_SDR_XFER) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error bad type 0x%x \n", - xfer.type); return -EINVAL; - } if (xfer.direction > JTAG_READ_WRITE_XFER) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error bad direction 0x%x \n", - xfer.direction); return -EINVAL; - } if (xfer.from > JTAG_STATE_CURRENT) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error bad from 0x%x \n", - xfer.from); return -EINVAL; - } + if (xfer.endstate > JTAG_STATE_CURRENT) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error bad endstate 0x%x \n", - xfer.endstate); return -EINVAL; - } data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); @@ -168,29 +139,20 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } if (IS_ERR(xfer_data)) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error in xfer_data \n"); return -EFAULT; - } padding.int_value = xfer.padding; dev_dbg(jtag->miscdev.parent, - "JTAG_IOCXFER: type: %s direction: %d, From: 0x%x END: %s, tdio: %lld, len: %d\n", + "JTAG_IOCXFER: type: %s direction: %d, END : %s, padding: (value: %d) pre_pad: %d post_pad: %d, len: %d\n", xfer.type ? "DR" : "IR", xfer.direction, - xfer.from, end_status_str[xfer.endstate], xfer.tdio, + end_status_str[xfer.endstate], padding.pad_data, + padding.pre_pad_number, padding.post_pad_number, xfer.length); - dev_dbg(jtag->miscdev.parent, - "JTAG_IOCXFER: padding: (value: %d) pre_pad: %d post_pad: %d \n", - padding.pad_data, - padding.pre_pad_number, padding.post_pad_number); print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, data_size, false); err = jtag->ops->xfer(jtag, &xfer, xfer_data); if (err) { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Error jtag->ops->xfer 0x%x \n", err); kfree(xfer_data); return err; } @@ -202,30 +164,15 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) xfer_data[data_size - 1] = (xfer_data[data_size - 1] & ubit_mask) | remaining_bits; - dev_dbg(jtag->miscdev.parent, - "JTAG_IOCXFER: copy_to_user tdio 0x%llx %p xfer_data %p size 0x%x\n", - xfer.tdio, u64_to_user_ptr(xfer.tdio), xfer_data, data_size ); err = copy_to_user(u64_to_user_ptr(xfer.tdio), (void *)xfer_data, data_size); - if (err) { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Failed copy_to_user err 0x%x \n", err); - } kfree(xfer_data); if (err) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Failed to free xfer_data \n"); return -EFAULT; - } if (copy_to_user((void __user *)arg, (void *)&xfer, sizeof(struct jtag_xfer))) - { - dev_err(jtag->miscdev.parent, - "JTAG_IOCXFER: Failed to copy to user area for size 0x%lx \n", sizeof(struct jtag_xfer)); return -EFAULT; - } break; } @@ -283,6 +230,9 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (get_user(active, (__u32 __user *)arg)) return -EFAULT; + dev_dbg(jtag->miscdev.parent, + "JTAG_SIOCTRST: active %d", active); + err = jtag->ops->trst_set(jtag, active); break; @@ -335,9 +285,12 @@ struct jtag *jtag_alloc(struct device *host, size_t priv_size, if (!ops->status_set || !ops->status_get || !ops->xfer) return NULL; - jtag = kzalloc(sizeof(*jtag) + priv_size, GFP_KERNEL); + jtag = kzalloc(sizeof(*jtag), GFP_KERNEL); if (!jtag) return NULL; + jtag->priv = kzalloc(priv_size, GFP_KERNEL); + if (!jtag->priv) + return NULL; jtag->ops = ops; jtag->miscdev.parent = host; @@ -361,7 +314,7 @@ static int jtag_register(struct jtag *jtag) if (!dev) return -ENODEV; - id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); + id = ida_alloc(&jtag_ida, GFP_KERNEL); if (id < 0) return id; @@ -385,7 +338,7 @@ static int jtag_register(struct jtag *jtag) err_jtag_name: kfree(jtag->miscdev.name); err_jtag_alloc: - ida_simple_remove(&jtag_ida, id); + ida_free(&jtag_ida, id); return err; } @@ -393,7 +346,7 @@ static void jtag_unregister(struct jtag *jtag) { misc_deregister(&jtag->miscdev); kfree(jtag->miscdev.name); - ida_simple_remove(&jtag_ida, jtag->id); + ida_free(&jtag_ida, jtag->id); } static void devm_jtag_unregister(struct device *dev, void *res) diff --git a/include/linux/jtag.h b/include/linux/jtag.h index 3b7157df3e4c01..87396ee21df995 100644 --- a/include/linux/jtag.h +++ b/include/linux/jtag.h @@ -9,7 +9,7 @@ #include #include -#define JTAG_MAX_XFER_DATA_LEN (0xFFFFFFFF) //65535 +#define JTAG_MAX_XFER_DATA_LEN (0xFFFFFFFF) struct jtag; /** @@ -23,8 +23,8 @@ struct jtag; * @mode_set: set specific work mode for JTAG. Filled by dev driver * @trst_set: set TRST pin active(pull low) for JTAG. Filled by dev driver * @bitbang: set low level bitbang operations. Filled by dev driver - * @enable: enables JTAG interface in master mode. Filled by dev driver - * @disable: disables JTAG interface master mode. Filled by dev driver + * @enable: enables JTAG interface in controller mode. Filled by dev driver + * @disable: disables JTAG interface controller mode. Filled by dev driver */ struct jtag_ops { int (*freq_get)(struct jtag *jtag, u32 *freq); diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h index 77d0b471efd33f..ed82fbce2c17b1 100644 --- a/include/uapi/linux/jtag.h +++ b/include/uapi/linux/jtag.h @@ -20,16 +20,23 @@ */ #define JTAG_CONTROL_MODE 1 /* - * JTAG_MASTER_OUTPUT_DISABLE: JTAG master mode output disable, it is used to - * enable other devices to own the JTAG bus. + * JTAG_TCK_CYCLE_DELAY_COUNT: JTAG delay counter for aspeed_jtag_tck_cycle. Used + * set the number of jtag_tck_cycle delays repetitions. + * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE + */ +#define JTAG_TCK_CYCLE_DELAY_COUNT 2 +/* + * JTAG_CONTROLLER_OUTPUT_DISABLE: JTAG controller mode output disable, it is + * used to enable other devices to own the JTAG bus. * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE */ -#define JTAG_MASTER_OUTPUT_DISABLE 0 +#define JTAG_CONTROLLER_OUTPUT_DISABLE 0 /* - * JTAG_MASTER_MODE: JTAG master mode. Used to set JTAG controller master mode + * JTAG_CONTROLLER_MODE: JTAG controller mode. Used to set JTAG controller in + * host mode. * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE */ -#define JTAG_MASTER_MODE 1 +#define JTAG_CONTROLLER_MODE 1 /* * JTAG_XFER_HW_MODE: JTAG hardware mode. Used to set HW drived or bitbang * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE @@ -123,7 +130,8 @@ enum jtag_xfer_direction { * * @reset: 0 - run IDLE/PAUSE from current state * 1 - go through TEST_LOGIC/RESET state before IDLE/PAUSE - * @end: completion flag + * @from: initital jtag state + * @endstate: jtag end state * @tck: clock counter * * Structure provide interface to JTAG device for JTAG set state execution. @@ -132,7 +140,7 @@ struct jtag_tap_state { __u8 reset; __u8 from; __u8 endstate; - __u8 tck; + __u32 tck; }; /** @@ -211,8 +219,8 @@ struct tck_bitbang { * struct jtag_mode - jtag mode: * * @feature: 0 - JTAG feature setting selector for JTAG controller HW/SW - * 1 - JTAG feature setting selector for controller bus master - * mode output (enable / disable). + * 1 - JTAG feature setting selector for controller bus mode + * output (enable / disable). * @mode: (0 - SW / 1 - HW) for JTAG_XFER_MODE feature(0) * (0 - output disable / 1 - output enable) for JTAG_CONTROL_MODE * feature(1)