1 /* $NetBSD: ralink_cfi.c,v 1.2 2023/05/10 00:07:58 riastradh Exp $ */
2 /*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Cliff Neighbors.
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 ralink
33 */
34
35 #include "opt_flash.h"
36 #include "locators.h"
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: ralink_cfi.c,v 1.2 2023/05/10 00:07:58 riastradh Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/cdefs.h>
44 #include <sys/device.h>
45 #include <sys/endian.h>
46
47 #include <sys/bus.h>
48
49 #include <mips/ralink/ralink_var.h>
50 #include <mips/ralink/ralink_reg.h>
51
52 #include <dev/nor/nor.h>
53 #include <dev/nor/cfi.h>
54
55
56 static int ra_cfi_match(device_t, cfdata_t, void *);
57 static void ra_cfi_attach(device_t, device_t, void *);
58 static int ra_cfi_detach(device_t, int);
59
60 struct ra_cfi_softc {
61 device_t sc_dev;
62 device_t sc_nordev;
63 struct cfi sc_cfi;
64 bus_addr_t sc_addr;
65 bus_size_t sc_size;
66 struct nor_interface sc_nor_if;
67 };
68
69 CFATTACH_DECL_NEW(ralink_cfi, sizeof(struct ra_cfi_softc), ra_cfi_match,
70 ra_cfi_attach, ra_cfi_detach, NULL);
71
72 /*
73 * ra_cfi_addr - return bus address for the CFI NOR flash
74 */
75 static inline bus_addr_t
ra_cfi_addr(struct mainbus_attach_args * const ma)76 ra_cfi_addr(struct mainbus_attach_args * const ma)
77 {
78 return RA_FLASH_BASE; /* XXX configure TBD */
79 }
80
81 static int
ra_cfi_match(device_t parent,cfdata_t match,void * aux)82 ra_cfi_match(device_t parent, cfdata_t match, void *aux)
83 {
84 struct mainbus_attach_args * const ma = aux;
85 bus_size_t tmpsize = CFI_QRY_MIN_MAP_SIZE;
86 bus_addr_t addr;
87 struct cfi cfi;
88 int rv;
89
90 KASSERT(ma->ma_memt != NULL);
91
92 addr = ra_cfi_addr(ma);
93 #ifdef NOTYET
94 if (addr == MAINBUSCF_ADDR_DEFAULT) {
95 aprint_error("%s: no base address\n", __func__);
96 return 0;
97 }
98 #endif
99
100 cfi.cfi_bst = ma->ma_memt;
101 int error = bus_space_map(cfi.cfi_bst, addr, tmpsize, 0, &cfi.cfi_bsh);
102 if (error != 0) {
103 aprint_error("%s: cannot map %#" PRIxBUSSIZE" at offset %#"
104 PRIxBUSADDR ", error %d\n", __func__, tmpsize, addr, error);
105 return false;
106 }
107
108 if (! cfi_probe(&cfi)) {
109 aprint_debug("%s: probe addr %#" PRIxBUSADDR
110 ", CFI not found\n", __func__, addr);
111 rv = 0;
112 } else {
113 rv = 1;
114 }
115
116 bus_space_unmap(cfi.cfi_bst, cfi.cfi_bsh, tmpsize);
117
118 return rv;
119 }
120
121 static void
ra_cfi_attach(device_t parent,device_t self,void * aux)122 ra_cfi_attach(device_t parent, device_t self, void *aux)
123 {
124 struct ra_cfi_softc *sc = device_private(self);
125 struct mainbus_attach_args * const ma = aux;
126 struct cfi_query_data * const qryp = &sc->sc_cfi.cfi_qry_data;
127 const bus_size_t tmpsize = CFI_QRY_MIN_MAP_SIZE;
128 bool found;
129 int error;
130
131 aprint_normal("\n");
132
133 sc->sc_dev = self;
134 sc->sc_cfi.cfi_bst = ma->ma_memt;
135 sc->sc_addr = ra_cfi_addr(ma);
136
137 /* map enough to identify, remap later when size is known */
138 error = bus_space_map(sc->sc_cfi.cfi_bst, sc->sc_addr, tmpsize,
139 0, &sc->sc_cfi.cfi_bsh);
140 if (error != 0) {
141 aprint_error_dev(self, "could not map error %d\n", error);
142 return;
143 }
144
145 found = cfi_identify(&sc->sc_cfi);
146
147 bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, tmpsize);
148
149 if (! found) {
150 /* should not happen, we already probed OK in match */
151 aprint_error_dev(self, "could not map error %d\n", error);
152 return;
153 }
154
155 sc->sc_size = 1 << qryp->device_size;
156
157 sc->sc_nor_if = nor_interface_cfi;
158 sc->sc_nor_if.private = &sc->sc_cfi;
159 sc->sc_nor_if.access_width = (1 << sc->sc_cfi.cfi_portwidth);
160
161 cfi_print(self, &sc->sc_cfi);
162
163 error = bus_space_map(sc->sc_cfi.cfi_bst, sc->sc_addr, sc->sc_size,
164 0, &sc->sc_cfi.cfi_bsh);
165 if (error != 0) {
166 aprint_error_dev(self, "could not map error %d\n", error);
167 return;
168 }
169
170 if (! pmf_device_register1(self, NULL, NULL, NULL))
171 aprint_error_dev(self, "couldn't establish power handler\n");
172
173 sc->sc_nordev = nor_attach_mi(&sc->sc_nor_if, self);
174
175 }
176
177 static int
ra_cfi_detach(device_t self,int flags)178 ra_cfi_detach(device_t self, int flags)
179 {
180 struct ra_cfi_softc *sc = device_private(self);
181 int error;
182
183 error = config_detach_children(self, flags);
184 if (error)
185 return error;
186
187 pmf_device_deregister(self);
188
189 bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, sc->sc_size);
190
191 return 0;
192 }
193