bhnd_pcie2_hostb.c revision 302408
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: stable/11/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c 301697 2016-06-08 21:31:33Z landonf $"); 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 74static const struct bhnd_device_quirk bhnd_pcie2_quirks[]; 75 76 77static int bhnd_pcie2_wars_early_once(struct bhnd_pcie2hb_softc *sc); 78static int bhnd_pcie2_wars_hwup(struct bhnd_pcie2hb_softc *sc); 79static 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 88static const struct bhnd_device bhnd_pcie2_devs[] = { 89 BHND_PCI_DEV(PCIE2, bhnd_pcie2_quirks), 90 BHND_DEVICE_END 91}; 92 93static 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 104static int 105bhnd_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 139failed: 140 bhnd_pcie2_generic_detach(dev); 141 return (error); 142} 143 144static int 145bhnd_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 159static int 160bhnd_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 174static int 175bhnd_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 */ 202static int 203bhnd_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 */ 213static int 214bhnd_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 */ 224static int 225bhnd_pcie2_wars_hwdown(struct bhnd_pcie2hb_softc *sc) 226{ 227 // TODO 228 return (ENXIO); 229} 230 231static 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 241DEFINE_CLASS_1(bhnd_hostb, bhnd_pcie2_hostb_driver, 242 bhnd_pcie2_hostb_methods, sizeof(struct bhnd_pcie2hb_softc), 243 bhnd_pcie2_driver); 244 245DRIVER_MODULE(bhnd_pcie2_hostb, bhnd, bhnd_pcie2_hostb_driver, bhnd_hostb_devclass, 0, 0); 246 247MODULE_VERSION(bhnd_pcie2_hostb, 1); 248MODULE_DEPEND(bhnd_pcie2_hostb, bhnd, 1, 1, 1); 249MODULE_DEPEND(bhnd_pcie2_hostb, bhnd_pcie2, 1, 1, 1); 250