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