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