1296077Sadrian/*- 2296077Sadrian * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3296077Sadrian * All rights reserved. 4296077Sadrian * 5296077Sadrian * Redistribution and use in source and binary forms, with or without 6296077Sadrian * modification, are permitted provided that the following conditions 7296077Sadrian * are met: 8296077Sadrian * 1. Redistributions of source code must retain the above copyright 9296077Sadrian * notice, this list of conditions and the following disclaimer, 10296077Sadrian * without modification. 11296077Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12296077Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13296077Sadrian * redistribution must be conditioned upon including a substantially 14296077Sadrian * similar Disclaimer requirement for further binary redistribution. 15296077Sadrian * 16296077Sadrian * NO WARRANTY 17296077Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18296077Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19296077Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20296077Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21296077Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22296077Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23296077Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24296077Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25296077Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26296077Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27296077Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28296077Sadrian */ 29296077Sadrian 30296077Sadrian#include <sys/cdefs.h> 31296077Sadrian__FBSDID("$FreeBSD$"); 32296077Sadrian 33296077Sadrian/* 34298479Sadrian * Broadcom Common PCI/PCIe Support. 35296077Sadrian * 36298479Sadrian * This base driver implementation is shared by the bhnd_pcib (root complex) 37298479Sadrian * and bhnd_pci_hostb (host bridge) drivers. 38296077Sadrian */ 39296077Sadrian 40296077Sadrian#include <sys/param.h> 41298479Sadrian#include <sys/malloc.h> 42296077Sadrian#include <sys/kernel.h> 43298479Sadrian#include <sys/bus.h> 44296077Sadrian#include <sys/module.h> 45298479Sadrian#include <sys/systm.h> 46296077Sadrian 47298479Sadrian#include <machine/bus.h> 48298479Sadrian#include <sys/rman.h> 49298479Sadrian#include <machine/resource.h> 50298479Sadrian 51298479Sadrian#include <dev/bhnd/bhnd.h> 52298479Sadrian#include <dev/mdio/mdio.h> 53298479Sadrian 54298479Sadrian#include "bhnd_pcireg.h" 55296077Sadrian#include "bhnd_pcivar.h" 56296077Sadrian 57298479Sadrianstatic int bhnd_pcie_mdio_wait_idle(struct bhnd_pci_softc *sc); 58298479Sadrianstatic int bhnd_pcie_mdio_ioctl(struct bhnd_pci_softc *sc, uint32_t cmd); 59298479Sadrianstatic int bhnd_pcie_mdio_enable(struct bhnd_pci_softc *sc); 60298479Sadrianstatic void bhnd_pcie_mdio_disable(struct bhnd_pci_softc *sc); 61298479Sadrianstatic int bhnd_pcie_mdio_cmd_write(struct bhnd_pci_softc *sc, 62298479Sadrian uint32_t cmd); 63298479Sadrianstatic int bhnd_pcie_mdio_cmd_read(struct bhnd_pci_softc *sc, uint32_t cmd, 64298479Sadrian uint16_t *data_read); 65298479Sadrian 66298479Sadrianstatic struct bhnd_device_quirk bhnd_pci_quirks[]; 67298479Sadrianstatic struct bhnd_device_quirk bhnd_pcie_quirks[]; 68298479Sadrian 69298479Sadrian#define BHND_PCI_QUIRKS bhnd_pci_quirks 70298479Sadrian#define BHND_PCIE_QUIRKS bhnd_pcie_quirks 71301697Slandonf#define BHND_PCI_DEV(_core, _desc, ...) \ 72301697Slandonf { BHND_DEVICE(BCM, _core, _desc, BHND_ ## _core ## _QUIRKS, \ 73298479Sadrian ## __VA_ARGS__), BHND_PCI_REGFMT_ ## _core } 74298479Sadrian 75298479Sadrianstatic const struct bhnd_pci_device { 76298479Sadrian struct bhnd_device device; 77298479Sadrian bhnd_pci_regfmt_t regfmt; /**< register format */ 78298479Sadrian} bhnd_pci_devs[] = { 79298479Sadrian BHND_PCI_DEV(PCI, "Host-PCI bridge", BHND_DF_HOSTB), 80300628Sadrian BHND_PCI_DEV(PCI, "PCI-BHND bridge", BHND_DF_SOC), 81298479Sadrian BHND_PCI_DEV(PCIE, "PCIe-G1 Host-PCI bridge", BHND_DF_HOSTB), 82300628Sadrian BHND_PCI_DEV(PCIE, "PCIe-G1 PCI-BHND bridge", BHND_DF_SOC), 83298479Sadrian 84298479Sadrian { BHND_DEVICE_END, 0 } 85298479Sadrian}; 86298479Sadrian 87298479Sadrian/* Device quirks tables */ 88298479Sadrianstatic struct bhnd_device_quirk bhnd_pci_quirks[] = { BHND_DEVICE_QUIRK_END }; 89298479Sadrianstatic struct bhnd_device_quirk bhnd_pcie_quirks[] = { 90300628Sadrian BHND_CORE_QUIRK(HWREV_GTE(10), BHND_PCI_QUIRK_SD_C22_EXTADDR), 91300628Sadrian 92298479Sadrian BHND_DEVICE_QUIRK_END 93298479Sadrian}; 94298479Sadrian 95298479Sadrian#define BHND_PCIE_MDIO_CTL_DELAY 10 /**< usec delay required between 96298479Sadrian * MDIO_CTL/MDIO_DATA accesses. */ 97298479Sadrian#define BHND_PCIE_MDIO_RETRY_DELAY 2000 /**< usec delay before retrying 98298479Sadrian * BHND_PCIE_MDIOCTL_DONE. */ 99298479Sadrian#define BHND_PCIE_MDIO_RETRY_COUNT 200 /**< number of times to loop waiting 100298479Sadrian * for BHND_PCIE_MDIOCTL_DONE. */ 101298479Sadrian 102298479Sadrian#define BHND_PCI_READ_4(_sc, _reg) \ 103298479Sadrian bhnd_bus_read_4((_sc)->mem_res, (_reg)) 104298479Sadrian#define BHND_PCI_WRITE_4(_sc, _reg, _val) \ 105298479Sadrian bhnd_bus_write_4((_sc)->mem_res, (_reg), (_val)) 106298479Sadrian 107298479Sadrian#define BHND_PCIE_ASSERT(sc) \ 108298479Sadrian KASSERT(bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE, \ 109298479Sadrian ("not a pcie device!")); 110298479Sadrian 111298479Sadrianint 112298479Sadrianbhnd_pci_generic_probe(device_t dev) 113298479Sadrian{ 114298479Sadrian const struct bhnd_device *id; 115298479Sadrian 116298479Sadrian id = bhnd_device_lookup(dev, &bhnd_pci_devs[0].device, 117298479Sadrian sizeof(bhnd_pci_devs[0])); 118298479Sadrian if (id == NULL) 119298479Sadrian return (ENXIO); 120298479Sadrian 121298479Sadrian bhnd_set_custom_core_desc(dev, id->desc); 122298479Sadrian return (BUS_PROBE_DEFAULT); 123298479Sadrian} 124298479Sadrian 125298479Sadrianint 126298479Sadrianbhnd_pci_generic_attach(device_t dev) 127298479Sadrian{ 128298479Sadrian struct bhnd_pci_softc *sc; 129298479Sadrian int error; 130298479Sadrian 131298479Sadrian sc = device_get_softc(dev); 132298479Sadrian sc->dev = dev; 133298479Sadrian sc->quirks = bhnd_device_quirks(dev, &bhnd_pci_devs[0].device, 134298479Sadrian sizeof(bhnd_pci_devs[0])); 135298479Sadrian 136298479Sadrian /* Allocate bus resources */ 137298479Sadrian sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 138298479Sadrian RF_ACTIVE); 139298479Sadrian if (sc->mem_res == NULL) 140298479Sadrian return (ENXIO); 141298479Sadrian 142298479Sadrian BHND_PCI_LOCK_INIT(sc); 143298479Sadrian 144298479Sadrian /* Probe and attach children */ 145298479Sadrian if ((error = bus_generic_attach(dev))) 146298479Sadrian goto cleanup; 147298479Sadrian 148298479Sadrian return (0); 149298479Sadrian 150298479Sadriancleanup: 151298479Sadrian bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); 152298479Sadrian BHND_PCI_LOCK_DESTROY(sc); 153298479Sadrian 154298479Sadrian return (error); 155298479Sadrian} 156298479Sadrian 157298479Sadrianint 158298479Sadrianbhnd_pci_generic_detach(device_t dev) 159298479Sadrian{ 160298479Sadrian struct bhnd_pci_softc *sc; 161298479Sadrian int error; 162298479Sadrian 163298479Sadrian sc = device_get_softc(dev); 164298479Sadrian 165298479Sadrian if ((error = bus_generic_detach(dev))) 166298479Sadrian return (error); 167298479Sadrian 168298479Sadrian bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); 169298479Sadrian 170298479Sadrian BHND_PCI_LOCK_DESTROY(sc); 171298479Sadrian 172298479Sadrian return (0); 173298479Sadrian} 174298479Sadrian 175298479Sadrianstatic struct resource_list * 176298479Sadrianbhnd_pci_get_resource_list(device_t dev, device_t child) 177298479Sadrian{ 178298479Sadrian struct bhnd_pci_devinfo *dinfo; 179298479Sadrian 180298479Sadrian if (device_get_parent(child) != dev) 181298479Sadrian return (NULL); 182298479Sadrian 183298479Sadrian dinfo = device_get_ivars(child); 184298479Sadrian return (&dinfo->resources); 185298479Sadrian} 186298479Sadrian 187298479Sadrianstatic device_t 188298479Sadrianbhnd_pci_add_child(device_t dev, u_int order, const char *name, int unit) 189298479Sadrian{ 190298479Sadrian struct bhnd_pci_devinfo *dinfo; 191298479Sadrian device_t child; 192298479Sadrian 193298479Sadrian child = device_add_child_ordered(dev, order, name, unit); 194298479Sadrian if (child == NULL) 195298479Sadrian return (NULL); 196298479Sadrian 197298479Sadrian dinfo = malloc(sizeof(struct bhnd_pci_devinfo), M_DEVBUF, M_NOWAIT); 198298479Sadrian if (dinfo == NULL) { 199298479Sadrian device_delete_child(dev, child); 200298479Sadrian return (NULL); 201298479Sadrian } 202298479Sadrian 203298479Sadrian resource_list_init(&dinfo->resources); 204298479Sadrian 205298479Sadrian device_set_ivars(child, dinfo); 206298479Sadrian return (child); 207298479Sadrian} 208298479Sadrian 209298479Sadrianstatic void 210298479Sadrianbhnd_pci_child_deleted(device_t dev, device_t child) 211298479Sadrian{ 212298479Sadrian struct bhnd_pci_devinfo *dinfo; 213298479Sadrian 214298479Sadrian if (device_get_parent(child) != dev) 215298479Sadrian return; 216298479Sadrian 217298479Sadrian dinfo = device_get_ivars(child); 218298479Sadrian if (dinfo != NULL) { 219298479Sadrian resource_list_free(&dinfo->resources); 220298479Sadrian free(dinfo, M_DEVBUF); 221298479Sadrian } 222298479Sadrian 223298479Sadrian device_set_ivars(child, NULL); 224298479Sadrian} 225298479Sadrian 226298479Sadrianint 227298479Sadrianbhnd_pci_generic_suspend(device_t dev) 228298479Sadrian{ 229298479Sadrian return (bus_generic_suspend(dev)); 230298479Sadrian} 231298479Sadrian 232298479Sadrianint 233298479Sadrianbhnd_pci_generic_resume(device_t dev) 234298479Sadrian{ 235298479Sadrian return (bus_generic_resume(dev)); 236298479Sadrian} 237298479Sadrian 238296077Sadrian/** 239298479Sadrian * Read a 32-bit PCIe TLP/DLLP/PLP protocol register. 240298479Sadrian * 241298479Sadrian * @param sc The bhndb_pci driver state. 242298479Sadrian * @param addr The protocol register offset. 243296077Sadrian */ 244298479Sadrianuint32_t 245298479Sadrianbhnd_pcie_read_proto_reg(struct bhnd_pci_softc *sc, uint32_t addr) 246298479Sadrian{ 247298479Sadrian uint32_t val; 248296077Sadrian 249298479Sadrian BHND_PCIE_ASSERT(sc); 250298479Sadrian 251298479Sadrian BHND_PCI_LOCK(sc); 252298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); 253298479Sadrian val = BHND_PCI_READ_4(sc, BHND_PCIE_IND_DATA); 254298479Sadrian BHND_PCI_UNLOCK(sc); 255298479Sadrian 256298479Sadrian return (val); 257298479Sadrian} 258298479Sadrian 259298479Sadrian/** 260298479Sadrian * Write a 32-bit PCIe TLP/DLLP/PLP protocol register value. 261298479Sadrian * 262298479Sadrian * @param sc The bhndb_pci driver state. 263298479Sadrian * @param addr The protocol register offset. 264298479Sadrian * @param val The value to write to @p addr. 265298479Sadrian */ 266298479Sadrianvoid 267298479Sadrianbhnd_pcie_write_proto_reg(struct bhnd_pci_softc *sc, uint32_t addr, 268298479Sadrian uint32_t val) 269298479Sadrian{ 270298479Sadrian BHND_PCIE_ASSERT(sc); 271298479Sadrian 272298479Sadrian BHND_PCI_LOCK(sc); 273298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); 274298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_DATA, val); 275298479Sadrian BHND_PCI_UNLOCK(sc); 276298479Sadrian} 277298479Sadrian 278298479Sadrian/* Spin until the MDIO device reports itself as idle, or timeout is reached. */ 279298479Sadrianstatic int 280298479Sadrianbhnd_pcie_mdio_wait_idle(struct bhnd_pci_softc *sc) 281298479Sadrian{ 282298479Sadrian uint32_t ctl; 283298479Sadrian 284298479Sadrian /* Spin waiting for the BUSY flag to clear */ 285298479Sadrian for (int i = 0; i < BHND_PCIE_MDIO_RETRY_COUNT; i++) { 286298479Sadrian ctl = BHND_PCI_READ_4(sc, BHND_PCIE_MDIO_CTL); 287298479Sadrian if ((ctl & BHND_PCIE_MDIOCTL_DONE)) 288298479Sadrian return (0); 289298479Sadrian 290298479Sadrian DELAY(BHND_PCIE_MDIO_RETRY_DELAY); 291298479Sadrian } 292298479Sadrian 293298479Sadrian return (ETIMEDOUT); 294298479Sadrian} 295298479Sadrian 296298479Sadrian 297298479Sadrian/** 298298479Sadrian * Write an MDIO IOCTL and wait for completion. 299298479Sadrian */ 300298479Sadrianstatic int 301298479Sadrianbhnd_pcie_mdio_ioctl(struct bhnd_pci_softc *sc, uint32_t cmd) 302298479Sadrian{ 303298479Sadrian BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); 304298479Sadrian 305298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_CTL, cmd); 306298479Sadrian DELAY(BHND_PCIE_MDIO_CTL_DELAY); 307298479Sadrian return (0); 308298479Sadrian} 309298479Sadrian 310298479Sadrian/** 311298479Sadrian * Enable MDIO device 312298479Sadrian */ 313298479Sadrianstatic int 314298479Sadrianbhnd_pcie_mdio_enable(struct bhnd_pci_softc *sc) 315298479Sadrian{ 316298479Sadrian uint32_t ctl; 317298479Sadrian 318298479Sadrian BHND_PCIE_ASSERT(sc); 319298479Sadrian 320298479Sadrian /* Enable MDIO clock and preamble mode */ 321298479Sadrian ctl = BHND_PCIE_MDIOCTL_PREAM_EN|BHND_PCIE_MDIOCTL_DIVISOR_VAL; 322298479Sadrian return (bhnd_pcie_mdio_ioctl(sc, ctl)); 323298479Sadrian} 324298479Sadrian 325298479Sadrian/** 326298479Sadrian * Disable MDIO device. 327298479Sadrian */ 328298479Sadrianstatic void 329298479Sadrianbhnd_pcie_mdio_disable(struct bhnd_pci_softc *sc) 330298479Sadrian{ 331298479Sadrian if (bhnd_pcie_mdio_ioctl(sc, 0)) 332298479Sadrian device_printf(sc->dev, "failed to disable MDIO clock\n"); 333298479Sadrian} 334298479Sadrian 335298479Sadrian 336298479Sadrian/** 337298479Sadrian * Issue a write command and wait for completion 338298479Sadrian */ 339298479Sadrianstatic int 340298479Sadrianbhnd_pcie_mdio_cmd_write(struct bhnd_pci_softc *sc, uint32_t cmd) 341298479Sadrian{ 342298479Sadrian int error; 343298479Sadrian 344298479Sadrian BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); 345298479Sadrian 346298479Sadrian cmd |= BHND_PCIE_MDIODATA_START|BHND_PCIE_MDIODATA_TA|BHND_PCIE_MDIODATA_CMD_WRITE; 347298479Sadrian 348298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_DATA, cmd); 349298479Sadrian DELAY(BHND_PCIE_MDIO_CTL_DELAY); 350298479Sadrian 351298479Sadrian if ((error = bhnd_pcie_mdio_wait_idle(sc))) 352298479Sadrian return (error); 353298479Sadrian 354298479Sadrian return (0); 355298479Sadrian} 356298479Sadrian 357298479Sadrian/** 358298479Sadrian * Issue an an MDIO read command, wait for completion, and return 359298479Sadrian * the result in @p data_read. 360298479Sadrian */ 361298479Sadrianstatic int 362298479Sadrianbhnd_pcie_mdio_cmd_read(struct bhnd_pci_softc *sc, uint32_t cmd, 363298479Sadrian uint16_t *data_read) 364298479Sadrian{ 365298479Sadrian int error; 366298479Sadrian 367298479Sadrian BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); 368298479Sadrian 369298479Sadrian cmd |= BHND_PCIE_MDIODATA_START|BHND_PCIE_MDIODATA_TA|BHND_PCIE_MDIODATA_CMD_READ; 370298479Sadrian BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_DATA, cmd); 371298479Sadrian DELAY(BHND_PCIE_MDIO_CTL_DELAY); 372298479Sadrian 373298479Sadrian if ((error = bhnd_pcie_mdio_wait_idle(sc))) 374298479Sadrian return (error); 375298479Sadrian 376298479Sadrian *data_read = (BHND_PCI_READ_4(sc, BHND_PCIE_MDIO_DATA) & 377298479Sadrian BHND_PCIE_MDIODATA_DATA_MASK); 378298479Sadrian return (0); 379298479Sadrian} 380298479Sadrian 381298479Sadrian 382298479Sadrianint 383298479Sadrianbhnd_pcie_mdio_read(struct bhnd_pci_softc *sc, int phy, int reg) 384298479Sadrian{ 385298479Sadrian uint32_t cmd; 386298479Sadrian uint16_t val; 387298479Sadrian int error; 388298479Sadrian 389298479Sadrian /* Enable MDIO access */ 390298479Sadrian BHND_PCI_LOCK(sc); 391298479Sadrian bhnd_pcie_mdio_enable(sc); 392298479Sadrian 393298479Sadrian /* Issue the read */ 394298479Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg); 395298479Sadrian error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val); 396298479Sadrian 397298479Sadrian /* Disable MDIO access */ 398298479Sadrian bhnd_pcie_mdio_disable(sc); 399298479Sadrian BHND_PCI_UNLOCK(sc); 400298479Sadrian 401298479Sadrian if (error) 402298479Sadrian return (~0U); 403298479Sadrian 404298479Sadrian return (val); 405298479Sadrian} 406298479Sadrian 407298479Sadrianint 408298479Sadrianbhnd_pcie_mdio_write(struct bhnd_pci_softc *sc, int phy, int reg, int val) 409298479Sadrian{ 410298479Sadrian uint32_t cmd; 411298479Sadrian int error; 412298479Sadrian 413298479Sadrian /* Enable MDIO access */ 414298479Sadrian BHND_PCI_LOCK(sc); 415298479Sadrian bhnd_pcie_mdio_enable(sc); 416298479Sadrian 417298479Sadrian /* Issue the write */ 418298479Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg) | (val & BHND_PCIE_MDIODATA_DATA_MASK); 419298479Sadrian error = bhnd_pcie_mdio_cmd_write(sc, cmd); 420298479Sadrian 421298479Sadrian /* Disable MDIO access */ 422298479Sadrian bhnd_pcie_mdio_disable(sc); 423298479Sadrian BHND_PCI_UNLOCK(sc); 424298479Sadrian 425298479Sadrian return (error); 426298479Sadrian} 427298479Sadrian 428298479Sadrianint 429298479Sadrianbhnd_pcie_mdio_read_ext(struct bhnd_pci_softc *sc, int phy, int devaddr, 430298479Sadrian int reg) 431298479Sadrian{ 432298479Sadrian uint32_t cmd; 433300015Sadrian uint16_t val; 434298479Sadrian int error; 435298479Sadrian 436298479Sadrian if (devaddr == MDIO_DEVADDR_NONE) 437298479Sadrian return (bhnd_pcie_mdio_read(sc, phy, reg)); 438298479Sadrian 439298479Sadrian /* Extended register access is only supported for the SerDes device, 440298479Sadrian * using the non-standard C22 extended address mechanism */ 441300015Sadrian if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) || 442300015Sadrian phy != BHND_PCIE_PHYADDR_SD) 443300015Sadrian { 444298479Sadrian return (~0U); 445300015Sadrian } 446298479Sadrian 447298479Sadrian /* Enable MDIO access */ 448298479Sadrian BHND_PCI_LOCK(sc); 449298479Sadrian bhnd_pcie_mdio_enable(sc); 450298479Sadrian 451298479Sadrian /* Write the block address to the address extension register */ 452300015Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr; 453298479Sadrian if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd))) 454298479Sadrian goto cleanup; 455298479Sadrian 456298479Sadrian /* Issue the read */ 457300015Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg); 458298479Sadrian error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val); 459298479Sadrian 460298479Sadriancleanup: 461298479Sadrian bhnd_pcie_mdio_disable(sc); 462298479Sadrian BHND_PCI_UNLOCK(sc); 463298479Sadrian 464298479Sadrian if (error) 465298479Sadrian return (~0U); 466298479Sadrian 467298479Sadrian return (val); 468298479Sadrian} 469298479Sadrian 470298479Sadrianint 471298479Sadrianbhnd_pcie_mdio_write_ext(struct bhnd_pci_softc *sc, int phy, int devaddr, 472298479Sadrian int reg, int val) 473298479Sadrian{ 474298479Sadrian uint32_t cmd; 475298479Sadrian int error; 476298479Sadrian 477298479Sadrian if (devaddr == MDIO_DEVADDR_NONE) 478298479Sadrian return (bhnd_pcie_mdio_write(sc, phy, reg, val)); 479298479Sadrian 480298479Sadrian /* Extended register access is only supported for the SerDes device, 481298479Sadrian * using the non-standard C22 extended address mechanism */ 482300015Sadrian if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) || 483300015Sadrian phy != BHND_PCIE_PHYADDR_SD) 484300015Sadrian { 485298479Sadrian return (~0U); 486300015Sadrian } 487298479Sadrian 488298479Sadrian /* Enable MDIO access */ 489298479Sadrian BHND_PCI_LOCK(sc); 490298479Sadrian bhnd_pcie_mdio_enable(sc); 491298479Sadrian 492298479Sadrian /* Write the block address to the address extension register */ 493300015Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr; 494298479Sadrian if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd))) 495298479Sadrian goto cleanup; 496298479Sadrian 497298479Sadrian /* Issue the write */ 498300015Sadrian cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg) | 499298479Sadrian (val & BHND_PCIE_MDIODATA_DATA_MASK); 500298479Sadrian error = bhnd_pcie_mdio_cmd_write(sc, cmd); 501298479Sadrian 502298479Sadriancleanup: 503298479Sadrian bhnd_pcie_mdio_disable(sc); 504298479Sadrian BHND_PCI_UNLOCK(sc); 505298479Sadrian 506298479Sadrian return (error); 507298479Sadrian} 508298479Sadrian 509298479Sadrianstatic device_method_t bhnd_pci_methods[] = { 510298479Sadrian /* Device interface */ 511298479Sadrian DEVMETHOD(device_probe, bhnd_pci_generic_probe), 512298479Sadrian DEVMETHOD(device_attach, bhnd_pci_generic_attach), 513298479Sadrian DEVMETHOD(device_detach, bhnd_pci_generic_detach), 514298479Sadrian DEVMETHOD(device_suspend, bhnd_pci_generic_suspend), 515298479Sadrian DEVMETHOD(device_resume, bhnd_pci_generic_resume), 516298479Sadrian 517298479Sadrian /* Bus interface */ 518298479Sadrian DEVMETHOD(bus_add_child, bhnd_pci_add_child), 519298479Sadrian DEVMETHOD(bus_child_deleted, bhnd_pci_child_deleted), 520298479Sadrian DEVMETHOD(bus_print_child, bus_generic_print_child), 521298479Sadrian DEVMETHOD(bus_get_resource_list, bhnd_pci_get_resource_list), 522298479Sadrian DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 523298479Sadrian DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 524298479Sadrian DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 525298479Sadrian 526298479Sadrian DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 527298479Sadrian DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 528298479Sadrian DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 529298479Sadrian DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 530298479Sadrian DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 531298479Sadrian 532298479Sadrian DEVMETHOD_END 533298479Sadrian}; 534298479Sadrian 535298479SadrianDEFINE_CLASS_0(bhnd_pci, bhnd_pci_driver, bhnd_pci_methods, sizeof(struct bhnd_pci_softc)); 536298947SadrianMODULE_DEPEND(bhnd_pci, bhnd, 1, 1, 1); 537298947SadrianMODULE_DEPEND(bhnd_pci, pci, 1, 1, 1); 538296077SadrianMODULE_VERSION(bhnd_pci, 1); 539