/* $OpenBSD: moxtet.c,v 1.1 2019/10/07 19:35:07 patrick Exp $ */ /* * Copyright (c) 2019 Patrick Wildt * * 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 #include #include #include #include #include #include #include #include #define MOX_NMODULE 10 #define MOX_CPU_EMMC 0x00 #define MOX_CPU_SD 0x10 #define MOX_MODULE_SFP 0x01 #define MOX_MODULE_PCI 0x02 #define MOX_MODULE_TOPAZ 0x03 #define MOX_MODULE_PERIDOT 0x04 #define MOX_MODULE_USB3 0x05 #define MOX_MODULE_PASSPCI 0x06 struct moxtet_softc { struct device sc_dev; int sc_node; spi_tag_t sc_spi_tag; struct spi_config sc_spi_conf; int sc_nmodule; }; int moxtet_match(struct device *, void *, void *); void moxtet_attach(struct device *, struct device *, void *); int moxtet_detach(struct device *, int); int moxtet_read(struct moxtet_softc *, char *, size_t); int moxtet_write(struct moxtet_softc *, char *, size_t); struct cfattach moxtet_ca = { sizeof(struct moxtet_softc), moxtet_match, moxtet_attach, moxtet_detach }; struct cfdriver moxtet_cd = { NULL, "moxtet", DV_DULL }; int moxtet_match(struct device *parent, void *match, void *aux) { struct spi_attach_args *sa = aux; if (strcmp(sa->sa_name, "cznic,moxtet") == 0) return 1; return 0; } void moxtet_attach(struct device *parent, struct device *self, void *aux) { struct moxtet_softc *sc = (struct moxtet_softc *)self; struct spi_attach_args *sa = aux; uint8_t buf[MOX_NMODULE]; int i; sc->sc_spi_tag = sa->sa_tag; sc->sc_node = *(int *)sa->sa_cookie; pinctrl_byname(sc->sc_node, "default"); sc->sc_spi_conf.sc_bpw = 8; sc->sc_spi_conf.sc_freq = OF_getpropint(sc->sc_node, "spi-max-frequency", 0); sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0); if (OF_getproplen(sc->sc_node, "spi-cpol") == 0) sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL; if (OF_getproplen(sc->sc_node, "spi-cpha") == 0) sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA; if (OF_getproplen(sc->sc_node, "spi-cs-high") == 0) sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CS_HIGH; if (moxtet_read(sc, buf, sizeof(buf))) { printf(": can't read moxtet\n"); return; } if (buf[0] == MOX_CPU_EMMC) printf(": eMMC"); else if (buf[0] == MOX_CPU_SD) printf(": SD"); else { printf(": unknown\n"); return; } for (i = 1; i < MOX_NMODULE; i++) { if (buf[i] == 0xff) break; sc->sc_nmodule++; switch (buf[i] & 0xf) { case MOX_MODULE_SFP: printf(", SFP"); break; case MOX_MODULE_PCI: printf(", mPCIe"); break; case MOX_MODULE_TOPAZ: printf(", 4x GbE"); break; case MOX_MODULE_PERIDOT: printf(", 8x GbE"); break; case MOX_MODULE_USB3: printf(", 4x USB 3.0"); break; case MOX_MODULE_PASSPCI: printf(", mPCIe (passthrough)"); break; default: printf(", unknown (0x%02x)", buf[i] & 0xf); break; } } printf("\n"); } int moxtet_detach(struct device *self, int flags) { return 0; } int moxtet_read(struct moxtet_softc *sc, char *buf, size_t len) { int error; spi_acquire_bus(sc->sc_spi_tag, 0); spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); error = spi_read(sc->sc_spi_tag, buf, len); spi_release_bus(sc->sc_spi_tag, 0); return error; } int moxtet_write(struct moxtet_softc *sc, char *buf, size_t len) { int error; spi_acquire_bus(sc->sc_spi_tag, 0); spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); error = spi_write(sc->sc_spi_tag, buf, len); spi_release_bus(sc->sc_spi_tag, 0); return error; }