View | Details | Raw Unified | Return to bug 282738 | Differences between
and this patch

Collapse All | Expand All

(-)b/sys/dev/nctgpio/nctgpio.c (-14 / +210 lines)
Lines 1-245 Link Here
1
/*-
1
/*-
2
 * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com>
2
 * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com>
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
12
 *    documentation and/or other materials provided with the distribution.
13
 *
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
24
 * SUCH DAMAGE.
25
 *
25
 *
26
 */
26
 */
27
27
28
/*
28
/*
29
 * Nuvoton GPIO driver.
29
 * Nuvoton GPIO driver.
30
 */
30
 */
31
31
32
#include <sys/cdefs.h>
32
#include <sys/cdefs.h>
33
33
34
#include <sys/param.h>
34
#include <sys/param.h>
35
#include <sys/kernel.h>
35
#include <sys/kernel.h>
36
#include <sys/systm.h>
36
#include <sys/systm.h>
37
#include <sys/bus.h>
37
#include <sys/bus.h>
38
#include <sys/eventhandler.h>
38
#include <sys/eventhandler.h>
39
#include <sys/lock.h>
39
#include <sys/lock.h>
40
40
41
#include <sys/module.h>
41
#include <sys/module.h>
42
#include <sys/gpio.h>
42
#include <sys/gpio.h>
43
43
44
#include <machine/bus.h>
44
#include <machine/bus.h>
45
45
46
#include <dev/gpio/gpiobusvar.h>
46
#include <dev/gpio/gpiobusvar.h>
47
#include <dev/superio/superio.h>
47
#include <dev/superio/superio.h>
48
48
49
#include "gpio_if.h"
49
#include "gpio_if.h"
50
50
51
#define NCT_PPOD_LDN 0xf /* LDN used to select Push-Pull/Open-Drain */
51
#define NCT_PPOD_LDN 0xf /* LDN used to select Push-Pull/Open-Drain */
52
52
53
/* Direct access through GPIO register table */
53
/* Direct access through GPIO register table */
54
#define	NCT_IO_GSR			0 /* Group Select */
54
#define	NCT_IO_GSR			0 /* Group Select */
55
#define	NCT_IO_IOR			1 /* I/O */
55
#define	NCT_IO_IOR			1 /* I/O */
56
#define	NCT_IO_DAT			2 /* Data */
56
#define	NCT_IO_DAT			2 /* Data */
57
#define	NCT_IO_INV			3 /* Inversion */
57
#define	NCT_IO_INV			3 /* Inversion */
58
#define	NCT_IO_DST          4 /* Status */
58
#define	NCT_IO_DST          4 /* Status */
59
59
60
#define NCT_MAX_GROUP   9
60
#define NCT_MAX_GROUP   9
61
#define NCT_MAX_PIN     75
61
#define NCT_MAX_PIN     75
62
62
63
#define NCT_PIN_IS_VALID(_sc, _p)   ((_p) < (_sc)->npins)
63
#define NCT_PIN_IS_VALID(_sc, _p)   ((_p) < (_sc)->npins)
64
#define NCT_PIN_GROUP(_sc, _p)      ((_sc)->pinmap[(_p)].group)
64
#define NCT_PIN_GROUP(_sc, _p)      ((_sc)->pinmap[(_p)].group)
65
#define NCT_PIN_GRPNUM(_sc, _p)     ((_sc)->pinmap[(_p)].grpnum)
65
#define NCT_PIN_GRPNUM(_sc, _p)     ((_sc)->pinmap[(_p)].grpnum)
66
#define NCT_PIN_BIT(_sc, _p)        ((_sc)->pinmap[(_p)].bit)
66
#define NCT_PIN_BIT(_sc, _p)        ((_sc)->pinmap[(_p)].bit)
67
#define NCT_PIN_BITMASK(_p)         (1 << ((_p) & 7))
67
#define NCT_PIN_BITMASK(_p)         (1 << ((_p) & 7))
68
68
69
#define NCT_GPIO_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
69
#define NCT_GPIO_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
70
	GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
70
	GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
71
	GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
71
	GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
72
72
73
#define NCT_PREFER_INDIRECT_CHANNEL 2
73
#define NCT_PREFER_INDIRECT_CHANNEL 2
74
#define NCT_NO_ENABLE               4
74
75
75
#define NCT_VERBOSE_PRINTF(dev, ...)            \
76
#define NCT_VERBOSE_PRINTF(dev, ...)            \
76
	do {                                        \
77
	do {                                        \
77
		if (__predict_false(bootverbose))       \
78
		if (__predict_false(bootverbose))       \
78
			device_printf(dev, __VA_ARGS__);    \
79
			device_printf(dev, __VA_ARGS__);    \
79
	} while (0)
80
	} while (0)
80
81
81
/*
82
/*
82
 * Note that the values are important.
83
 * Note that the values are important.
83
 * They match actual register offsets.
84
 * They match actual register offsets.
84
 */
85
 */
85
typedef enum {
86
typedef enum {
86
	REG_IOR = 0,
87
	REG_IOR = 0,
87
	REG_DAT = 1,
88
	REG_DAT = 1,
88
	REG_INV = 2,
89
	REG_INV = 2,
89
} reg_t;
90
} reg_t;
90
91
91
struct nct_gpio_group {
92
struct nct_gpio_group {
92
 	uint32_t    caps;
93
 	uint32_t    caps;
93
	uint8_t     enable_ldn;
94
	uint8_t     enable_ldn;
94
	uint8_t     enable_reg;
95
	uint8_t     enable_reg;
95
	uint8_t     enable_mask;
96
	uint8_t     enable_mask;
96
	uint8_t     data_ldn;
97
	uint8_t     data_ldn;
97
	uint8_t     iobase;
98
	uint8_t     iobase;
98
	uint8_t     ppod_reg; /* Push-Pull/Open-Drain */
99
	uint8_t     ppod_reg; /* Push-Pull/Open-Drain */
99
	uint8_t     grpnum;
100
	uint8_t     grpnum;
100
	uint8_t     pinbits[8];
101
	uint8_t     pinbits[8];
101
	uint8_t     npins;
102
	uint8_t     npins;
102
};
103
};
103
104
104
struct nct_softc {
105
struct nct_softc {
105
	device_t			dev;
106
	device_t			dev;
106
	device_t			busdev;
107
	device_t			busdev;
107
	struct mtx			mtx;
108
	struct mtx			mtx;
108
	struct resource			*iores;
109
	struct resource			*iores;
109
	int				iorid;
110
	int				iorid;
110
	int				curgrp;
111
	int				curgrp;
111
	struct {
112
	struct {
112
		uint8_t ior[NCT_MAX_GROUP + 1];       /* direction, 1: input 0: output */
113
		uint8_t ior[NCT_MAX_GROUP + 1];       /* direction, 1: input 0: output */
113
		uint8_t out[NCT_MAX_GROUP + 1];       /* output value */
114
		uint8_t out[NCT_MAX_GROUP + 1];       /* output value */
114
		uint8_t out_known[NCT_MAX_GROUP + 1]; /* whether out is valid */
115
		uint8_t out_known[NCT_MAX_GROUP + 1]; /* whether out is valid */
115
		uint8_t inv[NCT_MAX_GROUP + 1];       /* inversion, 1: inverted */
116
		uint8_t inv[NCT_MAX_GROUP + 1];       /* inversion, 1: inverted */
116
	} cache;
117
	} cache;
117
	struct gpio_pin				pins[NCT_MAX_PIN + 1];
118
	struct gpio_pin				pins[NCT_MAX_PIN + 1];
118
	struct nct_device			*nctdevp;
119
	struct nct_device			*nctdevp;
119
	int							npins; /* Total number of pins */
120
	int							npins; /* Total number of pins */
120
121
121
	/* Lookup tables */
122
	/* Lookup tables */
122
	struct {
123
	struct {
123
		struct nct_gpio_group *group;
124
		struct nct_gpio_group *group;
124
		uint8_t                grpnum;
125
		uint8_t                grpnum;
125
		uint8_t                bit;
126
		uint8_t                bit;
126
	} pinmap[NCT_MAX_PIN+1];
127
	} pinmap[NCT_MAX_PIN+1];
127
	struct nct_gpio_group *grpmap[NCT_MAX_GROUP+1];
128
	struct nct_gpio_group *grpmap[NCT_MAX_GROUP+1];
128
};
129
};
129
130
130
#define GPIO_LOCK_INIT(_sc)	mtx_init(&(_sc)->mtx,		\
131
#define GPIO_LOCK_INIT(_sc)	mtx_init(&(_sc)->mtx,		\
131
		device_get_nameunit(dev), NULL, MTX_DEF)
132
		device_get_nameunit(dev), NULL, MTX_DEF)
132
#define GPIO_LOCK_DESTROY(_sc)		mtx_destroy(&(_sc)->mtx)
133
#define GPIO_LOCK_DESTROY(_sc)		mtx_destroy(&(_sc)->mtx)
133
#define GPIO_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
134
#define GPIO_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
134
#define GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->mtx)
135
#define GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->mtx)
135
#define GPIO_ASSERT_LOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
136
#define GPIO_ASSERT_LOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
136
#define GPIO_ASSERT_UNLOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
137
#define GPIO_ASSERT_UNLOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
137
138
138
#define GET_BIT(v, b)	(((v) >> (b)) & 1)
139
#define GET_BIT(v, b)	(((v) >> (b)) & 1)
139
140
140
/*
141
/*
141
 * For most devices there are several GPIO devices, we attach only to one of
142
 * For most devices there are several GPIO devices, we attach only to one of
142
 * them and use the rest without attaching.
143
 * them and use the rest without attaching.
143
 */
144
 */
