Patrick Rudolph has uploaded this change for review.

View Change

sb/intel/common: Add AHCI code

Implement a clean implementation based on AHCI spec 1.0-1.3 and the
Intel ICH/PCH datasheets.

The common implementation should combine all features of the duplicated
code present in the various southbridge implementations.

It compiles on x86_64, uses less magic values and detects the AHCI version
at runtime.

Change-Id: I5714788aa74b2d8bd855cbc65dd3d78c0a0101b8
Signed-off-by: Patrick Rudolph <siro@das-labor.org>
---
A src/include/ahci.h
M src/southbridge/intel/common/Kconfig
M src/southbridge/intel/common/Makefile.inc
A src/southbridge/intel/common/ahci.c
A src/southbridge/intel/common/ahci.h
5 files changed, 252 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/37/37137/1
diff --git a/src/include/ahci.h b/src/include/ahci.h
new file mode 100644
index 0000000..e7818fb
--- /dev/null
+++ b/src/include/ahci.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Patrick Rudolph <siro@das-labor.org>
+ *
+ * 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 __AHCI_H__
+#define __AHCI_H__
+
+/* Serial ATA AHCI 1.3.1 Specification */
+
+#define AHCI_CAP 0x00
+#define AHCI_CAP_NP 0x1f
+#define AHCI_CAP_PSC (1u << 13)
+#define AHCI_CAP_SSC (1u << 14)
+#define AHCI_CAP_PMD (1u << 15)
+#define AHCI_CAP_SPM (1u << 17)
+#define AHCI_CAP_SAM (1u << 18)
+#define AHCI_CAP_SNZO (1u << 19)
+#define AHCI_CAP_ISS(x) ((x) << 20)
+#define AHCI_CAP_SCLO (1u << 24)
+#define AHCI_CAP_SAL (1u << 25)
+#define AHCI_CAP_SALP (1u << 26)
+#define AHCI_CAP_SSS (1u << 27)
+#define AHCI_CAP_SIS (1u << 28)
+#define AHCI_CAP_SNCQ (1u << 30)
+#define AHCI_CAP_S64A (1u << 31)
+/* Added in AHCI 1.1 */
+#define AHCI_CAP_SXS (1u << 5)
+#define AHCI_CAP_EMS (1u << 6)
+#define AHCI_CAP_CCCS (1u << 7)
+/* Added in AHCI 1.2 */
+#define AHCI_CAP_SSNTF (1u << 29)
+
+#define AHCI_GHC 0x04
+#define AHCI_GHC_AE (1u << 31)
+#define AHCI_PI 0x0c
+#define AHCI_VS 0x10
+#define AHCI_VS_MAJOR(x) ((x >> 16) & 0xf)
+#define AHCI_VS_MINOR(x) ((x >> 8) & 0xf)
+
+/* Added in AHCI 1.1 */
+#define AHCI_CCC_CTL 0x14
+#define AHCI_CCC_PORTS 0x18
+#define AHCI_EM_LOC 0x1c
+#define AHCI_EM_CTL 0x20
+/* Added in AHCI 1.2 */
+#define AHCI_CAP2 0x24
+#define AHCI_CAP2_BOH (1u << 0)
+/* Added in AHCI 1.3 */
+#define AHCI_CAP2_NVMP (1u << 1)
+#define AHCI_CAP2_APST (1u << 2)
+#define AHCI_CAP2_SDS (1u << 3)
+#define AHCI_CAP2_SADM (1u << 4)
+#define AHCI_CAP2_DESO (1u << 5)
+
+#define AHCI_BOHC 0x28
+
+#define AHCI_VENDOR 0xa0
+#define AHCI_PORT 0x100
+#define AHCI_PORT_PxCMD 0x18
+#define AHCI_PORT_LEN 0x80
+
+
+#endif
diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig
index 18bcd2e..376f077 100644
--- a/src/southbridge/intel/common/Kconfig
+++ b/src/southbridge/intel/common/Kconfig
@@ -2,6 +2,10 @@
def_bool n
select HAVE_CF9_RESET

+config SOUTHBRIDGE_INTEL_COMMON_AHCI
+ def_bool n
+ depends on PCI
+
config SOUTHBRIDGE_INTEL_COMMON_RTC
def_bool n

diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc
index c8521e1..e87ae82 100644
--- a/src/southbridge/intel/common/Makefile.inc
+++ b/src/southbridge/intel/common/Makefile.inc
@@ -18,6 +18,8 @@

all-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_RESET) += reset.c

+ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_AHCI) += ahci.c
+
romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c
ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c

