summaryrefslogtreecommitdiffstats
path: root/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
blob: 407952e3065e22f72e6bcc7e4a382ab7f2c53610 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
From e80d2ec15e83fe1e6bb1ee4c8b3d4dad196e023f Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Mon, 22 Jun 2015 02:21:29 -0500
Subject: [PATCH 067/143] southbridge/amd/sb700: Recover if AHCI disk
 detection fails

Change-Id: I29051af5eca5d31b6aecc261e9a48028380eccb3
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/southbridge/amd/sb700/sata.c |   83 ++++++++++++++++++++++++++++++++++----
 1 file changed, 75 insertions(+), 8 deletions(-)

diff --git a/src/southbridge/amd/sb700/sata.c b/src/southbridge/amd/sb700/sata.c
index d51baa1..ce242c1 100644
--- a/src/southbridge/amd/sb700/sata.c
+++ b/src/southbridge/amd/sb700/sata.c
@@ -31,12 +31,15 @@
 static int sata_drive_detect(int portnum, uint16_t iobar)
 {
 	u8 byte, byte2;
+	u8 byte_prev, byte2_prev;
 	int i = 0;
+	byte_prev = byte2_prev = 0;
 	outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
 	while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
 		(byte != (0xa0 + 0x10 * (portnum % 2))) ||
 		((byte2 & 0x88) != 0)) {
-		printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
+		if ((byte != byte_prev) || (byte2 != byte2_prev))
+			printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
 		if (byte != (0xa0 + 0x10 * (portnum % 2))) {
 			/* This will happen at the first iteration of this loop
 			 * if the first SATA port is unpopulated and the
@@ -45,11 +48,22 @@ static int sata_drive_detect(int portnum, uint16_t iobar)
 			printk(BIOS_DEBUG, "drive no longer selected after %i ms, "
 				"retrying init\n", i * 10);
 			return 1;
-		} else
-			printk(BIOS_SPEW, "drive detection not yet completed, "
-				"waiting...\n");
+		} else {
+			if (i == 0)
+				printk(BIOS_SPEW, "drive detection not yet completed, "
+					"waiting...\n");
+		}
 		mdelay(10);
 		i++;
+		byte_prev = byte;
+		byte2_prev = byte2;
+
+		/* Detect stuck SATA controller and attempt reset */
+		if (i > 1024) {
+			printk(BIOS_DEBUG, "drive detection not done after %i ms, "
+				"resetting HBA and retrying init\n", i * 10);
+			return 2;
+		}
 	}
 	printk(BIOS_SPEW, "drive detection done after %i ms\n", i * 10);
 	return 0;
@@ -105,12 +119,13 @@ static void sata_init(struct device *dev)
 	uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
 	uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
 	uint16_t current_bar;
-	int i, j;
+	int i, j, ret;
 	uint8_t nvram;
 	uint8_t sata_ahci_mode;
 	uint8_t sata_alpm_enable;
 	uint8_t port_count;
 	uint8_t max_port_count;
+	uint8_t hba_reset_count;
 
 	sata_ahci_mode = 0;
 	if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
@@ -124,14 +139,23 @@ static void sata_init(struct device *dev)
 	/* SATA SMBus Disable */
 	sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
 
+	hba_reset_count = 0;
+
+retry_init:
 	byte = pci_read_config8(sm_dev, 0xad);
 	/* Disable SATA SMBUS */
-	byte |= (1 << 0);
-	/* Enable SATA and power saving */
 	byte |= (1 << 1);
+	/* Enable SATA and power saving */
+	byte |= (1 << 0);
 	byte |= (1 << 5);
 	pci_write_config8(sm_dev, 0xad, byte);
 
+	/* Take the PHY logic out of reset */
+	word = pci_read_config16(dev, 0x84);
+	word |= 0x1 << 2;
+	word &= ~0x1f8;
+	pci_write_config16(dev, 0x84, word);
+
 	/* get rev_id */
 	rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
 
@@ -324,6 +348,26 @@ static void sata_init(struct device *dev)
 	if (port_count > max_port_count)
 		port_count = max_port_count;
 
+	/* Send COMRESET to all ports */
+	for (i = 0; i < port_count; i++) {
+		/* Read in Port-N Serial ATA Control Register */
+		byte = read8(sata_bar5 + 0x12C + 0x80 * i);
+
+		/* Set Reset Bit */
+		byte |= 0x1;
+		write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+
+		/* Wait 1ms */
+		mdelay(1);
+
+		/* Clear Reset Bit */
+		byte &= ~0x01;
+		write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+
+		/* Wait 1ms */
+		mdelay(1);
+	}
+
 	/* RPR7.7 SATA drive detection. */
 	/* Use BAR5+0x128,BAR0 for Primary Slave */
 	/* Use BAR5+0x1A8,BAR0 for Primary Slave */
@@ -369,8 +413,31 @@ static void sata_init(struct device *dev)
 					current_bar = ((i / 2) == 0) ? sata_bar0 : sata_bar2;
 				else
 					current_bar = ide_bar0;
-				if (!sata_drive_detect(i, current_bar))
+				ret = sata_drive_detect(i, current_bar);
+				if (ret == 0) {
 					break;
+				} else if (ret == 2) {
+					/* Reset PHY logic */
+					word = pci_read_config16(dev, 0x84);
+					word &= ~(0x1 << 2);
+					word |= 0x1f8;
+					pci_write_config16(dev, 0x84, word);
+
+					/* Disable SATA controller */
+					byte = pci_read_config8(sm_dev, 0xad);
+					byte &= ~(0x1);
+					pci_write_config8(sm_dev, 0xad, byte);
+
+					mdelay(100);
+
+					/* Retry initialization */
+					hba_reset_count++;
+					if (hba_reset_count < 16)
+						goto retry_init;
+					else
+						printk(BIOS_WARNING, "HBA reset count exceeded, "
+							"continuing but AHCI drives may not function\n");
+				}
 			}
 			if (sata_ahci_mode)
 				printk(BIOS_DEBUG, "AHCI device %d is %sready after %i tries\n",
-- 
1.7.9.5