]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
x86: Add Intel Braswell SoC support
authorBin Meng <bmeng.cn@gmail.com>
Wed, 16 Aug 2017 05:41:58 +0000 (22:41 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Sat, 16 Sep 2017 06:57:44 +0000 (14:57 +0800)
This adds initial Intel Braswell SoC support. It uses Intel FSP
to initialize the chipset.

Similar to its predecessor BayTrail, there are some work to do to
enable the legacy UART integrated in the Braswell SoC.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/x86/Kconfig
arch/x86/cpu/Makefile
arch/x86/cpu/braswell/Kconfig [new file with mode: 0644]
arch/x86/cpu/braswell/Makefile [new file with mode: 0644]
arch/x86/cpu/braswell/braswell.c [new file with mode: 0644]
arch/x86/cpu/braswell/cpu.c [new file with mode: 0644]
arch/x86/cpu/braswell/early_uart.c [new file with mode: 0644]
arch/x86/include/asm/arch-braswell/iomap.h [new file with mode: 0644]

index cda11d296b0bcc5ab363a3780dc7c5725d54aeec..38a618753a2a931e2599481867d6cf5e4b408e52 100644 (file)
@@ -108,6 +108,7 @@ source "board/intel/Kconfig"
 
 # platform-specific options below
 source "arch/x86/cpu/baytrail/Kconfig"
+source "arch/x86/cpu/braswell/Kconfig"
 source "arch/x86/cpu/broadwell/Kconfig"
 source "arch/x86/cpu/coreboot/Kconfig"
 source "arch/x86/cpu/ivybridge/Kconfig"
index 999429e62b197c5d64c29302704239eb11a3d6f2..94cdff18cc0943bc97e5c790f9bb7f263f22c543 100644 (file)
@@ -27,6 +27,7 @@ endif
 
 obj-y += intel_common/
 obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/
+obj-$(CONFIG_INTEL_BRASWELL) += braswell/
 obj-$(CONFIG_INTEL_BROADWELL) += broadwell/
 obj-$(CONFIG_SYS_COREBOOT) += coreboot/
 obj-$(CONFIG_EFI_APP) += efi/
diff --git a/arch/x86/cpu/braswell/Kconfig b/arch/x86/cpu/braswell/Kconfig
new file mode 100644 (file)
index 0000000..0e214a7
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+config INTEL_BRASWELL
+       bool
+       select HAVE_FSP
+       select ARCH_MISC_INIT
+       select CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED
+       imply HAVE_INTEL_ME
+       imply HAVE_VBT
+       imply ENABLE_MRC_CACHE
+       imply ENV_IS_IN_SPI_FLASH
+       imply AHCI_PCI
+       imply ICH_SPI
+       imply MMC
+       imply MMC_PCI
+       imply MMC_SDHCI
+       imply MMC_SDHCI_SDMA
+       imply SCSI
+       imply SPI_FLASH
+       imply SYS_NS16550
+       imply USB
+       imply USB_XHCI_HCD
+       imply VIDEO_FSP
+
+if INTEL_BRASWELL
+
+config FSP_ADDR
+       hex
+       default 0xfff20000
+
+config FSP_LOCKDOWN_SPI
+       bool
+       default y
+
+endif
diff --git a/arch/x86/cpu/braswell/Makefile b/arch/x86/cpu/braswell/Makefile
new file mode 100644 (file)
index 0000000..19bcee6
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y += braswell.o cpu.o early_uart.o
diff --git a/arch/x86/cpu/braswell/braswell.c b/arch/x86/cpu/braswell/braswell.c
new file mode 100644 (file)
index 0000000..37099aa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/mrccache.h>
+#include <asm/post.h>
+
+int arch_cpu_init(void)
+{
+       post_code(POST_CPU_INIT);
+
+       return x86_cpu_init_f();
+}
+
+int arch_misc_init(void)
+{
+#ifdef CONFIG_ENABLE_MRC_CACHE
+       /*
+        * We intend not to check any return value here, as even MRC cache
+        * is not saved successfully, it is not a severe error that will
+        * prevent system from continuing to boot.
+        */
+       mrccache_save();
+#endif
+
+       return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+       /* cold reset */
+       x86_full_reset();
+}
diff --git a/arch/x86/cpu/braswell/cpu.c b/arch/x86/cpu/braswell/cpu.c
new file mode 100644 (file)
index 0000000..6ff9036
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * Derived from arch/x86/cpu/baytrail/cpu.c
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/cpu.h>
+#include <asm/cpu_x86.h>
+#include <asm/io.h>
+#include <asm/lapic.h>
+#include <asm/msr.h>
+#include <asm/turbo.h>
+
+static const unsigned int braswell_bus_freq_table[] = {
+       83333333,
+       100000000,
+       133333333,
+       116666666,
+       80000000,
+       93333333,
+       90000000,
+       88900000,
+       87500000
+};
+
+static unsigned int braswell_bus_freq(void)
+{
+       msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
+
+       if ((clk_info.lo & 0xf) < (ARRAY_SIZE(braswell_bus_freq_table)))
+               return braswell_bus_freq_table[clk_info.lo & 0xf];
+
+       return 0;
+}
+
+static unsigned long braswell_tsc_freq(void)
+{
+       msr_t platform_info;
+       ulong bclk = braswell_bus_freq();
+
+       if (!bclk)
+               return 0;
+
+       platform_info = msr_read(MSR_PLATFORM_INFO);
+
+       return bclk * ((platform_info.lo >> 8) & 0xff);
+}
+
+static int braswell_get_info(struct udevice *dev, struct cpu_info *info)
+{
+       info->cpu_freq = braswell_tsc_freq();
+       info->features = (1 << CPU_FEAT_L1_CACHE) | (1 << CPU_FEAT_MMU);
+
+       return 0;
+}
+
+static int braswell_get_count(struct udevice *dev)
+{
+       int ecx = 0;
+
+       /*
+        * Use the algorithm described in Intel 64 and IA-32 Architectures
+        * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
+        * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
+        * of CPUID Extended Topology Leaf.
+        */
+       while (1) {
+               struct cpuid_result leaf_b;
+
+               leaf_b = cpuid_ext(0xb, ecx);
+
+               /*
+                * Braswell doesn't have hyperthreading so just determine the
+                * number of cores by from level type (ecx[15:8] == * 2)
+                */
+               if ((leaf_b.ecx & 0xff00) == 0x0200)
+                       return leaf_b.ebx & 0xffff;
+
+               ecx++;
+       }
+
+       return 0;
+}
+
+static void braswell_set_max_freq(void)
+{
+       msr_t perf_ctl;
+       msr_t msr;
+
+       /* Enable speed step */
+       msr = msr_read(MSR_IA32_MISC_ENABLES);
+       msr.lo |= (1 << 16);
+       msr_write(MSR_IA32_MISC_ENABLES, msr);
+
+       /* Enable Burst Mode */
+       msr = msr_read(MSR_IA32_MISC_ENABLES);
+       msr.hi = 0;
+       msr_write(MSR_IA32_MISC_ENABLES, msr);
+
+       /*
+        * Set guaranteed ratio [21:16] from IACORE_TURBO_RATIOS to
+        * bits [15:8] of the PERF_CTL
+        */
+       msr = msr_read(MSR_IACORE_TURBO_RATIOS);
+       perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
+
+       /*
+        * Set guaranteed vid [22:16] from IACORE_TURBO_VIDS to
+        * bits [7:0] of the PERF_CTL
+        */
+       msr = msr_read(MSR_IACORE_TURBO_VIDS);
+       perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
+
+       perf_ctl.hi = 0;
+       msr_write(MSR_IA32_PERF_CTL, perf_ctl);
+}
+
+static int braswell_probe(struct udevice *dev)
+{
+       debug("Init Braswell core\n");
+
+       /*
+        * On Braswell the turbo disable bit is actually scoped at the
+        * building-block level, not package. For non-BSP cores that are
+        * within a building block, enable turbo. The cores within the BSP's
+        * building block will just see it already enabled and move on.
+        */
+       if (lapicid())
+               turbo_enable();
+
+       /* Dynamic L2 shrink enable and threshold, clear SINGLE_PCTL bit 11 */
+       msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f080f, 0xe0008),
+       msr_clrsetbits_64(MSR_POWER_MISC,
+                         ENABLE_ULFM_AUTOCM_MASK | ENABLE_INDP_AUTOCM_MASK, 0);
+
+       /* Disable C1E */
+       msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
+       msr_setbits_64(MSR_POWER_MISC, 0x44);
+
+       /* Set this core to max frequency ratio */
+       braswell_set_max_freq();
+
+       return 0;
+}
+
+static const struct udevice_id braswell_ids[] = {
+       { .compatible = "intel,braswell-cpu" },
+       { }
+};
+
+static const struct cpu_ops braswell_ops = {
+       .get_desc       = cpu_x86_get_desc,
+       .get_info       = braswell_get_info,
+       .get_count      = braswell_get_count,
+       .get_vendor     = cpu_x86_get_vendor,
+};
+
+U_BOOT_DRIVER(cpu_x86_braswell_drv) = {
+       .name           = "cpu_x86_braswell",
+       .id             = UCLASS_CPU,
+       .of_match       = braswell_ids,
+       .bind           = cpu_x86_bind,
+       .probe          = braswell_probe,
+       .ops            = &braswell_ops,
+};
diff --git a/arch/x86/cpu/braswell/early_uart.c b/arch/x86/cpu/braswell/early_uart.c
new file mode 100644 (file)
index 0000000..c70a885
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#define PCI_DEV_CONFIG(segbus, dev, fn) ( \
+               (((segbus) & 0xfff) << 20) | \
+               (((dev) & 0x1f) << 15) | \
+               (((fn)  & 0x07) << 12))
+
+/* Platform Controller Unit */
+#define LPC_DEV                        0x1f
+#define LPC_FUNC               0
+
+/* Enable UART */
+#define UART_CONT              0x80
+
+/* UART PAD definitions */
+#define UART_RXD_COMMUITY      1
+#define UART_TXD_COMMUITY      1
+#define UART_RXD_FAMILY                4
+#define UART_TXD_FAMILY                4
+#define UART_RXD_PAD           2
+#define UART_TXD_PAD           7
+#define UART_RXD_FUNC          3
+#define UART_TXD_FUNC          3
+
+/* IO Memory */
+#define IO_BASE_ADDRESS                0xfed80000
+
+static inline uint32_t gpio_pconf0(int community, int family, int pad)
+{
+       return IO_BASE_ADDRESS + community * 0x8000 + 0x4400 +
+               family * 0x400 + pad * 8;
+}
+
+static void gpio_select_func(int community, int family, int pad, int func)
+{
+       uint32_t pconf0_addr = gpio_pconf0(community, family, pad);
+
+       clrsetbits_le32(pconf0_addr, 0xf << 16, func << 16);
+}
+
+static void x86_pci_write_config32(int dev, unsigned int where, u32 value)
+{
+       unsigned long addr;
+
+       addr = CONFIG_PCIE_ECAM_BASE | dev | (where & ~3);
+       writel(value, addr);
+}
+
+/* This can be called after memory-mapped PCI is working */
+int setup_internal_uart(int enable)
+{
+       /* Enable or disable the legacy UART hardware */
+       x86_pci_write_config32(PCI_DEV_CONFIG(0, LPC_DEV, LPC_FUNC), UART_CONT,
+                              enable);
+
+       /* All done for the disable part, so just return */
+       if (!enable)
+               return 0;
+
+       /*
+        * Set up the pads to the UART function. This allows the signals to
+        * leave the chip
+        */
+       gpio_select_func(UART_RXD_COMMUITY, UART_RXD_FAMILY,
+                        UART_RXD_PAD, UART_RXD_FUNC);
+       gpio_select_func(UART_TXD_COMMUITY, UART_TXD_FAMILY,
+                        UART_TXD_PAD, UART_TXD_FUNC);
+
+       return 0;
+}
+
+void board_debug_uart_init(void)
+{
+       setup_internal_uart(1);
+}
diff --git a/arch/x86/include/asm/arch-braswell/iomap.h b/arch/x86/include/asm/arch-braswell/iomap.h
new file mode 100644 (file)
index 0000000..7df2dc5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _BRASWELL_IOMAP_H_
+#define _BRASWELL_IOMAP_H_
+
+/* Memory Mapped IO bases */
+
+/* Power Management Controller */
+#define PMC_BASE_ADDRESS       0xfed03000
+#define PMC_BASE_SIZE          0x400
+
+/* Power Management Unit */
+#define PUNIT_BASE_ADDRESS     0xfed05000
+#define PUNIT_BASE_SIZE                0x800
+
+/* Intel Legacy Block */
+#define ILB_BASE_ADDRESS       0xfed08000
+#define ILB_BASE_SIZE          0x400
+
+/* SPI Bus */
+#define SPI_BASE_ADDRESS       0xfed01000
+#define SPI_BASE_SIZE          0x400
+
+/* Root Complex Base Address */
+#define RCBA_BASE_ADDRESS      0xfed1c000
+#define RCBA_BASE_SIZE         0x400
+
+/* IO Memory */
+#define IO_BASE_ADDRESS                0xfed80000
+#define IO_BASE_SIZE           0x4000
+
+/* MODPHY */
+#define MPHY_BASE_ADDRESS      0xfef00000
+#define MPHY_BASE_SIZE         0x100000
+
+/* IO Port bases */
+
+#define ACPI_BASE_ADDRESS      0x400
+#define ACPI_BASE_SIZE         0x80
+
+#define GPIO_BASE_ADDRESS      0x500
+#define GPIO_BASE_SIZE         0x100
+
+#define SMBUS_BASE_ADDRESS     0xefa0
+
+#endif /* _BRASWELL_IOMAP_H_ */