1*d7025110Sriastradh /* $NetBSD: ralink_cfi.c,v 1.2 2023/05/10 00:07:58 riastradh Exp $ */
2136422beScliff /*-
3136422beScliff * Copyright (c) 2011 The NetBSD Foundation, Inc.
4136422beScliff * All rights reserved.
5136422beScliff *
6136422beScliff * This code is derived from software contributed to The NetBSD Foundation
7136422beScliff * by Cliff Neighbors.
8136422beScliff *
9136422beScliff * Redistribution and use in source and binary forms, with or without
10136422beScliff * modification, are permitted provided that the following conditions
11136422beScliff * are met:
12136422beScliff * 1. Redistributions of source code must retain the above copyright
13136422beScliff * notice, this list of conditions and the following disclaimer.
14136422beScliff * 2. Redistributions in binary form must reproduce the above copyright
15136422beScliff * notice, this list of conditions and the following disclaimer in the
16136422beScliff * documentation and/or other materials provided with the distribution.
17136422beScliff *
18136422beScliff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19136422beScliff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20136422beScliff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21136422beScliff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22136422beScliff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23136422beScliff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24136422beScliff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25136422beScliff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26136422beScliff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27136422beScliff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28136422beScliff * POSSIBILITY OF SUCH DAMAGE.
29136422beScliff */
30136422beScliff
31136422beScliff /*
32136422beScliff * NOR CFI driver support for ralink
33136422beScliff */
34136422beScliff
35136422beScliff #include "opt_flash.h"
36136422beScliff #include "locators.h"
37136422beScliff
38136422beScliff #include <sys/cdefs.h>
39*d7025110Sriastradh __KERNEL_RCSID(0, "$NetBSD: ralink_cfi.c,v 1.2 2023/05/10 00:07:58 riastradh Exp $");
40136422beScliff
41136422beScliff #include <sys/param.h>
42136422beScliff #include <sys/systm.h>
43136422beScliff #include <sys/cdefs.h>
44136422beScliff #include <sys/device.h>
45136422beScliff #include <sys/endian.h>
46136422beScliff
47136422beScliff #include <sys/bus.h>
48136422beScliff
49136422beScliff #include <mips/ralink/ralink_var.h>
50136422beScliff #include <mips/ralink/ralink_reg.h>
51136422beScliff
52136422beScliff #include <dev/nor/nor.h>
53136422beScliff #include <dev/nor/cfi.h>
54136422beScliff
55136422beScliff
56136422beScliff static int ra_cfi_match(device_t, cfdata_t, void *);
57136422beScliff static void ra_cfi_attach(device_t, device_t, void *);
58136422beScliff static int ra_cfi_detach(device_t, int);
59136422beScliff
60136422beScliff struct ra_cfi_softc {
61136422beScliff device_t sc_dev;
62136422beScliff device_t sc_nordev;
63136422beScliff struct cfi sc_cfi;
64136422beScliff bus_addr_t sc_addr;
65136422beScliff bus_size_t sc_size;
66136422beScliff struct nor_interface sc_nor_if;
67136422beScliff };
68136422beScliff
69136422beScliff CFATTACH_DECL_NEW(ralink_cfi, sizeof(struct ra_cfi_softc), ra_cfi_match,
70136422beScliff ra_cfi_attach, ra_cfi_detach, NULL);
71136422beScliff
72136422beScliff /*
73136422beScliff * ra_cfi_addr - return bus address for the CFI NOR flash
74136422beScliff */
75136422beScliff static inline bus_addr_t
ra_cfi_addr(struct mainbus_attach_args * const ma)76136422beScliff ra_cfi_addr(struct mainbus_attach_args * const ma)
77136422beScliff {
78136422beScliff return RA_FLASH_BASE; /* XXX configure TBD */
79136422beScliff }
80136422beScliff
81136422beScliff static int
ra_cfi_match(device_t parent,cfdata_t match,void * aux)82136422beScliff ra_cfi_match(device_t parent, cfdata_t match, void *aux)
83136422beScliff {
84136422beScliff struct mainbus_attach_args * const ma = aux;
85136422beScliff bus_size_t tmpsize = CFI_QRY_MIN_MAP_SIZE;
86136422beScliff bus_addr_t addr;
87136422beScliff struct cfi cfi;
88136422beScliff int rv;
89136422beScliff
90136422beScliff KASSERT(ma->ma_memt != NULL);
91136422beScliff
92136422beScliff addr = ra_cfi_addr(ma);
93136422beScliff #ifdef NOTYET
94136422beScliff if (addr == MAINBUSCF_ADDR_DEFAULT) {
95136422beScliff aprint_error("%s: no base address\n", __func__);
96136422beScliff return 0;
97136422beScliff }
98136422beScliff #endif
99136422beScliff
100136422beScliff cfi.cfi_bst = ma->ma_memt;
101136422beScliff int error = bus_space_map(cfi.cfi_bst, addr, tmpsize, 0, &cfi.cfi_bsh);
102136422beScliff if (error != 0) {
103136422beScliff aprint_error("%s: cannot map %#" PRIxBUSSIZE" at offset %#"
104136422beScliff PRIxBUSADDR ", error %d\n", __func__, tmpsize, addr, error);
105136422beScliff return false;
106136422beScliff }
107136422beScliff
108136422beScliff if (! cfi_probe(&cfi)) {
109136422beScliff aprint_debug("%s: probe addr %#" PRIxBUSADDR
110136422beScliff ", CFI not found\n", __func__, addr);
111136422beScliff rv = 0;
112136422beScliff } else {
113136422beScliff rv = 1;
114136422beScliff }
115136422beScliff
116136422beScliff bus_space_unmap(cfi.cfi_bst, cfi.cfi_bsh, tmpsize);
117136422beScliff
118136422beScliff return rv;
119136422beScliff }
120136422beScliff
121136422beScliff static void
ra_cfi_attach(device_t parent,device_t self,void * aux)122136422beScliff ra_cfi_attach(device_t parent, device_t self, void *aux)
123136422beScliff {
124136422beScliff struct ra_cfi_softc *sc = device_private(self);
125136422beScliff struct mainbus_attach_args * const ma = aux;
126136422beScliff struct cfi_query_data * const qryp = &sc->sc_cfi.cfi_qry_data;
127136422beScliff const bus_size_t tmpsize = CFI_QRY_MIN_MAP_SIZE;
128136422beScliff bool found;
129136422beScliff int error;
130136422beScliff
131136422beScliff aprint_normal("\n");
132136422beScliff
133136422beScliff sc->sc_dev = self;
134136422beScliff sc->sc_cfi.cfi_bst = ma->ma_memt;
135136422beScliff sc->sc_addr = ra_cfi_addr(ma);
136136422beScliff
137136422beScliff /* map enough to identify, remap later when size is known */
138136422beScliff error = bus_space_map(sc->sc_cfi.cfi_bst, sc->sc_addr, tmpsize,
139136422beScliff 0, &sc->sc_cfi.cfi_bsh);
140136422beScliff if (error != 0) {
141136422beScliff aprint_error_dev(self, "could not map error %d\n", error);
142136422beScliff return;
143136422beScliff }
144136422beScliff
145136422beScliff found = cfi_identify(&sc->sc_cfi);
146136422beScliff
147136422beScliff bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, tmpsize);
148136422beScliff
149136422beScliff if (! found) {
150136422beScliff /* should not happen, we already probed OK in match */
151136422beScliff aprint_error_dev(self, "could not map error %d\n", error);
152136422beScliff return;
153136422beScliff }
154136422beScliff
155136422beScliff sc->sc_size = 1 << qryp->device_size;
156136422beScliff
157136422beScliff sc->sc_nor_if = nor_interface_cfi;
158136422beScliff sc->sc_nor_if.private = &sc->sc_cfi;
159136422beScliff sc->sc_nor_if.access_width = (1 << sc->sc_cfi.cfi_portwidth);
160136422beScliff
161136422beScliff cfi_print(self, &sc->sc_cfi);
162136422beScliff
163136422beScliff error = bus_space_map(sc->sc_cfi.cfi_bst, sc->sc_addr, sc->sc_size,
164136422beScliff 0, &sc->sc_cfi.cfi_bsh);
165136422beScliff if (error != 0) {
166136422beScliff aprint_error_dev(self, "could not map error %d\n", error);
167136422beScliff return;
168136422beScliff }
169136422beScliff
170136422beScliff if (! pmf_device_register1(self, NULL, NULL, NULL))
171136422beScliff aprint_error_dev(self, "couldn't establish power handler\n");
172136422beScliff
173136422beScliff sc->sc_nordev = nor_attach_mi(&sc->sc_nor_if, self);
174136422beScliff
175136422beScliff }
176136422beScliff
177136422beScliff static int
ra_cfi_detach(device_t self,int flags)178136422beScliff ra_cfi_detach(device_t self, int flags)
179136422beScliff {
180136422beScliff struct ra_cfi_softc *sc = device_private(self);
181*d7025110Sriastradh int error;
182*d7025110Sriastradh
183*d7025110Sriastradh error = config_detach_children(self, flags);
184*d7025110Sriastradh if (error)
185*d7025110Sriastradh return error;
186136422beScliff
187136422beScliff pmf_device_deregister(self);
188136422beScliff
189136422beScliff bus_space_unmap(sc->sc_cfi.cfi_bst, sc->sc_cfi.cfi_bsh, sc->sc_size);
190136422beScliff
191*d7025110Sriastradh return 0;
192136422beScliff }
193