144
struct nct_device {
145
struct nct_device {
145
	uint16_t                  devid;
146
	uint16_t                  devid;
147
	uint16_t                  mask;
146
	int                       extid;
148
	int                       extid;
149
	uint8_t                   ldn;
147
	const char               *descr;
150
	const char               *descr;
148
	int                       ngroups;
151
	int                       ngroups;
149
	struct nct_gpio_group     groups[NCT_MAX_GROUP + 1];
152
	struct nct_gpio_group     groups[NCT_MAX_GROUP + 1];
150
} nct_devices[] = {
153
} nct_devices[] = {
151
	{
154
	{
152
		.devid   = 0xa025,
155
		.devid   = 0xa025,
153
		.descr   = "GPIO on Winbond 83627DHG IC ver. 5",
156
		.descr   = "GPIO on Winbond 83627DHG IC ver. 5",
154
		.ngroups = 5,
157
		.ngroups = 5,
155
		.groups  = {
158
		.groups  = {
156
			{
159
			{
157
				.grpnum      = 2,
160
				.grpnum      = 2,
158
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
161
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
159
				.enable_ldn  = 0x09,
162
				.enable_ldn  = 0x09,
160
				.enable_reg  = 0x30,
163
				.enable_reg  = 0x30,
161
				.enable_mask = 0x01,
164
				.enable_mask = 0x01,
162
				.data_ldn    = 0x09,
165
				.data_ldn    = 0x09,
163
				.ppod_reg    = 0xe0, /* FIXME Need to check for this group. */
166
				.ppod_reg    = 0xe0, /* FIXME Need to check for this group. */
164
				.caps        = NCT_GPIO_CAPS,
167
				.caps        = NCT_GPIO_CAPS,
165
				.npins       = 8,
168
				.npins       = 8,
166
				.iobase      = 0xe3,
169
				.iobase      = 0xe3,
167
			},
170
			},
168
			{
171
			{
169
				.grpnum      = 3,
172
				.grpnum      = 3,
170
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
173
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
171
				.enable_ldn  = 0x09,
174
				.enable_ldn  = 0x09,
172
				.enable_reg  = 0x30,
175
				.enable_reg  = 0x30,
173
				.enable_mask = 0x02,
176
				.enable_mask = 0x02,
174
				.data_ldn    = 0x09,
177
				.data_ldn    = 0x09,
175
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
178
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
176
				.caps        = NCT_GPIO_CAPS,
179
				.caps        = NCT_GPIO_CAPS,
177
				.npins       = 8,
180
				.npins       = 8,
178
				.iobase      = 0xf0,
181
				.iobase      = 0xf0,
179
			},
182
			},
180
			{
183
			{
181
				.grpnum      = 4,
184
				.grpnum      = 4,
182
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
185
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
183
				.enable_ldn  = 0x09,
186
				.enable_ldn  = 0x09,
184
				.enable_reg  = 0x30,
187
				.enable_reg  = 0x30,
185
				.enable_mask = 0x04,
188
				.enable_mask = 0x04,
186
				.data_ldn    = 0x09,
189
				.data_ldn    = 0x09,
187
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
190
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
188
				.caps        = NCT_GPIO_CAPS,
191
				.caps        = NCT_GPIO_CAPS,
189
				.npins       = 8,
192
				.npins       = 8,
190
				.iobase      = 0xf4,
193
				.iobase      = 0xf4,
191
			},
194
			},
192
			{
195
			{
193
				.grpnum      = 5,
196
				.grpnum      = 5,
194
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
197
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
195
				.enable_ldn  = 0x09,
198
				.enable_ldn  = 0x09,
196
				.enable_reg  = 0x30,
199
				.enable_reg  = 0x30,
197
				.enable_mask = 0x08,
200
				.enable_mask = 0x08,
198
				.data_ldn    = 0x09,
201
				.data_ldn    = 0x09,
199
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
202
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
200
				.caps        = NCT_GPIO_CAPS,
203
				.caps        = NCT_GPIO_CAPS,
201
				.npins       = 8,
204
				.npins       = 8,
202
				.iobase      = 0xe0,
205
				.iobase      = 0xe0,
203
			},
206
			},
204
			{
207
			{
205
				.grpnum      = 6,
208
				.grpnum      = 6,
206
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
209
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
207
				.enable_ldn  = 0x07,
210
				.enable_ldn  = 0x07,
208
				.enable_reg  = 0x30,
211
				.enable_reg  = 0x30,
209
				.enable_mask = 0x01,
212
				.enable_mask = 0x01,
210
				.data_ldn    = 0x07,
213
				.data_ldn    = 0x07,
211
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
214
				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
212
				.caps        = NCT_GPIO_CAPS,
215
				.caps        = NCT_GPIO_CAPS,
213
				.npins       = 8,
216
				.npins       = 8,
214
				.iobase      = 0xf4,
217
				.iobase      = 0xf4,
215
			},
218
			},
216
		},
219
		},
217
	},
220
	},
218
	{
221
	{
219
		.devid   = 0x1061,
222
		.devid   = 0x1061,
220
		.descr   = "GPIO on Nuvoton NCT5104D",
223
		.descr   = "GPIO on Nuvoton NCT5104D",
221
		.ngroups = 2,
224
		.ngroups = 2,
222
		.groups  = {
225
		.groups  = {
223
			{
226
			{
224
				.grpnum      = 0,
227
				.grpnum      = 0,
225
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
228
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
226
				.enable_ldn  = 0x07,
229
				.enable_ldn  = 0x07,
227
				.enable_reg  = 0x30,
230
				.enable_reg  = 0x30,
228
				.enable_mask = 0x01,
231
				.enable_mask = 0x01,
229
				.data_ldn    = 0x07,
232
				.data_ldn    = 0x07,
230
				.ppod_reg    = 0xe0,
233
				.ppod_reg    = 0xe0,
231
				.caps        = NCT_GPIO_CAPS,
234
				.caps        = NCT_GPIO_CAPS,
232
				.npins       = 8,
235
				.npins       = 8,
233
				.iobase      = 0xe0,
236
				.iobase      = 0xe0,
234
			},
237
			},
235
			{
238
			{
236
				.grpnum      = 1,
239
				.grpnum      = 1,
237
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
240
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
238
				.enable_ldn  = 0x07,
241
				.enable_ldn  = 0x07,
239
				.enable_reg  = 0x30,
242
				.enable_reg  = 0x30,
240
				.enable_mask = 0x02,
243
				.enable_mask = 0x02,
241
				.data_ldn    = 0x07,
244
				.data_ldn    = 0x07,
242
				.ppod_reg    = 0xe1,
245
				.ppod_reg    = 0xe1,
243
				.caps        = NCT_GPIO_CAPS,
246
				.caps        = NCT_GPIO_CAPS,
244
				.npins       = 8,
247
				.npins       = 8,
245
				.iobase      = 0xe4,
248
				.iobase      = 0xe4,
Lines 651-848 struct nct_device { Link Here
651
			},
654
			},
652
			{
655
			{
653
				.grpnum      = 1,
656
				.grpnum      = 1,
654
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
657
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
655
				.enable_ldn  = 0x07,
658
				.enable_ldn  = 0x07,
656
				.enable_reg  = 0x30,
659
				.enable_reg  = 0x30,
657
				.enable_mask = 0x02,
660
				.enable_mask = 0x02,
658
				.data_ldn    = 0x07,
661
				.data_ldn    = 0x07,
659
				.ppod_reg    = 0xe1,
662
				.ppod_reg    = 0xe1,
660
				.caps        = NCT_GPIO_CAPS,
663
				.caps        = NCT_GPIO_CAPS,
661
				.npins       = 8,
664
				.npins       = 8,
662
				.iobase      = 0xe4,
665
				.iobase      = 0xe4,
663
			},
666
			},
664
			{
667
			{
665
				.grpnum      = 2,
668
				.grpnum      = 2,
666
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
669
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
667
				.enable_ldn  = 0x07,
670
				.enable_ldn  = 0x07,
668
				.enable_reg  = 0x30,
671
				.enable_reg  = 0x30,
669
				.enable_mask = 0x04,
672
				.enable_mask = 0x04,
670
				.data_ldn    = 0x07,
673
				.data_ldn    = 0x07,
671
				.ppod_reg    = 0xe1,
674
				.ppod_reg    = 0xe1,
672
				.caps        = NCT_GPIO_CAPS,
675
				.caps        = NCT_GPIO_CAPS,
673
				.npins       = 8,
676
				.npins       = 8,
674
				.iobase      = 0xe8,
677
				.iobase      = 0xe8,
675
			},
678
			},
676
			{
679
			{
677
				.grpnum      = 3,
680
				.grpnum      = 3,
678
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
681
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
679
				.enable_ldn  = 0x07,
682
				.enable_ldn  = 0x07,
680
				.enable_reg  = 0x30,
683
				.enable_reg  = 0x30,
681
				.enable_mask = 0x08,
684
				.enable_mask = 0x08,
682
				.data_ldn    = 0x07,
685
				.data_ldn    = 0x07,
683
				.ppod_reg    = 0xe1,
686
				.ppod_reg    = 0xe1,
684
				.caps        = NCT_GPIO_CAPS,
687
				.caps        = NCT_GPIO_CAPS,
685
				.npins       = 8,
688
				.npins       = 8,
686
				.iobase      = 0xec,
689
				.iobase      = 0xec,
687
			},
690
			},
688
			{
691
			{
689
				.grpnum      = 4,
692
				.grpnum      = 4,
690
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
693
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
691
				.enable_ldn  = 0x07,
694
				.enable_ldn  = 0x07,
692
				.enable_reg  = 0x30,
695
				.enable_reg  = 0x30,
693
				.enable_mask = 0x10,
696
				.enable_mask = 0x10,
694
				.data_ldn    = 0x07,
697
				.data_ldn    = 0x07,
695
				.ppod_reg    = 0xe1,
698
				.ppod_reg    = 0xe1,
696
				.caps        = NCT_GPIO_CAPS,
699
				.caps        = NCT_GPIO_CAPS,
697
				.npins       = 8,
700
				.npins       = 8,
698
				.iobase      = 0xf0,
701
				.iobase      = 0xf0,
699
			},
702
			},
700
			{
703
			{
701
				.grpnum      = 5,
704
				.grpnum      = 5,
702
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
705
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
703
				.enable_ldn  = 0x07,
706
				.enable_ldn  = 0x07,
704
				.enable_reg  = 0x30,
707
				.enable_reg  = 0x30,
705
				.enable_mask = 0x20,
708
				.enable_mask = 0x20,
706
				.data_ldn    = 0x07,
709
				.data_ldn    = 0x07,
707
				.ppod_reg    = 0xe1,
710
				.ppod_reg    = 0xe1,
708
				.caps        = NCT_GPIO_CAPS,
711
				.caps        = NCT_GPIO_CAPS,
709
				.npins       = 8,
712
				.npins       = 8,
710
				.iobase      = 0xf4,
713
				.iobase      = 0xf4,
711
			},
714
			},
712
			{
715
			{
713
				.grpnum      = 6,
716
				.grpnum      = 6,
714
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
717
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
715
				.enable_ldn  = 0x07,
718
				.enable_ldn  = 0x07,
716
				.enable_reg  = 0x30,
719
				.enable_reg  = 0x30,
717
				.enable_mask = 0x40,
720
				.enable_mask = 0x40,
718
				.data_ldn    = 0x07,
721
				.data_ldn    = 0x07,
719
				.ppod_reg    = 0xe1,
722
				.ppod_reg    = 0xe1,
720
				.caps        = NCT_GPIO_CAPS,
723
				.caps        = NCT_GPIO_CAPS,
721
				.npins       = 8,
724
				.npins       = 8,
722
				.iobase      = 0xf8,
725
				.iobase      = 0xf8,
723
			},
726
			},
724
			{
727
			{
725
				.grpnum      = 7,
728
				.grpnum      = 7,
726
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
729
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
727
				.enable_ldn  = 0x07,
730
				.enable_ldn  = 0x07,
728
				.enable_reg  = 0x30,
731
				.enable_reg  = 0x30,
729
				.enable_mask = 0x80,
732
				.enable_mask = 0x80,
730
				.data_ldn    = 0x07,
733
				.data_ldn    = 0x07,
731
				.ppod_reg    = 0xe1,
734
				.ppod_reg    = 0xe1,
732
				.caps        = NCT_GPIO_CAPS,
735
				.caps        = NCT_GPIO_CAPS,
733
				.npins       = 8,
736
				.npins       = 8,
734
				.iobase      = 0xfc,
737
				.iobase      = 0xfc,
735
			},
738
			},
736
			{
739
			{
737
				.grpnum      = 8,
740
				.grpnum      = 8,
738
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
741
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
739
				.enable_ldn  = 0x09,
742
				.enable_ldn  = 0x09,
740
				.enable_reg  = 0x30,
743
				.enable_reg  = 0x30,
741
				.enable_mask = 0x01,
744
				.enable_mask = 0x01,
742
				.data_ldn    = 0x09,
745
				.data_ldn    = 0x09,
743
				.ppod_reg    = 0xe1,
746
				.ppod_reg    = 0xe1,
744
				.caps        = NCT_GPIO_CAPS,
747
				.caps        = NCT_GPIO_CAPS,
745
				.npins       = 8,
748
				.npins       = 8,
746
				.iobase      = 0xf0,
749
				.iobase      = 0xf0,
747
			},
750
			},
748
		},
751
		},
749
	},
752
	},
753
	{
754
		.devid   = 0xd284,
755
		.mask    = 0xffdf,
756
		.ldn	 = 7,
757
		.descr   = "GPIO on Nuvoton NCT6122D/NCT6126D",
758
		.ngroups = 8,
759
		.groups  = {
760
			// LDN7, GPIO0-7
761
			{
762
				.grpnum      = 0,
763
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
764
				.enable_ldn  = 0x07,
765
				.enable_reg  = 0x30,
766
				.enable_mask = 0x01,
767
				.data_ldn    = 0x07,
768
				.ppod_reg    = 0xe0,
769
				.caps        = NCT_GPIO_CAPS,
770
				.npins       = 8,
771
				.iobase      = 0xe0,
772
			},
773
			{
774
				.grpnum      = 1,
775
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
776
				.enable_ldn  = 0x07,
777
				.enable_reg  = 0x30,
778
				.enable_mask = 0x02,
779
				.data_ldn    = 0x07,
780
				.ppod_reg    = 0xe1,
781
				.caps        = NCT_GPIO_CAPS,
782
				.npins       = 8,
783
				.iobase      = 0xe4,
784
			},
785
			{
786
				.grpnum      = 2,
787
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
788
				.enable_ldn  = 0x07,
789
				.enable_reg  = 0x30,
790
				.enable_mask = 0x04,
791
				.data_ldn    = 0x07,
792
				.ppod_reg    = 0xe2,
793
				.caps        = NCT_GPIO_CAPS,
794
				.npins       = 8,
795
				.iobase      = 0xe8,
796
			},
797
			{
798
				.grpnum      = 3,
799
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
800
				.enable_ldn  = 0x07,
801
				.enable_reg  = 0x30,
802
				.enable_mask = 0x08,
803
				.data_ldn    = 0x07,
804
				.ppod_reg    = 0xe3,
805
				.caps        = NCT_GPIO_CAPS,
806
				.npins       = 8,
807
				.iobase      = 0xec,
808
			},
809
			{
810
				.grpnum      = 4,
811
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
812
				.enable_ldn  = 0x07,
813
				.enable_reg  = 0x30,
814
				.enable_mask = 0x10,
815
				.data_ldn    = 0x07,
816
				.ppod_reg    = 0xe4,
817
				.caps        = NCT_GPIO_CAPS,
818
				.npins       = 8,
819
				.iobase      = 0xf0,
820
			},
821
			{
822
				.grpnum      = 5,
823
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
824
				.enable_ldn  = 0x07,
825
				.enable_reg  = 0x30,
826
				.enable_mask = 0x20,
827
				.data_ldn    = 0x07,
828
				.ppod_reg    = 0xe5,
829
				.caps        = NCT_GPIO_CAPS,
830
				.npins       = 8,
831
				.iobase      = 0xf4,
832
			},
833
			{
834
				.grpnum      = 6,
835
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
836
				.enable_ldn  = 0x07,
837
				.enable_reg  = 0x30,
838
				.enable_mask = 0x40,
839
				.data_ldn    = 0x07,
840
				.ppod_reg    = 0xe6,
841
				.caps        = NCT_GPIO_CAPS,
842
				.npins       = 8,
843
				.iobase      = 0xf8,
844
			},
845
			{
846
				.grpnum      = 7,
847
				.pinbits     = { 0, 1 },
848
				.enable_ldn  = 0x07,
849
				.enable_reg  = 0x30,
850
				.enable_mask = 0x80,
851
				.data_ldn    = 0x07,
852
				.ppod_reg    = 0xe7,
853
				.caps        = NCT_GPIO_CAPS,
854
				.npins       = 2,
855
				.iobase      = 0xfc,
856
			},
857
		},
858
	},
859
	{
860
		.devid   = 0xd284,
861
		.mask    = 0xffdf,
862
		.ldn	 = 9,
863
		.descr   = "GPIO on Nuvoton NCT6122D/NCT6126D",
864
		.ngroups = 4,
865
		.groups  = {
866
			// LDN9, GPIO8,GPIO9,GPIOA,GPIOB
867
			{
868
				.grpnum      = 8,
869
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
870
				.enable_ldn  = 0x09,
871
				.enable_reg  = 0x30,
872
				.enable_mask = 0x01,
873
				.data_ldn    = 0x09,
874
				.ppod_reg    = 0xe8,
875
				.caps        = NCT_GPIO_CAPS,
876
				.npins       = 8,
877
				.iobase      = 0xf0,
878
			},
879
			{
880
				.grpnum      = 9,
881
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
882
				.enable_ldn  = 0x09,
883
				.enable_reg  = 0x30,
884
				.enable_mask = 0x02,
885
				.data_ldn    = 0x09,
886
				.ppod_reg    = 0xe9,
887
				.caps        = NCT_GPIO_CAPS,
888
				.npins       = 8,
889
				.iobase      = 0xf4,
890
			},
891
			{
892
				.grpnum      = 0xa,
893
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
894
				.enable_ldn  = 0x09,
895
				.enable_reg  = 0x30,
896
				.enable_mask = 0x04,
897
				.data_ldn    = 0x09,
898
				.ppod_reg    = 0xea,
899
				.caps        = NCT_GPIO_CAPS,
900
				.npins       = 8,
901
				.iobase      = 0xf8,
902
			},
903
			{
904
				.grpnum      = 0xb,
905
				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
906
				.enable_ldn  = 0x09,
907
				.enable_reg  = 0x30,
908
				.enable_mask = 0x08,
909
				.data_ldn    = 0x09,
910
				.ppod_reg    = 0xeb,
911
				.caps        = NCT_GPIO_CAPS,
912
				.npins       = 8,
913
				.iobase      = 0xfc,
914
			},
915
		},
916
	},
750
};
917
};
751
918
752
static const char *
919
static const char *
753
io2str(uint8_t ioport)
920
io2str(uint8_t ioport)
754
{
921
{
755
	switch (ioport) {
922
	switch (ioport) {
756
	case NCT_IO_GSR: return ("grpsel");
923
	case NCT_IO_GSR: return ("grpsel");
757
	case NCT_IO_IOR: return ("io");
924
	case NCT_IO_IOR: return ("io");
758
	case NCT_IO_DAT: return ("data");
925
	case NCT_IO_DAT: return ("data");
759
	case NCT_IO_INV: return ("inv");
926
	case NCT_IO_INV: return ("inv");
760
	case NCT_IO_DST: return ("status");
927
	case NCT_IO_DST: return ("status");
761
	default:         return ("?");
928
	default:         return ("?");
762
	}
929
	}
763
}
930
}
764
931
765
static void
932
static void
766
nct_io_set_group(struct nct_softc *sc, uint8_t grpnum)
933
nct_io_set_group(struct nct_softc *sc, uint8_t grpnum)
767
{
934
{
768
	GPIO_ASSERT_LOCKED(sc);
935
	GPIO_ASSERT_LOCKED(sc);
769
936
770
	if (grpnum == sc->curgrp)
937
	if (grpnum == sc->curgrp)
771
		return;
938
		return;
772
939
773
	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
940
	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
774
		io2str(NCT_IO_GSR), grpnum, NCT_IO_GSR);
941
		io2str(NCT_IO_GSR), grpnum, NCT_IO_GSR);
775
	bus_write_1(sc->iores, NCT_IO_GSR, grpnum);
942
	bus_write_1(sc->iores, NCT_IO_GSR, grpnum);
776
	sc->curgrp = grpnum;
943
	sc->curgrp = grpnum;
777
}
944
}
778
945
779
static uint8_t
946
static uint8_t
780
nct_io_read(struct nct_softc *sc, uint8_t grpnum, uint8_t reg)
947
nct_io_read(struct nct_softc *sc, uint8_t grpnum, uint8_t reg)
781
{
948
{
782
	uint8_t val;
949
	uint8_t val;
783
950
784
	nct_io_set_group(sc, grpnum);
951
	nct_io_set_group(sc, grpnum);
785
952
786
	val = bus_read_1(sc->iores, reg);
953
	val = bus_read_1(sc->iores, reg);
787
	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x ioport %d\n",
954
	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x ioport %d\n",
788
		io2str(reg), val, reg);
955
		io2str(reg), val, reg);
