1*c7fb772bSthorpej /* $NetBSD: nor.c,v 1.7 2021/08/07 16:19:13 thorpej Exp $ */
2de9f8578Sahoka
3de9f8578Sahoka /*-
4de9f8578Sahoka * Copyright (c) 2011 Department of Software Engineering,
5de9f8578Sahoka * University of Szeged, Hungary
6de9f8578Sahoka * Copyright (c) 2011 Adam Hoka <ahoka@NetBSD.org>
7de9f8578Sahoka * All rights reserved.
8de9f8578Sahoka *
9de9f8578Sahoka * This code is derived from software contributed to The NetBSD Foundation
10de9f8578Sahoka * by the Department of Software Engineering, University of Szeged, Hungary
11de9f8578Sahoka *
12de9f8578Sahoka * Redistribution and use in source and binary forms, with or without
13de9f8578Sahoka * modification, are permitted provided that the following conditions
14de9f8578Sahoka * are met:
15de9f8578Sahoka * 1. Redistributions of source code must retain the above copyright
16de9f8578Sahoka * notice, this list of conditions and the following disclaimer.
17de9f8578Sahoka * 2. Redistributions in binary form must reproduce the above copyright
18de9f8578Sahoka * notice, this list of conditions and the following disclaimer in the
19de9f8578Sahoka * documentation and/or other materials provided with the distribution.
20de9f8578Sahoka *
21de9f8578Sahoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22de9f8578Sahoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23de9f8578Sahoka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24de9f8578Sahoka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25de9f8578Sahoka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26de9f8578Sahoka * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27de9f8578Sahoka * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28de9f8578Sahoka * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29de9f8578Sahoka * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30de9f8578Sahoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31de9f8578Sahoka * SUCH DAMAGE.
32de9f8578Sahoka */
33de9f8578Sahoka
34de9f8578Sahoka /* Common driver for NOR chips implementing the ONFI CFI specification */
35de9f8578Sahoka
36de9f8578Sahoka #include <sys/cdefs.h>
37*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: nor.c,v 1.7 2021/08/07 16:19:13 thorpej Exp $");
38de9f8578Sahoka
39de9f8578Sahoka #include "locators.h"
40bf03074aScliff #include "opt_nor.h"
41de9f8578Sahoka
42de9f8578Sahoka #include <sys/param.h>
43de9f8578Sahoka #include <sys/types.h>
44de9f8578Sahoka #include <sys/device.h>
45de9f8578Sahoka #include <sys/kmem.h>
46de9f8578Sahoka #include <sys/sysctl.h>
47de9f8578Sahoka #include <sys/atomic.h>
48de9f8578Sahoka
49de9f8578Sahoka #include <dev/flash/flash.h>
50bf03074aScliff #include <dev/flash/flash_io.h>
51de9f8578Sahoka #include <dev/nor/nor.h>
52de9f8578Sahoka
53de9f8578Sahoka
54bf03074aScliff static int nor_match(device_t, cfdata_t, void *);
55bf03074aScliff static void nor_attach(device_t, device_t, void *);
56bf03074aScliff static int nor_detach(device_t, int);
57bf03074aScliff static bool nor_shutdown(device_t, int);
58bf03074aScliff static int nor_print(void *, const char *);
59de9f8578Sahoka static int nor_search(device_t, cfdata_t, const int *, void *);
60de9f8578Sahoka
61bf03074aScliff /* flash interface implementation */
62bf03074aScliff static int nor_flash_isbad(device_t, flash_off_t, bool *);
63bf03074aScliff static int nor_flash_markbad(device_t, flash_off_t);
64bf03074aScliff static int nor_flash_write(device_t, flash_off_t, size_t, size_t *,
65bf03074aScliff const u_char *);
66bf03074aScliff static int nor_flash_read(device_t, flash_off_t, size_t, size_t *, uint8_t *);
67bf03074aScliff static int nor_flash_erase_all(device_t);
68bf03074aScliff static int nor_flash_erase(device_t, struct flash_erase_instruction *);
69bf03074aScliff static int nor_flash_submit(device_t, buf_t *);
70bf03074aScliff
71bf03074aScliff /* default functions for driver development */
72bf03074aScliff static void nor_default_select(device_t, bool);
73bf03074aScliff static int nor_default_read_page(device_t, flash_off_t, uint8_t *);
74bf03074aScliff static int nor_default_program_page(device_t, flash_off_t, const uint8_t *);
75bf03074aScliff
76bf03074aScliff static int nor_scan_media(device_t, struct nor_chip *);
77bf03074aScliff
78de9f8578Sahoka CFATTACH_DECL_NEW(nor, sizeof(struct nor_softc),
79de9f8578Sahoka nor_match, nor_attach, nor_detach, NULL);
80de9f8578Sahoka
81de9f8578Sahoka #ifdef NOR_DEBUG
82de9f8578Sahoka int nordebug = NOR_DEBUG;
83de9f8578Sahoka #endif
84de9f8578Sahoka
85de9f8578Sahoka int nor_cachesync_timeout = 1;
86de9f8578Sahoka int nor_cachesync_nodenum;
87de9f8578Sahoka
88bf03074aScliff struct flash_interface nor_flash_if = {
89bf03074aScliff .type = FLASH_TYPE_NOR,
90bf03074aScliff
91bf03074aScliff .read = nor_flash_read,
92bf03074aScliff .write = nor_flash_write,
93bf03074aScliff .erase = nor_flash_erase,
94bf03074aScliff .block_isbad = nor_flash_isbad,
95bf03074aScliff .block_markbad = nor_flash_markbad,
96bf03074aScliff
97bf03074aScliff .submit = nor_flash_submit
98bf03074aScliff };
99bf03074aScliff
100de9f8578Sahoka #ifdef NOR_VERBOSE
1015df0d50bScliff const struct nor_manufacturer nor_mfrs[] = {
102de9f8578Sahoka { NOR_MFR_AMD, "AMD" },
103de9f8578Sahoka { NOR_MFR_FUJITSU, "Fujitsu" },
104de9f8578Sahoka { NOR_MFR_RENESAS, "Renesas" },
105de9f8578Sahoka { NOR_MFR_STMICRO, "ST Micro" },
106de9f8578Sahoka { NOR_MFR_MICRON, "Micron" },
107de9f8578Sahoka { NOR_MFR_NATIONAL, "National" },
108de9f8578Sahoka { NOR_MFR_TOSHIBA, "Toshiba" },
109de9f8578Sahoka { NOR_MFR_HYNIX, "Hynix" },
1101608a978Scliff { NOR_MFGR_MACRONIX, "Macronix" },
111de9f8578Sahoka { NOR_MFR_SAMSUNG, "Samsung" },
112de9f8578Sahoka { NOR_MFR_UNKNOWN, "Unknown" }
113de9f8578Sahoka };
114de9f8578Sahoka
115de9f8578Sahoka static const char *
nor_midtoname(int id)116de9f8578Sahoka nor_midtoname(int id)
117de9f8578Sahoka {
118de9f8578Sahoka int i;
119de9f8578Sahoka
120de9f8578Sahoka for (i = 0; nor_mfrs[i].id != 0; i++) {
121de9f8578Sahoka if (nor_mfrs[i].id == id)
122de9f8578Sahoka return nor_mfrs[i].name;
123de9f8578Sahoka }
124de9f8578Sahoka
125de9f8578Sahoka KASSERT(nor_mfrs[i].id == 0);
126de9f8578Sahoka
127de9f8578Sahoka return nor_mfrs[i].name;
128de9f8578Sahoka }
129de9f8578Sahoka #endif
130de9f8578Sahoka
131de9f8578Sahoka /* ARGSUSED */
132bf03074aScliff static int
nor_match(device_t parent,cfdata_t match,void * aux)133de9f8578Sahoka nor_match(device_t parent, cfdata_t match, void *aux)
134de9f8578Sahoka {
135de9f8578Sahoka /* pseudo device, always attaches */
136de9f8578Sahoka return 1;
137de9f8578Sahoka }
138de9f8578Sahoka
139bf03074aScliff static void
nor_attach(device_t parent,device_t self,void * aux)140de9f8578Sahoka nor_attach(device_t parent, device_t self, void *aux)
141de9f8578Sahoka {
142bf03074aScliff struct nor_softc * const sc = device_private(self);
143bf03074aScliff struct nor_attach_args * const naa = aux;
144bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
145de9f8578Sahoka
146de9f8578Sahoka sc->sc_dev = self;
147bf03074aScliff sc->sc_controller_dev = parent;
148bf03074aScliff sc->sc_nor_if = naa->naa_nor_if;
149de9f8578Sahoka
150de9f8578Sahoka aprint_naive("\n");
151bf03074aScliff aprint_normal("\n");
152bf03074aScliff
153bf03074aScliff if (nor_scan_media(self, chip))
154bf03074aScliff return;
155bf03074aScliff
156bf03074aScliff sc->sc_flash_if = nor_flash_if;
157bf03074aScliff sc->sc_flash_if.erasesize = chip->nc_block_size;
158bf03074aScliff sc->sc_flash_if.page_size = chip->nc_page_size;
159bf03074aScliff sc->sc_flash_if.writesize = chip->nc_page_size;
160de9f8578Sahoka
161de9f8578Sahoka /* allocate cache */
162bf03074aScliff #ifdef NOTYET
163de9f8578Sahoka chip->nc_oob_cache = kmem_alloc(chip->nc_spare_size, KM_SLEEP);
164bf03074aScliff #endif
165de9f8578Sahoka chip->nc_page_cache = kmem_alloc(chip->nc_page_size, KM_SLEEP);
166de9f8578Sahoka
167de9f8578Sahoka mutex_init(&sc->sc_device_lock, MUTEX_DEFAULT, IPL_NONE);
168de9f8578Sahoka
169bf03074aScliff if (flash_sync_thread_init(&sc->sc_flash_io, self, &sc->sc_flash_if)) {
170de9f8578Sahoka goto error;
171de9f8578Sahoka }
172de9f8578Sahoka
173de9f8578Sahoka if (!pmf_device_register1(sc->sc_dev, NULL, NULL, nor_shutdown))
174de9f8578Sahoka aprint_error_dev(sc->sc_dev,
175de9f8578Sahoka "couldn't establish power handler\n");
176de9f8578Sahoka
177de9f8578Sahoka #ifdef NOR_BBT
178de9f8578Sahoka nor_bbt_init(self);
179de9f8578Sahoka nor_bbt_scan(self);
180de9f8578Sahoka #endif
181de9f8578Sahoka
182de9f8578Sahoka /*
183de9f8578Sahoka * Attach all our devices
184de9f8578Sahoka */
1852685996bSthorpej config_search(self, NULL,
186*c7fb772bSthorpej CFARGS(.search = nor_search));
187de9f8578Sahoka
188de9f8578Sahoka return;
189bf03074aScliff
190de9f8578Sahoka error:
191bf03074aScliff #ifdef NOTET
192de9f8578Sahoka kmem_free(chip->nc_oob_cache, chip->nc_spare_size);
193bf03074aScliff #endif
194de9f8578Sahoka kmem_free(chip->nc_page_cache, chip->nc_page_size);
195de9f8578Sahoka mutex_destroy(&sc->sc_device_lock);
196de9f8578Sahoka }
197de9f8578Sahoka
198de9f8578Sahoka static int
nor_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)199de9f8578Sahoka nor_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
200de9f8578Sahoka {
201bf03074aScliff struct nor_softc * const sc = device_private(parent);
202bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
203de9f8578Sahoka struct flash_attach_args faa;
204de9f8578Sahoka
205bf03074aScliff faa.partinfo.part_offset = cf->cf_loc[FLASHBUSCF_OFFSET];
206de9f8578Sahoka
207de9f8578Sahoka if (cf->cf_loc[FLASHBUSCF_SIZE] == 0) {
208bf03074aScliff faa.partinfo.part_size =
209bf03074aScliff chip->nc_size - faa.partinfo.part_offset;
210de9f8578Sahoka } else {
211bf03074aScliff faa.partinfo.part_size = cf->cf_loc[FLASHBUSCF_SIZE];
212de9f8578Sahoka }
213de9f8578Sahoka
214de9f8578Sahoka if (cf->cf_loc[FLASHBUSCF_READONLY])
215bf03074aScliff faa.partinfo.part_flags = FLASH_PART_READONLY;
216de9f8578Sahoka else
217bf03074aScliff faa.partinfo.part_flags = 0;
218de9f8578Sahoka
219bf03074aScliff faa.flash_if = &sc->sc_flash_if;
220de9f8578Sahoka
2212685996bSthorpej if (config_probe(parent, cf, &faa)) {
2222685996bSthorpej if (config_attach(parent, cf, &faa, nor_print,
223*c7fb772bSthorpej CFARGS_NONE) != NULL) {
224de9f8578Sahoka return 0;
225de9f8578Sahoka } else {
226de9f8578Sahoka return 1;
227de9f8578Sahoka }
228de9f8578Sahoka }
229de9f8578Sahoka
230de9f8578Sahoka return 1;
231de9f8578Sahoka }
232de9f8578Sahoka
233bf03074aScliff static int
nor_detach(device_t self,int flags)234de9f8578Sahoka nor_detach(device_t self, int flags)
235de9f8578Sahoka {
236bf03074aScliff struct nor_softc * const sc = device_private(self);
237bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
238de9f8578Sahoka int error = 0;
239de9f8578Sahoka
240de9f8578Sahoka error = config_detach_children(self, flags);
241de9f8578Sahoka if (error) {
242de9f8578Sahoka return error;
243de9f8578Sahoka }
244de9f8578Sahoka
245bf03074aScliff flash_sync_thread_destroy(&sc->sc_flash_io);
246de9f8578Sahoka #ifdef NOR_BBT
247de9f8578Sahoka nor_bbt_detach(self);
248de9f8578Sahoka #endif
249bf03074aScliff #ifdef NOTET
250de9f8578Sahoka /* free oob cache */
251de9f8578Sahoka kmem_free(chip->nc_oob_cache, chip->nc_spare_size);
252bf03074aScliff #endif
253de9f8578Sahoka kmem_free(chip->nc_page_cache, chip->nc_page_size);
254de9f8578Sahoka
255de9f8578Sahoka mutex_destroy(&sc->sc_device_lock);
256de9f8578Sahoka
257de9f8578Sahoka pmf_device_deregister(sc->sc_dev);
258de9f8578Sahoka
259de9f8578Sahoka return error;
260de9f8578Sahoka }
261de9f8578Sahoka
262bf03074aScliff static int
nor_print(void * aux,const char * pnp)263de9f8578Sahoka nor_print(void *aux, const char *pnp)
264de9f8578Sahoka {
265de9f8578Sahoka if (pnp != NULL)
266de9f8578Sahoka aprint_normal("nor at %s\n", pnp);
267de9f8578Sahoka
268de9f8578Sahoka return UNCONF;
269de9f8578Sahoka }
270de9f8578Sahoka
271de9f8578Sahoka /* ask for a nor driver to attach to the controller */
272de9f8578Sahoka device_t
nor_attach_mi(struct nor_interface * const nor_if,device_t parent)273bf03074aScliff nor_attach_mi(struct nor_interface * const nor_if, device_t parent)
274de9f8578Sahoka {
275de9f8578Sahoka struct nor_attach_args arg;
276de9f8578Sahoka
277de9f8578Sahoka KASSERT(nor_if != NULL);
278de9f8578Sahoka
279bf03074aScliff if (nor_if->select == NULL)
280bf03074aScliff nor_if->select = &nor_default_select;
281bf03074aScliff if (nor_if->read_page == NULL)
282bf03074aScliff nor_if->read_page = &nor_default_read_page;
283bf03074aScliff if (nor_if->program_page == NULL)
284bf03074aScliff nor_if->program_page = &nor_default_program_page;
285bf03074aScliff
286de9f8578Sahoka arg.naa_nor_if = nor_if;
287bf03074aScliff
2882685996bSthorpej device_t dev = config_found(parent, &arg, nor_print,
289*c7fb772bSthorpej CFARGS(.iattr = "norbus"));
290bf03074aScliff
291bf03074aScliff return dev;
292de9f8578Sahoka }
293de9f8578Sahoka
294bf03074aScliff static void
nor_default_select(device_t self,bool n)295bf03074aScliff nor_default_select(device_t self, bool n)
296bf03074aScliff {
297bf03074aScliff /* do nothing */
298bf03074aScliff return;
299bf03074aScliff }
300bf03074aScliff
301bf03074aScliff static int
nor_flash_submit(device_t self,buf_t * const bp)302bf03074aScliff nor_flash_submit(device_t self, buf_t * const bp)
303bf03074aScliff {
304bf03074aScliff struct nor_softc * const sc = device_private(self);
305bf03074aScliff
306bf03074aScliff return flash_io_submit(&sc->sc_flash_io, bp);
307bf03074aScliff }
308bf03074aScliff
309bf03074aScliff
310de9f8578Sahoka /* default everything to reasonable values, to ease future api changes */
311de9f8578Sahoka void
nor_init_interface(struct nor_interface * const nor_if)312bf03074aScliff nor_init_interface(struct nor_interface * const nor_if)
313de9f8578Sahoka {
314bf03074aScliff nor_if->select = &nor_default_select;
315bf03074aScliff nor_if->read_1 = NULL;
316bf03074aScliff nor_if->read_2 = NULL;
317bf03074aScliff nor_if->read_4 = NULL;
318bf03074aScliff nor_if->read_buf_1 = NULL;
319bf03074aScliff nor_if->read_buf_2 = NULL;
320bf03074aScliff nor_if->read_buf_4 = NULL;
321bf03074aScliff nor_if->write_1 = NULL;
322bf03074aScliff nor_if->write_2 = NULL;
323bf03074aScliff nor_if->write_4 = NULL;
324bf03074aScliff nor_if->write_buf_1 = NULL;
325bf03074aScliff nor_if->write_buf_2 = NULL;
326bf03074aScliff nor_if->write_buf_4 = NULL;
327bf03074aScliff nor_if->busy = NULL;
328de9f8578Sahoka }
329de9f8578Sahoka
330bf03074aScliff #ifdef NOTYET
331de9f8578Sahoka /* handle quirks here */
332de9f8578Sahoka static void
nor_quirks(device_t self,struct nor_chip * const chip)333bf03074aScliff nor_quirks(device_t self, struct nor_chip * const chip)
334de9f8578Sahoka {
335de9f8578Sahoka /* this is an example only! */
336de9f8578Sahoka switch (chip->nc_manf_id) {
337de9f8578Sahoka case NOR_MFR_SAMSUNG:
338de9f8578Sahoka if (chip->nc_dev_id == 0x00) {
339de9f8578Sahoka /* do something only samsung chips need */
340de9f8578Sahoka /* or */
341de9f8578Sahoka /* chip->nc_quirks |= NC_QUIRK_NO_READ_START */
342de9f8578Sahoka }
343de9f8578Sahoka }
344de9f8578Sahoka
345de9f8578Sahoka return;
346de9f8578Sahoka }
347de9f8578Sahoka #endif
348de9f8578Sahoka
349de9f8578Sahoka /**
350de9f8578Sahoka * scan media to determine the chip's properties
351de9f8578Sahoka * this function resets the device
352de9f8578Sahoka */
353de9f8578Sahoka static int
nor_scan_media(device_t self,struct nor_chip * const chip)354bf03074aScliff nor_scan_media(device_t self, struct nor_chip * const chip)
355de9f8578Sahoka {
356bf03074aScliff struct nor_softc * const sc = device_private(self);
357bf03074aScliff char pbuf[3][sizeof("XXXX MB")];
358de9f8578Sahoka
359bf03074aScliff KASSERT(sc->sc_nor_if != NULL);
360bf03074aScliff KASSERT(sc->sc_nor_if->scan_media != NULL);
361bf03074aScliff int error = sc->sc_nor_if->scan_media(self, chip);
362bf03074aScliff if (error != 0)
363bf03074aScliff return error;
364de9f8578Sahoka
365de9f8578Sahoka #ifdef NOR_VERBOSE
366de9f8578Sahoka aprint_normal_dev(self,
367bf03074aScliff "manufacturer id: 0x%.4x (%s), device id: 0x%.4x\n",
368de9f8578Sahoka chip->nc_manf_id,
369de9f8578Sahoka nor_midtoname(chip->nc_manf_id),
370de9f8578Sahoka chip->nc_dev_id);
371de9f8578Sahoka #endif
372de9f8578Sahoka
373bf03074aScliff format_bytes(pbuf[0], sizeof(pbuf[0]), chip->nc_page_size);
374bf03074aScliff format_bytes(pbuf[1], sizeof(pbuf[1]), chip->nc_spare_size);
375bf03074aScliff format_bytes(pbuf[2], sizeof(pbuf[2]), chip->nc_block_size);
376de9f8578Sahoka aprint_normal_dev(self,
377bf03074aScliff "page size: %s, spare size: %s, block size: %s\n",
378bf03074aScliff pbuf[0], pbuf[1], pbuf[2]);
379de9f8578Sahoka
380bf03074aScliff format_bytes(pbuf[0], sizeof(pbuf[0]), chip->nc_size);
381de9f8578Sahoka aprint_normal_dev(self,
382de9f8578Sahoka "LUN size: %" PRIu32 " blocks, LUNs: %" PRIu8
383bf03074aScliff ", total storage size: %s\n",
384bf03074aScliff chip->nc_lun_blocks, chip->nc_num_luns, pbuf[0]);
385de9f8578Sahoka
386bf03074aScliff #ifdef NOTYET
387de9f8578Sahoka /* XXX does this apply to nor? */
388de9f8578Sahoka /*
389de9f8578Sahoka * calculate badblock marker offset in oob
390de9f8578Sahoka * we try to be compatible with linux here
391de9f8578Sahoka */
392de9f8578Sahoka if (chip->nc_page_size > 512)
393de9f8578Sahoka chip->nc_badmarker_offs = 0;
394de9f8578Sahoka else
395de9f8578Sahoka chip->nc_badmarker_offs = 5;
396bf03074aScliff #endif
397de9f8578Sahoka
398de9f8578Sahoka /* Calculate page shift and mask */
399de9f8578Sahoka chip->nc_page_shift = ffs(chip->nc_page_size) - 1;
400de9f8578Sahoka chip->nc_page_mask = ~(chip->nc_page_size - 1);
401de9f8578Sahoka /* same for block */
402de9f8578Sahoka chip->nc_block_shift = ffs(chip->nc_block_size) - 1;
403de9f8578Sahoka chip->nc_block_mask = ~(chip->nc_block_size - 1);
404de9f8578Sahoka
405bf03074aScliff #ifdef NOTYET
406de9f8578Sahoka /* look for quirks here if needed in future */
407bf03074aScliff nor_quirks(self, chip);
408bf03074aScliff #endif
409de9f8578Sahoka
410de9f8578Sahoka return 0;
411de9f8578Sahoka }
412de9f8578Sahoka
413de9f8578Sahoka /* ARGSUSED */
414bf03074aScliff static bool
nor_shutdown(device_t self,int howto)415de9f8578Sahoka nor_shutdown(device_t self, int howto)
416de9f8578Sahoka {
417de9f8578Sahoka return true;
418de9f8578Sahoka }
419de9f8578Sahoka
420de9f8578Sahoka /* implementation of the block device API */
421de9f8578Sahoka
422bf03074aScliff /* read a page, default implementation */
423bf03074aScliff static int
nor_default_read_page(device_t self,flash_off_t offset,uint8_t * const data)424bf03074aScliff nor_default_read_page(device_t self, flash_off_t offset, uint8_t * const data)
425de9f8578Sahoka {
426bf03074aScliff struct nor_softc * const sc = device_private(self);
427bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
428bf03074aScliff
429bf03074aScliff /*
430bf03074aScliff * access by specified access_width
431bf03074aScliff * note: #bits == 1 << width
432bf03074aScliff */
433bf03074aScliff switch(sc->sc_nor_if->access_width) {
434bf03074aScliff case 0:
435bf03074aScliff nor_read_buf_1(self, offset, data, chip->nc_page_size);
436bf03074aScliff break;
437bf03074aScliff case 1:
438bf03074aScliff nor_read_buf_2(self, offset, data, chip->nc_page_size);
439bf03074aScliff break;
440bf03074aScliff case 2:
441bf03074aScliff nor_read_buf_4(self, offset, data, chip->nc_page_size);
442bf03074aScliff break;
443bf03074aScliff #ifdef NOTYET
444bf03074aScliff case 3:
445bf03074aScliff nor_read_buf_8(self, offset, data, chip->nc_page_size);
446bf03074aScliff break;
447bf03074aScliff #endif
448bf03074aScliff default:
449bf03074aScliff panic("%s: bad width %d\n", __func__, sc->sc_nor_if->access_width);
450bf03074aScliff }
451bf03074aScliff
452bf03074aScliff #if 0
453bf03074aScliff /* for debugging new drivers */
454bf03074aScliff nor_dump_data("page", data, chip->nc_page_size);
455bf03074aScliff #endif
456bf03074aScliff
457de9f8578Sahoka return 0;
458de9f8578Sahoka }
459de9f8578Sahoka
460bf03074aScliff /* write a page, default implementation */
461bf03074aScliff static int
nor_default_program_page(device_t self,flash_off_t offset,const uint8_t * const data)462bf03074aScliff nor_default_program_page(device_t self, flash_off_t offset,
463bf03074aScliff const uint8_t * const data)
464de9f8578Sahoka {
465bf03074aScliff struct nor_softc * const sc = device_private(self);
466bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
467bf03074aScliff
468bf03074aScliff /*
469bf03074aScliff * access by specified width
470bf03074aScliff * #bits == 1 << access_width
471bf03074aScliff */
472bf03074aScliff switch(sc->sc_nor_if->access_width) {
473bf03074aScliff case 0:
474bf03074aScliff nor_write_buf_1(self, offset, data, chip->nc_page_size);
475bf03074aScliff break;
476bf03074aScliff case 1:
477bf03074aScliff nor_write_buf_2(self, offset, data, chip->nc_page_size);
478bf03074aScliff break;
479bf03074aScliff case 2:
480bf03074aScliff nor_write_buf_4(self, offset, data, chip->nc_page_size);
481bf03074aScliff break;
482bf03074aScliff #ifdef NOTYET
483bf03074aScliff case 3:
484bf03074aScliff nor_write_buf_8(self, offset, data, chip->nc_page_size);
485bf03074aScliff break;
486bf03074aScliff #endif
487bf03074aScliff default:
488bf03074aScliff panic("%s: bad width %d\n", __func__,
489bf03074aScliff sc->sc_nor_if->access_width);
490bf03074aScliff }
491bf03074aScliff
492bf03074aScliff #if 0
493bf03074aScliff /* for debugging new drivers */
494bf03074aScliff nor_dump_data("page", data, chip->nc_page_size);
495bf03074aScliff #endif
496bf03074aScliff
497de9f8578Sahoka return 0;
498de9f8578Sahoka }
499de9f8578Sahoka
500bf03074aScliff /*
501bf03074aScliff * nor_flash_erase_all - erase the entire chip
502bf03074aScliff *
503bf03074aScliff * XXX a good way to brick your system
504bf03074aScliff */
505bf03074aScliff static int
nor_flash_erase_all(device_t self)506bf03074aScliff nor_flash_erase_all(device_t self)
507de9f8578Sahoka {
508bf03074aScliff struct nor_softc * const sc = device_private(self);
509bf03074aScliff int error;
510bf03074aScliff
511bf03074aScliff mutex_enter(&sc->sc_device_lock);
512bf03074aScliff error = nor_erase_all(self);
513bf03074aScliff mutex_exit(&sc->sc_device_lock);
514bf03074aScliff
515bf03074aScliff return error;
516bf03074aScliff }
517bf03074aScliff
518bf03074aScliff static int
nor_flash_erase(device_t self,struct flash_erase_instruction * const ei)519bf03074aScliff nor_flash_erase(device_t self, struct flash_erase_instruction * const ei)
520bf03074aScliff {
521bf03074aScliff struct nor_softc * const sc = device_private(self);
522bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
523bf03074aScliff flash_off_t addr;
524bf03074aScliff int error = 0;
525bf03074aScliff
526bf03074aScliff if (ei->ei_addr < 0 || ei->ei_len < chip->nc_block_size)
527bf03074aScliff return EINVAL;
528bf03074aScliff
529bf03074aScliff if (ei->ei_addr + ei->ei_len > chip->nc_size) {
530bf03074aScliff DPRINTF(("%s: erase address is past the end"
531bf03074aScliff " of the device\n", __func__));
532bf03074aScliff return EINVAL;
533bf03074aScliff }
534bf03074aScliff
535bf03074aScliff if ((ei->ei_addr == 0) && (ei->ei_len == chip->nc_size)
536bf03074aScliff && (sc->sc_nor_if->erase_all != NULL)) {
537bf03074aScliff return nor_flash_erase_all(self);
538bf03074aScliff }
539bf03074aScliff
540bf03074aScliff if (ei->ei_addr % chip->nc_block_size != 0) {
541bf03074aScliff aprint_error_dev(self,
542bf03074aScliff "nor_flash_erase: ei_addr (%ju) is not"
543bf03074aScliff " a multiple of block size (%ju)\n",
544bf03074aScliff (uintmax_t)ei->ei_addr,
545bf03074aScliff (uintmax_t)chip->nc_block_size);
546bf03074aScliff return EINVAL;
547bf03074aScliff }
548bf03074aScliff
549bf03074aScliff if (ei->ei_len % chip->nc_block_size != 0) {
550bf03074aScliff aprint_error_dev(self,
551bf03074aScliff "nor_flash_erase: ei_len (%ju) is not"
552bf03074aScliff " a multiple of block size (%ju)",
553bf03074aScliff (uintmax_t)ei->ei_len,
554bf03074aScliff (uintmax_t)chip->nc_block_size);
555bf03074aScliff return EINVAL;
556bf03074aScliff }
557bf03074aScliff
558bf03074aScliff mutex_enter(&sc->sc_device_lock);
559bf03074aScliff addr = ei->ei_addr;
560bf03074aScliff while (addr < ei->ei_addr + ei->ei_len) {
561bf03074aScliff #ifdef NOTYET
562bf03074aScliff if (nor_isbad(self, addr)) {
563bf03074aScliff aprint_error_dev(self, "bad block encountered\n");
564bf03074aScliff ei->ei_state = FLASH_ERASE_FAILED;
565bf03074aScliff error = EIO;
566bf03074aScliff goto out;
567bf03074aScliff }
568bf03074aScliff #endif
569bf03074aScliff
570bf03074aScliff error = nor_erase_block(self, addr);
571bf03074aScliff if (error) {
572bf03074aScliff ei->ei_state = FLASH_ERASE_FAILED;
573bf03074aScliff goto out;
574bf03074aScliff }
575bf03074aScliff
576bf03074aScliff addr += chip->nc_block_size;
577bf03074aScliff }
578bf03074aScliff mutex_exit(&sc->sc_device_lock);
579bf03074aScliff
580bf03074aScliff ei->ei_state = FLASH_ERASE_DONE;
581bf03074aScliff if (ei->ei_callback != NULL) {
582bf03074aScliff ei->ei_callback(ei);
583bf03074aScliff }
584bf03074aScliff
585bf03074aScliff return 0;
586bf03074aScliff out:
587bf03074aScliff mutex_exit(&sc->sc_device_lock);
588bf03074aScliff
589bf03074aScliff return error;
590bf03074aScliff }
591bf03074aScliff
592bf03074aScliff /*
593bf03074aScliff * handle (page) unaligned write to nor
594bf03074aScliff */
595bf03074aScliff static int
nor_flash_write_unaligned(device_t self,flash_off_t offset,size_t len,size_t * const retlen,const uint8_t * const buf)596bf03074aScliff nor_flash_write_unaligned(device_t self, flash_off_t offset, size_t len,
597bf03074aScliff size_t * const retlen, const uint8_t * const buf)
598bf03074aScliff {
599bf03074aScliff struct nor_softc * const sc = device_private(self);
600bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
601bf03074aScliff flash_off_t first, last, firstoff;
602bf03074aScliff const uint8_t *bufp;
603bf03074aScliff flash_off_t addr;
604bf03074aScliff size_t left, count;
605bf03074aScliff int error = 0, i;
606bf03074aScliff
607bf03074aScliff first = offset & chip->nc_page_mask;
608bf03074aScliff firstoff = offset & ~chip->nc_page_mask;
609bf03074aScliff /* XXX check if this should be len - 1 */
610bf03074aScliff last = (offset + len) & chip->nc_page_mask;
611bf03074aScliff count = last - first + 1;
612bf03074aScliff
613bf03074aScliff addr = first;
614bf03074aScliff *retlen = 0;
615bf03074aScliff
616bf03074aScliff mutex_enter(&sc->sc_device_lock);
617bf03074aScliff if (count == 1) {
618bf03074aScliff #ifdef NOTYET
619bf03074aScliff if (nor_isbad(self, addr)) {
620bf03074aScliff aprint_error_dev(self,
621bf03074aScliff "nor_flash_write_unaligned: "
622bf03074aScliff "bad block encountered\n");
623bf03074aScliff error = EIO;
624bf03074aScliff goto out;
625bf03074aScliff }
626bf03074aScliff #endif
627bf03074aScliff
628bf03074aScliff error = nor_read_page(self, addr, chip->nc_page_cache);
629bf03074aScliff if (error) {
630bf03074aScliff goto out;
631bf03074aScliff }
632bf03074aScliff
633bf03074aScliff memcpy(chip->nc_page_cache + firstoff, buf, len);
634bf03074aScliff
635bf03074aScliff error = nor_program_page(self, addr, chip->nc_page_cache);
636bf03074aScliff if (error) {
637bf03074aScliff goto out;
638bf03074aScliff }
639bf03074aScliff
640bf03074aScliff *retlen = len;
641bf03074aScliff goto out;
642bf03074aScliff }
643bf03074aScliff
644bf03074aScliff bufp = buf;
645bf03074aScliff left = len;
646bf03074aScliff
647bf03074aScliff for (i = 0; i < count && left != 0; i++) {
648bf03074aScliff #ifdef NOTYET
649bf03074aScliff if (nor_isbad(self, addr)) {
650bf03074aScliff aprint_error_dev(self,
651bf03074aScliff "nor_flash_write_unaligned: "
652bf03074aScliff "bad block encountered\n");
653bf03074aScliff error = EIO;
654bf03074aScliff goto out;
655bf03074aScliff }
656bf03074aScliff #endif
657bf03074aScliff
658bf03074aScliff if (i == 0) {
659bf03074aScliff error = nor_read_page(self, addr, chip->nc_page_cache);
660bf03074aScliff if (error) {
661bf03074aScliff goto out;
662bf03074aScliff }
663bf03074aScliff
664bf03074aScliff memcpy(chip->nc_page_cache + firstoff,
665bf03074aScliff bufp, chip->nc_page_size - firstoff);
666bf03074aScliff
667bf03074aScliff printf("write page: %s: %d\n", __FILE__, __LINE__);
668bf03074aScliff error = nor_program_page(self, addr,
669bf03074aScliff chip->nc_page_cache);
670bf03074aScliff if (error) {
671bf03074aScliff goto out;
672bf03074aScliff }
673bf03074aScliff
674bf03074aScliff bufp += chip->nc_page_size - firstoff;
675bf03074aScliff left -= chip->nc_page_size - firstoff;
676bf03074aScliff *retlen += chip->nc_page_size - firstoff;
677bf03074aScliff
678bf03074aScliff } else if (i == count - 1) {
679bf03074aScliff error = nor_read_page(self, addr, chip->nc_page_cache);
680bf03074aScliff if (error) {
681bf03074aScliff goto out;
682bf03074aScliff }
683bf03074aScliff
684bf03074aScliff memcpy(chip->nc_page_cache, bufp, left);
685bf03074aScliff
686bf03074aScliff error = nor_program_page(self, addr,
687bf03074aScliff chip->nc_page_cache);
688bf03074aScliff if (error) {
689bf03074aScliff goto out;
690bf03074aScliff }
691bf03074aScliff
692bf03074aScliff *retlen += left;
693bf03074aScliff KASSERT(left < chip->nc_page_size);
694bf03074aScliff
695bf03074aScliff } else {
696bf03074aScliff /* XXX debug */
697bf03074aScliff if (left > chip->nc_page_size) {
698bf03074aScliff printf("left: %zu, i: %d, count: %zu\n",
699bf03074aScliff (size_t )left, i, count);
700bf03074aScliff }
701bf03074aScliff KASSERT(left > chip->nc_page_size);
702bf03074aScliff
703bf03074aScliff error = nor_program_page(self, addr, bufp);
704bf03074aScliff if (error) {
705bf03074aScliff goto out;
706bf03074aScliff }
707bf03074aScliff
708bf03074aScliff bufp += chip->nc_page_size;
709bf03074aScliff left -= chip->nc_page_size;
710bf03074aScliff *retlen += chip->nc_page_size;
711bf03074aScliff }
712bf03074aScliff
713bf03074aScliff addr += chip->nc_page_size;
714bf03074aScliff }
715bf03074aScliff
716bf03074aScliff KASSERT(*retlen == len);
717bf03074aScliff out:
718bf03074aScliff mutex_exit(&sc->sc_device_lock);
719bf03074aScliff
720bf03074aScliff return error;
721bf03074aScliff }
722bf03074aScliff
723bf03074aScliff static int
nor_flash_write(device_t self,flash_off_t offset,size_t len,size_t * const retlen,const uint8_t * const buf)724bf03074aScliff nor_flash_write(device_t self, flash_off_t offset, size_t len,
725bf03074aScliff size_t * const retlen, const uint8_t * const buf)
726bf03074aScliff {
727bf03074aScliff struct nor_softc * const sc = device_private(self);
728bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
729bf03074aScliff const uint8_t *bufp;
730bf03074aScliff size_t pages, page;
731bf03074aScliff daddr_t addr;
732bf03074aScliff int error = 0;
733bf03074aScliff
734bf03074aScliff if ((offset + len) > chip->nc_size) {
735bf03074aScliff DPRINTF(("%s: write (off: 0x%jx, len: %ju),"
736bf03074aScliff " exceeds device size (0x%jx)\n", __func__,
737bf03074aScliff (uintmax_t)offset, (uintmax_t)len,
738bf03074aScliff (uintmax_t)chip->nc_size));
739bf03074aScliff return EINVAL;
740bf03074aScliff }
741bf03074aScliff
742bf03074aScliff if (len % chip->nc_page_size != 0 ||
743bf03074aScliff offset % chip->nc_page_size != 0) {
744bf03074aScliff return nor_flash_write_unaligned(self,
745bf03074aScliff offset, len, retlen, buf);
746bf03074aScliff }
747bf03074aScliff
748bf03074aScliff pages = len / chip->nc_page_size;
749bf03074aScliff KASSERT(pages != 0);
750bf03074aScliff *retlen = 0;
751bf03074aScliff
752bf03074aScliff addr = offset;
753bf03074aScliff bufp = buf;
754bf03074aScliff
755bf03074aScliff mutex_enter(&sc->sc_device_lock);
756bf03074aScliff for (page = 0; page < pages; page++) {
757bf03074aScliff #ifdef NOTYET
758bf03074aScliff /* do we need this check here? */
759bf03074aScliff if (nor_isbad(self, addr)) {
760bf03074aScliff aprint_error_dev(self,
761bf03074aScliff "nor_flash_write: bad block encountered\n");
762bf03074aScliff
763bf03074aScliff error = EIO;
764bf03074aScliff goto out;
765bf03074aScliff }
766bf03074aScliff #endif
767bf03074aScliff
768bf03074aScliff error = nor_program_page(self, addr, bufp);
769bf03074aScliff if (error) {
770bf03074aScliff goto out;
771bf03074aScliff }
772bf03074aScliff
773bf03074aScliff addr += chip->nc_page_size;
774bf03074aScliff bufp += chip->nc_page_size;
775bf03074aScliff *retlen += chip->nc_page_size;
776bf03074aScliff }
777bf03074aScliff out:
778bf03074aScliff mutex_exit(&sc->sc_device_lock);
779bf03074aScliff DPRINTF(("%s: retlen: %zu, len: %zu\n", __func__, *retlen, len));
780bf03074aScliff
781bf03074aScliff return error;
782bf03074aScliff }
783bf03074aScliff
784bf03074aScliff /*
785bf03074aScliff * handle (page) unaligned read from nor
786bf03074aScliff */
787bf03074aScliff static int
nor_flash_read_unaligned(device_t self,flash_off_t offset,size_t len,size_t * const retlen,uint8_t * const buf)788bf03074aScliff nor_flash_read_unaligned(device_t self, flash_off_t offset, size_t len,
789bf03074aScliff size_t * const retlen, uint8_t * const buf)
790bf03074aScliff {
791bf03074aScliff struct nor_softc * const sc = device_private(self);
792bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
793bf03074aScliff daddr_t first, last, count, firstoff;
794bf03074aScliff uint8_t *bufp;
795bf03074aScliff daddr_t addr;
796bf03074aScliff size_t left;
797bf03074aScliff int error = 0, i;
798bf03074aScliff
799bf03074aScliff first = offset & chip->nc_page_mask;
800bf03074aScliff firstoff = offset & ~chip->nc_page_mask;
801bf03074aScliff last = (offset + len) & chip->nc_page_mask;
802bf03074aScliff count = (last - first) / chip->nc_page_size + 1;
803bf03074aScliff
804bf03074aScliff addr = first;
805bf03074aScliff bufp = buf;
806bf03074aScliff left = len;
807bf03074aScliff *retlen = 0;
808bf03074aScliff
809bf03074aScliff mutex_enter(&sc->sc_device_lock);
810bf03074aScliff if (count == 1) {
811bf03074aScliff error = nor_read_page(self, addr, chip->nc_page_cache);
812bf03074aScliff if (error) {
813bf03074aScliff goto out;
814bf03074aScliff }
815bf03074aScliff
816bf03074aScliff memcpy(bufp, chip->nc_page_cache + firstoff, len);
817bf03074aScliff
818bf03074aScliff *retlen = len;
819bf03074aScliff goto out;
820bf03074aScliff }
821bf03074aScliff
822bf03074aScliff for (i = 0; i < count && left != 0; i++) {
823bf03074aScliff /* XXX Why use the page cache here ? */
824bf03074aScliff error = nor_read_page(self, addr, chip->nc_page_cache);
825bf03074aScliff if (error) {
826bf03074aScliff goto out;
827bf03074aScliff }
828bf03074aScliff
829bf03074aScliff if (i == 0) {
830bf03074aScliff memcpy(bufp, chip->nc_page_cache + firstoff,
831bf03074aScliff chip->nc_page_size - firstoff);
832bf03074aScliff
833bf03074aScliff bufp += chip->nc_page_size - firstoff;
834bf03074aScliff left -= chip->nc_page_size - firstoff;
835bf03074aScliff *retlen += chip->nc_page_size - firstoff;
836bf03074aScliff
837bf03074aScliff } else if (i == count - 1) {
838bf03074aScliff memcpy(bufp, chip->nc_page_cache, left);
839bf03074aScliff *retlen += left;
840bf03074aScliff KASSERT(left < chip->nc_page_size);
841bf03074aScliff
842bf03074aScliff } else {
843bf03074aScliff memcpy(bufp, chip->nc_page_cache, chip->nc_page_size);
844bf03074aScliff
845bf03074aScliff bufp += chip->nc_page_size;
846bf03074aScliff left -= chip->nc_page_size;
847bf03074aScliff *retlen += chip->nc_page_size;
848bf03074aScliff }
849bf03074aScliff
850bf03074aScliff addr += chip->nc_page_size;
851bf03074aScliff }
852bf03074aScliff KASSERT(*retlen == len);
853bf03074aScliff out:
854bf03074aScliff mutex_exit(&sc->sc_device_lock);
855bf03074aScliff
856bf03074aScliff return error;
857bf03074aScliff }
858bf03074aScliff
859bf03074aScliff static int
nor_flash_read(device_t self,flash_off_t offset,size_t len,size_t * const retlen,uint8_t * const buf)860bf03074aScliff nor_flash_read(device_t self, flash_off_t offset, size_t len,
861bf03074aScliff size_t * const retlen, uint8_t * const buf)
862bf03074aScliff {
863bf03074aScliff struct nor_softc * const sc = device_private(self);
864bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
865bf03074aScliff uint8_t *bufp;
866bf03074aScliff size_t addr;
867bf03074aScliff size_t i, pages;
868bf03074aScliff int error = 0;
869bf03074aScliff
870bf03074aScliff *retlen = 0;
871bf03074aScliff
872bf03074aScliff DPRINTF(("%s: off: 0x%jx, len: %zu\n",
873bf03074aScliff __func__, (uintmax_t)offset, len));
874bf03074aScliff
875bf03074aScliff if (__predict_false((offset + len) > chip->nc_size)) {
876bf03074aScliff DPRINTF(("%s: read (off: 0x%jx, len: %zu),"
877bf03074aScliff " exceeds device size (%ju)\n", __func__,
878bf03074aScliff (uintmax_t)offset, len, (uintmax_t)chip->nc_size));
879bf03074aScliff return EINVAL;
880bf03074aScliff }
881bf03074aScliff
882bf03074aScliff /* Handle unaligned access, shouldnt be needed when using the
883bf03074aScliff * block device, as strategy handles it, so only low level
884bf03074aScliff * accesses will use this path
885bf03074aScliff */
886bf03074aScliff /* XXX^2 */
887bf03074aScliff #if 0
888bf03074aScliff if (len < chip->nc_page_size)
889bf03074aScliff panic("TODO page size is larger than read size");
890bf03074aScliff #endif
891bf03074aScliff
892bf03074aScliff if (len % chip->nc_page_size != 0 ||
893bf03074aScliff offset % chip->nc_page_size != 0) {
894bf03074aScliff return nor_flash_read_unaligned(self,
895bf03074aScliff offset, len, retlen, buf);
896bf03074aScliff }
897bf03074aScliff
898bf03074aScliff bufp = buf;
899bf03074aScliff addr = offset;
900bf03074aScliff pages = len / chip->nc_page_size;
901bf03074aScliff
902bf03074aScliff mutex_enter(&sc->sc_device_lock);
903bf03074aScliff for (i = 0; i < pages; i++) {
904bf03074aScliff #ifdef NOTYET
905bf03074aScliff /* XXX do we need this check here? */
906bf03074aScliff if (nor_isbad(self, addr)) {
907bf03074aScliff aprint_error_dev(self, "bad block encountered\n");
908bf03074aScliff error = EIO;
909bf03074aScliff goto out;
910bf03074aScliff }
911bf03074aScliff #endif
912bf03074aScliff error = nor_read_page(self, addr, bufp);
913bf03074aScliff if (error)
914bf03074aScliff goto out;
915bf03074aScliff
916bf03074aScliff bufp += chip->nc_page_size;
917bf03074aScliff addr += chip->nc_page_size;
918bf03074aScliff *retlen += chip->nc_page_size;
919bf03074aScliff }
920bf03074aScliff out:
921bf03074aScliff mutex_exit(&sc->sc_device_lock);
922bf03074aScliff
923bf03074aScliff return error;
924bf03074aScliff }
925bf03074aScliff
926bf03074aScliff static int
nor_flash_isbad(device_t self,flash_off_t ofs,bool * const isbad)927bf03074aScliff nor_flash_isbad(device_t self, flash_off_t ofs, bool * const isbad)
928bf03074aScliff {
929bf03074aScliff struct nor_softc * const sc = device_private(self);
930bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
931bf03074aScliff #ifdef NOTYET
932bf03074aScliff bool result;
933bf03074aScliff #endif
934de9f8578Sahoka
935de9f8578Sahoka if (ofs > chip->nc_size) {
936bf03074aScliff DPRINTF(("%s: offset 0x%jx is larger than"
937bf03074aScliff " device size (0x%jx)\n", __func__,
938bf03074aScliff (uintmax_t)ofs, (uintmax_t)chip->nc_size));
939de9f8578Sahoka return EINVAL;
940de9f8578Sahoka }
941de9f8578Sahoka
942de9f8578Sahoka if (ofs % chip->nc_block_size != 0) {
943de9f8578Sahoka DPRINTF(("offset (0x%jx) is not the multiple of block size "
944de9f8578Sahoka "(%ju)",
945de9f8578Sahoka (uintmax_t)ofs, (uintmax_t)chip->nc_block_size));
946de9f8578Sahoka return EINVAL;
947de9f8578Sahoka }
948de9f8578Sahoka
949bf03074aScliff #ifdef NOTYET
950de9f8578Sahoka mutex_enter(&sc->sc_device_lock);
951bf03074aScliff result = nor_isbad(self, ofs);
952de9f8578Sahoka mutex_exit(&sc->sc_device_lock);
953de9f8578Sahoka
954bf03074aScliff *isbad = result;
955bf03074aScliff #else
956de9f8578Sahoka *isbad = false;
957bf03074aScliff #endif
958de9f8578Sahoka
959de9f8578Sahoka return 0;
960de9f8578Sahoka }
961de9f8578Sahoka
962bf03074aScliff static int
nor_flash_markbad(device_t self,flash_off_t ofs)963de9f8578Sahoka nor_flash_markbad(device_t self, flash_off_t ofs)
964de9f8578Sahoka {
965bf03074aScliff struct nor_softc * const sc = device_private(self);
966bf03074aScliff struct nor_chip * const chip = &sc->sc_chip;
967de9f8578Sahoka
968de9f8578Sahoka if (ofs > chip->nc_size) {
969bf03074aScliff DPRINTF(("%s: offset 0x%jx is larger than"
970bf03074aScliff " device size (0x%jx)\n", __func__,
971bf03074aScliff ofs, (uintmax_t)chip->nc_size));
972de9f8578Sahoka return EINVAL;
973de9f8578Sahoka }
974de9f8578Sahoka
975de9f8578Sahoka if (ofs % chip->nc_block_size != 0) {
976de9f8578Sahoka panic("offset (%ju) is not the multiple of block size (%ju)",
977de9f8578Sahoka (uintmax_t)ofs, (uintmax_t)chip->nc_block_size);
978de9f8578Sahoka }
979de9f8578Sahoka
980de9f8578Sahoka /* TODO: implement this */
981de9f8578Sahoka
982de9f8578Sahoka return 0;
983de9f8578Sahoka }
984de9f8578Sahoka
985de9f8578Sahoka static int
sysctl_nor_verify(SYSCTLFN_ARGS)986de9f8578Sahoka sysctl_nor_verify(SYSCTLFN_ARGS)
987de9f8578Sahoka {
988de9f8578Sahoka int error, t;
989de9f8578Sahoka struct sysctlnode node;
990de9f8578Sahoka
991de9f8578Sahoka node = *rnode;
992de9f8578Sahoka t = *(int *)rnode->sysctl_data;
993de9f8578Sahoka node.sysctl_data = &t;
994de9f8578Sahoka error = sysctl_lookup(SYSCTLFN_CALL(&node));
995de9f8578Sahoka if (error || newp == NULL)
996de9f8578Sahoka return error;
997de9f8578Sahoka
998de9f8578Sahoka if (node.sysctl_num == nor_cachesync_nodenum) {
999de9f8578Sahoka if (t <= 0 || t > 60)
1000de9f8578Sahoka return EINVAL;
1001de9f8578Sahoka } else {
1002de9f8578Sahoka return EINVAL;
1003de9f8578Sahoka }
1004de9f8578Sahoka
1005de9f8578Sahoka *(int *)rnode->sysctl_data = t;
1006de9f8578Sahoka
1007de9f8578Sahoka return 0;
1008de9f8578Sahoka }
1009de9f8578Sahoka
1010de9f8578Sahoka SYSCTL_SETUP(sysctl_nor, "sysctl nor subtree setup")
1011de9f8578Sahoka {
1012de9f8578Sahoka int rc, nor_root_num;
1013de9f8578Sahoka const struct sysctlnode *node;
1014de9f8578Sahoka
1015de9f8578Sahoka if ((rc = sysctl_createv(clog, 0, NULL, &node,
1016de9f8578Sahoka CTLFLAG_PERMANENT, CTLTYPE_NODE, "nor",
1017de9f8578Sahoka SYSCTL_DESCR("NOR driver controls"),
1018de9f8578Sahoka NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
1019de9f8578Sahoka goto error;
1020de9f8578Sahoka }
1021de9f8578Sahoka
1022de9f8578Sahoka nor_root_num = node->sysctl_num;
1023de9f8578Sahoka
1024de9f8578Sahoka if ((rc = sysctl_createv(clog, 0, NULL, &node,
1025de9f8578Sahoka CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1026de9f8578Sahoka CTLTYPE_INT, "cache_sync_timeout",
1027de9f8578Sahoka SYSCTL_DESCR("NOR write cache sync timeout in seconds"),
1028de9f8578Sahoka sysctl_nor_verify, 0, &nor_cachesync_timeout,
1029de9f8578Sahoka 0, CTL_HW, nor_root_num, CTL_CREATE,
1030de9f8578Sahoka CTL_EOL)) != 0) {
1031de9f8578Sahoka goto error;
1032de9f8578Sahoka }
1033de9f8578Sahoka
1034de9f8578Sahoka nor_cachesync_nodenum = node->sysctl_num;
1035de9f8578Sahoka
1036de9f8578Sahoka return;
1037de9f8578Sahoka
1038de9f8578Sahoka error:
1039de9f8578Sahoka aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
1040de9f8578Sahoka }
1041de9f8578Sahoka
1042de9f8578Sahoka MODULE(MODULE_CLASS_DRIVER, nor, "flash");
1043de9f8578Sahoka
1044de9f8578Sahoka #ifdef _MODULE
1045de9f8578Sahoka #include "ioconf.c"
1046de9f8578Sahoka #endif
1047de9f8578Sahoka
1048de9f8578Sahoka static int
nor_modcmd(modcmd_t cmd,void * opaque)1049de9f8578Sahoka nor_modcmd(modcmd_t cmd, void *opaque)
1050de9f8578Sahoka {
1051de9f8578Sahoka switch (cmd) {
1052de9f8578Sahoka case MODULE_CMD_INIT:
1053de9f8578Sahoka #ifdef _MODULE
1054de9f8578Sahoka return config_init_component(cfdriver_ioconf_nor,
1055de9f8578Sahoka cfattach_ioconf_nor, cfdata_ioconf_nor);
1056de9f8578Sahoka #else
1057de9f8578Sahoka return 0;
1058de9f8578Sahoka #endif
1059de9f8578Sahoka case MODULE_CMD_FINI:
1060de9f8578Sahoka #ifdef _MODULE
1061de9f8578Sahoka return config_fini_component(cfdriver_ioconf_nor,
1062de9f8578Sahoka cfattach_ioconf_nor, cfdata_ioconf_nor);
1063de9f8578Sahoka #else
1064de9f8578Sahoka return 0;
1065de9f8578Sahoka #endif
1066de9f8578Sahoka default:
1067de9f8578Sahoka return ENOTTY;
1068de9f8578Sahoka }
1069de9f8578Sahoka }
1070