Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 Sep 2019 22:25:22 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r352853 - in head/sys: arm64/conf arm64/rockchip conf
Message-ID:  <201909282225.x8SMPMxW021031@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Sat Sep 28 22:25:21 2019
New Revision: 352853
URL: https://svnweb.freebsd.org/changeset/base/352853

Log:
  arm64: rockchip: Add usb2phy driver
  
  This driver is for the usb phy present on rockchip SoC.
  It only support RK3399 and host mode for now.
  The driver expose the usb clock needed by the usb controller.

Added:
  head/sys/arm64/rockchip/rk_usb2phy.c   (contents, props changed)
Modified:
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files.arm64

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Sat Sep 28 22:23:21 2019	(r352852)
+++ head/sys/arm64/conf/GENERIC	Sat Sep 28 22:25:21 2019	(r352853)
@@ -205,6 +205,7 @@ device		pl011
 # USB support
 device		aw_ehci			# Allwinner EHCI USB interface (USB 2.0)
 device		aw_usbphy		# Allwinner USB PHY
+device		rk_usb2phy		# Rockchip USB2PHY
 device		dwcotg			# DWC OTG controller
 device		ohci			# OHCI USB interface
 device		ehci			# EHCI USB interface (USB 2.0)

Added: head/sys/arm64/rockchip/rk_usb2phy.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/rockchip/rk_usb2phy.c	Sat Sep 28 22:25:21 2019	(r352853)
@@ -0,0 +1,374 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Emmanuel Vadot <manu@FreeBSD.Org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Rockchip USB2PHY
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/gpio.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_subr.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/phy/phy_usb.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/extres/syscon/syscon.h>
+
+#include "clkdev_if.h"
+#include "syscon_if.h"
+
+#define	RK3399_GRF_USB20_PHY0_CON0	0x0
+#define	RK3399_GRF_USB20_PHY0_CON1	0x4
+#define	RK3399_GRF_USB20_PHY0_CON2	0x8
+#define	RK3399_GRF_USB20_PHY0_CON3	0xC
+
+struct rk_usb2phy_reg {
+	uint32_t	offset;
+	uint32_t	enable_mask;
+	uint32_t	disable_mask;
+};
+
+struct rk_usb2phy_regs {
+	struct rk_usb2phy_reg	clk_ctl;
+};
+
+struct rk_usb2phy_regs rk3399_regs = {
+	.clk_ctl = {
+		/* bit 4 put pll in suspend */
+		.enable_mask = 0x100000,
+		.disable_mask = 0x100010,
+	}
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "rockchip,rk3399-usb2phy",	(uintptr_t)&rk3399_regs },
+	{ NULL,				0 }
+};
+
+struct rk_usb2phy_softc {
+	device_t		dev;
+	struct syscon		*grf;
+	regulator_t		phy_supply;
+	clk_t			clk;
+};
+
+/* Phy class and methods. */
+static int rk_usb2phy_enable(struct phynode *phynode, bool enable);
+static phynode_method_t rk_usb2phy_phynode_methods[] = {
+	PHYNODEMETHOD(phynode_enable,	rk_usb2phy_enable),
+
+	PHYNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(rk_usb2phy_phynode, rk_usb2phy_phynode_class,
+    rk_usb2phy_phynode_methods,
+    sizeof(struct phynode_usb_sc), phynode_usb_class);
+
+enum RK3399_USBPHY {
+	RK3399_USBPHY_HOST = 0,
+	RK3399_USBPHY_OTG,
+};
+
+static int
+rk_usb2phy_enable(struct phynode *phynode, bool enable)
+{
+	struct rk_usb2phy_softc *sc;
+	device_t dev;
+	intptr_t phy;
+	int error;
+
+	dev = phynode_get_device(phynode);
+	phy = phynode_get_id(phynode);
+	sc = device_get_softc(dev);
+
+	if (phy != RK3399_USBPHY_HOST)
+		return (ERANGE);
+
+	if (sc->phy_supply) {
+		if (enable)
+			error = regulator_enable(sc->phy_supply);
+		else
+			error = regulator_disable(sc->phy_supply);
+		if (error != 0) {
+			device_printf(dev, "Cannot %sable the regulator\n",
+			    enable ? "En" : "Dis");
+			goto fail;
+		}
+	}
+
+	return (0);
+fail:
+	return (ENXIO);
+}
+
+/* Clock class and method */
+struct rk_usb2phy_clk_sc {
+	device_t	clkdev;
+	struct syscon	*grf;
+	struct rk_usb2phy_regs	*regs;
+};
+
+static int
+rk_usb2phy_clk_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+rk_usb2phy_clk_set_gate(struct clknode *clk, bool enable)
+{
+	struct rk_usb2phy_clk_sc *sc;
+
+	sc = clknode_get_softc(clk);
+
+	if (enable)
+		SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset,
+		    sc->regs->clk_ctl.enable_mask);
+	else
+		SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset,
+		    sc->regs->clk_ctl.disable_mask);
+	return (0);
+}
+
+static int
+rk_usb2phy_clk_recalc(struct clknode *clk, uint64_t *freq)
+{
+
+	*freq = 480000000;
+
+	return (0);
+}
+
+static clknode_method_t rk_usb2phy_clk_clknode_methods[] = {
+	/* Device interface */
+
+	CLKNODEMETHOD(clknode_init,		rk_usb2phy_clk_init),
+	CLKNODEMETHOD(clknode_set_gate,		rk_usb2phy_clk_set_gate),
+	CLKNODEMETHOD(clknode_recalc_freq,	rk_usb2phy_clk_recalc),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(rk_usb2phy_clk_clknode, rk_usb2phy_clk_clknode_class,
+    rk_usb2phy_clk_clknode_methods, sizeof(struct rk_usb2phy_clk_sc),
+    clknode_class);
+
+static int
+rk_usb2phy_clk_ofw_map(struct clkdom *clkdom, uint32_t ncells,
+    phandle_t *cells, struct clknode **clk)
+{
+
+	if (ncells != 0)
+		return (ERANGE);
+
+	*clk = clknode_find_by_id(clkdom, 0);
+
+	if (*clk == NULL)
+		return (ENXIO);
+	return (0);
+}
+
+static int
+rk_usb2phy_export_clock(struct rk_usb2phy_softc *devsc)
+{
+	struct clknode_init_def def;
+	struct rk_usb2phy_clk_sc *sc;
+	const char **clknames;
+	struct clkdom *clkdom;
+	struct clknode *clk;
+	clk_t clk_parent;
+	phandle_t node;
+	phandle_t regs[2];
+	int i, nclocks, ncells, error;
+
+	node = ofw_bus_get_node(devsc->dev);
+
+	error = ofw_bus_parse_xref_list_get_length(node, "clocks",
+	    "#clock-cells", &ncells);
+	if (error != 0 || ncells != 1) {
+		device_printf(devsc->dev, "couldn't find parent clock\n");
+		return (ENXIO);
+	}
+
+	nclocks = ofw_bus_string_list_to_array(node, "clock-output-names",
+	    &clknames);
+	if (nclocks != 1)
+		return (ENXIO);
+
+	clkdom = clkdom_create(devsc->dev);
+	clkdom_set_ofw_mapper(clkdom, rk_usb2phy_clk_ofw_map);
+
+	memset(&def, 0, sizeof(def));
+	def.id = 0;
+	def.name = clknames[0];
+	def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, M_WAITOK);
+	for (i = 0; i < ncells; i++) {
+		error = clk_get_by_ofw_index(devsc->dev, 0, i, &clk_parent);
+		if (error != 0) {
+			device_printf(devsc->dev, "cannot get clock %d\n", error);
+			return (ENXIO);
+		}
+		def.parent_names[i] = clk_get_name(clk_parent);
+		clk_release(clk_parent);
+	}
+	def.parent_cnt = ncells;
+
+	clk = clknode_create(clkdom, &rk_usb2phy_clk_clknode_class, &def);
+	if (clk == NULL) {
+		device_printf(devsc->dev, "cannot create clknode\n");
+		return (ENXIO);
+	}
+
+	sc = clknode_get_softc(clk);
+	sc->clkdev = device_get_parent(devsc->dev);
+	sc->grf = devsc->grf;
+	sc->regs = (struct rk_usb2phy_regs *)ofw_bus_search_compatible(devsc->dev, compat_data)->ocd_data;
+	OF_getencprop(node, "reg", regs, sizeof(regs));
+	sc->regs->clk_ctl.offset = regs[0];
+	clknode_register(clkdom, clk);
+
+	if (clkdom_finit(clkdom) != 0) {
+		device_printf(devsc->dev, "cannot finalize clkdom initialization\n");
+		return (ENXIO);
+	}
+
+	if (bootverbose)
+		clkdom_dump(clkdom);
+
+	return (0);
+}
+
+static int
+rk_usb2phy_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Rockchip RK3399 USB2PHY");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rk_usb2phy_attach(device_t dev)
+{
+	struct rk_usb2phy_softc *sc;
+	struct phynode_init_def phy_init;
+	struct phynode *phynode;
+	phandle_t node, host;
+	int err;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	node = ofw_bus_get_node(dev);
+
+	if (syscon_get_handle_default(dev, &sc->grf) != 0) {
+		device_printf(dev, "Cannot get syscon handle\n");
+		return (ENXIO);
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "phyclk", &sc->clk) != 0) {
+		device_printf(dev, "Cannot get clock\n");
+		return (ENXIO);
+	}
+	err = clk_enable(sc->clk);
+	if (err != 0) {
+		device_printf(dev, "Could not enable clock %s\n",
+		    clk_get_name(sc->clk));
+		return (ENXIO);
+	}
+
+	err = rk_usb2phy_export_clock(sc);
+	if (err != 0)
+		return (err);
+
+	/* Only host is supported right now */
+
+	host = ofw_bus_find_child(node, "host-port");
+	if (host == 0) {
+		device_printf(dev, "Cannot find host-port child node\n");
+		return (ENXIO);
+	}
+
+	if (!ofw_bus_node_status_okay(host)) {
+		device_printf(dev, "host-port isn't okay\n");
+		return (0);
+	}
+
+	regulator_get_by_ofw_property(dev, host, "phy-supply", &sc->phy_supply);
+	phy_init.id = RK3399_USBPHY_HOST;
+	phy_init.ofw_node = host;
+	phynode = phynode_create(dev, &rk_usb2phy_phynode_class, &phy_init);
+	if (phynode == NULL) {
+		device_printf(dev, "failed to create host USB2PHY\n");
+		return (ENXIO);
+	}
+	if (phynode_register(phynode) == NULL) {
+		device_printf(dev, "failed to register host USB2PHY\n");
+		return (ENXIO);
+	}
+
+	OF_device_register_xref(OF_xref_from_node(host), dev);
+
+	return (0);
+}
+
+static device_method_t rk_usb2phy_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		rk_usb2phy_probe),
+	DEVMETHOD(device_attach,	rk_usb2phy_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t rk_usb2phy_driver = {
+	"rk_usb2phy",
+	rk_usb2phy_methods,
+	sizeof(struct rk_usb2phy_softc)
+};
+
+static devclass_t rk_usb2phy_devclass;
+EARLY_DRIVER_MODULE(rk_usb2phy, simplebus, rk_usb2phy_driver,
+    rk_usb2phy_devclass, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(rk_usb2phy, 1);

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Sat Sep 28 22:23:21 2019	(r352852)
+++ head/sys/conf/files.arm64	Sat Sep 28 22:25:21 2019	(r352853)
@@ -282,6 +282,7 @@ arm64/rockchip/rk805.c			optional fdt rk805 soc_rockch
 arm64/rockchip/rk_grf.c			optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399
 arm64/rockchip/rk_pinctrl.c		optional fdt rk_pinctrl soc_rockchip_rk3328 | fdt rk_pinctrl soc_rockchip_rk3399
 arm64/rockchip/rk_gpio.c		optional fdt rk_gpio soc_rockchip_rk3328 | fdt rk_gpio soc_rockchip_rk3399
+arm64/rockchip/rk_usb2phy.c		optional fdt rk_usb2phy soc_rockchip_rk3328 | soc_rockchip_rk3399
 arm64/rockchip/if_dwc_rk.c		optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399
 dev/dwc/if_dwc.c			optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399
 dev/dwc/if_dwc_if.m			optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909282225.x8SMPMxW021031>