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