blob: 7c8cfe814443098bccd0ae0472c2dd9e36e5b536 [file] [log] [blame]
Patrick Rudolph59de6c92015-12-26 08:33:16 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011-2016 The Chromium OS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <stdint.h>
17#include <string.h>
18#include <arch/io.h>
19#include <device/device.h>
20#include <device/pci.h>
Patrick Rudolph2a7be5b2018-07-27 09:49:14 +020021#include <arch/early_variables.h>
Patrick Rudolph59de6c92015-12-26 08:33:16 +010022
23#include "gpio.h"
24
25#define MAX_GPIO_NUMBER 75 /* zero based */
26
Patrick Rudolph2a7be5b2018-07-27 09:49:14 +020027/* LPC GPIO Base Address Register */
28#define GPIO_BASE 0x48
29
30/* PCI Configuration Space (D31:F0): LPC */
31#if defined(__SIMPLE_DEVICE__)
32#define PCH_LPC_DEV PCI_DEV(0, 0x1f, 0)
33#else
34#define PCH_LPC_DEV dev_find_slot(0, PCI_DEVFN(0x1f, 0))
35#endif
36
Patrick Rudolph59de6c92015-12-26 08:33:16 +010037static u16 get_gpio_base(void)
38{
Patrick Rudolph2a7be5b2018-07-27 09:49:14 +020039#if defined(__SMM__)
40 /* Don't assume GPIO_BASE is still the same */
41 return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffe;
Patrick Rudolph59de6c92015-12-26 08:33:16 +010042#else
Patrick Rudolph2a7be5b2018-07-27 09:49:14 +020043 static u16 gpiobase CAR_GLOBAL;
44
45 if (gpiobase)
46 return gpiobase;
47
48 gpiobase = pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffe;
49
50 return gpiobase;
Patrick Rudolph59de6c92015-12-26 08:33:16 +010051#endif
52}
53
54void setup_pch_gpios(const struct pch_gpio_map *gpio)
55{
56 u16 gpiobase = get_gpio_base();
57
Patrick Rudolphdf369af2017-01-02 18:41:37 +010058 /* The order of these calls does matter on ICH9M and prior.
59 * The level has to be set on pins configured as gpio,
60 * but on newer platforms we want to change the level first
61 * to make sure there are no glitches on the lines !
62 * Write the gpio level twice to satisfy both requirements.
63 */
64
Patrick Rudolph59de6c92015-12-26 08:33:16 +010065 /* GPIO Set 1 */
66 if (gpio->set1.level)
67 outl(*((u32 *)gpio->set1.level), gpiobase + GP_LVL);
68 if (gpio->set1.mode)
69 outl(*((u32 *)gpio->set1.mode), gpiobase + GPIO_USE_SEL);
70 if (gpio->set1.direction)
71 outl(*((u32 *)gpio->set1.direction), gpiobase + GP_IO_SEL);
Patrick Rudolphdf369af2017-01-02 18:41:37 +010072 if (gpio->set1.level)
73 outl(*((u32 *)gpio->set1.level), gpiobase + GP_LVL);
Patrick Rudolph59de6c92015-12-26 08:33:16 +010074 if (gpio->set1.reset)
75 outl(*((u32 *)gpio->set1.reset), gpiobase + GP_RST_SEL1);
76 if (gpio->set1.invert)
77 outl(*((u32 *)gpio->set1.invert), gpiobase + GPI_INV);
78 if (gpio->set1.blink)
79 outl(*((u32 *)gpio->set1.blink), gpiobase + GPO_BLINK);
80
81 /* GPIO Set 2 */
82 if (gpio->set2.level)
83 outl(*((u32 *)gpio->set2.level), gpiobase + GP_LVL2);
84 if (gpio->set2.mode)
85 outl(*((u32 *)gpio->set2.mode), gpiobase + GPIO_USE_SEL2);
86 if (gpio->set2.direction)
87 outl(*((u32 *)gpio->set2.direction), gpiobase + GP_IO_SEL2);
Patrick Rudolphdf369af2017-01-02 18:41:37 +010088 if (gpio->set2.level)
89 outl(*((u32 *)gpio->set2.level), gpiobase + GP_LVL2);
Patrick Rudolph59de6c92015-12-26 08:33:16 +010090 if (gpio->set2.reset)
91 outl(*((u32 *)gpio->set2.reset), gpiobase + GP_RST_SEL2);
92
93 /* GPIO Set 3 */
94 if (gpio->set3.level)
95 outl(*((u32 *)gpio->set3.level), gpiobase + GP_LVL3);
96 if (gpio->set3.mode)
97 outl(*((u32 *)gpio->set3.mode), gpiobase + GPIO_USE_SEL3);
98 if (gpio->set3.direction)
99 outl(*((u32 *)gpio->set3.direction), gpiobase + GP_IO_SEL3);
Patrick Rudolphdf369af2017-01-02 18:41:37 +0100100 if (gpio->set3.level)
101 outl(*((u32 *)gpio->set3.level), gpiobase + GP_LVL3);
Patrick Rudolph59de6c92015-12-26 08:33:16 +0100102 if (gpio->set3.reset)
103 outl(*((u32 *)gpio->set3.reset), gpiobase + GP_RST_SEL3);
104}
105
106/*
107 * return current gpio level.
108 */
109int get_gpio(int gpio_num)
110{
111 static const int gpio_reg_offsets[] = {GP_LVL, GP_LVL2, GP_LVL3};
112 u16 gpio_base = get_gpio_base();
113 int index, bit;
114
115 if (gpio_num > MAX_GPIO_NUMBER)
116 return 0; /* Just ignore wrong gpio numbers. */
117
118 index = gpio_num / 32;
119 bit = gpio_num % 32;
120
121 return (inl(gpio_base + gpio_reg_offsets[index]) >> bit) & 1;
122}
123
124/*
125 * get a number comprised of multiple GPIO values. gpio_num_array points to
126 * the array of gpio pin numbers to scan, terminated by -1.
127 */
128unsigned get_gpios(const int *gpio_num_array)
129{
130 int gpio;
131 unsigned bitmask = 1;
132 unsigned vector = 0;
133
134 while (bitmask &&
135 ((gpio = *gpio_num_array++) != -1)) {
136 if (get_gpio(gpio))
137 vector |= bitmask;
138 bitmask <<= 1;
139 }
140 return vector;
141}
142
143/*
144 * set gpio output to level.
145 */
146void set_gpio(int gpio_num, int value)
147{
148 static const int gpio_reg_offsets[] = {
149 GP_LVL, GP_LVL2, GP_LVL3
150 };
151 u16 gpio_base = get_gpio_base();
152 int index, bit;
153 u32 config;
154
155 if (gpio_num > MAX_GPIO_NUMBER)
156 return; /* Just ignore wrong gpio numbers. */
157
158 index = gpio_num / 32;
159 bit = gpio_num % 32;
160
161 config = inl(gpio_base + gpio_reg_offsets[index]);
162 config &= ~(1 << bit);
Patrick Rudolph0e4f83e2017-07-22 12:16:11 +0200163 if (value != 0)
164 config |= (1 << bit);
Patrick Rudolph59de6c92015-12-26 08:33:16 +0100165 outl(config, gpio_base + gpio_reg_offsets[index]);
166}
167
168int gpio_is_native(int gpio_num)
169{
170 static const int gpio_reg_offsets[] = {
171 GPIO_USE_SEL, GPIO_USE_SEL2, GPIO_USE_SEL3
172 };
173 u16 gpio_base = get_gpio_base();
174 int index, bit;
175 u32 config;
176
177 if (gpio_num > MAX_GPIO_NUMBER)
178 return 0; /* Just ignore wrong gpio numbers. */
179
180 index = gpio_num / 32;
181 bit = gpio_num % 32;
182
183 config = inl(gpio_base + gpio_reg_offsets[index]);
184 return !(config & (1 << bit));
185}