1/* 2 * Broadcom SiliconBackplane chipcommon serial flash interface 3 * 4 * Copyright 2006, 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. 11 * 12 * $Id: dev_sflash.c,v 1.1.1.1 2008/10/15 03:25:53 james26_jang Exp $ 13 */ 14 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" 25 26#include "bsp_config.h" 27 28#include <typedefs.h> 29#include <osl.h> 30#include <bcmutils.h> 31#include <sbutils.h> 32#include <sflash.h> 33 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)) 37 38struct sflash_cfe { 39 sb_t *sbh; 40 chipcregs_t *cc; 41 struct sflash *info; 42 flashpart_t parts[FLASH_MAX_PARTITIONS]; 43}; 44 45static int sflashidx = 0; 46 47static int 48sflash_cfe_open(cfe_devctx_t *ctx) 49{ 50 return 0; 51} 52 53static int 54sflash_cfe_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 55{ 56 flashpart_t *part = (flashpart_t *) ctx->dev_softc; 57 struct sflash_cfe *sflash = (struct sflash_cfe *) part->fp_dev; 58 uint offset = (uint) buffer->buf_offset + part->fp_offset; 59 uint len = (uint) buffer->buf_length; 60 uchar *buf = (uchar *) buffer->buf_ptr; 61 int bytes, ret = 0; 62 63 buffer->buf_retlen = 0; 64 65 /* Check address range */ 66 if (!len) 67 return 0; 68 if ((offset + len) > sflash->info->size) 69 return CFE_ERR_IOERR; 70 71 while (len) { 72 if ((bytes = sflash_read(sflash->sbh, sflash->cc, offset, len, buf)) < 0) { 73 ret = bytes; 74 goto done; 75 } 76 offset += bytes; 77 len -= bytes; 78 buf += bytes; 79 buffer->buf_retlen += bytes; 80 } 81 82 done: 83 return ret; 84} 85 86static int 87sflash_cfe_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) 88{ 89 inpstat->inp_status = 1; 90 return 0; 91} 92 93static int 94sflash_cfe_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 95{ 96 flashpart_t *part = (flashpart_t *) ctx->dev_softc; 97 struct sflash_cfe *sflash = (struct sflash_cfe *) part->fp_dev; 98 uint offset = (uint) buffer->buf_offset + part->fp_offset; 99 uint len = (uint) buffer->buf_length; 100 uchar *buf = (uchar *) buffer->buf_ptr; 101 uchar *block = NULL; 102 uint blocksize = 0, mask; 103 iocb_buffer_t cur; 104 int bytes, ret = 0; 105 106 buffer->buf_retlen = 0; 107 108 /* Check address range */ 109 if (!len) 110 return 0; 111 112 if ((offset + len) > sflash->info->size) 113 return CFE_ERR_IOERR; 114 115 blocksize = sflash->info->blocksize; 116 mask = blocksize - 1; 117 118 if (block) 119 KFREE(block); 120 if (!(block = KMALLOC(blocksize, 0))) 121 return CFE_ERR_NOMEM; 122 123 /* Backup and erase one block at a time */ 124 while (len) { 125 /* Align offset */ 126 cur.buf_offset = offset & ~mask; 127 cur.buf_length = blocksize; 128 cur.buf_ptr = block; 129 130 /* Copy existing data into holding block if necessary */ 131 if (!isaligned(offset, blocksize) || (len < blocksize)) { 132 cur.buf_offset -= part->fp_offset; 133 if ((ret = sflash_cfe_read(ctx, &cur))) 134 goto done; 135 if (cur.buf_retlen != cur.buf_length) { 136 ret = CFE_ERR_IOERR; 137 goto done; 138 } 139 cur.buf_offset += part->fp_offset; 140 } 141 142 /* Copy input data into holding block */ 143 cur.buf_retlen = min(len, blocksize - (offset & mask)); 144 memcpy(cur.buf_ptr + (offset & mask), buf, cur.buf_retlen); 145 146 /* Erase block */ 147 if ((ret = sflash_erase(sflash->sbh, sflash->cc, (uint) cur.buf_offset)) < 0) 148 goto done; 149 while (sflash_poll(sflash->sbh, sflash->cc, (uint) cur.buf_offset)); 150 151 /* Write holding block */ 152 while (cur.buf_length) { 153 if ((bytes = sflash_write(sflash->sbh, sflash->cc, 154 (uint) cur.buf_offset, 155 (uint) cur.buf_length, 156 (uchar *) cur.buf_ptr)) < 0) { 157 ret = bytes; 158 goto done; 159 } 160 while (sflash_poll(sflash->sbh, sflash->cc, (uint) cur.buf_offset)); 161 162 cur.buf_offset += bytes; 163 cur.buf_length -= bytes; 164 cur.buf_ptr += bytes; 165 } 166 167 offset += cur.buf_retlen; 168 len -= cur.buf_retlen; 169 buf += cur.buf_retlen; 170 buffer->buf_retlen += cur.buf_retlen; 171 } 172 173 done: 174 if (block) 175 KFREE(block); 176 return ret; 177} 178 179static int 180sflash_cfe_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 181{ 182 flashpart_t *part = (flashpart_t *) ctx->dev_softc; 183 struct sflash_cfe *sflash = (struct sflash_cfe *) part->fp_dev; 184 flash_info_t *info; 185 186 switch (buffer->buf_ioctlcmd) { 187 case IOCTL_FLASH_WRITE_ALL: 188 sflash_cfe_write(ctx, buffer); 189 break; 190 case IOCTL_FLASH_GETINFO: 191 info = (flash_info_t *) buffer->buf_ptr; 192 info->flash_base = 0; 193 info->flash_size = sflash->info->size; 194 info->flash_type = sflash->info->type; 195 info->flash_flags = FLASH_FLAG_NOERASE; 196 break; 197 default: 198 return CFE_ERR_INV_COMMAND; 199 } 200 201 return 0; 202} 203 204static int 205sflash_cfe_close(cfe_devctx_t *ctx) 206{ 207 return 0; 208} 209 210static const cfe_devdisp_t sflash_cfe_dispatch = { 211 sflash_cfe_open, 212 sflash_cfe_read, 213 sflash_cfe_inpstat, 214 sflash_cfe_write, 215 sflash_cfe_ioctl, 216 sflash_cfe_close, 217 NULL, 218 NULL 219}; 220 221static void 222sflash_do_parts(struct sflash_cfe *sflash, newflash_probe_t *probe) 223{ 224 int idx; 225 int middlepart = -1; 226 int lobound = 0; 227 flashpart_t *parts = sflash->parts; 228 int hibound = sflash->info->size; 229 230 for (idx = 0; idx < probe->flash_nparts; idx++) { 231 if (probe->flash_parts[idx].fp_size == 0) { 232 middlepart = idx; 233 break; 234 } 235 parts[idx].fp_offset = lobound; 236 parts[idx].fp_size = probe->flash_parts[idx].fp_size; 237 lobound += probe->flash_parts[idx].fp_size; 238 } 239 240 if (idx != probe->flash_nparts) { 241 for (idx = probe->flash_nparts - 1; idx > middlepart; idx--) { 242 parts[idx].fp_size = probe->flash_parts[idx].fp_size; 243 hibound -= probe->flash_parts[idx].fp_size; 244 parts[idx].fp_offset = hibound; 245 } 246 } 247 248 if (middlepart != -1) { 249 parts[middlepart].fp_offset = lobound; 250 parts[middlepart].fp_size = hibound - lobound; 251 } 252} 253 254static void 255sflash_cfe_probe(cfe_driver_t *drv, 256 unsigned long probe_a, unsigned long probe_b, 257 void *probe_ptr) 258{ 259 newflash_probe_t *probe = (newflash_probe_t *) probe_ptr; 260 struct sflash_cfe *sflash; 261 char type[80], descr[80], name[80]; 262 int idx; 263 264 if (!(sflash = (struct sflash_cfe *) KMALLOC(sizeof(struct sflash_cfe), 0))) 265 return; 266 memset(sflash, 0, sizeof(struct sflash_cfe)); 267 268 /* Attach to the backplane and map to chipc */ 269 sflash->sbh = sb_kattach(SB_OSH); 270 271 sflash->cc = (chipcregs_t *)probe->flash_cmdset; 272 273 /* Initialize serial flash access */ 274 if (!(sflash->info = sflash_init(sflash->sbh, sflash->cc))) { 275 xprintf("sflash: found no supported devices\n"); 276 KFREE(sflash); 277 return; 278 } 279 280 /* Set description */ 281 switch (sflash->info->type) { 282 case SFLASH_ST: 283 sprintf(type, "ST"); 284 break; 285 case SFLASH_AT: 286 sprintf(type, "Atmel"); 287 break; 288 default: 289 sprintf(type, "Unknown type %d", sflash->info->type); 290 break; 291 } 292 293 if (probe->flash_nparts == 0) { 294 /* Just instantiate one device */ 295 sflash->parts[0].fp_dev = (flashdev_t *) sflash; 296 sflash->parts[0].fp_offset = 0; 297 sflash->parts[0].fp_size = sflash->info->size; 298 sprintf(descr, "%s %s size %uKB", 299 type, drv->drv_description, 300 (sflash->info->size + 1023) / 1024); 301 cfe_attach(drv, &sflash->parts[0], NULL, descr); 302 } else { 303 /* Partition flash into chunks */ 304 sflash_do_parts(sflash, probe); 305 306 /* Instantiate devices for each piece */ 307 for (idx = 0; idx < probe->flash_nparts; idx++) { 308 sprintf(descr, "%s %s offset %08X size %uKB", 309 type, drv->drv_description, 310 sflash->parts[idx].fp_offset, 311 (sflash->parts[idx].fp_size + 1023) / 1024); 312 sflash->parts[idx].fp_dev = (flashdev_t *) sflash; 313 if (probe->flash_parts[idx].fp_name) 314 strcpy(name, probe->flash_parts[idx].fp_name); 315 else 316 sprintf(name, "%d", idx); 317 cfe_attach_idx(drv, sflashidx, &sflash->parts[idx], name, descr); 318 } 319 } 320 321 sflashidx++; 322} 323 324const cfe_driver_t sflashdrv = { 325 "Serial flash", 326 "flash", 327 CFE_DEV_FLASH, 328 &sflash_cfe_dispatch, 329 sflash_cfe_probe 330}; 331