From 302cd81635f69f7d48a1a59d8578d40a1bdfcd79 Mon Sep 17 00:00:00 2001 From: dlg Date: Sun, 2 Apr 2023 01:21:39 +0000 Subject: [PATCH] add rkusbphy(4), a driver for the usb2phy on rockchip SoCs. the rkusbphy device has children nodes in the device tree which are the actual phys. this driver mostly exists to wire those children up as PHYs and turn the associated regulators on when a host controller enables the PHYs. in the future it should enable clocks and take ports out of suspend too. i'm not enabling this yet because it's useless without some tweaks in the usb host controller drivers. ok kettenis@ --- sys/dev/fdt/files.fdt | 6 +- sys/dev/fdt/rkusbphy.c | 241 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 sys/dev/fdt/rkusbphy.c diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 9d795822199..e653fbc8aff 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.183 2023/04/01 08:39:05 kettenis Exp $ +# $OpenBSD: files.fdt,v 1.184 2023/04/02 01:21:39 dlg Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -345,6 +345,10 @@ device rkcomphy attach rkcomphy at fdt file dev/fdt/rkcomphy.c rkcomphy +device rkusbphy +attach rkusbphy at fdt +file dev/fdt/rkusbphy.c rkusbphy + device rkdrm: drmbase, wsemuldisplaydev, rasops15, rasops16, rasops24, rasops32 attach rkdrm at fdt file dev/fdt/rkdrm.c rkdrm diff --git a/sys/dev/fdt/rkusbphy.c b/sys/dev/fdt/rkusbphy.c new file mode 100644 index 00000000000..f3c63fb311b --- /dev/null +++ b/sys/dev/fdt/rkusbphy.c @@ -0,0 +1,241 @@ +/* $OpenBSD: rkusbphy.c,v 1.1 2023/04/02 01:21:39 dlg Exp $ */ + +/* + * Copyright (c) 2023 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Rockchip USB2PHY with Innosilicon IP + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * chip stuff + */ + +struct rkusbphy_reg { + bus_size_t r_offs; +}; + +struct rkusbphy_port_regs { + struct rkusbphy_reg pr_phy_sus; + struct rkusbphy_reg pr_bvalid_det_en; +}; + +struct rkusbphy_chip { + bus_addr_t c_base_addr; + struct rkusbphy_port_regs c_regs; +}; + +static const struct rkusbphy_chip rkusbphy_rk3568[] = { + { + .c_base_addr = 0xfe8a0000, + }, + { + .c_base_addr = 0xfe8b0000, + }, +}; + +/* + * driver stuff + */ + +struct rkusbphy_softc { + struct device sc_dev; + const struct rkusbphy_chip *sc_chip; + struct regmap *sc_grf; + int sc_node; + + 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_otg_phy_enable(void *, uint32_t *); +static int rkusbphy_host_phy_enable(void *, uint32_t *); + +struct rkusbphy_port_config { + const char *pc_name; + int (*pc_enable)(void *, uint32_t *); +}; + +static void rkusbphy_register(struct rkusbphy_softc *, + struct phy_device *, const struct rkusbphy_port_config *); + +static const struct rkusbphy_port_config rkusbphy_otg_config = { + .pc_name = "otg-port", + .pc_enable = rkusbphy_otg_phy_enable, +}; + +static const struct rkusbphy_port_config rkusbphy_host_config = { + .pc_name = "host-port", + .pc_enable = rkusbphy_host_phy_enable, +}; + +const struct cfattach rkusbphy_ca = { + sizeof (struct rkusbphy_softc), rkusbphy_match, rkusbphy_attach +}; + +struct cfdriver rkusbphy_cd = { + NULL, "rkusbphy", DV_DULL +}; + +struct rkusbphy_id { + const char *id_name; + const struct rkusbphy_chip *id_chips; + size_t id_nchips; +}; + +#define RKUSBPHY_ID(_n, _c) { _n, _c, nitems(_c) } + +static const struct rkusbphy_id rkusbphy_ids[] = { + RKUSBPHY_ID("rockchip,rk3568-usb2phy", rkusbphy_rk3568), +}; + +static const struct rkusbphy_id * +rkusbphy_lookup(struct fdt_attach_args *faa) +{ + size_t i; + + for (i = 0; i < nitems(rkusbphy_ids); i++) { + const struct rkusbphy_id *id = &rkusbphy_ids[i]; + if (OF_is_compatible(faa->fa_node, id->id_name)) + return (id); + } + + return (NULL); +} + +static int +rkusbphy_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return (rkusbphy_lookup(faa) != NULL ? 1 : 0); +} + +static void +rkusbphy_attach(struct device *parent, struct device *self, void *aux) +{ + struct rkusbphy_softc *sc = (struct rkusbphy_softc *)self; + struct fdt_attach_args *faa = aux; + const struct rkusbphy_id *id = rkusbphy_lookup(faa); + size_t i; + uint32_t grfph; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + for (i = 0; i < id->id_nchips; i++) { + 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; + break; + } + } + if (sc->sc_chip == NULL) { + printf(": unknown base address 0x%llu\n", faa->fa_reg[0].addr); + return; + } + + sc->sc_node = faa->fa_node; + + grfph = OF_getpropint(sc->sc_node, "rockchip,usbgrf", 0); + sc->sc_grf = regmap_byphandle(grfph); + if (sc->sc_grf == NULL) { + printf("%s: rockchip,usbgrf 0x%x not found\n", DEVNAME(sc), + grfph); + 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 void +rkusbphy_register(struct rkusbphy_softc *sc, struct phy_device *pd, + const struct rkusbphy_port_config *pc) +{ + char status[32]; + int node; + + node = OF_getnodebyname(sc->sc_node, pc->pc_name); + if (node == 0) { + printf("%s: cannot find %s\n", DEVNAME(sc), pc->pc_name); + return; + } + + if (OF_getprop(node, "status", status, sizeof(status)) > 0 && + strcmp(status, "disabled") == 0) + return; + + pd->pd_node = node; + pd->pd_cookie = sc; + pd->pd_enable = pc->pc_enable; + phy_register(pd); +} + +static void +rkusbphy_phy_supply(struct rkusbphy_softc *sc, int node) +{ + int phandle; + + phandle = OF_getpropint(node, "phy-supply", 0); + if (phandle == 0) + return; + + regulator_enable(phandle); +} + +static int +rkusbphy_otg_phy_enable(void *cookie, uint32_t *cells) +{ + struct rkusbphy_softc *sc = cookie; + + rkusbphy_phy_supply(sc, sc->sc_otg_phy.pd_node); + + return (EINVAL); +} + +static int +rkusbphy_host_phy_enable(void *cookie, uint32_t *cells) +{ + struct rkusbphy_softc *sc = cookie; + + rkusbphy_phy_supply(sc, sc->sc_host_phy.pd_node); + + return (EINVAL); +} -- 2.20.1