1/* $OpenBSD: moxtet.c,v 1.2 2021/10/24 17:52:26 mpi Exp $ */
2/*
3 * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/systm.h>
20#include <sys/kernel.h>
21#include <sys/device.h>
22#include <sys/malloc.h>
23
24#include <dev/spi/spivar.h>
25
26#include <dev/ofw/openfirm.h>
27#include <dev/ofw/ofw_gpio.h>
28#include <dev/ofw/ofw_pinctrl.h>
29
30#define MOX_NMODULE		10
31
32#define MOX_CPU_EMMC		0x00
33#define MOX_CPU_SD		0x10
34
35#define MOX_MODULE_SFP		0x01
36#define MOX_MODULE_PCI		0x02
37#define MOX_MODULE_TOPAZ	0x03
38#define MOX_MODULE_PERIDOT	0x04
39#define MOX_MODULE_USB3		0x05
40#define MOX_MODULE_PASSPCI	0x06
41
42struct moxtet_softc {
43	struct device		 sc_dev;
44	int			 sc_node;
45
46	spi_tag_t		 sc_spi_tag;
47	struct spi_config	 sc_spi_conf;
48
49	int			 sc_nmodule;
50};
51
52int	 moxtet_match(struct device *, void *, void *);
53void	 moxtet_attach(struct device *, struct device *, void *);
54int	 moxtet_detach(struct device *, int);
55
56int	 moxtet_read(struct moxtet_softc *, char *, size_t);
57int	 moxtet_write(struct moxtet_softc *, char *, size_t);
58
59const struct cfattach moxtet_ca = {
60	sizeof(struct moxtet_softc), moxtet_match, moxtet_attach, moxtet_detach
61};
62
63struct cfdriver moxtet_cd = {
64	NULL, "moxtet", DV_DULL
65};
66
67int
68moxtet_match(struct device *parent, void *match, void *aux)
69{
70	struct spi_attach_args *sa = aux;
71
72	if (strcmp(sa->sa_name, "cznic,moxtet") == 0)
73		return 1;
74
75	return 0;
76}
77
78void
79moxtet_attach(struct device *parent, struct device *self, void *aux)
80{
81	struct moxtet_softc *sc = (struct moxtet_softc *)self;
82	struct spi_attach_args *sa = aux;
83	uint8_t buf[MOX_NMODULE];
84	int i;
85
86	sc->sc_spi_tag = sa->sa_tag;
87	sc->sc_node = *(int *)sa->sa_cookie;
88
89	pinctrl_byname(sc->sc_node, "default");
90
91	sc->sc_spi_conf.sc_bpw = 8;
92	sc->sc_spi_conf.sc_freq = OF_getpropint(sc->sc_node,
93	    "spi-max-frequency", 0);
94	sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0);
95	if (OF_getproplen(sc->sc_node, "spi-cpol") == 0)
96		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL;
97	if (OF_getproplen(sc->sc_node, "spi-cpha") == 0)
98		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA;
99	if (OF_getproplen(sc->sc_node, "spi-cs-high") == 0)
100		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CS_HIGH;
101
102	if (moxtet_read(sc, buf, sizeof(buf))) {
103		printf(": can't read moxtet\n");
104		return;
105	}
106
107	if (buf[0] == MOX_CPU_EMMC)
108		printf(": eMMC");
109	else if (buf[0] == MOX_CPU_SD)
110		printf(": SD");
111	else {
112		printf(": unknown\n");
113		return;
114	}
115
116	for (i = 1; i < MOX_NMODULE; i++) {
117		if (buf[i] == 0xff)
118			break;
119		sc->sc_nmodule++;
120		switch (buf[i] & 0xf) {
121		case MOX_MODULE_SFP:
122			printf(", SFP");
123			break;
124		case MOX_MODULE_PCI:
125			printf(", mPCIe");
126			break;
127		case MOX_MODULE_TOPAZ:
128			printf(", 4x GbE");
129			break;
130		case MOX_MODULE_PERIDOT:
131			printf(", 8x GbE");
132			break;
133		case MOX_MODULE_USB3:
134			printf(", 4x USB 3.0");
135			break;
136		case MOX_MODULE_PASSPCI:
137			printf(", mPCIe (passthrough)");
138			break;
139		default:
140			printf(", unknown (0x%02x)", buf[i] & 0xf);
141			break;
142		}
143	}
144
145	printf("\n");
146}
147
148int
149moxtet_detach(struct device *self, int flags)
150{
151	return 0;
152}
153
154int
155moxtet_read(struct moxtet_softc *sc, char *buf, size_t len)
156{
157	int error;
158
159	spi_acquire_bus(sc->sc_spi_tag, 0);
160	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
161	error = spi_read(sc->sc_spi_tag, buf, len);
162	spi_release_bus(sc->sc_spi_tag, 0);
163	return error;
164}
165
166int
167moxtet_write(struct moxtet_softc *sc, char *buf, size_t len)
168{
169	int error;
170
171	spi_acquire_bus(sc->sc_spi_tag, 0);
172	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
173	error = spi_write(sc->sc_spi_tag, buf, len);
174	spi_release_bus(sc->sc_spi_tag, 0);
175	return error;
176}
177