/*
 * This file is part of the coreboot project.
 *
 * Copyright 2015 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _DRAMC_PI_API_H
#define _DRAMC_PI_API_H

#include <soc/emi.h>
#include <console/console.h>

enum {
	MAX_CLKO_DELAY = 15
};

enum {
	/* jitter meter for PLL phase calibration */
	JMETER_COUNT = 1024,
	JMETER_COUNT_N = JMETER_COUNT/10,
	/* 10us for more margin, Fin = 52 */
	JMETER_WAIT_DONE_US = (JMETER_COUNT/52 + 10)
};

enum {
	DLE_TEST_NUM = 4
};

enum {
	/* window type: tx/rx */
	RX_WIN = 0,
	TX_WIN = 1,
	/* stage type: setup/hold time */
	STAGE_SETUP = 0,
	STAGE_HOLD = 1,
	/* combinational flags of stage and window type */
	STAGE_SETUP_RX_WIN = STAGE_SETUP | RX_WIN << 1,
	STAGE_SETUP_TX_WIN = STAGE_SETUP | TX_WIN << 1,
	STAGE_HOLD_RX_WIN = STAGE_HOLD | RX_WIN << 1,
	STAGE_HOLD_TX_WIN = STAGE_HOLD | TX_WIN << 1
};

enum {
	RX_DQ = 0,
	RX_DQS,
	TX_DQ,
	TX_DQS,
	TX_DQM
};

enum {
	AUDIO = 1,
	XTALK,
	ISI
};

enum {
	MEMPLL_INIT = 0,
	MEMPLL_REF_LAG,
	MEMPLL_REF_LEAD
};

enum {
	FIRST_DQ_DELAY = 0,       /* first DQ delay taps */
	FIRST_DQS_DELAY = 0,      /* first DQS delay taps */
	MAX_DQDLY_TAPS = 16,	  /* max DQ delay taps */
	MAX_TX_DQSDLY_TAPS = 16,  /* max TX DQS delay taps */
	MAX_RX_DQSDLY_TAPS = 64   /* max RX DQS delay taps */
};

enum {
	DRAMK_READ = 0,
	DRAMK_WRITE = 1
};

enum {
	ENABLE = 1,
	DISABLE = 0
};

enum {
	DATA_WIDTH_16BIT = 16,
	DATA_WIDTH_32BIT = 32
};

enum dram_tw_op {
	TE_OP_WRITE_READ_CHECK = 0,
	TE_OP_READ_CHECK
};

enum {
	DQS_GW_TE_OFFSET = 0x10,
	DQS_GW_GOLD_COUNTER_32BIT = 0x20202020,
	DQS_GW_PATTERN1 = 0xaa000000,
	DQS_GW_PATTERN2 = 0x55000000
};

enum {
	/* pattern0 and base address for test engine when we do calibration */
	DEFAULT_TEST2_1_CAL = 0x55000000,
	/* for testing, to separate TA4-3 address for running simultaneously */
	/* pattern1 and offset address for test engine when we  do calibraion */
	DEFAULT_TEST2_2_CAL = 0xaa000400,
	/* pattern0 and base addr. for test engine when doing dqs GW */
	DEFAULT_TEST2_1_DQSIEN = 0x55000000,
	/* pattern1 and offset addr. for test engine when doing dqs GW */
	DEFAULT_TEST2_2_DQSIEN = 0xaa000010,
	/* gold pattern */
	DEFAULT_GOLD_DQSIEN = 0x20202020
};

enum {
	TEST_ISI_PATTERN = 0,
	TEST_AUDIO_PATTERN,
	TEST_TA1_SIMPLE,
	TEST_TESTPAT4,
	TEST_TESTPAT4_3,
	TEST_XTALK_PATTERN,
	TEST_MIX_PATTERN
};

struct dqs_perbit_dly {
	s8 first_dqdly_pass;
	s8 last_dqdly_pass;
	s8 first_dqsdly_pass;
	s8 last_dqsdly_pass;
	s8 best_first_dqdly_pass;
	s8 best_last_dqdly_pass;
	s8 best_first_dqsdly_pass;
	s8 best_last_dqsdly_pass;
	u8 best_dqdly;
	u8 best_dqsdly;
};

void transfer_to_spm_control(void);
void transfer_to_reg_control(void);
void dramc_phy_reset(u32 channel);
void clk_duty_cal(u32 channel);
void div2_phase_sync(void);
void dramc_runtime_config(u32 channel, const struct mt8173_sdram_params *sdram_params);
void dramc_rankinctl_config(u32 channel, const struct mt8173_sdram_params *sdram_params);

/* dramc init prototypes */
void mem_pll_init(const struct mt8173_sdram_params *sdram_params);
void dramc_init(u32 channel, const struct mt8173_sdram_params *sdram_params);
void dramc_pre_init(u32 channel, const struct mt8173_sdram_params *sdram_params);

/* mandatory calibration function prototypes */
void tx_window_perbit_cal(u32 channel);
void rx_window_perbit_cal(u32 channel);
void perbit_window_cal(u32 channel, u8 type);
void sw_impedance_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
void ca_training(u32 channel, const struct mt8173_sdram_params *sdram_params);
void rx_dqs_gating_cal(u32 channel, u8 rank, const struct mt8173_sdram_params *sdram_params);
void dual_rank_rx_datlat_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
void dual_rank_rx_dqs_gating_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
void write_leveling(u32 channel, const struct mt8173_sdram_params *sdram_params);

u8 dramk_calcu_best_dly(u8 bit, struct dqs_perbit_dly *p, u8 *p_max_byte);
u8 is_dual_rank(u32 channel, const struct mt8173_sdram_params *sdram_params);
u8 rx_datlat_cal(u32 channel, u8 rank, const struct mt8173_sdram_params *sdram_params);
u32 dram_k_perbit(u32 channel);
u32 dramc_engine2(u32 channel, enum dram_tw_op wr, u32 test2_1, u32 test2_2,
		  u8 testaudpat, u8 log2loopcount);

void dramk_check_dqs_win(struct dqs_perbit_dly *p, u8 dly_step, u8 last_step, u32 fail_bit);
void dramk_check_dq_win(struct dqs_perbit_dly *p, u8 dly_step, u8 last_step, u32 fail_bit);

void tx_delay_for_wrleveling(u32 channel, struct dqs_perbit_dly *dqdqs_perbit_dly,
			     u8 *ave_dqdly_byte, u8 *max_dqsdly_byte);

#if IS_ENABLED(CONFIG_DEBUG_DRAM)
#define dramc_dbg_msg(_x_...) printk(BIOS_DEBUG, _x_)
#else
#define dramc_dbg_msg(_x_...)
#endif

#endif /* _PI_API_H */