789
	return (val);
956
	return (val);
790
}
957
}
791
958
792
static void
959
static void
793
nct_io_write(struct nct_softc *sc, uint8_t grpnum, uint8_t reg, uint8_t val)
960
nct_io_write(struct nct_softc *sc, uint8_t grpnum, uint8_t reg, uint8_t val)
794
{
961
{
795
	nct_io_set_group(sc, grpnum);
962
	nct_io_set_group(sc, grpnum);
796
963
797
	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
964
	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
798
		io2str(reg), val, reg);
965
		io2str(reg), val, reg);
799
	bus_write_1(sc->iores, reg, val);
966
	bus_write_1(sc->iores, reg, val);
800
}
967
}
801
968
802
static uint8_t
969
static uint8_t
803
nct_get_ioreg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
970
nct_get_ioreg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
804
{
971
{
805
	uint8_t iobase;
972
	uint8_t iobase;
806
973
807
	if (sc->iores != NULL)
974
	if (sc->iores != NULL)
808
		iobase = NCT_IO_IOR;
975
		iobase = NCT_IO_IOR;
809
	else
976
	else
810
		iobase = sc->grpmap[grpnum]->iobase;
977
		iobase = sc->grpmap[grpnum]->iobase;
811
	return (iobase + reg);
978
	return (iobase + reg);
812
}
979
}
813
980
814
static const char *
981
static const char *
815
reg2str(reg_t reg)
982
reg2str(reg_t reg)
816
{
983
{
817
	switch (reg) {
984
	switch (reg) {
818
	case REG_IOR: return ("io");
985
	case REG_IOR: return ("io");
819
	case REG_DAT: return ("data");
986
	case REG_DAT: return ("data");
820
	case REG_INV: return ("inv");
987
	case REG_INV: return ("inv");
821
	default:      return ("?");
988
	default:      return ("?");
822
	}
989
	}
823
}
990
}
824
991
825
static uint8_t
992
static uint8_t
826
nct_read_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
993
nct_read_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
827
{
994
{
828
	struct nct_gpio_group *gp;
995
	struct nct_gpio_group *gp;
829
	uint8_t                ioreg;
996
	uint8_t                ioreg;
830
	uint8_t                val;
997
	uint8_t                val;
831
998
832
	ioreg = nct_get_ioreg(sc, reg, grpnum);
999
	ioreg = nct_get_ioreg(sc, reg, grpnum);
833
1000
834
	if (sc->iores != NULL)
1001
	if (sc->iores != NULL)
835
		return (nct_io_read(sc, grpnum, ioreg));
1002
		return (nct_io_read(sc, grpnum, ioreg));
836
1003
837
	gp  = sc->grpmap[grpnum];
1004
	gp  = sc->grpmap[grpnum];
838
	val = superio_ldn_read(sc->dev, gp->data_ldn, ioreg);
1005
	val = superio_ldn_read(sc->dev, gp->data_ldn, ioreg);
839
	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x from group GPIO%u ioreg 0x%x\n",
1006
	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x from group GPIO%u ioreg 0x%x\n",
840
		reg2str(reg), val, grpnum, ioreg);
1007
		reg2str(reg), val, grpnum, ioreg);
841
	return (val);
1008
	return (val);
842
}
1009
}
843
1010
844
static int
1011
static int
845
nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache)
1012
nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache)
846
{
1013
{
847
	uint8_t bit;
1014
	uint8_t bit;
848
	uint8_t group;
1015
	uint8_t group;
Lines 993-1302 nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num) Link Here
993
		else
1160
		else
994
			NCT_VERBOSE_PRINTF(sc->dev,
1161
			NCT_VERBOSE_PRINTF(sc->dev,
995
				"read %d from output pin %u<GPIO%u%u>, cache miss\n",
1162
				"read %d from output pin %u<GPIO%u%u>, cache miss\n",
996
				b, pin_num, group, bit);
1163
				b, pin_num, group, bit);
997
	}
1164
	}
998
1165
999
	return (b);
1166
	return (b);
1000
}
1167
}
1001
1168
1002
/*
1169
/*
1003
 * NB: state of an input pin cannot be cached, of course.
1170
 * NB: state of an input pin cannot be cached, of course.
1004
 * For an output we can either take the value from the cache if it's valid
1171
 * For an output we can either take the value from the cache if it's valid
1005
 * or read the state from the hadrware and cache it.
1172
 * or read the state from the hadrware and cache it.
1006
 */
1173
 */
