xref: /netbsd-src/sys/arch/mips/ralink/ralink_cfi.c (revision d702511000114b76d34ff807058b279d2515a935)
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