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