diff options
Diffstat (limited to 'util/autoport/lynxpoint_lp_gpio.go')
-rw-r--r-- | util/autoport/lynxpoint_lp_gpio.go | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/util/autoport/lynxpoint_lp_gpio.go b/util/autoport/lynxpoint_lp_gpio.go new file mode 100644 index 00000000..fbc1686a --- /dev/null +++ b/util/autoport/lynxpoint_lp_gpio.go @@ -0,0 +1,252 @@ +package main + +import ( + "fmt" + "os" + "strings" +) + +const ( + PIRQI = 0 + PIRQJ = 1 + PIRQK = 2 + PIRQL = 3 + PIRQM = 4 + PIRQN = 5 + PIRQO = 6 + PIRQP = 7 + PIRQQ = 8 + PIRQR = 9 + PIRQS = 10 + PIRQT = 11 + PIRQU = 12 + PIRQV = 13 + PIRQW = 14 + PIRQX = 15 +) + +/* from sb/intel/lynxpoint/lp_gpio.c */ +func lp_gpio_to_pirq(gpioNum uint16) int { + switch gpioNum { + case 8: + return PIRQI + case 9: + return PIRQJ + case 10: + return PIRQK + case 13: + return PIRQL + case 14: + return PIRQM + case 45: + return PIRQN + case 46: + return PIRQO + case 47: + return PIRQP + case 48: + return PIRQQ + case 49: + return PIRQR + case 50: + return PIRQS + case 51: + return PIRQT + case 52: + return PIRQU + case 53: + return PIRQV + case 54: + return PIRQW + case 55: + return PIRQX + default: + return -1 + } +} + +func conf0str(conf0 uint32) string { + if (conf0 & 1) == 0 { + return "GPIO_MODE_NATIVE" + } else { + s := []string{"GPIO_MODE_GPIO"} + var gpio_output bool + if ((conf0 >> 2) & 1) == 1 { + s = append(s, "GPIO_DIR_INPUT") + gpio_output = false + } else { + s = append(s, "GPIO_DIR_OUTPUT") + gpio_output = true + } + if ((conf0 >> 3) & 1) == 1 { + s = append(s, "GPIO_INVERT") + } + if ((conf0 >> 4) & 1) == 1 { + s = append(s, "GPIO_IRQ_LEVEL") + } + if gpio_output { + if ((conf0 >> 31) & 1) == 1 { + s = append(s, "GPO_LEVEL_HIGH") + } else { + s = append(s, "GPO_LEVEL_LOW") + } + } + return strings.Join(s, " | ") + } +} + +func lpgpio_preset(conf0 uint32, owner uint32, route uint32, irqen uint32, pirq uint32) string { + if conf0 == 0xd { /* 0b1101: MODE_GPIO | INPUT | INVERT */ + if owner == 0 { /* OWNER_ACPI */ + if irqen == 0 && pirq == 0 { + if route == 0 { /* SCI */ + return "GPIO_ACPI_SCI" + } else { + return "GPIO_ACPI_SMI" + } + } + return "" + } else { /* OWNER_GPIO */ + if route == 0 && irqen == 0 && pirq != 0 { + return "GPIO_INPUT_INVERT" + } + return "" + } + } + + if conf0 == 0x5 && owner == 1 { /* 0b101: MODE_GPIO | INPUT, OWNER_GPIO */ + if route == 0 && irqen == 0 { + if pirq == 1 { + return "GPIO_PIRQ" + } else { + return "GPIO_INPUT" + } + } + return "" + } + + if owner == 1 && irqen == 1 { + if route == 0 && pirq == 0 { + if conf0 == 0x5 { /* 0b00101 */ + return "GPIO_IRQ_EDGE" + } + if conf0 == 0x15 { /* 0b10101 */ + return "GPIO_IRQ_LEVEL" + } + } + return "" + } + return "" +} + +func gpio_str(conf0 uint32, conf1 uint32, owner uint32, route uint32, irqen uint32, reset uint32, blink uint32, pirq uint32) string { + s := []string{} + s = append(s, fmt.Sprintf(".conf0 = %s", conf0str(conf0))) + if conf1 != 0 { + s = append(s, fmt.Sprintf(".conf1 = 0x%x", conf1)) + } + if owner != 0 { + s = append(s, ".owner = GPIO_OWNER_GPIO") + } + if route != 0 { + s = append(s, ".route = GPIO_ROUTE_SMI") + } + if irqen != 0 { + s = append(s, ".irqen = GPIO_IRQ_ENABLE") + } + if reset != 0 { + s = append(s, ".reset = GPIO_RESET_RSMRST") + } + if blink != 0 { + s = append(s, ".blink = GPO_BLINK") + } + if pirq != 0 { + s = append(s, ".pirq = GPIO_PIRQ_APIC_ROUTE") + } + return strings.Join(s, ", ") +} + +/* start addresses of GPIO registers */ +const ( + GPIO_OWN = 0x0 + GPIPIRQ2IOXAPIC = 0x10 + GPO_BLINK = 0x18 + GPI_ROUT = 0x30 + GP_RST_SEL = 0x60 + GPI_IE = 0x90 + GPnCONFIGA = 0x100 + GPnCONFIGB = 0x104 +) + +func PrintLPGPIO(gpio *os.File, inteltool InteltoolData) { + for gpioNum := uint16(0); gpioNum <= 94; gpioNum++ { + if gpioNum < 10 { + fmt.Fprintf(gpio, "\t[%d] = ", gpioNum) + } else { + fmt.Fprintf(gpio, "\t[%d] = ", gpioNum) + } + conf0 := inteltool.GPIO[GPnCONFIGA+gpioNum*8] + conf1 := inteltool.GPIO[GPnCONFIGB+gpioNum*8] + set := gpioNum / 32 + bit := gpioNum % 32 + /* owner only effective in GPIO mode */ + owner := (inteltool.GPIO[GPIO_OWN+set*4] >> bit) & 1 + route := (inteltool.GPIO[GPI_ROUT+set*4] >> bit) & 1 + irqen := (inteltool.GPIO[GPI_IE+set*4] >> bit) & 1 + reset := (inteltool.GPIO[GP_RST_SEL+set*4] >> bit) & 1 + var blink, pirq uint32 + /* blink only effective in GPIO output mode */ + if set == 0 { + blink = (inteltool.GPIO[GPO_BLINK] >> bit) & 1 + } else { + blink = 0 + } + irqset := lp_gpio_to_pirq(gpioNum) + if irqset >= 0 { + pirq = (inteltool.GPIO[GPIPIRQ2IOXAPIC] >> uint(irqset)) & 1 + } else { + pirq = 0 + } + + if (conf0 & 1) == 0 { + fmt.Fprintf(gpio, "LP_GPIO_NATIVE,\n") + } else if (conf0 & 4) == 0 { + /* configured as output */ + if ((conf0 >> 31) & 1) == 0 { + fmt.Fprintf(gpio, "LP_GPIO_OUT_LOW,\n") + } else { + fmt.Fprintf(gpio, "LP_GPIO_OUT_HIGH,\n") + } + } else if (conf1 & 4) != 0 { + /* configured as input and sensing disabled */ + fmt.Fprintf(gpio, "LP_GPIO_UNUSED,\n") + } else { + is_preset := false + if conf1 == 0 && reset == 0 && blink == 0 { + preset := lpgpio_preset(conf0, owner, route, irqen, pirq) + if preset != "" { + fmt.Fprintf(gpio, "LP_%s,\n", preset) + is_preset = true + } + } + if !is_preset { + fmt.Fprintf(gpio, "{ %s },\n", gpio_str(conf0, conf1, owner, route, irqen, reset, blink, pirq)) + } + } + } +} + +func Lynxpoint_LP_GPIO(ctx Context, inteltool InteltoolData) { + gpio := Create(ctx, "gpio.c") + defer gpio.Close() + + AddROMStageFile("gpio.c", "") + + Add_gpl(gpio) + gpio.WriteString(`#include <southbridge/intel/lynxpoint/lp_gpio.h> + +const struct pch_lp_gpio_map mainboard_lp_gpio_map[] = { +`) + PrintLPGPIO(gpio, inteltool) + gpio.WriteString("\tLP_GPIO_END\n};\n") +} |