1 /* $OpenBSD: ahci_fdt.c,v 1.8 2023/04/08 02:32:38 dlg Exp $ */ 2 /* 3 * Copyright (c) 2013,2017 Patrick Wildt <patrick@blueri.se> 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/buf.h> 21 #include <sys/kernel.h> 22 #include <sys/malloc.h> 23 #include <sys/device.h> 24 #include <sys/queue.h> 25 26 #include <machine/bus.h> 27 #include <machine/fdt.h> 28 29 #include <dev/ic/ahcireg.h> 30 #include <dev/ic/ahcivar.h> 31 32 #include <dev/ofw/openfirm.h> 33 #include <dev/ofw/ofw_clock.h> 34 #include <dev/ofw/ofw_misc.h> 35 #include <dev/ofw/fdt.h> 36 37 int ahci_fdt_match(struct device *, void *, void *); 38 void ahci_fdt_attach(struct device *, struct device *, void *); 39 int ahci_fdt_detach(struct device *, int); 40 int ahci_fdt_activate(struct device *, int); 41 42 extern int ahci_intr(void *); 43 44 const struct cfattach ahci_fdt_ca = { 45 sizeof(struct ahci_softc), 46 ahci_fdt_match, 47 ahci_fdt_attach, 48 ahci_fdt_detach, 49 ahci_fdt_activate 50 }; 51 52 int 53 ahci_fdt_match(struct device *parent, void *match, void *aux) 54 { 55 struct fdt_attach_args *faa = aux; 56 57 return OF_is_compatible(faa->fa_node, "generic-ahci") || 58 OF_is_compatible(faa->fa_node, "cavium,octeon-7130-ahci") || 59 OF_is_compatible(faa->fa_node, "marvell,armada-3700-ahci") || 60 OF_is_compatible(faa->fa_node, "snps,dwc-ahci"); 61 } 62 63 void 64 ahci_fdt_attach(struct device *parent, struct device *self, void *aux) 65 { 66 struct ahci_softc *sc = (struct ahci_softc *) self; 67 struct fdt_attach_args *faa = aux; 68 uint32_t pi; 69 70 if (faa->fa_nreg < 1) 71 return; 72 73 sc->sc_iot = faa->fa_iot; 74 sc->sc_ios = faa->fa_reg[0].size; 75 sc->sc_dmat = faa->fa_dmat; 76 77 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 78 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 79 panic("ahci_fdt_attach: bus_space_map failed!"); 80 81 sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, 82 ahci_intr, sc, sc->sc_dev.dv_xname); 83 if (sc->sc_ih == NULL) { 84 printf(": can't establish interrupt\n"); 85 goto unmap; 86 } 87 88 clock_set_assigned(faa->fa_node); 89 clock_enable_all(faa->fa_node); 90 phy_enable(faa->fa_node, "sata-phy"); 91 92 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x118, 1U << 22); 93 pi = OF_getpropint(faa->fa_node, "ports-implemented", 0x0); 94 if (pi != 0) 95 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AHCI_REG_PI, pi); 96 97 printf(":"); 98 99 if (ahci_attach(sc) != 0) { 100 /* error printed by ahci_attach */ 101 goto irq; /* disable phy and clocks? */ 102 } 103 104 return; 105 irq: 106 fdt_intr_disestablish(sc->sc_ih); 107 unmap: 108 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 109 } 110 111 int 112 ahci_fdt_detach(struct device *self, int flags) 113 { 114 struct ahci_softc *sc = (struct ahci_softc *) self; 115 116 ahci_detach(sc, flags); 117 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 118 return 0; 119 } 120 121 int 122 ahci_fdt_activate(struct device *self, int act) 123 { 124 struct ahci_softc *sc = (struct ahci_softc *) self; 125 126 return ahci_activate((struct device *)sc, act); 127 } 128