Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_mbox.c revision 1.15.8.1
      1  1.15.8.1   thorpej /*	$NetBSD: bcm2835_mbox.c,v 1.15.8.1 2021/03/23 07:14:43 thorpej Exp $	*/
      2       1.1     skrll 
      3       1.1     skrll /*-
      4       1.1     skrll  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5       1.1     skrll  * All rights reserved.
      6       1.1     skrll  *
      7       1.1     skrll  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1     skrll  * by Nick Hudson
      9       1.1     skrll  *
     10       1.1     skrll  * Redistribution and use in source and binary forms, with or without
     11       1.1     skrll  * modification, are permitted provided that the following conditions
     12       1.1     skrll  * are met:
     13       1.1     skrll  * 1. Redistributions of source code must retain the above copyright
     14       1.1     skrll  *    notice, this list of conditions and the following disclaimer.
     15       1.1     skrll  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1     skrll  *    notice, this list of conditions and the following disclaimer in the
     17       1.1     skrll  *    documentation and/or other materials provided with the distribution.
     18       1.1     skrll  *
     19       1.1     skrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1     skrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1     skrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1     skrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1     skrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1     skrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1     skrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1     skrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1     skrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1     skrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1     skrll  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1     skrll  */
     31       1.1     skrll 
     32       1.1     skrll #include <sys/cdefs.h>
     33  1.15.8.1   thorpej __KERNEL_RCSID(0, "$NetBSD: bcm2835_mbox.c,v 1.15.8.1 2021/03/23 07:14:43 thorpej Exp $");
     34       1.1     skrll 
     35       1.1     skrll #include <sys/param.h>
     36       1.1     skrll #include <sys/systm.h>
     37       1.1     skrll #include <sys/device.h>
     38       1.1     skrll #include <sys/kernel.h>
     39       1.1     skrll #include <sys/timetc.h>
     40       1.1     skrll #include <sys/bus.h>
     41       1.4  jmcneill #include <sys/mutex.h>
     42       1.1     skrll 
     43       1.1     skrll #include <arm/broadcom/bcm2835_mbox.h>
     44       1.1     skrll #include <arm/broadcom/bcm2835_mboxreg.h>
     45       1.1     skrll #include <arm/broadcom/bcm2835reg.h>
     46      1.14  jmcneill #include <arm/broadcom/bcm2835var.h>
     47       1.1     skrll 
     48       1.1     skrll static struct bcm2835mbox_softc *bcm2835mbox_sc;
     49       1.1     skrll 
     50       1.8     skrll static int
     51       1.8     skrll bcmmbox_intr1(struct bcm2835mbox_softc *sc, int cv)
     52       1.8     skrll {
     53       1.8     skrll 	uint32_t mbox, chan, data;
     54       1.8     skrll 	int ret = 0;
     55       1.8     skrll 
     56       1.8     skrll 	KASSERT(mutex_owned(&sc->sc_intr_lock));
     57       1.8     skrll 
     58       1.8     skrll 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, BCM2835_MBOX_SIZE,
     59       1.8     skrll 	    BUS_SPACE_BARRIER_READ);
     60       1.8     skrll 
     61       1.8     skrll 	while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh,
     62       1.8     skrll 	    BCM2835_MBOX0_STATUS) & BCM2835_MBOX_STATUS_EMPTY) == 0) {
     63       1.8     skrll 
     64       1.8     skrll 		mbox = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
     65       1.8     skrll 		    BCM2835_MBOX0_READ);
     66       1.8     skrll 
     67       1.8     skrll 		chan = BCM2835_MBOX_CHAN(mbox);
     68       1.8     skrll 		data = BCM2835_MBOX_DATA(mbox);
     69       1.8     skrll 		ret = 1;
     70       1.8     skrll 
     71       1.8     skrll 		if (BCM2835_MBOX_CHAN(sc->sc_mbox[chan]) != 0) {
     72       1.8     skrll 			aprint_error("bcmmbox_intr: chan %d overflow\n",chan);
     73       1.8     skrll 			continue;
     74       1.8     skrll 		}
     75       1.8     skrll 
     76       1.8     skrll 		sc->sc_mbox[chan] = data | BCM2835_MBOX_CHANMASK;
     77       1.8     skrll 
     78       1.8     skrll 		if (cv)
     79       1.8     skrll 			cv_broadcast(&sc->sc_chan[chan]);
     80       1.8     skrll 	}
     81       1.8     skrll 
     82       1.8     skrll 	return ret;
     83       1.8     skrll }
     84       1.8     skrll 
     85      1.14  jmcneill void
     86      1.14  jmcneill bcmmbox_attach(struct bcm2835mbox_softc *sc)
     87      1.14  jmcneill {
     88      1.14  jmcneill 	struct bcmmbox_attach_args baa;
     89      1.14  jmcneill 	int i;
     90      1.14  jmcneill 
     91      1.14  jmcneill 	if (bcm2835mbox_sc == NULL)
     92      1.14  jmcneill 		bcm2835mbox_sc = sc;
     93      1.14  jmcneill 
     94      1.14  jmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
     95      1.14  jmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
     96      1.14  jmcneill 	for (i = 0; i < BCM2835_MBOX_NUMCHANNELS; ++i)
     97      1.14  jmcneill 		cv_init(&sc->sc_chan[i], "bcmmbox");
     98      1.14  jmcneill 
     99      1.14  jmcneill 	/* enable mbox interrupt */
    100      1.15  jmcneill 	if (sc->sc_intrh != NULL)
    101      1.15  jmcneill 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BCM2835_MBOX_CFG,
    102      1.15  jmcneill 		    BCM2835_MBOX_CFG_DATAIRQEN);
    103      1.14  jmcneill 
    104      1.14  jmcneill 	baa.baa_dmat = sc->sc_dmat;
    105  1.15.8.1   thorpej 	sc->sc_platdev = config_found(sc->sc_dev, &baa, NULL, CFARG_EOL);
    106      1.14  jmcneill }
    107      1.14  jmcneill 
    108      1.14  jmcneill int
    109       1.8     skrll bcmmbox_intr(void *cookie)
    110       1.8     skrll {
    111       1.8     skrll 	struct bcm2835mbox_softc *sc = cookie;
    112       1.8     skrll 	int ret;
    113       1.8     skrll 
    114       1.8     skrll 	mutex_enter(&sc->sc_intr_lock);
    115       1.8     skrll 
    116       1.8     skrll 	ret = bcmmbox_intr1(sc, 1);
    117       1.8     skrll 
    118       1.8     skrll 	mutex_exit(&sc->sc_intr_lock);
    119       1.8     skrll 
    120       1.8     skrll 	return ret;
    121       1.8     skrll }
    122       1.8     skrll 
    123       1.1     skrll void
    124       1.1     skrll bcmmbox_read(uint8_t chan, uint32_t *data)
    125       1.1     skrll {
    126       1.1     skrll 	struct bcm2835mbox_softc *sc = bcm2835mbox_sc;
    127       1.1     skrll 
    128       1.1     skrll 	KASSERT(sc != NULL);
    129       1.1     skrll 
    130       1.8     skrll 	mutex_enter(&sc->sc_lock);
    131       1.8     skrll 
    132       1.8     skrll 	mutex_enter(&sc->sc_intr_lock);
    133       1.8     skrll 	while (BCM2835_MBOX_CHAN(sc->sc_mbox[chan]) == 0) {
    134      1.15  jmcneill 		if (cold || sc->sc_intrh == NULL)
    135       1.8     skrll 			bcmmbox_intr1(sc, 0);
    136       1.8     skrll 		else
    137       1.8     skrll 			cv_wait(&sc->sc_chan[chan], &sc->sc_intr_lock);
    138       1.8     skrll 	}
    139       1.8     skrll 	*data = BCM2835_MBOX_DATA(sc->sc_mbox[chan]);
    140       1.8     skrll 	sc->sc_mbox[chan] = 0;
    141       1.8     skrll 	mutex_exit(&sc->sc_intr_lock);
    142       1.8     skrll 
    143       1.8     skrll 	mutex_exit(&sc->sc_lock);
    144       1.1     skrll }
    145       1.1     skrll 
    146       1.1     skrll void
    147       1.1     skrll bcmmbox_write(uint8_t chan, uint32_t data)
    148       1.1     skrll {
    149       1.1     skrll 	struct bcm2835mbox_softc *sc = bcm2835mbox_sc;
    150       1.1     skrll 
    151       1.1     skrll 	KASSERT(sc != NULL);
    152       1.8     skrll 	KASSERT(BCM2835_MBOX_CHAN(chan) == chan);
    153       1.8     skrll 	KASSERT(BCM2835_MBOX_CHAN(data) == 0);
    154       1.8     skrll 
    155       1.8     skrll 	mutex_enter(&sc->sc_lock);
    156       1.8     skrll 
    157       1.8     skrll 	bcm2835_mbox_write(sc->sc_iot, sc->sc_ioh, chan, data);
    158       1.1     skrll 
    159       1.8     skrll 	mutex_exit(&sc->sc_lock);
    160       1.1     skrll }
    161       1.3  jmcneill 
    162       1.3  jmcneill int
    163       1.3  jmcneill bcmmbox_request(uint8_t chan, void *buf, size_t buflen, uint32_t *pres)
    164       1.3  jmcneill {
    165       1.3  jmcneill 	struct bcm2835mbox_softc *sc = bcm2835mbox_sc;
    166       1.3  jmcneill 	void *dma_buf;
    167       1.3  jmcneill 	bus_dmamap_t map;
    168       1.3  jmcneill 	bus_dma_segment_t segs[1];
    169       1.3  jmcneill 	int nsegs;
    170       1.3  jmcneill 	int error;
    171       1.3  jmcneill 
    172       1.3  jmcneill 	KASSERT(sc != NULL);
    173       1.3  jmcneill 
    174       1.3  jmcneill 	error = bus_dmamem_alloc(sc->sc_dmat, buflen, 16, 0, segs, 1,
    175       1.3  jmcneill 	    &nsegs, BUS_DMA_WAITOK);
    176       1.3  jmcneill 	if (error)
    177       1.3  jmcneill 		return error;
    178       1.3  jmcneill 	error = bus_dmamem_map(sc->sc_dmat, segs, nsegs, buflen, &dma_buf,
    179       1.3  jmcneill 	    BUS_DMA_WAITOK);
    180       1.3  jmcneill 	if (error)
    181       1.3  jmcneill 		goto map_failed;
    182       1.3  jmcneill 	error = bus_dmamap_create(sc->sc_dmat, buflen, 1, buflen, 0,
    183       1.3  jmcneill 	    BUS_DMA_WAITOK, &map);
    184       1.3  jmcneill 	if (error)
    185       1.3  jmcneill 		goto create_failed;
    186       1.3  jmcneill 	error = bus_dmamap_load(sc->sc_dmat, map, dma_buf, buflen, NULL,
    187       1.3  jmcneill 	    BUS_DMA_WAITOK);
    188       1.3  jmcneill 	if (error)
    189       1.3  jmcneill 		goto load_failed;
    190       1.3  jmcneill 
    191       1.3  jmcneill 	memcpy(dma_buf, buf, buflen);
    192       1.3  jmcneill 
    193       1.8     skrll 	bus_dmamap_sync(sc->sc_dmat, map, 0, buflen,
    194       1.8     skrll 	     BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
    195       1.3  jmcneill 	bcmmbox_write(chan, map->dm_segs[0].ds_addr);
    196       1.3  jmcneill 	bcmmbox_read(chan, pres);
    197       1.8     skrll 	bus_dmamap_sync(sc->sc_dmat, map, 0, buflen,
    198       1.8     skrll 	    BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
    199       1.4  jmcneill 
    200       1.3  jmcneill 	memcpy(buf, dma_buf, buflen);
    201       1.3  jmcneill 
    202       1.3  jmcneill 	bus_dmamap_unload(sc->sc_dmat, map);
    203       1.3  jmcneill load_failed:
    204       1.3  jmcneill 	bus_dmamap_destroy(sc->sc_dmat, map);
    205       1.3  jmcneill create_failed:
    206       1.3  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, dma_buf, buflen);
    207       1.3  jmcneill map_failed:
    208       1.3  jmcneill 	bus_dmamem_free(sc->sc_dmat, segs, nsegs);
    209       1.6     skrll 
    210       1.3  jmcneill 	return error;
    211       1.3  jmcneill }
    212