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