xref: /aosp_15_r20/external/coreboot/util/autoport/lynxpoint_lp_gpio.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1package main
2
3import (
4	"fmt"
5	"os"
6	"strings"
7)
8
9const (
10	PIRQI = 0
11	PIRQJ = 1
12	PIRQK = 2
13	PIRQL = 3
14	PIRQM = 4
15	PIRQN = 5
16	PIRQO = 6
17	PIRQP = 7
18	PIRQQ = 8
19	PIRQR = 9
20	PIRQS = 10
21	PIRQT = 11
22	PIRQU = 12
23	PIRQV = 13
24	PIRQW = 14
25	PIRQX = 15
26)
27
28/* from sb/intel/lynxpoint/lp_gpio.c */
29func lp_gpio_to_pirq(gpioNum uint16) int {
30	var pirqmap = map[uint16] int {
31		8: PIRQI,
32		9: PIRQJ,
33		10: PIRQK,
34		13: PIRQL,
35		14: PIRQM,
36		45: PIRQN,
37		46: PIRQO,
38		47: PIRQP,
39		48: PIRQQ,
40		49: PIRQR,
41		50: PIRQS,
42		51: PIRQT,
43		52: PIRQU,
44		53: PIRQV,
45		54: PIRQW,
46		55: PIRQX,
47	}
48	pirq, valid := pirqmap[gpioNum]
49	if (valid) {
50		return pirq
51	} else {
52		return -1
53	}
54}
55
56func conf0str(conf0 uint32) string {
57	if (conf0 & 1) == 0 {
58		return "GPIO_MODE_NATIVE"
59	} else {
60		s := []string{"GPIO_MODE_GPIO"}
61		var gpio_output bool
62		if ((conf0 >> 2) & 1) == 1 {
63			s = append(s, "GPIO_DIR_INPUT")
64			gpio_output = false
65		} else {
66			s = append(s, "GPIO_DIR_OUTPUT")
67			gpio_output = true
68		}
69		if ((conf0 >> 3) & 1) == 1 {
70			s = append(s, "GPIO_INVERT")
71		}
72		if ((conf0 >> 4) & 1) == 1 {
73			s = append(s, "GPIO_IRQ_LEVEL")
74		}
75		if gpio_output {
76			if ((conf0 >> 31) & 1) == 1 {
77				s = append(s, "GPO_LEVEL_HIGH")
78			} else {
79				s = append(s, "GPO_LEVEL_LOW")
80			}
81		}
82		return strings.Join(s, " | ")
83	}
84}
85
86func lpgpio_preset(conf0 uint32, owner uint32, route uint32, irqen uint32, pirq uint32) string {
87	if conf0 == 0xd { /* 0b1101: MODE_GPIO | INPUT | INVERT */
88		if owner == 0 { /* OWNER_ACPI */
89			if irqen == 0 && pirq == 0 {
90				if route == 0 { /* SCI */
91					return "GPIO_ACPI_SCI"
92				} else {
93					return "GPIO_ACPI_SMI"
94				}
95			}
96			return ""
97		} else { /* OWNER_GPIO */
98			if route == 0 && irqen == 0 && pirq != 0 {
99				return "GPIO_INPUT_INVERT"
100			}
101			return ""
102		}
103	}
104
105	if conf0 == 0x5 && owner == 1 { /* 0b101: MODE_GPIO | INPUT, OWNER_GPIO */
106		if route == 0 && irqen == 0 {
107			if pirq == 1 {
108				return "GPIO_PIRQ"
109			} else {
110				return "GPIO_INPUT"
111			}
112		}
113		return ""
114	}
115
116	if owner == 1 && irqen == 1 {
117		if route == 0 && pirq == 0 {
118			if conf0 == 0x5 { /* 0b00101 */
119				return "GPIO_IRQ_EDGE"
120			}
121			if conf0 == 0x15 { /* 0b10101 */
122				return "GPIO_IRQ_LEVEL"
123			}
124		}
125		return ""
126	}
127	return ""
128}
129
130func gpio_str(conf0 uint32, conf1 uint32, owner uint32, route uint32, irqen uint32, reset uint32, blink uint32, pirq uint32) string {
131	s := []string{}
132	s = append(s, fmt.Sprintf(".conf0 = %s", conf0str(conf0)))
133	if conf1 != 0 {
134		s = append(s, fmt.Sprintf(".conf1 = 0x%x", conf1))
135	}
136	if owner != 0 {
137		s = append(s, ".owner = GPIO_OWNER_GPIO")
138	}
139	if route != 0 {
140		s = append(s, ".route = GPIO_ROUTE_SMI")
141	}
142	if irqen != 0 {
143		s = append(s, ".irqen = GPIO_IRQ_ENABLE")
144	}
145	if reset != 0 {
146		s = append(s, ".reset = GPIO_RESET_RSMRST")
147	}
148	if blink != 0 {
149		s = append(s, ".blink = GPO_BLINK")
150	}
151	if pirq != 0 {
152		s = append(s, ".pirq = GPIO_PIRQ_APIC_ROUTE")
153	}
154	return strings.Join(s, ", ")
155}
156
157/* start addresses of GPIO registers */
158const (
159	GPIO_OWN        = 0x0
160	GPIPIRQ2IOXAPIC = 0x10
161	GPO_BLINK       = 0x18
162	GPI_ROUT        = 0x30
163	GP_RST_SEL      = 0x60
164	GPI_IE          = 0x90
165	GPnCONFIGA      = 0x100
166	GPnCONFIGB      = 0x104
167)
168
169func PrintLPGPIO(gpio *os.File, inteltool InteltoolData) {
170	for gpioNum := uint16(0); gpioNum <= 94; gpioNum++ {
171		if gpioNum < 10 {
172			fmt.Fprintf(gpio, "\t[%d]  = ", gpioNum)
173		} else {
174			fmt.Fprintf(gpio, "\t[%d] = ", gpioNum)
175		}
176		conf0 := inteltool.GPIO[GPnCONFIGA+gpioNum*8]
177		conf1 := inteltool.GPIO[GPnCONFIGB+gpioNum*8]
178		set := gpioNum / 32
179		bit := gpioNum % 32
180		/* owner only effective in GPIO mode */
181		owner := (inteltool.GPIO[GPIO_OWN+set*4] >> bit) & 1
182		route := (inteltool.GPIO[GPI_ROUT+set*4] >> bit) & 1
183		irqen := (inteltool.GPIO[GPI_IE+set*4] >> bit) & 1
184		reset := (inteltool.GPIO[GP_RST_SEL+set*4] >> bit) & 1
185		var blink, pirq uint32
186		/* blink only effective in GPIO output mode */
187		if set == 0 {
188			blink = (inteltool.GPIO[GPO_BLINK] >> bit) & 1
189		} else {
190			blink = 0
191		}
192		irqset := lp_gpio_to_pirq(gpioNum)
193		if irqset >= 0 {
194			pirq = (inteltool.GPIO[GPIPIRQ2IOXAPIC] >> uint(irqset)) & 1
195		} else {
196			pirq = 0
197		}
198
199		if (conf0 & 1) == 0 {
200			fmt.Fprintf(gpio, "LP_GPIO_NATIVE,\n")
201		} else if (conf0 & 4) == 0 {
202			/* configured as output */
203			if ((conf0 >> 31) & 1) == 0 {
204				fmt.Fprintf(gpio, "LP_GPIO_OUT_LOW,\n")
205			} else {
206				fmt.Fprintf(gpio, "LP_GPIO_OUT_HIGH,\n")
207			}
208		} else if (conf1 & 4) != 0 {
209			/* configured as input and sensing disabled */
210			fmt.Fprintf(gpio, "LP_GPIO_UNUSED,\n")
211		} else {
212			is_preset := false
213			if conf1 == 0 && reset == 0 && blink == 0 {
214				preset := lpgpio_preset(conf0, owner, route, irqen, pirq)
215				if preset != "" {
216					fmt.Fprintf(gpio, "LP_%s,\n", preset)
217					is_preset = true
218				}
219			}
220			if !is_preset {
221				fmt.Fprintf(gpio, "{ %s },\n", gpio_str(conf0, conf1, owner, route, irqen, reset, blink, pirq))
222			}
223		}
224	}
225}
226
227func Lynxpoint_LP_GPIO(ctx Context, inteltool InteltoolData) {
228	gpio := Create(ctx, "gpio.c")
229	defer gpio.Close()
230
231	AddROMStageFile("gpio.c", "")
232
233	Add_gpl(gpio)
234	gpio.WriteString(`#include <southbridge/intel/lynxpoint/lp_gpio.h>
235
236const struct pch_lp_gpio_map mainboard_lp_gpio_map[] = {
237`)
238	PrintLPGPIO(gpio, inteltool)
239	gpio.WriteString("\tLP_GPIO_END\n};\n")
240}
241