xref: /openbsd/sys/dev/pci/com_pci.c (revision 0f9891f1)
1 /* $OpenBSD: com_pci.c,v 1.4 2024/05/24 06:02:53 jsg 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/tty.h>
21 
22 #include <dev/pci/pcidevs.h>
23 #include <dev/pci/pcireg.h>
24 #include <dev/pci/pcivar.h>
25 
26 #include <dev/ic/comreg.h>
27 #include <dev/ic/comvar.h>
28 
29 #define com_usr 31	/* Synopsys DesignWare UART */
30 
31 /* Intel Low Power Subsystem */
32 #define LPSS_CLK		0x200
33 #define  LPSS_CLK_GATE			(1 << 0)
34 #define  LPSS_CLK_MDIV_SHIFT		1
35 #define  LPSS_CLK_MDIV_MASK		0x3fff
36 #define  LPSS_CLK_NDIV_SHIFT		16
37 #define  LPSS_CLK_NDIV_MASK		0x3fff
38 #define  LPSS_CLK_UPDATE		(1U << 31)
39 #define LPSS_RESETS		0x204
40 #define  LPSS_RESETS_FUNC		(3 << 0)
41 #define  LPSS_RESETS_IDMA		(1 << 2)
42 #define LPSS_ACTIVELTR		0x210
43 #define LPSS_IDLELTR		0x214
44 #define  LPSS_LTR_VALUE_MASK		(0x3ff << 0)
45 #define  LPSS_LTR_SCALE_MASK		(0x3 << 10)
46 #define  LPSS_LTR_SCALE_1US		(2 << 10)
47 #define  LPSS_LTR_SCALE_32US		(3 << 10)
48 #define  LPSS_LTR_REQ			(1 << 15)
49 #define LPSS_SSP		0x220
50 #define  LPSS_SSP_DIS_DMA_FIN		(1 << 0)
51 #define LPSS_REMAP_ADDR		0x240
52 #define LPSS_CAPS		0x2fc
53 #define  LPSS_CAPS_TYPE_I2C		(0 << 4)
54 #define  LPSS_CAPS_TYPE_UART		(1 << 4)
55 #define  LPSS_CAPS_TYPE_SPI		(2 << 4)
56 #define  LPSS_CAPS_TYPE_MASK		(0xf << 4)
57 #define  LPSS_CAPS_NO_IDMA		(1 << 8)
58 
59 #define LPSS_REG_OFF		0x200
60 #define LPSS_REG_SIZE		0x100
61 #define LPSS_REG_NUM		(LPSS_REG_SIZE / sizeof(uint32_t))
62 
63 #define HREAD4(sc, reg)							\
64 	(bus_space_read_4((sc)->sc.sc_iot, (sc)->sc.sc_ioh, (reg)))
65 #define HWRITE4(sc, reg, val)						\
66 	bus_space_write_4((sc)->sc.sc_iot, (sc)->sc.sc_ioh, (reg), (val))
67 #define HSET4(sc, reg, bits)						\
68 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
69 #define HCLR4(sc, reg, bits)						\
70 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
71 
72 int	com_pci_match(struct device *, void *, void *);
73 void	com_pci_attach(struct device *, struct device *, void *);
74 int	com_pci_detach(struct device *, int);
75 int	com_pci_activate(struct device *, int);
76 int	com_pci_intr_designware(void *);
77 
78 struct com_pci_softc {
79 	struct com_softc	 sc;
80 	pci_chipset_tag_t	 sc_pc;
81 	pcireg_t		 sc_id;
82 
83 	bus_size_t		 sc_ios;
84 	void			*sc_ih;
85 
86 	uint32_t		 sc_priv[LPSS_REG_NUM];
87 };
88 
89 const struct cfattach com_pci_ca = {
90 	sizeof(struct com_pci_softc), com_pci_match,
91 	com_pci_attach, com_pci_detach, com_pci_activate,
92 };
93 
94 const struct pci_matchid com_pci_ids[] = {
95 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_1 },
96 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_2 },
97 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_3 },
98 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_UART_4 },
99 };
100 
101 int
com_pci_match(struct device * parent,void * match,void * aux)102 com_pci_match(struct device *parent, void *match, void *aux)
103 {
104 	return (pci_matchbyid(aux, com_pci_ids, nitems(com_pci_ids)));
105 }
106 
107 void
com_pci_attach(struct device * parent,struct device * self,void * aux)108 com_pci_attach(struct device *parent, struct device *self, void *aux)
109 {
110 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
111 	struct pci_attach_args *pa = aux;
112 	pci_intr_handle_t ih;
113 	const char *intrstr;
114 	uint64_t freq, m, n;
115 	uint32_t caps;
116 
117 	sc->sc_pc = pa->pa_pc;
118 	sc->sc_id = pa->pa_id;
119 	sc->sc.sc_frequency = COM_FREQ;
120 	sc->sc.sc_uarttype = COM_UART_16550;
121 	sc->sc.sc_reg_width = 4;
122 	sc->sc.sc_reg_shift = 2;
123 
124 	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
125 
126 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
127 	    &sc->sc.sc_iot, &sc->sc.sc_ioh, &sc->sc.sc_iobase, &sc->sc_ios, 0)) {
128 		printf(": can't map mem space\n");
129 		return;
130 	}
131 
132 	/*
133 	 * Once we are adding non-Intel and non-LPSS device it will make
134 	 * sense to add a second table and use pci_matchbyid().
135 	 */
136 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
137 		caps = HREAD4(sc, LPSS_CAPS);
138 		if ((caps & LPSS_CAPS_TYPE_MASK) != LPSS_CAPS_TYPE_UART) {
139 			bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh,
140 			    sc->sc_ios);
141 			printf(": not a UART\n");
142 			return;
143 		}
144 
145 		HWRITE4(sc, LPSS_RESETS, 0);
146 		HWRITE4(sc, LPSS_RESETS, LPSS_RESETS_FUNC | LPSS_RESETS_IDMA);
147 		HWRITE4(sc, LPSS_REMAP_ADDR, sc->sc.sc_iobase);
148 
149 		/* 100 MHz base clock */
150 		freq = 100 * 1000 * 1000;
151 		m = n = HREAD4(sc, LPSS_CLK);
152 		m = (m >> LPSS_CLK_MDIV_SHIFT) & LPSS_CLK_MDIV_MASK;
153 		n = (n >> LPSS_CLK_NDIV_SHIFT) & LPSS_CLK_NDIV_MASK;
154 		if (m && n) {
155 			freq *= m;
156 			freq /= n;
157 		}
158 		sc->sc.sc_frequency = freq;
159 	}
160 
161 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
162 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
163 		printf(": unable to map interrupt\n");
164 		return;
165 	}
166 
167 	intrstr = pci_intr_string(pa->pa_pc, ih);
168 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
169 	    com_pci_intr_designware, &sc->sc, sc->sc.sc_dev.dv_xname);
170 	if (sc->sc_ih == NULL) {
171 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
172 		printf(": can't establish interrupt");
173 		if (intrstr != NULL)
174 			printf(" at %s", intrstr);
175 		printf("\n");
176 		return;
177 	}
178 
179 	com_attach_subr(&sc->sc);
180 }
181 
182 int
com_pci_detach(struct device * self,int flags)183 com_pci_detach(struct device *self, int flags)
184 {
185 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
186 	int rv;
187 
188 	rv = com_detach(self, flags);
189 	if (rv != 0)
190 		return (rv);
191 	if (sc->sc_ih != NULL) {
192 		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
193 		sc->sc_ih = NULL;
194 	}
195 	if (sc->sc_ios != 0) {
196 		bus_space_unmap(sc->sc.sc_iot, sc->sc.sc_ioh, sc->sc_ios);
197 		sc->sc_ios = 0;
198 	}
199 
200 	return (rv);
201 }
202 
203 int
com_pci_activate(struct device * self,int act)204 com_pci_activate(struct device *self, int act)
205 {
206 	struct com_pci_softc *sc = (struct com_pci_softc *)self;
207 	int i, rv = 0;
208 
209 	if (PCI_VENDOR(sc->sc_id) != PCI_VENDOR_INTEL)
210 		return com_activate(self, act);
211 
212 	switch (act) {
213 	case DVACT_RESUME:
214 		for (i = 0; i < LPSS_REG_NUM; i++)
215 			HWRITE4(sc, i * sizeof(uint32_t), sc->sc_priv[i]);
216 		rv = com_activate(self, act);
217 		break;
218 	case DVACT_SUSPEND:
219 		rv = com_activate(self, act);
220 		for (i = 0; i < LPSS_REG_NUM; i++)
221 			sc->sc_priv[i] = HREAD4(sc, i * sizeof(uint32_t));
222 		break;
223 	default:
224 		rv = com_activate(self, act);
225 		break;
226 	}
227 
228 	return (rv);
229 }
230 
231 int
com_pci_intr_designware(void * cookie)232 com_pci_intr_designware(void *cookie)
233 {
234 	struct com_softc *sc = cookie;
235 
236 	com_read_reg(sc, com_usr);
237 
238 	return comintr(sc);
239 }
240