bhnd_pci_hostb.c revision 300015
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: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c 300015 2016-05-17 06:52:53Z adrian $");
32296077Sadrian
33296077Sadrian/*
34298479Sadrian * Broadcom BHND PCI/PCIe-Gen1 PCI-Host Bridge.
35296077Sadrian *
36298479Sadrian * This driver handles all interactions with PCI bridge cores operating in
37298479Sadrian * endpoint mode.
38298479Sadrian *
39298479Sadrian * Host-level PCI operations are handled at the bhndb bridge level by the
40298479Sadrian * bhndb_pci driver.
41296077Sadrian */
42296077Sadrian
43296077Sadrian#include <sys/param.h>
44296077Sadrian#include <sys/kernel.h>
45298479Sadrian
46298479Sadrian#include <sys/malloc.h>
47298479Sadrian
48296077Sadrian#include <sys/bus.h>
49296077Sadrian#include <sys/module.h>
50298479Sadrian
51296077Sadrian#include <sys/systm.h>
52296077Sadrian
53296077Sadrian#include <machine/bus.h>
54296077Sadrian#include <sys/rman.h>
55296077Sadrian#include <machine/resource.h>
56296077Sadrian
57296077Sadrian#include <dev/bhnd/bhnd.h>
58296077Sadrian
59300015Sadrian#include <dev/pci/pcireg.h>
60300015Sadrian#include <dev/pci/pcivar.h>
61300015Sadrian
62300015Sadrian#include <dev/bhnd/cores/chipc/chipc.h>
63300015Sadrian#include <dev/bhnd/cores/chipc/chipcreg.h>
64300015Sadrian
65298479Sadrian#include "bhnd_pcireg.h"
66298479Sadrian#include "bhnd_pci_hostbvar.h"
67298479Sadrian
68298479Sadrianstatic const struct bhnd_device_quirk bhnd_pci_quirks[];
69298479Sadrianstatic const struct bhnd_device_quirk bhnd_pcie_quirks[];
70300015Sadrianstatic const struct bhnd_chip_quirk bhnd_pci_chip_quirks[];
71299996Sadrianstatic const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[];
72298479Sadrian
73300015Sadrian/* Device driver work-around variations */
74300015Sadriantypedef enum {
75300015Sadrian	BHND_PCI_WAR_ATTACH,	/**< apply attach workarounds */
76300015Sadrian	BHND_PCI_WAR_RESUME,	/**< apply resume workarounds */
77300015Sadrian	BHND_PCI_WAR_SUSPEND,	/**< apply suspend workarounds */
78300015Sadrian	BHND_PCI_WAR_DETACH	/**< apply detach workarounds */
79300015Sadrian} bhnd_pci_war_state;
80300015Sadrian
81298479Sadrianstatic int	bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
82300015Sadrianstatic int	bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
83300015Sadrian		    bhnd_pci_war_state state);
84300015Sadrianstatic int	bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
85300015Sadrian		    bhnd_pci_war_state state);
86298479Sadrian
87298479Sadrian/*
88298479Sadrian * device/quirk tables
89298479Sadrian */
90300015Sadrian
91300015Sadrian#define	BHND_PCI_DEV(_core, _quirks, _chip_quirks)		\
92300015Sadrian	BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
93300015Sadrian
94298479Sadrianstatic const struct bhnd_device bhnd_pci_devs[] = {
95300015Sadrian	BHND_PCI_DEV(PCI,	bhnd_pci_quirks,	bhnd_pci_chip_quirks),
96299996Sadrian	BHND_PCI_DEV(PCIE,	bhnd_pcie_quirks,	bhnd_pcie_chip_quirks),
97298479Sadrian	BHND_DEVICE_END
98296077Sadrian};
99296077Sadrian
100298479Sadrianstatic const struct bhnd_device_quirk bhnd_pci_quirks[] = {
101298479Sadrian	{ BHND_HWREV_ANY,	BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST },
102298479Sadrian	{ BHND_HWREV_GTE(11),	BHND_PCI_QUIRK_SBTOPCI2_READMULTI |
103298479Sadrian				BHND_PCI_QUIRK_CLKRUN_DSBL },
104298479Sadrian	BHND_DEVICE_QUIRK_END
105298479Sadrian};
106298479Sadrian
107300015Sadrianstatic const struct bhnd_chip_quirk bhnd_pci_chip_quirks[] = {
108300015Sadrian	/* BCM4321CB2 boards that require 960ns latency timer override */
109300015Sadrian	{{ BHND_CHIP_BTYPE(BCM4321CB2) },
110300015Sadrian		BHND_PCI_QUIRK_960NS_LATTIM_OVR },
111300015Sadrian	{{ BHND_CHIP_BTYPE(BCM4321CB2_AG) },
112300015Sadrian		BHND_PCI_QUIRK_960NS_LATTIM_OVR },
113300015Sadrian
114300015Sadrian	BHND_CHIP_QUIRK_END
115300015Sadrian};
116300015Sadrian
117298479Sadrianstatic const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
118298479Sadrian	{ BHND_HWREV_EQ		(0),	BHND_PCIE_QUIRK_SDR9_L0s_HANG },
119300015Sadrian	{ BHND_HWREV_RANGE	(0,1),	BHND_PCIE_QUIRK_UR_STATUS_FIX },
120298479Sadrian	{ BHND_HWREV_EQ		(1),	BHND_PCIE_QUIRK_PCIPM_REQEN },
121298479Sadrian
122300015Sadrian	{ BHND_HWREV_RANGE	(3,5),	BHND_PCIE_QUIRK_ASPM_OVR |
123298479Sadrian					BHND_PCIE_QUIRK_SDR9_POLARITY |
124298479Sadrian					BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY },
125298479Sadrian
126298479Sadrian	{ BHND_HWREV_LTE	(6),	BHND_PCIE_QUIRK_L1_IDLE_THRESH },
127298479Sadrian	{ BHND_HWREV_GTE	(6),	BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET },
128298479Sadrian	{ BHND_HWREV_EQ		(7),	BHND_PCIE_QUIRK_SERDES_NOPLLDOWN },
129298479Sadrian	{ BHND_HWREV_GTE	(8),	BHND_PCIE_QUIRK_L1_TIMER_PERF },
130300015Sadrian
131300015Sadrian	{ BHND_HWREV_LTE	(17),	BHND_PCIE_QUIRK_MAX_MRRS_128 },
132300015Sadrian
133298479Sadrian	BHND_DEVICE_QUIRK_END
134298479Sadrian};
135298479Sadrian
136299996Sadrianstatic const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[] = {
137299996Sadrian	/* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
138299996Sadrian	 * to be set. */
139300015Sadrian	{{ BHND_CHIP_BVENDOR	(PCI_VENDOR_APPLE),
140300015Sadrian	   BHND_CHIP_SROMREV	(HWREV_EQ(4)),
141300015Sadrian	   BHND_CHIP_BREV	(HWREV_LTE(0x71)) },
142300015Sadrian		BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN		},
143299996Sadrian
144300015Sadrian	/* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
145300015Sadrian	{{ BHND_CHIP_BVT	(PCI_VENDOR_APPLE,	BCM94322X9)	},
146300015Sadrian		BHND_PCIE_QUIRK_SERDES_TXDRV_700MV	},
147300015Sadrian
148300015Sadrian	/* Apple BCM4331 board-specific quirks */
149300015Sadrian#define	BHND_APPLE_4331_QUIRK(_board, ...)				\
150300015Sadrian	{{ BHND_CHIP_ID		(4331),					\
151300015Sadrian	   BHND_CHIP_BVT	(PCI_VENDOR_APPLE,	_board), },	\
152300015Sadrian		__VA_ARGS__ }
153300015Sadrian
154300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X19,
155300015Sadrian	    BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
156300015Sadrian
157300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X28,
158300015Sadrian	    BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
159300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X28B, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
160300015Sadrian
161300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X29B,
162300015Sadrian	    BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
163300015Sadrian
164300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X19C,
165300015Sadrian	    BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
166300015Sadrian
167300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X29D, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
168300015Sadrian	BHND_APPLE_4331_QUIRK(BCM94331X33, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
169300015Sadrian#undef BHND_APPLE_4331_QUIRK
170300015Sadrian
171299996Sadrian	BHND_CHIP_QUIRK_END
172299996Sadrian};
173299996Sadrian
174298479Sadrian#define	BHND_PCI_SOFTC(_sc)	(&((_sc)->common))
175298479Sadrian
176298479Sadrian#define	BHND_PCI_READ_2(_sc, _reg)		\
177298479Sadrian	bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
178298479Sadrian
179298479Sadrian#define	BHND_PCI_READ_4(_sc, _reg)		\
180298479Sadrian	bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
181298479Sadrian
182298479Sadrian#define	BHND_PCI_WRITE_2(_sc, _reg, _val)	\
183298479Sadrian	bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
184298479Sadrian
185298479Sadrian#define	BHND_PCI_WRITE_4(_sc, _reg, _val)	\
186298479Sadrian	bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
187298479Sadrian
188298479Sadrian#define	BHND_PCI_PROTO_READ_4(_sc, _reg)	\
189298479Sadrian	bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
190298479Sadrian
191298479Sadrian#define	BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val)	\
192298479Sadrian	bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
193298479Sadrian
194298479Sadrian#define	BHND_PCI_MDIO_READ(_sc, _phy, _reg)	\
195298479Sadrian	bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
196298479Sadrian
197298479Sadrian#define	BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)		\
198298479Sadrian	bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
199298479Sadrian
200300015Sadrian#define	BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)		\
201300015Sadrian	bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
202300015Sadrian
203300015Sadrian#define	BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)	\
204300015Sadrian	bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),		\
205300015Sadrian	    (_devaddr), (_reg), (_val))
206300015Sadrian
207298479Sadrian#define	BPCI_REG_SET(_regv, _attr, _val)	\
208298479Sadrian	BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
209298479Sadrian
210298479Sadrian#define	BPCI_REG_GET(_regv, _attr)	\
211298479Sadrian	BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
212298479Sadrian
213298479Sadrian#define	BPCI_CMN_REG_SET(_regv, _attr, _val)			\
214298479Sadrian	BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
215298479Sadrian	    BHND_ ## _attr, (_val))
216298479Sadrian
217298479Sadrian#define	BPCI_CMN_REG_GET(_regv, _attr)				\
218298479Sadrian	BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
219298479Sadrian	    BHND_ ## _attr)
220298479Sadrian
221296077Sadrianstatic int
222298479Sadrianbhnd_pci_hostb_attach(device_t dev)
223296077Sadrian{
224298479Sadrian	struct bhnd_pcihb_softc	*sc;
225298479Sadrian	int			 error;
226298479Sadrian
227298479Sadrian	sc = device_get_softc(dev);
228300015Sadrian	sc->dev = dev;
229298479Sadrian	sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
230298479Sadrian	    sizeof(bhnd_pci_devs[0]));
231298479Sadrian
232300015Sadrian	/* Find the host PCI bridge device */
233300015Sadrian	sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
234300015Sadrian	if (sc->pci_dev == NULL) {
235300015Sadrian		device_printf(dev, "parent pci bridge device not found\n");
236300015Sadrian		return (ENXIO);
237300015Sadrian	}
238300015Sadrian
239300015Sadrian	/* Common setup */
240298479Sadrian	if ((error = bhnd_pci_generic_attach(dev)))
241298479Sadrian		return (error);
242298479Sadrian
243298479Sadrian	/* Apply early single-shot work-arounds */
244300015Sadrian	if ((error = bhnd_pci_wars_early_once(sc)))
245300015Sadrian		goto failed;
246296077Sadrian
247298479Sadrian	/* Apply attach/resume work-arounds */
248300015Sadrian	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
249300015Sadrian		goto failed;
250296077Sadrian
251298479Sadrian	return (0);
252300015Sadrian
253300015Sadrianfailed:
254300015Sadrian	bhnd_pci_generic_detach(dev);
255300015Sadrian	return (error);
256296077Sadrian}
257296077Sadrian
258296077Sadrianstatic int
259298479Sadrianbhnd_pci_hostb_detach(device_t dev)
260296077Sadrian{
261298479Sadrian	struct bhnd_pcihb_softc *sc;
262298479Sadrian	int			 error;
263298479Sadrian
264298479Sadrian	sc = device_get_softc(dev);
265298479Sadrian
266298479Sadrian	/* Apply suspend/detach work-arounds */
267300015Sadrian	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
268298479Sadrian		return (error);
269298479Sadrian
270298479Sadrian	return (bhnd_pci_generic_detach(dev));
271296077Sadrian}
272296077Sadrian
273296077Sadrianstatic int
274298479Sadrianbhnd_pci_hostb_suspend(device_t dev)
275296077Sadrian{
276298479Sadrian	struct bhnd_pcihb_softc *sc;
277298479Sadrian	int			 error;
278298479Sadrian
279298479Sadrian	sc = device_get_softc(dev);
280298479Sadrian
281298479Sadrian	/* Apply suspend/detach work-arounds */
282300015Sadrian	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
283298479Sadrian		return (error);
284298479Sadrian
285298479Sadrian	return (bhnd_pci_generic_suspend(dev));
286298479Sadrian}
287298479Sadrian
288298479Sadrianstatic int
289298479Sadrianbhnd_pci_hostb_resume(device_t dev)
290298479Sadrian{
291298479Sadrian	struct bhnd_pcihb_softc	*sc;
292298479Sadrian	int			 error;
293298479Sadrian
294298479Sadrian	sc = device_get_softc(dev);
295298479Sadrian
296298479Sadrian	if ((error = bhnd_pci_generic_resume(dev)))
297298479Sadrian		return (error);
298298479Sadrian
299298479Sadrian	/* Apply attach/resume work-arounds */
300300015Sadrian	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
301298479Sadrian		bhnd_pci_generic_detach(dev);
302298479Sadrian		return (error);
303298479Sadrian	}
304298479Sadrian
305296077Sadrian	return (0);
306296077Sadrian}
307296077Sadrian
308298479Sadrian/**
309298479Sadrian * Apply any hardware work-arounds that must be executed exactly once, early in
310298479Sadrian * the attach process.
311298479Sadrian *
312298479Sadrian * This must be called after core enumeration and discovery of all applicable
313298479Sadrian * quirks, but prior to probe/attach of any cores, parsing of
314298479Sadrian * SPROM, etc.
315298479Sadrian */
316296077Sadrianstatic int
317298479Sadrianbhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
318296077Sadrian{
319300015Sadrian	int error;
320300015Sadrian
321300015Sadrian	/* Set PCI latency timer */
322300015Sadrian	if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
323300015Sadrian		pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
324300015Sadrian		    1);
325300015Sadrian	}
326300015Sadrian
327300015Sadrian	/* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
328300015Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
329300015Sadrian		struct bhnd_board_info	board;
330300015Sadrian		bool			aspm_en;
331300015Sadrian
332300015Sadrian		/* Fetch board info */
333300015Sadrian		if ((error = bhnd_read_board_info(sc->dev, &board)))
334300015Sadrian			return (error);
335300015Sadrian
336300015Sadrian		/* Check board flags */
337300015Sadrian		aspm_en = true;
338300015Sadrian		if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
339300015Sadrian			aspm_en = false;
340300015Sadrian
341300015Sadrian		/* Early Apple devices did not (but should have) set
342300015Sadrian		 * BHND_BFL2_PCIEWAR_OVR in SPROM. */
343300015Sadrian		if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
344300015Sadrian			aspm_en = false;
345300015Sadrian
346300015Sadrian		sc->aspm_quirk_override.aspm_en = aspm_en;
347300015Sadrian	}
348300015Sadrian
349298479Sadrian	/* Determine correct polarity by observing the attach-time PCIe PHY
350298479Sadrian	 * link status. This is used later to reset/force the SerDes
351298479Sadrian	 * polarity */
352298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
353298479Sadrian		uint32_t st;
354298479Sadrian		bool inv;
355298479Sadrian
356298479Sadrian		st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
357298479Sadrian		inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
358298479Sadrian		sc->sdr9_quirk_polarity.inv = inv;
359298479Sadrian	}
360298479Sadrian
361300015Sadrian	/* Override maximum read request size */
362300015Sadrian	if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
363300015Sadrian		int	msize;
364300015Sadrian
365300015Sadrian		msize = 128; /* compatible with all PCIe-G1 core revisions */
366300015Sadrian		if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
367300015Sadrian			msize = 512;
368300015Sadrian
369300015Sadrian		if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
370300015Sadrian			panic("set mrrs on non-PCIe device");
371300015Sadrian	}
372300015Sadrian
373296077Sadrian	return (0);
374296077Sadrian}
375296077Sadrian
376298479Sadrian/**
377298479Sadrian * Apply any hardware workarounds that are required upon attach or resume
378298479Sadrian * of the bridge device.
379298479Sadrian */
380296077Sadrianstatic int
381300015Sadrianbhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
382296077Sadrian{
383298479Sadrian	/* Note that the order here matters; these work-arounds
384298479Sadrian	 * should not be re-ordered without careful review of their
385298479Sadrian	 * interdependencies */
386298479Sadrian
387298479Sadrian	/* Enable PCI prefetch/burst/readmulti flags */
388298479Sadrian	if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
389298479Sadrian	    sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
390298479Sadrian	{
391298479Sadrian		uint32_t sbp2;
392298479Sadrian		sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
393298479Sadrian
394298479Sadrian		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
395298479Sadrian			sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
396298479Sadrian
397298479Sadrian		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
398298479Sadrian			sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
399298479Sadrian
400298479Sadrian		BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
401298479Sadrian	}
402298479Sadrian
403298479Sadrian	/* Disable PCI CLKRUN# */
404298479Sadrian	if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
405298479Sadrian		uint32_t ctl;
406298479Sadrian
407298479Sadrian		ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
408298479Sadrian		ctl |= BHND_PCI_CLKRUN_DSBL;
409298479Sadrian		BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
410298479Sadrian	}
411298479Sadrian
412298479Sadrian	/* Enable TLP unmatched address handling work-around */
413298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
414298479Sadrian		uint32_t wrs;
415298479Sadrian		wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
416298479Sadrian		wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
417298479Sadrian		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
418298479Sadrian	}
419298479Sadrian
420298479Sadrian	/* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
421298479Sadrian	 * data during L0s to L0 exit transitions. */
422298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
423298479Sadrian		uint16_t sdv;
424298479Sadrian
425298479Sadrian		/* Set RX track/acquire timers to 2.064us/40.96us */
426298479Sadrian		sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
427298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
428298479Sadrian		    (40960/1024));
429298479Sadrian		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
430298479Sadrian		    BHND_PCIE_SDR9_RX_TIMER1, sdv);
431298479Sadrian
432298479Sadrian		/* Apply CDR frequency workaround */
433298479Sadrian		sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
434298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
435298479Sadrian		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
436298479Sadrian		    BHND_PCIE_SDR9_RX_CDR, sdv);
437298479Sadrian
438298479Sadrian		/* Apply CDR BW tunings */
439298479Sadrian		sdv = 0;
440298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
441298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
442298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
443298479Sadrian		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
444298479Sadrian		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
445298479Sadrian		    BHND_PCIE_SDR9_RX_CDRBW, sdv);
446298479Sadrian	}
447298479Sadrian
448298479Sadrian	/* Force correct SerDes polarity */
449298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
450298479Sadrian		uint16_t	rxctl;
451298479Sadrian
452298479Sadrian		rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
453298479Sadrian		    BHND_PCIE_SDR9_RX_CTRL);
454298479Sadrian
455298479Sadrian		rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
456298479Sadrian		if (sc->sdr9_quirk_polarity.inv)
457298479Sadrian			rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
458298479Sadrian		else
459298479Sadrian			rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
460298479Sadrian
461298479Sadrian		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
462298479Sadrian		    BHND_PCIE_SDR9_RX_CTRL, rxctl);
463298479Sadrian	}
464298479Sadrian
465298479Sadrian	/* Disable startup retry on PLL frequency detection failure */
466298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
467298479Sadrian		uint16_t	pctl;
468298479Sadrian
469298479Sadrian		pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
470298479Sadrian		    BHND_PCIE_SDR9_PLL_CTRL);
471298479Sadrian
472298479Sadrian		pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
473298479Sadrian		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
474298479Sadrian		    BHND_PCIE_SDR9_PLL_CTRL, pctl);
475298479Sadrian	}
476298479Sadrian
477298479Sadrian	/* Explicitly enable PCI-PM */
478298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
479298479Sadrian		uint32_t lcreg;
480298479Sadrian		lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
481298479Sadrian		lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
482298479Sadrian		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
483298479Sadrian	}
484298479Sadrian
485298479Sadrian	/* Adjust L1 timer to fix slow L1->L0 transitions */
486298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
487298479Sadrian		uint32_t pmt;
488298479Sadrian		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
489298479Sadrian		pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
490298479Sadrian		    BHND_PCIE_L1THRESHOLD_WARVAL);
491298479Sadrian		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
492298479Sadrian	}
493298479Sadrian
494298479Sadrian	/* Extend L1 timer for better performance.
495298479Sadrian	 * TODO: We could enable/disable this on demand for better power
496298479Sadrian	 * savings if we tie this to HT clock request handling */
497298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
498298479Sadrian		uint32_t pmt;
499298479Sadrian		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
500298479Sadrian		pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
501298479Sadrian		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
502298479Sadrian	}
503298479Sadrian
504300015Sadrian	/* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
505300015Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
506300015Sadrian		bus_size_t	reg;
507300015Sadrian		uint16_t	cfg;
508300015Sadrian
509300015Sadrian		/* Set ASPM L1/L0s flags in SPROM shadow */
510300015Sadrian		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
511300015Sadrian		cfg = BHND_PCI_READ_2(sc, reg);
512300015Sadrian
513300015Sadrian		if (sc->aspm_quirk_override.aspm_en)
514300015Sadrian			cfg |= BHND_PCIE_SRSH_ASPM_ENB;
515300015Sadrian		else
516300015Sadrian			cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
517300015Sadrian
518300015Sadrian		BHND_PCI_WRITE_2(sc, reg, cfg);
519300015Sadrian
520300015Sadrian
521300015Sadrian		/* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
522300015Sadrian		cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
523300015Sadrian
524300015Sadrian		if (sc->aspm_quirk_override.aspm_en)
525300015Sadrian			cfg |= PCIEM_LINK_CTL_ASPMC;
526300015Sadrian		else
527300015Sadrian			cfg &= ~PCIEM_LINK_CTL_ASPMC;
528300015Sadrian
529300015Sadrian		cfg &= ~PCIEM_LINK_CTL_ECPM;		/* CLKREQ# */
530300015Sadrian
531300015Sadrian		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
532300015Sadrian
533300015Sadrian		/* Set CLKREQ (ECPM) flags in SPROM shadow */
534300015Sadrian		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
535300015Sadrian		cfg = BHND_PCI_READ_2(sc, reg);
536300015Sadrian
537300015Sadrian		if (sc->aspm_quirk_override.aspm_en)
538300015Sadrian			cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
539300015Sadrian		else
540300015Sadrian			cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
541300015Sadrian
542300015Sadrian		BHND_PCI_WRITE_2(sc, reg, cfg);
543300015Sadrian	}
544300015Sadrian
545298479Sadrian	/* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
546298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
547298479Sadrian		bus_size_t	reg;
548298479Sadrian		uint16_t	cfg;
549298479Sadrian
550298479Sadrian		/* Fetch the misc cfg flags from SPROM */
551298479Sadrian		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
552298479Sadrian		cfg = BHND_PCI_READ_2(sc, reg);
553298479Sadrian
554298479Sadrian		/* Write EXIT_NOPRST flag if not already set in SPROM */
555298479Sadrian		if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
556298479Sadrian			cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
557298479Sadrian			BHND_PCI_WRITE_2(sc, reg, cfg);
558298479Sadrian		}
559298479Sadrian	}
560298479Sadrian
561300015Sadrian	/* Disable SerDes PLL down */
562300015Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
563300015Sadrian		device_t	bhnd, chipc;
564300015Sadrian		bus_size_t	reg;
565300015Sadrian
566300015Sadrian		bhnd = device_get_parent(sc->dev);
567300015Sadrian		chipc = bhnd_find_child(bhnd, BHND_DEVCLASS_CC, 0);
568300015Sadrian		KASSERT(chipc != NULL, ("missing chipcommon device"));
569300015Sadrian
570300015Sadrian		/* Write SerDes PLL disable flag to the ChipCommon core */
571300015Sadrian		BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
572300015Sadrian		    CHIPCTRL_4321_PLL_DOWN);
573300015Sadrian
574300015Sadrian		/* Clear SPROM shadow backdoor register */
575300015Sadrian		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
576300015Sadrian		BHND_PCI_WRITE_2(sc, reg, 0);
577300015Sadrian	}
578300015Sadrian
579300015Sadrian	/* Adjust TX drive strength and pre-emphasis coefficient */
580300015Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
581300015Sadrian		uint16_t txdrv;
582300015Sadrian
583300015Sadrian		/* Fetch current TX driver parameters */
584300015Sadrian		txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
585300015Sadrian		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
586300015Sadrian
587300015Sadrian		/* Set 700mV drive strength */
588300015Sadrian		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
589300015Sadrian			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
590300015Sadrian			    BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
591300015Sadrian
592300015Sadrian			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
593300015Sadrian			    BHND_PCIE_APPLE_TX_IDRIVER_700MV);
594300015Sadrian		}
595300015Sadrian
596300015Sadrian		/* ... or, set max drive strength */
597300015Sadrian		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
598300015Sadrian			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
599300015Sadrian			    BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
600300015Sadrian
601300015Sadrian			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
602300015Sadrian			    BHND_PCIE_APPLE_TX_IDRIVER_MAX);
603300015Sadrian		}
604300015Sadrian
605300015Sadrian		BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
606300015Sadrian		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
607300015Sadrian	}
608300015Sadrian
609296077Sadrian	return (0);
610296077Sadrian}
611296077Sadrian
612298479Sadrian/**
613298479Sadrian * Apply any hardware workarounds that are required upon detach or suspend
614298479Sadrian * of the bridge device.
615298479Sadrian */
616298479Sadrianstatic int
617300015Sadrianbhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
618300015Sadrian{
619298479Sadrian	/* Reduce L1 timer for better power savings.
620298479Sadrian	 * TODO: We could enable/disable this on demand for better power
621298479Sadrian	 * savings if we tie this to HT clock request handling */
622298479Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
623298479Sadrian		uint32_t pmt;
624298479Sadrian		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
625298479Sadrian		pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
626298479Sadrian		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
627298479Sadrian	}
628298479Sadrian
629300015Sadrian	/* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
630300015Sadrian	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
631300015Sadrian		uint16_t	lcreg;
632300015Sadrian
633300015Sadrian		lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
634300015Sadrian
635300015Sadrian		lcreg |= PCIEM_LINK_CTL_ECPM;	/* CLKREQ# */
636300015Sadrian		if (state == BHND_PCI_WAR_SUSPEND)
637300015Sadrian			lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
638300015Sadrian
639300015Sadrian		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
640300015Sadrian	}
641300015Sadrian
642298479Sadrian	return (0);
643298479Sadrian}
644298479Sadrian
645296077Sadrianstatic device_method_t bhnd_pci_hostb_methods[] = {
646296077Sadrian	/* Device interface */
647298479Sadrian	DEVMETHOD(device_attach,		bhnd_pci_hostb_attach),
648298479Sadrian	DEVMETHOD(device_detach,		bhnd_pci_hostb_detach),
649298479Sadrian	DEVMETHOD(device_suspend,		bhnd_pci_hostb_suspend),
650298479Sadrian	DEVMETHOD(device_resume,		bhnd_pci_hostb_resume),
651296077Sadrian
652296077Sadrian	DEVMETHOD_END
653296077Sadrian};
654296077Sadrian
655300015SadrianDEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
656298479Sadrian    sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
657300015SadrianDRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
658296077Sadrian
659296077SadrianMODULE_VERSION(bhnd_pci_hostb, 1);
660298947SadrianMODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
661298479SadrianMODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);
662