2c0d5a2067415f9dd29bddbbc9fca2ce98e021b1
[coreboot.git] / src / southbridge / nvidia / ck804 / ck804.c
1 /*
2  * Copyright 2004 Tyan Computer
3  *  by yhlu@tyan.com
4  */
5
6 #include <console/console.h>
7 #include <arch/io.h>
8 #include <device/device.h>
9 #include <device/pci.h>
10 #include <device/pci_ids.h>
11 #include <device/pci_ops.h>
12 #include "ck804.h"
13
14 static uint32_t final_reg;
15
16 static device_t find_lpc_dev(device_t dev, unsigned devfn)
17 {
18         device_t lpc_dev;
19
20         lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
21         if (!lpc_dev)
22                 return lpc_dev;
23
24         if ((lpc_dev->vendor != PCI_VENDOR_ID_NVIDIA)
25                 || ((lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_LPC)
26                 && (lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_PRO)
27                 && (lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_SLAVE)))
28         {
29                 uint32_t id;
30                 id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
31                 if ((id != (PCI_VENDOR_ID_NVIDIA |
32                       (PCI_DEVICE_ID_NVIDIA_CK804_LPC << 16)))
33                     && (id != (PCI_VENDOR_ID_NVIDIA |
34                          (PCI_DEVICE_ID_NVIDIA_CK804_PRO << 16)))
35                     && (id != (PCI_VENDOR_ID_NVIDIA |
36                          (PCI_DEVICE_ID_NVIDIA_CK804_SLAVE << 16))))
37                 {
38                         lpc_dev = 0;
39                 }
40         }
41
42         return lpc_dev;
43 }
44
45 void ck804_enable(device_t dev)
46 {
47         device_t lpc_dev;
48         unsigned index = 0, index2 = 0, deviceid, vendorid, devfn;
49         uint32_t reg_old, reg;
50         uint8_t byte;
51
52         struct southbridge_nvidia_ck804_config *conf;
53         conf = dev->chip_info;
54
55         if (dev->device == 0x0000) {
56                 vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
57                 deviceid = (vendorid >> 16) & 0xffff;
58                 /* vendorid &= 0xffff; */
59         } else {
60                 /* vendorid = dev->vendor; */
61                 deviceid = dev->device;
62         }
63
64         devfn = (dev->path.pci.devfn) & ~7;
65         switch (deviceid) {
66         case PCI_DEVICE_ID_NVIDIA_CK804_SM:
67                 index = 16;
68                 break;
69         case PCI_DEVICE_ID_NVIDIA_CK804_USB:
70                 devfn -= (1 << 3);
71                 index = 8;
72                 break;
73         case PCI_DEVICE_ID_NVIDIA_CK804_USB2:
74                 devfn -= (1 << 3);
75                 index = 20;
76                 break;
77         case PCI_DEVICE_ID_NVIDIA_CK804_NIC:
78                 devfn -= (9 << 3);
79                 index = 10;
80                 break;
81         case PCI_DEVICE_ID_NVIDIA_CK804_NIC_BRIDGE:
82                 devfn -= (9 << 3);
83                 index = 10;
84                 break;
85         case PCI_DEVICE_ID_NVIDIA_CK804_ACI:
86                 devfn -= (3 << 3);
87                 index = 12;
88                 break;
89         case PCI_DEVICE_ID_NVIDIA_CK804_MCI:
90                 devfn -= (3 << 3);
91                 index = 13;
92                 break;
93         case PCI_DEVICE_ID_NVIDIA_CK804_IDE:
94                 devfn -= (5 << 3);
95                 index = 14;
96                 break;
97         case PCI_DEVICE_ID_NVIDIA_CK804_SATA0:
98                 devfn -= (6 << 3);
99                 index = 22;
100                 break;
101         case PCI_DEVICE_ID_NVIDIA_CK804_SATA1:
102                 devfn -= (7 << 3);
103                 index = 18;
104                 break;
105         case PCI_DEVICE_ID_NVIDIA_CK804_PCI:
106                 devfn -= (8 << 3);
107                 index = 15;
108                 break;
109         case PCI_DEVICE_ID_NVIDIA_CK804_PCI_E:
110                 devfn -= (0xa << 3);
111                 index2 = 19;
112                 break;
113         default:
114                 index = 0;
115         }
116
117         if (index2 != 0) {
118                 int i;
119                 for (i = 0; i < 4; i++) {
120                         lpc_dev = find_lpc_dev(dev, devfn - (i << 3));
121                         if (!lpc_dev)
122                                 continue;
123                         index2 -= i;
124                         break;
125                 }
126
127                 if (lpc_dev) {
128                         reg_old = reg = pci_read_config32(lpc_dev, 0xe4);
129                         if (!dev->enabled)
130                                 reg |= (1 << index2);
131                         if (reg != reg_old)
132                                 pci_write_config32(lpc_dev, 0xe4, reg);
133                 }
134
135                 index2 = 0;
136                 return;
137         }
138
139         lpc_dev = find_lpc_dev(dev, devfn);
140         if (!lpc_dev)
141                 return;
142
143         if (index == 0) {
144                 final_reg = pci_read_config32(lpc_dev, 0xe8);
145                 final_reg &= ~((1 << 16) | (1 << 8) | (1 << 20) | (1 << 10)
146                         | (1 << 12) | (1 << 13) | (1 << 14) | (1 << 22)
147                         | (1 << 18) | (1 << 15));
148                 pci_write_config32(lpc_dev, 0xe8, final_reg);
149
150                 reg_old = reg = pci_read_config32(lpc_dev, 0xe4);
151                 reg |= (1 << 20);
152                 if (reg != reg_old)
153                         pci_write_config32(lpc_dev, 0xe4, reg);
154
155                 byte = pci_read_config8(lpc_dev, 0x74);
156                 byte |= ((1 << 1));
157                 pci_write_config8(dev, 0x74, byte);
158
159                 byte = pci_read_config8(lpc_dev, 0xdd);
160                 byte |= ((1 << 0) | (1 << 3));
161                 pci_write_config8(dev, 0xdd, byte);
162
163                 return;
164         }
165
166         if (!dev->enabled)
167                 final_reg |= (1 << index);
168
169         if (index == 10) {
170                 reg_old = pci_read_config32(lpc_dev, 0xe8);
171                 if (final_reg != reg_old)
172                         pci_write_config32(lpc_dev, 0xe8, final_reg);
173         }
174 }
175
176 struct chip_operations southbridge_nvidia_ck804_ops = {
177         CHIP_NAME("NVIDIA CK804 Southbridge")
178         .enable_dev = ck804_enable,
179 };