14ffd4dfeSGrzegorz Bernacki /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
304ffd4dfeSGrzegorz Bernacki #include <sys/systm.h>
314ffd4dfeSGrzegorz Bernacki #include <sys/kernel.h>
324e462178SIan Lepore #include <sys/module.h>
334ffd4dfeSGrzegorz Bernacki #include <sys/slicer.h>
344ffd4dfeSGrzegorz Bernacki
354ffd4dfeSGrzegorz Bernacki #include <dev/fdt/fdt_common.h>
364874af73SMarius Strobl #include <dev/ofw/ofw_bus.h>
374874af73SMarius Strobl #include <dev/ofw/openfirm.h>
384ffd4dfeSGrzegorz Bernacki
394ffd4dfeSGrzegorz Bernacki #ifdef DEBUG
404ffd4dfeSGrzegorz Bernacki #define debugf(fmt, args...) do { printf("%s(): ", __func__); \
414ffd4dfeSGrzegorz Bernacki printf(fmt,##args); } while (0)
424ffd4dfeSGrzegorz Bernacki #else
434ffd4dfeSGrzegorz Bernacki #define debugf(fmt, args...)
444ffd4dfeSGrzegorz Bernacki #endif
454ffd4dfeSGrzegorz Bernacki
46db58d718SIan Lepore static int fill_slices(device_t dev, const char *provider,
474874af73SMarius Strobl struct flash_slice *slices, int *slices_num);
484874af73SMarius Strobl static void fdt_slicer_init(void);
494874af73SMarius Strobl
504874af73SMarius Strobl static int
fill_slices_from_node(phandle_t node,struct flash_slice * slices,int * count)51a6bcabcdSIan Lepore fill_slices_from_node(phandle_t node, struct flash_slice *slices, int *count)
524ffd4dfeSGrzegorz Bernacki {
53a6bcabcdSIan Lepore char *label;
54a6bcabcdSIan Lepore phandle_t child;
554ffd4dfeSGrzegorz Bernacki u_long base, size;
56a6bcabcdSIan Lepore int flags, i;
57db58d718SIan Lepore ssize_t nmlen;
584ffd4dfeSGrzegorz Bernacki
59db58d718SIan Lepore i = 0;
60db58d718SIan Lepore for (child = OF_child(node); child != 0; child = OF_peer(child)) {
61a6bcabcdSIan Lepore flags = FLASH_SLICES_FLAG_NONE;
624ffd4dfeSGrzegorz Bernacki
6385f55a2aSIan Lepore /* Nodes with a compatible property are not slices. */
6485f55a2aSIan Lepore if (OF_hasprop(child, "compatible"))
6585f55a2aSIan Lepore continue;
6685f55a2aSIan Lepore
674ffd4dfeSGrzegorz Bernacki if (i == FLASH_SLICES_MAX_NUM) {
684ffd4dfeSGrzegorz Bernacki debugf("not enough buffer for slice i=%d\n", i);
694ffd4dfeSGrzegorz Bernacki break;
704ffd4dfeSGrzegorz Bernacki }
714ffd4dfeSGrzegorz Bernacki
72db58d718SIan Lepore /* Retrieve start and size of the slice. */
73db58d718SIan Lepore if (fdt_regsize(child, &base, &size) != 0) {
744ffd4dfeSGrzegorz Bernacki debugf("error during processing reg property, i=%d\n",
754ffd4dfeSGrzegorz Bernacki i);
764ffd4dfeSGrzegorz Bernacki continue;
774ffd4dfeSGrzegorz Bernacki }
784ffd4dfeSGrzegorz Bernacki
794ffd4dfeSGrzegorz Bernacki if (size == 0) {
804ffd4dfeSGrzegorz Bernacki debugf("slice i=%d with no size\n", i);
814ffd4dfeSGrzegorz Bernacki continue;
824ffd4dfeSGrzegorz Bernacki }
834ffd4dfeSGrzegorz Bernacki
84db58d718SIan Lepore /* Retrieve label. */
85a6bcabcdSIan Lepore nmlen = OF_getprop_alloc(child, "label", (void **)&label);
86db58d718SIan Lepore if (nmlen <= 0) {
874ffd4dfeSGrzegorz Bernacki /* Use node name if no label defined */
88a6bcabcdSIan Lepore nmlen = OF_getprop_alloc(child, "name", (void **)&label);
89db58d718SIan Lepore if (nmlen <= 0) {
904ffd4dfeSGrzegorz Bernacki debugf("slice i=%d with no name\n", i);
91a6bcabcdSIan Lepore label = NULL;
924ffd4dfeSGrzegorz Bernacki }
934ffd4dfeSGrzegorz Bernacki }
944ffd4dfeSGrzegorz Bernacki
95a6bcabcdSIan Lepore if (OF_hasprop(child, "read-only"))
96a6bcabcdSIan Lepore flags |= FLASH_SLICES_FLAG_RO;
97a6bcabcdSIan Lepore
98db58d718SIan Lepore /* Fill slice entry data. */
994ffd4dfeSGrzegorz Bernacki slices[i].base = base;
1004ffd4dfeSGrzegorz Bernacki slices[i].size = size;
101a6bcabcdSIan Lepore slices[i].label = label;
102a6bcabcdSIan Lepore slices[i].flags = flags;
1034ffd4dfeSGrzegorz Bernacki i++;
1044ffd4dfeSGrzegorz Bernacki }
1054ffd4dfeSGrzegorz Bernacki
106a6bcabcdSIan Lepore *count = i;
1074ffd4dfeSGrzegorz Bernacki return (0);
1084ffd4dfeSGrzegorz Bernacki }
1094874af73SMarius Strobl
110a6bcabcdSIan Lepore static int
fill_slices(device_t dev,const char * provider __unused,struct flash_slice * slices,int * slices_num)111a6bcabcdSIan Lepore fill_slices(device_t dev, const char *provider __unused,
112a6bcabcdSIan Lepore struct flash_slice *slices, int *slices_num)
113a6bcabcdSIan Lepore {
114a6bcabcdSIan Lepore phandle_t child, node;
115a6bcabcdSIan Lepore
116a6bcabcdSIan Lepore /*
117a6bcabcdSIan Lepore * We assume the caller provides buffer for FLASH_SLICES_MAX_NUM
118a6bcabcdSIan Lepore * flash_slice structures.
119a6bcabcdSIan Lepore */
120a6bcabcdSIan Lepore if (slices == NULL) {
121a6bcabcdSIan Lepore *slices_num = 0;
122a6bcabcdSIan Lepore return (ENOMEM);
123a6bcabcdSIan Lepore }
124a6bcabcdSIan Lepore
125a6bcabcdSIan Lepore node = ofw_bus_get_node(dev);
126a6bcabcdSIan Lepore
127a6bcabcdSIan Lepore /*
128a6bcabcdSIan Lepore * If there is a child node whose compatible is "fixed-partitions" then
129a6bcabcdSIan Lepore * we have new-style data where all partitions are the children of that
130a6bcabcdSIan Lepore * node. Otherwise we have old-style data where all the children of the
131a6bcabcdSIan Lepore * device node are the partitions.
132a6bcabcdSIan Lepore */
133a6bcabcdSIan Lepore child = fdt_find_compatible(node, "fixed-partitions", false);
134a6bcabcdSIan Lepore if (child == 0)
135a6bcabcdSIan Lepore return fill_slices_from_node(node, slices, slices_num);
136a6bcabcdSIan Lepore else
137a6bcabcdSIan Lepore return fill_slices_from_node(child, slices, slices_num);
138a6bcabcdSIan Lepore }
139a6bcabcdSIan Lepore
1404874af73SMarius Strobl static void
fdt_slicer_init(void)1414874af73SMarius Strobl fdt_slicer_init(void)
1424874af73SMarius Strobl {
1434874af73SMarius Strobl
144db58d718SIan Lepore flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_NAND, false);
145db58d718SIan Lepore flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_CFI, false);
146db58d718SIan Lepore flash_register_slicer(fill_slices, FLASH_SLICES_TYPE_SPI, false);
1474874af73SMarius Strobl }
1484874af73SMarius Strobl
1494e462178SIan Lepore static void
fdt_slicer_cleanup(void)1504e462178SIan Lepore fdt_slicer_cleanup(void)
1514e462178SIan Lepore {
1524e462178SIan Lepore
1534e462178SIan Lepore flash_register_slicer(NULL, FLASH_SLICES_TYPE_NAND, true);
1544e462178SIan Lepore flash_register_slicer(NULL, FLASH_SLICES_TYPE_CFI, true);
1554e462178SIan Lepore flash_register_slicer(NULL, FLASH_SLICES_TYPE_SPI, true);
1564e462178SIan Lepore }
1574e462178SIan Lepore
1584874af73SMarius Strobl /*
1590ddc94d6SKyle Evans * Must be initialized after GEOM classes (SI_SUB_DRIVERS/SI_ORDER_SECOND),
1604874af73SMarius Strobl * i. e. after g_init() is called, due to the use of the GEOM topology_lock
1614874af73SMarius Strobl * in flash_register_slicer(). However, must be before SI_SUB_CONFIGURE.
1624874af73SMarius Strobl */
1630ddc94d6SKyle Evans SYSINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_THIRD, fdt_slicer_init, NULL);
1640ddc94d6SKyle Evans SYSUNINIT(fdt_slicer, SI_SUB_DRIVERS, SI_ORDER_THIRD, fdt_slicer_cleanup, NULL);
1654e462178SIan Lepore
1664e462178SIan Lepore static int
mod_handler(module_t mod,int type,void * data)1674e462178SIan Lepore mod_handler(module_t mod, int type, void *data)
1684e462178SIan Lepore {
1694e462178SIan Lepore
1704e462178SIan Lepore /*
1714e462178SIan Lepore * Nothing to do here: the SYSINIT/SYSUNINIT defined above run
1724e462178SIan Lepore * automatically at module load/unload time.
1734e462178SIan Lepore */
1744e462178SIan Lepore return (0);
1754e462178SIan Lepore }
1764e462178SIan Lepore
1774e462178SIan Lepore static moduledata_t fdt_slicer_mod = {
1784e462178SIan Lepore "fdt_slicer", mod_handler, NULL
1794e462178SIan Lepore };
1804e462178SIan Lepore
1810ddc94d6SKyle Evans DECLARE_MODULE(fdt_slicer, fdt_slicer_mod, SI_SUB_DRIVERS, SI_ORDER_THIRD);
182*2352336aSMark Johnston MODULE_DEPEND(fdt_slicer, geom_flashmap, 0, 0, 0);
1834e462178SIan Lepore MODULE_VERSION(fdt_slicer, 1);
184