Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 6cbdafb

Browse files
committed
WIP: Add support for the NXP Layerscape PCIe Gen4 controller
1 parent e50ea4d commit 6cbdafb

File tree

3 files changed

+321
-0
lines changed

3 files changed

+321
-0
lines changed

sys/arm64/conf/GENERIC

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ device cpufreq
148148
# Bus drivers
149149
device pci
150150
device pci_n1sdp # ARM Neoverse N1 SDP PCI
151+
device pci_layerscape # NXP Layerscape LX2160 PCI
151152
device al_pci # Annapurna Alpine PCI-E
152153
options PCI_HP # PCI-Express native HotPlug
153154
options PCI_IOV # PCI SR-IOV support

sys/conf/files.arm64

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ dev/neta/if_mvneta.c optional neta mdio mii
285285
dev/ofw/ofw_cpu.c optional fdt
286286
dev/ofw/ofwpci.c optional fdt pci
287287
dev/pci/controller/pci_n1sdp.c optional pci_n1sdp acpi
288+
dev/pci/controller/pci_layerscape.c optional pci_layerscape acpi
288289
dev/pci/pci_host_generic.c optional pci
289290
dev/pci/pci_host_generic_acpi.c optional pci acpi
290291
dev/pci/pci_host_generic_fdt.c optional pci fdt
Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/*-
2+
* Copyright (c) 2020 The NetBSD Foundation, Inc.
3+
* All rights reserved.
4+
*
5+
* This code is derived from software contributed to The NetBSD Foundation
6+
* by Jared McNeill <jmcneill@invisible.ca>.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
* 1. Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in the
15+
* documentation and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18+
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* 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 IN
25+
* 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 THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
*/
29+
30+
/*
31+
* NXP Layerscape PCIe Gen4 controller (not ECAM compliant)
32+
*/
33+
34+
#include <sys/cdefs.h>
35+
__FBSDID("$FreeBSD$");
36+
37+
#include <sys/param.h>
38+
#include <sys/systm.h>
39+
#include <sys/malloc.h>
40+
#include <sys/bus.h>
41+
#include <sys/endian.h>
42+
#include <sys/kernel.h>
43+
#include <sys/module.h>
44+
#include <sys/rman.h>
45+
#include <sys/mutex.h>
46+
47+
#include <vm/vm.h>
48+
#include <vm/vm_extern.h>
49+
#include <vm/vm_page.h>
50+
51+
#include <contrib/dev/acpica/include/acpi.h>
52+
#include <contrib/dev/acpica/include/accommon.h>
53+
54+
#include <dev/acpica/acpivar.h>
55+
#include <dev/acpica/acpi_pcibvar.h>
56+
57+
#include <dev/pci/pcivar.h>
58+
#include <dev/pci/pcireg.h>
59+
#include <dev/pci/pcib_private.h>
60+
#include <dev/pci/pci_host_generic.h>
61+
#include <dev/pci/pci_host_generic_acpi.h>
62+
63+
#include "pcib_if.h"
64+
65+
#define __BIT(__n) (((__n) == 32) ? 0 : ((uint32_t)1 << (__n)))
66+
#define __BITS(__m, __n) \
67+
((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
68+
#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
69+
#define __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask))
70+
71+
#define PCI_ID_REG 0
72+
73+
#define PAB_CTRL 0x808
74+
#define PAB_CTRL_PAGE_SEL __BITS(18,13)
75+
#define PAB_AXI_AMAP_PEX_WIN_L(x) (0xba8 + 0x10 * (x))
76+
#define PAB_AXI_AMAP_PEX_WIN_H(x) (0xbac + 0x10 * (x))
77+
#define INDIRECT_ADDR_BOUNDARY 0xc00
78+
79+
#define LUT_BASE 0x80000
80+
#define LUT_GCR 0x28
81+
#define LUT_GCR_RRE __BIT(0)
82+
83+
#define REG_TO_PAGE_INDEX(reg) (((reg) >> 10) & 0x3ff)
84+
#define REG_TO_PAGE_ADDR(reg) (((reg) & 0x3ff) | INDIRECT_ADDR_BOUNDARY)
85+
86+
#define PAB_TARGET_BUS(b) ((b) << 24)
87+
#define PAB_TARGET_DEV(d) ((d) << 19)
88+
#define PAB_TARGET_FUNC(f) ((f) << 16)
89+
90+
struct layerscape_pcie_acpi_softc {
91+
struct generic_pcie_acpi_softc acpi;
92+
93+
bus_space_handle_t bsh;
94+
uint8_t rev;
95+
struct mtx lock;
96+
};
97+
98+
static void
99+
layerscape_ccsr_setpage(struct layerscape_pcie_acpi_softc *sc, u_int page_index)
100+
{
101+
uint32_t val;
102+
103+
val = bus_space_read_4(sc->acpi.base.bst, sc->bsh, PAB_CTRL);
104+
val &= ~PAB_CTRL_PAGE_SEL;
105+
val |= __SHIFTIN(page_index, PAB_CTRL_PAGE_SEL);
106+
bus_space_write_4(sc->acpi.base.bst, sc->bsh, PAB_CTRL, val);
107+
}
108+
109+
static uint32_t
110+
layerscape_ccsr_read4(struct layerscape_pcie_acpi_softc *sc, bus_size_t reg)
111+
{
112+
const bool indirect = reg >= INDIRECT_ADDR_BOUNDARY;
113+
const u_int page_index = indirect ? REG_TO_PAGE_INDEX(reg) : 0;
114+
const bus_size_t page_addr = indirect ? REG_TO_PAGE_ADDR(reg) : reg;
115+
116+
layerscape_ccsr_setpage(sc, page_index);
117+
return (bus_space_read_4(sc->acpi.base.bst, sc->bsh, page_addr));
118+
}
119+
120+
static void
121+
layerscape_ccsr_write4(struct layerscape_pcie_acpi_softc *sc,
122+
bus_size_t reg, uint32_t data)
123+
{
124+
const bool indirect = reg >= INDIRECT_ADDR_BOUNDARY;
125+
const u_int page_index = indirect ? REG_TO_PAGE_INDEX(reg) : 0;
126+
const bus_size_t page_addr = indirect ? REG_TO_PAGE_ADDR(reg) : reg;
127+
128+
layerscape_ccsr_setpage(sc, page_index);
129+
bus_space_write_4(sc->acpi.base.bst, sc->bsh, page_addr, data);
130+
}
131+
132+
static void
133+
layerscape_select_target(struct layerscape_pcie_acpi_softc *sc,
134+
u_int bus, u_int slot, u_int func)
135+
{
136+
const uint32_t target = PAB_TARGET_BUS(bus) |
137+
PAB_TARGET_DEV(slot) | PAB_TARGET_FUNC(func);
138+
139+
layerscape_ccsr_write4(sc, PAB_AXI_AMAP_PEX_WIN_L(0), target);
140+
layerscape_ccsr_write4(sc, PAB_AXI_AMAP_PEX_WIN_H(0), 0);
141+
}
142+
143+
144+
static uint32_t
145+
layerscape_pcie_read_config(device_t dev, u_int bus, u_int slot,
146+
u_int func, u_int reg, int bytes)
147+
{
148+
struct layerscape_pcie_acpi_softc *sc = device_get_softc(dev);
149+
uint32_t result;
150+
151+
if ((bus <= sc->acpi.base.bus_start + 1) && (slot > 0))
152+
return (~0U);
153+
if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
154+
(reg > PCIE_REGMAX))
155+
return (~0U);
156+
/* XXX: NetBSD does acpimcfg_conf_valid for bus != bus_start */
157+
158+
mtx_lock(&sc->lock);
159+
160+
if (sc->rev == 0x10 && reg == PCI_ID_REG)
161+
bus_space_write_4(sc->acpi.base.bst, sc->bsh, LUT_BASE + LUT_GCR, 0);
162+
163+
if (bus == sc->acpi.base.bus_start) {
164+
result = layerscape_ccsr_read4(sc, reg);
165+
} else {
166+
layerscape_select_target(sc, bus, slot, func);
167+
result = bus_space_read_4(sc->acpi.base.bst, sc->acpi.base.bsh, reg);
168+
}
169+
170+
if (sc->rev == 0x10 && reg == PCI_ID_REG)
171+
bus_space_write_4(sc->acpi.base.bst, sc->bsh, LUT_BASE + LUT_GCR, LUT_GCR_RRE);
172+
173+
mtx_unlock(&sc->lock);
174+
return (result);
175+
}
176+
177+
static void
178+
layerscape_pcie_write_config(device_t dev, u_int bus, u_int slot,
179+
u_int func, u_int reg, uint32_t data, int bytes)
180+
{
181+
struct layerscape_pcie_acpi_softc *sc = device_get_softc(dev);
182+
183+
if ((bus <= sc->acpi.base.bus_start + 1) && (slot > 0))
184+
return;
185+
if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
186+
(reg > PCIE_REGMAX))
187+
return;
188+
/* XXX: NetBSD does acpimcfg_conf_valid for bus != bus_start */
189+
190+
mtx_lock(&sc->lock);
191+
192+
if (bus == sc->acpi.base.bus_start) {
193+
layerscape_ccsr_write4(sc, reg, data);
194+
} else {
195+
layerscape_select_target(sc, bus, slot, func);
196+
bus_space_write_4(sc->acpi.base.bst, sc->acpi.base.bsh, reg, data);
197+
}
198+
199+
mtx_unlock(&sc->lock);
200+
}
201+
202+
static int
203+
layerscape_pcie_acpi_probe(device_t dev)
204+
{
205+
ACPI_DEVICE_INFO *devinfo;
206+
ACPI_TABLE_HEADER *hdr;
207+
ACPI_STATUS status;
208+
ACPI_HANDLE h;
209+
int root;
210+
211+
if (acpi_disabled("pcib") || (h = acpi_get_handle(dev)) == NULL ||
212+
ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
213+
return (ENXIO);
214+
215+
root = (devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0;
216+
AcpiOsFree(devinfo);
217+
if (!root)
218+
return (ENXIO);
219+
220+
/* TODO: Move this to an ACPI quirk? */
221+
status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr);
222+
if (ACPI_FAILURE(status))
223+
return (ENXIO);
224+
225+
if (memcmp(hdr->OemId, "NXP ", ACPI_OEM_ID_SIZE) != 0 ||
226+
memcmp(hdr->OemTableId, "LX2160 ", ACPI_OEM_TABLE_ID_SIZE) != 0)
227+
return (ENXIO);
228+
229+
device_set_desc(dev, "NXP Layerscape PCI host controller");
230+
return (BUS_PROBE_DEFAULT);
231+
}
232+
233+
static ACPI_STATUS
234+
nxp0016_resource_handler(ACPI_RESOURCE *res, void *context)
235+
{
236+
device_t dev;
237+
struct layerscape_pcie_acpi_softc *sc;
238+
vm_offset_t base_addr;
239+
size_t length;
240+
241+
if (res->Type != ACPI_RESOURCE_TYPE_FIXED_MEMORY32)
242+
return (AE_OK);
243+
244+
dev = context;
245+
device_printf(dev, "found the memory resource!");
246+
sc = device_get_softc(dev);
247+
248+
base_addr = (vm_offset_t)res->Data.FixedMemory32.Address;
249+
length = res->Data.FixedMemory32.AddressLength;
250+
251+
if (bus_space_map(sc->acpi.base.bst, base_addr, length, 0, &sc->bsh) != 0)
252+
return (AE_ERROR);
253+
254+
device_printf(dev, "mapped the memory resource!");
255+
256+
return (AE_OK);
257+
}
258+
259+
static ACPI_STATUS
260+
child_device_handler(ACPI_HANDLE handle, UINT32 level,
261+
void *context, void **status)
262+
{
263+
// ACPI_HANDLE h;
264+
265+
// ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
266+
267+
if (!acpi_MatchHid(handle, "NXP0016"))
268+
return (AE_OK);
269+
270+
device_printf((device_t)context, "found the nxp0016!");
271+
272+
return (AcpiWalkResources(handle, "_CRS",
273+
nxp0016_resource_handler, context));
274+
}
275+
276+
static int
277+
layerscape_pcie_acpi_attach(device_t dev)
278+
{
279+
struct layerscape_pcie_acpi_softc *sc;
280+
// ACPI_HANDLE handle;
281+
// ACPI_STATUS status;
282+
int err;
283+
284+
err = pci_host_generic_acpi_init(dev);
285+
if (err != 0)
286+
return (err);
287+
288+
sc = device_get_softc(dev);
289+
// handle = acpi_get_handle(dev);
290+
291+
// _SEG: sc->acpi.base.ecam
292+
AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 100,
293+
child_device_handler, NULL, dev, NULL);
294+
295+
sc->rev = bus_space_read_4(sc->acpi.base.bst, sc->bsh, 0x08) & 0xff;
296+
device_printf(dev, "Controller revision %#x\n", sc->rev);
297+
298+
device_add_child(dev, "pci", -1);
299+
return (bus_generic_attach(dev));
300+
}
301+
302+
static device_method_t layerscape_pcie_acpi_methods[] = {
303+
DEVMETHOD(device_probe, layerscape_pcie_acpi_probe),
304+
DEVMETHOD(device_attach, layerscape_pcie_acpi_attach),
305+
306+
/* pcib interface */
307+
DEVMETHOD(pcib_read_config, layerscape_pcie_read_config),
308+
DEVMETHOD(pcib_write_config, layerscape_pcie_write_config),
309+
310+
DEVMETHOD_END
311+
};
312+
313+
DEFINE_CLASS_1(pcib, layerscape_pcie_acpi_driver, layerscape_pcie_acpi_methods,
314+
sizeof(struct layerscape_pcie_acpi_softc), generic_pcie_acpi_driver);
315+
316+
static devclass_t layerscape_pcie_acpi_devclass;
317+
318+
DRIVER_MODULE(layerscape_pcib, acpi, layerscape_pcie_acpi_driver,
319+
layerscape_pcie_acpi_devclass, 0, 0);

0 commit comments

Comments
 (0)