// SPDX-License-Identifier: GPL-2.0-or-later 
 | 
/* 
 | 
 * altera-jtag.c 
 | 
 * 
 | 
 * altera FPGA driver 
 | 
 * 
 | 
 * Copyright (C) Altera Corporation 1998-2001 
 | 
 * Copyright (C) 2010 NetUP Inc. 
 | 
 * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> 
 | 
 */ 
 | 
  
 | 
#include <linux/delay.h> 
 | 
#include <linux/firmware.h> 
 | 
#include <linux/slab.h> 
 | 
#include <misc/altera.h> 
 | 
#include "altera-exprt.h" 
 | 
#include "altera-jtag.h" 
 | 
  
 | 
#define    alt_jtag_io(a, b, c)\ 
 | 
        astate->config->jtag_io(astate->config->dev, a, b, c); 
 | 
  
 | 
#define    alt_malloc(a)    kzalloc(a, GFP_KERNEL); 
 | 
  
 | 
/* 
 | 
 * This structure shows, for each JTAG state, which state is reached after 
 | 
 * a single TCK clock cycle with TMS high or TMS low, respectively.  This 
 | 
 * describes all possible state transitions in the JTAG state machine. 
 | 
 */ 
 | 
struct altera_jtag_machine { 
 | 
    enum altera_jtag_state tms_high; 
 | 
    enum altera_jtag_state tms_low; 
 | 
}; 
 | 
  
 | 
static const struct altera_jtag_machine altera_transitions[] = { 
 | 
    /* RESET     */    { RESET,    IDLE }, 
 | 
    /* IDLE      */    { DRSELECT,    IDLE }, 
 | 
    /* DRSELECT  */    { IRSELECT,    DRCAPTURE }, 
 | 
    /* DRCAPTURE */    { DREXIT1,    DRSHIFT }, 
 | 
    /* DRSHIFT   */    { DREXIT1,    DRSHIFT }, 
 | 
    /* DREXIT1   */    { DRUPDATE,    DRPAUSE }, 
 | 
    /* DRPAUSE   */    { DREXIT2,    DRPAUSE }, 
 | 
    /* DREXIT2   */    { DRUPDATE,    DRSHIFT }, 
 | 
    /* DRUPDATE  */    { DRSELECT,    IDLE }, 
 | 
    /* IRSELECT  */    { RESET,    IRCAPTURE }, 
 | 
    /* IRCAPTURE */    { IREXIT1,    IRSHIFT }, 
 | 
    /* IRSHIFT   */    { IREXIT1,    IRSHIFT }, 
 | 
    /* IREXIT1   */    { IRUPDATE,    IRPAUSE }, 
 | 
    /* IRPAUSE   */    { IREXIT2,    IRPAUSE }, 
 | 
    /* IREXIT2   */    { IRUPDATE,    IRSHIFT }, 
 | 
    /* IRUPDATE  */    { DRSELECT,    IDLE } 
 | 
}; 
 | 
  
 | 
/* 
 | 
 * This table contains the TMS value to be used to take the NEXT STEP on 
 | 
 * the path to the desired state.  The array index is the current state, 
 | 
 * and the bit position is the desired endstate.  To find out which state 
 | 
 * is used as the intermediate state, look up the TMS value in the 
 | 
 * altera_transitions[] table. 
 | 
 */ 
 | 
static const u16 altera_jtag_path_map[16] = { 
 | 
    /* RST    RTI    SDRS    CDR    SDR    E1DR    PDR    E2DR */ 
 | 
    0x0001,    0xFFFD,    0xFE01,    0xFFE7,    0xFFEF,    0xFF0F,    0xFFBF,    0xFFFF, 
 | 
    /* UDR    SIRS    CIR    SIR    E1IR    PIR    E2IR    UIR */ 
 | 
    0xFEFD,    0x0001,    0xF3FF,    0xF7FF,    0x87FF,    0xDFFF,    0xFFFF,    0x7FFD 
 | 
}; 
 | 
  
 | 
/* Flag bits for alt_jtag_io() function */ 
 | 
#define TMS_HIGH   1 
 | 
#define TMS_LOW    0 
 | 
#define TDI_HIGH   1 
 | 
#define TDI_LOW    0 
 | 
#define READ_TDO   1 
 | 
#define IGNORE_TDO 0 
 | 
  
 | 
