/**
 * Set bit field
 * @param[in] data raw data
 * @param[in] mask bit field mask
 * @param[in] value new value
 * @return new raw data
 */
static uint32_t set(uint32_t data, uint32_t mask, uint32_t value)
{
	return ((value << first_bit_set(mask)) & mask) | (data & ~mask);
}
/*
 * __do_dqs_gw_calib: do DQS gating window calibration.
 * @cbs: pointer to the print_callbacks structure.
 * Return error code.
 */
static int __do_dqs_gw_calib(print_callbacks *cbs)
{
    int err;
    int i, c, f, cnt, max;

    err = -1;

    dqs_gw_coarse = 0;
    dqs_gw_fine = 0;
    for (i = 0; i < DQS_GW_COARSE_MAX; i++) {
        dqs_gw[i] = 0;
    }
    memset((void *)&cur_pwin, 0, sizeof(struct dqs_gw_pass_win));
    memset((void *)&max_pwin, 0, sizeof(struct dqs_gw_pass_win));

    /* enable DQS gating window counter */
    *(volatile unsigned int *)DRAMC_SPCMD |= (1 << 8);

    if (ETT_TUNING_FACTOR_NUMS(dqs_gw_tuning_factors) > 0) {
        ett_recursive_factor_tuning(ETT_TUNING_FACTOR_NUMS(dqs_gw_tuning_factors)-1, dqs_gw_tuning_factors, cbs);
    }

    if (max_pwin.size > 0) {
        /*
         * DQS GW calibration rule 2: From the lastest pass-index, 
         *                            decrease 0.5T (i.e; coarse value - 1),
         *                            check continuous 4 passed window.
         */
#if 0
        print("max pass-window: coarse_end = %d, fine_end = %d\n", max_pwin.coarse_end, max_pwin.fine_end);
#endif
        c = max_pwin.coarse_end;
        for (cnt = 0, f = max_pwin.fine_end; cnt < DQS_GW_FINE_CHK_RANGE && f >= 0; cnt++, f--) {
            if (!(dqs_gw[c - 1] & (1 << f))) {
                break;
            }
#if 0
            print("dqs_gw[%d][%d] = 1'b1\n", c - 1, f);
#endif
            if (f == 0) {
                if (c == 0) {
                    break;
                } else {
                    f = DQS_GW_FINE_MAX - 1;
                    c--;
                }
            }
        }

        if (cnt == DQS_GW_FINE_CHK_RANGE) {
            print("coarse = %s\n", dqsi_gw_dly_coarse_tbl[max_pwin.coarse_end - 1]);
            print("fine = %s\n", dqsi_gw_dly_fine_tbl[max_pwin.fine_end]);
            dqsi_gw_dly_coarse_factor_handler(dqsi_gw_dly_coarse_tbl[max_pwin.coarse_end - 1]);
            dqsi_gw_dly_fine_factor_handler(dqsi_gw_dly_fine_tbl[max_pwin.fine_end]);
            err = 0;
            goto __do_dqs_gw_calib_exit;
        }

        /*
         * DQS GW calibration rule 3: Select a coarse value with the max passed window.
         *                            Select a fine value from the middle of the passed window.
         */
        c = 0;
        for (i = 0; i < DQS_GW_COARSE_MAX; i++) {
            cnt = nr_bit_set(dqs_gw[i]);
#if 0
            print("nr_bit_set(dqs_gw[%d]) = %d\n", i, cnt);
#endif
            if (cnt >= max) {
                max = cnt;
                c = i;
            }
        }
        cnt = nr_bit_set(dqs_gw[c]);
        if (cnt) {
            f = first_bit_set(dqs_gw[c]) + cnt / 2;
            print("coarse = %s\n", dqsi_gw_dly_coarse_tbl[c]);
            print("fine = %s\n", dqsi_gw_dly_fine_tbl[f]);
            dqsi_gw_dly_coarse_factor_handler(dqsi_gw_dly_coarse_tbl[c]);
            dqsi_gw_dly_fine_factor_handler(dqsi_gw_dly_fine_tbl[f]);
            err = 0;
        }
    } else {
        print("Cannot find any pass-window\n");
    }

__do_dqs_gw_calib_exit:
    return err;
}
/**
 * Get bit field
 * @param[in] data raw data
 * @param[in] mask bit field mask
 * @return bit field value
 */
static uint32_t get(uint32_t data, uint32_t mask)
{
	return (data & mask) >> first_bit_set(mask);
}