1 /* $OpenBSD: bcm2835_aux.c,v 1.6 2020/07/17 08:07:34 patrick Exp $ */ 2 /* 3 * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> 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/device.h> 21 22 #include <machine/bus.h> 23 #include <machine/fdt.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/ofw_clock.h> 27 #include <dev/ofw/fdt.h> 28 29 /* 30 * This auxiliary device handles interrupts and clocks for one UART 31 * and two SPI controllers. For now we only support the UART, so we 32 * simply register its interrupt handler directly with our parent 33 * interrupt controller. 34 */ 35 #define BCMAUX_UART 0 36 #define BCMAUX_SPI0 1 37 #define BCMAUX_SPI1 2 38 39 struct bcmaux_softc { 40 struct device sc_dev; 41 bus_space_tag_t sc_iot; 42 bus_space_handle_t sc_ioh; 43 44 struct clock_device sc_cd; 45 struct interrupt_controller sc_ic; 46 }; 47 48 int bcmaux_match(struct device *, void *, void *); 49 void bcmaux_attach(struct device *, struct device *, void *); 50 51 struct cfattach bcmaux_ca = { 52 sizeof(struct bcmaux_softc), bcmaux_match, bcmaux_attach 53 }; 54 55 struct cfdriver bcmaux_cd = { 56 NULL, "bcmaux", DV_DULL 57 }; 58 59 uint32_t bcm_aux_get_frequency(void *, uint32_t *); 60 void *bcm_aux_intr_establish_fdt(void *, int *, int, struct cpu_info *, 61 int (*)(void *), void *, char *); 62 63 int 64 bcmaux_match(struct device *parent, void *match, void *aux) 65 { 66 struct fdt_attach_args *faa = aux; 67 68 return OF_is_compatible(faa->fa_node, "brcm,bcm2835-aux"); 69 } 70 71 void 72 bcmaux_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct bcmaux_softc *sc = (struct bcmaux_softc *)self; 75 struct fdt_attach_args *faa = aux; 76 77 if (faa->fa_nreg < 1) { 78 printf(": no registers\n"); 79 return; 80 } 81 82 sc->sc_iot = faa->fa_iot; 83 84 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 85 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 86 printf(": can't map registers\n"); 87 } 88 89 printf("\n"); 90 91 sc->sc_cd.cd_node = faa->fa_node; 92 sc->sc_cd.cd_cookie = sc; 93 sc->sc_cd.cd_get_frequency = bcm_aux_get_frequency; 94 clock_register(&sc->sc_cd); 95 96 sc->sc_ic.ic_node = faa->fa_node; 97 sc->sc_ic.ic_cookie = &sc->sc_ic; 98 sc->sc_ic.ic_establish = bcm_aux_intr_establish_fdt; 99 sc->sc_ic.ic_disestablish = fdt_intr_disestablish; 100 sc->sc_ic.ic_barrier = intr_barrier; 101 fdt_intr_register(&sc->sc_ic); 102 } 103 104 uint32_t 105 bcm_aux_get_frequency(void *cookie, uint32_t *cells) 106 { 107 uint32_t idx = cells[0]; 108 109 /* Only support the UART for now. */ 110 if (idx == BCMAUX_UART) 111 return 500000000; 112 113 printf("%s: 0x%08x\n", __func__, idx); 114 return 0; 115 } 116 117 void * 118 bcm_aux_intr_establish_fdt(void *cookie, int *cells, int level, 119 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 120 { 121 struct interrupt_controller *ic = cookie; 122 uint32_t idx = cells[0]; 123 124 /* Only support the UART for now. */ 125 if (idx != BCMAUX_UART) 126 return NULL; 127 128 return fdt_intr_establish_cpu(ic->ic_node, level, ci, func, arg, name); 129 } 130