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