aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64/rockchip
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2020-09-19 11:27:16 +0000
committerMichal Meloun <mmel@FreeBSD.org>2020-09-19 11:27:16 +0000
commitb8bfffc1b619cca5262f848b665bd56c4de0052b (patch)
treec4e97c4166cb1d819ad07baf73dc00fbe476e803 /sys/arm64/rockchip
parent95a85c125d0e6761eb56430e6679358ffab53624 (diff)
downloadsrc-b8bfffc1b619cca5262f848b665bd56c4de0052b.tar.gz
src-b8bfffc1b619cca5262f848b665bd56c4de0052b.zip
Implement workaround for broken access to configuration space.
Due to a HW bug in the RockChip PCIe implementation, attempting to access a non-existent register in the configuration space will throw an exception. Use new bus functions bus_peek() and bus_poke() to overcomme this limitation.
Notes
Notes: svn path=/head/; revision=365900
Diffstat (limited to 'sys/arm64/rockchip')
-rw-r--r--sys/arm64/rockchip/rk_pcie.c55
1 files changed, 21 insertions, 34 deletions
diff --git a/sys/arm64/rockchip/rk_pcie.c b/sys/arm64/rockchip/rk_pcie.c
index 9c1e6b04d8e2..ea4ce5b568e6 100644
--- a/sys/arm64/rockchip/rk_pcie.c
+++ b/sys/arm64/rockchip/rk_pcie.c
@@ -310,7 +310,7 @@ rk_pcie_check_dev(struct rk_pcie_softc *sc, u_int bus, u_int slot, u_int func,
uint32_t val;
if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX ||
- func > PCI_FUNCMAX || reg > PCI_REGMAX)
+ func > PCI_FUNCMAX || reg > PCIE_REGMAX)
return (false);
if (bus == sc->root_bus) {
@@ -325,8 +325,8 @@ rk_pcie_check_dev(struct rk_pcie_softc *sc, u_int bus, u_int slot, u_int func,
if (STATUS1_LINK_ST_GET(val) != STATUS1_LINK_ST_UP)
return (false);
- /* only one device is on first subordinate bus */
- if (bus == sc->sub_bus && slot)
+ /* only one device can be on first subordinate bus */
+ if (bus == sc->sub_bus && slot != 0 )
return (false);
return (true);
}
@@ -452,45 +452,41 @@ rk_pcie_read_config(device_t dev, u_int bus, u_int slot,
u_int func, u_int reg, int bytes)
{
struct rk_pcie_softc *sc;
- uint32_t data;
+ uint32_t d32, data;
+ uint16_t d16;
+ uint8_t d8;
uint64_t addr;
- int type;
+ int type, ret;
sc = device_get_softc(dev);
if (!rk_pcie_check_dev(sc, bus, slot, func, reg))
return (0xFFFFFFFFU);
-
if (bus == sc->root_bus)
return (rk_pcie_local_cfg_read(sc, false, reg, bytes));
addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) |
ATU_CFG_REG(reg);
- if (bus == sc->sub_bus) {
- type = ATU_TYPE_CFG0;
- } else {
- type = ATU_TYPE_CFG1;
- /*
- * XXX FIXME: any attempt to generate type1 configuration
- * access causes external data abort
- */
- return (0xFFFFFFFFU);
- }
+ type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1;
rk_pcie_map_cfg_atu(sc, 0, type);
+ ret = -1;
switch (bytes) {
case 1:
- data = bus_read_1(sc->axi_mem_res, addr);
+ ret = bus_peek_1(sc->axi_mem_res, addr, &d8);
+ data = d8;
break;
case 2:
- data = bus_read_2(sc->axi_mem_res, addr);
+ ret = bus_peek_2(sc->axi_mem_res, addr, &d16);
+ data = d16;
break;
case 4:
- data = bus_read_4(sc->axi_mem_res, addr);
+ ret = bus_peek_4(sc->axi_mem_res, addr, &d32);
+ data = d32;
break;
- default:
- data = 0xFFFFFFFFU;
}
+ if (ret != 0)
+ data = 0xFFFFFFFF;
return (data);
}
@@ -512,27 +508,18 @@ rk_pcie_write_config(device_t dev, u_int bus, u_int slot,
addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) |
ATU_CFG_REG(reg);
- if (bus == sc->sub_bus){
- type = ATU_TYPE_CFG0;
- } else {
- type = ATU_TYPE_CFG1;
- /*
- * XXX FIXME: any attempt to generate type1 configuration
- * access causes external data abort
- */
- return;
- }
+ type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1;
rk_pcie_map_cfg_atu(sc, 0, type);
switch (bytes) {
case 1:
- bus_write_1(sc->axi_mem_res, addr, val);
+ bus_poke_1(sc->axi_mem_res, addr, (uint8_t)val);
break;
case 2:
- bus_write_2(sc->axi_mem_res, addr, val);
+ bus_poke_2(sc->axi_mem_res, addr, (uint16_t)val);
break;
case 4:
- bus_write_4(sc->axi_mem_res, addr, val);
+ bus_poke_4(sc->axi_mem_res, addr, val);
break;
default:
break;