blob: 2b07de2735bc30d006c7a17075ea5c124a60c8d7 [file] [log] [blame]
Duncan Laurie045f1532012-12-17 11:29:10 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Google Inc. 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.
Duncan Laurie045f1532012-12-17 11:29:10 -080014 */
15
16#include <stdint.h>
17#include <string.h>
18#include <arch/io.h>
Duncan Laurie045f1532012-12-17 11:29:10 -080019#include <device/device.h>
20#include <device/pci.h>
Duncan Laurie045f1532012-12-17 11:29:10 -080021
22#include "pch.h"
23#include "lp_gpio.h"
24
25static u16 get_gpio_base(void)
26{
Shawn Nematbakhshccb12fb2013-07-03 17:55:38 -070027#if defined(__PRE_RAM__) || defined(__SMM__)
Duncan Laurie045f1532012-12-17 11:29:10 -080028 return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc;
29#else
30 return pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
31 GPIO_BASE) & 0xfffc;
32#endif
33}
34
Duncan Lauriec5939992013-05-24 11:06:49 -070035
36/*
37 * This function will return a number that indicates which PIRQ
38 * this GPIO maps to. If this is not a PIRQ capable GPIO then
39 * it will return -1. The GPIO to PIRQ mapping is not linear.
40 */
41static int lp_gpio_to_pirq(int gpio)
42{
43 switch (gpio) {
44 case 8: return 0; /* PIRQI */
45 case 9: return 1; /* PIRQJ */
46 case 10: return 2; /* PIRQK */
47 case 13: return 3; /* PIRQL */
48 case 14: return 4; /* PIRQM */
49 case 45: return 5; /* PIRQN */
50 case 46: return 6; /* PIRQO */
51 case 47: return 7; /* PIRQP */
52 case 48: return 8; /* PIRQQ */
53 case 49: return 9; /* PIRQR */
54 case 50: return 10; /* PIRQS */
55 case 51: return 11; /* PIRQT */
56 case 52: return 12; /* PIRQU */
57 case 53: return 13; /* PIRQV */
58 case 54: return 14; /* PIRQW */
59 case 55: return 15; /* PIRQX */
60 default: return -1;
61 };
62}
63
Duncan Laurie045f1532012-12-17 11:29:10 -080064void setup_pch_lp_gpios(const struct pch_lp_gpio_map map[])
65{
66 u16 gpio_base = get_gpio_base();
67 const struct pch_lp_gpio_map *config;
68 u32 owner[3] = {0};
69 u32 route[3] = {0};
70 u32 irqen[3] = {0};
71 u32 reset[3] = {0};
72 u32 blink = 0;
Duncan Lauriec5939992013-05-24 11:06:49 -070073 u16 pirq2apic = 0;
Duncan Laurie55ad9722013-04-23 13:43:23 -070074 int set, bit, gpio = 0;
Duncan Laurie045f1532012-12-17 11:29:10 -080075
Duncan Laurie55ad9722013-04-23 13:43:23 -070076 for (config = map; config->conf0 != GPIO_LIST_END; config++, gpio++) {
77 if (gpio > MAX_GPIO_NUMBER)
78 break;
Duncan Laurie045f1532012-12-17 11:29:10 -080079
80 /* Setup Configuration registers 1 and 2 */
Duncan Laurie55ad9722013-04-23 13:43:23 -070081 outl(config->conf0, gpio_base + GPIO_CONFIG0(gpio));
82 outl(config->conf1, gpio_base + GPIO_CONFIG1(gpio));
Duncan Laurie045f1532012-12-17 11:29:10 -080083
84 /* Determine set and bit based on GPIO number */
Duncan Laurie55ad9722013-04-23 13:43:23 -070085 set = gpio >> 5;
86 bit = gpio % 32;
Duncan Laurie045f1532012-12-17 11:29:10 -080087
88 /* Apply settings to set specific bits */
89 owner[set] |= config->owner << bit;
90 route[set] |= config->route << bit;
91 irqen[set] |= config->irqen << bit;
92 reset[set] |= config->reset << bit;
93
94 if (set == 0)
95 blink |= config->blink << bit;
Duncan Lauriec5939992013-05-24 11:06:49 -070096
97 /* PIRQ to IO-APIC map */
98 if (config->pirq == GPIO_PIRQ_APIC_ROUTE) {
99 set = lp_gpio_to_pirq(gpio);
100 if (set >= 0)
101 pirq2apic |= 1 << set;
102 }
Duncan Laurie045f1532012-12-17 11:29:10 -0800103 }
104
105 for (set = 0; set <= 2; set++) {
106 outl(owner[set], gpio_base + GPIO_OWNER(set));
107 outl(route[set], gpio_base + GPIO_ROUTE(set));
108 outl(irqen[set], gpio_base + GPIO_IRQ_IE(set));
109 outl(reset[set], gpio_base + GPIO_RESET(set));
110 }
111
112 outl(blink, gpio_base + GPIO_BLINK);
Duncan Lauriec5939992013-05-24 11:06:49 -0700113 outl(pirq2apic, gpio_base + GPIO_PIRQ_APIC_EN);
Duncan Laurie045f1532012-12-17 11:29:10 -0800114}
115
116int get_gpio(int gpio_num)
117{
118 u16 gpio_base = get_gpio_base();
119
Duncan Laurie55ad9722013-04-23 13:43:23 -0700120 if (gpio_num > MAX_GPIO_NUMBER)
Duncan Laurie045f1532012-12-17 11:29:10 -0800121 return 0;
122
123 return !!(inl(gpio_base + GPIO_CONFIG0(gpio_num)) & GPI_LEVEL);
124}
125
126/*
127 * get a number comprised of multiple GPIO values. gpio_num_array points to
128 * the array of gpio pin numbers to scan, terminated by -1.
129 */
130unsigned get_gpios(const int *gpio_num_array)
131{
132 int gpio;
133 unsigned bitmask = 1;
134 unsigned vector = 0;
135
136 while (bitmask &&
137 ((gpio = *gpio_num_array++) != -1)) {
138 if (get_gpio(gpio))
139 vector |= bitmask;
140 bitmask <<= 1;
141 }
142 return vector;
143}
Duncan Laurie15de7cb2013-04-23 13:44:37 -0700144
145void set_gpio(int gpio_num, int value)
146{
147 u16 gpio_base = get_gpio_base();
148 u32 conf0;
149
150 if (gpio_num > MAX_GPIO_NUMBER)
151 return;
152
153 conf0 = inl(gpio_base + GPIO_CONFIG0(gpio_num));
154 conf0 &= ~GPO_LEVEL_MASK;
155 conf0 |= value << GPO_LEVEL_SHIFT;
156 outl(conf0, gpio_base + GPIO_CONFIG0(gpio_num));
157}
Aaron Durbin550bcca2013-06-21 13:37:23 -0500158
159int gpio_is_native(int gpio_num)
160{
161 u16 gpio_base = get_gpio_base();
162
163 return !(inl(gpio_base + GPIO_CONFIG0(gpio_num)) & 1);
164}