]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/cores/chipc/chipc_slicer.c
Import mandoc 1.14.4
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / cores / chipc / chipc_slicer.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15  *    redistribution must be conditioned upon including a substantially
16  *    similar Disclaimer requirement for further binary redistribution.
17  *
18  * NO WARRANTY
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGES.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * Slicer is required to split firmware images into pieces.
37  * The first supported FW is TRX-based used by Asus routers
38  * TODO: add NetGear FW (CHK)
39  */
40
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/errno.h>
45 #include <sys/rman.h>
46 #include <sys/bus.h>
47 #include <sys/systm.h>
48 #include <sys/slicer.h>
49
50 #include <machine/bus.h>
51
52 #include <dev/bhnd/bhnd_debug.h>
53
54 #include "chipc_slicer.h"
55
56 #include <dev/cfi/cfi_var.h>
57 #include "chipc_spi.h"
58
59 static int      chipc_slicer_walk(device_t dev, struct resource *res,
60                     struct flash_slice *slices, int *nslices);
61
62 void
63 chipc_register_slicer(chipc_flash flash_type)
64 {
65         switch (flash_type) {
66         case CHIPC_SFLASH_AT:
67         case CHIPC_SFLASH_ST:
68                 flash_register_slicer(chipc_slicer_spi, FLASH_SLICES_TYPE_SPI,
69                    TRUE);
70                 break;
71         case CHIPC_PFLASH_CFI:
72                 flash_register_slicer(chipc_slicer_cfi, FLASH_SLICES_TYPE_CFI,
73                    TRUE);
74                 break;
75         default:
76                 /* Unsupported */
77                 break;
78         }
79 }
80
81 int
82 chipc_slicer_cfi(device_t dev, const char *provider __unused,
83     struct flash_slice *slices, int *nslices)
84 {
85         struct cfi_softc        *sc;
86         device_t                 parent;
87
88         /* must be CFI flash */
89         if (device_get_devclass(dev) != devclass_find("cfi"))
90                 return (ENXIO);
91
92         /* must be attached to chipc */
93         if ((parent = device_get_parent(dev)) == NULL) {
94                 BHND_ERROR_DEV(dev, "no found ChipCommon device");
95                 return (ENXIO);
96         }
97
98         if (device_get_devclass(parent) != devclass_find("bhnd_chipc")) {
99                 BHND_ERROR_DEV(dev, "no found ChipCommon device");
100                 return (ENXIO);
101         }
102
103         sc = device_get_softc(dev);
104         return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
105 }
106
107 int
108 chipc_slicer_spi(device_t dev, const char *provider __unused,
109     struct flash_slice *slices, int *nslices)
110 {
111         struct chipc_spi_softc  *sc;
112         device_t                 chipc, spi, spibus;
113
114         BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev));
115
116         /* must be SPI-attached flash */
117         spibus = device_get_parent(dev);
118         if (spibus == NULL) {
119                 BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device");
120                 return (ENXIO);
121         }
122
123         spi = device_get_parent(spibus);
124         if (spi == NULL) {
125                 BHND_ERROR_DEV(dev, "no found ChipCommon SPI device");
126                 return (ENXIO);
127         }
128
129         chipc = device_get_parent(spi);
130         if (device_get_devclass(chipc) != devclass_find("bhnd_chipc")) {
131                 BHND_ERROR_DEV(dev, "no found ChipCommon device");
132                 return (ENXIO);
133         }
134
135         sc = device_get_softc(spi);
136         return (chipc_slicer_walk(dev, sc->sc_flash_res, slices, nslices));
137 }
138
139 /*
140  * Main processing part
141  */
142 static int
143 chipc_slicer_walk(device_t dev, struct resource *res,
144     struct flash_slice *slices, int *nslices)
145 {
146         uint32_t         fw_len;
147         uint32_t         fs_ofs;
148         uint32_t         val;
149         uint32_t         ofs_trx;
150         int              flash_size;
151
152         *nslices = 0;
153
154         flash_size = rman_get_size(res);
155         ofs_trx = flash_size;
156
157         BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...",
158             flash_size);
159
160         /* Find FW header in flash memory with step=128Kb (0x1000) */
161         for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){
162                 val = bus_read_4(res, ofs);
163                 switch (val) {
164                 case TRX_MAGIC:
165                         /* check for second TRX */
166                         if (ofs_trx < ofs) {
167                                 BHND_TRACE_DEV(dev, "stop on 2nd TRX: %x", ofs);
168                                 break;
169                         }
170
171                         BHND_TRACE("TRX found: %x", ofs);
172                         ofs_trx = ofs;
173                         /* read last offset of TRX header */
174                         fs_ofs = bus_read_4(res, ofs + 24);
175                         BHND_TRACE("FS offset: %x", fs_ofs);
176
177                         /*
178                          * GEOM IO will panic if offset is not aligned
179                          * on sector size, i.e. 512 bytes
180                          */
181                         if (fs_ofs % 0x200 != 0) {
182                                 BHND_WARN("WARNING! filesystem offset should be"
183                                     " aligned on sector size (%d bytes)", 0x200);
184                                 BHND_WARN("ignoring TRX firmware image");
185                                 break;
186                         }
187
188                         slices[*nslices].base = ofs + fs_ofs;
189                         //XXX: fully sized? any other partition?
190                         fw_len = bus_read_4(res, ofs + 4);
191                         slices[*nslices].size = fw_len - fs_ofs;
192                         slices[*nslices].label = "rootfs";
193                         *nslices += 1;
194                         break;
195                 case CFE_MAGIC:
196                         BHND_TRACE("CFE found: %x", ofs);
197                         break;
198                 case NVRAM_MAGIC:
199                         BHND_TRACE("NVRAM found: %x", ofs);
200                         break;
201                 default:
202                         break;
203                 }
204         }
205
206         BHND_TRACE("slicer: done");
207         return (0);
208 }