blob: e49a7cbda53ff9be86eb56bd4fb1afb2ac2041be [file] [log] [blame]
Felix Held3f3eca92020-01-23 17:12:32 +01001/* SPDX-License-Identifier: GPL-2.0-or-later */
2/* This file is part of the coreboot project. */
Steven Sherkd9de6c42013-04-11 08:40:57 -06003
Piotr Kleinschmidt79d7f6b2019-10-07 11:59:11 +02004#include <console/console.h>
Steven Sherkd9de6c42013-04-11 08:40:57 -06005#include <device/pnp.h>
Piotr Kleinschmidt79d7f6b2019-10-07 11:59:11 +02006#include <device/device.h>
Nico Huber1c811282013-06-15 20:33:44 +02007#include <superio/conf_mode.h>
Elyes HAOUAS2329a252019-05-15 22:11:18 +02008
Steven Sherkd9de6c42013-04-11 08:40:57 -06009#include "nct5104d.h"
Dave Frodin29179f02014-06-12 16:28:21 -060010#include "chip.h"
Steven Sherkd9de6c42013-04-11 08:40:57 -060011
Kyösti Mälkki0430c692015-05-11 20:21:06 +030012static void set_irq_trigger_type(struct device *dev, bool trig_level)
Steven Sherkd9de6c42013-04-11 08:40:57 -060013{
Dave Frodin29179f02014-06-12 16:28:21 -060014 u8 reg10, reg11, reg26;
15
Dave Frodin29179f02014-06-12 16:28:21 -060016 //Before accessing CR10 OR CR11 Bit 4 in CR26 must be set to 1
17 reg26 = pnp_read_config(dev, GLOBAL_OPTION_CR26);
18 reg26 |= CR26_LOCK_REG;
19 pnp_write_config(dev, GLOBAL_OPTION_CR26, reg26);
20
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +010021 switch (dev->path.pnp.device) {
Dave Frodin29179f02014-06-12 16:28:21 -060022 //SP1 (UARTA) IRQ type selection (1:level,0:edge) is controlled by CR 10, bit 5
23 case NCT5104D_SP1:
24 reg10 = pnp_read_config(dev, IRQ_TYPE_SEL_CR10);
Kyösti Mälkki0430c692015-05-11 20:21:06 +030025 if (trig_level)
Dave Frodin29179f02014-06-12 16:28:21 -060026 reg10 |= (1 << 5);
27 else
28 reg10 &= ~(1 << 5);
29 pnp_write_config(dev, IRQ_TYPE_SEL_CR10, reg10);
30 break;
31 //SP2 (UARTB) IRQ type selection (1:level,0:edge) is controlled by CR 10, bit 4
32 case NCT5104D_SP2:
33 reg10 = pnp_read_config(dev, IRQ_TYPE_SEL_CR10);
Kyösti Mälkki0430c692015-05-11 20:21:06 +030034 if (trig_level)
Dave Frodin29179f02014-06-12 16:28:21 -060035 reg10 |= (1 << 4);
36 else
37 reg10 &= ~(1 << 4);
38 pnp_write_config(dev, IRQ_TYPE_SEL_CR10, reg10);
39 break;
40 //SP3 (UARTC) IRQ type selection (1:level,0:edge) is controlled by CR 11, bit 5
41 case NCT5104D_SP3:
42 reg11 = pnp_read_config(dev,IRQ_TYPE_SEL_CR11);
Kyösti Mälkki0430c692015-05-11 20:21:06 +030043 if (trig_level)
Dave Frodin29179f02014-06-12 16:28:21 -060044 reg11 |= (1 << 5);
45 else
46 reg11 &= ~(1 << 5);
47 pnp_write_config(dev, IRQ_TYPE_SEL_CR11, reg11);
48 break;
49 //SP4 (UARTD) IRQ type selection (1:level,0:edge) is controlled by CR 11, bit 4
50 case NCT5104D_SP4:
51 reg11 = pnp_read_config(dev,IRQ_TYPE_SEL_CR11);
Kyösti Mälkki0430c692015-05-11 20:21:06 +030052 if (trig_level)
Dave Frodin29179f02014-06-12 16:28:21 -060053 reg11 |= (1 << 4);
54 else
55 reg11 &= ~(1 << 4);
56 pnp_write_config(dev, IRQ_TYPE_SEL_CR11, reg11);
57 break;
58 default:
59 break;
60 }
61
62 //Clear access control register
63 reg26 = pnp_read_config(dev, GLOBAL_OPTION_CR26);
64 reg26 &= ~CR26_LOCK_REG;
65 pnp_write_config(dev, GLOBAL_OPTION_CR26, reg26);
Kyösti Mälkki0430c692015-05-11 20:21:06 +030066}
67
Kyösti Mälkkid22206a2015-05-11 20:58:18 +030068static void route_pins_to_uart(struct device *dev, bool to_uart)
69{
70 u8 reg;
71
72 reg = pnp_read_config(dev, 0x1c);
73
74 switch (dev->path.pnp.device) {
75 case NCT5104D_SP3:
76 case NCT5104D_GPIO0:
77 /* Route pins 33 - 40. */
78 if (to_uart)
79 reg |= (1 << 3);
80 else
81 reg &= ~(1 << 3);
82 break;
83 case NCT5104D_SP4:
84 case NCT5104D_GPIO1:
85 /* Route pins 41 - 48. */
86 if (to_uart)
87 reg |= (1 << 2);
88 else
89 reg &= ~(1 << 2);
90 break;
91 default:
92 break;
93 }
94
95 pnp_write_config(dev, 0x1c, reg);
96}
97
Piotr Kleinschmidtb52f7c72019-09-19 16:25:56 +020098static void reset_gpio_default_in(struct device *dev)
99{
100 pnp_set_logical_device(dev);
101
102 /* Soft reset GPIOs to default state: IN */
103 switch (dev->path.pnp.device) {
104 case NCT5104D_GPIO0:
105 pnp_write_config(dev, NCT5104D_GPIO0_IO, 0xFF);
106 break;
107 case NCT5104D_GPIO1:
108 pnp_write_config(dev, NCT5104D_GPIO1_IO, 0xFF);
109 break;
110 case NCT5104D_GPIO6:
111 pnp_write_config(dev, NCT5104D_GPIO6_IO, 0xFF);
112 break;
113 default:
114 break;
115 }
116}
117
118static void reset_gpio_default_od(struct device *dev)
119{
120 struct device *gpio0, *gpio1, *gpio6;
121
122 gpio0 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO0);
123 gpio1 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO1);
124 gpio6 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO6);
125
126 pnp_set_logical_device(dev);
127
128 /* Soft reset GPIOs to default state: Open-drain */
129 if (gpio0 && gpio0->enabled)
130 pnp_write_config(dev, NCT5104D_GPIO0_PP_OD, 0xFF);
131
132 if (gpio1 && gpio1->enabled)
133 pnp_write_config(dev, NCT5104D_GPIO1_PP_OD, 0xFF);
134
135 if (gpio6 && gpio6->enabled)
136 pnp_write_config(dev, NCT5104D_GPIO6_PP_OD, 0xFF);
137}
138
Piotr Kleinschmidt79d7f6b2019-10-07 11:59:11 +0200139static void disable_gpio_io_port(struct device *dev)
140{
141 struct device *gpio0, *gpio1, *gpio6;
142
143 /*
144 * Since UARTC and UARTD share pins with GPIO0 and GPIO1 and the
145 * GPIO/UART can be selected via Kconfig, check whether at least one of
146 * GPIOs is enabled and if yes keep the GPIO IO VLDN enabled. If no
147 * GPIOs are enabled, disable the VLDN in order to protect from invalid
148 * devicetree + Kconfig settings.
149 */
150 gpio0 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO0);
151 gpio1 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO1);
152 gpio6 = dev_find_slot_pnp(dev->path.pnp.port, NCT5104D_GPIO6);
153
154 if (!((gpio0 && gpio0->enabled) || (gpio1 && gpio1->enabled) ||
155 (gpio6 && gpio6->enabled))) {
156 dev->enabled = 0;
157 printk(BIOS_WARNING, "WARNING: GPIO IO port configured,"
158 " but no GPIO enabled. Disabling...");
159 }
160}
161
Kyösti Mälkki0430c692015-05-11 20:21:06 +0300162static void nct5104d_init(struct device *dev)
163{
164 struct superio_nuvoton_nct5104d_config *conf = dev->chip_info;
165
166 if (!dev->enabled)
167 return;
168
169 pnp_enter_conf_mode(dev);
170
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +0100171 switch (dev->path.pnp.device) {
Kyösti Mälkki0430c692015-05-11 20:21:06 +0300172 case NCT5104D_SP1:
173 case NCT5104D_SP2:
Kyösti Mälkkid22206a2015-05-11 20:58:18 +0300174 set_irq_trigger_type(dev, conf->irq_trigger_type != 0);
175 break;
Kyösti Mälkki0430c692015-05-11 20:21:06 +0300176 case NCT5104D_SP3:
177 case NCT5104D_SP4:
Kyösti Mälkkid22206a2015-05-11 20:58:18 +0300178 route_pins_to_uart(dev, true);
Kyösti Mälkki0430c692015-05-11 20:21:06 +0300179 set_irq_trigger_type(dev, conf->irq_trigger_type != 0);
180 break;
Kyösti Mälkkid22206a2015-05-11 20:58:18 +0300181 case NCT5104D_GPIO0:
182 case NCT5104D_GPIO1:
183 route_pins_to_uart(dev, false);
Piotr Kleinschmidtb52f7c72019-09-19 16:25:56 +0200184 reset_gpio_default_in(dev);
185 break;
186 case NCT5104D_GPIO6:
187 reset_gpio_default_in(dev);
188 break;
189 case NCT5104D_GPIO_PP_OD:
190 reset_gpio_default_od(dev);
Kyösti Mälkkid22206a2015-05-11 20:58:18 +0300191 break;
Piotr Kleinschmidt79d7f6b2019-10-07 11:59:11 +0200192 case NCT5104D_GPIO_IO:
193 disable_gpio_io_port(dev);
194 break;
Kyösti Mälkki0430c692015-05-11 20:21:06 +0300195 default:
196 break;
197 }
198
Dave Frodin29179f02014-06-12 16:28:21 -0600199 pnp_exit_conf_mode(dev);
Steven Sherkd9de6c42013-04-11 08:40:57 -0600200}
201
Steven Sherkd9de6c42013-04-11 08:40:57 -0600202static struct device_operations ops = {
203 .read_resources = pnp_read_resources,
Nico Huber0b2ee932013-06-15 19:58:35 +0200204 .set_resources = pnp_set_resources,
205 .enable_resources = pnp_enable_resources,
206 .enable = pnp_alt_enable,
Steven Sherkd9de6c42013-04-11 08:40:57 -0600207 .init = nct5104d_init,
Nico Huber1c811282013-06-15 20:33:44 +0200208 .ops_pnp_mode = &pnp_conf_mode_8787_aa,
Steven Sherkd9de6c42013-04-11 08:40:57 -0600209};
210
211static struct pnp_info pnp_dev_info[] = {
Felix Held9911d642018-07-06 20:55:53 +0200212 { NULL, NCT5104D_FDC, PNP_IO0 | PNP_IRQ0, 0x07f8, },
213 { NULL, NCT5104D_SP1, PNP_IO0 | PNP_IRQ0, 0x07f8, },
214 { NULL, NCT5104D_SP2, PNP_IO0 | PNP_IRQ0, 0x07f8, },
215 { NULL, NCT5104D_SP3, PNP_IO0 | PNP_IRQ0, 0x07f8, },
216 { NULL, NCT5104D_SP4, PNP_IO0 | PNP_IRQ0, 0x07f8, },
217 { NULL, NCT5104D_GPIO_WDT},
Felix Held9911d642018-07-06 20:55:53 +0200218 { NULL, NCT5104D_GPIO0},
219 { NULL, NCT5104D_GPIO1},
220 { NULL, NCT5104D_GPIO6},
Piotr Kleinschmidtb52f7c72019-09-19 16:25:56 +0200221 { NULL, NCT5104D_GPIO_PP_OD},
Piotr Kleinschmidt79d7f6b2019-10-07 11:59:11 +0200222 { NULL, NCT5104D_GPIO_IO, PNP_IO0, 0x07f8, },
Felix Held9911d642018-07-06 20:55:53 +0200223 { NULL, NCT5104D_PORT80},
Steven Sherkd9de6c42013-04-11 08:40:57 -0600224};
225
226static void enable_dev(struct device *dev)
227{
228 pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
229}
230
231struct chip_operations superio_nuvoton_nct5104d_ops = {
Paul Menzel87eacac2014-06-05 07:52:49 +0200232 CHIP_NAME("Nuvoton NCT5104D Super I/O")
Steven Sherkd9de6c42013-04-11 08:40:57 -0600233 .enable_dev = enable_dev,
234};