Module Name: src Committed By: jmcneill Date: Sun Mar 10 11:10:21 UTC 2019
Modified Files: src/sys/arch/arm/rockchip: files.rockchip src/sys/arch/evbarm/conf: GENERIC64 Added Files: src/sys/arch/arm/rockchip: rk_emmcphy.c Log Message: Add support for Rockchip eMMC PHY To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/rockchip/files.rockchip cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/rockchip/rk_emmcphy.c cvs rdiff -u -r1.82 -r1.83 src/sys/arch/evbarm/conf/GENERIC64 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/rockchip/files.rockchip diff -u src/sys/arch/arm/rockchip/files.rockchip:1.16 src/sys/arch/arm/rockchip/files.rockchip:1.17 --- src/sys/arch/arm/rockchip/files.rockchip:1.16 Thu Mar 7 00:35:22 2019 +++ src/sys/arch/arm/rockchip/files.rockchip Sun Mar 10 11:10:21 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files.rockchip,v 1.16 2019/03/07 00:35:22 jakllsch Exp $ +# $NetBSD: files.rockchip,v 1.17 2019/03/10 11:10:21 jmcneill Exp $ # # Configuration info for Rockchip family SoCs # @@ -63,6 +63,11 @@ device rkpcie: pcibus, pcihost_fdt attach rkpcie at fdt file arch/arm/rockchip/rk3399_pcie.c rkpcie +# eMMC PHY +device rkemmcphy +attach rkemmcphy at fdt +file arch/arm/rockchip/rk_emmcphy.c rkemmcphy + # SOC parameters defflag opt_soc.h SOC_ROCKCHIP defflag opt_soc.h SOC_RK3328: SOC_ROCKCHIP Index: src/sys/arch/evbarm/conf/GENERIC64 diff -u src/sys/arch/evbarm/conf/GENERIC64:1.82 src/sys/arch/evbarm/conf/GENERIC64:1.83 --- src/sys/arch/evbarm/conf/GENERIC64:1.82 Wed Mar 6 19:36:59 2019 +++ src/sys/arch/evbarm/conf/GENERIC64 Sun Mar 10 11:10:21 2019 @@ -1,5 +1,5 @@ # -# $NetBSD: GENERIC64,v 1.82 2019/03/06 19:36:59 jakllsch Exp $ +# $NetBSD: GENERIC64,v 1.83 2019/03/10 11:10:21 jmcneill Exp $ # # GENERIC ARM (aarch64) kernel # @@ -338,6 +338,7 @@ tegrartc* at fdt? # NVIDIA Tegra RTC dwcmmc* at fdt? # Designware SD/MMC mesongxmmc* at fdt? # Amlogic Meson GX eMMC/SD/SDIO controller mmcpwrseq* at fdt? # Simple MMC power sequence provider +rkemmcphy* at fdt? # Rockchip eMMC PHY sdhc* at fdt? # SD Host Controller Interface sdhost* at fdt? # Broadcom BCM283x SD Host Interface sunximmc* at fdt? # Allwinner SD/MMC Added files: Index: src/sys/arch/arm/rockchip/rk_emmcphy.c diff -u /dev/null src/sys/arch/arm/rockchip/rk_emmcphy.c:1.1 --- /dev/null Sun Mar 10 11:10:21 2019 +++ src/sys/arch/arm/rockchip/rk_emmcphy.c Sun Mar 10 11:10:21 2019 @@ -0,0 +1,237 @@ +/* $NetBSD: rk_emmcphy.c,v 1.1 2019/03/10 11:10:21 jmcneill Exp $ */ + +/*- + * Copyright (c) 2019 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * 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 ``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 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: rk_emmcphy.c,v 1.1 2019/03/10 11:10:21 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/mutex.h> +#include <sys/kmem.h> + +#include <dev/fdt/fdtvar.h> + +#define GRF_EMMCPHY_CON0 0x00 +#define PHYCTRL_FRQSEL __BITS(13,12) +#define PHYCTRL_FRQSEL_200M 0 +#define PHYCTRL_FRQSEL_50M 1 +#define PHYCTRL_FRQSEL_100M 2 +#define PHYCTRL_FRQSEL_150M 3 +#define PHYCTRL_OTAPDLYENA __BIT(11) +#define PHYCTRL_OTAPDLYSEL __BITS(10,7) +#define PHYCTRL_ITAPCHGWIN __BIT(6) +#define PHYCTRL_ITAPDLYSEL __BITS(5,1) +#define PHYCTRL_ITAPDLYENA __BIT(0) +#define GRF_EMMCPHY_CON1 0x04 +#define PHYCTRL_CLKBUFSEL __BITS(8,6) +#define PHYCTRL_SELDLYTXCLK __BIT(5) +#define PHYCTRL_SELDLYRXCLK __BIT(4) +#define PHYCTRL_STRBSEL __BITS(3,0) +#define GRF_EMMCPHY_CON2 0x08 +#define PHYCTRL_REN_STRB __BIT(9) +#define PHYCTRL_REN_CMD __BIT(8) +#define PHYCTRL_REN_DAT __BITS(7,0) +#define GRF_EMMCPHY_CON3 0x0c +#define PHYCTRL_PU_STRB __BIT(9) +#define PHYCTRL_PU_CMD __BIT(8) +#define PHYCTRL_PU_DAT __BITS(7,0) +#define GRF_EMMCPHY_CON4 0x10 +#define PHYCTRL_OD_RELEASE_CMD __BIT(9) +#define PHYCTRL_OD_RELEASE_STRB __BIT(8) +#define PHYCTRL_OD_RELEASE_DAT __BITS(7,0) +#define GRF_EMMCPHY_CON5 0x14 +#define PHYCTRL_ODEN_STRB __BIT(9) +#define PHYCTRL_ODEN_CMD __BIT(8) +#define PHYCTRL_ODEN_DAT __BITS(7,0) +#define GRF_EMMCPHY_CON6 0x18 +#define PHYCTRL_DLL_TRM_ICP __BITS(12,9) +#define PHYCTRL_EN_RTRIM __BIT(8) +#define PHYCTRL_RETRIM __BIT(7) +#define PHYCTRL_DR_TY __BITS(6,4) +#define PHYCTRL_RETENB __BIT(3) +#define PHYCTRL_RETEN __BIT(2) +#define PHYCTRL_ENDLL __BIT(1) +#define PHYCTRL_PDB __BIT(0) +#define GRF_EMMCPHY_STATUS 0x20 +#define PHYCTRL_CALDONE __BIT(6) +#define PHYCTRL_DLLRDY __BIT(5) +#define PHYCTRL_RTRIM __BITS(4,1) +#define PHYCTRL_EXR_NINST __BIT(0) + +static const char * const compatible[] = { + "rockchip,rk3399-emmc-phy", + NULL +}; + +struct rk_emmcphy_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; +}; + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int rk_emmcphy_match(device_t, cfdata_t, void *); +static void rk_emmcphy_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(rkemmcphy, sizeof(struct rk_emmcphy_softc), + rk_emmcphy_match, rk_emmcphy_attach, NULL, NULL); + +static void * +rk_emmcphy_acquire(device_t dev, const void *data, size_t len) +{ + if (len != 0) + return NULL; + + return device_private(dev); +} + +static void +rk_emmcphy_release(device_t dev, void *priv) +{ +} + +static int +rk_emmcphy_enable(device_t dev, void *priv, bool enable) +{ + struct rk_emmcphy_softc * const sc = priv; + const int phandle = sc->sc_phandle; + struct clk *clk; + uint32_t mask, val; + u_int rate, frqsel; + + /* Power down PHY and disable DLL before making changes */ + mask = PHYCTRL_ENDLL | PHYCTRL_PDB; + val = 0; + WR4(sc, GRF_EMMCPHY_CON6, (mask << 16) | val); + + if (enable == false) + return 0; + + clk = fdtbus_clock_get(phandle, "emmcclk"); + rate = clk ? clk_get_rate(clk) : 0; + + if (rate != 0) { + if (rate < 75000000) + frqsel = PHYCTRL_FRQSEL_50M; + else if (rate < 125000000) + frqsel = PHYCTRL_FRQSEL_100M; + else if (rate < 175000000) + frqsel = PHYCTRL_FRQSEL_150M; + else + frqsel = PHYCTRL_FRQSEL_200M; + } else { + frqsel = PHYCTRL_FRQSEL_200M; + } + + delay(3); + + /* Power up PHY */ + mask = PHYCTRL_PDB; + val = PHYCTRL_PDB; + WR4(sc, GRF_EMMCPHY_CON6, (mask << 16) | val); + + /* Wait for calibration */ + delay(10); + val = RD4(sc, GRF_EMMCPHY_STATUS); + if ((val & PHYCTRL_CALDONE) == 0) { + device_printf(dev, "PHY calibration did not complete\n"); + return EIO; + } + + /* Set DLL frequency */ + mask = PHYCTRL_FRQSEL; + val = __SHIFTIN(frqsel, PHYCTRL_FRQSEL); + WR4(sc, GRF_EMMCPHY_CON0, (mask << 16) | val); + + /* Enable DLL */ + mask = PHYCTRL_ENDLL; + val = PHYCTRL_ENDLL; + WR4(sc, GRF_EMMCPHY_CON6, (mask << 16) | val); + + if (rate != 0) { + /* Wait for DLL ready */ + delay(50000); + val = RD4(sc, GRF_EMMCPHY_STATUS); + if ((val & PHYCTRL_DLLRDY) == 0) { + device_printf(dev, "DLL loop failed to lock\n"); + return EIO; + } + } + + return 0; +} + +static const struct fdtbus_phy_controller_func rk_emmcphy_funcs = { + .acquire = rk_emmcphy_acquire, + .release = rk_emmcphy_release, + .enable = rk_emmcphy_enable, +}; + +static int +rk_emmcphy_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +rk_emmcphy_attach(device_t parent, device_t self, void *aux) +{ + struct rk_emmcphy_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": eMMC PHY\n"); + + fdtbus_register_phy_controller(self, phandle, &rk_emmcphy_funcs); +}