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 PCI/PCIe-Gen1 PCI-Host Bridge.
35 *
36 * This driver handles all interactions with PCI 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#include <sys/param.h>
44#include <sys/kernel.h>
45
46#include <sys/malloc.h>
47
48#include <sys/bus.h>
49#include <sys/module.h>
50
51#include <sys/systm.h>
52
53#include <machine/bus.h>
54#include <sys/rman.h>
55#include <machine/resource.h>
56
57#include <dev/bhnd/bhnd.h>
58
59#include <dev/pci/pcireg.h>
60#include <dev/pci/pcivar.h>
61
62#include <dev/bhnd/cores/chipc/chipc.h>
63#include <dev/bhnd/cores/chipc/chipcreg.h>
64
65#include "bhnd_pcireg.h"
66#include "bhnd_pci_hostbvar.h"
67
68static const struct bhnd_device_quirk bhnd_pci_quirks[];
69static const struct bhnd_device_quirk bhnd_pcie_quirks[];
70
71/* Device driver work-around variations */
72typedef enum {
73	BHND_PCI_WAR_ATTACH,	/**< apply attach workarounds */
74	BHND_PCI_WAR_RESUME,	/**< apply resume workarounds */
75	BHND_PCI_WAR_SUSPEND,	/**< apply suspend workarounds */
76	BHND_PCI_WAR_DETACH	/**< apply detach workarounds */
77} bhnd_pci_war_state;
78
79static int	bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
80static int	bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
81		    bhnd_pci_war_state state);
82static int	bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
83		    bhnd_pci_war_state state);
84
85/*
86 * device/quirk tables
87 */
88
89#define	BHND_PCI_DEV(_core, _quirks)		\
90	BHND_DEVICE(BCM, _core, NULL, _quirks, BHND_DF_HOSTB)
91
92static const struct bhnd_device bhnd_pci_devs[] = {
93	BHND_PCI_DEV(PCI,	bhnd_pci_quirks),
94	BHND_PCI_DEV(PCIE,	bhnd_pcie_quirks),
95	BHND_DEVICE_END
96};
97
98static const struct bhnd_device_quirk bhnd_pci_quirks[] = {
99	/* core revision quirks */
100	BHND_CORE_QUIRK	(HWREV_ANY,	BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST),
101	BHND_CORE_QUIRK	(HWREV_GTE(11),	BHND_PCI_QUIRK_SBTOPCI2_READMULTI |
102					BHND_PCI_QUIRK_CLKRUN_DSBL),
103
104	/* BCM4321CB2 boards that require 960ns latency timer override */
105	BHND_BOARD_QUIRK(BCM4321CB2,	BHND_PCI_QUIRK_960NS_LATTIM_OVR),
106	BHND_BOARD_QUIRK(BCM4321CB2_AG,	BHND_PCI_QUIRK_960NS_LATTIM_OVR),
107
108	BHND_DEVICE_QUIRK_END
109};
110
111static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
112	/* core revision quirks */
113	BHND_CORE_QUIRK	(HWREV_EQ (0),	BHND_PCIE_QUIRK_SDR9_L0s_HANG),
114	BHND_CORE_QUIRK	(HWREV_RANGE(0,1),
115	    BHND_PCIE_QUIRK_UR_STATUS_FIX),
116
117	BHND_CORE_QUIRK	(HWREV_EQ (1),	BHND_PCIE_QUIRK_PCIPM_REQEN),
118
119	BHND_CORE_QUIRK	(HWREV_RANGE(3,5),
120	    BHND_PCIE_QUIRK_ASPM_OVR | BHND_PCIE_QUIRK_SDR9_POLARITY |
121	    BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY),
122
123	BHND_CORE_QUIRK	(HWREV_LTE(6),	BHND_PCIE_QUIRK_L1_IDLE_THRESH),
124	BHND_CORE_QUIRK	(HWREV_GTE(6),	BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET),
125	BHND_CORE_QUIRK	(HWREV_EQ (7),	BHND_PCIE_QUIRK_SERDES_NOPLLDOWN),
126	BHND_CORE_QUIRK	(HWREV_GTE(8),	BHND_PCIE_QUIRK_L1_TIMER_PERF),
127
128	BHND_CORE_QUIRK	(HWREV_LTE(17),	BHND_PCIE_QUIRK_MAX_MRRS_128),
129
130	/* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
131	 * to be set. */
132	{{ BHND_MATCH_BOARD_VENDOR	(PCI_VENDOR_APPLE),
133	   BHND_MATCH_BOARD_REV		(HWREV_LTE(0x71)),
134	   BHND_MATCH_SROMREV		(EQ(4)) },
135		BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
136
137	/* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
138	{{ BHND_CHIP_ID(BCM4322),
139	   BHND_MATCH_BOARD(PCI_VENDOR_APPLE, BCM94322X9), },
140		BHND_PCIE_QUIRK_SERDES_TXDRV_700MV },
141
142	/* Apple BCM4331 board-specific quirks */
143#define	BHND_A4331_QUIRK(_board, ...)	\
144	{{ BHND_CHIP_ID(BCM4331),		\
145	    BHND_MATCH_BOARD(PCI_VENDOR_APPLE, _board) }, __VA_ARGS__ }
146
147	BHND_A4331_QUIRK(BCM94331X19,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
148					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
149
150	BHND_A4331_QUIRK(BCM94331X28,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
151					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
152
153	BHND_A4331_QUIRK(BCM94331X28B,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
154
155	BHND_A4331_QUIRK(BCM94331X29B,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
156					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
157
158	BHND_A4331_QUIRK(BCM94331X19C,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
159					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
160
161	BHND_A4331_QUIRK(BCM94331X29D,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
162
163	BHND_A4331_QUIRK(BCM94331X33,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
164
165#undef BHND_A4331_QUIRK
166
167	BHND_DEVICE_QUIRK_END
168};
169
170
171#define	BHND_PCI_SOFTC(_sc)	(&((_sc)->common))
172
173#define	BHND_PCI_READ_2(_sc, _reg)		\
174	bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
175
176#define	BHND_PCI_READ_4(_sc, _reg)		\
177	bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
178
179#define	BHND_PCI_WRITE_2(_sc, _reg, _val)	\
180	bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
181
182#define	BHND_PCI_WRITE_4(_sc, _reg, _val)	\
183	bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
184
185#define	BHND_PCI_PROTO_READ_4(_sc, _reg)	\
186	bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
187
188#define	BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val)	\
189	bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
190
191#define	BHND_PCI_MDIO_READ(_sc, _phy, _reg)	\
192	bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
193
194#define	BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)		\
195	bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
196
197#define	BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)		\
198	bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
199
200#define	BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)	\
201	bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),		\
202	    (_devaddr), (_reg), (_val))
203
204#define	BPCI_REG_SET(_regv, _attr, _val)	\
205	BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
206
207#define	BPCI_REG_GET(_regv, _attr)	\
208	BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
209
210#define	BPCI_CMN_REG_SET(_regv, _attr, _val)			\
211	BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
212	    BHND_ ## _attr, (_val))
213
214#define	BPCI_CMN_REG_GET(_regv, _attr)				\
215	BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
216	    BHND_ ## _attr)
217
218static int
219bhnd_pci_hostb_attach(device_t dev)
220{
221	struct bhnd_pcihb_softc	*sc;
222	int			 error;
223
224	sc = device_get_softc(dev);
225	sc->dev = dev;
226	sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
227	    sizeof(bhnd_pci_devs[0]));
228
229	/* Find the host PCI bridge device */
230	sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
231	if (sc->pci_dev == NULL) {
232		device_printf(dev, "parent pci bridge device not found\n");
233		return (ENXIO);
234	}
235
236	/* Common setup */
237	if ((error = bhnd_pci_generic_attach(dev)))
238		return (error);
239
240	/* Apply early single-shot work-arounds */
241	if ((error = bhnd_pci_wars_early_once(sc)))
242		goto failed;
243
244	/* Apply attach/resume work-arounds */
245	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
246		goto failed;
247
248	return (0);
249
250failed:
251	bhnd_pci_generic_detach(dev);
252	return (error);
253}
254
255static int
256bhnd_pci_hostb_detach(device_t dev)
257{
258	struct bhnd_pcihb_softc *sc;
259	int			 error;
260
261	sc = device_get_softc(dev);
262
263	/* Apply suspend/detach work-arounds */
264	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
265		return (error);
266
267	return (bhnd_pci_generic_detach(dev));
268}
269
270static int
271bhnd_pci_hostb_suspend(device_t dev)
272{
273	struct bhnd_pcihb_softc *sc;
274	int			 error;
275
276	sc = device_get_softc(dev);
277
278	/* Apply suspend/detach work-arounds */
279	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
280		return (error);
281
282	return (bhnd_pci_generic_suspend(dev));
283}
284
285static int
286bhnd_pci_hostb_resume(device_t dev)
287{
288	struct bhnd_pcihb_softc	*sc;
289	int			 error;
290
291	sc = device_get_softc(dev);
292
293	if ((error = bhnd_pci_generic_resume(dev)))
294		return (error);
295
296	/* Apply attach/resume work-arounds */
297	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
298		bhnd_pci_generic_detach(dev);
299		return (error);
300	}
301
302	return (0);
303}
304
305/**
306 * Apply any hardware work-arounds that must be executed exactly once, early in
307 * the attach process.
308 *
309 * This must be called after core enumeration and discovery of all applicable
310 * quirks, but prior to probe/attach of any cores, parsing of
311 * SPROM, etc.
312 */
313static int
314bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
315{
316	int error;
317
318	/* Set PCI latency timer */
319	if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
320		pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
321		    1);
322	}
323
324	/* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
325	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
326		struct bhnd_board_info	board;
327		bool			aspm_en;
328
329		/* Fetch board info */
330		if ((error = bhnd_read_board_info(sc->dev, &board)))
331			return (error);
332
333		/* Check board flags */
334		aspm_en = true;
335		if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
336			aspm_en = false;
337
338		/* Early Apple devices did not (but should have) set
339		 * BHND_BFL2_PCIEWAR_OVR in SPROM. */
340		if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
341			aspm_en = false;
342
343		sc->aspm_quirk_override.aspm_en = aspm_en;
344	}
345
346	/* Determine correct polarity by observing the attach-time PCIe PHY
347	 * link status. This is used later to reset/force the SerDes
348	 * polarity */
349	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
350		uint32_t st;
351		bool inv;
352
353		st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
354		inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
355		sc->sdr9_quirk_polarity.inv = inv;
356	}
357
358	/* Override maximum read request size */
359	if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
360		int	msize;
361
362		msize = 128; /* compatible with all PCIe-G1 core revisions */
363		if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
364			msize = 512;
365
366		if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
367			panic("set mrrs on non-PCIe device");
368	}
369
370	return (0);
371}
372
373/**
374 * Apply any hardware workarounds that are required upon attach or resume
375 * of the bridge device.
376 */
377static int
378bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
379{
380	/* Note that the order here matters; these work-arounds
381	 * should not be re-ordered without careful review of their
382	 * interdependencies */
383
384	/* Enable PCI prefetch/burst/readmulti flags */
385	if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
386	    sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
387	{
388		uint32_t sbp2;
389		sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
390
391		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
392			sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
393
394		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
395			sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
396
397		BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
398	}
399
400	/* Disable PCI CLKRUN# */
401	if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
402		uint32_t ctl;
403
404		ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
405		ctl |= BHND_PCI_CLKRUN_DSBL;
406		BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
407	}
408
409	/* Enable TLP unmatched address handling work-around */
410	if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
411		uint32_t wrs;
412		wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
413		wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
414		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
415	}
416
417	/* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
418	 * data during L0s to L0 exit transitions. */
419	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
420		uint16_t sdv;
421
422		/* Set RX track/acquire timers to 2.064us/40.96us */
423		sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
424		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
425		    (40960/1024));
426		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
427		    BHND_PCIE_SDR9_RX_TIMER1, sdv);
428
429		/* Apply CDR frequency workaround */
430		sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
431		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
432		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
433		    BHND_PCIE_SDR9_RX_CDR, sdv);
434
435		/* Apply CDR BW tunings */
436		sdv = 0;
437		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
438		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
439		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
440		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
441		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
442		    BHND_PCIE_SDR9_RX_CDRBW, sdv);
443	}
444
445	/* Force correct SerDes polarity */
446	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
447		uint16_t	rxctl;
448
449		rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
450		    BHND_PCIE_SDR9_RX_CTRL);
451
452		rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
453		if (sc->sdr9_quirk_polarity.inv)
454			rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
455		else
456			rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
457
458		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
459		    BHND_PCIE_SDR9_RX_CTRL, rxctl);
460	}
461
462	/* Disable startup retry on PLL frequency detection failure */
463	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
464		uint16_t	pctl;
465
466		pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
467		    BHND_PCIE_SDR9_PLL_CTRL);
468
469		pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
470		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
471		    BHND_PCIE_SDR9_PLL_CTRL, pctl);
472	}
473
474	/* Explicitly enable PCI-PM */
475	if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
476		uint32_t lcreg;
477		lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
478		lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
479		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
480	}
481
482	/* Adjust L1 timer to fix slow L1->L0 transitions */
483	if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
484		uint32_t pmt;
485		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
486		pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
487		    BHND_PCIE_L1THRESHOLD_WARVAL);
488		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
489	}
490
491	/* Extend L1 timer for better performance.
492	 * TODO: We could enable/disable this on demand for better power
493	 * savings if we tie this to HT clock request handling */
494	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
495		uint32_t pmt;
496		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
497		pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
498		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
499	}
500
501	/* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
502	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
503		bus_size_t	reg;
504		uint16_t	cfg;
505
506		/* Set ASPM L1/L0s flags in SPROM shadow */
507		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
508		cfg = BHND_PCI_READ_2(sc, reg);
509
510		if (sc->aspm_quirk_override.aspm_en)
511			cfg |= BHND_PCIE_SRSH_ASPM_ENB;
512		else
513			cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
514
515		BHND_PCI_WRITE_2(sc, reg, cfg);
516
517
518		/* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
519		cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
520
521		if (sc->aspm_quirk_override.aspm_en)
522			cfg |= PCIEM_LINK_CTL_ASPMC;
523		else
524			cfg &= ~PCIEM_LINK_CTL_ASPMC;
525
526		cfg &= ~PCIEM_LINK_CTL_ECPM;		/* CLKREQ# */
527
528		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
529
530		/* Set CLKREQ (ECPM) flags in SPROM shadow */
531		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
532		cfg = BHND_PCI_READ_2(sc, reg);
533
534		if (sc->aspm_quirk_override.aspm_en)
535			cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
536		else
537			cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
538
539		BHND_PCI_WRITE_2(sc, reg, cfg);
540	}
541
542	/* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
543	if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
544		bus_size_t	reg;
545		uint16_t	cfg;
546
547		/* Fetch the misc cfg flags from SPROM */
548		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
549		cfg = BHND_PCI_READ_2(sc, reg);
550
551		/* Write EXIT_NOPRST flag if not already set in SPROM */
552		if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
553			cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
554			BHND_PCI_WRITE_2(sc, reg, cfg);
555		}
556	}
557
558	/* Disable SerDes PLL down */
559	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
560		device_t	bhnd, chipc;
561		bus_size_t	reg;
562
563		bhnd = device_get_parent(sc->dev);
564		chipc = bhnd_find_child(bhnd, BHND_DEVCLASS_CC, 0);
565		KASSERT(chipc != NULL, ("missing chipcommon device"));
566
567		/* Write SerDes PLL disable flag to the ChipCommon core */
568		BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
569		    CHIPCTRL_4321_PLL_DOWN);
570
571		/* Clear SPROM shadow backdoor register */
572		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
573		BHND_PCI_WRITE_2(sc, reg, 0);
574	}
575
576	/* Adjust TX drive strength and pre-emphasis coefficient */
577	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
578		uint16_t txdrv;
579
580		/* Fetch current TX driver parameters */
581		txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
582		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
583
584		/* Set 700mV drive strength */
585		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
586			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
587			    BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
588
589			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
590			    BHND_PCIE_APPLE_TX_IDRIVER_700MV);
591		}
592
593		/* ... or, set max drive strength */
594		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
595			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
596			    BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
597
598			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
599			    BHND_PCIE_APPLE_TX_IDRIVER_MAX);
600		}
601
602		BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
603		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
604	}
605
606	return (0);
607}
608
609/**
610 * Apply any hardware workarounds that are required upon detach or suspend
611 * of the bridge device.
612 */
613static int
614bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
615{
616	/* Reduce L1 timer for better power savings.
617	 * TODO: We could enable/disable this on demand for better power
618	 * savings if we tie this to HT clock request handling */
619	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
620		uint32_t pmt;
621		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
622		pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
623		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
624	}
625
626	/* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
627	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
628		uint16_t	lcreg;
629
630		lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
631
632		lcreg |= PCIEM_LINK_CTL_ECPM;	/* CLKREQ# */
633		if (state == BHND_PCI_WAR_SUSPEND)
634			lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
635
636		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
637	}
638
639	return (0);
640}
641
642static device_method_t bhnd_pci_hostb_methods[] = {
643	/* Device interface */
644	DEVMETHOD(device_attach,		bhnd_pci_hostb_attach),
645	DEVMETHOD(device_detach,		bhnd_pci_hostb_detach),
646	DEVMETHOD(device_suspend,		bhnd_pci_hostb_suspend),
647	DEVMETHOD(device_resume,		bhnd_pci_hostb_resume),
648
649	DEVMETHOD_END
650};
651
652DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
653    sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
654DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
655
656MODULE_VERSION(bhnd_pci_hostb, 1);
657MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
658MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);
659