2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2012, Broadcom Corporation
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"
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"
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))
40 struct hndsflash
*info
;
41 flashpart_t parts
[FLASH_MAX_PARTITIONS
];
44 static int sflashidx
= 0;
47 sflash_cfe_open(cfe_devctx_t
*ctx
)
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
;
62 buffer
->buf_retlen
= 0;
64 /* Check address range */
67 if ((offset
+ len
) > sflash
->info
->size
)
71 if ((bytes
= hndsflash_read(sflash
->info
, offset
, len
, buf
)) < 0) {
78 buffer
->buf_retlen
+= bytes
;
86 sflash_cfe_inpstat(cfe_devctx_t
*ctx
, iocb_inpstat_t
*inpstat
)
88 inpstat
->inp_status
= 1;
92 #ifdef CFE_FLASH_ERASE_FLASH_ENABLED
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
;
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 */
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
;
122 uint blocksize
= 0, mask
;
126 buffer
->buf_retlen
= 0;
128 /* Check address range */
132 if ((offset
+ len
) > sflash
->info
->size
)
133 return CFE_ERR_IOERR
;
135 blocksize
= sflash
->info
->blocksize
;
136 mask
= blocksize
- 1;
140 if (!(block
= KMALLOC(blocksize
, 0)))
141 return CFE_ERR_NOMEM
;
143 /* Backup and erase one block at a time */
146 cur
.buf_offset
= offset
& ~mask
;
147 cur
.buf_length
= blocksize
;
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
)))
155 if (cur
.buf_retlen
!= cur
.buf_length
) {
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
);
167 if ((ret
= hndsflash_erase(sflash
->info
, (uint
)cur
.buf_offset
)) < 0)
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) {
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
;
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
;
205 #ifdef CFE_FLASH_ERASE_FLASH_ENABLED
206 flash_range_t
*range
;
209 switch (buffer
->buf_ioctlcmd
) {
210 case IOCTL_FLASH_WRITE_ALL
:
211 sflash_cfe_write(ctx
, buffer
);
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
;
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
;
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
);
238 return CFE_ERR_INV_COMMAND
;
245 sflash_cfe_close(cfe_devctx_t
*ctx
)
250 static const cfe_devdisp_t sflash_cfe_dispatch
= {
262 sflash_do_parts(struct sflash_cfe
*sflash
, newflash_probe_t
*probe
)
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) {
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
;
295 sflash_cfe_probe(cfe_driver_t
*drv
,
296 unsigned long probe_a
, unsigned long probe_b
,
299 newflash_probe_t
*probe
= (newflash_probe_t
*)probe_ptr
;
300 struct sflash_cfe
*sflash
;
301 char type
[80], descr
[80], name
[80];
304 if (!(sflash
= (struct sflash_cfe
*)KMALLOC(sizeof(struct sflash_cfe
), 0)))
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");
318 /* Get the flash total size */
319 probe
->flash_size
= sflash
->info
->size
;
321 /* Set description */
322 switch (sflash
->info
->type
) {
325 sprintf(type
, "ST Compatible");
329 sprintf(type
, "Atmel");
332 sprintf(type
, "Unknown type %d", sflash
->info
->type
);
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
);
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
);
359 sprintf(name
, "%d", idx
);
360 cfe_attach_idx(drv
, sflashidx
, &sflash
->parts
[idx
], name
, descr
);
366 const cfe_driver_t sflashdrv
= {
370 &sflash_cfe_dispatch
,