blob: ef95f7e5624e965362930d49d6b74987f06cd9e7 [file] [log] [blame]
Mariusz Szafranskia4041332017-08-02 17:28:17 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 - 2017 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <stdint.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020018#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020019#include <device/pci_ops.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020020#include <device/pci.h>
21#include <device/pci_def.h>
22#include <device/device.h>
Elyes HAOUASa1e22b82019-03-18 22:49:36 +010023#include <string.h>
Mariusz Szafranskia4041332017-08-02 17:28:17 +020024#include <soc/iomap.h>
25#include <soc/soc_util.h>
26#include <soc/pmc.h>
27#include <soc/smbus.h>
28#include <soc/lpc.h>
29#include <soc/pci_devs.h>
30#include <soc/systemagent.h>
31
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010032#ifdef __SIMPLE_DEVICE__
33pci_devfn_t get_hostbridge_dev(void)
Mariusz Szafranskia4041332017-08-02 17:28:17 +020034{
Mariusz Szafranskia4041332017-08-02 17:28:17 +020035 return PCI_DEV(0, SA_DEV, SA_FUNC);
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010036}
Mariusz Szafranskia4041332017-08-02 17:28:17 +020037#else
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010038struct device *get_hostbridge_dev(void)
39{
Kyösti Mälkki903b40a2019-07-03 07:25:59 +030040 return pcidev_on_root(SA_DEV, SA_FUNC);
Mariusz Szafranskia4041332017-08-02 17:28:17 +020041}
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010042#endif
Mariusz Szafranskia4041332017-08-02 17:28:17 +020043
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010044#ifdef __SIMPLE_DEVICE__
45pci_devfn_t get_lpc_dev(void)
Mariusz Szafranskia4041332017-08-02 17:28:17 +020046{
Mariusz Szafranskia4041332017-08-02 17:28:17 +020047 return PCI_DEV(0, LPC_DEV, LPC_FUNC);
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010048}
Mariusz Szafranskia4041332017-08-02 17:28:17 +020049#else
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010050struct device *get_lpc_dev(void)
51{
Kyösti Mälkki903b40a2019-07-03 07:25:59 +030052 return pcidev_on_root(LPC_DEV, LPC_FUNC);
Mariusz Szafranskia4041332017-08-02 17:28:17 +020053}
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010054#endif
Mariusz Szafranskia4041332017-08-02 17:28:17 +020055
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010056#ifdef __SIMPLE_DEVICE__
57pci_devfn_t get_pmc_dev(void)
Mariusz Szafranskia4041332017-08-02 17:28:17 +020058{
Mariusz Szafranskia4041332017-08-02 17:28:17 +020059 return PCI_DEV(0, PMC_DEV, PMC_FUNC);
Mariusz Szafranskia4041332017-08-02 17:28:17 +020060}
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010061#else
62struct device *get_pmc_dev(void)
Mariusz Szafranskia4041332017-08-02 17:28:17 +020063{
Kyösti Mälkki903b40a2019-07-03 07:25:59 +030064 return pcidev_on_root(PMC_DEV, PMC_FUNC);
Mariusz Szafranskia4041332017-08-02 17:28:17 +020065}
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010066#endif
67
68#ifdef __SIMPLE_DEVICE__
69pci_devfn_t get_smbus_dev(void)
70{
71 return PCI_DEV(0, SMBUS_DEV, SMBUS_FUNC);
72}
73#else
74struct device *get_smbus_dev(void)
75{
Kyösti Mälkki903b40a2019-07-03 07:25:59 +030076 return pcidev_on_root(SMBUS_DEV, SMBUS_FUNC);
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010077}
78#endif
Mariusz Szafranskia4041332017-08-02 17:28:17 +020079
80uint32_t get_pciebase(void)
81{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +010082#ifdef __SIMPLE_DEVICE__
83 pci_devfn_t dev;
84#else
85 struct device *dev;
86#endif
Mariusz Szafranskia4041332017-08-02 17:28:17 +020087 u32 pciexbar_reg;
88
89 dev = get_hostbridge_dev();
90 if (!dev)
91 return 0;
92
93 pciexbar_reg = pci_read_config32(dev, PCIEXBAR);
94
95 if (!(pciexbar_reg & (1 << 0)))
96 return 0;
97
98 switch (pciexbar_reg & MASK_PCIEXBAR_LENGTH) {
99 case MASK_PCIEXBAR_LENGTH_256M:
100 pciexbar_reg &= MASK_PCIEXBAR_256M;
101 break;
102 case MASK_PCIEXBAR_LENGTH_128M:
103 pciexbar_reg &= MASK_PCIEXBAR_128M;
104 break;
105 case MASK_PCIEXBAR_LENGTH_64M:
106 pciexbar_reg &= MASK_PCIEXBAR_64M;
107 break;
108 default:
109 pciexbar_reg &= MASK_PCIEXBAR_256M;
110 break;
111 }
112
113 return pciexbar_reg;
114}
115
116uint32_t get_pcielength(void)
117{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100118#ifdef __SIMPLE_DEVICE__
119 pci_devfn_t dev;
120#else
121 struct device *dev;
122#endif
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200123 u32 pciexbar_reg;
124
125 dev = get_hostbridge_dev();
126 if (!dev)
127 return 0;
128
129 pciexbar_reg = pci_read_config32(dev, PCIEXBAR);
130
131 if (!(pciexbar_reg & (1 << 0)))
132 return 0;
133
134 switch (pciexbar_reg & MASK_PCIEXBAR_LENGTH) {
135 case MASK_PCIEXBAR_LENGTH_256M:
136 pciexbar_reg = 256;
137 break;
138 case MASK_PCIEXBAR_LENGTH_128M:
139 pciexbar_reg = 128;
140 break;
141 case MASK_PCIEXBAR_LENGTH_64M:
142 pciexbar_reg = 64;
143 break;
144 default:
145 pciexbar_reg = 64;
146 break;
147 }
148
149 return pciexbar_reg;
150}
151
152uint32_t get_tseg_memory(void)
153{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100154#ifdef __SIMPLE_DEVICE__
155 pci_devfn_t dev;
156#else
157 struct device *dev;
158#endif
159 dev = get_hostbridge_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200160
161 if (!dev)
162 return 0;
163
164 return pci_read_config32(dev, TSEGMB) & MASK_TSEGMB;
165}
166
167uint32_t get_top_of_low_memory(void)
168{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100169#ifdef __SIMPLE_DEVICE__
170 pci_devfn_t dev;
171#else
172 struct device *dev;
173#endif
174 dev = get_hostbridge_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200175
176 if (!dev)
177 return 0;
178
179 return pci_read_config32(dev, TOLUD) & MASK_TOLUD;
180}
181
182uint64_t get_top_of_upper_memory(void)
183{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100184#ifdef __SIMPLE_DEVICE__
185 pci_devfn_t dev;
186#else
187 struct device *dev;
188#endif
189 dev = get_hostbridge_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200190
191 if (!dev)
192 return 0;
193
194 return ((uint64_t)(pci_read_config32(dev, TOUUD_HI) & MASK_TOUUD_HI)
195 << 32) +
196 (uint64_t)(pci_read_config32(dev, TOUUD_LO) & MASK_TOUUD_LO);
197}
198
199uint16_t get_pmbase(void)
200{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100201#ifdef __SIMPLE_DEVICE__
202 pci_devfn_t dev;
203#else
204 struct device *dev;
205#endif
206 dev = get_pmc_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200207
208 if (!dev)
209 return 0;
210
211 return pci_read_config16(dev, PMC_ACPI_BASE) & 0xfff8;
212}
213
214uint16_t get_tcobase(void)
215{
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100216#ifdef __SIMPLE_DEVICE__
217 pci_devfn_t dev;
218#else
219 struct device *dev;
220#endif
221 dev = get_smbus_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200222
223 if (!dev)
224 return 0;
225
226 return pci_read_config16(dev, TCOBASE) & MASK_TCOBASE;
227}
228
229void mmio_andthenor32(void *addr, uint32_t val2and, uint32_t val2or)
230{
231 uint32_t reg32;
232
233 reg32 = read32(addr);
234 reg32 &= (uint32_t)val2and;
235 reg32 |= (uint32_t)val2or;
236 write32(addr, reg32);
237}
238
239uint8_t silicon_stepping(void)
240{
241 uint8_t revision_id;
Elyes HAOUAS6f01f432018-12-05 10:56:30 +0100242#ifdef __SIMPLE_DEVICE__
243 pci_devfn_t dev;
244#else
245 struct device *dev;
246#endif
247 dev = get_lpc_dev();
Mariusz Szafranskia4041332017-08-02 17:28:17 +0200248
249 if (!dev)
250 return 0;
251
252 revision_id = pci_read_config8(dev, PCI_REVISION_ID);
253
254 return revision_id;
255}
256
257void *memcpy_s(void *dest, const void *src, size_t n)
258{
259 uint8_t *dp;
260 const uint8_t *sp;
261
262 dp = (uint8_t *)dest;
263 sp = (uint8_t *)src;
264
265 if (!n)
266 return dest;
267
268 if (n > UINT32_MAX)
269 return dest;
270
271 if (!dp)
272 return dest;
273
274 if (!sp)
275 return dest;
276
277 /*
278 * overlap is undefined behavior, do not allow
279 */
280 if (((dp > sp) && (dp < (sp + n))) || ((sp > dp) && (sp < (dp + n))))
281 return dest;
282
283 /*
284 * now perform the copy
285 */
286
287 /* Original memcpy() function */
288 unsigned long d0, d1, d2;
289
290 asm volatile(
291#ifdef __x86_64__
292 "rep ; movsd\n\t"
293 "mov %4,%%rcx\n\t"
294#else
295 "rep ; movsl\n\t"
296 "movl %4,%%ecx\n\t"
297#endif
298 "rep ; movsb\n\t"
299 : "=&c"(d0), "=&D"(d1), "=&S"(d2)
300 : "0"(n >> 2), "g"(n & 3), "1"(dest), "2"(src)
301 : "memory");
302
303 return dest;
304}