Add support for Intel Panther Point PCH
[coreboot.git] / src / southbridge / intel / bd82x6x / pch.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2008-2009 coresystems GmbH
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <console/console.h>
22 #include <delay.h>
23 #include <device/device.h>
24 #include <device/pci.h>
25 #include "pch.h"
26
27 static int pch_revision_id = -1;
28
29 int pch_silicon_revision(void)
30 {
31         if (pch_revision_id < 0)
32                 pch_revision_id = pci_read_config8(
33                         dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
34                         PCI_REVISION_ID);
35         return pch_revision_id;
36 }
37
38 /* Set bit in Function Disble register to hide this device */
39 static void pch_hide_devfn(unsigned devfn)
40 {
41         switch (devfn) {
42         case PCI_DEVFN(22, 0): /* MEI #1 */
43                 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
44                 break;
45         case PCI_DEVFN(22, 1): /* MEI #2 */
46                 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
47                 break;
48         case PCI_DEVFN(22, 2): /* IDE-R */
49                 RCBA32_OR(FD2, PCH_DISABLE_IDER);
50                 break;
51         case PCI_DEVFN(22, 3): /* KT */
52                 RCBA32_OR(FD2, PCH_DISABLE_KT);
53                 break;
54         case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
55                 RCBA32_OR(BUC, PCH_DISABLE_GBE);
56                 break;
57         case PCI_DEVFN(26, 0): /* EHCI #2 */
58                 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
59                 break;
60         case PCI_DEVFN(27, 0): /* HD Audio Controller */
61                 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
62                 break;
63         case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
64         case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
65         case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
66         case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
67         case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
68         case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
69         case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
70         case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
71                 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
72                 break;
73         case PCI_DEVFN(29, 0): /* EHCI #1 */
74                 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
75                 break;
76         case PCI_DEVFN(30, 0): /* PCI-to-PCI Bridge */
77                 RCBA32_OR(FD, PCH_DISABLE_P2P);
78                 break;
79         case PCI_DEVFN(31, 0): /* LPC */
80                 RCBA32_OR(FD, PCH_DISABLE_LPC);
81                 break;
82         case PCI_DEVFN(31, 2): /* SATA #1 */
83                 RCBA32_OR(FD, PCH_DISABLE_SATA1);
84                 break;
85         case PCI_DEVFN(31, 3): /* SMBUS */
86                 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
87                 break;
88         case PCI_DEVFN(31, 5): /* SATA #22 */
89                 RCBA32_OR(FD, PCH_DISABLE_SATA2);
90                 break;
91         case PCI_DEVFN(31, 6): /* Thermal Subsystem */
92                 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
93                 break;
94         }
95 }
96
97 #define IOBP_RETRY 1000
98 static inline int iobp_poll(void)
99 {
100         unsigned try = IOBP_RETRY;
101         u32 data;
102
103         while (try--) {
104                 data = RCBA32(IOBPS);
105                 if ((data & 1) == 0)
106                         return 1;
107                 udelay(10);
108         }
109
110         printk(BIOS_ERR, "IOBP timeout\n");
111         return 0;
112 }
113
114 void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
115 {
116         u32 data;
117
118         /* Set the address */
119         RCBA32(IOBPIRI) = address;
120
121         /* READ OPCODE */
122         if (pch_silicon_revision() >= PCH_STEP_B0)
123                 RCBA32(IOBPS) = IOBPS_RW_BX;
124         else
125                 RCBA32(IOBPS) = IOBPS_READ_AX;
126         if (!iobp_poll())
127                 return;
128
129         /* Read IOBP data */
130         data = RCBA32(IOBPD);
131         if (!iobp_poll())
132                 return;
133
134         /* Check for successful transaction */
135         if ((RCBA32(IOBPS) & 0x6) != 0) {
136                 printk(BIOS_ERR, "IOBP read 0x%08x failed\n", address);
137                 return;
138         }
139
140         /* Update the data */
141         data &= andvalue;
142         data |= orvalue;
143
144         /* WRITE OPCODE */
145         if (pch_silicon_revision() >= PCH_STEP_B0)
146                 RCBA32(IOBPS) = IOBPS_RW_BX;
147         else
148                 RCBA32(IOBPS) = IOBPS_WRITE_AX;
149         if (!iobp_poll())
150                 return;
151
152         /* Write IOBP data */
153         RCBA32(IOBPD) = data;
154         if (!iobp_poll())
155                 return;
156 }
157
158 /* Check if any port in set X to X+3 is enabled */
159 static int pch_pcie_check_set_enabled(device_t dev)
160 {
161         device_t port;
162         int port_func;
163         int dev_func = PCI_FUNC(dev->path.pci.devfn);
164
165         printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
166
167         /* Go through static device tree list of devices
168          * because enumeration is still in progress */
169         for (port = all_devices; port; port = port->next) {
170                 /* Only care about PCIe root ports */
171                 if (PCI_SLOT(port->path.pci.devfn) !=
172                     PCI_SLOT(dev->path.pci.devfn))
173                         continue;
174
175                 /* Check if port is in range and enabled */
176                 port_func = PCI_FUNC(port->path.pci.devfn);
177                 if (port_func >= dev_func &&
178                     port_func < (dev_func + 4) &&
179                     port->enabled)
180                         return 1;
181         }
182
183         /* None of the ports in this set are enabled */
184         return 0;
185 }
186
187 void pch_enable(device_t dev)
188 {
189         u32 reg32;
190
191         if (!dev->enabled) {
192                 printk(BIOS_DEBUG, "%s: Disabling device\n",  dev_path(dev));
193
194                 /*
195                  * PCIE Power Savings for stepping B1+:
196                  *
197                  * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
198                  * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
199                  *
200                  * This check is done here instead of pcie driver
201                  * because the pcie driver enable() handler is not
202                  * called unless the device is enabled.
203                  */
204                 if (pch_silicon_revision() >= PCH_STEP_B1 &&
205                     PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT &&
206                     (PCI_FUNC(dev->path.pci.devfn) == 0 ||
207                      PCI_FUNC(dev->path.pci.devfn) == 4)) {
208                         if (!pch_pcie_check_set_enabled(dev)) {
209                                 u8 reg8 = pci_read_config8(dev, 0xe2);
210                                 reg8 |= 1;
211                                 pci_write_config8(dev, 0xe2, reg8);
212                         }
213                 }
214
215                 /* Ensure memory, io, and bus master are all disabled */
216                 reg32 = pci_read_config32(dev, PCI_COMMAND);
217                 reg32 &= ~(PCI_COMMAND_MASTER |
218                            PCI_COMMAND_MEMORY | PCI_COMMAND_IO  );
219                 pci_write_config32(dev, PCI_COMMAND, reg32);
220
221                 /* Hide this device if possible */
222                 pch_hide_devfn(dev->path.pci.devfn);
223         } else {
224                 /* Enable SERR */
225                 reg32 = pci_read_config32(dev, PCI_COMMAND);
226                 reg32 |= PCI_COMMAND_SERR;
227                 pci_write_config32(dev, PCI_COMMAND, reg32);
228         }
229 }
230
231 struct chip_operations southbridge_intel_bd82x6x_ops = {
232         CHIP_NAME("Intel Series 6 (" CONFIG_PCH_CHIP_NAME ") Southbridge")
233         .enable_dev = pch_enable,
234 };