1007
static bool
1174
static bool
1008
nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
1175
nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
1009
{
1176
{
1010
	uint8_t bit;
1177
	uint8_t bit;
1011
	uint8_t group;
1178
	uint8_t group;
1012
	bool    val;
1179
	bool    val;
1013
1180
1014
	if (nct_pin_is_input(sc, pin_num)) {
1181
	if (nct_pin_is_input(sc, pin_num)) {
1015
		return (nct_get_pin_reg(sc, REG_DAT, pin_num));
1182
		return (nct_get_pin_reg(sc, REG_DAT, pin_num));
1016
	}
1183
	}
1017
1184
1018
	group = NCT_PIN_GRPNUM(sc, pin_num);
1185
	group = NCT_PIN_GRPNUM(sc, pin_num);
1019
	bit   = NCT_PIN_BIT(sc, pin_num);
1186
	bit   = NCT_PIN_BIT(sc, pin_num);
1020
1187
1021
	if (GET_BIT(sc->cache.out_known[group], bit)) {
1188
	if (GET_BIT(sc->cache.out_known[group], bit)) {
1022
		val = GET_BIT(sc->cache.out[group], bit);
1189
		val = GET_BIT(sc->cache.out[group], bit);
1023
1190
1024
		NCT_VERBOSE_PRINTF(sc->dev,
1191
		NCT_VERBOSE_PRINTF(sc->dev,
1025
			"read %d from output pin %u<GPIO%u%u>, cache hit\n",
1192
			"read %d from output pin %u<GPIO%u%u>, cache hit\n",
1026
			val, pin_num, group, bit);
1193
			val, pin_num, group, bit);
1027
1194
1028
		return (val);
1195
		return (val);
1029
	}
1196
	}
1030
1197
1031
	val = nct_get_pin_reg(sc, REG_DAT, pin_num);
1198
	val = nct_get_pin_reg(sc, REG_DAT, pin_num);
1032
	sc->cache.out_known[group] |= 1 << bit;
1199
	sc->cache.out_known[group] |= 1 << bit;
1033
	if (val)
1200
	if (val)
1034
		sc->cache.out[group] |= 1 << bit;
1201
		sc->cache.out[group] |= 1 << bit;
1035
	else
1202
	else
1036
		sc->cache.out[group] &= ~(1 << bit);
1203
		sc->cache.out[group] &= ~(1 << bit);
1037
	return (val);
1204
	return (val);
1038
}
1205
}
1039
1206
1040
/* FIXME Incorret for NCT5585D and probably other chips. */
1207
/* FIXME Incorret for NCT5585D and probably other chips. */
1041
static uint8_t
1208
static uint8_t
1042
nct_ppod_reg(struct nct_softc *sc, uint32_t pin_num)
1209
nct_ppod_reg(struct nct_softc *sc, uint32_t pin_num)
1043
{
1210
{
1044
	uint8_t group = NCT_PIN_GRPNUM(sc, pin_num);
1211
	uint8_t group = NCT_PIN_GRPNUM(sc, pin_num);
1045
1212
1046
	return (sc->grpmap[group]->ppod_reg);
1213
	return (sc->grpmap[group]->ppod_reg);
1047
}
1214
}
1048
1215
1049
/*
1216
/*
1050
 * NB: PP/OD can be configured only via configuration registers.
1217
 * NB: PP/OD can be configured only via configuration registers.
1051
 * Also, the registers are in a different logical device.
1218
 * Also, the registers are in a different logical device.
1052
 * So, this is a special case.  No caching too.
1219
 * So, this is a special case.  No caching too.
1053
 */
1220
 */
1054
static void
1221
static void
1055
nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
1222
nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
1056
{
1223
{
1057
	uint8_t reg;
1224
	uint8_t reg;
1058
	uint8_t outcfg;
1225
	uint8_t outcfg;
1059
1226
1060
	reg = nct_ppod_reg(sc, pin_num);
1227
	reg = nct_ppod_reg(sc, pin_num);
1061
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1228
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1062
	outcfg |= NCT_PIN_BITMASK(pin_num);
1229
	outcfg |= NCT_PIN_BITMASK(pin_num);
1063
	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1230
	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1064
}
1231
}
1065
1232
1066
static void
1233
static void
1067
nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
1234
nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
1068
{
1235
{
1069
	uint8_t reg;
1236
	uint8_t reg;
1070
	uint8_t outcfg;
1237
	uint8_t outcfg;
1071
1238
1072
	reg = nct_ppod_reg(sc, pin_num);
1239
	reg = nct_ppod_reg(sc, pin_num);
1073
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1240
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1074
	outcfg &= ~NCT_PIN_BITMASK(pin_num);
1241
	outcfg &= ~NCT_PIN_BITMASK(pin_num);
1075
	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1242
	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1076
}
1243
}
1077
1244
1078
static bool
1245
static bool
1079
nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
1246
nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
1080
{
1247
{
1081
	uint8_t reg;
1248
	uint8_t reg;
1082
	uint8_t outcfg;
1249
	uint8_t outcfg;
1083
1250
1084
	reg = nct_ppod_reg(sc, pin_num);
1251
	reg = nct_ppod_reg(sc, pin_num);
1085
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1252
	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1086
	return (outcfg & NCT_PIN_BITMASK(pin_num));
1253
	return (outcfg & NCT_PIN_BITMASK(pin_num));
1087
}
1254
}
1088
1255
1089
static struct nct_device *
1256
static struct nct_device *
1090
nct_lookup_device(device_t dev)
1257
nct_lookup_device(device_t dev)
1091
{
1258
{
1092
	struct nct_device *nctdevp;
1259
	struct nct_device *nd;
1093
	uint16_t           devid;
1260
	uint16_t           devid;
1094
	int                i, extid;
1261
	int                i, extid;
1262
	uint8_t            ldn;
1095
1263
1096
	devid = superio_devid(dev);
1264
	devid = superio_devid(dev);
1097
	extid = superio_extid(dev);
1265
	extid = superio_extid(dev);
1098
	for (i = 0, nctdevp = nct_devices; i < nitems(nct_devices); i++, nctdevp++) {
1266
	ldn = superio_get_ldn(dev);
1099
		if (devid == nctdevp->devid && nctdevp->extid == extid)
1267
	for (i = 0, nd = nct_devices; i < nitems(nct_devices); i++, nd++) {
1100
			return (nctdevp);
1268
		if (nd->devid != (nd->mask ? (devid & nd->mask) : devid))
1269
			continue;
1270
		if (nd->extid && (nd->extid != extid))
1271
			continue;
1272
		if (nd->ldn && (nd->ldn != ldn))
1273
			continue;
1274
1275
		return (nd);
1101
	}
1276
	}
1102
	return (NULL);
1277
	return (NULL);
1103
}
1278
}
1104
1279
1105
static int
1280
static int
1106
nct_probe(device_t dev)
1281
nct_probe(device_t dev)
1107
{
1282
{
1108
	struct nct_device *nctdevp;
1283
	struct nct_device *nctdevp;
1109
	uint8_t            ldn;
1284
	uint8_t            ldn;
1110
1285
1111
	ldn = superio_get_ldn(dev);
1286
	ldn = superio_get_ldn(dev);
1112
1287
1113
	if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
1288
	if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
1114
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
1289
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
1115
		return (ENXIO);
1290
		return (ENXIO);
1116
	}
1291
	}
1117
	if (superio_get_type(dev) != SUPERIO_DEV_GPIO) {
1292
	if (superio_get_type(dev) != SUPERIO_DEV_GPIO) {
1118
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a GPIO device\n", ldn);
1293
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a GPIO device\n", ldn);
1119
		return (ENXIO);
1294
		return (ENXIO);
1120
	}
1295
	}
1121
1296
1122
	nctdevp = nct_lookup_device(dev);
1297
	nctdevp = nct_lookup_device(dev);
1123
	if (nctdevp == NULL) {
1298
	if (nctdevp == NULL) {
1124
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
1299
		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
1125
		return (ENXIO);
1300
		return (ENXIO);
1126
	}
1301
	}
1127
	device_set_desc(dev, nctdevp->descr);
1302
	device_set_desc(dev, nctdevp->descr);
1128
	return (BUS_PROBE_DEFAULT);
1303
	return (BUS_PROBE_DEFAULT);
1129
}
1304
}
1130
1305
1306
static void
1307
nct_enable_gpios (device_t dev, struct nct_softc *sc)
1308
{
1309
	struct nct_gpio_group *gp;
1310
	uint8_t v;
1311
	int g;
1312
1313
	/* Enable GPIO groups */
1314
	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1315
		NCT_VERBOSE_PRINTF(dev,
1316
			"GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n",
1317
			gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn,
1318
			gp->enable_reg);
1319
		v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg);
1320
		v |= gp->enable_mask;
1321
		superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v);
1322
	}
1323
	return;
1324
}
1325
1131
static int
1326
static int
1132
nct_attach(device_t dev)
1327
nct_attach(device_t dev)
1133
{
1328
{
1134
	struct nct_softc *sc;
1329
	struct nct_softc *sc;
1135
	struct nct_gpio_group *gp;
1330
	struct nct_gpio_group *gp;
1136
	uint32_t pin_num;
1331
	uint32_t pin_num;
1137
	uint8_t v;
1332
	uint8_t v;
1138
	int flags, i, g;
1333
	int flags, i, g;
1139
1334
1140
	sc          = device_get_softc(dev);
1335
	sc          = device_get_softc(dev);
1141
	sc->dev     = dev;
1336
	sc->dev     = dev;
1142
	sc->nctdevp = nct_lookup_device(dev);
1337
	sc->nctdevp = nct_lookup_device(dev);
1143
1338
1144
	flags = 0;
1339
	flags = 0;
1145
	(void)resource_int_value(device_get_name(dev), device_get_unit(dev), "flags", &flags);
1340
	(void)resource_int_value(device_get_name(dev), device_get_unit(dev), "flags", &flags);
1146
1341
1147
	if ((flags & NCT_PREFER_INDIRECT_CHANNEL) == 0) {
1342
	if ((flags & NCT_PREFER_INDIRECT_CHANNEL) == 0) {
1148
		uint16_t iobase;
1343
		uint16_t iobase;
1149
		device_t dev_8;
1344
		device_t dev_8;
1150
1345
1151
		/*
1346
		/*
1152
		 * As strange as it may seem, I/O port base is configured in the
1347
		 * As strange as it may seem, I/O port base is configured in the
1153
		 * Logical Device 8 which is primarily used for WDT, but also plays
1348
		 * Logical Device 8 which is primarily used for WDT, but also plays
1154
		 * a role in GPIO configuration.
1349
		 * a role in GPIO configuration.
1155
		 */
1350
		 */
1156
		iobase = 0;
1351
		iobase = 0;
1157
		dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8);
1352
		dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8);
1158
		if (dev_8 != NULL)
1353
		if (dev_8 != NULL)
1159
			iobase = superio_get_iobase(dev_8);
1354
			iobase = superio_get_iobase(dev_8);
1160
		if (iobase != 0 && iobase != 0xffff) {
1355
		if (iobase != 0 && iobase != 0xffff) {
1161
			int err;
1356
			int err;
1162
1357
1163
			NCT_VERBOSE_PRINTF(dev, "iobase %#x\n", iobase);
1358
			NCT_VERBOSE_PRINTF(dev, "iobase %#x\n", iobase);
1164
			sc->curgrp = -1;
1359
			sc->curgrp = -1;
1165
			sc->iorid = 0;
1360
			sc->iorid = 0;
1166
			err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid,
1361
			err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid,
1167
				iobase, 7); /* FIXME NCT6796D-E have 8 registers according to table 18.3. */
1362
				iobase, 7); /* FIXME NCT6796D-E have 8 registers according to table 18.3. */
1168
			if (err == 0) {
1363
			if (err == 0) {
1169
				sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
1364
				sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
1170
					&sc->iorid, RF_ACTIVE);
1365
					&sc->iorid, RF_ACTIVE|RF_SHAREABLE);
1171
				if (sc->iores == NULL) {
1366
				if (sc->iores == NULL) {
1172
					device_printf(dev, "can't map i/o space, "
1367
					device_printf(dev, "can't map i/o space, "
1173
						"iobase=%#x\n", iobase);
1368
						"iobase=%#x\n", iobase);
1174
				}
1369
				}
1175
			} else {
1370
			} else {
1176
				device_printf(dev,
1371
				device_printf(dev,
1177
					"failed to set io port resource at %#x\n", iobase);
1372
					"failed to set io port resource at %#x\n", iobase);
1178
			}
1373
			}
