blob: 448ee8bd68886164dde36a8b3aeed46f994ddbe3 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Duncan Laurie045f1532012-12-17 11:29:10 -08002
3#include <stdint.h>
Duncan Laurie045f1532012-12-17 11:29:10 -08004#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Duncan Laurie045f1532012-12-17 11:29:10 -08006#include <device/device.h>
7#include <device/pci.h>
Duncan Laurie045f1532012-12-17 11:29:10 -08008
9#include "pch.h"
10#include "lp_gpio.h"
11
12static u16 get_gpio_base(void)
13{
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030014#ifdef __SIMPLE_DEVICE__
Duncan Laurie045f1532012-12-17 11:29:10 -080015 return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc;
16#else
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030017 return pci_read_config16(pcidev_on_root(0x1f, 0),
Duncan Laurie045f1532012-12-17 11:29:10 -080018 GPIO_BASE) & 0xfffc;
19#endif
20}
21
Duncan Lauriec5939992013-05-24 11:06:49 -070022/*
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 */
27static 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
Duncan Laurie045f1532012-12-17 11:29:10 -080050void 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;
Duncan Lauriec5939992013-05-24 11:06:49 -070059 u16 pirq2apic = 0;
Duncan Laurie55ad9722013-04-23 13:43:23 -070060 int set, bit, gpio = 0;
Duncan Laurie045f1532012-12-17 11:29:10 -080061
Duncan Laurie55ad9722013-04-23 13:43:23 -070062 for (config = map; config->conf0 != GPIO_LIST_END; config++, gpio++) {
63 if (gpio > MAX_GPIO_NUMBER)
64 break;
Duncan Laurie045f1532012-12-17 11:29:10 -080065
66 /* Setup Configuration registers 1 and 2 */
Duncan Laurie55ad9722013-04-23 13:43:23 -070067 outl(config->conf0, gpio_base + GPIO_CONFIG0(gpio));
68 outl(config->conf1, gpio_base + GPIO_CONFIG1(gpio));
Duncan Laurie045f1532012-12-17 11:29:10 -080069
70 /* Determine set and bit based on GPIO number */
Duncan Laurie55ad9722013-04-23 13:43:23 -070071 set = gpio >> 5;
72 bit = gpio % 32;
Duncan Laurie045f1532012-12-17 11:29:10 -080073
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;
Duncan Lauriec5939992013-05-24 11:06:49 -070082
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 }
Duncan Laurie045f1532012-12-17 11:29:10 -080089 }
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);
Duncan Lauriec5939992013-05-24 11:06:49 -070099 outl(pirq2apic, gpio_base + GPIO_PIRQ_APIC_EN);
Duncan Laurie045f1532012-12-17 11:29:10 -0800100}
101
102int get_gpio(int gpio_num)
103{
104 u16 gpio_base = get_gpio_base();
105
Duncan Laurie55ad9722013-04-23 13:43:23 -0700106 if (gpio_num > MAX_GPIO_NUMBER)
Duncan Laurie045f1532012-12-17 11:29:10 -0800107 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 */
Martin Rothff744bf2019-10-23 21:46:03 -0600116unsigned int get_gpios(const int *gpio_num_array)
Duncan Laurie045f1532012-12-17 11:29:10 -0800117{
118 int gpio;
Martin Rothff744bf2019-10-23 21:46:03 -0600119 unsigned int bitmask = 1;
120 unsigned int vector = 0;
Duncan Laurie045f1532012-12-17 11:29:10 -0800121
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}
Duncan Laurie15de7cb2013-04-23 13:44:37 -0700130
131void 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}
Aaron Durbin550bcca2013-06-21 13:37:23 -0500144
145int 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}