From: dlg Date: Mon, 3 Apr 2023 01:21:31 +0000 (+0000) Subject: do actual init of the phy itself when needed. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=5b0e326912cc07e732fad29c972eb9a012d18c34;p=openbsd do actual init of the phy itself when needed. turn the phy clock on and take the port out of suspend when something (eg, xhci or ehci) wants to use the port. before this the code just enabled power on the phy port regulators. ok kettenis@ --- diff --git a/sys/dev/fdt/rkusbphy.c b/sys/dev/fdt/rkusbphy.c index f3c63fb311b..2f30f97cd88 100644 --- a/sys/dev/fdt/rkusbphy.c +++ b/sys/dev/fdt/rkusbphy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rkusbphy.c,v 1.1 2023/04/02 01:21:39 dlg Exp $ */ +/* $OpenBSD: rkusbphy.c,v 1.2 2023/04/03 01:21:31 dlg Exp $ */ /* * Copyright (c) 2023 David Gwynne @@ -40,24 +40,53 @@ struct rkusbphy_reg { bus_size_t r_offs; + unsigned int r_shift; + uint32_t r_mask; + uint32_t r_set; }; struct rkusbphy_port_regs { - struct rkusbphy_reg pr_phy_sus; - struct rkusbphy_reg pr_bvalid_det_en; + struct rkusbphy_reg phy_enable; +}; + +struct rkusbphy_regs { + struct rkusbphy_reg clk_enable; + + struct rkusbphy_port_regs otg; + struct rkusbphy_port_regs host; }; struct rkusbphy_chip { - bus_addr_t c_base_addr; - struct rkusbphy_port_regs c_regs; + bus_addr_t c_base_addr; + const struct rkusbphy_regs *c_regs; +}; + +/* + * RK3568 has two USB2PHY nodes that have a GRF each. Each GRF has + * the same register layout. + */ + +static const struct rkusbphy_regs rkusbphy_rk3568_regs = { + /* shift, mask, set */ + .clk_enable = { 0x0008, 4, 0x1, 0x0 }, + + .otg = { + .phy_enable = { 0x0000, 0, 0x1ff, 0x1d2 }, + }, + + .host = { + .phy_enable = { 0x0004, 0, 0x1ff, 0x1d2 }, + }, }; static const struct rkusbphy_chip rkusbphy_rk3568[] = { { .c_base_addr = 0xfe8a0000, + .c_regs = &rkusbphy_rk3568_regs, }, { .c_base_addr = 0xfe8b0000, + .c_regs = &rkusbphy_rk3568_regs, }, }; @@ -67,20 +96,32 @@ static const struct rkusbphy_chip rkusbphy_rk3568[] = { struct rkusbphy_softc { struct device sc_dev; - const struct rkusbphy_chip *sc_chip; + const struct rkusbphy_regs *sc_regs; struct regmap *sc_grf; int sc_node; + int sc_running; + struct phy_device sc_otg_phy; struct phy_device sc_host_phy; }; #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) -static int rkusbphy_match(struct device *, void *, void *); -static void rkusbphy_attach(struct device *, struct device *, void *); +static int rkusbphy_match(struct device *, void *, void *); +static void rkusbphy_attach(struct device *, struct device *, + void *); + +static uint32_t rkusbphy_rd(struct rkusbphy_softc *, + const struct rkusbphy_reg *); +static int rkusbphy_isset(struct rkusbphy_softc *, + const struct rkusbphy_reg *); +static void rkusbphy_wr(struct rkusbphy_softc *, + const struct rkusbphy_reg *, uint32_t); +static void rkusbphy_set(struct rkusbphy_softc *, + const struct rkusbphy_reg *); -static int rkusbphy_otg_phy_enable(void *, uint32_t *); -static int rkusbphy_host_phy_enable(void *, uint32_t *); +static int rkusbphy_otg_phy_enable(void *, uint32_t *); +static int rkusbphy_host_phy_enable(void *, uint32_t *); struct rkusbphy_port_config { const char *pc_name; @@ -160,11 +201,11 @@ rkusbphy_attach(struct device *parent, struct device *self, void *aux) const struct rkusbphy_chip *c = &id->id_chips[i]; if (faa->fa_reg[0].addr == c->c_base_addr) { printf(": phy %zu\n", i); - sc->sc_chip = c; + sc->sc_regs = c->c_regs; break; } } - if (sc->sc_chip == NULL) { + if (sc->sc_regs == NULL) { printf(": unknown base address 0x%llu\n", faa->fa_reg[0].addr); return; } @@ -179,12 +220,45 @@ rkusbphy_attach(struct device *parent, struct device *self, void *aux) return; } - reset_assert_all(sc->sc_node); - rkusbphy_register(sc, &sc->sc_otg_phy, &rkusbphy_otg_config); rkusbphy_register(sc, &sc->sc_host_phy, &rkusbphy_host_config); } +static uint32_t +rkusbphy_rd(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r) +{ + uint32_t v; + + if (r->r_mask == 0) + return (0); + + v = regmap_read_4(sc->sc_grf, r->r_offs); + + return ((v >> r->r_shift) & r->r_mask); +} + +static int +rkusbphy_isset(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r) +{ + return (rkusbphy_rd(sc, r) == r->r_set); +} + +static void +rkusbphy_wr(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r, uint32_t v) +{ + if (r->r_mask == 0) + return; + + regmap_write_4(sc->sc_grf, r->r_offs, + (r->r_mask << (r->r_shift + 16)) | (v << r->r_shift)); +} + +static void +rkusbphy_set(struct rkusbphy_softc *sc, const struct rkusbphy_reg *r) +{ + rkusbphy_wr(sc, r, r->r_set); +} + static void rkusbphy_register(struct rkusbphy_softc *sc, struct phy_device *pd, const struct rkusbphy_port_config *pc) @@ -213,6 +287,17 @@ rkusbphy_phy_supply(struct rkusbphy_softc *sc, int node) { int phandle; + if (!sc->sc_running) { + clock_enable(sc->sc_node, "phyclk"); + if (!rkusbphy_isset(sc, &sc->sc_regs->clk_enable)) { + rkusbphy_set(sc, &sc->sc_regs->clk_enable); + + delay(1200); + } + + sc->sc_running = 1; + } + phandle = OF_getpropint(node, "phy-supply", 0); if (phandle == 0) return; @@ -227,6 +312,9 @@ rkusbphy_otg_phy_enable(void *cookie, uint32_t *cells) rkusbphy_phy_supply(sc, sc->sc_otg_phy.pd_node); + rkusbphy_set(sc, &sc->sc_regs->otg.phy_enable); + delay(1500); + return (EINVAL); } @@ -237,5 +325,8 @@ rkusbphy_host_phy_enable(void *cookie, uint32_t *cells) rkusbphy_phy_supply(sc, sc->sc_host_phy.pd_node); + rkusbphy_set(sc, &sc->sc_regs->host.phy_enable); + delay(1500); + return (EINVAL); }