e951e8ec7f
Change-Id: I0442cc5bc54efd7e2c4e5496182c8df85acbcf91 Signed-off-by: Elyes HAOUAS <ehaouas@noos.fr> Reviewed-on: https://review.coreboot.org/c/coreboot/+/33491 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
420 lines
12 KiB
C
420 lines
12 KiB
C
/*
|
|
* This file is part of the coreboot project.
|
|
*
|
|
* Copyright (C) 2007-2008 coresystems GmbH
|
|
* 2012 secunet Security Networks AG
|
|
* Copyright (C) 2015 Damien Zammit <damien@zamaudio.com>
|
|
*
|
|
* 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 __NORTHBRIDGE_INTEL_X4X_H__
|
|
#define __NORTHBRIDGE_INTEL_X4X_H__
|
|
|
|
/*
|
|
* D0:F0
|
|
*/
|
|
#define D0F0_EPBAR_LO 0x40
|
|
#define D0F0_EPBAR_HI 0x44
|
|
#define D0F0_MCHBAR_LO 0x48
|
|
#define D0F0_MCHBAR_HI 0x4c
|
|
#define D0F0_GGC 0x52
|
|
#define D0F0_DEVEN 0x54
|
|
#define D0EN (1 << 0)
|
|
#define D1EN (1 << 1)
|
|
#define IGD0EN (1 << 3)
|
|
#define IGD1EN (1 << 4)
|
|
#define D3F0EN (1 << 6)
|
|
#define D3F1EN (1 << 7)
|
|
#define D3F2EN (1 << 8)
|
|
#define D3F3EN (1 << 9)
|
|
#define PEG1EN (1 << 13)
|
|
#define BOARD_DEVEN (D0EN | D1EN | IGD0EN | IGD1EN | PEG1EN)
|
|
#define D0F0_PCIEXBAR_LO 0x60
|
|
#define D0F0_PCIEXBAR_HI 0x64
|
|
#define D0F0_DMIBAR_LO 0x68
|
|
#define D0F0_DMIBAR_HI 0x6c
|
|
#define D0F0_PAM(x) (0x90+(x)) /* 0-6*/
|
|
#define D0F0_REMAPBASE 0x98
|
|
#define D0F0_REMAPLIMIT 0x9a
|
|
#define D0F0_SMRAM 0x9d
|
|
#define D0F0_ESMRAMC 0x9e
|
|
#define D0F0_TOM 0xa0
|
|
#define D0F0_TOUUD 0xa2
|
|
#define D0F0_TOLUD 0xb0
|
|
#define D0F0_GBSM 0xa4
|
|
#define D0F0_BGSM 0xa8
|
|
#define D0F0_TSEG 0xac
|
|
#define D0F0_SKPD 0xdc /* Scratchpad Data */
|
|
#define D0F0_CAPID0 0xe0
|
|
|
|
/*
|
|
* D1:F0 PEG
|
|
*/
|
|
#define PEG_CAP 0xa2
|
|
#define SLOTCAP 0xb4
|
|
#define PEGLC 0xec
|
|
#define D1F0_VCCAP 0x104
|
|
#define D1F0_VC0RCTL 0x114
|
|
|
|
/*
|
|
* Graphics frequencies
|
|
*/
|
|
#define GCFGC_PCIDEV PCI_DEV(0, 2, 0)
|
|
#define GCFGC_OFFSET 0xf0
|
|
#define GCFGC_CR_SHIFT 0
|
|
#define GCFGC_CR_MASK (0xf << GCFGC_CR_SHIFT)
|
|
#define GCFGC_CS_SHIFT 8
|
|
#define GCFGC_CS_MASK (0xf << GCFGC_CS_SHIFT)
|
|
#define GCFGC_CD_SHIFT 12
|
|
#define GCFGC_CD_MASK (0x1 << GCFGC_CD_SHIFT)
|
|
#define GCFGC_UPDATE_SHIFT 5
|
|
#define GCFGC_UPDATE (0x1 << GCFGC_UPDATE_SHIFT)
|
|
|
|
/*
|
|
* MCHBAR
|
|
*/
|
|
|
|
#define MCHBAR8(x) (*((volatile u8 *)(DEFAULT_MCHBAR + (x))))
|
|
#define MCHBAR16(x) (*((volatile u16 *)(DEFAULT_MCHBAR + (x))))
|
|
#define MCHBAR32(x) (*((volatile u32 *)(DEFAULT_MCHBAR + (x))))
|
|
#define MCHBAR8_AND(x, and) (MCHBAR8(x) = MCHBAR8(x) & (and))
|
|
#define MCHBAR8_OR(x, or) (MCHBAR8(x) = MCHBAR8(x) | (or))
|
|
#define MCHBAR8_AND_OR(x, and, or) \
|
|
(MCHBAR8(x) = (MCHBAR8(x) & (and)) | (or))
|
|
#define MCHBAR16_AND(x, and) (MCHBAR16(x) = MCHBAR16(x) & (and))
|
|
#define MCHBAR16_OR(x, or) (MCHBAR16(x) = MCHBAR16(x) | (or))
|
|
#define MCHBAR16_AND_OR(x, and, or) \
|
|
(MCHBAR16(x) = (MCHBAR16(x) & (and)) | (or))
|
|
#define MCHBAR32_AND(x, and) (MCHBAR32(x) = MCHBAR32(x) & (and))
|
|
#define MCHBAR32_OR(x, or) (MCHBAR32(x) = MCHBAR32(x) | (or))
|
|
#define MCHBAR32_AND_OR(x, and, or) \
|
|
(MCHBAR32(x) = (MCHBAR32(x) & (and)) | (or))
|
|
|
|
#define CHDECMISC 0x111
|
|
#define STACKED_MEM (1 << 1)
|
|
|
|
#define C0DRB0 0x200
|
|
#define C0DRB1 0x202
|
|
#define C0DRB2 0x204
|
|
#define C0DRB3 0x206
|
|
#define C0DRA01 0x208
|
|
#define C0DRA23 0x20a
|
|
#define C0CKECTRL 0x260
|
|
|
|
#define C1DRB0 0x600
|
|
#define C1DRB1 0x602
|
|
#define C1DRB2 0x604
|
|
#define C1DRB3 0x606
|
|
#define C1DRA01 0x608
|
|
#define C1DRA23 0x60a
|
|
#define C1CKECTRL 0x660
|
|
|
|
#define PMSTS_MCHBAR 0x0f14 /* Self refresh channel status */
|
|
#define PMSTS_WARM_RESET (1 << 8)
|
|
#define PMSTS_BOTH_SELFREFRESH (3 << 0)
|
|
|
|
#define CLKCFG_MCHBAR 0x0c00
|
|
#define CLKCFG_FSBCLK_SHIFT 0
|
|
#define CLKCFG_FSBCLK_MASK (7 << CLKCFG_FSBCLK_SHIFT)
|
|
#define CLKCFG_MEMCLK_SHIFT 4
|
|
#define CLKCFG_MEMCLK_MASK (7 << CLKCFG_MEMCLK_SHIFT)
|
|
#define CLKCFG_UPDATE (1 << 12)
|
|
|
|
#define SSKPD_MCHBAR 0x0c20 /* 64 bit */
|
|
|
|
/*
|
|
* DMIBAR
|
|
*/
|
|
|
|
#define DMIBAR8(x) (*((volatile u8 *)(DEFAULT_DMIBAR + (x))))
|
|
#define DMIBAR16(x) (*((volatile u16 *)(DEFAULT_DMIBAR + (x))))
|
|
#define DMIBAR32(x) (*((volatile u32 *)(DEFAULT_DMIBAR + (x))))
|
|
|
|
#define DMIVC0RCTL 0x14
|
|
#define DMIVC1RCTL 0x20
|
|
#define DMIVC1RSTS 0x26
|
|
#define DMIESD 0x44
|
|
#define DMILE1D 0x50
|
|
#define DMILE1A 0x58
|
|
#define DMILE2D 0x60
|
|
#define DMILE2A 0x68
|
|
|
|
/*
|
|
* EPBAR
|
|
*/
|
|
|
|
#define EPBAR8(x) (*((volatile u8 *)(DEFAULT_EPBAR + (x))))
|
|
#define EPBAR16(x) (*((volatile u16 *)(DEFAULT_EPBAR + (x))))
|
|
#define EPBAR32(x) (*((volatile u32 *)(DEFAULT_EPBAR + (x))))
|
|
|
|
#define EPESD 0x44
|
|
#define EPLE1D 0x50
|
|
#define EPLE1A 0x58
|
|
#define EPLE2D 0x60
|
|
|
|
#define NOP_CMD 0x2
|
|
#define PRECHARGE_CMD 0x4
|
|
#define MRS_CMD 0x6
|
|
#define EMRS_CMD 0x8
|
|
#define EMRS1_CMD (EMRS_CMD | 0x10)
|
|
#define EMRS2_CMD (EMRS_CMD | 0x20)
|
|
#define EMRS3_CMD (EMRS_CMD | 0x30)
|
|
#define ZQCAL_CMD 0xa
|
|
#define CBR_CMD 0xc
|
|
#define NORMALOP_CMD 0xe
|
|
|
|
#define TOTAL_CHANNELS 2
|
|
#define TOTAL_DIMMS 4
|
|
#define TOTAL_BYTELANES 8
|
|
#define DIMMS_PER_CHANNEL (TOTAL_DIMMS / TOTAL_CHANNELS)
|
|
#define RAW_CARD_UNPOPULATED 0xff
|
|
#define RAW_CARD_POPULATED 0
|
|
|
|
#define DIMM_IS_POPULATED(dimms, idx) (dimms[idx].card_type != RAW_CARD_UNPOPULATED)
|
|
#define IF_DIMM_POPULATED(dimms, idx) if (dimms[idx].card_type != RAW_CARD_UNPOPULATED)
|
|
#define ONLY_DIMMA_IS_POPULATED(dimms, ch) ( \
|
|
(DIMM_IS_POPULATED(dimms, (ch == 0) ? 0 : 2) && \
|
|
!DIMM_IS_POPULATED(dimms, (ch == 0) ? 1 : 3)))
|
|
#define ONLY_DIMMB_IS_POPULATED(dimms, ch) ( \
|
|
(DIMM_IS_POPULATED(dimms, (ch == 0) ? 1 : 3) && \
|
|
!DIMM_IS_POPULATED(dimms, (ch == 0) ? 0 : 2)))
|
|
#define BOTH_DIMMS_ARE_POPULATED(dimms, ch) ( \
|
|
(DIMM_IS_POPULATED(dimms, (ch == 0) ? 0 : 2) && \
|
|
(DIMM_IS_POPULATED(dimms, (ch == 0) ? 1 : 3))))
|
|
#define FOR_EACH_DIMM(idx) \
|
|
for (idx = 0; idx < TOTAL_DIMMS; ++idx)
|
|
#define FOR_EACH_POPULATED_DIMM(dimms, idx) \
|
|
FOR_EACH_DIMM(idx) IF_DIMM_POPULATED(dimms, idx)
|
|
#define FOR_EACH_DIMM_IN_CHANNEL(ch, idx) \
|
|
for (idx = (ch) << 1; idx < ((ch) << 1) + DIMMS_PER_CHANNEL; ++idx)
|
|
#define FOR_EACH_POPULATED_DIMM_IN_CHANNEL(dimms, ch, idx) \
|
|
FOR_EACH_DIMM_IN_CHANNEL(ch, idx) IF_DIMM_POPULATED(dimms, idx)
|
|
#define CHANNEL_IS_POPULATED(dimms, idx) \
|
|
((dimms[idx<<1].card_type != RAW_CARD_UNPOPULATED) \
|
|
|| (dimms[(idx<<1) + 1].card_type != RAW_CARD_UNPOPULATED))
|
|
#define CHANNEL_IS_CARDF(dimms, idx) \
|
|
((dimms[idx<<1].card_type == 0xf) \
|
|
|| (dimms[(idx<<1) + 1].card_type == 0xf))
|
|
#define IF_CHANNEL_POPULATED(dimms, idx) \
|
|
if ((dimms[idx<<1].card_type != RAW_CARD_UNPOPULATED) \
|
|
|| (dimms[(idx<<1) + 1].card_type != RAW_CARD_UNPOPULATED))
|
|
#define FOR_EACH_CHANNEL(idx) \
|
|
for (idx = 0; idx < TOTAL_CHANNELS; ++idx)
|
|
#define FOR_EACH_POPULATED_CHANNEL(dimms, idx) \
|
|
FOR_EACH_CHANNEL(idx) IF_CHANNEL_POPULATED(dimms, idx)
|
|
|
|
#define RANKS_PER_CHANNEL 4
|
|
#define RANK_IS_POPULATED(dimms, ch, r) \
|
|
(((dimms[ch<<1].card_type != RAW_CARD_UNPOPULATED) && ((r) < dimms[ch<<1].ranks)) || \
|
|
((dimms[(ch<<1) + 1].card_type != RAW_CARD_UNPOPULATED) && ((r) >= 2) && ((r) < (dimms[(ch<<1) + 1].ranks + 2))))
|
|
#define IF_RANK_POPULATED(dimms, ch, r) \
|
|
if (((dimms[ch<<1].card_type != RAW_CARD_UNPOPULATED) \
|
|
&& ((r) < dimms[ch<<1].ranks)) \
|
|
|| ((dimms[(ch<<1) + 1].card_type != RAW_CARD_UNPOPULATED) \
|
|
&& ((r) >= 2) && ((r) < (dimms[(ch<<1) + 1].ranks + 2))))
|
|
#define FOR_EACH_RANK_IN_CHANNEL(r) \
|
|
for (r = 0; r < RANKS_PER_CHANNEL; ++r)
|
|
#define FOR_EACH_POPULATED_RANK_IN_CHANNEL(dimms, ch, r) \
|
|
FOR_EACH_RANK_IN_CHANNEL(r) IF_RANK_POPULATED(dimms, ch, r)
|
|
#define FOR_EACH_RANK(ch, r) \
|
|
FOR_EACH_CHANNEL(ch) FOR_EACH_RANK_IN_CHANNEL(r)
|
|
#define FOR_EACH_POPULATED_RANK(dimms, ch, r) \
|
|
FOR_EACH_RANK(ch, r) IF_RANK_POPULATED(dimms, ch, r)
|
|
#define FOR_EACH_BYTELANE(l) \
|
|
for (l = 0; l < TOTAL_BYTELANES; l++)
|
|
#define FOR_EACH_POPULATED_CHANNEL_AND_BYTELANE(dimms, ch, l) \
|
|
FOR_EACH_POPULATED_CHANNEL (dimms, ch) FOR_EACH_BYTELANE(l)
|
|
|
|
#define DDR3_MAX_CAS 18
|
|
|
|
enum fsb_clock {
|
|
FSB_CLOCK_800MHz = 0,
|
|
FSB_CLOCK_1066MHz = 1,
|
|
FSB_CLOCK_1333MHz = 2,
|
|
};
|
|
|
|
enum mem_clock {
|
|
MEM_CLOCK_400MHz = 0,
|
|
MEM_CLOCK_533MHz = 1,
|
|
MEM_CLOCK_667MHz = 2,
|
|
MEM_CLOCK_800MHz = 3,
|
|
MEM_CLOCK_1066MHz = 4,
|
|
MEM_CLOCK_1333MHz = 5,
|
|
};
|
|
|
|
enum ddr {
|
|
DDR2 = 2,
|
|
DDR3 = 3,
|
|
};
|
|
|
|
enum ddrxspd {
|
|
DDR2SPD = 0x8,
|
|
DDR3SPD = 0xb,
|
|
};
|
|
|
|
enum chip_width { /* as in DDR3 spd */
|
|
CHIP_WIDTH_x4 = 0,
|
|
CHIP_WIDTH_x8 = 1,
|
|
CHIP_WIDTH_x16 = 2,
|
|
CHIP_WIDTH_x32 = 3,
|
|
};
|
|
|
|
enum chip_cap { /* as in DDR3 spd */
|
|
CHIP_CAP_256M = 0,
|
|
CHIP_CAP_512M = 1,
|
|
CHIP_CAP_1G = 2,
|
|
CHIP_CAP_2G = 3,
|
|
CHIP_CAP_4G = 4,
|
|
CHIP_CAP_8G = 5,
|
|
CHIP_CAP_16G = 6,
|
|
};
|
|
|
|
struct dll_setting {
|
|
u8 tap;
|
|
u8 pi;
|
|
u8 db_en;
|
|
u8 db_sel;
|
|
u8 clk_delay;
|
|
u8 coarse;
|
|
};
|
|
|
|
struct rt_dqs_setting {
|
|
u8 tap;
|
|
u8 pi;
|
|
};
|
|
|
|
enum n_banks {
|
|
N_BANKS_4 = 0,
|
|
N_BANKS_8 = 1,
|
|
};
|
|
|
|
struct timings {
|
|
unsigned int CAS;
|
|
unsigned int tclk;
|
|
enum fsb_clock fsb_clk;
|
|
enum mem_clock mem_clk;
|
|
unsigned int tRAS;
|
|
unsigned int tRP;
|
|
unsigned int tRCD;
|
|
unsigned int tWR;
|
|
unsigned int tRFC;
|
|
unsigned int tWTR;
|
|
unsigned int tRRD;
|
|
unsigned int tRTP;
|
|
};
|
|
|
|
struct dimminfo {
|
|
unsigned int card_type; /* 0xff: unpopulated,
|
|
0xa - 0xf: raw card type A - F */
|
|
enum chip_width width;
|
|
unsigned int page_size; /* of whole DIMM in Bytes (4096 or 8192) */
|
|
enum n_banks n_banks;
|
|
unsigned int ranks;
|
|
unsigned int rows;
|
|
unsigned int cols;
|
|
u16 spd_crc;
|
|
u8 mirrored;
|
|
};
|
|
|
|
struct rcven_timings {
|
|
u8 min_common_coarse;
|
|
u8 coarse_offset[TOTAL_BYTELANES];
|
|
u8 medium[TOTAL_BYTELANES];
|
|
u8 tap[TOTAL_BYTELANES];
|
|
u8 pi[TOTAL_BYTELANES];
|
|
};
|
|
|
|
/* The setup is up to two DIMMs per channel */
|
|
struct sysinfo {
|
|
int boot_path;
|
|
enum fsb_clock max_fsb;
|
|
|
|
int dimm_config[2];
|
|
int spd_type;
|
|
int channel_capacity[2];
|
|
struct timings selected_timings;
|
|
struct dimminfo dimms[4];
|
|
u8 spd_map[4];
|
|
struct rcven_timings rcven_t[TOTAL_CHANNELS];
|
|
/*
|
|
* The rt_dqs delay register for rank 0 seems to be used
|
|
* for all other ranks on the channel, so only save that
|
|
*/
|
|
struct rt_dqs_setting rt_dqs[TOTAL_CHANNELS][TOTAL_BYTELANES];
|
|
struct dll_setting dqs_settings[TOTAL_CHANNELS][TOTAL_BYTELANES];
|
|
struct dll_setting dq_settings[TOTAL_CHANNELS][TOTAL_BYTELANES];
|
|
u8 nmode;
|
|
u8 stacked_mode;
|
|
};
|
|
#define BOOT_PATH_NORMAL 0
|
|
#define BOOT_PATH_WARM_RESET 1
|
|
#define BOOT_PATH_RESUME 2
|
|
|
|
enum ddr2_signals {
|
|
CLKSET0 = 0,
|
|
CTRL0,
|
|
CLKSET1,
|
|
CMD,
|
|
CTRL1,
|
|
CTRL2,
|
|
CTRL3,
|
|
};
|
|
|
|
#ifndef __BOOTBLOCK__
|
|
void x4x_early_init(void);
|
|
void x4x_late_init(int s3resume);
|
|
u32 decode_igd_memory_size(u32 gms);
|
|
u32 decode_igd_gtt_size(u32 gsm);
|
|
u32 decode_tseg_size(const u32 esmramc);
|
|
u8 decode_pciebar(u32 *const base, u32 *const len);
|
|
void sdram_initialize(int boot_path, const u8 *spd_map);
|
|
void do_raminit(struct sysinfo *, int fast_boot);
|
|
void rcven(struct sysinfo *s);
|
|
u32 fsb_to_mhz(u32 speed);
|
|
u32 ddr_to_mhz(u32 speed);
|
|
u32 test_address(int channel, int rank);
|
|
void dqsset(u8 ch, u8 lane, const struct dll_setting *setting);
|
|
void dqset(u8 ch, u8 lane, const struct dll_setting *setting);
|
|
void rt_set_dqs(u8 channel, u8 lane, u8 rank,
|
|
struct rt_dqs_setting *dqs_setting);
|
|
int do_write_training(struct sysinfo *s);
|
|
int do_read_training(struct sysinfo *s);
|
|
void search_write_leveling(struct sysinfo *s);
|
|
void send_jedec_cmd(const struct sysinfo *s, u8 r, u8 ch, u8 cmd, u32 val);
|
|
|
|
extern const struct dll_setting default_ddr2_667_ctrl[7];
|
|
extern const struct dll_setting default_ddr2_800_ctrl[7];
|
|
extern const struct dll_setting default_ddr3_800_ctrl[2][7];
|
|
extern const struct dll_setting default_ddr3_1067_ctrl[2][7];
|
|
extern const struct dll_setting default_ddr3_1333_ctrl[2][7];
|
|
extern const struct dll_setting default_ddr2_667_dqs[TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr2_800_dqs[TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_800_dqs[2][TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_1067_dqs[2][TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_1333_dqs[2][TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr2_667_dq[TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr2_800_dq[TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_800_dq[2][TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_1067_dq[2][TOTAL_BYTELANES];
|
|
extern const struct dll_setting default_ddr3_1333_dq[2][TOTAL_BYTELANES];
|
|
extern const u8 ddr3_emrs1_rtt_nom_config[16][4];
|
|
extern const u8 post_jedec_tab[3][4][2];
|
|
extern const u32 ddr3_c2_tab[2][3][6][2];
|
|
extern const u8 ddr3_c2_x264[3][6];
|
|
extern const u16 ddr3_c2_x23c[3][6];
|
|
|
|
struct acpi_rsdp;
|
|
#ifndef __SIMPLE_DEVICE__
|
|
unsigned long northbridge_write_acpi_tables(struct device *device,
|
|
unsigned long start, struct acpi_rsdp *rsdp);
|
|
#endif /* __SIMPLE_DEVICE__ */
|
|
#endif
|
|
#endif /* __NORTHBRIDGE_INTEL_X4X_H__ */
|