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