1 /*- 2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * Broadcom BHND PCIe-Gen2 PCI-Host Bridge. 35 * 36 * This driver handles all interactions with PCIe-G2 bridge cores operating in 37 * endpoint mode. 38 * 39 * Host-level PCI operations are handled at the bhndb bridge level by the 40 * bhndb_pci driver. 41 */ 42 43 // TODO 44 // 45 // A full survey of known quirks/work-arounds has not been completed. 46 // 47 // Work-arounds for the following are not yet implemented: 48 // - BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH 49 // 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards 50 // BCM94360X51P2, BCM94360X51A) 51 52 #include <sys/param.h> 53 #include <sys/kernel.h> 54 55 #include <sys/malloc.h> 56 57 #include <sys/bus.h> 58 #include <sys/module.h> 59 60 #include <sys/systm.h> 61 62 #include <machine/bus.h> 63 #include <sys/rman.h> 64 #include <machine/resource.h> 65 66 #include <dev/bhnd/bhnd.h> 67 68 #include <dev/pci/pcireg.h> 69 #include <dev/pci/pcivar.h> 70 71 #include "bhnd_pcie2_reg.h" 72 #include "bhnd_pcie2_hostbvar.h" 73 74 static const struct bhnd_device_quirk bhnd_pcie2_quirks[]; 75 76 77 static int bhnd_pcie2_wars_early_once(struct bhnd_pcie2hb_softc *sc); 78 static int bhnd_pcie2_wars_hwup(struct bhnd_pcie2hb_softc *sc); 79 static int bhnd_pcie2_wars_hwdown(struct bhnd_pcie2hb_softc *sc); 80 81 /* 82 * device/quirk tables 83 */ 84 85 #define BHND_PCI_DEV(_core, _quirks) \ 86 BHND_DEVICE(BCM, _core, NULL, _quirks, BHND_DF_HOSTB) 87 88 static const struct bhnd_device bhnd_pcie2_devs[] = { 89 BHND_PCI_DEV(PCIE2, bhnd_pcie2_quirks), 90 BHND_DEVICE_END 91 }; 92 93 static const struct bhnd_device_quirk bhnd_pcie2_quirks[] = { 94 /* Apple BCM4360 boards that require adjusting TX amplitude and 95 * differential output de-emphasis of the PCIe SerDes */ 96 {{ BHND_MATCH_BOARD(PCI_VENDOR_APPLE, BCM94360X51P2), }, 97 BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH }, 98 {{ BHND_MATCH_BOARD(PCI_VENDOR_APPLE, BCM94360X51A), }, 99 BHND_PCIE2_QUIRK_SERDES_TXDRV_DEEMPH }, 100 101 BHND_DEVICE_QUIRK_END 102 }; 103 104 static int 105 bhnd_pcie2_hostb_attach(device_t dev) 106 { 107 struct bhnd_pcie2hb_softc *sc; 108 int error; 109 110 sc = device_get_softc(dev); 111 sc->dev = dev; 112 sc->quirks = bhnd_device_quirks(dev, bhnd_pcie2_devs, 113 sizeof(bhnd_pcie2_devs[0])); 114 115 /* Find the host PCI bridge device */ 116 sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci")); 117 if (sc->pci_dev == NULL) { 118 device_printf(dev, "parent pci bridge device not found\n"); 119 return (ENXIO); 120 } 121 122 /* Common setup */ 123 if ((error = bhnd_pcie2_generic_attach(dev))) 124 return (error); 125 126 127 /* Apply early single-shot work-arounds */ 128 if ((error = bhnd_pcie2_wars_early_once(sc))) 129 goto failed; 130 131 132 /* Apply attach/resume work-arounds */ 133 if ((error = bhnd_pcie2_wars_hwup(sc))) 134 goto failed; 135 136 137 return (0); 138 139 failed: 140 bhnd_pcie2_generic_detach(dev); 141 return (error); 142 } 143 144 static int 145 bhnd_pcie2_hostb_detach(device_t dev) 146 { 147 struct bhnd_pcie2hb_softc *sc; 148 int error; 149 150 sc = device_get_softc(dev); 151 152 /* Apply suspend/detach work-arounds */ 153 if ((error = bhnd_pcie2_wars_hwdown(sc))) 154 return (error); 155 156 return (bhnd_pcie2_generic_detach(dev)); 157 } 158 159 static int 160 bhnd_pcie2_hostb_suspend(device_t dev) 161 { 162 struct bhnd_pcie2hb_softc *sc; 163 int error; 164 165 sc = device_get_softc(dev); 166 167 /* Apply suspend/detach work-arounds */ 168 if ((error = bhnd_pcie2_wars_hwdown(sc))) 169 return (error); 170 171 return (bhnd_pcie2_generic_suspend(dev)); 172 } 173 174 static int 175 bhnd_pcie2_hostb_resume(device_t dev) 176 { 177 struct bhnd_pcie2hb_softc *sc; 178 int error; 179 180 sc = device_get_softc(dev); 181 182 if ((error = bhnd_pcie2_generic_resume(dev))) 183 return (error); 184 185 /* Apply attach/resume work-arounds */ 186 if ((error = bhnd_pcie2_wars_hwup(sc))) { 187 bhnd_pcie2_generic_detach(dev); 188 return (error); 189 } 190 191 return (0); 192 } 193 194 /** 195 * Apply any hardware work-arounds that must be executed exactly once, early in 196 * the attach process. 197 * 198 * This must be called after core enumeration and discovery of all applicable 199 * quirks, but prior to probe/attach of any cores, parsing of 200 * SPROM, etc. 201 */ 202 static int 203 bhnd_pcie2_wars_early_once(struct bhnd_pcie2hb_softc *sc) 204 { 205 // TODO 206 return (ENXIO); 207 } 208 209 /** 210 * Apply any hardware workarounds that are required upon attach or resume 211 * of the bridge device. 212 */ 213 static int 214 bhnd_pcie2_wars_hwup(struct bhnd_pcie2hb_softc *sc) 215 { 216 // TODO 217 return (ENXIO); 218 } 219 220 /** 221 * Apply any hardware workarounds that are required upon detach or suspend 222 * of the bridge device. 223 */ 224 static int 225 bhnd_pcie2_wars_hwdown(struct bhnd_pcie2hb_softc *sc) 226 { 227 // TODO 228 return (ENXIO); 229 } 230 231 static device_method_t bhnd_pcie2_hostb_methods[] = { 232 /* Device interface */ 233 DEVMETHOD(device_attach, bhnd_pcie2_hostb_attach), 234 DEVMETHOD(device_detach, bhnd_pcie2_hostb_detach), 235 DEVMETHOD(device_suspend, bhnd_pcie2_hostb_suspend), 236 DEVMETHOD(device_resume, bhnd_pcie2_hostb_resume), 237 238 DEVMETHOD_END 239 }; 240 241 DEFINE_CLASS_1(bhnd_hostb, bhnd_pcie2_hostb_driver, 242 bhnd_pcie2_hostb_methods, sizeof(struct bhnd_pcie2hb_softc), 243 bhnd_pcie2_driver); 244 245 DRIVER_MODULE(bhnd_pcie2_hostb, bhnd, bhnd_pcie2_hostb_driver, bhnd_hostb_devclass, 0, 0); 246 247 MODULE_VERSION(bhnd_pcie2_hostb, 1); 248 MODULE_DEPEND(bhnd_pcie2_hostb, bhnd, 1, 1, 1); 249 MODULE_DEPEND(bhnd_pcie2_hostb, bhnd_pcie2, 1, 1, 1); 250