xref: /openbsd/sys/dev/pci/com_pci.c (revision 4bdff4be)
1 /* $OpenBSD: com_pci.c,v 1.3 2023/09/11 08:41:26 mvs Exp $ */
2 /*
3  * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/kernel.h>
21 #include <sys/tty.h>
22 
23 #include <dev/pci/pcidevs.h>
24 #include <dev/pci/pcireg.h>
25 #include <dev/pci/pcivar.h>
26 
27 #include <dev/ic/comreg.h>
28 #include <dev/ic/comvar.h>
29 #include <dev/ic/ns16550reg.h>
30 
31 #define com_usr 31	/* Synopsys DesignWare UART */
32 
33 /* Intel Low Power Subsystem */
34 #define LPSS_CLK		0x200
35 #define  LPSS_CLK_GATE			(1 << 0)
36 #define  LPSS_CLK_MDIV_SHIFT		1
37 #define  LPSS_CLK_MDIV_MASK		0x3fff
38 #define  LPSS_CLK_NDIV_SHIFT		16
39 #define  LPSS_CLK_NDIV_MASK		0x3fff
40 #define  LPSS_CLK_UPDATE		(1U << 31)
41 #define LPSS_RESETS		0x204
42 #define  LPSS_RESETS_FUNC		(3 << 0)
43 #define  LPSS_RESETS_IDMA		(1 << 2)
44 #define LPSS_ACTIVELTR		0x210
45 #define LPSS_IDLELTR		0x214
46 #define  LPSS_LTR_VALUE_MASK		(0x3ff << 0)
47 #define  LPSS_LTR_SCALE_MASK		(0x3 << 10)
48 #define  LPSS_LTR_SCALE_1US		(2 << 10)
49 #define  LPSS_LTR_SCALE_32US		(3 << 10)
50 #define  LPSS_LTR_REQ			(1 << 15)
51 #define LPSS_SSP		0x220
52 #define  LPSS_SSP_DIS_DMA_FIN		(1 << 0)
53 #define LPSS_REMAP_ADDR		0x240
54 #define LPSS_CAPS		0x2fc
55 #define  LPSS_CAPS_TYPE_I2C		(0 << 4)
56 #define  LPSS_CAPS_TYPE_UART		(1 << 4)
57 #define  LPSS_CAPS_TYPE_SPI		(2 << 4)
58 #define  LPSS_CAPS_TYPE_MASK		(0xf << 4)
59 #define  LPSS_CAPS_NO_IDMA		(1 << 8)
60 
61 #define LPSS_REG_OFF		0x200
62 #define LPSS_REG_SIZE		0x100
63 #define LPSS_REG_NUM		(LPSS_REG_SIZE / sizeof(uint32_t))
64 
65 #define HREAD4(sc, reg)							\
66 	(bus_space_read_4((sc)->sc.sc_iot, (sc)->sc.sc_ioh, (reg)))
67 #define HWRITE4(sc, reg, val)						\
68 	bus_space_write_4((sc)->sc.sc_iot, (sc)->sc.sc_ioh, (reg), (val))
69 #define HSET4(sc, reg, bits)						\
70 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
71 #define HCLR4(sc, reg, bits)						\
72 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
73 
74 int	com_pci_match(struct device *, void *, void *);
75 void	com_pci_attach(struct device *, struct device *, void *);
76 int	com_pci_detach(struct device *, int);
77 int	com_pci_activate(struct device *, int);
78 int	com_pci_intr_designware(void *);
79 
80 struct com_pci_softc {
81 	struct com_softc	 sc;
82 	pci_chipset_tag_t	 sc_pc;
83 	pcireg_t		 sc_id;
84 
85 	bus_size_t		 sc_ios;
86 	void			*sc_ih;
87 
88 	uint32_t		 sc_priv[LPSS_REG_NUM];
89 };
90 
91 const struct cfattach com_pci_ca = {
92 	sizeof(struct com_pci_softc), com_pci_match,
93 	com_pci_attach, com_pci_detach, com_pci_activate,
94 };
95 
96 const struct pci_matchid com_pci_ids[] = {
97 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_1 },
98 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_2 },
99 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_3 },
100 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_4 },
101 };
102 
103 int
104 com_pci_match(struct device *parent, void *match, void *aux)
105 {
106 	return (pci_matchbyid(aux, com_pci_ids, nitems(com_pci_ids)));
107 }
108 
109 void
110 com_pci_attach(struct device *parent, struct device *self, void *aux)
111 {
112 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
113 	struct pci_attach_args *pa = aux;
114 	pci_intr_handle_t ih;
115 	const char *intrstr;
116 	uint64_t freq, m, n;
117 	uint32_t caps;
118 
119 	sc->sc_pc = pa->pa_pc;
120 	sc->sc_id = pa->pa_id;
121 	sc->sc.sc_frequency = COM_FREQ;
122 	sc->sc.sc_uarttype = COM_UART_16550;
123 	sc->sc.sc_reg_width = 4;
124 	sc->sc.sc_reg_shift = 2;
125 
126 	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
127 
128 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
129 	    &sc->sc.sc_iot, &sc->sc.sc_ioh, &sc->sc.sc_iobase, &sc->sc_ios, 0)) {
130 		printf(": can't map mem space\n");
131 		return;
132 	}
133 
134 	/*
135 	 * Once we are adding non-Intel and non-LPSS device it will make
136 	 * sense to add a second table and use pci_matchbyid().
137 	 */
138 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
139 		caps = HREAD4(sc, LPSS_CAPS);
140 		if ((caps & LPSS_CAPS_TYPE_MASK) != LPSS_CAPS_TYPE_UART) {
141 			bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh,
142 			    sc->sc_ios);
143 			printf(": not a UART\n");
144 			return;
145 		}
146 
147 		HWRITE4(sc, LPSS_RESETS, 0);
148 		HWRITE4(sc, LPSS_RESETS, LPSS_RESETS_FUNC | LPSS_RESETS_IDMA);
149 		HWRITE4(sc, LPSS_REMAP_ADDR, sc->sc.sc_iobase);
150 
151 		/* 100 MHz base clock */
152 		freq = 100 * 1000 * 1000;
153 		m = n = HREAD4(sc, LPSS_CLK);
154 		m = (m >> LPSS_CLK_MDIV_SHIFT) & LPSS_CLK_MDIV_MASK;
155 		n = (n >> LPSS_CLK_NDIV_SHIFT) & LPSS_CLK_NDIV_MASK;
156 		if (m && n) {
157 			freq *= m;
158 			freq /= n;
159 		}
160 		sc->sc.sc_frequency = freq;
161 	}
162 
163 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
164 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
165 		printf(": unable to map interrupt\n");
166 		return;
167 	}
168 
169 	intrstr = pci_intr_string(pa->pa_pc, ih);
170 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
171 	    com_pci_intr_designware, &sc->sc, sc->sc.sc_dev.dv_xname);
172 	if (sc->sc_ih == NULL) {
173 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
174 		printf(": can't establish interrupt");
175 		if (intrstr != NULL)
176 			printf(" at %s", intrstr);
177 		printf("\n");
178 		return;
179 	}
180 
181 	com_attach_subr(&sc->sc);
182 }
183 
184 int
185 com_pci_detach(struct device *self, int flags)
186 {
187 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
188 	int rv;
189 
190 	rv = com_detach(self, flags);
191 	if (rv != 0)
192 		return (rv);
193 	if (sc->sc_ih != NULL) {
194 		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
195 		sc->sc_ih = NULL;
196 	}
197 	if (sc->sc_ios != 0) {
198 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
199 		sc->sc_ios = 0;
200 	}
201 
202 	return (rv);
203 }
204 
205 int
206 com_pci_activate(struct device *self, int act)
207 {
208 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
209 	int i, rv = 0;
210 
211 	if (PCI_VENDOR(sc->sc_id) != PCI_VENDOR_INTEL)
212 		return com_activate(self, act);
213 
214 	switch (act) {
215 	case DVACT_RESUME:
216 		for (i = 0; i < LPSS_REG_NUM; i++)
217 			HWRITE4(sc, i * sizeof(uint32_t), sc->sc_priv[i]);
218 		rv = com_activate(self, act);
219 		break;
220 	case DVACT_SUSPEND:
221 		rv = com_activate(self, act);
222 		for (i = 0; i < LPSS_REG_NUM; i++)
223 			sc->sc_priv[i] = HREAD4(sc, i * sizeof(uint32_t));
224 		break;
225 	default:
226 		rv = com_activate(self, act);
227 		break;
228 	}
229 
230 	return (rv);
231 }
232 
233 int
234 com_pci_intr_designware(void *cookie)
235 {
236 	struct com_softc *sc = cookie;
237 
238 	com_read_reg(sc, com_usr);
239 
240 	return comintr(sc);
241 }
242