1 /* $NetBSD: flash_cfi.c,v 1.5 2023/05/10 00:08:14 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 Frank Wille. 5 * All rights reserved. 6 * 7 * Written by Frank Wille for The NetBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * NOR CFI driver support for sandpoint 33 */ 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: flash_cfi.c,v 1.5 2023/05/10 00:08:14 riastradh Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/device.h> 39 40 #include <machine/autoconf.h> 41 42 #include <dev/nor/nor.h> 43 #include <dev/nor/cfi.h> 44 45 46 static int sandpointcfi_probe(device_t, cfdata_t, void *); 47 static void sandpointcfi_attach(device_t, device_t, void *); 48 static int sandpointcfi_detach(device_t, int); 49 50 struct sandpointcfi_softc { 51 device_t sc_dev; 52 device_t sc_nordev; 53 struct cfi sc_cfi; 54 bus_size_t sc_size; 55 struct nor_interface sc_nor_if; 56 }; 57 58 CFATTACH_DECL_NEW(sandpointcfi, sizeof(struct sandpointcfi_softc), 59 sandpointcfi_probe, sandpointcfi_attach, sandpointcfi_detach, NULL); 60 61 static int 62 sandpointcfi_probe(device_t parent, cfdata_t cf, void *aux) 63 { 64 extern struct cfdriver cfi_cd; 65 struct mainbus_attach_args *ma = aux; 66 const bus_size_t qrysize = CFI_QRY_MIN_MAP_SIZE; 67 struct cfi cfi; 68 int error, rv; 69 70 if (strcmp(ma->ma_name, cfi_cd.cd_name) != 0) 71 return 0; 72 73 KASSERT(ma->ma_bst != NULL); 74 75 cfi.cfi_bst = ma->ma_bst; 76 77 /* flash should be at least 2 MiB in size at 0xffe00000 */ 78 error = bus_space_map(cfi.cfi_bst, 0xffe00000, qrysize, 0, 79 &cfi.cfi_bsh); 80 if (error != 0) { 81 aprint_error("%s: cannot map %d at offset %#x, error %d\n", 82 __func__, qrysize, ma->ma_addr, error); 83 return 0; 84 } 85 86 /* probe for NOR flash */ 87 if (!cfi_probe(&cfi)) { 88 aprint_debug("%s: probe addr %#x, CFI not found\n", 89 __func__, ma->ma_addr); 90 rv = 0; 91 } else 92 rv = 1; 93 94 bus_space_unmap(cfi.cfi_bst, cfi.cfi_bsh, qrysize); 95 return rv; 96 } 97 98 static void 99 sandpointcfi_attach(device_t parent, device_t self, void *aux) 100 { 101 struct mainbus_attach_args *ma = aux; 102 struct sandpointcfi_softc *sc; 103 const bus_size_t qrysize = CFI_QRY_MIN_MAP_SIZE; 104 bus_addr_t addr; 105 bool found; 106 int error; 107 108 aprint_naive("\n"); 109 aprint_normal("\n"); 110 111 sc = device_private(self); 112 sc->sc_dev = self; 113 sc->sc_cfi.cfi_bst = ma->ma_bst; 114 115 /* map enough to identify, remap later when size is known */ 116 error = bus_space_map(sc->sc_cfi.cfi_bst, 0xffe00000, qrysize, 0, 117 &sc->sc_cfi.cfi_bsh); 118 if (error != 0) { 119 aprint_error_dev(self, "could not map error %d\n", error); 120 return; 121 } 122 123 /* identify the NOR flash */ 124 found = cfi_identify(&sc->sc_cfi); 125 126 bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, qrysize); 127 if (!found) { 128 /* should not happen, we already probed OK in match */ 129 aprint_error_dev(self, "could not map error %d\n", error); 130 return; 131 } 132 133 /* get size of flash in bytes */ 134 sc->sc_size = 1 << sc->sc_cfi.cfi_qry_data.device_size; 135 136 /* determine real base address */ 137 addr = (0xffffffff - sc->sc_size) + 1; 138 139 sc->sc_nor_if = nor_interface_cfi; 140 sc->sc_nor_if.private = &sc->sc_cfi; 141 sc->sc_nor_if.access_width = (1 << sc->sc_cfi.cfi_portwidth); 142 143 cfi_print(self, &sc->sc_cfi); 144 145 error = bus_space_map(sc->sc_cfi.cfi_bst, addr, sc->sc_size, 0, 146 &sc->sc_cfi.cfi_bsh); 147 if (error != 0) { 148 aprint_error_dev(self, "could not map error %d\n", error); 149 return; 150 } 151 152 if (!pmf_device_register1(self, NULL, NULL, NULL)) 153 aprint_error_dev(self, "couldn't establish power handler\n"); 154 155 sc->sc_nordev = nor_attach_mi(&sc->sc_nor_if, self); 156 } 157 158 static int 159 sandpointcfi_detach(device_t self, int flags) 160 { 161 struct sandpointcfi_softc *sc device_private(self); 162 int error; 163 164 error = config_detach_children(self, flags); 165 if (error) 166 return error; 167 168 pmf_device_deregister(self); 169 170 bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, sc->sc_size); 171 return 0; 172 } 173