diff options
author | Huayang Duan <huayang.duan@mediatek.com> | 2018-09-26 14:24:02 +0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2018-10-18 15:01:02 +0000 |
commit | c2ef1029fabfccbdd3e86c5f659f83109313c9f9 (patch) | |
tree | 0d1208ef6a4074b0ea1bf773b1abac6627a2c290 | |
parent | 91a580308ced877813a1a38c1ec1d16e0d397887 (diff) |
mediatek/mt8183: Add EMI init for DDR driver init
Add EMI config to initialize memory.
BRANCH=none
TEST=Boots correctly on Kukui, and inits DRAM successfully with related
patches.
Signed-off-by: Huayang Duan <huayang.duan@mediatek.com>
Change-Id: I945181aa1c901fe78ec1f4478a928c600c1b1dea
Reviewed-on: https://review.coreboot.org/28835
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
-rw-r--r-- | src/soc/mediatek/mt8183/Makefile.inc | 1 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/emi.c | 271 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h | 56 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h | 135 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/include/soc/emi.h | 22 | ||||
-rw-r--r-- | src/soc/mediatek/mt8183/memory.c | 22 |
6 files changed, 505 insertions, 2 deletions
diff --git a/src/soc/mediatek/mt8183/Makefile.inc b/src/soc/mediatek/mt8183/Makefile.inc index c5e8120007..4a5490b64c 100644 --- a/src/soc/mediatek/mt8183/Makefile.inc +++ b/src/soc/mediatek/mt8183/Makefile.inc @@ -21,6 +21,7 @@ verstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c verstage-y += ../common/wdt.c romstage-y += ../common/cbmem.c emi.c +romstage-y += memory.c romstage-y += ../common/gpio.c gpio.c romstage-y += ../common/mmu_operations.c mmu_operations.c romstage-$(CONFIG_SPI_FLASH) += ../common/spi.c spi.c diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c index e37fd56537..7fc1380916 100644 --- a/src/soc/mediatek/mt8183/emi.c +++ b/src/soc/mediatek/mt8183/emi.c @@ -13,9 +13,278 @@ * GNU General Public License for more details. */ +#include <arch/io.h> #include <soc/emi.h> +#include <soc/infracfg.h> +#include <soc/dramc_pi_api.h> +#include <soc/dramc_register.h> + +struct emi_regs *emi_regs = (void *)EMI_BASE; +const u8 phy_mapping[CHANNEL_MAX][16] = { + [CHANNEL_A] = { + 1, 0, 2, 4, 3, 7, 5, 6, + 9, 8, 12, 11, 10, 15, 13, 14 + }, + + [CHANNEL_B] = { + 0, 1, 5, 6, 3, 7, 4, 2, + 9, 8, 12, 15, 11, 14, 13, 10 + } +}; + +void dramc_set_broadcast(u32 onoff) +{ + write32(&mt8183_infracfg->dramc_wbr, onoff); +} + +u32 dramc_get_broadcast(void) +{ + return read32(&mt8183_infracfg->dramc_wbr); +} + +static u64 get_ch_rank_size(u8 chn, u8 rank) +{ + u32 shift_for_16bit = 1; + u32 col_bit, row_bit; + u32 emi_cona = read32(&emi_regs->cona); + + shift_for_16bit = (emi_cona & 0x2) ? 0 : 1; + + col_bit = ((emi_cona >> (chn * 16 + rank * 2 + 4)) & 0x03) + 9; + row_bit = ((((emi_cona >> (24 - chn * 20 + rank)) & 0x01) << 2) + + ((emi_cona >> (12 + chn * 16 + rank * 2)) & 0x03)) + 13; + + /* data width (bytes) * 8 banks */ + return ((u64)(1 << (row_bit + col_bit))) * + ((u64)(4 >> shift_for_16bit) * 8); +} + +void dramc_get_rank_size(u64 *dram_rank_size) +{ + u64 ch0_rank0_size, ch0_rank1_size, ch1_rank0_size, ch1_rank1_size; + u64 ch_rank0_size = 0, ch_rank1_size = 0; + u32 emi_cona = read32(&emi_regs->cona); + u32 emi_conh = read32(&emi_regs->conh); + + dram_rank_size[0] = 0; + dram_rank_size[1] = 0; + + ch0_rank0_size = (emi_conh >> 16) & 0xf; + ch0_rank1_size = (emi_conh >> 20) & 0xf; + ch1_rank0_size = (emi_conh >> 24) & 0xf; + ch1_rank1_size = (emi_conh >> 28) & 0xf; + + /* CH0 EMI */ + if (ch0_rank0_size == 0) + ch_rank0_size = get_ch_rank_size(CHANNEL_A, RANK_0); + else + ch_rank0_size = (ch0_rank0_size * 256 << 20); + + /* dual rank enable */ + if ((emi_cona & (1 << 17)) != 0) { + if (ch0_rank1_size == 0) + ch_rank1_size = get_ch_rank_size(CHANNEL_A, RANK_1); + else + ch_rank1_size = (ch0_rank1_size * 256 << 20); + } + + dram_rank_size[0] = ch_rank0_size; + dram_rank_size[1] = ch_rank1_size; + + if (ch1_rank0_size == 0) + ch_rank0_size = get_ch_rank_size(CHANNEL_B, RANK_0); + else + ch_rank0_size = (ch1_rank0_size * 256 << 20); + + if ((emi_cona & (1 << 16)) != 0) { + if (ch1_rank1_size == 0) + ch_rank1_size = get_ch_rank_size(CHANNEL_B, RANK_1); + else + ch_rank1_size = (ch1_rank1_size * 256 << 20); + } + dram_rank_size[0] += ch_rank0_size; + dram_rank_size[1] += ch_rank1_size; +} size_t sdram_size(void) { - return (size_t)4 * GiB; + size_t dram_size = 0; + u64 rank_size[RANK_MAX]; + + dramc_get_rank_size(&rank_size[0]); + + for (int i = 0; i < RANK_MAX; i++) { + dram_size += rank_size[i]; + dramc_show("rank%d size:0x%llx\n", i, rank_size[i]); + } + + return dram_size; +} + +static void set_rank_info_to_conf(const struct sdram_params *params) +{ + u8 u4value = 0; + + /* CONA 17th bit 0: Disable dual rank mode + * 1: Enable dual rank mode */ + u4value = ((params->emi_cona_val & (0x1 << 17)) >> 17) ? 0 : 1; + clrsetbits_le32(&ch[0].ao.arbctl, 0x1 << 12, u4value << 12); +} + +static void set_MRR_pinmux_mapping(void) +{ + for (u8 chn = 0; chn < CHANNEL_MAX; chn++) { + const u8 *map = phy_mapping[chn]; + write32(&ch[chn].ao.mrr_bit_mux1, + (map[0] << 0) | (map[1] << 8) | + (map[2] << 16) | (map[3] << 24)); + + write32(&ch[chn].ao.mrr_bit_mux2, + (map[4] << 0) | (map[5] << 8) | + (map[6] << 16) | (map[7] << 24)); + + write32(&ch[chn].ao.mrr_bit_mux3, + (map[8] << 0) | (map[9] << 8) | + (map[10] << 16) | (map[11] << 24)); + + write32(&ch[chn].ao.mrr_bit_mux4, + (map[12] << 0) | (map[13] << 8) | + (map[14] << 16) | (map[15] << 24)); + } +} + +static void global_option_init(const struct sdram_params *params) +{ + set_rank_info_to_conf(params); + set_MRR_pinmux_mapping(); +} + +static void emi_esl_setting1(void) +{ + dramc_set_broadcast(DRAMC_BROADCAST_ON); + + write32(&emi_regs->cona, 0xa053a154); + write32(&emi_regs->conb, 0x17283544); + write32(&emi_regs->conc, 0x0a1a0b1a); + write32(&emi_regs->cond, 0x3657587a); + write32(&emi_regs->cone, 0x80400148); + write32(&emi_regs->conf, 0x00000000); + write32(&emi_regs->cong, 0x2b2b2a38); + write32(&emi_regs->conh, 0x00000000); + write32(&emi_regs->coni, 0x00008803); + write32(&emi_regs->conm, 0x000001ff); + write32(&emi_regs->conn, 0x00000000); + write32(&emi_regs->mdct, 0x11338c17); + write32(&emi_regs->mdct_2nd, 0x00001112); + write32(&emi_regs->iocl, 0xa8a8a8a8); + write32(&emi_regs->iocl_2nd, 0x25252525); + write32(&emi_regs->iocm, 0xa8a8a8a8); + write32(&emi_regs->iocm_2nd, 0x25252525); + write32(&emi_regs->testb, 0x00060037); + write32(&emi_regs->testc, 0x38460000); + write32(&emi_regs->testd, 0x00000000); + write32(&emi_regs->arba, 0x4020524f); + write32(&emi_regs->arbb, 0x4020504f); + write32(&emi_regs->arbc, 0xa0a050c6); + write32(&emi_regs->arbd, 0x000070cc); + write32(&emi_regs->arbe, 0x40406045); + write32(&emi_regs->arbf, 0xa0a070d5); + write32(&emi_regs->arbg, 0xa0a0504f); + write32(&emi_regs->arbh, 0xa0a0504f); + write32(&emi_regs->arbi, 0x00007108); + write32(&emi_regs->arbi_2nd, 0x00007108); + write32(&emi_regs->slct, 0x0001ff00); + + write32(&ch[0].emi.chn_cona, 0x0400a051); + write32(&ch[0].emi.chn_conb, 0x00ff2048); + write32(&ch[0].emi.chn_conc, 0x00000000); + write32(&ch[0].emi.chn_mdct, 0x88008817); + write32(&ch[0].emi.chn_testb, 0x00030027); + write32(&ch[0].emi.chn_testc, 0x38460002); + write32(&ch[0].emi.chn_testd, 0x00000000); + write32(&ch[0].emi.chn_md_pre_mask, 0x00000f00); + write32(&ch[0].emi.chn_md_pre_mask_shf, 0x00000b00); + write32(&ch[0].emi.chn_arbi, 0x20406188); + write32(&ch[0].emi.chn_arbi_2nd, 0x20406188); + write32(&ch[0].emi.chn_arbj, 0x3719595e); + write32(&ch[0].emi.chn_arbj_2nd, 0x3719595e); + write32(&ch[0].emi.chn_arbk, 0x64f3fc79); + write32(&ch[0].emi.chn_arbk_2nd, 0x64f3fc79); + write32(&ch[0].emi.chn_slct, 0x00080888); + write32(&ch[0].emi.chn_arb_ref, 0x82410222); + write32(&ch[0].emi.chn_emi_shf0, 0x8a228c17); + write32(&ch[0].emi.chn_rkarb0, 0x0006002f); + write32(&ch[0].emi.chn_rkarb1, 0x01010101); + write32(&ch[0].emi.chn_rkarb2, 0x10100820); + write32(&ch[0].emi.chn_eco3, 0x00000000); + + dramc_set_broadcast(DRAMC_BROADCAST_OFF); +} + +static void emi_esl_setting2(void) +{ + dramc_set_broadcast(DRAMC_BROADCAST_ON); + + write32(&ch[0].emi.chn_conc, 0x01); + write32(&emi_regs->conm, 0x05ff); + + dramc_set_broadcast(DRAMC_BROADCAST_OFF); +} + +static void emi_init(const struct sdram_params *params) +{ + emi_esl_setting1(); + + write32(&emi_regs->cona, params->emi_cona_val); + write32(&emi_regs->conf, params->emi_conf_val); + write32(&emi_regs->conh, params->emi_conh_val); + + for (size_t chn = CHANNEL_A; chn < CHANNEL_MAX; chn++) { + write32(&ch[chn].emi.chn_cona, params->chn_emi_cona_val[chn]); + write32(&ch[chn].emi.chn_conc, 0); + } +} + +static void emi_init2(const struct sdram_params *params) +{ + emi_esl_setting2(); + + setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 1, 0x1 << 4); + setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 7, 0x1 << 4); + + write32(&emi_regs->bwct0, 0x0a000705); + write32(&emi_regs->bwct0_3rd, 0x0); + + /* EMI QoS 0.5 */ + write32(&emi_regs->bwct0_2nd, 0x00030023); + write32(&emi_regs->bwct0_4th, 0x00c00023); + write32(&emi_regs->bwct0_5th, 0x00240023); +} + +static void dramc_init_pre_settings(void) +{ + clrsetbits_le32(&ch[0].phy.ca_cmd[8], + (0x1 << 21) | (0x1 << 20) | (0x1 << 19) | (0x1 << 18) | + (0x1f << 8) | (0x1f << 0), + (0x1 << 19) | (0xa << 8) | (0xa << 0)); + + setbits_le32(&ch[0].phy.misc_ctrl1, 0x1 << 12); + clrbits_le32(&ch[0].phy.misc_ctrl1, 0x1 << 13); + setbits_le32(&ch[0].phy.misc_ctrl1, 0x1 << 31); +} + +static void init_dram(const struct sdram_params *params) +{ + global_option_init(params); + emi_init(params); + + dramc_set_broadcast(DRAMC_BROADCAST_ON); + dramc_init_pre_settings(); + + emi_init2(params); +} + +void mt_set_emi(const struct sdram_params *params) +{ + init_dram(params); } diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h new file mode 100644 index 0000000000..e699e80f8b --- /dev/null +++ b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 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_COMMON_MT8183_H_ +#define _DRAMC_COMMON_MT8183_H_ + +#define DRAM_DFS_SHUFFLE_MAX 3 + +enum { + CHANNEL_A = 0, + CHANNEL_B, + CHANNEL_MAX +}; + +enum { + RANK_0 = 0, + RANK_1, + RANK_MAX +}; + +enum dram_odt_type { + ODT_OFF = 0, + ODT_ON +}; + +enum { + DQ_DATA_WIDTH = 16, + DQS_BIT_NUMBER = 8, + DQS_NUMBER = (DQ_DATA_WIDTH / DQS_BIT_NUMBER) +}; + +/* + * Internal CBT mode enum + * 1. Calibration flow uses vGet_Dram_CBT_Mode to + * differentiate between mixed vs non-mixed LP4 + * 2. Declared as dram_cbt_mode[RANK_MAX] internally to + * store each rank's CBT mode type + */ +enum { + CBT_NORMAL_MODE = 0, + CBT_BYTE_MODE1 +}; + +#endif /* _DRAMC_COMMON_MT8183_H_ */ diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h new file mode 100644 index 0000000000..e24bd6c8e8 --- /dev/null +++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h @@ -0,0 +1,135 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 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_MT8183_H +#define _DRAMC_PI_API_MT8183_H + +#include <types.h> +#include <soc/emi.h> +#include <console/console.h> + +#define dramc_show(_x_...) printk(BIOS_INFO, _x_) +#if IS_ENABLED(CONFIG_DEBUG_DRAM) +#define dramc_dbg(_x_...) printk(BIOS_DEBUG, _x_) +#else +#define dramc_dbg(_x_...) +#endif + +#define ENABLE 1 +#define DISABLE 0 + +#define DATLAT_TAP_NUMBER 32 + +#define MAX_CMP_CPT_WAIT_LOOP 10000 +#define TIME_OUT_CNT 100 + +#define DRAMC_BROADCAST_ON 0x1f +#define DRAMC_BROADCAST_OFF 0x0 +#define MAX_BACKUP_REG_CNT 32 + +enum dram_te_op { + TE_OP_WRITE_READ_CHECK = 0, + TE_OP_READ_CHECK +}; + +enum { + DBI_OFF = 0, + DBI_ON +}; + +enum { + FSP_0 = 0, + FSP_1, + FSP_MAX +}; + +enum { + TX_DQ_DQS_MOVE_DQ_ONLY = 0, + TX_DQ_DQS_MOVE_DQM_ONLY, + TX_DQ_DQS_MOVE_DQ_DQM +}; + +enum { + MAX_CA_FINE_TUNE_DELAY = 63, + MAX_CS_FINE_TUNE_DELAY = 63, + MAX_CLK_FINE_TUNE_DELAY = 31, + CATRAINING_NUM = 6, + PASS_RANGE_NA = 0x7fff +}; + +enum { + GATING_OFF = 0, + GATING_ON = 1 +}; + +enum { + CKE_FIXOFF = 0, + CKE_FIXON, + CKE_DYNAMIC +}; + +enum { + GATING_PATTERN_NUM = 0x23, + GATING_GOLDEND_DQSCNT = 0x4646 +}; + +enum { + IMPCAL_STAGE_DRVP = 0x1, + IMPCAL_STAGE_DRVN, + IMPCAL_STAGE_TRACKING +}; + +enum { + DQS_GW_COARSE_STEP = 1, + DQS_GW_FINE_START = 0, + DQS_GW_FINE_END = 32, + DQS_GW_FINE_STEP = 4, + DQS_GW_FREQ_DIV = 4, + RX_DQS_CTL_LOOP = 8, + RX_DLY_DQSIENSTB_LOOP = 32 +}; + +enum { + SAVE_VALUE, + RESTORE_VALUE +}; + +enum { + DQ_DIV_SHIFT = 3, + DQ_DIV_MASK = BIT(DQ_DIV_SHIFT) - 1, + OEN_SHIFT = 16, + + DQS_DELAY_2T = 3, + DQS_DELAY_0P5T = 4, + DQS_DELAY = ((DQS_DELAY_2T << DQ_DIV_SHIFT) + DQS_DELAY_0P5T) << 5, + + DQS_OEN_DELAY_2T = 3, + DQS_OEN_DELAY_0P5T = 1, + + SELPH_DQS0 = (DQS_DELAY_2T << 0) | (DQS_DELAY_2T << 4) | + (DQS_DELAY_2T << 8) | (DQS_DELAY_2T << 12) | + (DQS_OEN_DELAY_2T << 16) | (DQS_OEN_DELAY_2T << 20) | + (DQS_OEN_DELAY_2T << 24) | (DQS_OEN_DELAY_2T << 28), + + SELPH_DQS1 = (DQS_DELAY_0P5T << 0) | (DQS_DELAY_0P5T << 4) | + (DQS_DELAY_0P5T << 8) | (DQS_DELAY_0P5T << 12) | + (DQS_OEN_DELAY_0P5T << 16) | (DQS_OEN_DELAY_0P5T << 20) | + (DQS_OEN_DELAY_0P5T << 24) | (DQS_OEN_DELAY_0P5T << 28) +}; + +void dramc_get_rank_size(u64 *dram_rank_size); +void dramc_set_broadcast(u32 onoff); +u32 dramc_get_broadcast(void); +#endif /* _DRAMC_PI_API_MT8183_H */ diff --git a/src/soc/mediatek/mt8183/include/soc/emi.h b/src/soc/mediatek/mt8183/include/soc/emi.h index edc27a8c99..c3c8e81cfa 100644 --- a/src/soc/mediatek/mt8183/include/soc/emi.h +++ b/src/soc/mediatek/mt8183/include/soc/emi.h @@ -18,7 +18,27 @@ #include <stdint.h> #include <types.h> +#include <soc/dramc_common_mt8183.h> +struct sdram_params { + u32 impedance[2][4]; + u8 wr_level[CHANNEL_MAX][RANK_MAX][DQS_NUMBER]; + u8 cbt_cs[CHANNEL_MAX][RANK_MAX]; + u8 cbt_mr12[CHANNEL_MAX][RANK_MAX]; + s8 clk_delay; + s8 dqs_delay[CHANNEL_MAX]; + u32 emi_cona_val; + u32 emi_conh_val; + u32 emi_conf_val; + u32 chn_emi_cona_val[CHANNEL_MAX]; + u32 cbt_mode_extern; + u16 delay_cell_unit; +}; + +int complex_mem_test(u8 *start, unsigned int len); size_t sdram_size(void); +const struct sdram_params *get_sdram_config(void); +void mt_set_emi(const struct sdram_params *params); +void mt_mem_init(const struct sdram_params *params); -#endif +#endif /* SOC_MEDIATEK_MT8183_EMI_H */ diff --git a/src/soc/mediatek/mt8183/memory.c b/src/soc/mediatek/mt8183/memory.c new file mode 100644 index 0000000000..643ca6bb2f --- /dev/null +++ b/src/soc/mediatek/mt8183/memory.c @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 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. + */ + +#include <soc/emi.h> + +void mt_mem_init(const struct sdram_params *params) +{ + /* memory calibration */ + mt_set_emi(params); +} |