xref: /freebsd/sys/dev/fdt/fdt_slicer.c (revision 4e462178745853ecc014c13f82f89cfe39b83e9c)
14ffd4dfeSGrzegorz Bernacki /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
44ffd4dfeSGrzegorz Bernacki  * Copyright (c) 2012 Semihalf.
54ffd4dfeSGrzegorz Bernacki  * All rights reserved.
64ffd4dfeSGrzegorz Bernacki  *
74ffd4dfeSGrzegorz Bernacki  * Redistribution and use in source and binary forms, with or without
84ffd4dfeSGrzegorz Bernacki  * modification, are permitted provided that the following conditions
94ffd4dfeSGrzegorz Bernacki  * are met:
104ffd4dfeSGrzegorz Bernacki  * 1. Redistributions of source code must retain the above copyright
114ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer.
124ffd4dfeSGrzegorz Bernacki  * 2. Redistributions in binary form must reproduce the above copyright
134ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer in the
144ffd4dfeSGrzegorz Bernacki  *    documentation and/or other materials provided with the distribution.
154ffd4dfeSGrzegorz Bernacki  *
164ffd4dfeSGrzegorz Bernacki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174ffd4dfeSGrzegorz Bernacki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184ffd4dfeSGrzegorz Bernacki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194ffd4dfeSGrzegorz Bernacki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204ffd4dfeSGrzegorz Bernacki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214ffd4dfeSGrzegorz Bernacki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224ffd4dfeSGrzegorz Bernacki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234ffd4dfeSGrzegorz Bernacki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244ffd4dfeSGrzegorz Bernacki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254ffd4dfeSGrzegorz Bernacki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264ffd4dfeSGrzegorz Bernacki  * SUCH DAMAGE.
274ffd4dfeSGrzegorz Bernacki  */
284ffd4dfeSGrzegorz Bernacki 
294ffd4dfeSGrzegorz Bernacki #include <sys/cdefs.h>
304ffd4dfeSGrzegorz Bernacki __FBSDID("$FreeBSD$");
314ffd4dfeSGrzegorz Bernacki 
324ffd4dfeSGrzegorz Bernacki #include <sys/param.h>
334ffd4dfeSGrzegorz Bernacki #include <sys/systm.h>
344ffd4dfeSGrzegorz Bernacki #include <sys/kernel.h>
35*4e462178SIan Lepore #include <sys/module.h>
364ffd4dfeSGrzegorz Bernacki #include <sys/slicer.h>
374ffd4dfeSGrzegorz Bernacki 
384ffd4dfeSGrzegorz Bernacki #include <dev/fdt/fdt_common.h>
394874af73SMarius Strobl #include <dev/ofw/ofw_bus.h>
404874af73SMarius Strobl #include <dev/ofw/openfirm.h>
414ffd4dfeSGrzegorz Bernacki 
424ffd4dfeSGrzegorz Bernacki #ifdef DEBUG
434ffd4dfeSGrzegorz Bernacki #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
444ffd4dfeSGrzegorz Bernacki     printf(fmt,##args); } while (0)
454ffd4dfeSGrzegorz Bernacki #else
464ffd4dfeSGrzegorz Bernacki #define debugf(fmt, args...)
474ffd4dfeSGrzegorz Bernacki #endif
484ffd4dfeSGrzegorz Bernacki 
494874af73SMarius Strobl static int fdt_flash_fill_slices(device_t dev, const char *provider,
504874af73SMarius Strobl     struct flash_slice *slices, int *slices_num);
514874af73SMarius Strobl static void fdt_slicer_init(void);
524874af73SMarius Strobl 
534874af73SMarius Strobl static int
544874af73SMarius Strobl fdt_flash_fill_slices(device_t dev, const char *provider __unused,
554874af73SMarius Strobl     struct flash_slice *slices, int *slices_num)
564ffd4dfeSGrzegorz Bernacki {
574ffd4dfeSGrzegorz Bernacki 	char *slice_name;
584ffd4dfeSGrzegorz Bernacki 	phandle_t dt_node, dt_child;
594ffd4dfeSGrzegorz Bernacki 	u_long base, size;
604ffd4dfeSGrzegorz Bernacki 	int i;
614ffd4dfeSGrzegorz Bernacki 	ssize_t name_len;
624ffd4dfeSGrzegorz Bernacki 
634ffd4dfeSGrzegorz Bernacki 	/*
644ffd4dfeSGrzegorz Bernacki 	 * We assume the caller provides buffer for FLASH_SLICES_MAX_NUM
654ffd4dfeSGrzegorz Bernacki 	 * flash_slice structures.
664ffd4dfeSGrzegorz Bernacki 	 */
674ffd4dfeSGrzegorz Bernacki 	if (slices == NULL) {
684ffd4dfeSGrzegorz Bernacki 		*slices_num = 0;
694ffd4dfeSGrzegorz Bernacki 		return (ENOMEM);
704ffd4dfeSGrzegorz Bernacki 	}
714ffd4dfeSGrzegorz Bernacki 
724ffd4dfeSGrzegorz Bernacki 	dt_node = ofw_bus_get_node(dev);
734ffd4dfeSGrzegorz Bernacki 	for (dt_child = OF_child(dt_node), i = 0; dt_child != 0;
744ffd4dfeSGrzegorz Bernacki 	    dt_child = OF_peer(dt_child)) {
754ffd4dfeSGrzegorz Bernacki 
764ffd4dfeSGrzegorz Bernacki 		if (i == FLASH_SLICES_MAX_NUM) {
774ffd4dfeSGrzegorz Bernacki 			debugf("not enough buffer for slice i=%d\n", i);
784ffd4dfeSGrzegorz Bernacki 			break;
794ffd4dfeSGrzegorz Bernacki 		}
804ffd4dfeSGrzegorz Bernacki 
814ffd4dfeSGrzegorz Bernacki 		/*
824ffd4dfeSGrzegorz Bernacki 		 * Retrieve start and size of the slice.
834ffd4dfeSGrzegorz Bernacki 		 */
844ffd4dfeSGrzegorz Bernacki 		if (fdt_regsize(dt_child, &base, &size) != 0) {
854ffd4dfeSGrzegorz Bernacki 			debugf("error during processing reg property, i=%d\n",
864ffd4dfeSGrzegorz Bernacki 			    i);
874ffd4dfeSGrzegorz Bernacki 			continue;
884ffd4dfeSGrzegorz Bernacki 		}
894ffd4dfeSGrzegorz Bernacki 
904ffd4dfeSGrzegorz Bernacki 		if (size == 0) {
914ffd4dfeSGrzegorz Bernacki 			debugf("slice i=%d with no size\n", i);
924ffd4dfeSGrzegorz Bernacki 			continue;
934ffd4dfeSGrzegorz Bernacki 		}
944ffd4dfeSGrzegorz Bernacki 
954ffd4dfeSGrzegorz Bernacki 		/*
964ffd4dfeSGrzegorz Bernacki 		 * Retrieve label.
974ffd4dfeSGrzegorz Bernacki 		 */
98217d17bcSOleksandr Tymoshenko 		name_len = OF_getprop_alloc(dt_child, "label",
994ffd4dfeSGrzegorz Bernacki 		    (void **)&slice_name);
1004ffd4dfeSGrzegorz Bernacki 		if (name_len <= 0) {
1014ffd4dfeSGrzegorz Bernacki 			/* Use node name if no label defined */
1024874af73SMarius Strobl 			name_len = OF_getprop_alloc(dt_child, "name",
103217d17bcSOleksandr Tymoshenko 			    (void **)&slice_name);
1044ffd4dfeSGrzegorz Bernacki 			if (name_len <= 0) {
1054ffd4dfeSGrzegorz Bernacki 				debugf("slice i=%d with no name\n", i);
1064ffd4dfeSGrzegorz Bernacki 				slice_name = NULL;
1074ffd4dfeSGrzegorz Bernacki 			}
1084ffd4dfeSGrzegorz Bernacki 		}
1094ffd4dfeSGrzegorz Bernacki 
1104ffd4dfeSGrzegorz Bernacki 		/*
1114ffd4dfeSGrzegorz Bernacki 		 * Fill slice entry data.
1124ffd4dfeSGrzegorz Bernacki 		 */
1134ffd4dfeSGrzegorz Bernacki 		slices[i].base = base;
1144ffd4dfeSGrzegorz Bernacki 		slices[i].size = size;
1154ffd4dfeSGrzegorz Bernacki 		slices[i].label = slice_name;
1164ffd4dfeSGrzegorz Bernacki 		i++;
1174ffd4dfeSGrzegorz Bernacki 	}
1184ffd4dfeSGrzegorz Bernacki 
1194ffd4dfeSGrzegorz Bernacki 	*slices_num = i;
1204ffd4dfeSGrzegorz Bernacki 	return (0);
1214ffd4dfeSGrzegorz Bernacki }
1224874af73SMarius Strobl 
1234874af73SMarius Strobl static void
1244874af73SMarius Strobl fdt_slicer_init(void)
1254874af73SMarius Strobl {
1264874af73SMarius Strobl 
1274874af73SMarius Strobl 	flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_NAND,
1284874af73SMarius Strobl 	   FALSE);
1294874af73SMarius Strobl 	flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_CFI,
1304874af73SMarius Strobl 	   FALSE);
1314874af73SMarius Strobl 	flash_register_slicer(fdt_flash_fill_slices, FLASH_SLICES_TYPE_SPI,
1324874af73SMarius Strobl 	   FALSE);
1334874af73SMarius Strobl }
1344874af73SMarius Strobl 
135*4e462178SIan Lepore static void
136*4e462178SIan Lepore fdt_slicer_cleanup(void)
137*4e462178SIan Lepore {
138*4e462178SIan Lepore 
139*4e462178SIan Lepore 	flash_register_slicer(NULL, FLASH_SLICES_TYPE_NAND, true);
140*4e462178SIan Lepore 	flash_register_slicer(NULL, FLASH_SLICES_TYPE_CFI, true);
141*4e462178SIan Lepore 	flash_register_slicer(NULL, FLASH_SLICES_TYPE_SPI, true);
142*4e462178SIan Lepore }
143*4e462178SIan Lepore 
1444874af73SMarius Strobl /*
1454874af73SMarius Strobl  * Must be initialized after GEOM classes (SI_SUB_DRIVERS/SI_ORDER_FIRST),
1464874af73SMarius Strobl  * i. e. after g_init() is called, due to the use of the GEOM topology_lock
1474874af73SMarius Strobl  * in flash_register_slicer().  However, must be before SI_SUB_CONFIGURE.
1484874af73SMarius Strobl  */
149*4e462178SIan Lepore SYSINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_SECOND, fdt_slicer_init, NULL);
150*4e462178SIan Lepore SYSUNINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_SECOND, fdt_slicer_cleanup, NULL);
151*4e462178SIan Lepore 
152*4e462178SIan Lepore static int
153*4e462178SIan Lepore mod_handler(module_t mod, int type, void *data)
154*4e462178SIan Lepore {
155*4e462178SIan Lepore 
156*4e462178SIan Lepore 	/*
157*4e462178SIan Lepore 	 * Nothing to do here: the SYSINIT/SYSUNINIT defined above run
158*4e462178SIan Lepore 	 * automatically at module load/unload time.
159*4e462178SIan Lepore 	 */
160*4e462178SIan Lepore 	return (0);
161*4e462178SIan Lepore }
162*4e462178SIan Lepore 
163*4e462178SIan Lepore static moduledata_t fdt_slicer_mod = {
164*4e462178SIan Lepore 	"fdt_slicer", mod_handler, NULL
165*4e462178SIan Lepore };
166*4e462178SIan Lepore 
167*4e462178SIan Lepore DECLARE_MODULE(fdt_slicer, fdt_slicer_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
168*4e462178SIan Lepore MODULE_VERSION(fdt_slicer, 1);
169