diff --git a/src/southbridge/intel/common/ahci.c b/src/southbridge/intel/common/ahci.c
new file mode 100644
index 0000000..ca20d30
--- /dev/null
+++ b/src/southbridge/intel/common/ahci.c
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Patrick Rudolph <siro@das-labor.org>
+ *
+ * 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 <ahci.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <console/console.h>
+
+#include "ahci.h"
+
+/**
+ * Initialize the AHCI config space.
+ * @param port_map The ports to enable
+ * @param sam Set SAM bit (no legacy device support)
+ * @param cccs Set CCCS bit
+ * @param iss Limit the controller to sata gen x
+ * @param devslp Enable DEVSLP feature if supported
+ * @param clear_vnd Clear bits in vendor config space
+ */
+void sb_ahci_init(struct device *const dev,
+ const u32 port_map,
+ const bool sam,
+ const bool cccs,
+ const u8 iss,
+ const bool devslp,
+ const u32 clear_vnd)
+{
+ u32 reg32;
+ u8 major, minor;
+ struct resource *res;
+ u8 *abar;
+ unsigned int ports;
+
+ /* Initialize AHCI memory-mapped space */
+ res = find_resource(dev, PCI_BASE_ADDRESS_5);
+ if (!res)
+ return;
+
+ abar = res2mmio(res, 0, 0);
+ /*
+ * Set AHCI access mode.
+ * Spec: "No other ABAR registers should be accessed before this."
+ */
+ reg32 = read32(abar + AHCI_GHC);
+ if (!(reg32 & AHCI_GHC_AE)) {
+ reg32 |= AHCI_GHC_AE;
+ write32(abar + AHCI_GHC, reg32);
+ }
+
+ /* Get AHCI version */
+ reg32 = read32(abar + AHCI_VS);
+ major = AHCI_VS_MAJOR(reg32);
+ minor = AHCI_VS_MINOR(reg32);
+ printk(BIOS_DEBUG, "AHCI: implements AHCI %d.%d\n", major, minor);
+
+ reg32 = read32(abar + AHCI_CAP);
+ printk(BIOS_DEBUG, "AHCI: supports SATA Gen%d\n", (reg32 >> 20) & 0xf);
+
+ ports = reg32 & AHCI_CAP_NP;
+ printk(BIOS_DEBUG, "AHCI: supports up to %d ports\n", ports);
+
+ /* CAP (HBA Capabilities) : enable power management */
+ /* Program Write-Once bits (this isn't part of the AHCI spec, but PCH). */
+ if (sam)
+ reg32 |= AHCI_CAP_SAM;
+ if (cccs && major >= 1 && minor >= 1)
+ reg32 |= AHCI_CAP_CCCS;
+ if (iss) {
+ u8 max_iss;
+ if (major >= 1 && minor >= 2)
+ max_iss = MIN(iss, 3);
+ else
+ max_iss = MIN(iss, 2);
+ reg32 &= ~AHCI_CAP_ISS(0xf);
+ reg32 |= AHCI_CAP_ISS(max_iss);
+ printk(BIOS_DEBUG, "AHCI: limited to Gen%d\n", max_iss);
+ }
+ reg32 |= AHCI_CAP_PSC;
+ reg32 |= AHCI_CAP_SSC;
+ reg32 |= AHCI_CAP_SALP;
+ reg32 |= AHCI_CAP_SSS;
+ if (major >= 1 && minor >= 1) {
+ reg32 &= ~AHCI_CAP_SXS;
+ reg32 &= ~AHCI_CAP_EMS;
+ reg32 &= ~AHCI_CAP_SPM;
+ }
+ write32(abar + AHCI_CAP, reg32);
+
+ if (major >= 1 && minor >= 2) {
+ reg32 = read32(abar + AHCI_CAP2);
+ /* Clear BIOS handoff support */
+ reg32 &= ~AHCI_CAP2_BOH;
+ if (major >= 1 && minor >= 3) {
+ /* Configure DEVSLP support */
+ if (devslp) {
+ reg32 |= AHCI_CAP2_APST;
+ reg32 |= AHCI_CAP2_SDS;
+ reg32 |= AHCI_CAP2_SADM;
+ reg32 |= AHCI_CAP2_DESO;
+ } else {
+ reg32 &= ~AHCI_CAP2_SDS;
+ }
+ /* Disable NVMHCI */
+ reg32 &= ~AHCI_CAP2_NVMP;
+ }
+ write32(abar + AHCI_CAP2, reg32);
+ }
+
+ if (port_map & ~((1 << ports) - 1))
+ printk(BIOS_ERR, "AHCI: Invalid port map given!\n");
+
+ write32(abar + AHCI_PI, port_map & ((1 << ports) - 1));
+ /* PCH code reads back twice, do we need it, too? */
+ (void) read32(abar + AHCI_PI); /* Read back 1 */
+ (void) read32(abar + AHCI_PI); /* Read back 2 */
+
+ /* Clear vendor specific bits */
+ reg32 = read32(abar + AHCI_VENDOR);
+ reg32 &= ~clear_vnd;
+ write32(abar + AHCI_VENDOR, reg32);
+
+ /* Lock R/WO bits in Port command registers. */
+ for (size_t i = 0; i < ports; ++i) {
+ if (!((1 << i) & port_map))
+ continue;
+ u8 *addr = abar + AHCI_PORT + (i * AHCI_PORT_LEN);
+ write32(addr, read32(addr + AHCI_PORT_PxCMD));
+ }
+}
diff --git a/src/southbridge/intel/common/ahci.h b/src/southbridge/intel/common/ahci.h
new file mode 100644
index 0000000..9d4a025
--- /dev/null
+++ b/src/southbridge/intel/common/ahci.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Patrick Rudolph <siro@das-labor.org>
+ *
+ * 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 SOUTHBRIDGE_INTEL_COMMON_AHCI_H
+#define SOUTHBRIDGE_INTEL_COMMON_AHCI_H
+
+#include <device/device.h>
+
+void sb_ahci_init(struct device *const dev,
+ const u32 port_map,
+ const bool sam,
+ const bool cccs,
+ const u8 iss,
+ const bool devslp,
+ const u32 clear_vnd);
+
+#endif /* SOUTHBRIDGE_INTEL_COMMON_AHCI_H */
+

To view, visit change 37137. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I5714788aa74b2d8bd855cbc65dd3d78c0a0101b8
Gerrit-Change-Number: 37137
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <siro@das-labor.org>
Gerrit-MessageType: newchange