1d943d79aSZbigniew Bodek /*-
2d943d79aSZbigniew Bodek * Copyright (c) 2015 The FreeBSD Foundation
3d943d79aSZbigniew Bodek *
4d943d79aSZbigniew Bodek * This software was developed by Semihalf under
5d943d79aSZbigniew Bodek * the sponsorship of the FreeBSD Foundation.
6d943d79aSZbigniew Bodek *
7d943d79aSZbigniew Bodek * Redistribution and use in source and binary forms, with or without
8d943d79aSZbigniew Bodek * modification, are permitted provided that the following conditions
9d943d79aSZbigniew Bodek * are met:
10d943d79aSZbigniew Bodek * 1. Redistributions of source code must retain the above copyright
11d943d79aSZbigniew Bodek * notice, this list of conditions and the following disclaimer.
12d943d79aSZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright
13d943d79aSZbigniew Bodek * notice, this list of conditions and the following disclaimer in the
14d943d79aSZbigniew Bodek * documentation and/or other materials provided with the distribution.
15d943d79aSZbigniew Bodek *
16d943d79aSZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d943d79aSZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d943d79aSZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d943d79aSZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d943d79aSZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d943d79aSZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d943d79aSZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d943d79aSZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d943d79aSZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d943d79aSZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d943d79aSZbigniew Bodek * SUCH DAMAGE.
27d943d79aSZbigniew Bodek */
28d943d79aSZbigniew Bodek
29d943d79aSZbigniew Bodek /* Common PCIe functions for Cavium Thunder SOC */
30d943d79aSZbigniew Bodek
31d943d79aSZbigniew Bodek #include <sys/cdefs.h>
32fb05500bSWojciech Macek #include "opt_platform.h"
33fb05500bSWojciech Macek
34d943d79aSZbigniew Bodek #include <sys/param.h>
35d943d79aSZbigniew Bodek #include <sys/systm.h>
36d943d79aSZbigniew Bodek #include <sys/kernel.h>
3768a59477SZbigniew Bodek #include <sys/malloc.h>
38d943d79aSZbigniew Bodek #include <sys/bus.h>
39bc5758b6SZbigniew Bodek #include <sys/rman.h>
40bc5758b6SZbigniew Bodek
41d943d79aSZbigniew Bodek #include <machine/bus.h>
42d943d79aSZbigniew Bodek #include <machine/cpu.h>
43d943d79aSZbigniew Bodek #include <machine/intr.h>
44d943d79aSZbigniew Bodek
45fb05500bSWojciech Macek #ifdef FDT
46fb05500bSWojciech Macek #include <dev/ofw/openfirm.h>
47fb05500bSWojciech Macek #include <dev/ofw/ofw_bus.h>
48fb05500bSWojciech Macek #include <dev/ofw/ofw_bus_subr.h>
49fb05500bSWojciech Macek #include <dev/ofw/ofw_pci.h>
50fb05500bSWojciech Macek #endif
51fb05500bSWojciech Macek
522445e7c8SWojciech Macek #include <sys/pciio.h>
53fb05500bSWojciech Macek #include <dev/pci/pcireg.h>
542445e7c8SWojciech Macek #include <dev/pci/pcivar.h>
552445e7c8SWojciech Macek #include <dev/pci/pci_private.h>
56fb05500bSWojciech Macek #include <dev/pci/pcib_private.h>
57fb05500bSWojciech Macek #include <dev/pci/pci_host_generic.h>
58f94f8e62SAndrew Turner #ifdef FDT
59f94f8e62SAndrew Turner #include <dev/pci/pci_host_generic_fdt.h>
60f94f8e62SAndrew Turner #endif
61fb05500bSWojciech Macek
62d943d79aSZbigniew Bodek #include "thunder_pcie_common.h"
63d943d79aSZbigniew Bodek
6468a59477SZbigniew Bodek MALLOC_DEFINE(M_THUNDER_PCIE, "Thunder PCIe driver", "Thunder PCIe driver memory");
6568a59477SZbigniew Bodek
66fb05500bSWojciech Macek #define THUNDER_CFG_BASE_TO_ECAM(x) ((((x) >> 36UL) & 0x3) | (((x) >> 42UL) & 0x4))
67fb05500bSWojciech Macek
68d943d79aSZbigniew Bodek uint32_t
range_addr_is_pci(struct pcie_range * ranges,uint64_t addr,uint64_t size)69d943d79aSZbigniew Bodek range_addr_is_pci(struct pcie_range *ranges, uint64_t addr, uint64_t size)
70d943d79aSZbigniew Bodek {
71d943d79aSZbigniew Bodek struct pcie_range *r;
72d943d79aSZbigniew Bodek int tuple;
73d943d79aSZbigniew Bodek
74fb05500bSWojciech Macek for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
75d943d79aSZbigniew Bodek r = &ranges[tuple];
76d943d79aSZbigniew Bodek if (addr >= r->pci_base &&
77d943d79aSZbigniew Bodek addr < (r->pci_base + r->size) &&
78d943d79aSZbigniew Bodek size < r->size) {
79d943d79aSZbigniew Bodek /* Address is within PCI range */
80d943d79aSZbigniew Bodek return (1);
81d943d79aSZbigniew Bodek }
82d943d79aSZbigniew Bodek }
83d943d79aSZbigniew Bodek
84d943d79aSZbigniew Bodek /* Address is outside PCI range */
85d943d79aSZbigniew Bodek return (0);
86d943d79aSZbigniew Bodek }
87d943d79aSZbigniew Bodek
88d943d79aSZbigniew Bodek uint32_t
range_addr_is_phys(struct pcie_range * ranges,uint64_t addr,uint64_t size)89d943d79aSZbigniew Bodek range_addr_is_phys(struct pcie_range *ranges, uint64_t addr, uint64_t size)
90d943d79aSZbigniew Bodek {
91d943d79aSZbigniew Bodek struct pcie_range *r;
92d943d79aSZbigniew Bodek int tuple;
93d943d79aSZbigniew Bodek
94fb05500bSWojciech Macek for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
95d943d79aSZbigniew Bodek r = &ranges[tuple];
96d943d79aSZbigniew Bodek if (addr >= r->phys_base &&
97d943d79aSZbigniew Bodek addr < (r->phys_base + r->size) &&
98d943d79aSZbigniew Bodek size < r->size) {
99d943d79aSZbigniew Bodek /* Address is within Physical range */
100d943d79aSZbigniew Bodek return (1);
101d943d79aSZbigniew Bodek }
102d943d79aSZbigniew Bodek }
103d943d79aSZbigniew Bodek
104d943d79aSZbigniew Bodek /* Address is outside Physical range */
105d943d79aSZbigniew Bodek return (0);
106d943d79aSZbigniew Bodek }
107d943d79aSZbigniew Bodek
108d943d79aSZbigniew Bodek uint64_t
range_addr_phys_to_pci(struct pcie_range * ranges,uint64_t phys_addr)10952ea10afSWojciech Macek range_addr_phys_to_pci(struct pcie_range *ranges, uint64_t phys_addr)
11052ea10afSWojciech Macek {
11152ea10afSWojciech Macek struct pcie_range *r;
11252ea10afSWojciech Macek uint64_t offset;
11352ea10afSWojciech Macek int tuple;
11452ea10afSWojciech Macek
11552ea10afSWojciech Macek /* Find physical address corresponding to given bus address */
11652ea10afSWojciech Macek for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
11752ea10afSWojciech Macek r = &ranges[tuple];
11852ea10afSWojciech Macek if (phys_addr >= r->phys_base &&
11952ea10afSWojciech Macek phys_addr < (r->phys_base + r->size)) {
12052ea10afSWojciech Macek /* Given phys addr is in this range.
12152ea10afSWojciech Macek * Translate phys addr to bus addr.
12252ea10afSWojciech Macek */
12352ea10afSWojciech Macek offset = phys_addr - r->phys_base;
12452ea10afSWojciech Macek return (r->pci_base + offset);
12552ea10afSWojciech Macek }
12652ea10afSWojciech Macek }
12752ea10afSWojciech Macek return (0);
12852ea10afSWojciech Macek }
12952ea10afSWojciech Macek
13052ea10afSWojciech Macek uint64_t
range_addr_pci_to_phys(struct pcie_range * ranges,uint64_t pci_addr)131d943d79aSZbigniew Bodek range_addr_pci_to_phys(struct pcie_range *ranges, uint64_t pci_addr)
132d943d79aSZbigniew Bodek {
133d943d79aSZbigniew Bodek struct pcie_range *r;
134d943d79aSZbigniew Bodek uint64_t offset;
135d943d79aSZbigniew Bodek int tuple;
136d943d79aSZbigniew Bodek
137d943d79aSZbigniew Bodek /* Find physical address corresponding to given bus address */
138fb05500bSWojciech Macek for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
139d943d79aSZbigniew Bodek r = &ranges[tuple];
140d943d79aSZbigniew Bodek if (pci_addr >= r->pci_base &&
141d943d79aSZbigniew Bodek pci_addr < (r->pci_base + r->size)) {
142d943d79aSZbigniew Bodek /* Given pci addr is in this range.
143d943d79aSZbigniew Bodek * Translate bus addr to phys addr.
144d943d79aSZbigniew Bodek */
145d943d79aSZbigniew Bodek offset = pci_addr - r->pci_base;
146d943d79aSZbigniew Bodek return (r->phys_base + offset);
147d943d79aSZbigniew Bodek }
148d943d79aSZbigniew Bodek }
149d943d79aSZbigniew Bodek return (0);
150d943d79aSZbigniew Bodek }
151d943d79aSZbigniew Bodek
152fb05500bSWojciech Macek int
thunder_pcie_identify_ecam(device_t dev,int * ecam)153fb05500bSWojciech Macek thunder_pcie_identify_ecam(device_t dev, int *ecam)
154fb05500bSWojciech Macek {
155fb05500bSWojciech Macek rman_res_t start;
156fb05500bSWojciech Macek
157fb05500bSWojciech Macek /* Check if we're running on Cavium ThunderX */
158fb05500bSWojciech Macek if (!CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK,
159*8b47c1aeSAndrew Turner CPU_IMPL_CAVIUM, CPU_PART_THUNDERX, 0, 0))
160fb05500bSWojciech Macek return (EINVAL);
161fb05500bSWojciech Macek
162fb05500bSWojciech Macek start = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
163fb05500bSWojciech Macek *ecam = THUNDER_CFG_BASE_TO_ECAM(start);
164fb05500bSWojciech Macek
165fb05500bSWojciech Macek device_printf(dev, "ThunderX quirk, setting ECAM to %d\n", *ecam);
166fb05500bSWojciech Macek
167fb05500bSWojciech Macek return (0);
168fb05500bSWojciech Macek }
1692445e7c8SWojciech Macek
1702445e7c8SWojciech Macek #ifdef THUNDERX_PASS_1_1_ERRATA
1712445e7c8SWojciech Macek struct resource *
thunder_pcie_alloc_resource(device_t dev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)1722445e7c8SWojciech Macek thunder_pcie_alloc_resource(device_t dev, device_t child, int type, int *rid,
1732445e7c8SWojciech Macek rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
1742445e7c8SWojciech Macek {
1752445e7c8SWojciech Macek pci_addr_t map, testval;
1762445e7c8SWojciech Macek
1772445e7c8SWojciech Macek /*
1782445e7c8SWojciech Macek * If Enhanced Allocation is not used, we can't allocate any random
1792445e7c8SWojciech Macek * range. All internal devices have hardcoded place where they can
1802445e7c8SWojciech Macek * be located within PCI address space. Fortunately, we can read
1812445e7c8SWojciech Macek * this value from BAR.
1822445e7c8SWojciech Macek */
1832445e7c8SWojciech Macek if (((type == SYS_RES_IOPORT) || (type == SYS_RES_MEMORY)) &&
1842445e7c8SWojciech Macek RMAN_IS_DEFAULT_RANGE(start, end)) {
1852445e7c8SWojciech Macek /* Read BAR manually to get resource address and size */
1862445e7c8SWojciech Macek pci_read_bar(child, *rid, &map, &testval, NULL);
1872445e7c8SWojciech Macek
1882445e7c8SWojciech Macek /* Mask the information bits */
1892445e7c8SWojciech Macek if (PCI_BAR_MEM(map))
1902445e7c8SWojciech Macek map &= PCIM_BAR_MEM_BASE;
1912445e7c8SWojciech Macek else
1922445e7c8SWojciech Macek map &= PCIM_BAR_IO_BASE;
1932445e7c8SWojciech Macek
1942445e7c8SWojciech Macek if (PCI_BAR_MEM(testval))
1952445e7c8SWojciech Macek testval &= PCIM_BAR_MEM_BASE;
1962445e7c8SWojciech Macek else
1972445e7c8SWojciech Macek testval &= PCIM_BAR_IO_BASE;
1982445e7c8SWojciech Macek
1992445e7c8SWojciech Macek start = map;
2002445e7c8SWojciech Macek end = start + count - 1;
2012445e7c8SWojciech Macek }
2022445e7c8SWojciech Macek
203d2314cb3SAndrew Turner return (pci_host_generic_core_alloc_resource(dev, child, type, rid,
204d2314cb3SAndrew Turner start, end, count, flags));
2052445e7c8SWojciech Macek }
2062445e7c8SWojciech Macek #endif
207