183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
224774278SSimon Glass /*
324774278SSimon Glass  * From Coreboot northbridge/intel/sandybridge/northbridge.c
424774278SSimon Glass  *
524774278SSimon Glass  * Copyright (C) 2007-2009 coresystems GmbH
624774278SSimon Glass  * Copyright (C) 2011 The Chromium Authors
724774278SSimon Glass  */
824774278SSimon Glass 
924774278SSimon Glass #include <common.h>
10279006dbSSimon Glass #include <dm.h>
1124774278SSimon Glass #include <asm/msr.h>
1224774278SSimon Glass #include <asm/cpu.h>
1306d336ccSSimon Glass #include <asm/intel_regs.h>
1424774278SSimon Glass #include <asm/io.h>
1524774278SSimon Glass #include <asm/pci.h>
1624774278SSimon Glass #include <asm/processor.h>
1724774278SSimon Glass #include <asm/arch/pch.h>
1824774278SSimon Glass #include <asm/arch/model_206ax.h>
1924774278SSimon Glass #include <asm/arch/sandybridge.h>
2024774278SSimon Glass 
2105af050eSSimon Glass DECLARE_GLOBAL_DATA_PTR;
2205af050eSSimon Glass 
bridge_silicon_revision(struct udevice * dev)231605b100SSimon Glass int bridge_silicon_revision(struct udevice *dev)
2424774278SSimon Glass {
2524774278SSimon Glass 	struct cpuid_result result;
261605b100SSimon Glass 	u16 bridge_id;
271605b100SSimon Glass 	u8 stepping;
2824774278SSimon Glass 
2924774278SSimon Glass 	result = cpuid(1);
3024774278SSimon Glass 	stepping = result.eax & 0xf;
311605b100SSimon Glass 	dm_pci_read_config16(dev, PCI_DEVICE_ID, &bridge_id);
321605b100SSimon Glass 	bridge_id &= 0xf0;
331605b100SSimon Glass 	return bridge_id | stepping;
3424774278SSimon Glass }
3524774278SSimon Glass 
get_pcie_bar(struct udevice * dev,u32 * base,u32 * len)361a9dd221SSimon Glass static int get_pcie_bar(struct udevice *dev, u32 *base, u32 *len)
3724774278SSimon Glass {
3824774278SSimon Glass 	u32 pciexbar_reg;
3924774278SSimon Glass 
4024774278SSimon Glass 	*base = 0;
4124774278SSimon Glass 	*len = 0;
4224774278SSimon Glass 
431a9dd221SSimon Glass 	dm_pci_read_config32(dev, PCIEXBAR, &pciexbar_reg);
4424774278SSimon Glass 
4524774278SSimon Glass 	if (!(pciexbar_reg & (1 << 0)))
4624774278SSimon Glass 		return 0;
4724774278SSimon Glass 
4824774278SSimon Glass 	switch ((pciexbar_reg >> 1) & 3) {
4924774278SSimon Glass 	case 0: /* 256MB */
5024774278SSimon Glass 		*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
5124774278SSimon Glass 				(1 << 28));
5224774278SSimon Glass 		*len = 256 * 1024 * 1024;
5324774278SSimon Glass 		return 1;
5424774278SSimon Glass 	case 1: /* 128M */
5524774278SSimon Glass 		*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
5624774278SSimon Glass 				(1 << 28) | (1 << 27));
5724774278SSimon Glass 		*len = 128 * 1024 * 1024;
5824774278SSimon Glass 		return 1;
5924774278SSimon Glass 	case 2: /* 64M */
6024774278SSimon Glass 		*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
6124774278SSimon Glass 				(1 << 28) | (1 << 27) | (1 << 26));
6224774278SSimon Glass 		*len = 64 * 1024 * 1024;
6324774278SSimon Glass 		return 1;
6424774278SSimon Glass 	}
6524774278SSimon Glass 
6624774278SSimon Glass 	return 0;
6724774278SSimon Glass }
6824774278SSimon Glass 
add_fixed_resources(struct udevice * dev,int index)691a9dd221SSimon Glass static void add_fixed_resources(struct udevice *dev, int index)
7024774278SSimon Glass {
7124774278SSimon Glass 	u32 pcie_config_base, pcie_config_size;
7224774278SSimon Glass 
731a9dd221SSimon Glass 	if (get_pcie_bar(dev, &pcie_config_base, &pcie_config_size)) {
7424774278SSimon Glass 		debug("Adding PCIe config bar base=0x%08x size=0x%x\n",
7524774278SSimon Glass 		      pcie_config_base, pcie_config_size);
7624774278SSimon Glass 	}
7724774278SSimon Glass }
7824774278SSimon Glass 
northbridge_dmi_init(struct udevice * dev,int rev)791605b100SSimon Glass static void northbridge_dmi_init(struct udevice *dev, int rev)
8024774278SSimon Glass {
8124774278SSimon Glass 	/* Clear error status bits */
8224774278SSimon Glass 	writel(0xffffffff, DMIBAR_REG(0x1c4));
8324774278SSimon Glass 	writel(0xffffffff, DMIBAR_REG(0x1d0));
8424774278SSimon Glass 
8524774278SSimon Glass 	/* Steps prior to DMI ASPM */
861605b100SSimon Glass 	if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
8724774278SSimon Glass 		clrsetbits_le32(DMIBAR_REG(0x250), (1 << 22) | (1 << 20),
8824774278SSimon Glass 				1 << 21);
8924774278SSimon Glass 	}
9024774278SSimon Glass 
9124774278SSimon Glass 	setbits_le32(DMIBAR_REG(0x238), 1 << 29);
9224774278SSimon Glass 
931605b100SSimon Glass 	if (rev >= SNB_STEP_D0) {
9424774278SSimon Glass 		setbits_le32(DMIBAR_REG(0x1f8), 1 << 16);
951605b100SSimon Glass 	} else if (rev >= SNB_STEP_D1) {
9624774278SSimon Glass 		clrsetbits_le32(DMIBAR_REG(0x1f8), 1 << 26, 1 << 16);
9724774278SSimon Glass 		setbits_le32(DMIBAR_REG(0x1fc), (1 << 12) | (1 << 23));
9824774278SSimon Glass 	}
9924774278SSimon Glass 
10024774278SSimon Glass 	/* Enable ASPM on SNB link, should happen before PCH link */
1011605b100SSimon Glass 	if ((rev & BASE_REV_MASK) == BASE_REV_SNB)
10224774278SSimon Glass 		setbits_le32(DMIBAR_REG(0xd04), 1 << 4);
10324774278SSimon Glass 
10424774278SSimon Glass 	setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0));
10524774278SSimon Glass }
10624774278SSimon Glass 
northbridge_init(struct udevice * dev,int rev)1071605b100SSimon Glass static void northbridge_init(struct udevice *dev, int rev)
10824774278SSimon Glass {
10924774278SSimon Glass 	u32 bridge_type;
11024774278SSimon Glass 
11124774278SSimon Glass 	add_fixed_resources(dev, 6);
1121605b100SSimon Glass 	northbridge_dmi_init(dev, rev);
11324774278SSimon Glass 
11424774278SSimon Glass 	bridge_type = readl(MCHBAR_REG(0x5f10));
11524774278SSimon Glass 	bridge_type &= ~0xff;
11624774278SSimon Glass 
1171605b100SSimon Glass 	if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
11824774278SSimon Glass 		/* Enable Power Aware Interrupt Routing - fixed priority */
11924774278SSimon Glass 		clrsetbits_8(MCHBAR_REG(0x5418), 0xf, 0x4);
12024774278SSimon Glass 
12124774278SSimon Glass 		/* 30h for IvyBridge */
12224774278SSimon Glass 		bridge_type |= 0x30;
12324774278SSimon Glass 	} else {
12424774278SSimon Glass 		/* 20h for Sandybridge */
12524774278SSimon Glass 		bridge_type |= 0x20;
12624774278SSimon Glass 	}
12724774278SSimon Glass 	writel(bridge_type, MCHBAR_REG(0x5f10));
12824774278SSimon Glass 
12924774278SSimon Glass 	/*
13024774278SSimon Glass 	 * Set bit 0 of BIOS_RESET_CPL to indicate to the CPU
13124774278SSimon Glass 	 * that BIOS has initialized memory and power management
13224774278SSimon Glass 	 */
13324774278SSimon Glass 	setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 1);
13424774278SSimon Glass 	debug("Set BIOS_RESET_CPL\n");
13524774278SSimon Glass 
13624774278SSimon Glass 	/* Configure turbo power limits 1ms after reset complete bit */
13724774278SSimon Glass 	mdelay(1);
13824774278SSimon Glass 	set_power_limits(28);
13924774278SSimon Glass 
14024774278SSimon Glass 	/*
14124774278SSimon Glass 	 * CPUs with configurable TDP also need power limits set
14224774278SSimon Glass 	 * in MCHBAR.  Use same values from MSR_PKG_POWER_LIMIT.
14324774278SSimon Glass 	 */
14424774278SSimon Glass 	if (cpu_config_tdp_levels()) {
14524774278SSimon Glass 		msr_t msr = msr_read(MSR_PKG_POWER_LIMIT);
14624774278SSimon Glass 
14724774278SSimon Glass 		writel(msr.lo, MCHBAR_REG(0x59A0));
14824774278SSimon Glass 		writel(msr.hi, MCHBAR_REG(0x59A4));
14924774278SSimon Glass 	}
15024774278SSimon Glass 
15124774278SSimon Glass 	/* Set here before graphics PM init */
15224774278SSimon Glass 	writel(0x00100001, MCHBAR_REG(0x5500));
15324774278SSimon Glass }
15424774278SSimon Glass 
sandybridge_setup_northbridge_bars(struct udevice * dev)155279006dbSSimon Glass static void sandybridge_setup_northbridge_bars(struct udevice *dev)
156279006dbSSimon Glass {
157279006dbSSimon Glass 	/* Set up all hardcoded northbridge BARs */
158279006dbSSimon Glass 	debug("Setting up static registers\n");
159279006dbSSimon Glass 	dm_pci_write_config32(dev, EPBAR, DEFAULT_EPBAR | 1);
160279006dbSSimon Glass 	dm_pci_write_config32(dev, EPBAR + 4, (0LL + DEFAULT_EPBAR) >> 32);
16106d336ccSSimon Glass 	dm_pci_write_config32(dev, MCHBAR, MCH_BASE_ADDRESS | 1);
16206d336ccSSimon Glass 	dm_pci_write_config32(dev, MCHBAR + 4, (0LL + MCH_BASE_ADDRESS) >> 32);
163279006dbSSimon Glass 	/* 64MB - busses 0-63 */
164279006dbSSimon Glass 	dm_pci_write_config32(dev, PCIEXBAR, DEFAULT_PCIEXBAR | 5);
165279006dbSSimon Glass 	dm_pci_write_config32(dev, PCIEXBAR + 4,
166279006dbSSimon Glass 			      (0LL + DEFAULT_PCIEXBAR) >> 32);
167279006dbSSimon Glass 	dm_pci_write_config32(dev, DMIBAR, DEFAULT_DMIBAR | 1);
168279006dbSSimon Glass 	dm_pci_write_config32(dev, DMIBAR + 4, (0LL + DEFAULT_DMIBAR) >> 32);
169279006dbSSimon Glass 
170279006dbSSimon Glass 	/* Set C0000-FFFFF to access RAM on both reads and writes */
171279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM0, 0x30);
172279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM1, 0x33);
173279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM2, 0x33);
174279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM3, 0x33);
175279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM4, 0x33);
176279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM5, 0x33);
177279006dbSSimon Glass 	dm_pci_write_config8(dev, PAM6, 0x33);
178279006dbSSimon Glass }
179279006dbSSimon Glass 
180*6744c0d6SSimon Glass /**
181*6744c0d6SSimon Glass  * sandybridge_init_iommu() - Set up IOMMU so that azalia can be used
182*6744c0d6SSimon Glass  *
183*6744c0d6SSimon Glass  * It is not obvious where these values come from. They may be undocumented.
184*6744c0d6SSimon Glass  */
sandybridge_init_iommu(struct udevice * dev)185*6744c0d6SSimon Glass static void sandybridge_init_iommu(struct udevice *dev)
186*6744c0d6SSimon Glass {
187*6744c0d6SSimon Glass 	u32 capid0_a;
188*6744c0d6SSimon Glass 
189*6744c0d6SSimon Glass 	dm_pci_read_config32(dev, 0xe4, &capid0_a);
190*6744c0d6SSimon Glass 	if (capid0_a & (1 << 23)) {
191*6744c0d6SSimon Glass 		log_debug("capid0_a not needed\n");
192*6744c0d6SSimon Glass 		return;
193*6744c0d6SSimon Glass 	}
194*6744c0d6SSimon Glass 
195*6744c0d6SSimon Glass 	/* setup BARs */
196*6744c0d6SSimon Glass 	writel(IOMMU_BASE1 >> 32, MCHBAR_REG(0x5404));
197*6744c0d6SSimon Glass 	writel(IOMMU_BASE1 | 1, MCHBAR_REG(0x5400));
198*6744c0d6SSimon Glass 	writel(IOMMU_BASE2 >> 32, MCHBAR_REG(0x5414));
199*6744c0d6SSimon Glass 	writel(IOMMU_BASE2 | 1, MCHBAR_REG(0x5410));
200*6744c0d6SSimon Glass 
201*6744c0d6SSimon Glass 	/* lock policies */
202*6744c0d6SSimon Glass 	writel(0x80000000, IOMMU_BASE1 + 0xff0);
203*6744c0d6SSimon Glass 
204*6744c0d6SSimon Glass 	/* Enable azalia sound */
205*6744c0d6SSimon Glass 	writel(0x20000000, IOMMU_BASE2 + 0xff0);
206*6744c0d6SSimon Glass 	writel(0xa0000000, IOMMU_BASE2 + 0xff0);
207*6744c0d6SSimon Glass }
208*6744c0d6SSimon Glass 
bd82x6x_northbridge_early_init(struct udevice * dev)2099ed781a6SSimon Glass static int bd82x6x_northbridge_early_init(struct udevice *dev)
210279006dbSSimon Glass {
211279006dbSSimon Glass 	const int chipset_type = SANDYBRIDGE_MOBILE;
212279006dbSSimon Glass 	u32 capid0_a;
213279006dbSSimon Glass 	u8 reg8;
214279006dbSSimon Glass 
215279006dbSSimon Glass 	/* Device ID Override Enable should be done very early */
216279006dbSSimon Glass 	dm_pci_read_config32(dev, 0xe4, &capid0_a);
217279006dbSSimon Glass 	if (capid0_a & (1 << 10)) {
218279006dbSSimon Glass 		dm_pci_read_config8(dev, 0xf3, &reg8);
219279006dbSSimon Glass 		reg8 &= ~7; /* Clear 2:0 */
220279006dbSSimon Glass 
221279006dbSSimon Glass 		if (chipset_type == SANDYBRIDGE_MOBILE)
222279006dbSSimon Glass 			reg8 |= 1; /* Set bit 0 */
223279006dbSSimon Glass 
224279006dbSSimon Glass 		dm_pci_write_config8(dev, 0xf3, reg8);
225279006dbSSimon Glass 	}
226279006dbSSimon Glass 
227279006dbSSimon Glass 	sandybridge_setup_northbridge_bars(dev);
228279006dbSSimon Glass 
229*6744c0d6SSimon Glass 	/* Setup IOMMU BARs */
230*6744c0d6SSimon Glass 	sandybridge_init_iommu(dev);
231*6744c0d6SSimon Glass 
232279006dbSSimon Glass 	/* Device Enable */
233279006dbSSimon Glass 	dm_pci_write_config32(dev, DEVEN, DEVEN_HOST | DEVEN_IGD);
234279006dbSSimon Glass 
235279006dbSSimon Glass 	return 0;
236279006dbSSimon Glass }
237279006dbSSimon Glass 
bd82x6x_northbridge_probe(struct udevice * dev)2389ed781a6SSimon Glass static int bd82x6x_northbridge_probe(struct udevice *dev)
2399ed781a6SSimon Glass {
2401605b100SSimon Glass 	int rev;
2411605b100SSimon Glass 
2429ed781a6SSimon Glass 	if (!(gd->flags & GD_FLG_RELOC))
2439ed781a6SSimon Glass 		return bd82x6x_northbridge_early_init(dev);
2449ed781a6SSimon Glass 
2451605b100SSimon Glass 	rev = bridge_silicon_revision(dev);
2461605b100SSimon Glass 	northbridge_init(dev, rev);
2479ed781a6SSimon Glass 
2489ed781a6SSimon Glass 	return 0;
2499ed781a6SSimon Glass }
2509ed781a6SSimon Glass 
251279006dbSSimon Glass static const struct udevice_id bd82x6x_northbridge_ids[] = {
252279006dbSSimon Glass 	{ .compatible = "intel,bd82x6x-northbridge" },
253279006dbSSimon Glass 	{ }
254279006dbSSimon Glass };
255279006dbSSimon Glass 
256279006dbSSimon Glass U_BOOT_DRIVER(bd82x6x_northbridge_drv) = {
257279006dbSSimon Glass 	.name		= "bd82x6x_northbridge",
258279006dbSSimon Glass 	.id		= UCLASS_NORTHBRIDGE,
259279006dbSSimon Glass 	.of_match	= bd82x6x_northbridge_ids,
260279006dbSSimon Glass 	.probe		= bd82x6x_northbridge_probe,
261279006dbSSimon Glass };
262