1179
		}
1374
		}
1180
	}
1375
	}
1181
	NCT_VERBOSE_PRINTF(dev, "iores %p %s channel\n",
1376
	NCT_VERBOSE_PRINTF(dev, "iores %p %s channel\n",
1182
		sc->iores, (sc->iores ? "direct" : "indirect"));
1377
		sc->iores, (sc->iores ? "direct" : "indirect"));
1183
1378
1184
	/* Enable GPIO groups */
1379
	if (flags & NCT_NO_ENABLE) {
1185
	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1380
		NCT_VERBOSE_PRINTF(dev, "skipping enable.\n");
1186
		NCT_VERBOSE_PRINTF(dev,
1381
	} else {
1187
			"GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n",
1382
		nct_enable_gpios(dev, sc);
1188
			gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn,
1189
			gp->enable_reg);
1190
		v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg);
1191
		v |= gp->enable_mask;
1192
		superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v);
1193
	}
1383
	}
1194
1384
1195
	GPIO_LOCK_INIT(sc);
1385
	GPIO_LOCK_INIT(sc);
1196
	GPIO_LOCK(sc);
1386
	GPIO_LOCK(sc);
1197
1387
1198
	pin_num   = 0;
1388
	pin_num   = 0;
1199
	sc->npins = 0;
1389
	sc->npins = 0;
1200
	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1390
	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1201
1391
1202
		sc->grpmap[gp->grpnum] = gp;
1392
		sc->grpmap[gp->grpnum] = gp;
1203
1393
1394
		if (flags & NCT_NO_ENABLE) {
1395
			v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg);
1396
			if ((v & gp->enable_mask) == 0)
1397
				continue;
1398
		}
1399
1204
		/*
1400
		/*
1205
		 * Caching input values is meaningless as an input can be changed at any
1401
		 * Caching input values is meaningless as an input can be changed at any
1206
		 * time by an external agent.  But outputs are controlled by this
1402
		 * time by an external agent.  But outputs are controlled by this
1207
		 * driver, so it can cache their state.  Also, the hardware remembers
1403
		 * driver, so it can cache their state.  Also, the hardware remembers
1208
		 * the output state of a pin when the pin is switched to input mode and
1404
		 * the output state of a pin when the pin is switched to input mode and
1209
		 * then back to output mode.  So, the cache stays valid.
1405
		 * then back to output mode.  So, the cache stays valid.
1210
		 * The only problem is with pins that are in input mode at the attach
1406
		 * The only problem is with pins that are in input mode at the attach
1211
		 * time.  For them the output state is not known until it is set by the
1407
		 * time.  For them the output state is not known until it is set by the
1212
		 * driver for the first time.
1408
		 * driver for the first time.
1213
		 * 'out' and 'out_known' bits form a tri-state output cache:
1409
		 * 'out' and 'out_known' bits form a tri-state output cache:
1214
		 * |-----+-----------+---------|
1410
		 * |-----+-----------+---------|
1215
		 * | out | out_known | cache   |
1411
		 * | out | out_known | cache   |
1216
		 * |-----+-----------+---------|
1412
		 * |-----+-----------+---------|
1217
		 * |   X |         0 | invalid |
1413
		 * |   X |         0 | invalid |
1218
		 * |   0 |         1 |       0 |
1414
		 * |   0 |         1 |       0 |
1219
		 * |   1 |         1 |       1 |
1415
		 * |   1 |         1 |       1 |
1220
		 * |-----+-----------+---------|
1416
		 * |-----+-----------+---------|
1221
		 */
1417
		 */
1222
		sc->cache.inv[gp->grpnum]       = nct_read_reg(sc, REG_INV, gp->grpnum);
1418
		sc->cache.inv[gp->grpnum]       = nct_read_reg(sc, REG_INV, gp->grpnum);
1223
		sc->cache.ior[gp->grpnum]       = nct_read_reg(sc, REG_IOR, gp->grpnum);
1419
		sc->cache.ior[gp->grpnum]       = nct_read_reg(sc, REG_IOR, gp->grpnum);
1224
		sc->cache.out[gp->grpnum]       = nct_read_reg(sc, REG_DAT, gp->grpnum);
1420
		sc->cache.out[gp->grpnum]       = nct_read_reg(sc, REG_DAT, gp->grpnum);
1225
		sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum];
1421
		sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum];
1226
1422
1227
		sc->npins += gp->npins;
1423
		sc->npins += gp->npins;
1228
		for (i = 0; i < gp->npins; i++, pin_num++) {
1424
		for (i = 0; i < gp->npins; i++, pin_num++) {
1229
			struct gpio_pin *pin;
1425
			struct gpio_pin *pin;
1230
1426
1231
			sc->pinmap[pin_num].group  = gp;
1427
			sc->pinmap[pin_num].group  = gp;
1232
			sc->pinmap[pin_num].grpnum = gp->grpnum;
1428
			sc->pinmap[pin_num].grpnum = gp->grpnum;
1233
			sc->pinmap[pin_num].bit    = gp->pinbits[i];
1429
			sc->pinmap[pin_num].bit    = gp->pinbits[i];
1234
1430
1235
			pin           = &sc->pins[pin_num];
1431
			pin           = &sc->pins[pin_num];
1236
			pin->gp_pin   = pin_num;
1432
			pin->gp_pin   = pin_num;
1237
			pin->gp_caps  = gp->caps;
1433
			pin->gp_caps  = gp->caps;
1238
			pin->gp_flags = 0;
1434
			pin->gp_flags = 0;
1239
1435
1240
			snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u",
1436
			snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u",
1241
				gp->grpnum, gp->pinbits[i]);
1437
				gp->grpnum, gp->pinbits[i]);
1242
1438
1243
			if (nct_pin_is_input(sc, pin_num))
1439
			if (nct_pin_is_input(sc, pin_num))
1244
				pin->gp_flags |= GPIO_PIN_INPUT;
1440
				pin->gp_flags |= GPIO_PIN_INPUT;
1245
			else
1441
			else
1246
				pin->gp_flags |= GPIO_PIN_OUTPUT;
1442
				pin->gp_flags |= GPIO_PIN_OUTPUT;
1247
1443
1248
			if (nct_pin_is_opendrain(sc, pin_num))
1444
			if (nct_pin_is_opendrain(sc, pin_num))
1249
				pin->gp_flags |= GPIO_PIN_OPENDRAIN;
1445
				pin->gp_flags |= GPIO_PIN_OPENDRAIN;
1250
			else
1446
			else
1251
				pin->gp_flags |= GPIO_PIN_PUSHPULL;
1447
				pin->gp_flags |= GPIO_PIN_PUSHPULL;
1252
1448
1253
			if (nct_pin_is_inverted(sc, pin_num))
1449
			if (nct_pin_is_inverted(sc, pin_num))
1254
				pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
1450
				pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
1255
		}
1451
		}
1256
	}
1452
	}
1257
	NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins);
1453
	NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins);
1258
1454
1259
	GPIO_UNLOCK(sc);
1455
	GPIO_UNLOCK(sc);
1260
1456
1261
	sc->busdev = gpiobus_attach_bus(dev);
1457
	sc->busdev = gpiobus_attach_bus(dev);
1262
	if (sc->busdev == NULL) {
1458
	if (sc->busdev == NULL) {
1263
		device_printf(dev, "failed to attach to gpiobus\n");
1459
		device_printf(dev, "failed to attach to gpiobus\n");
1264
		GPIO_LOCK_DESTROY(sc);
1460
		GPIO_LOCK_DESTROY(sc);
1265
		return (ENXIO);
1461
		return (ENXIO);
1266
	}
1462
	}
1267
1463
1268
	return (0);
1464
	return (0);