int altera_jinit(struct altera_state *astate) 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
  
 | 
    /* initial JTAG state is unknown */ 
 | 
    js->jtag_state = ILLEGAL_JTAG_STATE; 
 | 
  
 | 
    /* initialize to default state */ 
 | 
    js->drstop_state = IDLE; 
 | 
    js->irstop_state = IDLE; 
 | 
    js->dr_pre  = 0; 
 | 
    js->dr_post = 0; 
 | 
    js->ir_pre  = 0; 
 | 
    js->ir_post = 0; 
 | 
    js->dr_length    = 0; 
 | 
    js->ir_length    = 0; 
 | 
  
 | 
    js->dr_pre_data  = NULL; 
 | 
    js->dr_post_data = NULL; 
 | 
    js->ir_pre_data  = NULL; 
 | 
    js->ir_post_data = NULL; 
 | 
    js->dr_buffer     = NULL; 
 | 
    js->ir_buffer     = NULL; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) 
 | 
{ 
 | 
    js->drstop_state = state; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) 
 | 
{ 
 | 
    js->irstop_state = state; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int altera_set_dr_pre(struct altera_jtag *js, 
 | 
                u32 count, u32 start_index, 
 | 
                u8 *preamble_data) 
 | 
{ 
 | 
    int status = 0; 
 | 
    u32 i; 
 | 
    u32 j; 
 | 
  
 | 
    if (count > js->dr_pre) { 
 | 
        kfree(js->dr_pre_data); 
 | 
        js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); 
 | 
        if (js->dr_pre_data == NULL) 
 | 
            status = -ENOMEM; 
 | 
        else 
 | 
            js->dr_pre = count; 
 | 
    } else 
 | 
        js->dr_pre = count; 
 | 
  
 | 
    if (status == 0) { 
 | 
        for (i = 0; i < count; ++i) { 
 | 
            j = i + start_index; 
 | 
  
 | 
            if (preamble_data == NULL) 
 | 
                js->dr_pre_data[i >> 3] |= (1 << (i & 7)); 
 | 
            else { 
 | 
                if (preamble_data[j >> 3] & (1 << (j & 7))) 
 | 
                    js->dr_pre_data[i >> 3] |= 
 | 
                            (1 << (i & 7)); 
 | 
                else 
 | 
                    js->dr_pre_data[i >> 3] &= 
 | 
                            ~(u32)(1 << (i & 7)); 
 | 
  
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, 
 | 
                            u8 *preamble_data) 
 | 
{ 
 | 
    int status = 0; 
 | 
    u32 i; 
 | 
    u32 j; 
 | 
  
 | 
    if (count > js->ir_pre) { 
 | 
        kfree(js->ir_pre_data); 
 | 
        js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); 
 | 
        if (js->ir_pre_data == NULL) 
 | 
            status = -ENOMEM; 
 | 
        else 
 | 
            js->ir_pre = count; 
 | 
  
 | 
    } else 
 | 
        js->ir_pre = count; 
 | 
  
 | 
    if (status == 0) { 
 | 
        for (i = 0; i < count; ++i) { 
 | 
            j = i + start_index; 
 | 
            if (preamble_data == NULL) 
 | 
                js->ir_pre_data[i >> 3] |= (1 << (i & 7)); 
 | 
            else { 
 | 
                if (preamble_data[j >> 3] & (1 << (j & 7))) 
 | 
                    js->ir_pre_data[i >> 3] |= 
 | 
                            (1 << (i & 7)); 
 | 
                else 
 | 
                    js->ir_pre_data[i >> 3] &= 
 | 
                            ~(u32)(1 << (i & 7)); 
 | 
  
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, 
 | 
                        u8 *postamble_data) 
 | 
{ 
 | 
    int status = 0; 
 | 
    u32 i; 
 | 
    u32 j; 
 | 
  
 | 
    if (count > js->dr_post) { 
 | 
        kfree(js->dr_post_data); 
 | 
        js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); 
 | 
  
 | 
        if (js->dr_post_data == NULL) 
 | 
            status = -ENOMEM; 
 | 
        else 
 | 
            js->dr_post = count; 
 | 
  
 | 
    } else 
 | 
        js->dr_post = count; 
 | 
  
 | 
    if (status == 0) { 
 | 
        for (i = 0; i < count; ++i) { 
 | 
            j = i + start_index; 
 | 
  
 | 
            if (postamble_data == NULL) 
 | 
                js->dr_post_data[i >> 3] |= (1 << (i & 7)); 
 | 
            else { 
 | 
                if (postamble_data[j >> 3] & (1 << (j & 7))) 
 | 
                    js->dr_post_data[i >> 3] |= 
 | 
                                (1 << (i & 7)); 
 | 
                else 
 | 
                    js->dr_post_data[i >> 3] &= 
 | 
                        ~(u32)(1 << (i & 7)); 
 | 
  
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, 
 | 
                        u8 *postamble_data) 
 | 
{ 
 | 
    int status = 0; 
 | 
    u32 i; 
 | 
    u32 j; 
 | 
  
 | 
    if (count > js->ir_post) { 
 | 
        kfree(js->ir_post_data); 
 | 
        js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); 
 | 
        if (js->ir_post_data == NULL) 
 | 
            status = -ENOMEM; 
 | 
        else 
 | 
            js->ir_post = count; 
 | 
  
 | 
    } else 
 | 
        js->ir_post = count; 
 | 
  
 | 
    if (status != 0) 
 | 
        return status; 
 | 
  
 | 
    for (i = 0; i < count; ++i) { 
 | 
        j = i + start_index; 
 | 
  
 | 
        if (postamble_data == NULL) 
 | 
            js->ir_post_data[i >> 3] |= (1 << (i & 7)); 
 | 
        else { 
 | 
            if (postamble_data[j >> 3] & (1 << (j & 7))) 
 | 
                js->ir_post_data[i >> 3] |= (1 << (i & 7)); 
 | 
            else 
 | 
                js->ir_post_data[i >> 3] &= 
 | 
                    ~(u32)(1 << (i & 7)); 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
static void altera_jreset_idle(struct altera_state *astate) 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int i; 
 | 
    /* Go to Test Logic Reset (no matter what the starting state may be) */ 
 | 
    for (i = 0; i < 5; ++i) 
 | 
        alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); 
 | 
  
 | 
    /* Now step to Run Test / Idle */ 
 | 
    alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); 
 | 
    js->jtag_state = IDLE; 
 | 
} 
 | 
  
 | 
int altera_goto_jstate(struct altera_state *astate, 
 | 
                    enum altera_jtag_state state) 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int tms; 
 | 
    int count = 0; 
 | 
    int status = 0; 
 | 
  
 | 
    if (js->jtag_state == ILLEGAL_JTAG_STATE) 
 | 
        /* initialize JTAG chain to known state */ 
 | 
        altera_jreset_idle(astate); 
 | 
  
 | 
    if (js->jtag_state == state) { 
 | 
        /* 
 | 
         * We are already in the desired state. 
 | 
         * If it is a stable state, loop here. 
 | 
         * Otherwise do nothing (no clock cycles). 
 | 
         */ 
 | 
        if ((state == IDLE) || (state == DRSHIFT) || 
 | 
            (state == DRPAUSE) || (state == IRSHIFT) || 
 | 
                (state == IRPAUSE)) { 
 | 
            alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); 
 | 
        } else if (state == RESET) 
 | 
            alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); 
 | 
  
 | 
    } else { 
 | 
        while ((js->jtag_state != state) && (count < 9)) { 
 | 
            /* Get TMS value to take a step toward desired state */ 
 | 
            tms = (altera_jtag_path_map[js->jtag_state] & 
 | 
                            (1 << state)) 
 | 
                            ? TMS_HIGH : TMS_LOW; 
 | 
  
 | 
            /* Take a step */ 
 | 
            alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); 
 | 
  
 | 
            if (tms) 
 | 
                js->jtag_state = 
 | 
                    altera_transitions[js->jtag_state].tms_high; 
 | 
            else 
 | 
                js->jtag_state = 
 | 
                    altera_transitions[js->jtag_state].tms_low; 
 | 
  
 | 
            ++count; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (js->jtag_state != state) 
 | 
        status = -EREMOTEIO; 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_wait_cycles(struct altera_state *astate, 
 | 
                    s32 cycles, 
 | 
                    enum altera_jtag_state wait_state) 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int tms; 
 | 
    s32 count; 
 | 
    int status = 0; 
 | 
  
 | 
    if (js->jtag_state != wait_state) 
 | 
        status = altera_goto_jstate(astate, wait_state); 
 | 
  
 | 
    if (status == 0) { 
 | 
        /* 
 | 
         * Set TMS high to loop in RESET state 
 | 
         * Set TMS low to loop in any other stable state 
 | 
         */ 
 | 
        tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; 
 | 
  
 | 
        for (count = 0L; count < cycles; count++) 
 | 
            alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); 
 | 
  
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_wait_msecs(struct altera_state *astate, 
 | 
            s32 microseconds, enum altera_jtag_state wait_state) 
 | 
/* 
 | 
 * Causes JTAG hardware to sit in the specified stable 
 | 
 * state for the specified duration of real time.  If 
 | 
 * no JTAG operations have been performed yet, then only 
 | 
 * a delay is performed.  This permits the WAIT USECS 
 | 
 * statement to be used in VECTOR programs without causing 
 | 
 * any JTAG operations. 
 | 
 * Returns 0 for success, else appropriate error code. 
 | 
 */ 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int status = 0; 
 | 
  
 | 
    if ((js->jtag_state != ILLEGAL_JTAG_STATE) && 
 | 
        (js->jtag_state != wait_state)) 
 | 
        status = altera_goto_jstate(astate, wait_state); 
 | 
  
 | 
    if (status == 0) 
 | 
        /* Wait for specified time interval */ 
 | 
        udelay(microseconds); 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
static void altera_concatenate_data(u8 *buffer, 
 | 
                u8 *preamble_data, 
 | 
                u32 preamble_count, 
 | 
                u8 *target_data, 
 | 
                u32 start_index, 
 | 
                u32 target_count, 
 | 
                u8 *postamble_data, 
 | 
                u32 postamble_count) 
 | 
/* 
 | 
 * Copies preamble data, target data, and postamble data 
 | 
 * into one buffer for IR or DR scans. 
 | 
 */ 
 | 
{ 
 | 
    u32 i, j, k; 
 | 
  
 | 
    for (i = 0L; i < preamble_count; ++i) { 
 | 
        if (preamble_data[i >> 3L] & (1L << (i & 7L))) 
 | 
            buffer[i >> 3L] |= (1L << (i & 7L)); 
 | 
        else 
 | 
            buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); 
 | 
  
 | 
    } 
 | 
  
 | 
    j = start_index; 
 | 
    k = preamble_count + target_count; 
 | 
    for (; i < k; ++i, ++j) { 
 | 
        if (target_data[j >> 3L] & (1L << (j & 7L))) 
 | 
            buffer[i >> 3L] |= (1L << (i & 7L)); 
 | 
        else 
 | 
            buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); 
 | 
  
 | 
    } 
 | 
  
 | 
    j = 0L; 
 | 
    k = preamble_count + target_count + postamble_count; 
 | 
    for (; i < k; ++i, ++j) { 
 | 
        if (postamble_data[j >> 3L] & (1L << (j & 7L))) 
 | 
            buffer[i >> 3L] |= (1L << (i & 7L)); 
 | 
        else 
 | 
            buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); 
 | 
  
 | 
    } 
 | 
} 
 | 
  
 | 
static int alt_jtag_drscan(struct altera_state *astate, 
 | 
            int start_state, 
 | 
            int count, 
 | 
            u8 *tdi, 
 | 
            u8 *tdo) 
 | 
{ 
 | 
    int i = 0; 
 | 
    int tdo_bit = 0; 
 | 
    int status = 1; 
 | 
  
 | 
    /* First go to DRSHIFT state */ 
 | 
    switch (start_state) { 
 | 
    case 0:                        /* IDLE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    case 1:                        /* DRPAUSE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DREXIT2 */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRUPDATE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    case 2:                        /* IRPAUSE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IREXIT2 */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IRUPDATE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* DRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = 0; 
 | 
    } 
 | 
  
 | 
    if (status) { 
 | 
        /* loop in the SHIFT-DR state */ 
 | 
        for (i = 0; i < count; i++) { 
 | 
            tdo_bit = alt_jtag_io( 
 | 
                    (i == count - 1), 
 | 
                    tdi[i >> 3] & (1 << (i & 7)), 
 | 
                    (tdo != NULL)); 
 | 
  
 | 
            if (tdo != NULL) { 
 | 
                if (tdo_bit) 
 | 
                    tdo[i >> 3] |= (1 << (i & 7)); 
 | 
                else 
 | 
                    tdo[i >> 3] &= ~(u32)(1 << (i & 7)); 
 | 
  
 | 
            } 
 | 
        } 
 | 
  
 | 
        alt_jtag_io(0, 0, 0);    /* DRPAUSE */ 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
static int alt_jtag_irscan(struct altera_state *astate, 
 | 
            int start_state, 
 | 
            int count, 
 | 
            u8 *tdi, 
 | 
            u8 *tdo) 
 | 
{ 
 | 
    int i = 0; 
 | 
    int tdo_bit = 0; 
 | 
    int status = 1; 
 | 
  
 | 
    /* First go to IRSHIFT state */ 
 | 
    switch (start_state) { 
 | 
    case 0:                        /* IDLE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    case 1:                        /* DRPAUSE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DREXIT2 */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRUPDATE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    case 2:                        /* IRPAUSE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IREXIT2 */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IRUPDATE */ 
 | 
        alt_jtag_io(1, 0, 0);    /* DRSELECT */ 
 | 
        alt_jtag_io(1, 0, 0);    /* IRSELECT */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRCAPTURE */ 
 | 
        alt_jtag_io(0, 0, 0);    /* IRSHIFT */ 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = 0; 
 | 
    } 
 | 
  
 | 
    if (status) { 
 | 
        /* loop in the SHIFT-IR state */ 
 | 
        for (i = 0; i < count; i++) { 
 | 
            tdo_bit = alt_jtag_io( 
 | 
                      (i == count - 1), 
 | 
                      tdi[i >> 3] & (1 << (i & 7)), 
 | 
                      (tdo != NULL)); 
 | 
            if (tdo != NULL) { 
 | 
                if (tdo_bit) 
 | 
                    tdo[i >> 3] |= (1 << (i & 7)); 
 | 
                else 
 | 
                    tdo[i >> 3] &= ~(u32)(1 << (i & 7)); 
 | 
  
 | 
            } 
 | 
        } 
 | 
  
 | 
        alt_jtag_io(0, 0, 0);    /* IRPAUSE */ 
 | 
    } 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
static void altera_extract_target_data(u8 *buffer, 
 | 
                u8 *target_data, 
 | 
                u32 start_index, 
 | 
                u32 preamble_count, 
 | 
                u32 target_count) 
 | 
/* 
 | 
 * Copies target data from scan buffer, filtering out 
 | 
 * preamble and postamble data. 
 | 
 */ 
 | 
{ 
 | 
    u32 i; 
 | 
    u32 j; 
 | 
    u32 k; 
 | 
  
 | 
    j = preamble_count; 
 | 
    k = start_index + target_count; 
 | 
    for (i = start_index; i < k; ++i, ++j) { 
 | 
        if (buffer[j >> 3] & (1 << (j & 7))) 
 | 
            target_data[i >> 3] |= (1 << (i & 7)); 
 | 
        else 
 | 
            target_data[i >> 3] &= ~(u32)(1 << (i & 7)); 
 | 
  
 | 
    } 
 | 
} 
 | 
  
 | 
int altera_irscan(struct altera_state *astate, 
 | 
                u32 count, 
 | 
                u8 *tdi_data, 
 | 
                u32 start_index) 
 | 
/* Shifts data into instruction register */ 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int start_code = 0; 
 | 
    u32 alloc_chars = 0; 
 | 
    u32 shift_count = js->ir_pre + count + js->ir_post; 
 | 
    int status = 0; 
 | 
    enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; 
 | 
  
 | 
    switch (js->jtag_state) { 
 | 
    case ILLEGAL_JTAG_STATE: 
 | 
    case RESET: 
 | 
    case IDLE: 
 | 
        start_code = 0; 
 | 
        start_state = IDLE; 
 | 
        break; 
 | 
  
 | 
    case DRSELECT: 
 | 
    case DRCAPTURE: 
 | 
    case DRSHIFT: 
 | 
    case DREXIT1: 
 | 
    case DRPAUSE: 
 | 
    case DREXIT2: 
 | 
    case DRUPDATE: 
 | 
        start_code = 1; 
 | 
        start_state = DRPAUSE; 
 | 
        break; 
 | 
  
 | 
    case IRSELECT: 
 | 
    case IRCAPTURE: 
 | 
    case IRSHIFT: 
 | 
    case IREXIT1: 
 | 
    case IRPAUSE: 
 | 
    case IREXIT2: 
 | 
    case IRUPDATE: 
 | 
        start_code = 2; 
 | 
        start_state = IRPAUSE; 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = -EREMOTEIO; 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->jtag_state != start_state) 
 | 
            status = altera_goto_jstate(astate, start_state); 
 | 
  
 | 
    if (status == 0) { 
 | 
        if (shift_count > js->ir_length) { 
 | 
            alloc_chars = (shift_count + 7) >> 3; 
 | 
            kfree(js->ir_buffer); 
 | 
            js->ir_buffer = (u8 *)alt_malloc(alloc_chars); 
 | 
            if (js->ir_buffer == NULL) 
 | 
                status = -ENOMEM; 
 | 
            else 
 | 
                js->ir_length = alloc_chars * 8; 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (status == 0) { 
 | 
        /* 
 | 
         * Copy preamble data, IR data, 
 | 
         * and postamble data into a buffer 
 | 
         */ 
 | 
        altera_concatenate_data(js->ir_buffer, 
 | 
                    js->ir_pre_data, 
 | 
                    js->ir_pre, 
 | 
                    tdi_data, 
 | 
                    start_index, 
 | 
                    count, 
 | 
                    js->ir_post_data, 
 | 
                    js->ir_post); 
 | 
        /* Do the IRSCAN */ 
 | 
        alt_jtag_irscan(astate, 
 | 
                start_code, 
 | 
                shift_count, 
 | 
                js->ir_buffer, 
 | 
                NULL); 
 | 
  
 | 
        /* alt_jtag_irscan() always ends in IRPAUSE state */ 
 | 
        js->jtag_state = IRPAUSE; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->irstop_state != IRPAUSE) 
 | 
            status = altera_goto_jstate(astate, js->irstop_state); 
 | 
  
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_swap_ir(struct altera_state *astate, 
 | 
                u32 count, 
 | 
                u8 *in_data, 
 | 
                u32 in_index, 
 | 
                u8 *out_data, 
 | 
                u32 out_index) 
 | 
/* Shifts data into instruction register, capturing output data */ 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int start_code = 0; 
 | 
    u32 alloc_chars = 0; 
 | 
    u32 shift_count = js->ir_pre + count + js->ir_post; 
 | 
    int status = 0; 
 | 
    enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; 
 | 
  
 | 
    switch (js->jtag_state) { 
 | 
    case ILLEGAL_JTAG_STATE: 
 | 
    case RESET: 
 | 
    case IDLE: 
 | 
        start_code = 0; 
 | 
        start_state = IDLE; 
 | 
        break; 
 | 
  
 | 
    case DRSELECT: 
 | 
    case DRCAPTURE: 
 | 
    case DRSHIFT: 
 | 
    case DREXIT1: 
 | 
    case DRPAUSE: 
 | 
    case DREXIT2: 
 | 
    case DRUPDATE: 
 | 
        start_code = 1; 
 | 
        start_state = DRPAUSE; 
 | 
        break; 
 | 
  
 | 
    case IRSELECT: 
 | 
    case IRCAPTURE: 
 | 
    case IRSHIFT: 
 | 
    case IREXIT1: 
 | 
    case IRPAUSE: 
 | 
    case IREXIT2: 
 | 
    case IRUPDATE: 
 | 
        start_code = 2; 
 | 
        start_state = IRPAUSE; 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = -EREMOTEIO; 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->jtag_state != start_state) 
 | 
            status = altera_goto_jstate(astate, start_state); 
 | 
  
 | 
    if (status == 0) { 
 | 
        if (shift_count > js->ir_length) { 
 | 
            alloc_chars = (shift_count + 7) >> 3; 
 | 
            kfree(js->ir_buffer); 
 | 
            js->ir_buffer = (u8 *)alt_malloc(alloc_chars); 
 | 
            if (js->ir_buffer == NULL) 
 | 
                status = -ENOMEM; 
 | 
            else 
 | 
                js->ir_length = alloc_chars * 8; 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (status == 0) { 
 | 
        /* 
 | 
         * Copy preamble data, IR data, 
 | 
         * and postamble data into a buffer 
 | 
         */ 
 | 
        altera_concatenate_data(js->ir_buffer, 
 | 
                    js->ir_pre_data, 
 | 
                    js->ir_pre, 
 | 
                    in_data, 
 | 
                    in_index, 
 | 
                    count, 
 | 
                    js->ir_post_data, 
 | 
                    js->ir_post); 
 | 
  
 | 
        /* Do the IRSCAN */ 
 | 
        alt_jtag_irscan(astate, 
 | 
                start_code, 
 | 
                shift_count, 
 | 
                js->ir_buffer, 
 | 
                js->ir_buffer); 
 | 
  
 | 
        /* alt_jtag_irscan() always ends in IRPAUSE state */ 
 | 
        js->jtag_state = IRPAUSE; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->irstop_state != IRPAUSE) 
 | 
            status = altera_goto_jstate(astate, js->irstop_state); 
 | 
  
 | 
  
 | 
    if (status == 0) 
 | 
        /* Now extract the returned data from the buffer */ 
 | 
        altera_extract_target_data(js->ir_buffer, 
 | 
                    out_data, out_index, 
 | 
                    js->ir_pre, count); 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_drscan(struct altera_state *astate, 
 | 
                u32 count, 
 | 
                u8 *tdi_data, 
 | 
                u32 start_index) 
 | 
/* Shifts data into data register (ignoring output data) */ 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int start_code = 0; 
 | 
    u32 alloc_chars = 0; 
 | 
    u32 shift_count = js->dr_pre + count + js->dr_post; 
 | 
    int status = 0; 
 | 
    enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; 
 | 
  
 | 
    switch (js->jtag_state) { 
 | 
    case ILLEGAL_JTAG_STATE: 
 | 
    case RESET: 
 | 
    case IDLE: 
 | 
        start_code = 0; 
 | 
        start_state = IDLE; 
 | 
        break; 
 | 
  
 | 
    case DRSELECT: 
 | 
    case DRCAPTURE: 
 | 
    case DRSHIFT: 
 | 
    case DREXIT1: 
 | 
    case DRPAUSE: 
 | 
    case DREXIT2: 
 | 
    case DRUPDATE: 
 | 
        start_code = 1; 
 | 
        start_state = DRPAUSE; 
 | 
        break; 
 | 
  
 | 
    case IRSELECT: 
 | 
    case IRCAPTURE: 
 | 
    case IRSHIFT: 
 | 
    case IREXIT1: 
 | 
    case IRPAUSE: 
 | 
    case IREXIT2: 
 | 
    case IRUPDATE: 
 | 
        start_code = 2; 
 | 
        start_state = IRPAUSE; 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = -EREMOTEIO; 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->jtag_state != start_state) 
 | 
            status = altera_goto_jstate(astate, start_state); 
 | 
  
 | 
    if (status == 0) { 
 | 
        if (shift_count > js->dr_length) { 
 | 
            alloc_chars = (shift_count + 7) >> 3; 
 | 
            kfree(js->dr_buffer); 
 | 
            js->dr_buffer = (u8 *)alt_malloc(alloc_chars); 
 | 
            if (js->dr_buffer == NULL) 
 | 
                status = -ENOMEM; 
 | 
            else 
 | 
                js->dr_length = alloc_chars * 8; 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (status == 0) { 
 | 
        /* 
 | 
         * Copy preamble data, DR data, 
 | 
         * and postamble data into a buffer 
 | 
         */ 
 | 
        altera_concatenate_data(js->dr_buffer, 
 | 
                    js->dr_pre_data, 
 | 
                    js->dr_pre, 
 | 
                    tdi_data, 
 | 
                    start_index, 
 | 
                    count, 
 | 
                    js->dr_post_data, 
 | 
                    js->dr_post); 
 | 
        /* Do the DRSCAN */ 
 | 
        alt_jtag_drscan(astate, start_code, shift_count, 
 | 
                js->dr_buffer, NULL); 
 | 
        /* alt_jtag_drscan() always ends in DRPAUSE state */ 
 | 
        js->jtag_state = DRPAUSE; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->drstop_state != DRPAUSE) 
 | 
            status = altera_goto_jstate(astate, js->drstop_state); 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
int altera_swap_dr(struct altera_state *astate, u32 count, 
 | 
                u8 *in_data, u32 in_index, 
 | 
                u8 *out_data, u32 out_index) 
 | 
/* Shifts data into data register, capturing output data */ 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    int start_code = 0; 
 | 
    u32 alloc_chars = 0; 
 | 
    u32 shift_count = js->dr_pre + count + js->dr_post; 
 | 
    int status = 0; 
 | 
    enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; 
 | 
  
 | 
    switch (js->jtag_state) { 
 | 
    case ILLEGAL_JTAG_STATE: 
 | 
    case RESET: 
 | 
    case IDLE: 
 | 
        start_code = 0; 
 | 
        start_state = IDLE; 
 | 
        break; 
 | 
  
 | 
    case DRSELECT: 
 | 
    case DRCAPTURE: 
 | 
    case DRSHIFT: 
 | 
    case DREXIT1: 
 | 
    case DRPAUSE: 
 | 
    case DREXIT2: 
 | 
    case DRUPDATE: 
 | 
        start_code = 1; 
 | 
        start_state = DRPAUSE; 
 | 
        break; 
 | 
  
 | 
    case IRSELECT: 
 | 
    case IRCAPTURE: 
 | 
    case IRSHIFT: 
 | 
    case IREXIT1: 
 | 
    case IRPAUSE: 
 | 
    case IREXIT2: 
 | 
    case IRUPDATE: 
 | 
        start_code = 2; 
 | 
        start_state = IRPAUSE; 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        status = -EREMOTEIO; 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->jtag_state != start_state) 
 | 
            status = altera_goto_jstate(astate, start_state); 
 | 
  
 | 
    if (status == 0) { 
 | 
        if (shift_count > js->dr_length) { 
 | 
            alloc_chars = (shift_count + 7) >> 3; 
 | 
            kfree(js->dr_buffer); 
 | 
            js->dr_buffer = (u8 *)alt_malloc(alloc_chars); 
 | 
  
 | 
            if (js->dr_buffer == NULL) 
 | 
                status = -ENOMEM; 
 | 
            else 
 | 
                js->dr_length = alloc_chars * 8; 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (status == 0) { 
 | 
        /* 
 | 
         * Copy preamble data, DR data, 
 | 
         * and postamble data into a buffer 
 | 
         */ 
 | 
        altera_concatenate_data(js->dr_buffer, 
 | 
                js->dr_pre_data, 
 | 
                js->dr_pre, 
 | 
                in_data, 
 | 
                in_index, 
 | 
                count, 
 | 
                js->dr_post_data, 
 | 
                js->dr_post); 
 | 
  
 | 
        /* Do the DRSCAN */ 
 | 
        alt_jtag_drscan(astate, 
 | 
                start_code, 
 | 
                shift_count, 
 | 
                js->dr_buffer, 
 | 
                js->dr_buffer); 
 | 
  
 | 
        /* alt_jtag_drscan() always ends in DRPAUSE state */ 
 | 
        js->jtag_state = DRPAUSE; 
 | 
    } 
 | 
  
 | 
    if (status == 0) 
 | 
        if (js->drstop_state != DRPAUSE) 
 | 
            status = altera_goto_jstate(astate, js->drstop_state); 
 | 
  
 | 
    if (status == 0) 
 | 
        /* Now extract the returned data from the buffer */ 
 | 
        altera_extract_target_data(js->dr_buffer, 
 | 
                    out_data, 
 | 
                    out_index, 
 | 
                    js->dr_pre, 
 | 
                    count); 
 | 
  
 | 
    return status; 
 | 
} 
 | 
  
 | 
void altera_free_buffers(struct altera_state *astate) 
 | 
{ 
 | 
    struct altera_jtag *js = &astate->js; 
 | 
    /* If the JTAG interface was used, reset it to TLR */ 
 | 
    if (js->jtag_state != ILLEGAL_JTAG_STATE) 
 | 
        altera_jreset_idle(astate); 
 | 
  
 | 
    kfree(js->dr_pre_data); 
 | 
    js->dr_pre_data = NULL; 
 | 
  
 | 
    kfree(js->dr_post_data); 
 | 
    js->dr_post_data = NULL; 
 | 
  
 | 
    kfree(js->dr_buffer); 
 | 
    js->dr_buffer = NULL; 
 | 
  
 | 
    kfree(js->ir_pre_data); 
 | 
    js->ir_pre_data = NULL; 
 | 
  
 | 
    kfree(js->ir_post_data); 
 | 
    js->ir_post_data = NULL; 
 | 
  
 | 
    kfree(js->ir_buffer); 
 | 
    js->ir_buffer = NULL; 
 | 
} 
 |