1179055Sjfv/*	$OpenBSD: cdsdhc.c,v 1.2 2022/01/18 11:36:21 patrick Exp $	*/
2171384Sjfv
3190873Sjfv/*
4171384Sjfv * Copyright (c) 2022 Visa Hankala
5171384Sjfv *
6171384Sjfv * Permission to use, copy, modify, and distribute this software for any
7171384Sjfv * purpose with or without fee is hereby granted, provided that the above
8171384Sjfv * copyright notice and this permission notice appear in all copies.
9171384Sjfv *
10171384Sjfv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11171384Sjfv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12171384Sjfv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13171384Sjfv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14171384Sjfv * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15171384Sjfv * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16171384Sjfv * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17171384Sjfv */
18171384Sjfv
19171384Sjfv/*
20171384Sjfv * Driver glue for Cadence SD/SDIO/eMMC host controller.
21171384Sjfv */
22171384Sjfv
23171384Sjfv#include <sys/param.h>
24171384Sjfv#include <sys/systm.h>
25171384Sjfv#include <sys/conf.h>
26171384Sjfv#include <sys/device.h>
27171384Sjfv
28171384Sjfv#include <machine/bus.h>
29171384Sjfv#include <machine/fdt.h>
30171384Sjfv
31171384Sjfv#include <dev/ofw/fdt.h>
32179055Sjfv#include <dev/ofw/openfirm.h>
33179055Sjfv#include <dev/ofw/ofw_clock.h>
34171384Sjfv
35171384Sjfv#include <dev/sdmmc/sdhcvar.h>
36171384Sjfv#include <dev/sdmmc/sdmmcvar.h>
37171384Sjfv
38179055Sjfv/* Host Register Set */
39190873Sjfv#define HRS06				0x0018
40171384Sjfv#define  HRS06_ETR				(0x1 << 15)
41171384Sjfv#define  HRS06_ETV_MASK				(0x3f << 8)
42171384Sjfv#define  HRS06_ETV_SHIFT			8
43171384Sjfv#define  HRS06_EMM_MASK				(0x7 << 0)
44171384Sjfv#define  HRS06_EMM_SD				(0x0 << 0)
45171384Sjfv#define  HRS06_EMM_MMC_SDR			(0x2 << 0)
46171384Sjfv#define  HRS06_EMM_MMC_DDR			(0x3 << 0)
47171384Sjfv#define  HRS06_EMM_MMC_HS200			(0x4 << 0)
48171384Sjfv#define  HRS06_EMM_MMC_HS400			(0x5 << 0)
49171384Sjfv#define  HRS06_EMM_MMC_HS400_ENH		(0x6 << 0)
50171384Sjfv#define HRS31				0x007c
51185352Sjfv#define  HRS31_HOSTCTLVER(x)			(((x) >> 16) & 0xfff)
52171384Sjfv#define  HRS31_HOSTFIXVER(x)			((x) & 0xff)
53171384Sjfv
54171384Sjfv/* Slot Register Set */
55172043Sjfv#define SRS_OFFSET			0x200
56171384Sjfv#define SRS_SIZE			0x100
57171384Sjfv
58172043Sjfvstruct cdsdhc_softc {
59172043Sjfv	struct sdhc_softc	sc_sdhc;
60172043Sjfv	bus_space_tag_t		sc_iot;
61172043Sjfv	bus_space_handle_t	sc_ioh;
62172043Sjfv	bus_space_handle_t	sc_srs_ioh;
63172043Sjfv	void			*sc_ih;
64179055Sjfv
65172043Sjfv	struct sdhc_host	*sc_host;
66190873Sjfv};
67190873Sjfv
68190873Sjfv#define HREAD4(sc, reg) \
69172043Sjfv	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
70172043Sjfv#define HWRITE4(sc, reg, val) \
71172043Sjfv	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
72172043Sjfv
73172043Sjfvint	cdsdhc_match(struct device *, void *, void*);
74172043Sjfvvoid	cdsdhc_attach(struct device *, struct device *, void *);
75172043Sjfvvoid	cdsdhc_bus_clock_pre(struct sdhc_softc *, int, int);
76172043Sjfv
77172043Sjfvconst struct cfattach cdsdhc_ca = {
78172043Sjfv	sizeof(struct cdsdhc_softc), cdsdhc_match, cdsdhc_attach
79172043Sjfv};
80172043Sjfv
81172043Sjfvstruct cfdriver cdsdhc_cd = {
82172043Sjfv	NULL, "cdsdhc", DV_DULL
83172043Sjfv};
84172043Sjfv
85172043Sjfvint
86172043Sjfvcdsdhc_match(struct device *parent, void *match, void *aux)
87172043Sjfv{
88179055Sjfv	struct fdt_attach_args *faa = aux;
89172043Sjfv
90171384Sjfv	if (faa->fa_nreg < 1)
91171384Sjfv		return 0;
92185352Sjfv	return OF_is_compatible(faa->fa_node, "cdns,sd4hc");
93190873Sjfv}
94171384Sjfv
95171384Sjfvvoid
96179055Sjfvcdsdhc_attach(struct device *parent, struct device *self, void *aux)
97172043Sjfv{
98179055Sjfv	struct fdt_attach_args *faa = aux;
99185352Sjfv	struct cdsdhc_softc *sc = (struct cdsdhc_softc *)self;
100185352Sjfv	uint64_t capmask = 0, capset = 0;
101179055Sjfv	uint32_t ver;
102185352Sjfv
103172043Sjfv	sc->sc_iot = faa->fa_iot;
104171384Sjfv
105190873Sjfv	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
106190873Sjfv	    0, &sc->sc_ioh) != 0) {
107190873Sjfv		printf(": can't map registers\n");
108190873Sjfv		return;
109190873Sjfv	}
110171384Sjfv
111172043Sjfv	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, SRS_OFFSET, SRS_SIZE,
112171384Sjfv	    &sc->sc_srs_ioh) != 0) {
113171384Sjfv		printf(": can't map SRS subregion\n");
114172043Sjfv		goto unmap;
115172043Sjfv	}
116171384Sjfv
117171384Sjfv	clock_enable_all(faa->fa_node);
118179055Sjfv
119179055Sjfv	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
120172043Sjfv	    sdhc_intr, sc, sc->sc_sdhc.sc_dev.dv_xname);
121171384Sjfv	if (sc->sc_ih == NULL) {
122171384Sjfv		printf(": can't establish interrupt\n");
123171384Sjfv		goto disable;
124171384Sjfv	}
125171384Sjfv
126171384Sjfv	ver = HREAD4(sc, HRS31);
127171384Sjfv	printf(": rev 0x%x/0x%x\n", HRS31_HOSTCTLVER(ver),
128171384Sjfv	    HRS31_HOSTFIXVER(ver));
129171384Sjfv
130171384Sjfv	sc->sc_sdhc.sc_host = &sc->sc_host;
131179055Sjfv	sc->sc_sdhc.sc_dmat = faa->fa_dmat;
132179055Sjfv	sc->sc_sdhc.sc_bus_clock_pre = cdsdhc_bus_clock_pre;
133171384Sjfv	sdhc_host_found(&sc->sc_sdhc, sc->sc_iot, sc->sc_srs_ioh, SRS_SIZE,
134171384Sjfv	    1, capmask, capset);
135171384Sjfv	return;
136171384Sjfv
137171384Sjfvdisable:
138171384Sjfv	clock_disable_all(faa->fa_node);
139171384Sjfvunmap:
140171384Sjfv	bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
141171384Sjfv}
142171384Sjfv
143171384Sjfvvoid
144179055Sjfvcdsdhc_bus_clock_pre(struct sdhc_softc *sc_sdhc, int freq, int timing)
145179055Sjfv{
146171384Sjfv	struct cdsdhc_softc *sc = (struct cdsdhc_softc *)sc_sdhc;
147171384Sjfv	uint32_t mode, val;
148171384Sjfv
149179055Sjfv	switch (timing) {
150171384Sjfv	case SDMMC_TIMING_HIGHSPEED:
151171384Sjfv		mode = HRS06_EMM_MMC_SDR;
152171384Sjfv		break;
153171384Sjfv	case SDMMC_TIMING_MMC_DDR52:
154171384Sjfv		mode = HRS06_EMM_MMC_DDR;
155171384Sjfv		break;
156171384Sjfv	case SDMMC_TIMING_MMC_HS200:
157171384Sjfv		mode = HRS06_EMM_MMC_HS200;
158171384Sjfv		break;
159171384Sjfv	default:
160179055Sjfv		mode = HRS06_EMM_SD;
161179055Sjfv		break;
162171384Sjfv	}
163171384Sjfv
164171384Sjfv	val = HREAD4(sc, HRS06);
165171384Sjfv	val &= ~HRS06_EMM_MASK;
166171384Sjfv	val |= mode;
167171384Sjfv	HWRITE4(sc, HRS06, val);
168171384Sjfv}
169171384Sjfv