1269
}
1465
}
1270
1466
1271
static int
1467
static int
1272
nct_detach(device_t dev)
1468
nct_detach(device_t dev)
1273
{
1469
{
1274
	struct nct_softc *sc;
1470
	struct nct_softc *sc;
1275
1471
1276
	sc = device_get_softc(dev);
1472
	sc = device_get_softc(dev);
1277
	gpiobus_detach_bus(dev);
1473
	gpiobus_detach_bus(dev);
1278
1474
1279
	if (sc->iores != NULL)
1475
	if (sc->iores != NULL)
1280
		bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
1476
		bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
1281
	GPIO_ASSERT_UNLOCKED(sc);
1477
	GPIO_ASSERT_UNLOCKED(sc);
1282
	GPIO_LOCK_DESTROY(sc);
1478
	GPIO_LOCK_DESTROY(sc);
1283
1479
1284
	return (0);
1480
	return (0);
1285
}
1481
}
1286
1482
1287
static device_t
1483
static device_t
1288
nct_gpio_get_bus(device_t dev)
1484
nct_gpio_get_bus(device_t dev)
1289
{
1485
{
1290
	struct nct_softc *sc;
1486
	struct nct_softc *sc;
1291
1487
1292
	sc = device_get_softc(dev);
1488
	sc = device_get_softc(dev);
1293
1489
1294
	return (sc->busdev);
1490
	return (sc->busdev);
1295
}
1491
}
1296
1492
1297
static int
1493
static int
1298
nct_gpio_pin_max(device_t dev, int *maxpin)
1494
nct_gpio_pin_max(device_t dev, int *maxpin)
1299
{
1495
{
1300
	struct nct_softc *sc;
1496
	struct nct_softc *sc;
1301
1497
1302
	sc      = device_get_softc(dev);
1498
	sc      = device_get_softc(dev);
(-)b/sys/dev/ncthwm/ncthwm.c (-4 / +21 lines)
Lines 1-213 Link Here
1
/*-
1
/*-
2
 * SPDX-License-Identifier: BSD-2-Clause
2
 * SPDX-License-Identifier: BSD-2-Clause
3
 *
3
 *
4
 * Copyright (c) 2016-2022 Stormshield
4
 * Copyright (c) 2016-2022 Stormshield
5
 *
5
 *
6
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
7
 * modification, are permitted provided that the following conditions
8
 * are met:
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
13
 *    documentation and/or other materials provided with the distribution.
14
 *
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
 * SUCH DAMAGE.
25
 * SUCH DAMAGE.
26
 */
26
 */
27
27
28
#include <sys/cdefs.h>
28
#include <sys/cdefs.h>
29
#include <sys/param.h>
29
#include <sys/param.h>
30
#include <sys/systm.h>
30
#include <sys/systm.h>
31
#include <sys/bus.h>
31
#include <sys/bus.h>
32
#include <sys/kernel.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
33
#include <sys/module.h>
34
#include <sys/rman.h>
34
#include <sys/rman.h>
35
#include <sys/sysctl.h>
35
#include <sys/sysctl.h>
36
#include <sys/watchdog.h>
36
#include <sys/watchdog.h>
37
37
38
#include <dev/superio/superio.h>
38
#include <dev/superio/superio.h>
39
39
40
#include <machine/bus.h>
40
#include <machine/bus.h>
41
#include <machine/resource.h>
41
#include <machine/resource.h>
42
42
43
#define NCTHWM_FAN_MAX                 5
43
#define NCTHWM_FAN_MAX                 5
44
44
45
#define NCTHWM_BANK_SELECT 0x4e
45
#define NCTHWM_BANK_SELECT 0x4e
46
#define NCTHWM_VENDOR_ID   0x4f
46
#define NCTHWM_VENDOR_ID   0x4f
47
47
48
#define NCTHWM_VERBOSE_PRINTF(dev, ...)         \
48
#define NCTHWM_VERBOSE_PRINTF(dev, ...)         \
49
	do {                                        \
49
	do {                                        \
50
		if (__predict_false(bootverbose))       \
50
		if (__predict_false(bootverbose))       \
51
			device_printf(dev, __VA_ARGS__);    \
51
			device_printf(dev, __VA_ARGS__);    \
52
	} while (0)
52
	} while (0)
53
53
54
struct ncthwm_softc {
54
struct ncthwm_softc {
55
	device_t              dev;
55
	device_t              dev;
56
	struct ncthwm_device *nctdevp;
56
	struct ncthwm_device *nctdevp;
57
	struct resource      *iores;
57
	struct resource      *iores;
58
	int                   iorid;
58
	int                   iorid;
59
};
59
};
60
60
61
struct ncthwm_fan_info
61
struct ncthwm_fan_info
62
{
62
{
63
	const char *name;
63
	const char *name;
64
	uint8_t     low_byte_offset;
64
	uint8_t     low_byte_offset;
65
	uint8_t     high_byte_offset;
65
	uint8_t     high_byte_offset;
66
};
66
};
67
67
68
struct ncthwm_device {
68
struct ncthwm_device {
69
	uint16_t                 devid;
69
	uint16_t                 devid;
70
	uint16_t		 mask;
70
	const char              *descr;
71
	const char              *descr;
71
	uint8_t                  base_offset;
72
	uint8_t                  base_offset;
72
	uint8_t                  fan_bank;
73
	uint8_t                  fan_bank;
73
	uint8_t                  fan_count;
74
	uint8_t                  fan_count;
74
	struct ncthwm_fan_info   fan_info[NCTHWM_FAN_MAX];
75
	struct ncthwm_fan_info   fan_info[NCTHWM_FAN_MAX];
75
} ncthwm_devices[] = {
76
} ncthwm_devices[] = {
76
	{
77
	{
77
		.devid       = 0xc562,
78
		.devid       = 0xc562,
78
		.descr       = "HWM on Nuvoton NCT6779D",
79
		.descr       = "HWM on Nuvoton NCT6779D",
79
		.base_offset = 5,
80
		.base_offset = 5,
80
		.fan_bank    = 4,
81
		.fan_bank    = 4,
81
		.fan_count   = 5,
82
		.fan_count   = 5,
82
		.fan_info = {
83
		.fan_info = {
83
			{ .name = "SYSFAN",  .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
84
			{ .name = "SYSFAN",  .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
84
			{ .name = "CPUFAN",  .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
85
			{ .name = "CPUFAN",  .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
85
			{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
86
			{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
86
			{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
87
			{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
87
			{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
88
			{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
88
		},
89
		},
89
	}, {
90
	}, {
90
		.devid       = 0xd42a,
91
		.devid       = 0xd42a,
91
		.descr       = "HWM on Nuvoton NCT6796D-E",
92
		.descr       = "HWM on Nuvoton NCT6796D-E",
92
		.base_offset = 5,
93
		.base_offset = 5,
93
		.fan_bank    = 4,
94
		.fan_bank    = 4,
94
		.fan_count   = 5,
95
		.fan_count   = 5,
95
		.fan_info = {
96
		.fan_info = {
96
			{ .name = "SYSFAN",  .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
97
			{ .name = "SYSFAN",  .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
97
			{ .name = "CPUFAN",  .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
98
			{ .name = "CPUFAN",  .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
98
			{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
99
			{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
99
			{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
100
			{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
100
			{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
101
			{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
101
		},
102
		},
103
	}, {
104
		.devid       = 0xd284,
105
		.mask	     = 0xffdf,
106
		.descr       = "HWM on Nuvoton NCT6122D/NCT6126D",
107
		.base_offset = 5,
108
		.fan_bank    = 0,
109
		.fan_count   = 5,
110
		.fan_info = {
111
			{ .name = "SYSFAN",  .low_byte_offset = 0x31, .high_byte_offset = 0x30 },
112
			{ .name = "CPUFAN",  .low_byte_offset = 0x33, .high_byte_offset = 0x32 },
113
			{ .name = "AUXFAN0", .low_byte_offset = 0x35, .high_byte_offset = 0x34 },
114
			{ .name = "AUXFAN1", .low_byte_offset = 0x37, .high_byte_offset = 0x36 },
115
			{ .name = "AUXFAN2", .low_byte_offset = 0x39, .high_byte_offset = 0x38 },
116
		},
102
	}
117
	}
103
};
118
};
104
119
105
static struct ncthwm_device *
120
static struct ncthwm_device *
106
ncthwm_lookup_device(device_t dev)
121
ncthwm_lookup_device(device_t dev)
107
{
122
{
108
	int      i;
123
	struct ncthwm_device *d = ncthwm_devices;
109
	uint16_t devid;
124
	uint16_t devid;
110
125
111
	devid = superio_devid(dev);
126
	devid = superio_devid(dev);
112
	for (i = 0; i < nitems(ncthwm_devices); i++) {
127
	for (int i = 0; i < nitems(ncthwm_devices); i++, d++) {
113
		if (devid == ncthwm_devices[i].devid)
128
		if (d->devid != (d->mask ? (devid & d->mask) : devid))
114
			return (ncthwm_devices + i);
129
			continue;
130
131
		return (d);
115
	}
132
	}
116
	return (NULL);
133
	return (NULL);
117
}
134
}
118
135
119
static void
136
static void
120
ncthwm_write(struct ncthwm_softc *sc, uint8_t reg, uint8_t val)
137
ncthwm_write(struct ncthwm_softc *sc, uint8_t reg, uint8_t val)
121
{
138
{
122
	bus_write_1(sc->iores, 0, reg);
139
	bus_write_1(sc->iores, 0, reg);
123
	bus_write_1(sc->iores, 1, val);
140
	bus_write_1(sc->iores, 1, val);
124
}
141
}
125
142
126
static uint8_t
143
static uint8_t
127
ncthwm_read(struct ncthwm_softc *sc, uint8_t reg)
144
ncthwm_read(struct ncthwm_softc *sc, uint8_t reg)
128
{
145
{
129
	bus_write_1(sc->iores, 0, reg);
146
	bus_write_1(sc->iores, 0, reg);
130
	return (bus_read_1(sc->iores, 1));
147
	return (bus_read_1(sc->iores, 1));
131
}
148
}
132
149
133
static int
150
static int
134
ncthwm_query_fan_speed(SYSCTL_HANDLER_ARGS)
151
ncthwm_query_fan_speed(SYSCTL_HANDLER_ARGS)
135
{
152
{
136
	struct ncthwm_softc    *sc;
153
	struct ncthwm_softc    *sc;
137
	struct ncthwm_fan_info *fan;
154
	struct ncthwm_fan_info *fan;
138
	uint16_t                val;
155
	uint16_t                val;
139
156
140
	sc = arg1;
157
	sc = arg1;
141
	if (sc == NULL)
158
	if (sc == NULL)
142
		return (EINVAL);
159
		return (EINVAL);
143
160
144
	KASSERT(sc->nctdevp != NULL, ("Unreachable"));
161
	KASSERT(sc->nctdevp != NULL, ("Unreachable"));
145
162
146
	if (sc->nctdevp->fan_count <= arg2)
163
	if (sc->nctdevp->fan_count <= arg2)
147
		return (EINVAL);
164
		return (EINVAL);
148
	fan = &sc->nctdevp->fan_info[arg2];
165
	fan = &sc->nctdevp->fan_info[arg2];
149
166
150
	KASSERT(sc->iores != NULL, ("Unreachable"));
167
	KASSERT(sc->iores != NULL, ("Unreachable"));
151
168
152
	ncthwm_write(sc, NCTHWM_BANK_SELECT, sc->nctdevp->fan_bank);
169
	ncthwm_write(sc, NCTHWM_BANK_SELECT, sc->nctdevp->fan_bank);
153
	val  = ncthwm_read(sc, fan->high_byte_offset) << 8;
170
	val  = ncthwm_read(sc, fan->high_byte_offset) << 8;
154
	val |= ncthwm_read(sc, fan->low_byte_offset);
171
	val |= ncthwm_read(sc, fan->low_byte_offset);
155
172
156
	NCTHWM_VERBOSE_PRINTF(sc->dev, "%s: read %u from bank %u offset 0x%x-0x%x\n",
173
	NCTHWM_VERBOSE_PRINTF(sc->dev, "%s: read %u from bank %u offset 0x%x-0x%x\n",
157
		fan->name, val, sc->nctdevp->fan_bank, fan->high_byte_offset, fan->low_byte_offset);
174
		fan->name, val, sc->nctdevp->fan_bank, fan->high_byte_offset, fan->low_byte_offset);
158
175
159
	return (sysctl_handle_16(oidp, &val, 0, req));
176
	return (sysctl_handle_16(oidp, &val, 0, req));
160
}
177
}
161
178
162
static int
179
static int
163
ncthwm_probe(device_t dev)
180
ncthwm_probe(device_t dev)
164
{
181
{
165
	struct ncthwm_device *nctdevp;
182
	struct ncthwm_device *nctdevp;
166
	uint8_t               ldn;
183
	uint8_t               ldn;
167
184
168
	ldn = superio_get_ldn(dev);
185
	ldn = superio_get_ldn(dev);
169
186
170
	if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
187
	if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
171
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
188
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
172
		return (ENXIO);
189
		return (ENXIO);
173
	}
190
	}
174
	if (superio_get_type(dev) != SUPERIO_DEV_HWM) {
191
	if (superio_get_type(dev) != SUPERIO_DEV_HWM) {
175
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a HWM device\n", ldn);
192
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a HWM device\n", ldn);
176
		return (ENXIO);
193
		return (ENXIO);
177
	}
194
	}
178
195
179
	nctdevp = ncthwm_lookup_device(dev);
196
	nctdevp = ncthwm_lookup_device(dev);
180
	if (nctdevp == NULL) {
197
	if (nctdevp == NULL) {
181
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
198
		NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
182
		return (ENXIO);
199
		return (ENXIO);
183
	}
200
	}
184
	device_set_desc(dev, nctdevp->descr);
201
	device_set_desc(dev, nctdevp->descr);
185
	return (BUS_PROBE_DEFAULT);
202
	return (BUS_PROBE_DEFAULT);
186
}
203
}
187
204
188
static int
205
static int
189
ncthwm_attach(device_t dev)
206
ncthwm_attach(device_t dev)
190
{
207
{
191
	struct ncthwm_softc *sc;
208
	struct ncthwm_softc *sc;
192
	int                  i;
209
	int                  i;
193
	uint16_t             iobase;
210
	uint16_t             iobase;
194
211
195
	sc      = device_get_softc(dev);
212
	sc      = device_get_softc(dev);
196
	sc->dev = dev;
213
	sc->dev = dev;
197
214
198
	sc->nctdevp = ncthwm_lookup_device(dev);
215
	sc->nctdevp = ncthwm_lookup_device(dev);
199
	if (sc->nctdevp == NULL) {
216
	if (sc->nctdevp == NULL) {
200
		device_printf(dev, "device not supported\n");
217
		device_printf(dev, "device not supported\n");
201
		return (ENXIO);
218
		return (ENXIO);
202
	}
219
	}
203
220
204
	iobase    = superio_get_iobase(dev) + sc->nctdevp->base_offset;
221
	iobase    = superio_get_iobase(dev) + sc->nctdevp->base_offset;
205
	sc->iorid = 0;
222
	sc->iorid = 0;
206
	if (bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, iobase, 2) != 0) {
223
	if (bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, iobase, 2) != 0) {
207
		device_printf(dev, "failed to set I/O port resource at 0x%x\n", iobase);
224
		device_printf(dev, "failed to set I/O port resource at 0x%x\n", iobase);
208
		return (ENXIO);
225
		return (ENXIO);
209
	}
226
	}
210
	sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
227
	sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
211
		&sc->iorid, RF_ACTIVE);
228
		&sc->iorid, RF_ACTIVE);
212
	if (sc->iores == NULL) {
229
	if (sc->iores == NULL) {
213
		device_printf(dev, "can't map I/O space at 0x%x\n", iobase);
230
		device_printf(dev, "can't map I/O space at 0x%x\n", iobase);
(-)b/sys/dev/superio/superio.c (-2 / +25 lines)
Lines 200-574 ite_conf_enter(struct resource* res, uint16_t port) Link Here
200
	bus_write_1(res, 0, port == 0x2e ? 0x55 : 0xaa);
200
	bus_write_1(res, 0, port == 0x2e ? 0x55 : 0xaa);
201
}
201
}
202
202
203
static void
203
static void
204
ite_conf_exit(struct resource* res, uint16_t port)
204
ite_conf_exit(struct resource* res, uint16_t port)
205
{
205
{
206
	sio_write(res, 0x02, 0x02);
206
	sio_write(res, 0x02, 0x02);
207
}
207
}
208
208
209
static const struct sio_conf_methods ite_conf_methods = {
209
static const struct sio_conf_methods ite_conf_methods = {
210
	.enter = ite_conf_enter,
210
	.enter = ite_conf_enter,
211
	.exit = ite_conf_exit,
211
	.exit = ite_conf_exit,
212
	.vendor = SUPERIO_VENDOR_ITE
212
	.vendor = SUPERIO_VENDOR_ITE
213
};
213
};
214
214
215
static void
215
static void
216
nvt_conf_enter(struct resource* res, uint16_t port)
216
nvt_conf_enter(struct resource* res, uint16_t port)
217
{
217
{
218
	bus_write_1(res, 0, 0x87);
218
	bus_write_1(res, 0, 0x87);
219
	bus_write_1(res, 0, 0x87);
219
	bus_write_1(res, 0, 0x87);
220
}
220
}
221
221
222
static void
222
static void
223
nvt_conf_exit(struct resource* res, uint16_t port)
223
nvt_conf_exit(struct resource* res, uint16_t port)
224
{
224
{
225
	bus_write_1(res, 0, 0xaa);
225
	bus_write_1(res, 0, 0xaa);
226
}
226
}
227
227
228
static const struct sio_conf_methods nvt_conf_methods = {
228
static const struct sio_conf_methods nvt_conf_methods = {
229
	.enter = nvt_conf_enter,
229
	.enter = nvt_conf_enter,
230
	.exit = nvt_conf_exit,
230
	.exit = nvt_conf_exit,
231
	.vendor = SUPERIO_VENDOR_NUVOTON
231
	.vendor = SUPERIO_VENDOR_NUVOTON
232
};
232
};
233
233
234
static void
234
static void
235
fintek_conf_enter(struct resource* res, uint16_t port)
235
fintek_conf_enter(struct resource* res, uint16_t port)
236
{
236
{
237
	bus_write_1(res, 0, 0x87);
237
	bus_write_1(res, 0, 0x87);
238
	bus_write_1(res, 0, 0x87);
238
	bus_write_1(res, 0, 0x87);
239
}
239
}
240
240
241
static void
241
static void
242
fintek_conf_exit(struct resource* res, uint16_t port)
242
fintek_conf_exit(struct resource* res, uint16_t port)
243
{
243
{
244
	bus_write_1(res, 0, 0xaa);
244
	bus_write_1(res, 0, 0xaa);
245
}
245
}
246
246
247
static const struct sio_conf_methods fintek_conf_methods = {
247
static const struct sio_conf_methods fintek_conf_methods = {
248
	.enter = fintek_conf_enter,
248
	.enter = fintek_conf_enter,
249
	.exit = fintek_conf_exit,
249
	.exit = fintek_conf_exit,
250
	.vendor = SUPERIO_VENDOR_FINTEK
250
	.vendor = SUPERIO_VENDOR_FINTEK
251
};
251
};
252
252
253
static const struct sio_conf_methods * const methods_table[] = {
253
static const struct sio_conf_methods * const methods_table[] = {
254
	&ite_conf_methods,
254
	&ite_conf_methods,
255
	&nvt_conf_methods,
255
	&nvt_conf_methods,
256
	&fintek_conf_methods,
256
	&fintek_conf_methods,
257
	NULL
257
	NULL
258
};
258
};
259
259
260
static const uint16_t ports_table[] = {
260
static const uint16_t ports_table[] = {
261
	0x2e, 0x4e, 0
261
	0x2e, 0x4e, 0
262
};
262
};
263
263
264
const struct sio_device ite_devices[] = {
264
const struct sio_device ite_devices[] = {
265
	{ .ldn = 4, .type = SUPERIO_DEV_HWM },
265
	{ .ldn = 4, .type = SUPERIO_DEV_HWM },
266
	{ .ldn = 7, .type = SUPERIO_DEV_WDT },
266
	{ .ldn = 7, .type = SUPERIO_DEV_WDT },
267
	{ .type = SUPERIO_DEV_NONE },
267
	{ .type = SUPERIO_DEV_NONE },
268
};
268
};
269
269
270
const struct sio_device w83627_devices[] = {
270
const struct sio_device w83627_devices[] = {
271
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
271
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
272
	{ .ldn = 9, .type = SUPERIO_DEV_GPIO },
272
	{ .ldn = 9, .type = SUPERIO_DEV_GPIO },
273
	{ .type = SUPERIO_DEV_NONE },
273
	{ .type = SUPERIO_DEV_NONE },
274
};
274
};
275
275
276
const struct sio_device nvt_devices[] = {
276
const struct sio_device nvt_devices[] = {
277
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
277
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
278
	{ .type = SUPERIO_DEV_NONE },
278
	{ .type = SUPERIO_DEV_NONE },
279
};
279
};
280
280
281
const struct sio_device nct5104_devices[] = {
281
const struct sio_device nct5104_devices[] = {
282
	{ .ldn = 7, .type = SUPERIO_DEV_GPIO },
282
	{ .ldn = 7, .type = SUPERIO_DEV_GPIO },
283
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
283
	{ .ldn = 8, .type = SUPERIO_DEV_WDT },
284
	{ .ldn = 15, .type = SUPERIO_DEV_GPIO },
284
	{ .ldn = 15, .type = SUPERIO_DEV_GPIO },
285
	{ .type = SUPERIO_DEV_NONE },
285
	{ .type = SUPERIO_DEV_NONE },
286
};
286
};
287
287
288
const struct sio_device nct5585_devices[] = {
288
const struct sio_device nct5585_devices[] = {
289
	{ .ldn = 9, .type = SUPERIO_DEV_GPIO },
289
	{ .ldn = 9, .type = SUPERIO_DEV_GPIO },
290
	{ .type = SUPERIO_DEV_NONE },
290
	{ .type = SUPERIO_DEV_NONE },
291
};
291
};
292
292
293
const struct sio_device nct611x_devices[] = {
293
const struct sio_device nct611x_devices[] = {
294
	{ .ldn = 0x7, .type = SUPERIO_DEV_GPIO },
294
	{ .ldn = 0x7, .type = SUPERIO_DEV_GPIO },
295
	{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
295
	{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
296
	{ .type = SUPERIO_DEV_NONE },
296
	{ .type = SUPERIO_DEV_NONE },
297
};
297
};
298
298
299
const struct sio_device nct612x_devices[] = {
300
	{ .ldn = 0x7, .type = SUPERIO_DEV_GPIO },
301
	{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
302
	{ .ldn = 0x9, .type = SUPERIO_DEV_GPIO },
303
	{ .ldn = 0xb, .type = SUPERIO_DEV_HWM },
304
	{ .type = SUPERIO_DEV_NONE },
305
};
306
299
const struct sio_device nct67xx_devices[] = {
307
const struct sio_device nct67xx_devices[] = {
300
	{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
308
	{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
301
	{ .ldn = 0x9, .type = SUPERIO_DEV_GPIO },
309
	{ .ldn = 0x9, .type = SUPERIO_DEV_GPIO },
302
	{ .ldn = 0xb, .type = SUPERIO_DEV_HWM },
310
	{ .ldn = 0xb, .type = SUPERIO_DEV_HWM },
303
	{ .type = SUPERIO_DEV_NONE },
311
	{ .type = SUPERIO_DEV_NONE },
304
};
312
};
305
313
306
const struct sio_device fintek_devices[] = {
314
const struct sio_device fintek_devices[] = {
307
	{ .ldn = 6, .type = SUPERIO_DEV_GPIO },
315
	{ .ldn = 6, .type = SUPERIO_DEV_GPIO },
308
	{ .ldn = 7, .type = SUPERIO_DEV_WDT },
316
	{ .ldn = 7, .type = SUPERIO_DEV_WDT },
309
	{ .type = SUPERIO_DEV_NONE },
317
	{ .type = SUPERIO_DEV_NONE },
310
};
318
};
311
319
312
static const struct {
320
static const struct {
313
	superio_vendor_t	vendor;
321
	superio_vendor_t	vendor;
314
	uint16_t		devid;
322
	uint16_t		devid;
315
	uint16_t		mask;
323
	uint16_t		mask;
316
	int			extid; /* Extra ID: used to handle conflicting devid. */
324
	int			extid; /* Extra ID: used to handle conflicting devid. */
317
	const char		*descr;
325
	const char		*descr;
318
	const struct sio_device	*devices;
326
	const struct sio_device	*devices;
319
} superio_table[] = {
327
} superio_table[] = {
320
	{
328
	{
321
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8613,
329
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8613,
322
		.devices = ite_devices,
330
		.devices = ite_devices,
323
	},
331
	},
324
	{
332
	{
325
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712,
333
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712,
326
		.devices = ite_devices,
334
		.devices = ite_devices,
327
	},
335
	},
328
	{
336
	{
329
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716,
337
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716,
330
		.devices = ite_devices,
338
		.devices = ite_devices,
331
	},
339
	},
332
	{
340
	{
333
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718,
341
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718,
334
		.devices = ite_devices,
342
		.devices = ite_devices,
335
	},
343
	},
336
	{
344
	{
337
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720,
345
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720,
338
		.devices = ite_devices,
346
		.devices = ite_devices,
339
	},
347
	},
340
	{
348
	{
341
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721,
349
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721,
342
		.devices = ite_devices,
350
		.devices = ite_devices,
343
	},
351
	},
344
	{
352
	{
345
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726,
353
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726,
346
		.devices = ite_devices,
354
		.devices = ite_devices,
347
	},
355
	},
348
	{
356
	{
349
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728,
357
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728,
350
		.devices = ite_devices,
358
		.devices = ite_devices,
351
	},
359
	},
352
	{
360
	{
353
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771,
361
		.vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771,
354
		.devices = ite_devices,
362
		.devices = ite_devices,
355
	},
363
	},
356
	{
364
	{
357
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00,
365
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00,
358
		.descr	= "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)",
366
		.descr	= "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)",
359
		.devices = nct5104_devices,
367
		.devices = nct5104_devices,
360
	},
368
	},
361
	{
369
	{
362
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff,
370
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff,
363
		.descr = "Winbond 83627HF/F/HG/G",
371
		.descr = "Winbond 83627HF/F/HG/G",
364
		.devices = nvt_devices,
372
		.devices = nvt_devices,
365
	},
373
	},
366
	{
374
	{
367
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff,
375
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff,
368
		.descr = "Winbond 83627S",
376
		.descr = "Winbond 83627S",
369
		.devices = nvt_devices,
377
		.devices = nvt_devices,
370
	},
378
	},
371
	{
379
	{
372
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff,
380
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff,
373
		.descr = "Winbond 83697HF",
381
		.descr = "Winbond 83697HF",
374
		.devices = nvt_devices,
382
		.devices = nvt_devices,
375
	},
383
	},
376
	{
384
	{
377
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff,
385
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff,
378
		.descr = "Winbond 83697UG",
386
		.descr = "Winbond 83697UG",
379
		.devices = nvt_devices,
387
		.devices = nvt_devices,
380
	},
388
	},
381
	{
389
	{
382
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff,
390
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff,
383
		.descr = "Winbond 83637HF",
391
		.descr = "Winbond 83637HF",
384
		.devices = nvt_devices,
392
		.devices = nvt_devices,
385
	},
393
	},
386
	{
394
	{
387
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff,
395
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff,
388
		.descr = "Winbond 83627THF",
396
		.descr = "Winbond 83627THF",
389
		.devices = nvt_devices,
397
		.devices = nvt_devices,
390
	},
398
	},
391
	{
399
	{
392
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff,
400
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff,
393
		.descr = "Winbond 83687THF",
401
		.descr = "Winbond 83687THF",
394
		.devices = nvt_devices,
402
		.devices = nvt_devices,
395
	},
403
	},
396
	{
404
	{
397
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff,
405
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff,
398
		.descr = "Winbond 83627EHF",
406
		.descr = "Winbond 83627EHF",
399
		.devices = nvt_devices,
407
		.devices = nvt_devices,
400
	},
408
	},
401
	{
409
	{
402
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff,
410
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff,
403
		.descr = "Winbond 83627DHG",
411
		.descr = "Winbond 83627DHG",
404
		.devices = w83627_devices,
412
		.devices = w83627_devices,
405
	},
413
	},
406
	{
414
	{
407
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff,
415
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff,
408
		.descr = "Winbond 83627UHG",
416
		.descr = "Winbond 83627UHG",
409
		.devices = nvt_devices,
417
		.devices = nvt_devices,
410
	},
418
	},
411
	{
419
	{
412
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff,
420
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff,
413
		.descr = "Winbond 83667HG",
421
		.descr = "Winbond 83667HG",
414
		.devices = nvt_devices,
422
		.devices = nvt_devices,
415
	},
423
	},
416
	{
424
	{
417
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff,
425
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff,
418
		.descr = "Winbond 83627DHG-P",
426
		.descr = "Winbond 83627DHG-P",
419
		.devices = nvt_devices,
427
		.devices = nvt_devices,
420
	},
428
	},
421
	{
429
	{
422
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff,
430
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff,
423
		.descr = "Winbond 83667HG-B",
431
		.descr = "Winbond 83667HG-B",
424
		.devices = nvt_devices,
432
		.devices = nvt_devices,
425
	},
433
	},
426
	{
434
	{
427
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff,
435
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff,
428
		.descr = "Nuvoton NCT6775",
436
		.descr = "Nuvoton NCT6775",
429
		.devices = nvt_devices,
437
		.devices = nvt_devices,
430
	},
438
	},
431
	{
439
	{
432
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff,
440
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff,
433
		.descr = "Nuvoton NCT6776",
441
		.descr = "Nuvoton NCT6776",
434
		.devices = nvt_devices,
442
		.devices = nvt_devices,
435
	},
443
	},
436
	{
444
	{
437
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff,
445
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff,
438
		.descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)",
446
		.descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)",
439
		.devices = nct5104_devices,
447
		.devices = nct5104_devices,
440
	},
448
	},
441
	{
449
	{
442
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff,
450
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff,
443
		.descr   = "Nuvoton NCT6779D",
451
		.descr   = "Nuvoton NCT6779D",
444
		.devices = nct67xx_devices,
452
		.devices = nct67xx_devices,
445
	},
453
	},
446
	{
454
	{
447
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 1,
455
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 1,
448
		.descr   = "Nuvoton NCT6796D-E",
456
		.descr   = "Nuvoton NCT6796D-E",
449
		.devices = nct67xx_devices,
457
		.devices = nct67xx_devices,
450
	},
458
	},
451
	{
459
	{
452
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 2,
460
		.vendor  = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 2,
453
		.descr   = "Nuvoton NCT5585D",
461
		.descr   = "Nuvoton NCT5585D",
454
		.devices = nct5585_devices,
462
		.devices = nct5585_devices,
455
	},
463
	},
456
	{
464
	{
457
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff,
465
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff,
458
		.descr = "Nuvoton NCT6791",
466
		.descr = "Nuvoton NCT6791",
459
		.devices = nvt_devices,
467
		.devices = nvt_devices,
460
	},
468
	},
461
	{
469
	{
462
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff,
470
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff,
463
		.descr = "Nuvoton NCT6792",
471
		.descr = "Nuvoton NCT6792",
464
		.devices = nvt_devices,
472
		.devices = nvt_devices,
465
	},
473
	},
466
	{
474
	{
467
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff,
475
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff,
468
		.descr = "Nuvoton NCT6793",
476
		.descr = "Nuvoton NCT6793",
469
		.devices = nvt_devices,
477
		.devices = nvt_devices,
470
	},
478
	},
471
	{
479
	{
472
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd200, .mask = 0xff,
480
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd282,
473
		.descr = "Nuvoton NCT6112D/NCT6114D/NCT6116D",
481
		.descr = "Nuvoton NCT6112D",	// 2 UART
474
		.devices = nct611x_devices,
482
		.devices = nct611x_devices,
475
	},
483
	},
484
	{
485
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd280, .mask = 0x0003,
486
		.descr = "Nuvoton NCT6114D/NCT6116D",	// 4/6 UART - 0xd281? 0xd283?
487
		.devices = nct611x_devices,
488
	},
489
	{
490
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd2A4,
491
		.descr = "Nuvoton NCT6122D",	// 2 UART
492
		.devices = nct612x_devices,
493
	},
494
	{
495
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd284,
496
		.descr = "Nuvoton NCT6126D",	// 6 UART
497
		.devices = nct612x_devices,
498
	},
476
	{
499
	{
477
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff,
500
		.vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff,
478
		.descr = "Nuvoton NCT6795",
501
		.descr = "Nuvoton NCT6795",
479
		.devices = nvt_devices,
502
		.devices = nvt_devices,
480
	},
503
	},
481
	{
504
	{
482
		.vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x1210, .mask = 0xff,
505
		.vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x1210, .mask = 0xff,
483
		.descr = "Fintek F81803",
506
		.descr = "Fintek F81803",
484
		.devices = fintek_devices,
507
		.devices = fintek_devices,
485
	},
508
	},
486
	{
509
	{
487
		.vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x0704,
510
		.vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x0704,
488
		.descr = "Fintek F81865",
511
		.descr = "Fintek F81865",
489
		.devices = fintek_devices,
512
		.devices = fintek_devices,
490
	},
513
	},
491
	{ 0, 0 }
514
	{ 0, 0 }
492
};
515
};
493
516
494
static const char *
517
static const char *
495
devtype_to_str(superio_dev_type_t type)
518
devtype_to_str(superio_dev_type_t type)
496
{
519
{
497
	switch (type) {
520
	switch (type) {
498
	case SUPERIO_DEV_NONE:
521
	case SUPERIO_DEV_NONE:
499
		return ("none");
522
		return ("none");
500
	case SUPERIO_DEV_HWM:
523
	case SUPERIO_DEV_HWM:
501
		return ("HWM");
524
		return ("HWM");
502
	case SUPERIO_DEV_WDT:
525
	case SUPERIO_DEV_WDT:
503
		return ("WDT");
526
		return ("WDT");
504
	case SUPERIO_DEV_GPIO:
527
	case SUPERIO_DEV_GPIO:
505
		return ("GPIO");
528
		return ("GPIO");
506
	case SUPERIO_DEV_MAX:
529
	case SUPERIO_DEV_MAX:
507
		return ("invalid");
530
		return ("invalid");
508
	}
531
	}
509
	return ("invalid");
532
	return ("invalid");
510
}
533
}
511
534
512
static int
535
static int
513
superio_detect(device_t dev, bool claim, struct siosc *sc)
536
superio_detect(device_t dev, bool claim, struct siosc *sc)
514
{
537
{
515
	struct resource *res;
538
	struct resource *res;
516
	rman_res_t port;
539
	rman_res_t port;
517
	rman_res_t count;
540
	rman_res_t count;
518
	uint16_t devid;
541
	uint16_t devid;
519
	uint8_t revid;
542
	uint8_t revid;
520
	int error;
543
	int error;
521
	int rid;
544
	int rid;
522
	int i, m;
545
	int i, m;
523
	int prefer;
546
	int prefer;
524
547
525
	error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count);
548
	error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count);
526
	if (error != 0)
549
	if (error != 0)
527
		return (error);
550
		return (error);
528
	if (port > UINT16_MAX || count < NUMPORTS) {
551
	if (port > UINT16_MAX || count < NUMPORTS) {
529
		device_printf(dev, "unexpected I/O range size\n");
552
		device_printf(dev, "unexpected I/O range size\n");
530
		return (ENXIO);
553
		return (ENXIO);
531
	}
554
	}
532
555
533
	/*
556
	/*
534
	 * Make a temporary resource reservation for hardware probing.
557
	 * Make a temporary resource reservation for hardware probing.
535
	 * If we can't get the resources we need then
558
	 * If we can't get the resources we need then
536
	 * we need to abort.  Possibly this indicates
559
	 * we need to abort.  Possibly this indicates
537
	 * the resources were used by another device
560
	 * the resources were used by another device
538
	 * in which case the probe would have failed anyhow.
561
	 * in which case the probe would have failed anyhow.
539
	 */
562
	 */
540
	rid = 0;
563
	rid = 0;
541
	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
564
	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
542
	if (res == NULL) {
565
	if (res == NULL) {
543
		if (claim)
566
		if (claim)
544
			device_printf(dev, "failed to allocate I/O resource\n");
567
			device_printf(dev, "failed to allocate I/O resource\n");
545
		return (ENXIO);
568
		return (ENXIO);
546
	}
569
	}
547
570
548
	prefer = 0;
571
	prefer = 0;
549
	resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer", &prefer);
572
	resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer", &prefer);
550
	if (bootverbose && prefer > 0)
573
	if (bootverbose && prefer > 0)
551
		device_printf(dev, "prefer extid %d\n", prefer);
574
		device_printf(dev, "prefer extid %d\n", prefer);
552
575
553
	for (m = 0; methods_table[m] != NULL; m++) {
576
	for (m = 0; methods_table[m] != NULL; m++) {
554
		methods_table[m]->enter(res, port);
577
		methods_table[m]->enter(res, port);
555
		if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) {
578
		if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) {
556
			devid = sio_readw(res, 0x20);
579
			devid = sio_readw(res, 0x20);
557
			revid = sio_read(res, 0x22);
580
			revid = sio_read(res, 0x22);
558
		} else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) {
581
		} else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) {
559
			devid = sio_read(res, 0x20);
582
			devid = sio_read(res, 0x20);
560
			revid = sio_read(res, 0x21);
583
			revid = sio_read(res, 0x21);
561
			devid = (devid << 8) | revid;
584
			devid = (devid << 8) | revid;
562
		} else if (methods_table[m]->vendor == SUPERIO_VENDOR_FINTEK) {
585
		} else if (methods_table[m]->vendor == SUPERIO_VENDOR_FINTEK) {
563
			devid = sio_read(res, 0x20);
586
			devid = sio_read(res, 0x20);
564
			revid = sio_read(res, 0x21);
587
			revid = sio_read(res, 0x21);
565
			devid = (devid << 8) | revid;
588
			devid = (devid << 8) | revid;
566
		} else {
589
		} else {
567
			continue;
590
			continue;
568
		}
591
		}
569
		methods_table[m]->exit(res, port);
592
		methods_table[m]->exit(res, port);
570
		for (i = 0; superio_table[i].vendor != 0; i++) {
593
		for (i = 0; superio_table[i].vendor != 0; i++) {
571
			uint16_t mask;
594
			uint16_t mask;
572
595
573
			mask = superio_table[i].mask;
596
			mask = superio_table[i].mask;
574
			if (superio_table[i].vendor !=
597
			if (superio_table[i].vendor !=

Return to bug 282738