GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / dev / dev_sflash.c
blob765693b09d9b5e5d47c7d991819b145f727d85d2
1 /*
2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2012, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: dev_sflash.c 354444 2012-08-31 03:47:39Z $
15 #include "lib_types.h"
16 #include "lib_malloc.h"
17 #include "lib_printf.h"
18 #include "lib_string.h"
19 #include "addrspace.h"
20 #include "cfe_iocb.h"
21 #include "cfe_device.h"
22 #include "cfe_ioctl.h"
23 #include "cfe_error.h"
24 #include "dev_newflash.h"
26 #include "bsp_config.h"
28 #include <typedefs.h>
29 #include <osl.h>
30 #include <bcmutils.h>
31 #include <siutils.h>
32 #include <hndsflash.h>
34 #define isaligned(x, y) (((x) % (y)) == 0)
35 #define min(a, b) ((a) < (b) ? (a) : (b))
36 #define max(a, b) ((a) > (b) ? (a) : (b))
38 struct sflash_cfe {
39 si_t *sih;
40 struct hndsflash *info;
41 flashpart_t parts[FLASH_MAX_PARTITIONS];
44 static int sflashidx = 0;
46 static int
47 sflash_cfe_open(cfe_devctx_t *ctx)
49 return 0;
52 static int
53 sflash_cfe_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
55 flashpart_t *part = (flashpart_t *)ctx->dev_softc;
56 struct sflash_cfe *sflash = (struct sflash_cfe *)part->fp_dev;
57 uint offset = (uint)buffer->buf_offset + part->fp_offset;
58 uint len = (uint)buffer->buf_length;
59 uchar *buf = (uchar *)buffer->buf_ptr;
60 int bytes, ret = 0;
62 buffer->buf_retlen = 0;
64 /* Check address range */
65 if (!len)
66 return 0;
67 if ((offset + len) > sflash->info->size)
68 return CFE_ERR_IOERR;
70 while (len) {
71 if ((bytes = hndsflash_read(sflash->info, offset, len, buf)) < 0) {
72 ret = bytes;
73 goto done;
75 offset += bytes;
76 len -= bytes;
77 buf += bytes;
78 buffer->buf_retlen += bytes;
81 done:
82 return ret;
85 static int
86 sflash_cfe_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
88 inpstat->inp_status = 1;
89 return 0;
92 #ifdef CFE_FLASH_ERASE_FLASH_ENABLED
93 static int
94 sflash_cfe_erase_range(cfe_devctx_t *ctx, flash_range_t *range)
96 flashpart_t *part = (flashpart_t *)ctx->dev_softc;
97 struct sflash_cfe *sflash = (struct sflash_cfe *)part->fp_dev;
98 int len, offset;
100 offset = part->fp_offset + range->range_base;
101 len = range->range_length;
103 if ((offset < part->fp_offset) ||
104 ((offset + len) > (part->fp_offset + part->fp_size))) {
105 printf("!! offset 0x%x, len=0x%x over partition boundary: start: 0x%x, end: 0x%x",
106 offset, len, part->fp_offset, part->fp_offset + part->fp_size);
107 return CFE_ERR_INV_PARAM;
109 return hndsflash_commit(sflash->info, (uint)offset, (uint)len, NULL);
111 #endif /* CFE_FLASH_ERASE_FLASH_ENABLED */
113 static int
114 sflash_cfe_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
116 flashpart_t *part = (flashpart_t *)ctx->dev_softc;
117 struct sflash_cfe *sflash = (struct sflash_cfe *)part->fp_dev;
118 uint offset = (uint)buffer->buf_offset + part->fp_offset;
119 uint len = (uint)buffer->buf_length;
120 uchar *buf = (uchar *)buffer->buf_ptr;
121 uchar *block = NULL;
122 uint blocksize = 0, mask;
123 iocb_buffer_t cur;
124 int bytes, ret = 0;
126 buffer->buf_retlen = 0;
128 /* Check address range */
129 if (!len)
130 return 0;
132 if ((offset + len) > sflash->info->size)
133 return CFE_ERR_IOERR;
135 blocksize = sflash->info->blocksize;
136 mask = blocksize - 1;
138 if (block)
139 KFREE(block);
140 if (!(block = KMALLOC(blocksize, 0)))
141 return CFE_ERR_NOMEM;
143 /* Backup and erase one block at a time */
144 while (len) {
145 /* Align offset */
146 cur.buf_offset = offset & ~mask;
147 cur.buf_length = blocksize;
148 cur.buf_ptr = block;
150 /* Copy existing data into holding block if necessary */
151 if (!isaligned(offset, blocksize) || (len < blocksize)) {
152 cur.buf_offset -= part->fp_offset;
153 if ((ret = sflash_cfe_read(ctx, &cur)))
154 goto done;
155 if (cur.buf_retlen != cur.buf_length) {
156 ret = CFE_ERR_IOERR;
157 goto done;
159 cur.buf_offset += part->fp_offset;
162 /* Copy input data into holding block */
163 cur.buf_retlen = min(len, blocksize - (offset & mask));
164 memcpy(cur.buf_ptr + (offset & mask), buf, cur.buf_retlen);
166 /* Erase block */
167 if ((ret = hndsflash_erase(sflash->info, (uint)cur.buf_offset)) < 0)
168 goto done;
169 while (hndsflash_poll(sflash->info, (uint)cur.buf_offset));
171 /* Write holding block */
172 while (cur.buf_length) {
173 if ((bytes = hndsflash_write(sflash->info,
174 (uint)cur.buf_offset,
175 (uint)cur.buf_length,
176 (uchar *)cur.buf_ptr)) < 0) {
177 ret = bytes;
178 goto done;
180 while (hndsflash_poll(sflash->info, (uint)cur.buf_offset));
182 cur.buf_offset += bytes;
183 cur.buf_length -= bytes;
184 cur.buf_ptr += bytes;
187 offset += cur.buf_retlen;
188 len -= cur.buf_retlen;
189 buf += cur.buf_retlen;
190 buffer->buf_retlen += cur.buf_retlen;
193 done:
194 if (block)
195 KFREE(block);
196 return ret;
199 static int
200 sflash_cfe_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
202 flashpart_t *part = (flashpart_t *)ctx->dev_softc;
203 struct sflash_cfe *sflash = (struct sflash_cfe *)part->fp_dev;
204 flash_info_t *info;
205 #ifdef CFE_FLASH_ERASE_FLASH_ENABLED
206 flash_range_t *range;
207 #endif
209 switch (buffer->buf_ioctlcmd) {
210 case IOCTL_FLASH_WRITE_ALL:
211 sflash_cfe_write(ctx, buffer);
212 break;
213 case IOCTL_FLASH_GETINFO:
214 info = (flash_info_t *)buffer->buf_ptr;
215 info->flash_base = 0;
216 info->flash_size = sflash->info->size;
217 info->flash_type = sflash->info->type;
218 info->flash_flags = FLASH_FLAG_NOERASE;
219 break;
220 #ifdef FLASH_PARTITION_FILL_ENABLED
221 case IOCTL_FLASH_PARTITION_INFO:
222 info = (flash_info_t *)buffer->buf_ptr;
223 info->flash_base = part->fp_offset;
224 info->flash_size = part->fp_size;
225 break;
226 #endif
227 #ifdef CFE_FLASH_ERASE_FLASH_ENABLED
228 case IOCTL_FLASH_ERASE_RANGE:
229 range = (flash_range_t *)buffer->buf_ptr;
230 /* View the base 0 and range 0 as erase all parition */
231 if (range->range_base == 0 && range->range_length == 0) {
232 range->range_length = part->fp_size;
234 sflash_cfe_erase_range(ctx, range);
235 break;
236 #endif
237 default:
238 return CFE_ERR_INV_COMMAND;
241 return 0;
244 static int
245 sflash_cfe_close(cfe_devctx_t *ctx)
247 return 0;
250 static const cfe_devdisp_t sflash_cfe_dispatch = {
251 sflash_cfe_open,
252 sflash_cfe_read,
253 sflash_cfe_inpstat,
254 sflash_cfe_write,
255 sflash_cfe_ioctl,
256 sflash_cfe_close,
257 NULL,
258 NULL
261 static void
262 sflash_do_parts(struct sflash_cfe *sflash, newflash_probe_t *probe)
264 int idx;
265 int middlepart = -1;
266 int lobound = 0;
267 flashpart_t *parts = sflash->parts;
268 int hibound = sflash->info->size;
270 for (idx = 0; idx < probe->flash_nparts; idx++) {
271 if (probe->flash_parts[idx].fp_size == 0) {
272 middlepart = idx;
273 break;
275 parts[idx].fp_offset = lobound;
276 parts[idx].fp_size = probe->flash_parts[idx].fp_size;
277 lobound += probe->flash_parts[idx].fp_size;
280 if (idx != probe->flash_nparts) {
281 for (idx = probe->flash_nparts - 1; idx > middlepart; idx--) {
282 parts[idx].fp_size = probe->flash_parts[idx].fp_size;
283 hibound -= probe->flash_parts[idx].fp_size;
284 parts[idx].fp_offset = hibound;
288 if (middlepart != -1) {
289 parts[middlepart].fp_offset = lobound;
290 parts[middlepart].fp_size = hibound - lobound;
294 static void
295 sflash_cfe_probe(cfe_driver_t *drv,
296 unsigned long probe_a, unsigned long probe_b,
297 void *probe_ptr)
299 newflash_probe_t *probe = (newflash_probe_t *)probe_ptr;
300 struct sflash_cfe *sflash;
301 char type[80], descr[80], name[80];
302 int idx;
304 if (!(sflash = (struct sflash_cfe *)KMALLOC(sizeof(struct sflash_cfe), 0)))
305 return;
306 memset(sflash, 0, sizeof(struct sflash_cfe));
308 /* Attach to the backplane and map to chipc */
309 sflash->sih = si_kattach(SI_OSH);
311 /* Initialize serial flash access */
312 if (!(sflash->info = hndsflash_init(sflash->sih))) {
313 xprintf("sflash: found no supported devices\n");
314 KFREE(sflash);
315 return;
318 /* Get the flash total size */
319 probe->flash_size = sflash->info->size;
321 /* Set description */
322 switch (sflash->info->type) {
323 case SFLASH_ST:
324 case QSPIFLASH_ST:
325 sprintf(type, "ST Compatible");
326 break;
327 case SFLASH_AT:
328 case QSPIFLASH_AT:
329 sprintf(type, "Atmel");
330 break;
331 default:
332 sprintf(type, "Unknown type %d", sflash->info->type);
333 break;
336 if (probe->flash_nparts == 0) {
337 /* Just instantiate one device */
338 sflash->parts[0].fp_dev = (flashdev_t *)sflash;
339 sflash->parts[0].fp_offset = 0;
340 sflash->parts[0].fp_size = sflash->info->size;
341 sprintf(descr, "%s %s size %uKB",
342 type, drv->drv_description,
343 (sflash->info->size + 1023) / 1024);
344 cfe_attach(drv, &sflash->parts[0], NULL, descr);
345 } else {
346 /* Partition flash into chunks */
347 sflash_do_parts(sflash, probe);
349 /* Instantiate devices for each piece */
350 for (idx = 0; idx < probe->flash_nparts; idx++) {
351 sprintf(descr, "%s %s offset %08X size %uKB",
352 type, drv->drv_description,
353 sflash->parts[idx].fp_offset,
354 (sflash->parts[idx].fp_size + 1023) / 1024);
355 sflash->parts[idx].fp_dev = (flashdev_t *) sflash;
356 if (probe->flash_parts[idx].fp_name)
357 strcpy(name, probe->flash_parts[idx].fp_name);
358 else
359 sprintf(name, "%d", idx);
360 cfe_attach_idx(drv, sflashidx, &sflash->parts[idx], name, descr);
362 sflashidx++;
366 const cfe_driver_t sflashdrv = {
367 "Serial flash",
368 "flash",
369 CFE_DEV_FLASH,
370 &sflash_cfe_dispatch,
371 sflash_cfe_probe