1package main 2 3import "fmt" 4 5type LPVariant int 6 7const ( 8 LYNX_POINT_MOBILE LPVariant = iota 9 LYNX_POINT_DESKTOP 10 LYNX_POINT_SERVER 11 LYNX_POINT_ULT 12) 13 14type lynxpoint struct { 15 variant LPVariant 16 node *DevTreeNode 17} 18 19func lpPchGetFlashSize(ctx Context) { 20 inteltool := ctx.InfoSource.GetInteltool() 21 /* In LP PCH, Boot BIOS Straps field in GCS has only one bit. */ 22 switch (inteltool.RCBA[0x3410] >> 10) & 1 { 23 case 0: 24 ROMProtocol = "SPI" 25 highflkb := uint32(0) 26 for reg := uint16(0); reg < 5; reg++ { 27 fl := (inteltool.RCBA[0x3854+4*reg] >> 16) & 0x1fff 28 flkb := (fl + 1) << 2 29 if flkb > highflkb { 30 highflkb = flkb 31 } 32 } 33 ROMSizeKB = int(highflkb) 34 FlashROMSupport = "y" 35 } 36} 37 38func (b lynxpoint) GetGPIOHeader() string { 39 return "southbridge/intel/lynxpoint/pch.h" 40} 41 42func (b lynxpoint) EnableGPE(in int) { 43 if b.variant != LYNX_POINT_ULT { 44 b.node.Registers[fmt.Sprintf("gpi%d_routing", in)] = "2" 45 } 46} 47 48func (b lynxpoint) EncodeGPE(in int) int { 49 return in + 0x10 50} 51 52func (b lynxpoint) DecodeGPE(in int) int { 53 return in - 0x10 54} 55 56func (b lynxpoint) NeedRouteGPIOManually() { 57 b.node.Comment += ", FIXME: set gpiX_routing for EC support" 58} 59 60func GetLptDesktopEHCISetting(loc_param uint32, txamp uint32) (string, int) { 61 var port_pos string 62 var port_length int 63 64 if loc_param == 4 { 65 port_pos = "USB_PORT_BACK_PANEL" 66 if txamp <= 2 { 67 port_length = 0x40 68 } else if txamp >= 4 { 69 port_length = 0x140 70 } else { 71 port_length = 0x110 72 } 73 } else { 74 port_pos = "USB_PORT_FLEX" 75 port_length = 0x40 76 } 77 return port_pos, port_length 78} 79 80func GetLptMobileEHCISetting(loc_param uint32, txamp uint32) (string, int) { 81 var port_pos string 82 var port_length int 83 84 if loc_param == 4 { 85 port_pos = "USB_PORT_DOCK" 86 if txamp <= 1 { 87 port_length = 0x40 88 } else { 89 port_length = 0x80 90 } 91 } else if loc_param == 6 { 92 /* not internal, not dock, port_length >= 0x70 */ 93 port_pos = "USB_PORT_BACK_PANEL" 94 if txamp <= 2 { 95 port_length = 0x80 96 } else { 97 port_length = 0x110 98 } 99 } else { 100 port_pos = "USB_PORT_BACK_PANEL" 101 port_length = 0x40 102 } 103 return port_pos, port_length 104} 105 106func GetLptLPEHCISetting(loc_param uint32, txamp uint32) (string, int) { 107 var port_pos string 108 var port_length int 109 110 if loc_param == 6 { 111 /* back panel or mini pcie, length >= 0x70 */ 112 port_pos = "USB_PORT_MINI_PCIE" 113 if txamp <= 2 { 114 port_length = 0x80 115 } else { 116 port_length = 0x110 117 } 118 } else if loc_param == 4 { 119 port_pos = "USB_PORT_DOCK" 120 if txamp <= 1 { 121 port_length = 0x40 122 } else { 123 port_length = 0x80 124 } 125 } else { 126 port_pos = "USB_PORT_BACK_PANEL" 127 port_length = 0x40 128 } 129 return port_pos, port_length 130} 131 132func (b lynxpoint) Scan(ctx Context, addr PCIDevData) { 133 134 SouthBridge = &b 135 136 inteltool := ctx.InfoSource.GetInteltool() 137 138 isULT := (b.variant == LYNX_POINT_ULT) 139 140 if isULT { 141 Lynxpoint_LP_GPIO(ctx, inteltool) 142 } else { 143 GPIO(ctx, inteltool) 144 } 145 146 KconfigBool["SOUTHBRIDGE_INTEL_LYNXPOINT"] = true 147 if isULT { 148 KconfigBool["INTEL_LYNXPOINT_LP"] = true 149 } 150 KconfigBool["SERIRQ_CONTINUOUS_MODE"] = true 151 if isULT { 152 KconfigInt["USBDEBUG_HCD_INDEX"] = 1 153 } else { 154 KconfigInt["USBDEBUG_HCD_INDEX"] = 2 155 KconfigComment["USBDEBUG_HCD_INDEX"] = "FIXME: check this" 156 } 157 158 if isULT { 159 lpPchGetFlashSize(ctx) 160 } else { 161 ich9GetFlashSize(ctx) 162 } 163 164 FADT := ctx.InfoSource.GetACPI()["FACP"] 165 166 sp0dtle_data := (inteltool.IOBP[0xea002750] >> 24) & 0xf 167 sp0dtle_edge := (inteltool.IOBP[0xea002754] >> 16) & 0xf 168 sp1dtle_data := (inteltool.IOBP[0xea002550] >> 24) & 0xf 169 sp1dtle_edge := (inteltool.IOBP[0xea002554] >> 16) & 0xf 170 171 if sp0dtle_data != sp0dtle_edge { 172 fmt.Printf("Different SATA Gen3 port0 DTLE data and edge values are used.\n") 173 } 174 175 if sp1dtle_data != sp1dtle_edge { 176 fmt.Printf("Different SATA Gen3 port1 DTLE data and edge values are used.\n") 177 } 178 179 cur := DevTreeNode{ 180 Chip: "southbridge/intel/lynxpoint", 181 Comment: "Intel Series 8 Lynx Point PCH", 182 183 /* alt_gp_smi_en is not generated because coreboot doesn't use SMI like OEM firmware */ 184 Registers: map[string]string{ 185 "gen1_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x84:0x88]), 186 "gen2_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x88:0x8c]), 187 "gen3_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x8c:0x90]), 188 "gen4_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x90:0x94]), 189 "sata_port_map": fmt.Sprintf("0x%x", PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 2}].ConfigDump[0x92]&0x3f), 190 "docking_supported": (FormatBool((FADT[113] & (1 << 1)) != 0)), 191 "sata_port0_gen3_dtle": fmt.Sprintf("0x%x", sp0dtle_data), 192 "sata_port1_gen3_dtle": fmt.Sprintf("0x%x", sp1dtle_data), 193 }, 194 PCISlots: []PCISlot{ 195 PCISlot{PCIAddr: PCIAddr{Dev: 0x13, Func: 0}, writeEmpty: isULT, additionalComment: "Smart Sound Audio DSP"}, 196 PCISlot{PCIAddr: PCIAddr{Dev: 0x14, Func: 0}, writeEmpty: true, additionalComment: "xHCI Controller"}, 197 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 0}, writeEmpty: isULT, additionalComment: "Serial I/O DMA"}, 198 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 1}, writeEmpty: isULT, additionalComment: "I2C0"}, 199 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 2}, writeEmpty: isULT, additionalComment: "I2C1"}, 200 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 3}, writeEmpty: isULT, additionalComment: "GSPI0"}, 201 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 4}, writeEmpty: isULT, additionalComment: "GSPI1"}, 202 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 5}, writeEmpty: isULT, additionalComment: "UART0"}, 203 PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 6}, writeEmpty: isULT, additionalComment: "UART1"}, 204 PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 0}, writeEmpty: true, additionalComment: "Management Engine Interface 1"}, 205 PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 1}, writeEmpty: true, additionalComment: "Management Engine Interface 2"}, 206 PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 2}, writeEmpty: true, additionalComment: "Management Engine IDE-R"}, 207 PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 3}, writeEmpty: true, additionalComment: "Management Engine KT"}, 208 PCISlot{PCIAddr: PCIAddr{Dev: 0x17, Func: 0}, writeEmpty: isULT, additionalComment: "SDIO"}, 209 PCISlot{PCIAddr: PCIAddr{Dev: 0x19, Func: 0}, writeEmpty: true, additionalComment: "Intel Gigabit Ethernet"}, 210 PCISlot{PCIAddr: PCIAddr{Dev: 0x1a, Func: 0}, writeEmpty: !isULT, additionalComment: "USB2 EHCI #2"}, 211 PCISlot{PCIAddr: PCIAddr{Dev: 0x1b, Func: 0}, writeEmpty: true, additionalComment: "High Definition Audio"}, 212 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 0}, writeEmpty: true, additionalComment: "PCIe Port #1"}, 213 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 1}, writeEmpty: true, additionalComment: "PCIe Port #2"}, 214 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 2}, writeEmpty: true, additionalComment: "PCIe Port #3"}, 215 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 3}, writeEmpty: true, additionalComment: "PCIe Port #4"}, 216 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 4}, writeEmpty: true, additionalComment: "PCIe Port #5"}, 217 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 5}, writeEmpty: true, additionalComment: "PCIe Port #6"}, 218 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 6}, writeEmpty: !isULT, additionalComment: "PCIe Port #7"}, 219 PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 7}, writeEmpty: !isULT, additionalComment: "PCIe Port #8"}, 220 PCISlot{PCIAddr: PCIAddr{Dev: 0x1d, Func: 0}, writeEmpty: true, additionalComment: "USB2 EHCI #1"}, 221 PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 0}, writeEmpty: true, additionalComment: "LPC bridge"}, 222 PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 2}, writeEmpty: true, additionalComment: "SATA Controller (AHCI)"}, 223 PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 3}, writeEmpty: true, additionalComment: "SMBus"}, 224 PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 5}, writeEmpty: !isULT, additionalComment: "SATA Controller (Legacy)"}, 225 PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 6}, writeEmpty: true, additionalComment: "Thermal"}, 226 }, 227 } 228 229 if isULT { 230 cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x90]) 231 cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x94]) 232 cur.Registers["gpe0_en_3"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x98]) 233 cur.Registers["gpe0_en_4"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x9c]) 234 } else { 235 cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x28]) 236 cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x2c]) 237 } 238 239 b.node = &cur 240 241 PutPCIChip(addr, cur) 242 PutPCIDevParent(addr, "", "lpc") 243 244 DSDTIncludes = append(DSDTIncludes, DSDTInclude{ 245 File: "southbridge/intel/common/acpi/platform.asl", 246 }) 247 DSDTIncludes = append(DSDTIncludes, DSDTInclude{ 248 File: "southbridge/intel/lynxpoint/acpi/globalnvs.asl", 249 Comment: "global NVS and variables", 250 }) 251 DSDTIncludes = append(DSDTIncludes, DSDTInclude{ 252 File: "southbridge/intel/common/acpi/sleepstates.asl", 253 }) 254 DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{ 255 File: "southbridge/intel/lynxpoint/acpi/pch.asl", 256 }) 257 258 AddBootBlockFile("bootblock.c", "") 259 bb := Create(ctx, "bootblock.c") 260 defer bb.Close() 261 Add_gpl(bb) 262 bb.WriteString(`#include <southbridge/intel/lynxpoint/pch.h> 263 264/* FIXME: remove this if not needed */ 265void mainboard_config_superio(void) 266{ 267} 268`) 269 270 sb := Create(ctx, "romstage.c") 271 defer sb.Close() 272 Add_gpl(sb) 273 sb.WriteString(`#include <stdint.h> 274#include <northbridge/intel/haswell/haswell.h> 275#include <northbridge/intel/haswell/raminit.h> 276#include <southbridge/intel/lynxpoint/pch.h> 277 278void mainboard_config_rcba(void) 279{ 280} 281 282/* FIXME: called after romstage_common, remove it if not used */ 283void mb_late_romstage_setup(void) 284{ 285} 286 287void mb_get_spd_map(struct spd_info *spdi) 288{ 289 /* FIXME: check this */ 290 spdi->addresses[0] = 0x50; 291 spdi->addresses[1] = 0x51; 292 spdi->addresses[2] = 0x52; 293 spdi->addresses[3] = 0x53; 294} 295 296const struct usb2_port_config mainboard_usb2_ports[MAX_USB2_PORTS] = { 297 /* FIXME: Length and Location are computed from IOBP values, may be inaccurate */ 298 /* Length, Enable, OCn#, Location */ 299`) 300 301 pdo1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x64] 302 ocmap1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x74:0x78] 303 304 var pdo2 uint8 305 var ocmap2 []uint8 306 var nPorts uint 307 if isULT { 308 nPorts = 8 309 } else { 310 pdo2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x64] 311 ocmap2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x74:0x78] 312 nPorts = 14 313 } 314 315 xusb2pr := GetLE16(PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xd0:0xd4]) 316 317 for port := uint(0); port < nPorts; port++ { 318 var port_oc int = -1 319 var port_pos string 320 var port_disable uint8 321 322 if port < 8 { 323 port_disable = ((pdo1 >> port) & (uint8(xusb2pr>>port) ^ 1)) & 1 324 for oc := 0; oc < 4; oc++ { 325 if (ocmap1[oc] & (1 << port)) != 0 { 326 port_oc = oc 327 break 328 } 329 } 330 } else { 331 port_disable = ((pdo2 >> (port - 8)) & (uint8(xusb2pr>>port) ^ 1)) & 1 332 for oc := 0; oc < 4; oc++ { 333 if (ocmap2[oc] & (1 << (port - 8))) != 0 { 334 port_oc = oc + 4 335 break 336 } 337 } 338 } 339 340 /* get USB2 port length and location from IOBP */ 341 port_iobp := inteltool.IOBP[0xe5004100+uint32(port)*0x100] 342 loc_param := (port_iobp >> 8) & 7 343 txamp := (port_iobp >> 11) & 7 344 var port_length int 345 346 if isULT { 347 port_pos, port_length = GetLptLPEHCISetting(loc_param, txamp) 348 } else if b.variant == LYNX_POINT_MOBILE { 349 port_pos, port_length = GetLptMobileEHCISetting(loc_param, txamp) 350 } else { /* desktop or server */ 351 port_pos, port_length = GetLptDesktopEHCISetting(loc_param, txamp) 352 } 353 354 if port_disable == 1 { 355 port_pos = "USB_PORT_SKIP" 356 } 357 358 if port_oc == -1 { 359 fmt.Fprintf(sb, "\t{ 0x%04x, %d, USB_OC_PIN_SKIP, %s },\n", 360 port_length, (port_disable ^ 1), port_pos) 361 } else { 362 fmt.Fprintf(sb, "\t{ 0x%04x, %d, %d, %s },\n", 363 port_length, (port_disable ^ 1), port_oc, port_pos) 364 } 365 } 366 367 sb.WriteString(`}; 368 369const struct usb3_port_config mainboard_usb3_ports[MAX_USB3_PORTS] = { 370`) 371 372 xpdo := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xe8] 373 u3ocm := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xc8:0xd0] 374 375 if !isULT { 376 nPorts = 6 377 } else { 378 nPorts = 4 379 } 380 381 for port := uint(0); port < nPorts; port++ { 382 var port_oc int = -1 383 port_disable := (xpdo >> port) & 1 384 for oc := 0; oc < 8; oc++ { 385 if (u3ocm[oc] & (1 << port)) != 0 { 386 port_oc = oc 387 break 388 } 389 } 390 if port_oc == -1 { 391 fmt.Fprintf(sb, "\t{ %d, USB_OC_PIN_SKIP },\n", 392 (port_disable ^ 1)) 393 } else { 394 fmt.Fprintf(sb, "\t{ %d, %d },\n", 395 (port_disable ^ 1), port_oc) 396 } 397 } 398 399 sb.WriteString(`}; 400`) 401 402} 403 404func init() { 405 for _, id := range []uint16{ 406 0x8c41, 0x8c49, 0x8c4b, 0x8c4f, 407 } { 408 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_MOBILE}) 409 } 410 411 for _, id := range []uint16{ 412 0x8c42, 0x8c44, 0x8c46, 0x8c4a, 413 0x8c4c, 0x8c4e, 0x8c50, 0x8c5c, 414 } { 415 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_DESKTOP}) 416 } 417 418 for _, id := range []uint16{ 419 0x8c52, 0x8c54, 0x8c56, 420 } { 421 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_SERVER}) 422 } 423 424 for _, id := range []uint16{ 425 0x9c41, 0x9c43, 0x9c45, 426 } { 427 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_ULT}) 428 } 429 430 /* PCIe bridge */ 431 for _, id := range []uint16{ 432 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e, 433 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a, 434 } { 435 RegisterPCI(0x8086, id, GenericPCI{}) 436 } 437 438 /* SMBus controller */ 439 RegisterPCI(0x8086, 0x8c22, GenericPCI{MissingParent: "smbus"}) 440 RegisterPCI(0x8086, 0x9c22, GenericPCI{MissingParent: "smbus"}) 441 442 /* SATA */ 443 for _, id := range []uint16{ 444 0x8c00, 0x8c02, 0x8c04, 0x8c06, 0x8c08, 0x8c0e, 445 0x8c01, 0x8c03, 0x8c05, 0x8c07, 0x8c09, 0x8c0f, 446 0x9c03, 0x9c05, 0x9c07, 0x9c0f, 447 } { 448 RegisterPCI(0x8086, id, GenericPCI{}) 449 } 450 451 /* EHCI */ 452 for _, id := range []uint16{ 453 0x9c26, 0x8c26, 0x8c2d, 454 } { 455 RegisterPCI(0x8086, id, GenericPCI{}) 456 } 457 458 /* XHCI */ 459 RegisterPCI(0x8086, 0x8c31, GenericPCI{}) 460 RegisterPCI(0x8086, 0x9c31, GenericPCI{}) 461 462 /* ME and children */ 463 for _, id := range []uint16{ 464 0x8c3a, 0x8c3b, 0x8c3c, 0x8c3d, 465 0x9c3a, 0x9c3b, 0x9c3c, 0x9c3d, 466 } { 467 RegisterPCI(0x8086, id, GenericPCI{}) 468 } 469 470 /* Ethernet */ 471 RegisterPCI(0x8086, 0x8c33, GenericPCI{}) 472 473 /* Thermal */ 474 RegisterPCI(0x8086, 0x8c24, GenericPCI{}) 475 RegisterPCI(0x8086, 0x9c24, GenericPCI{}) 476 477 /* LAN Controller on LP PCH (if EEPROM has 0x0000/0xffff in DID) */ 478 RegisterPCI(0x8086, 0x155a, GenericPCI{}) 479 480 /* SDIO */ 481 RegisterPCI(0x8086, 0x9c35, GenericPCI{}) 482 483 /* Smart Sound Technology Controller */ 484 RegisterPCI(0x8086, 0x9c36, GenericPCI{}) 485 486 /* Serial I/O */ 487 for id := uint16(0x9c60); id <= 0x9c66; id++ { 488 RegisterPCI(0x8086, id, GenericPCI{}) 489 } 490} 491