summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2023-07-08 09:12:29 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2023-07-08 09:12:29 +0000
commit804a0c1670575a7e8cdacdfdcf97b59b9e9411df (patch)
tree47d981d476df76039881e888f07720012302c773 /sys
parentb371db4e148adcb1a852ca160c59397f4e46433f (diff)
Add support for the RK3588 PCIe3 PHY to rkpciephy(4). The PHY controls
4 lanes that can be routed to 4 of the 5 PCIe controllers in the following configurations. Either all 4 lanes go to the x4 controller, then the other 3 controllers stay disabled. If those are split, lane 0 goes to the x4 controller and lane 2 goes to the x2 controller. Lane 1 now either goes to the x4 one to build a x2, or it gets routed to a x1 controller. Lane 3 also either goes to the x2 one to build a x2, or it gets routed to a x1 controller. If lanes 1 or lane 3 are configured, they are routed towards the PCIe3 PHY instead of the Combo PHY. ok kettenis@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/fdt/rkpciephy.c115
1 files changed, 109 insertions, 6 deletions
diff --git a/sys/dev/fdt/rkpciephy.c b/sys/dev/fdt/rkpciephy.c
index 75fac8ea7e4..da5b50e84bd 100644
--- a/sys/dev/fdt/rkpciephy.c
+++ b/sys/dev/fdt/rkpciephy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rkpciephy.c,v 1.1 2023/03/19 11:17:16 kettenis Exp $ */
+/* $OpenBSD: rkpciephy.c,v 1.2 2023/07/08 09:12:28 patrick Exp $ */
/*
* Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
*
@@ -28,7 +28,7 @@
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/fdt.h>
-/* GRF registers */
+/* RK3568 GRF registers */
#define GRF_PCIE30PHY_CON(idx) ((idx) * 4)
/* CON1 */
#define GRF_PCIE30PHY_DA_OCM 0x80008000
@@ -42,6 +42,22 @@
#define GRF_PCIE30PHY_STATUS0 0x80
#define GRF_PCIE30PHY_SRAM_INIT_DONE (1 << 14)
+/* RK3588 GRF registers */
+#define RK3588_PCIE3PHY_GRF_CMN_CON(idx) ((idx) * 4)
+#define RK3588_GRF_PCIE3PHY_DA_OCM ((0x1 << 24) | (1 << 8))
+#define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1 (1 << 0)
+#define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3 (1 << 1)
+#define RK3588_GRF_PCIE3PHY_LANE_AGGREGATE (1 << 2)
+#define RK3588_GRF_PCIE3PHY_LANE_MASK (0x7 << 16)
+#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904
+#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04
+#define RK3588_PCIE3PHY_SRAM_INIT_DONE (1 << 0)
+#define RK3588_PHP_GRF_PCIESEL_CON 0x100
+#define RK3588_PHP_GRF_PCIE0L0_PCIE3 (1 << 0)
+#define RK3588_PHP_GRF_PCIE0L1_PCIE3 (1 << 1)
+#define RK3588_PHP_GRF_PCIE0L0_MASK (0x1 << 16)
+#define RK3588_PHP_GRF_PCIE0L1_MASK (0x1 << 17)
+
struct rkpciephy_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
@@ -61,14 +77,16 @@ struct cfdriver rkpciephy_cd = {
NULL, "rkpciephy", DV_DULL
};
-int rkpciephy_enable(void *, uint32_t *);
+int rk3568_pciephy_enable(void *, uint32_t *);
+int rk3588_pciephy_enable(void *, uint32_t *);
int
rkpciephy_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
- return OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy");
+ return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy") ||
+ OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy"));
}
void
@@ -81,12 +99,15 @@ rkpciephy_attach(struct device *parent, struct device *self, void *aux)
sc->sc_pd.pd_node = faa->fa_node;
sc->sc_pd.pd_cookie = sc;
- sc->sc_pd.pd_enable = rkpciephy_enable;
+ if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy"))
+ sc->sc_pd.pd_enable = rk3568_pciephy_enable;
+ if (OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy"))
+ sc->sc_pd.pd_enable = rk3588_pciephy_enable;
phy_register(&sc->sc_pd);
}
int
-rkpciephy_enable(void *cookie, uint32_t *cells)
+rk3568_pciephy_enable(void *cookie, uint32_t *cells)
{
struct rkpciephy_softc *sc = cookie;
struct regmap *rm;
@@ -135,3 +156,85 @@ rkpciephy_enable(void *cookie, uint32_t *cells)
return 0;
}
+
+int
+rk3588_pciephy_enable(void *cookie, uint32_t *cells)
+{
+ struct rkpciephy_softc *sc = cookie;
+ struct regmap *phy, *pipe;
+ int node = sc->sc_pd.pd_node;
+ uint32_t data_lanes[4] = { 1, 1, 1, 1 };
+ uint32_t grf, reg, stat;
+ int num_lanes, timo;
+
+ grf = OF_getpropint(node, "rockchip,phy-grf", 0);
+ phy = regmap_byphandle(grf);
+ if (phy == NULL)
+ return ENXIO;
+
+ clock_enable_all(node);
+ reset_assert(node, "phy");
+ delay(1);
+
+ regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0),
+ RK3588_GRF_PCIE3PHY_DA_OCM);
+
+ num_lanes = OF_getpropintarray(node, "data-lanes", data_lanes,
+ sizeof(data_lanes));
+ /* Use default setting in case of missing properties. */
+ if (num_lanes <= 0)
+ num_lanes = sizeof(data_lanes);
+ num_lanes /= sizeof(uint32_t);
+
+ reg = RK3588_GRF_PCIE3PHY_LANE_MASK;
+ /* If all links go to the first, aggregate toward x4 */
+ if (num_lanes >= 4 &&
+ data_lanes[0] == 1 && data_lanes[1] == 1 &&
+ data_lanes[2] == 1 && data_lanes[3] == 1) {
+ reg |= RK3588_GRF_PCIE3PHY_LANE_AGGREGATE;
+ } else {
+ /* If lanes 0+1 are not towards the same controller, split. */
+ if (num_lanes >= 2 && data_lanes[0] != data_lanes[1])
+ reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1;
+ /* If lanes 2+3 are not towards the same controller, split. */
+ if (num_lanes >= 4 && data_lanes[2] != data_lanes[3])
+ reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3;
+ }
+ regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0), reg);
+
+ grf = OF_getpropint(node, "rockchip,phy-grf", 0);
+ pipe = regmap_byphandle(grf);
+ if (pipe != NULL) {
+ reg = RK3588_PHP_GRF_PCIE0L0_MASK | RK3588_PHP_GRF_PCIE0L1_MASK;
+ /* If lane 1 is configured, move it from Combo to PCIE3 PHY */
+ if (num_lanes >= 2 && data_lanes[1] != 0) {
+ reg |= RK3588_PHP_GRF_PCIE0L0_PCIE3;
+ }
+ /* If lane 3 is configured, move it from Combo to PCIE3 PHY */
+ if (num_lanes >= 4 && data_lanes[3] != 0) {
+ reg |= RK3588_PHP_GRF_PCIE0L1_PCIE3;
+ }
+ regmap_write_4(pipe, RK3588_PHP_GRF_PCIESEL_CON, reg);
+ }
+
+ reset_deassert(node, "phy");
+
+ for (timo = 500; timo > 0; timo--) {
+ stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY0_STATUS1);
+ if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE)
+ break;
+ delay(100);
+ }
+ for (; timo > 0; timo--) {
+ stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY1_STATUS1);
+ if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE)
+ break;
+ delay(100);
+ }
+ if (timo == 0) {
+ printf("%s: timeout\n", sc->sc_dev.dv_xname);
+ return ETIMEDOUT;
+ }
+
+ return 0;
+}