Contiki 3.x
gpio.c
1 /*
2  * Copyright (C) 2015-2016, Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "gpio.h"
32 
33 #include <stdbool.h>
34 #include "helpers.h"
35 #include "paging.h"
36 #include "shared-isr.h"
37 #include "syscalls.h"
38 
39 /* GPIO Controler Registers */
40 #define SWPORTA_DR 0x00
41 #define SWPORTA_DDR 0x04
42 #define INTEN 0x30
43 #define INTMASK 0x34
44 #define INTTYPE_LEVEL 0x38
45 #define INT_POLARITY 0x3c
46 #define INTSTATUS 0x40
47 #define RAW_INTSTATUS 0x44
48 #define DEBOUNCE 0x48
49 #define PORTA_EOI 0x4c
50 #define EXT_PORTA 0x50
51 #define LS_SYNC 0x60
52 
53 #define PINS 8
54 
55 #define GPIO_IRQ 9
56 
57 #define HIGHEST_REG LS_SYNC
58 
59 #if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
60 #define MMIO_SZ MIN_PAGE_SIZE
61 #else
62 #define MMIO_SZ (HIGHEST_REG + 4)
63 #endif
64 
65 PROT_DOMAINS_ALLOC(pci_driver_t, drv);
66 
67 struct gpio_internal_data {
68  quarkX1000_gpio_callback callback;
69 };
70 
71 static struct gpio_internal_data data;
72 
73 void quarkX1000_gpio_mmin(uint32_t offset, uint32_t *res);
74 SYSCALLS_DEFINE_SINGLETON(quarkX1000_gpio_mmin, drv,
75  uint32_t offset, uint32_t *res)
76 {
77  uint32_t *loc_res;
78 
79  PROT_DOMAINS_VALIDATE_PTR(loc_res, res, sizeof(*res));
80  if(HIGHEST_REG < offset) {
81  halt();
82  }
83 
84  prot_domains_enable_mmio();
85  PCI_MMIO_READL(drv, *loc_res, offset);
86  prot_domains_disable_mmio();
87 }
88 
89 static inline uint32_t
90 read(uint32_t offset)
91 {
92  uint32_t res;
93  quarkX1000_gpio_mmin(offset, &res);
94  return res;
95 }
96 
97 void quarkX1000_gpio_mmout(uint32_t offset, uint32_t val);
98 SYSCALLS_DEFINE_SINGLETON(quarkX1000_gpio_mmout, drv,
99  uint32_t offset, uint32_t val)
100 {
101  if(HIGHEST_REG < offset) {
102  halt();
103  }
104 
105  prot_domains_enable_mmio();
106  PCI_MMIO_WRITEL(drv, offset, val);
107  prot_domains_disable_mmio();
108 }
109 
110 static inline void
111 write(uint32_t offset, uint32_t val)
112 {
113  quarkX1000_gpio_mmout(offset, val);
114 }
115 
116 /* value must be 0x0 or 0x1 */
117 static void
118 set_bit(uint32_t offset, uint32_t bit, uint32_t value)
119 {
120  uint32_t reg;
121 
122  reg = read(offset);
123 
124  reg &= ~BIT(bit);
125  reg |= value << bit;
126 
127  write(offset, reg);
128 }
129 
130 static bool
131 gpio_isr(void)
132 {
133  uint32_t int_status;
134 
135  int_status = read(INTSTATUS);
136 
137  if(int_status == 0) {
138  return false;
139  }
140 
141  if (data.callback)
142  data.callback(int_status);
143 
144  write(PORTA_EOI, -1);
145 
146  return true;
147 }
148 
149 static void
150 gpio_interrupt_config(uint8_t pin, int flags)
151 {
152  /* set as input */
153  set_bit(SWPORTA_DDR, pin, 0);
154 
155  /* set interrupt enabled */
156  set_bit(INTEN, pin, 1);
157 
158  /* unmask interrupt */
159  set_bit(INTMASK, pin, 0);
160 
161  /* set active high/low */
162  set_bit(INT_POLARITY, pin, !!(flags & QUARKX1000_GPIO_ACTIVE_HIGH));
163 
164  /* set level/edge */
165  set_bit(INTTYPE_LEVEL, pin, !!(flags & QUARKX1000_GPIO_EDGE));
166 
167  /* set debounce */
168  set_bit(DEBOUNCE, pin, !!(flags & QUARKX1000_GPIO_DEBOUNCE));
169 
170  /* set clock synchronous */
171  set_bit(LS_SYNC, 0, !!(flags & QUARKX1000_GPIO_CLOCK_SYNC));
172 }
173 
174 int
175 quarkX1000_gpio_config(uint8_t pin, int flags)
176 {
177  if (((flags & QUARKX1000_GPIO_IN) && (flags & QUARKX1000_GPIO_OUT)) ||
178  ((flags & QUARKX1000_GPIO_INT) && (flags & QUARKX1000_GPIO_OUT))) {
179  return -1;
180  }
181 
182  if (flags & QUARKX1000_GPIO_INT) {
183  gpio_interrupt_config(pin, flags);
184  } else {
185  /* set direction */
186  set_bit(SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT));
187 
188  /* set interrupt disabled */
189  set_bit(INTEN, pin, 0);
190  }
191 
192  return 0;
193 }
194 
195 int
196 quarkX1000_gpio_config_port(int flags)
197 {
198  uint8_t i;
199 
200  for (i = 0; i < PINS; i++) {
201  if (quarkX1000_gpio_config(i, flags) < 0) {
202  return -1;
203  }
204  }
205 
206  return 0;
207 }
208 
209 int
210 quarkX1000_gpio_read(uint8_t pin, uint8_t *value)
211 {
212  uint32_t value32 = read(EXT_PORTA);
213  *value = !!(value32 & BIT(pin));
214 
215  return 0;
216 }
217 
218 int
219 quarkX1000_gpio_write(uint8_t pin, uint8_t value)
220 {
221  set_bit(SWPORTA_DR, pin, !!value);
222  return 0;
223 }
224 
225 int
226 quarkX1000_gpio_read_port(uint8_t *value)
227 {
228  uint32_t value32 = read(EXT_PORTA);
229  *value = value32 & ~0xFFFFFF00;
230 
231  return 0;
232 }
233 
234 int
235 quarkX1000_gpio_write_port(uint8_t value)
236 {
237  write(SWPORTA_DR, value);
238  return 0;
239 }
240 
241 int
242 quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback)
243 {
244  data.callback = callback;
245  return 0;
246 }
247 
248 void
249 quarkX1000_gpio_clock_enable(void)
250 {
251  set_bit(LS_SYNC, 0, 1);
252 }
253 
254 void
255 quarkX1000_gpio_clock_disable(void)
256 {
257  set_bit(LS_SYNC, 0, 0);
258 }
259 
260 DEFINE_SHARED_IRQ(GPIO_IRQ, IRQAGENT3, INTC, PIRQC, gpio_isr);
261 
262 int
263 quarkX1000_gpio_init(void)
264 {
265  pci_config_addr_t pci_addr;
266 
267  pci_addr.raw = 0;
268  pci_addr.bus = 0;
269  pci_addr.dev = 21;
270  pci_addr.func = 2;
271  pci_addr.reg_off = PCI_CONFIG_REG_BAR1;
272 
273  pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN);
274 
275  PROT_DOMAINS_INIT_ID(drv);
276  pci_init(&drv, pci_addr, MMIO_SZ, 0, 0);
277  SYSCALLS_INIT(quarkX1000_gpio_mmin);
278  SYSCALLS_AUTHZ(quarkX1000_gpio_mmin, drv);
279  SYSCALLS_INIT(quarkX1000_gpio_mmout);
280  SYSCALLS_AUTHZ(quarkX1000_gpio_mmout, drv);
281 
282  data.callback = 0;
283 
284  quarkX1000_gpio_clock_enable();
285 
286  /* clear registers */
287  write(INTEN, 0);
288  write(INTMASK, 0);
289  write(PORTA_EOI, 0);
290 
291  return 0;
292 }
uint32_t func
Function number.
Definition: pci.h:89
#define BIT(x)
Useful to reference a single bit of a byte.
PCI configuration address.
Definition: pci.h:85
uint32_t dev
Device number.
Definition: pci.h:90
static uint8_t int_status(void)
Check whether a data or wake on motion interrupt has occurred.
uint32_t bus
Bus number.
Definition: pci.h:91
Data associated with each protection domain that is owned by clients of that domain and used to ident...
Definition: prot-domains.h:247
uint32_t reg_off
Register/offset number.
Definition: pci.h:88