blob: 4f14173586af0b7c6bff086b59844038c4ab91f0 [file] [log] [blame]
Lee Leahy4dd34ee2016-05-02 14:31:02 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2016 Intel Corp.
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 wacbmem_entryanty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define __SIMPLE_DEVICE__
17
Lee Leahyae738ac2016-07-24 08:03:37 -070018#include <cpu/x86/mtrr.h>
Lee Leahy4dd34ee2016-05-02 14:31:02 -070019#include <console/console.h>
20#include <soc/pci_devs.h>
Lee Leahy5ef051a2016-04-29 15:16:54 -070021#include <soc/ramstage.h>
Lee Leahy4dd34ee2016-05-02 14:31:02 -070022
Lee Leahy7f4b0532016-05-22 11:52:28 -070023static uint16_t get_gpe0_address(uint32_t reg_address)
24{
25 uint32_t gpe0_base_address;
26
27 /* Get the GPE0 base address */
28 gpe0_base_address = pci_read_config32(LPC_BDF, R_QNC_LPC_GPE0BLK);
29 ASSERT (gpe0_base_address >= 0x80000000);
30 gpe0_base_address &= B_QNC_LPC_GPE0BLK_MASK;
31
32 /* Return the GPE0 register address */
33 return (uint16_t)(gpe0_base_address + reg_address);
34}
35
Lee Leahyac690b12016-05-15 15:12:56 -070036static uint32_t *get_gpio_address(uint32_t reg_address)
37{
38 uint32_t gpio_base_address;
39
40 /* Get the GPIO base address */
41 gpio_base_address = pci_read_config32(I2CGPIO_BDF, PCI_BASE_ADDRESS_1);
42 gpio_base_address &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
43 ASSERT (gpio_base_address != 0x00000000);
44
45 /* Return the GPIO register address */
46 return (uint32_t *)(gpio_base_address + reg_address);
47}
48
49void *get_i2c_address(void)
50{
51 uint32_t gpio_base_address;
52
53 /* Get the GPIO base address */
54 gpio_base_address = pci_read_config32(I2CGPIO_BDF, PCI_BASE_ADDRESS_0);
55 gpio_base_address &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
56 ASSERT (gpio_base_address != 0x00000000);
57
58 /* Return the GPIO register address */
59 return (void *)gpio_base_address;
60}
61
62static uint16_t get_legacy_gpio_address(uint32_t reg_address)
63{
64 uint32_t gpio_base_address;
65
66 /* Get the GPIO base address */
67 gpio_base_address = pci_read_config32(LPC_BDF, R_QNC_LPC_GBA_BASE);
68 ASSERT (gpio_base_address >= 0x80000000);
69 gpio_base_address &= B_QNC_LPC_GPA_BASE_MASK;
70
71 /* Return the GPIO register address */
72 return (uint16_t)(gpio_base_address + reg_address);
73}
74
Lee Leahyae738ac2016-07-24 08:03:37 -070075static uint32_t mtrr_index_to_host_bridge_register_offset(unsigned long index)
76{
77 uint32_t offset;
78
79 /* Convert from MTRR index to host brigde offset (Datasheet 12.7.2) */
80 if (index == MTRR_CAP_MSR)
81 offset = QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP;
82 else if (index == MTRR_DEF_TYPE_MSR)
83 offset = QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE;
84 else if (index == MTRR_FIX_64K_00000)
85 offset = QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000;
86 else if ((index >= MTRR_FIX_16K_80000) && (index <= MTRR_FIX_16K_A0000))
87 offset = ((index - MTRR_FIX_16K_80000) << 1)
88 + QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000;
89 else if ((index >= MTRR_FIX_4K_C0000) && (index <= MTRR_FIX_4K_F8000))
90 offset = ((index - MTRR_FIX_4K_C0000) << 1)
91 + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0;
92 else if ((index >= MTRR_PHYS_BASE(0)) && (index <= MTRR_PHYS_MASK(7)))
93 offset = (index - MTRR_PHYS_BASE(0))
94 + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0;
95 else {
96 printk(BIOS_DEBUG, "index: 0x%08lx\n", index);
97 die("Invalid MTRR index specified!\n");
98 }
99 return offset;
100}
101
Lee Leahy4dd34ee2016-05-02 14:31:02 -0700102void mcr_write(uint8_t opcode, uint8_t port, uint32_t reg_address)
103{
104 pci_write_config32(MC_BDF, QNC_ACCESS_PORT_MCR,
105 (opcode << QNC_MCR_OP_OFFSET)
106 | ((uint32_t)port << QNC_MCR_PORT_OFFSET)
107 | ((reg_address & QNC_MCR_MASK) << QNC_MCR_REG_OFFSET)
108 | QNC_MCR_BYTE_ENABLES);
109}
110
111uint32_t mdr_read(void)
112{
113 return pci_read_config32(MC_BDF, QNC_ACCESS_PORT_MDR);
114}
115
116void mdr_write(uint32_t value)
117{
118 pci_write_config32(MC_BDF, QNC_ACCESS_PORT_MDR, value);
119}
120
121void mea_write(uint32_t reg_address)
122{
123 pci_write_config32(MC_BDF, QNC_ACCESS_PORT_MEA, reg_address
124 & QNC_MEA_MASK);
125}
126
Lee Leahyae738ac2016-07-24 08:03:37 -0700127uint32_t port_reg_read(uint8_t port, uint32_t offset)
128{
129 /* Read the port register */
130 mea_write(offset);
131 mcr_write(QUARK_OPCODE_READ, port, offset);
132 return mdr_read();
133}
134
135void port_reg_write(uint8_t port, uint32_t offset, uint32_t value)
136{
137 /* Write the port register */
138 mea_write(offset);
139 mdr_write(value);
140 mcr_write(QUARK_OPCODE_WRITE, port, offset);
141}
142
Lee Leahy7f4b0532016-05-22 11:52:28 -0700143static uint32_t reg_gpe0_read(uint32_t reg_address)
144{
145 /* Read the GPE0 register */
146 return inl(get_gpe0_address(reg_address));
147}
148
149static void reg_gpe0_write(uint32_t reg_address, uint32_t value)
150{
151 /* Write the GPE0 register */
152 outl(get_gpe0_address(reg_address), value);
153}
154
Lee Leahy083da162016-05-15 13:32:24 -0700155static uint32_t reg_gpio_read(uint32_t reg_address)
156{
157 /* Read the GPIO register */
158 return *get_gpio_address(reg_address);
159}
160
161static void reg_gpio_write(uint32_t reg_address, uint32_t value)
162{
163 /* Write the GPIO register */
164 *get_gpio_address(reg_address) = value;
165}
166
Lee Leahy660c67a2016-07-10 17:09:24 -0700167uint32_t reg_host_bridge_unit_read(uint32_t reg_address)
168{
169 /* Read the host bridge register */
170 mea_write(reg_address);
171 mcr_write(QUARK_OPCODE_READ, QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
172 reg_address);
173 return mdr_read();
174}
175
176static void reg_host_bridge_unit_write(uint32_t reg_address, uint32_t value)
177{
178 /* Write the host bridge register */
179 mea_write(reg_address);
180 mdr_write(value);
181 mcr_write(QUARK_OPCODE_WRITE, QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
182 reg_address);
183}
184
Lee Leahy083da162016-05-15 13:32:24 -0700185uint32_t reg_legacy_gpio_read(uint32_t reg_address)
186{
187 /* Read the legacy GPIO register */
188 return inl(get_legacy_gpio_address(reg_address));
189}
190
191void reg_legacy_gpio_write(uint32_t reg_address, uint32_t value)
192{
193 /* Write the legacy GPIO register */
194 outl(value, get_legacy_gpio_address(reg_address));
195}
196
Lee Leahy5ef051a2016-04-29 15:16:54 -0700197static uint32_t reg_pcie_afe_read(uint32_t reg_address)
198{
199 /* Read the PCIE AFE register */
200 mea_write(reg_address);
201 mcr_write(QUARK_OPCODE_IO_READ, QUARK_SC_PCIE_AFE_SB_PORT_ID,
202 reg_address);
203 return mdr_read();
204}
205
206static void reg_pcie_afe_write(uint32_t reg_address, uint32_t value)
207{
208 /* Write the PCIE AFE register */
209 mea_write(reg_address);
210 mdr_write(value);
211 mcr_write(QUARK_OPCODE_IO_WRITE, QUARK_SC_PCIE_AFE_SB_PORT_ID,
212 reg_address);
213}
214
Lee Leahy63e3dff2016-04-30 08:48:52 -0700215uint32_t reg_rmu_temp_read(uint32_t reg_address)
216{
217 /* Read the RMU temperature register */
218 mea_write(reg_address);
219 mcr_write(QUARK_OPCODE_READ, QUARK_NC_RMU_SB_PORT_ID, reg_address);
220 return mdr_read();
221}
222
223static void reg_rmu_temp_write(uint32_t reg_address, uint32_t value)
224{
225 /* Write the RMU temperature register */
226 mea_write(reg_address);
227 mdr_write(value);
228 mcr_write(QUARK_OPCODE_WRITE, QUARK_NC_RMU_SB_PORT_ID, reg_address);
229}
230
231static uint32_t reg_soc_unit_read(uint32_t reg_address)
232{
233 /* Read the temperature sensor register */
234 mea_write(reg_address);
235 mcr_write(QUARK_ALT_OPCODE_READ, QUARK_SCSS_SOC_UNIT_SB_PORT_ID,
236 reg_address);
237 return mdr_read();
238}
239
240static void reg_soc_unit_write(uint32_t reg_address, uint32_t value)
241{
242 /* Write the temperature sensor register */
243 mea_write(reg_address);
244 mdr_write(value);
245 mcr_write(QUARK_ALT_OPCODE_WRITE, QUARK_SCSS_SOC_UNIT_SB_PORT_ID,
246 reg_address);
247}
248
Lee Leahy4dd34ee2016-05-02 14:31:02 -0700249static uint32_t reg_usb_read(uint32_t reg_address)
250{
251 /* Read the USB register */
252 mea_write(reg_address);
253 mcr_write(QUARK_ALT_OPCODE_READ, QUARK_SC_USB_AFE_SB_PORT_ID,
254 reg_address);
255 return mdr_read();
256}
257
258static void reg_usb_write(uint32_t reg_address, uint32_t value)
259{
260 /* Write the USB register */
261 mea_write(reg_address);
262 mdr_write(value);
263 mcr_write(QUARK_ALT_OPCODE_WRITE, QUARK_SC_USB_AFE_SB_PORT_ID,
264 reg_address);
265}
266
267static uint64_t reg_read(struct reg_script_context *ctx)
268{
269 const struct reg_script *step = ctx->step;
270 uint64_t value = 0;
271
272 switch (step->id) {
273 default:
274 printk(BIOS_ERR,
275 "ERROR - Unknown register set (0x%08x)!\n",
276 step->id);
277 ctx->display_features = REG_SCRIPT_DISPLAY_NOTHING;
278 return 0;
279
Lee Leahy7f4b0532016-05-22 11:52:28 -0700280 case GPE0_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700281 ctx->display_prefix = "GPE0";
Lee Leahy7f4b0532016-05-22 11:52:28 -0700282 value = reg_gpe0_read(step->reg);
283 break;
284
Lee Leahy083da162016-05-15 13:32:24 -0700285 case GPIO_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700286 ctx->display_prefix = "GPIO";
Lee Leahy083da162016-05-15 13:32:24 -0700287 value = reg_gpio_read(step->reg);
288 break;
289
Lee Leahy660c67a2016-07-10 17:09:24 -0700290 case HOST_BRIDGE:
291 ctx->display_prefix = "Host Bridge";
292 value = reg_host_bridge_unit_read(step->reg);
293 break;
294
Lee Leahy083da162016-05-15 13:32:24 -0700295 case LEG_GPIO_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700296 ctx->display_prefix = "Legacy GPIO";
Lee Leahy083da162016-05-15 13:32:24 -0700297 value = reg_legacy_gpio_read(step->reg);
Lee Leahyb06724022016-07-18 10:39:55 -0700298 break;
Lee Leahy5ef051a2016-04-29 15:16:54 -0700299
300 case PCIE_AFE_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700301 ctx->display_prefix = "PCIe AFE";
Lee Leahy5ef051a2016-04-29 15:16:54 -0700302 value = reg_pcie_afe_read(step->reg);
Lee Leahy083da162016-05-15 13:32:24 -0700303 break;
304
Lee Leahy63e3dff2016-04-30 08:48:52 -0700305 case RMU_TEMP_REGS:
306 ctx->display_prefix = "RMU TEMP";
307 value = reg_rmu_temp_read(step->reg);
308 break;
309
310 case SOC_UNIT_REGS:
311 ctx->display_prefix = "SOC Unit";
312 value = reg_soc_unit_read(step->reg);
313 break;
314
Lee Leahy4dd34ee2016-05-02 14:31:02 -0700315 case USB_PHY_REGS:
316 ctx->display_prefix = "USB PHY";
317 value = reg_usb_read(step->reg);
318 break;
319 }
320 return value;
321}
322
323static void reg_write(struct reg_script_context *ctx)
324{
325 const struct reg_script *step = ctx->step;
326
327 switch (step->id) {
328 default:
329 printk(BIOS_ERR,
330 "ERROR - Unknown register set (0x%08x)!\n",
331 step->id);
332 ctx->display_features = REG_SCRIPT_DISPLAY_NOTHING;
333 return;
334
Lee Leahy7f4b0532016-05-22 11:52:28 -0700335 case GPE0_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700336 ctx->display_prefix = "GPE0";
Lee Leahy7f4b0532016-05-22 11:52:28 -0700337 reg_gpe0_write(step->reg, (uint32_t)step->value);
338 break;
339
Lee Leahy083da162016-05-15 13:32:24 -0700340 case GPIO_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700341 ctx->display_prefix = "GPIO";
Lee Leahy083da162016-05-15 13:32:24 -0700342 reg_gpio_write(step->reg, (uint32_t)step->value);
343 break;
344
Lee Leahy660c67a2016-07-10 17:09:24 -0700345 case HOST_BRIDGE:
346 ctx->display_prefix = "Host Bridge";
347 reg_host_bridge_unit_write(step->reg, (uint32_t)step->value);
348 break;
349
Lee Leahy083da162016-05-15 13:32:24 -0700350 case LEG_GPIO_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700351 ctx->display_prefix = "Legacy GPIO";
Lee Leahy083da162016-05-15 13:32:24 -0700352 reg_legacy_gpio_write(step->reg, (uint32_t)step->value);
353 break;
354
Lee Leahy5ef051a2016-04-29 15:16:54 -0700355 case PCIE_AFE_REGS:
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700356 ctx->display_prefix = "PCIe AFE";
Lee Leahy5ef051a2016-04-29 15:16:54 -0700357 reg_pcie_afe_write(step->reg, (uint32_t)step->value);
358 break;
359
360 case PCIE_RESET:
361 if (ctx->display_features) {
Lee Leahy6b24dfc2016-05-22 16:24:36 -0700362 ctx->display_prefix = "PCIe reset";
Lee Leahy5ef051a2016-04-29 15:16:54 -0700363 ctx->display_features &= ~REG_SCRIPT_DISPLAY_REGISTER;
364 }
365 mainboard_gpio_pcie_reset(step->value);
366 break;
367
Lee Leahy63e3dff2016-04-30 08:48:52 -0700368 case RMU_TEMP_REGS:
369 ctx->display_prefix = "RMU TEMP";
370 reg_rmu_temp_write(step->reg, (uint32_t)step->value);
371 break;
372
373 case SOC_UNIT_REGS:
374 ctx->display_prefix = "SOC Unit";
375 reg_soc_unit_write(step->reg, (uint32_t)step->value);
376 break;
377
Lee Leahy4c3f5dc2016-04-29 16:36:02 -0700378 case MICROSECOND_DELAY:
379 /* The actual delay is >= the requested delay */
380 if (ctx->display_features) {
381 /* Higher baud-rates will reduce the impact of displaying this message */
382 printk(BIOS_INFO, "Delay %lld uSec\n", step->value);
383 ctx->display_features = REG_SCRIPT_DISPLAY_NOTHING;
384 }
385 udelay(step->value);
386 break;
387
Lee Leahy4dd34ee2016-05-02 14:31:02 -0700388 case USB_PHY_REGS:
389 ctx->display_prefix = "USB PHY";
390 reg_usb_write(step->reg, (uint32_t)step->value);
391 break;
392 }
393}
394
Lee Leahyae738ac2016-07-24 08:03:37 -0700395msr_t soc_msr_read(unsigned index)
396{
397 uint32_t offset;
398 union {
399 uint64_t u64;
400 msr_t msr;
401 } value;
402
403 /* Read the low 32-bits of the register */
404 offset = mtrr_index_to_host_bridge_register_offset(index);
405 value.u64 = port_reg_read(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, offset);
406
407 /* For 64-bit registers, read the upper 32-bits */
408 if ((offset >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000)
409 && (offset <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000)) {
410 offset += 1;
411 value.u64 |= port_reg_read(QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
412 offset);
413 }
414 return value.msr;
415}
416
417void soc_msr_write(unsigned index, msr_t msr)
418{
419 uint32_t offset;
420 union {
421 uint32_t u32[2];
422 msr_t msr;
423 } value;
424
425 /* Write the low 32-bits of the register */
426 value.msr = msr;
427 offset = mtrr_index_to_host_bridge_register_offset(index);
428 port_reg_write(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, offset, value.u32[0]);
429
430 /* For 64-bit registers, write the upper 32-bits */
431 if ((offset >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000)
432 && (offset <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000)) {
433 offset += 1;
434 port_reg_write(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, offset,
435 value.u32[1]);
436 }
437}
438
Lee Leahy4dd34ee2016-05-02 14:31:02 -0700439const struct reg_script_bus_entry soc_reg_script_bus_table = {
440 SOC_TYPE, reg_read, reg_write
441};
442
443REG_SCRIPT_BUS_ENTRY(soc_reg_script_bus_table);