xref: /aosp_15_r20/external/coreboot/src/southbridge/intel/lynxpoint/lp_gpio.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdint.h>
4 #include <arch/io.h>
5 #include <device/pci_ops.h>
6 #include <device/device.h>
7 #include <device/pci.h>
8 
9 #include "pch.h"
10 #include "lp_gpio.h"
11 
get_gpio_base(void)12 static u16 get_gpio_base(void)
13 {
14 #ifdef __SIMPLE_DEVICE__
15 	return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc;
16 #else
17 	return pci_read_config16(pcidev_on_root(0x1f, 0),
18 				 GPIO_BASE) & 0xfffc;
19 #endif
20 }
21 
22 /*
23  * This function will return a number that indicates which PIRQ
24  * this GPIO maps to.  If this is not a PIRQ capable GPIO then
25  * it will return -1.  The GPIO to PIRQ mapping is not linear.
26  */
lp_gpio_to_pirq(int gpio)27 static int lp_gpio_to_pirq(int gpio)
28 {
29 	switch (gpio) {
30 	case 8:  return 0;	/* PIRQI */
31 	case 9:  return 1;	/* PIRQJ */
32 	case 10: return 2;	/* PIRQK */
33 	case 13: return 3;	/* PIRQL */
34 	case 14: return 4;	/* PIRQM */
35 	case 45: return 5;	/* PIRQN */
36 	case 46: return 6;	/* PIRQO */
37 	case 47: return 7;	/* PIRQP */
38 	case 48: return 8;	/* PIRQQ */
39 	case 49: return 9;	/* PIRQR */
40 	case 50: return 10;	/* PIRQS */
41 	case 51: return 11;	/* PIRQT */
42 	case 52: return 12;	/* PIRQU */
43 	case 53: return 13;	/* PIRQV */
44 	case 54: return 14;	/* PIRQW */
45 	case 55: return 15;	/* PIRQX */
46 	default: return -1;
47 	};
48 }
49 
setup_pch_lp_gpios(const struct pch_lp_gpio_map map[])50 void setup_pch_lp_gpios(const struct pch_lp_gpio_map map[])
51 {
52 	u16 gpio_base = get_gpio_base();
53 	const struct pch_lp_gpio_map *config;
54 	u32 owner[3] = {0};
55 	u32 route[3] = {0};
56 	u32 irqen[3] = {0};
57 	u32 reset[3] = {0};
58 	u32 blink = 0;
59 	u16 pirq2apic = 0;
60 	int set, bit, gpio = 0;
61 
62 	for (config = map; config->conf0 != GPIO_LIST_END; config++, gpio++) {
63 		if (gpio > MAX_GPIO_NUMBER)
64 			break;
65 
66 		/* Setup Configuration registers 1 and 2 */
67 		outl(config->conf0, gpio_base + GPIO_CONFIG0(gpio));
68 		outl(config->conf1, gpio_base + GPIO_CONFIG1(gpio));
69 
70 		/* Determine set and bit based on GPIO number */
71 		set = gpio >> 5;
72 		bit = gpio % 32;
73 
74 		/* Apply settings to set specific bits */
75 		owner[set] |= config->owner << bit;
76 		route[set] |= config->route << bit;
77 		irqen[set] |= config->irqen << bit;
78 		reset[set] |= config->reset << bit;
79 
80 		if (set == 0)
81 			blink |= config->blink << bit;
82 
83 		/* PIRQ to IO-APIC map */
84 		if (config->pirq == GPIO_PIRQ_APIC_ROUTE) {
85 			set = lp_gpio_to_pirq(gpio);
86 			if (set >= 0)
87 				pirq2apic |= 1 << set;
88 		}
89 	}
90 
91 	for (set = 0; set <= 2; set++) {
92 		outl(owner[set], gpio_base + GPIO_OWNER(set));
93 		outl(route[set], gpio_base + GPIO_ROUTE(set));
94 		outl(irqen[set], gpio_base + GPIO_IRQ_IE(set));
95 		outl(reset[set], gpio_base + GPIO_RESET(set));
96 	}
97 
98 	outl(blink, gpio_base + GPIO_BLINK);
99 	outl(pirq2apic, gpio_base + GPIO_PIRQ_APIC_EN);
100 }
101 
get_gpio(int gpio_num)102 int get_gpio(int gpio_num)
103 {
104 	u16 gpio_base = get_gpio_base();
105 
106 	if (gpio_num > MAX_GPIO_NUMBER)
107 		return 0;
108 
109 	return !!(inl(gpio_base + GPIO_CONFIG0(gpio_num)) & GPI_LEVEL);
110 }
111 
112 /*
113  * get a number comprised of multiple GPIO values. gpio_num_array points to
114  * the array of gpio pin numbers to scan, terminated by -1.
115  */
get_gpios(const int * gpio_num_array)116 unsigned int get_gpios(const int *gpio_num_array)
117 {
118 	int gpio;
119 	unsigned int bitmask = 1;
120 	unsigned int vector = 0;
121 
122 	while (bitmask &&
123 	       ((gpio = *gpio_num_array++) != -1)) {
124 		if (get_gpio(gpio))
125 			vector |= bitmask;
126 		bitmask <<= 1;
127 	}
128 	return vector;
129 }
130 
set_gpio(int gpio_num,int value)131 void set_gpio(int gpio_num, int value)
132 {
133 	u16 gpio_base = get_gpio_base();
134 	u32 conf0;
135 
136 	if (gpio_num > MAX_GPIO_NUMBER)
137 		return;
138 
139 	conf0 = inl(gpio_base + GPIO_CONFIG0(gpio_num));
140 	conf0 &= ~GPO_LEVEL_MASK;
141 	conf0 |= value << GPO_LEVEL_SHIFT;
142 	outl(conf0, gpio_base + GPIO_CONFIG0(gpio_num));
143 }
144 
gpio_is_native(int gpio_num)145 int gpio_is_native(int gpio_num)
146 {
147 	u16 gpio_base = get_gpio_base();
148 
149 	return !(inl(gpio_base + GPIO_CONFIG0(gpio_num)) & 1);
150 }
151