1 /* $OpenBSD: sxirintc.c,v 1.1 2022/07/14 19:06:29 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2022 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/fdt.h> 27 28 #define RINTC_IRQ_PENDING 0x10 29 #define RINTC_IRQ_ENABLE 0x40 30 #define RINTC_IRQ_ENABLE_NMI (1 << 0) 31 32 #define HREAD4(sc, reg) \ 33 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 34 #define HWRITE4(sc, reg, val) \ 35 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 36 #define HSET4(sc, reg, bits) \ 37 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 38 #define HCLR4(sc, reg, bits) \ 39 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 40 41 struct sxirintc_softc { 42 struct device sc_dev; 43 bus_space_tag_t sc_iot; 44 bus_space_handle_t sc_ioh; 45 }; 46 47 int sxirintc_match(struct device *, void *, void *); 48 void sxirintc_attach(struct device *, struct device *, void *); 49 int sxirintc_activate(struct device *, int); 50 51 const struct cfattach sxirintc_ca = { 52 sizeof(struct sxirintc_softc), sxirintc_match, sxirintc_attach, 53 NULL, sxirintc_activate 54 }; 55 56 struct cfdriver sxirintc_cd = { 57 NULL, "sxirintc", DV_DULL 58 }; 59 60 int 61 sxirintc_match(struct device *parent, void *match, void *aux) 62 { 63 struct fdt_attach_args *faa = aux; 64 65 return OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-r-intc"); 66 } 67 68 void 69 sxirintc_attach(struct device *parent, struct device *self, void *aux) 70 { 71 struct sxirintc_softc *sc = (struct sxirintc_softc *)self; 72 struct fdt_attach_args *faa = aux; 73 74 if (faa->fa_nreg < 1) { 75 printf(": no registers\n"); 76 return; 77 } 78 79 sc->sc_iot = faa->fa_iot; 80 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 81 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 82 printf(": can't map registers\n"); 83 return; 84 } 85 86 printf("\n"); 87 } 88 89 int 90 sxirintc_activate(struct device *self, int act) 91 { 92 struct sxirintc_softc *sc = (struct sxirintc_softc *)self; 93 94 /* 95 * Typically the "NMI" interrupt is controlled by the PMIC. 96 * This interrupt is routed in parallel to the GIC and the 97 * ARISC coprocessor. Enable this interrupt when we suspend 98 * such that the firmware running on the ARISC coprocessor can 99 * wake up the SoC when the PMIC triggers this interrupt. 100 */ 101 102 switch (act) { 103 case DVACT_SUSPEND: 104 HWRITE4(sc, RINTC_IRQ_PENDING, ~0); 105 HSET4(sc, RINTC_IRQ_ENABLE, RINTC_IRQ_ENABLE_NMI); 106 break; 107 case DVACT_RESUME: 108 HCLR4(sc, RINTC_IRQ_ENABLE, RINTC_IRQ_ENABLE_NMI); 109 break; 110 } 111 112 return 0; 113 } 114