#define MODULE "fpga"

#include "common.h"
#include "jtag.h"
#include "fpga.h"
#include "spz.h"

/*
 * See:
 * https://github.com/RichardPlunkett/jrunner-beaglebone/blob/master/jb_jtag.c
 * and the Cyclone III (!) handbook, volume 1, table 9-20, page 9-63
 */
enum JTAG_IR {
    JI_EXTEST           = 0x000,
    JI_PULSE_NCONFIG    = 0x001,
    JI_PROGRAM          = 0x002,
    JI_STARTUP          = 0x003,
    JI_CHECK_STATUS     = 0x004,
    JI_SAMPLE           = 0x005,
    JI_IDCODE           = 0x006,
    JI_USERCODE         = 0x007,
    JI_CONFIG_IO        = 0x00d,
    JI_CLAMP            = 0x00a,
    JI_HIGHZ            = 0x00b,
    JI_EXTEST2          = 0x00f, /* Stratix II, Cyclone II */
    JI_KEY_CLR_VREG     = 0x029,
    JI_KEY_PROG_VOL     = 0x1ad,
    JI_EN_ACTIVE_CLK    = 0x1ee,
    JI_FACTORY          = 0x281,
    JI_ACTIVE_ENGAGE    = 0x2b0,
    JI_ACTIVE_DISENGAGE = 0x2d0,
    JI_DIS_ACTIVE_CLK   = 0x2ee,
    JI_BYPASS           = 0x3ff
};
#define FPGA_IR_LEN 10

/* Copied from the SVF file */
#define JTAG_FPGA_LEADIN_BITS		(22*8)

/*
 * The check status chain seems to match the I/O chain, with in order
 * {output, control, input}; the chain represents the pads in
 * *reverse* order with bits [2:0] corresponding to pad 363 (D3) and
 * [1079:1077] to pad 0; pads 33-36 are the JTAG pins and are not
 * included in the chain.
 */
#define JTAG_FPGA_CHECK_STATUS_BITS	1080
#define PAD_TO_BIT(p,b)	(((359 - ((p) - 4*((p) > 36)))*3)+(b))
#define JTAG_FPGA_CONF_DONE_BIT		 PAD_TO_BIT(227, 1)

#define JTAG_FPGA_HZ	6000000
#define JTAG_FPGA_MS	((JTAG_FPGA_HZ+999)/1000)
#define JTAG_FPGA_US	((JTAG_FPGA_HZ+999999)/1000000)

static const struct jtag_config jtag_config_fpga = {
    .hz      = JTAG_FPGA_HZ,
    .pin_tdi = 16,
    .pin_tdo = 17,
    .pin_tms = 14,
    .pin_tck = 18,
    .be      = false
};

static bool test_bit(const uint32_t *buf, unsigned int bit)
{
    return (buf[bit >> 5] >> (bit & 31)) & 1;
}

static void fpga_finish(void)
{
    tap_goto_state(TAP_RUN_TEST_IDLE);

    /* Park IR at bypass, wait 1 ms */
    tap_set_ir(JI_BYPASS, FPGA_IR_LEN);
    tap_run_test_idle(JTAG_FPGA_MS);

    /* Reset?! */

    jtag_disable(NULL);
}

static uint32_t tap_get_idcode(void)
{
    uint32_t idcode;

    tap_set_ir(JI_IDCODE, FPGA_IR_LEN);
    tap_goto_state(TAP_SHIFT_DR);
    jtag_io(32, JIO_TMS, NULL, &idcode);
    tap_goto_state(TAP_RUN_TEST_IDLE);

    return idcode;
}

/*
 * See the Cyclone IV handbook, volume 1, table 8-17, page 8-59
 * for the programming flow.
 */
int fpga_program_spz(spz_stream *spz)
{
    int err = 0;
    uint32_t idcode;
    uint32_t check_status_buf[(JTAG_FPGA_CHECK_STATUS_BITS+31) >> 5];

    /* Configure JTAG to access the FPGA */
    jtag_enable(&jtag_config_fpga);

    int idcode_loops = 4;
    while (idcode_loops--) {
	idcode = tap_get_idcode();
	if (idcode == spz->header.addr)
	    break;

	MSG("invalid IDCODE %08X expected %08X, %s\n",
	    idcode, spz->header.addr,
	    idcode_loops ? "attempting reset..." : "giving up");

	if (!idcode_loops) {
	    MSG("check for JTAG cable connected, or power cycle board\n");
	    err = FWUPDATE_ERR_FPGA_MISMATCH;
	    goto fail;
	}

	tap_reset();
	jtag_delay(1000);
	tap_goto_state(TAP_SHIFT_DR);
	jtag_io(32, JIO_TMS, NULL, &idcode);
	MSG("IDCODE after reset %08X\n", idcode);
    }

    MSG("IDCODE %08X is valid\n", idcode);

    /* Disengage programming hardware if active */
    tap_set_ir(JI_ACTIVE_DISENGAGE, FPGA_IR_LEN);
    tap_run_test_idle(16);

    tap_set_ir(JI_PROGRAM, FPGA_IR_LEN);
    tap_run_test_idle(16);
    jtag_delay(100);
    tap_run_test_idle(8192);

    /* Leadin: shift in a number of 1s */
    tap_goto_state(TAP_SHIFT_DR);
    jtag_io(JTAG_FPGA_LEADIN_BITS, JIO_TDI, NULL, NULL);

    /* The actual data */
    err = jtag_shift_spz(spz, 0);

    /* 32 bits of 0 terminates the transaction */
    jtag_io(32, JIO_TMS, NULL, NULL);
    tap_goto_state(TAP_RUN_TEST_IDLE);

    /* Check status */
    int check_status_loops = 10;
    while (1) {
	tap_set_ir(JI_CHECK_STATUS, FPGA_IR_LEN);
	tap_run_test_idle(5*JTAG_FPGA_US);

	tap_goto_state(TAP_SHIFT_DR);
	jtag_io(JTAG_FPGA_CHECK_STATUS_BITS, JIO_TMS, NULL, check_status_buf);
	tap_goto_state(TAP_RUN_TEST_IDLE);

	if (!test_bit(check_status_buf, JTAG_FPGA_CONF_DONE_BIT)) {
	    check_status_loops--;

	    MSG("not ready to start... %s\n",
		check_status_loops ? "waiting" : "giving up");

	    if (!check_status_loops) {
		err = FWUPDATE_ERR_FPGA_FAILED;
		goto fail;
	    }

	    jtag_delay(10000);	/* 10 ms */
	} else {
	    MSG("ready to start\n");
	    break;
	}
    }

    /* Go to user mode */
    tap_set_ir(JI_STARTUP, FPGA_IR_LEN);
    tap_run_test_idle((4096*JTAG_FPGA_MS)/1000+512);

    /* Common finish */
 fail:
    fpga_finish();

    return err;
}

int fpga_reset(void)
{
    int err = 0;

    jtag_enable(&jtag_config_fpga);

    tap_run_test_idle(JTAG_FPGA_MS);

    /* Make sure to enable loader (not supposed to be needed...) */
    tap_set_ir(JI_ACTIVE_ENGAGE, FPGA_IR_LEN);
    tap_run_test_idle(16);

    /* Pulse nCONFIG via JTAG */
    tap_set_ir(JI_PULSE_NCONFIG, FPGA_IR_LEN);
    tap_run_test_idle(JTAG_FPGA_MS);

    /* Common finish */
    fpga_finish();

    return err;
}