diff options
author | 2019-11-29 22:00:54 +0000 | |
---|---|---|
committer | 2019-11-29 22:00:54 +0000 | |
commit | a1ad9a59919226ef9bd79a302a9313cab8dea84c (patch) | |
tree | f72d81742f4f6bb98db8012f3816676f3908915a | |
parent | Make rkgrf(4) behave like a simplebus(4) so we can attach drivers (diff) | |
download | wireguard-openbsd-a1ad9a59919226ef9bd79a302a9313cab8dea84c.tar.xz wireguard-openbsd-a1ad9a59919226ef9bd79a302a9313cab8dea84c.zip |
Add rkemmcphy(4), a driver for the RK3399's eMMC PHY.
-rw-r--r-- | sys/arch/arm64/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/arm64/conf/RAMDISK | 3 | ||||
-rw-r--r-- | sys/dev/fdt/files.fdt | 6 | ||||
-rw-r--r-- | sys/dev/fdt/rkemmcphy.c | 204 |
4 files changed, 213 insertions, 3 deletions
diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC index 4e8c413ef18..ed180c6510b 100644 --- a/sys/arch/arm64/conf/GENERIC +++ b/sys/arch/arm64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.132 2019/10/23 20:34:04 kettenis Exp $ +# $OpenBSD: GENERIC,v 1.133 2019/11/29 22:00:54 patrick Exp $ # # GENERIC machine description file # @@ -186,6 +186,7 @@ sfp* at fdt? rkclock* at fdt? early 1 rkgrf* at fdt? early 1 rkpinctrl* at fdt? early 1 +rkemmcphy* at fdt? rkgpio* at fdt? rkiic* at fdt? iic* at rkiic? diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK index 6598356acad..a3417d5b532 100644 --- a/sys/arch/arm64/conf/RAMDISK +++ b/sys/arch/arm64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.106 2019/10/23 20:34:04 kettenis Exp $ +# $OpenBSD: RAMDISK,v 1.107 2019/11/29 22:00:54 patrick Exp $ # # GENERIC machine description file # @@ -169,6 +169,7 @@ sfp* at fdt? rkclock* at fdt? early 1 rkgrf* at fdt? early 1 rkpinctrl* at fdt? early 1 +rkemmcphy* at fdt? rkgpio* at fdt? rkiic* at fdt? iic* at rkiic? diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 3d80daa27f2..caed8d5b84d 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.103 2019/11/29 21:59:55 patrick Exp $ +# $OpenBSD: files.fdt,v 1.104 2019/11/29 22:00:54 patrick Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -216,6 +216,10 @@ device rkdwusb: fdt attach rkdwusb at fdt file dev/fdt/rkdwusb.c rkdwusb +device rkemmcphy +attach rkemmcphy at fdt +file dev/fdt/rkemmcphy.c rkemmcphy + device rkgrf: fdt attach rkgrf at fdt file dev/fdt/rkgrf.c rkgrf diff --git a/sys/dev/fdt/rkemmcphy.c b/sys/dev/fdt/rkemmcphy.c new file mode 100644 index 00000000000..554cf7fcabd --- /dev/null +++ b/sys/dev/fdt/rkemmcphy.c @@ -0,0 +1,204 @@ +/* $OpenBSD: rkemmcphy.c,v 1.1 2019/11/29 22:00:54 patrick Exp $ */ +/* + * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se> + * + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_misc.h> +#include <dev/ofw/fdt.h> + +/* Registers */ +#define GRF_EMMCPHY_CON0 0x00 +#define GRF_EMMCPHY_CON0_OTAPDLYSEL_4 (0x4 << 7) +#define GRF_EMMCPHY_CON0_OTAPDLYENA_EN (1 << 11) +#define GRF_EMMCPHY_CON0_FREQSEL_200M (0x0 << 12) +#define GRF_EMMCPHY_CON0_FREQSEL_50M (0x1 << 12) +#define GRF_EMMCPHY_CON0_FREQSEL_100M (0x2 << 12) +#define GRF_EMMCPHY_CON0_FREQSEL_150M (0x3 << 12) +#define GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR (0xf << 23) +#define GRF_EMMCPHY_CON0_OTAPDLYENA_CLR (1 << 27) +#define GRF_EMMCPHY_CON0_FREQSEL_CLR (0x3 << 28) +#define GRF_EMMCPHY_CON1 0x04 +#define GRF_EMMCPHY_CON2 0x08 +#define GRF_EMMCPHY_CON3 0x0c +#define GRF_EMMCPHY_CON4 0x10 +#define GRF_EMMCPHY_CON5 0x14 +#define GRF_EMMCPHY_CON6 0x18 +#define GRF_EMMCPHY_CON6_PDB_OFF (0 << 0) +#define GRF_EMMCPHY_CON6_PDB_ON (1 << 0) +#define GRF_EMMCPHY_CON6_ENDLL_OFF (0 << 1) +#define GRF_EMMCPHY_CON6_ENDLL_ON (1 << 1) +#define GRF_EMMCPHY_CON6_DR_50OHM (0x0 << 4) +#define GRF_EMMCPHY_CON6_DR_33OHM (0x1 << 4) +#define GRF_EMMCPHY_CON6_DR_66OHM (0x2 << 4) +#define GRF_EMMCPHY_CON6_DR_100OHM (0x3 << 4) +#define GRF_EMMCPHY_CON6_DR_40OHM (0x4 << 4) +#define GRF_EMMCPHY_CON6_PDB_CLR (1 << 16) +#define GRF_EMMCPHY_CON6_ENDLL_CLR (1 << 17) +#define GRF_EMMCPHY_CON6_DR_CLR (0x7 << 20) +#define GRF_EMMCPHY_STATUS 0x20 +#define GRF_EMMCPHY_STATUS_DLLRDY (1 << 5) +#define GRF_EMMCPHY_STATUS_CALDONE (1 << 6) + +#define HREAD4(sc, reg) \ + (regmap_read_4((sc)->sc_rm, (sc)->sc_off + (reg))) +#define HWRITE4(sc, reg, val) \ + regmap_write_4((sc)->sc_rm, (sc)->sc_off + (reg), (val)) + +struct rkemmcphy_softc { + struct device sc_dev; + struct regmap *sc_rm; + bus_size_t sc_off; + + struct phy_device sc_pd; +}; + +int rkemmcphy_match(struct device *, void *, void *); +void rkemmcphy_attach(struct device *, struct device *, void *); + +struct cfattach rkemmcphy_ca = { + sizeof (struct rkemmcphy_softc), rkemmcphy_match, rkemmcphy_attach +}; + +struct cfdriver rkemmcphy_cd = { + NULL, "rkemmcphy", DV_DULL +}; + +int rkemmcphy_enable(void *, uint32_t *); + +int +rkemmcphy_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "rockchip,rk3399-emmc-phy"); +} + +void +rkemmcphy_attach(struct device *parent, struct device *self, void *aux) +{ + struct rkemmcphy_softc *sc = (struct rkemmcphy_softc *)self; + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + sc->sc_off = faa->fa_reg[0].addr; + + sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node)); + if (sc->sc_rm == NULL) { + printf(": can't map registers\n"); + return; + } + + printf("\n"); + + sc->sc_pd.pd_node = faa->fa_node; + sc->sc_pd.pd_cookie = sc; + sc->sc_pd.pd_enable = rkemmcphy_enable; + phy_register(&sc->sc_pd); +} + +int +rkemmcphy_enable(void *cookie, uint32_t *cells) +{ + struct rkemmcphy_softc *sc = cookie; + uint32_t impedance, freqsel, freq, reg; + int node = sc->sc_pd.pd_node; + int i; + + impedance = OF_getpropint(node, "drive-impedance-ohm", 0); + freq = clock_get_frequency(node, "emmcclk"); + + switch (impedance) { + case 100: + impedance = GRF_EMMCPHY_CON6_DR_100OHM; + break; + case 66: + impedance = GRF_EMMCPHY_CON6_DR_66OHM; + break; + case 50: + impedance = GRF_EMMCPHY_CON6_DR_50OHM; + break; + case 40: + impedance = GRF_EMMCPHY_CON6_DR_40OHM; + break; + case 33: + impedance = GRF_EMMCPHY_CON6_DR_33OHM; + break; + default: + impedance = GRF_EMMCPHY_CON6_DR_50OHM; + break; + } + + if (freq == 0) { + freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M; + } else if (freq < 75000000) { + freqsel = GRF_EMMCPHY_CON0_FREQSEL_50M; + } else if (freq < 125000000) { + freqsel = GRF_EMMCPHY_CON0_FREQSEL_100M; + } else if (freq < 175000000) { + freqsel = GRF_EMMCPHY_CON0_FREQSEL_150M; + } else { + freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M; + } + + HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_DR_CLR | impedance); + HWRITE4(sc, GRF_EMMCPHY_CON0, + GRF_EMMCPHY_CON0_OTAPDLYENA_CLR | GRF_EMMCPHY_CON0_OTAPDLYENA_EN | + GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR | GRF_EMMCPHY_CON0_OTAPDLYSEL_4); + + HWRITE4(sc, GRF_EMMCPHY_CON6, + GRF_EMMCPHY_CON6_PDB_CLR | GRF_EMMCPHY_CON6_PDB_OFF | + GRF_EMMCPHY_CON6_ENDLL_CLR | GRF_EMMCPHY_CON6_ENDLL_OFF); + + delay(3); + HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_PDB_CLR | + GRF_EMMCPHY_CON6_PDB_ON); + + for (i = 5; i > 0; i--) { + reg = HREAD4(sc, GRF_EMMCPHY_STATUS); + if (reg & GRF_EMMCPHY_STATUS_CALDONE) + break; + delay(10); + } + if (i == 0) + printf("%s: timeout\n", sc->sc_dev.dv_xname); + + HWRITE4(sc, GRF_EMMCPHY_CON0, GRF_EMMCPHY_CON0_FREQSEL_CLR | freqsel); + HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_ENDLL_CLR | + GRF_EMMCPHY_CON6_ENDLL_ON); + + if (freq != 0) { + for (i = 5; i > 0; i--) { + reg = HREAD4(sc, GRF_EMMCPHY_STATUS); + if (reg & GRF_EMMCPHY_STATUS_DLLRDY) + break; + delay(10 * 1000); + } + if (i == 0) + printf("%s: timeout\n", sc->sc_dev.dv_xname); + } + + return 0; +} |