blob: 4e29a572674f17681c07292abd23702881f7cdf8 [file] [log] [blame]
Angel Pons5f249e62020-04-04 18:51:01 +02001/* SPDX-License-Identifier: GPL-2.0-only */
David Hendricks8cbd5692017-12-01 20:49:48 -08002
3#include <console/console.h>
4#include <soc/gpio.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02005#include <device/mmio.h>
David Hendricks8cbd5692017-12-01 20:49:48 -08006#include <endian.h>
7#include <soc/addressmap.h>
8
9union gpio_const {
10 u64 u;
11 struct {
12 u64 gpios:8; /** Number of GPIOs implemented */
13 u64 pp:8; /** Number of PP vectors */
14 u64:48; /* Reserved */
15 } s;
16};
17union bit_cfg {
18 u64 u;
19 struct {
20 u64 tx_oe : 1; /* Output Enable */
21 u64 xor : 1; /* Invert */
22 u64 int_en : 1; /* Interrupt Enable */
23 u64 int_type : 1; /* Type of Interrupt */
24 u64 filt_cnt : 4; /* Glitch filter counter */
25 u64 filt_sel : 4; /* Glitch filter select */
26 u64 tx_od : 1; /* Set Output to Open Drain */
Elyes HAOUAScb103462019-01-03 09:38:52 +010027 u64 : 3;
David Hendricks8cbd5692017-12-01 20:49:48 -080028 u64 pin_sel : 10; /* Select type of pin */
Elyes HAOUAScb103462019-01-03 09:38:52 +010029 u64 : 38;
David Hendricks8cbd5692017-12-01 20:49:48 -080030 } s;
31};
32
33struct cavium_gpio {
34 u64 rx_dat;
35 u64 tx_set;
36 u64 tx_clr;
37 u64 multicast;
38 u64 ocla_exten_trg;
39 u64 strap;
40 u64 reserved[12];
41 union gpio_const gpio_const; /* Offset 90 */
42 u64 reserved2[109];
43 union bit_cfg bit_cfg[48]; /* Offset 400 */
44};
45
46/* Base address of GPIO BAR */
47static const void *gpio_get_baseaddr(void)
48{
49 return (const void *)GPIO_PF_BAR0;
50}
51
52/* Number of GPIO pins. Usually 48. */
53gpio_t gpio_pin_count(void)
54{
55 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
56 union gpio_const gpio_const;
57
58 gpio_const.u = read64(&regs->gpio_const.u);
59
60 if (gpio_const.s.gpios > 64)
61 return 64; // FIXME: Add support for more than 64 GPIOs
62 return gpio_const.s.gpios;
63}
64
65/* Set GPIO to software control and direction INPUT */
66void gpio_input(gpio_t gpio)
67{
68 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
69 union bit_cfg bit_cfg;
70
71 if (gpio >= gpio_pin_count())
72 return;
73
74 printk(BIOS_SPEW, "GPIO(%u): direction input\n", gpio);
75
76 bit_cfg.u = read64(&regs->bit_cfg[gpio]);
77 bit_cfg.s.pin_sel = 0;
78 bit_cfg.s.tx_oe = 0;
79 write64(&regs->bit_cfg[gpio], bit_cfg.u);
80}
81
82/* Set GPIO of direction OUTPUT to level */
83void gpio_set(gpio_t gpio, int value)
84{
85 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
86
87 if (gpio >= gpio_pin_count())
88 return;
89
90 printk(BIOS_SPEW, "GPIO(%u): level: %u\n", gpio, !!value);
91
92 if (value)
Patrick Rudolph517c4c12018-07-12 11:56:31 +020093 write64(&regs->tx_set, 1ULL << gpio);
David Hendricks8cbd5692017-12-01 20:49:48 -080094 else
Patrick Rudolph517c4c12018-07-12 11:56:31 +020095 write64(&regs->tx_clr, 1ULL << gpio);
David Hendricks8cbd5692017-12-01 20:49:48 -080096}
97
98/* Set GPIO direction to OUTPUT with level */
99void gpio_output(gpio_t gpio, int value)
100{
101 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
102 union bit_cfg bit_cfg;
103
104 if (gpio >= gpio_pin_count())
105 return;
106
107 gpio_set(gpio, value);
108
109 printk(BIOS_SPEW, "GPIO(%u): direction output with level: %u\n", gpio,
110 !!value);
111
112 bit_cfg.u = read64(&regs->bit_cfg[gpio]);
113 bit_cfg.s.pin_sel = 0;
114 bit_cfg.s.tx_oe = 1;
115 write64(&regs->bit_cfg[gpio], bit_cfg.u);
116}
117
118/* Set GPIO invert flag, that affects INPUT and OUTPUT */
119void gpio_invert(gpio_t gpio, int value)
120{
121 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
122 union bit_cfg bit_cfg;
123
124 if (gpio >= gpio_pin_count())
125 return;
126
127 bit_cfg.u = read64(&regs->bit_cfg[gpio]);
128 bit_cfg.s.xor = !!value;
129 write64(&regs->bit_cfg[gpio], bit_cfg.u);
130
131 printk(BIOS_SPEW, "GPIO(%u): invert: %s\n", gpio, value ? "ON" : "OFF");
132}
133
134/* Read GPIO level with direction set to INPUT */
135int gpio_get(gpio_t gpio)
136{
137 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
138
139 if (gpio >= gpio_pin_count())
140 return 0;
141
142 const u64 reg = read64(&regs->rx_dat);
Patrick Rudolph517c4c12018-07-12 11:56:31 +0200143 printk(BIOS_SPEW, "GPIO(%u): input: %u\n", gpio,
144 !!(reg & (1ULL << gpio)));
David Hendricks8cbd5692017-12-01 20:49:48 -0800145
Patrick Rudolph517c4c12018-07-12 11:56:31 +0200146 return !!(reg & (1ULL << gpio));
David Hendricks8cbd5692017-12-01 20:49:48 -0800147}
148
149/* Read GPIO STRAP level sampled at cold boot */
150int gpio_strap_value(gpio_t gpio)
151{
152 struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr();
153
154 if (gpio >= gpio_pin_count())
155 return 0;
156
157 const u64 reg = read64(&regs->strap);
Patrick Rudolph517c4c12018-07-12 11:56:31 +0200158 printk(BIOS_SPEW, "GPIO(%u): strap: %u\n", gpio,
159 !!(reg & (1ULL << gpio)));
David Hendricks8cbd5692017-12-01 20:49:48 -0800160
Patrick Rudolph517c4c12018-07-12 11:56:31 +0200161 return !!(reg & (1ULL << gpio));
David Hendricks8cbd5692017-12-01 20:49:48 -0800162}
163
164/* FIXME: Parse devicetree ? */
165void gpio_init(void)
166{
167 const size_t pin_count = gpio_pin_count();
168
169 printk(BIOS_DEBUG, "GPIO: base address: %p, pin count: %zd\n",
170 gpio_get_baseaddr(), pin_count);
171
172 if (!pin_count)
173 return;
174}
175
176void gpio_input_pulldown(gpio_t gpio)
177{
178}
179
180void gpio_input_pullup(gpio_t gpio)
181{
182}