lynxpoint.go
1 package main 2 3 import "fmt" 4 5 type LPVariant int 6 7 const ( 8 LYNX_POINT_MOBILE LPVariant = iota 9 LYNX_POINT_DESKTOP 10 LYNX_POINT_SERVER 11 LYNX_POINT_ULT 12 ) 13 14 type lynxpoint struct { 15 variant LPVariant 16 node *DevTreeNode 17 } 18 19 func 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 38 func (b lynxpoint) GetGPIOHeader() string { 39 return "southbridge/intel/lynxpoint/pch.h" 40 } 41 42 func (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 48 func (b lynxpoint) EncodeGPE(in int) int { 49 return in + 0x10 50 } 51 52 func (b lynxpoint) DecodeGPE(in int) int { 53 return in - 0x10 54 } 55 56 func (b lynxpoint) NeedRouteGPIOManually() { 57 b.node.Comment += ", FIXME: set gpiX_routing for EC support" 58 } 59 60 func 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 80 func 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 106 func 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 132 func (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_SPDX(bb, C, GPL2_only) 262 bb.WriteString(`#include <southbridge/intel/lynxpoint/pch.h> 263 264 /* FIXME: remove this if not needed */ 265 void mainboard_config_superio(void) 266 { 267 } 268 `) 269 270 sb := Create(ctx, "romstage.c") 271 defer sb.Close() 272 Add_SPDX(sb, C, GPL2_only) 273 sb.WriteString(`#include <stdint.h> 274 #include <northbridge/intel/haswell/haswell.h> 275 #include <southbridge/intel/lynxpoint/pch.h> 276 277 void mainboard_config_rcba(void) 278 { 279 } 280 281 /* FIXME: called after romstage_common, remove it if not used */ 282 void mb_late_romstage_setup(void) 283 { 284 } 285 286 const struct usb2_port_config mainboard_usb2_ports[MAX_USB2_PORTS] = { 287 /* FIXME: Length and Location are computed from IOBP values, may be inaccurate */ 288 /* Length, Enable, OCn#, Location */ 289 `) 290 291 pdo1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x64] 292 ocmap1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x74:0x78] 293 294 var pdo2 uint8 295 var ocmap2 []uint8 296 var nPorts uint 297 if isULT { 298 nPorts = 8 299 } else { 300 pdo2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x64] 301 ocmap2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x74:0x78] 302 nPorts = 14 303 } 304 305 xusb2pr := GetLE16(PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xd0:0xd4]) 306 307 for port := uint(0); port < nPorts; port++ { 308 var port_oc int = -1 309 var port_pos string 310 var port_disable uint8 311 312 if port < 8 { 313 port_disable = ((pdo1 >> port) & (uint8(xusb2pr>>port) ^ 1)) & 1 314 for oc := 0; oc < 4; oc++ { 315 if (ocmap1[oc] & (1 << port)) != 0 { 316 port_oc = oc 317 break 318 } 319 } 320 } else { 321 port_disable = ((pdo2 >> (port - 8)) & (uint8(xusb2pr>>port) ^ 1)) & 1 322 for oc := 0; oc < 4; oc++ { 323 if (ocmap2[oc] & (1 << (port - 8))) != 0 { 324 port_oc = oc + 4 325 break 326 } 327 } 328 } 329 330 /* get USB2 port length and location from IOBP */ 331 port_iobp := inteltool.IOBP[0xe5004100+uint32(port)*0x100] 332 loc_param := (port_iobp >> 8) & 7 333 txamp := (port_iobp >> 11) & 7 334 var port_length int 335 336 if isULT { 337 port_pos, port_length = GetLptLPEHCISetting(loc_param, txamp) 338 } else if b.variant == LYNX_POINT_MOBILE { 339 port_pos, port_length = GetLptMobileEHCISetting(loc_param, txamp) 340 } else { /* desktop or server */ 341 port_pos, port_length = GetLptDesktopEHCISetting(loc_param, txamp) 342 } 343 344 if port_disable == 1 { 345 port_pos = "USB_PORT_SKIP" 346 } 347 348 if port_oc == -1 { 349 fmt.Fprintf(sb, "\t{ 0x%04x, %d, USB_OC_PIN_SKIP, %s },\n", 350 port_length, (port_disable ^ 1), port_pos) 351 } else { 352 fmt.Fprintf(sb, "\t{ 0x%04x, %d, %d, %s },\n", 353 port_length, (port_disable ^ 1), port_oc, port_pos) 354 } 355 } 356 357 sb.WriteString(`}; 358 359 const struct usb3_port_config mainboard_usb3_ports[MAX_USB3_PORTS] = { 360 `) 361 362 xpdo := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xe8] 363 u3ocm := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xc8:0xd0] 364 365 if !isULT { 366 nPorts = 6 367 } else { 368 nPorts = 4 369 } 370 371 for port := uint(0); port < nPorts; port++ { 372 var port_oc int = -1 373 port_disable := (xpdo >> port) & 1 374 for oc := 0; oc < 8; oc++ { 375 if (u3ocm[oc] & (1 << port)) != 0 { 376 port_oc = oc 377 break 378 } 379 } 380 if port_oc == -1 { 381 fmt.Fprintf(sb, "\t{ %d, USB_OC_PIN_SKIP },\n", 382 (port_disable ^ 1)) 383 } else { 384 fmt.Fprintf(sb, "\t{ %d, %d },\n", 385 (port_disable ^ 1), port_oc) 386 } 387 } 388 389 sb.WriteString(`}; 390 `) 391 392 } 393 394 func init() { 395 for _, id := range []uint16{ 396 0x8c41, 0x8c49, 0x8c4b, 0x8c4f, 397 } { 398 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_MOBILE}) 399 } 400 401 for _, id := range []uint16{ 402 0x8c42, 0x8c44, 0x8c46, 0x8c4a, 403 0x8c4c, 0x8c4e, 0x8c50, 0x8c5c, 404 } { 405 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_DESKTOP}) 406 } 407 408 for _, id := range []uint16{ 409 0x8c52, 0x8c54, 0x8c56, 410 } { 411 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_SERVER}) 412 } 413 414 for _, id := range []uint16{ 415 0x9c41, 0x9c43, 0x9c45, 416 } { 417 RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_ULT}) 418 } 419 420 /* PCIe bridge */ 421 for _, id := range []uint16{ 422 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e, 423 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a, 424 } { 425 RegisterPCI(0x8086, id, GenericPCI{}) 426 } 427 428 /* SMBus controller */ 429 RegisterPCI(0x8086, 0x8c22, GenericPCI{MissingParent: "smbus"}) 430 RegisterPCI(0x8086, 0x9c22, GenericPCI{MissingParent: "smbus"}) 431 432 /* SATA */ 433 for _, id := range []uint16{ 434 0x8c00, 0x8c02, 0x8c04, 0x8c06, 0x8c08, 0x8c0e, 435 0x8c01, 0x8c03, 0x8c05, 0x8c07, 0x8c09, 0x8c0f, 436 0x9c03, 0x9c05, 0x9c07, 0x9c0f, 437 } { 438 RegisterPCI(0x8086, id, GenericPCI{}) 439 } 440 441 /* EHCI */ 442 for _, id := range []uint16{ 443 0x9c26, 0x8c26, 0x8c2d, 444 } { 445 RegisterPCI(0x8086, id, GenericPCI{}) 446 } 447 448 /* XHCI */ 449 RegisterPCI(0x8086, 0x8c31, GenericPCI{}) 450 RegisterPCI(0x8086, 0x9c31, GenericPCI{}) 451 452 /* ME and children */ 453 for _, id := range []uint16{ 454 0x8c3a, 0x8c3b, 0x8c3c, 0x8c3d, 455 0x9c3a, 0x9c3b, 0x9c3c, 0x9c3d, 456 } { 457 RegisterPCI(0x8086, id, GenericPCI{}) 458 } 459 460 /* Ethernet */ 461 RegisterPCI(0x8086, 0x8c33, GenericPCI{}) 462 463 /* Thermal */ 464 RegisterPCI(0x8086, 0x8c24, GenericPCI{}) 465 RegisterPCI(0x8086, 0x9c24, GenericPCI{}) 466 467 /* LAN Controller on LP PCH (if EEPROM has 0x0000/0xffff in DID) */ 468 RegisterPCI(0x8086, 0x155a, GenericPCI{}) 469 470 /* SDIO */ 471 RegisterPCI(0x8086, 0x9c35, GenericPCI{}) 472 473 /* Smart Sound Technology Controller */ 474 RegisterPCI(0x8086, 0x9c36, GenericPCI{}) 475 476 /* Serial I/O */ 477 for id := uint16(0x9c60); id <= 0x9c66; id++ { 478 RegisterPCI(0x8086, id, GenericPCI{}) 479 } 480 }