Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/jtag/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
62 changes: 24 additions & 38 deletions drivers/jtag/jtag-aspeed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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 |
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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;
Expand All @@ -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) |
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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;
}
}

Expand All @@ -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],
Expand Down Expand Up @@ -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",
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand Down
77 changes: 15 additions & 62 deletions drivers/jtag/jtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -385,15 +338,15 @@ 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;
}

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)
Expand Down
6 changes: 3 additions & 3 deletions include/linux/jtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <linux/types.h>
#include <uapi/linux/jtag.h>

#define JTAG_MAX_XFER_DATA_LEN (0xFFFFFFFF) //65535
#define JTAG_MAX_XFER_DATA_LEN (0xFFFFFFFF)

struct jtag;
/**
Expand All @@ -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);
Expand Down
Loading