/*
* Broadcom SiliconBackplane chipcommon serial flash interface
*
- * Copyright 2006, Broadcom Corporation
+ * Copyright 2007, Broadcom Corporation
* All Rights Reserved.
*
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
*
- * $Id: sflash.c,v 1.1.1.13 2006/02/27 03:43:16 honor Exp $
+ * $Id$
*/
-#include <osl.h>
#include <typedefs.h>
+#include <osl.h>
+#include "include/bcmutils.h"
+#include <sbutils.h>
#include <sbconfig.h>
#include <sbchipc.h>
-#include <mipsinc.h>
-#include <bcmutils.h>
#include <bcmdevs.h>
#include <sflash.h>
/* Issue a serial flash command */
static INLINE void
-sflash_cmd(chipcregs_t *cc, uint opcode)
+sflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode)
{
- W_REG(NULL, &cc->flashcontrol, SFLASH_START | opcode);
- while (R_REG(NULL, &cc->flashcontrol) & SFLASH_BUSY);
+ W_REG(osh, &cc->flashcontrol, SFLASH_START | opcode);
+ while (R_REG(osh, &cc->flashcontrol) & SFLASH_BUSY);
}
/* Initialize serial flash access */
struct sflash *
-sflash_init(chipcregs_t *cc)
+sflash_init(sb_t *sbh, chipcregs_t *cc)
{
uint32 id, id2;
+ osl_t *osh;
+
+ ASSERT(sbh);
+
+ osh = sb_osh(sbh);
bzero(&sflash, sizeof(sflash));
- sflash.type = R_REG(NULL, &cc->capabilities) & CAP_FLASH_MASK;
+ sflash.type = sbh->cccaps & CC_CAP_FLASH_MASK;
switch (sflash.type) {
case SFLASH_ST:
/* Probe for ST chips */
- sflash_cmd(cc, SFLASH_ST_DP);
- sflash_cmd(cc, SFLASH_ST_RES);
- id = R_REG(NULL, &cc->flashdata);
+ sflash_cmd(osh, cc, SFLASH_ST_DP);
+ sflash_cmd(osh, cc, SFLASH_ST_RES);
+ id = R_REG(osh, &cc->flashdata);
switch (id) {
case 0x11:
/* ST M25P20 2 Mbit Serial Flash */
sflash.numblocks = 128;
break;
case 0xbf:
- W_REG(NULL, &cc->flashaddress, 1);
- sflash_cmd(cc, SFLASH_ST_RES);
- id2 = R_REG(NULL, &cc->flashdata);
+ W_REG(osh, &cc->flashaddress, 1);
+ sflash_cmd(osh, cc, SFLASH_ST_RES);
+ id2 = R_REG(osh, &cc->flashdata);
if (id2 == 0x44) {
/* SST M25VF80 4 Mbit Serial Flash */
sflash.blocksize = 64 * 1024;
case SFLASH_AT:
/* Probe for Atmel chips */
- sflash_cmd(cc, SFLASH_AT_STATUS);
- id = R_REG(NULL, &cc->flashdata) & 0x3c;
+ sflash_cmd(osh, cc, SFLASH_AT_STATUS);
+ id = R_REG(osh, &cc->flashdata) & 0x3c;
switch (id) {
case 0xc:
/* Atmel AT45DB011 1Mbit Serial Flash */
/* Read len bytes starting at offset into buf. Returns number of bytes read. */
int
-sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
+sflash_read(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, uchar *buf)
{
- int cnt;
- uint32 *from, *to;
+ uint8 *from, *to;
+ int cnt, i;
+ osl_t *osh;
+
+ ASSERT(sbh);
if (!len)
return 0;
if ((len >= 4) && (offset & 3))
cnt = 4 - (offset & 3);
- else if ((len >= 4) && ((uint32)buf & 3))
- cnt = 4 - ((uint32)buf & 3);
+ else if ((len >= 4) && ((uintptr)buf & 3))
+ cnt = 4 - ((uintptr)buf & 3);
else
cnt = len;
- from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
- to = (uint32 *)buf;
+ osh = sb_osh(sbh);
+
+ from = (uint8 *)(uintptr)OSL_UNCACHED(SB_FLASH2 + offset);
+ to = (uint8 *)buf;
if (cnt < 4) {
- bcopy(from, to, cnt);
+ for (i = 0; i < cnt; i ++) {
+ *to = R_REG(osh, from);
+ from ++;
+ to ++;
+ }
return cnt;
}
while (cnt >= 4) {
- *to++ = *from++;
+ *(uint32 *)to = R_REG(osh, (uint32 *)from);
+ from += 4;
+ to += 4;
cnt -= 4;
}
/* Poll for command completion. Returns zero when complete. */
int
-sflash_poll(chipcregs_t *cc, uint offset)
+sflash_poll(sb_t *sbh, chipcregs_t *cc, uint offset)
{
+ osl_t *osh;
+
+ ASSERT(sbh);
+
+ osh = sb_osh(sbh);
+
if (offset >= sflash.size)
return -22;
switch (sflash.type) {
case SFLASH_ST:
/* Check for ST Write In Progress bit */
- sflash_cmd(cc, SFLASH_ST_RDSR);
- return R_REG(NULL, &cc->flashdata) & SFLASH_ST_WIP;
+ sflash_cmd(osh, cc, SFLASH_ST_RDSR);
+ return R_REG(osh, &cc->flashdata) & SFLASH_ST_WIP;
case SFLASH_AT:
/* Check for Atmel Ready bit */
- sflash_cmd(cc, SFLASH_AT_STATUS);
- return !(R_REG(NULL, &cc->flashdata) & SFLASH_AT_READY);
+ sflash_cmd(osh, cc, SFLASH_AT_STATUS);
+ return !(R_REG(osh, &cc->flashdata) & SFLASH_AT_READY);
}
return 0;
* written. Caller should poll for completion.
*/
int
-sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
+sflash_write(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf)
{
struct sflash *sfl;
int ret = 0;
bool is4712b0;
uint32 page, byte, mask;
+ osl_t *osh;
+
+ ASSERT(sbh);
+
+ osh = sb_osh(sbh);
if (!len)
return 0;
sfl = &sflash;
switch (sfl->type) {
case SFLASH_ST:
- mask = R_REG(NULL, &cc->chipid);
- is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) &&
- ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
+ is4712b0 = (sbh->chip == BCM4712_CHIP_ID) && (sbh->chiprev == 3);
/* Enable writes */
- sflash_cmd(cc, SFLASH_ST_WREN);
+ sflash_cmd(osh, cc, SFLASH_ST_WREN);
if (is4712b0) {
mask = 1 << 14;
- W_REG(NULL, &cc->flashaddress, offset);
- W_REG(NULL, &cc->flashdata, *buf++);
+ W_REG(osh, &cc->flashaddress, offset);
+ W_REG(osh, &cc->flashdata, *buf++);
/* Set chip select */
- OR_REG(NULL, &cc->gpioout, mask);
+ OR_REG(osh, &cc->gpioout, mask);
/* Issue a page program with the first byte */
- sflash_cmd(cc, SFLASH_ST_PP);
+ sflash_cmd(osh, cc, SFLASH_ST_PP);
ret = 1;
offset++;
len--;
while (len > 0) {
if ((offset & 255) == 0) {
/* Page boundary, drop cs and return */
- AND_REG(NULL, &cc->gpioout, ~mask);
- if (!sflash_poll(cc, offset)) {
+ AND_REG(osh, &cc->gpioout, ~mask);
+ if (!sflash_poll(sbh, cc, offset)) {
/* Flash rejected command */
return -11;
}
return ret;
} else {
/* Write single byte */
- sflash_cmd(cc, *buf++);
+ sflash_cmd(osh, cc, *buf++);
}
ret++;
offset++;
/* All done, drop cs if needed */
if ((offset & 255) != 1) {
/* Drop cs */
- AND_REG(NULL, &cc->gpioout, ~mask);
- if (!sflash_poll(cc, offset)) {
+ AND_REG(osh, &cc->gpioout, ~mask);
+ if (!sflash_poll(sbh, cc, offset)) {
+ /* Flash rejected command */
+ return -12;
+ }
+ }
+ } else if ( (sbh->ccrev >= 20) && (len != 1) ) {
+ //} else if ( sbh->ccrev >= 20 ) { /* foxconn modified by EricHuang, 05/24/2007 */
+ W_REG(NULL, &cc->flashaddress, offset);
+ W_REG(NULL, &cc->flashdata, *buf++);
+ /* Issue a page program with CSA bit set */
+ sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP);
+ ret = 1;
+ offset++;
+ len--;
+ while (len > 0) {
+ if ((offset & 255) == 0) {
+ /* Page boundary, poll droping cs and return */
+ W_REG(NULL, &cc->flashcontrol, 0);
+ /* wklin added start, 06/08/2007 */
+ W_REG(NULL, &cc->flashcontrol, 0);
+ OSL_DELAY(1);
+ /* wklin added end, 06/08/2007 */
+ /* wklin rmeoved start, 06/08/2007 */
+#if 0
+ if (!sflash_poll(sbh, cc, offset)) {
+ /* Flash rejected command */
+ return -11;
+ }
+#endif
+ /* wklin removed end, 06/08/2007 */
+ return ret;
+ } else {
+ /* Write single byte */
+ sflash_cmd(osh, cc, SFLASH_ST_CSA | *buf++);
+ }
+ ret++;
+ offset++;
+ len--;
+ }
+ /* All done, drop cs if needed */
+ if ((offset & 255) != 1) {
+ /* Drop cs, poll */
+ W_REG(NULL, &cc->flashcontrol, 0);
+ /* wklin added start, 06/08/2007 */
+ W_REG(NULL, &cc->flashcontrol, 0);
+ OSL_DELAY(1);
+ /* wklin added end, 06/08/2007 */
+ /* wklin removed start, 06/08/2007 */
+#if 0
+ if (!sflash_poll(sbh, cc, offset)) {
/* Flash rejected command */
return -12;
}
+#endif
+ /* wklin removed end, 06/08/2007 */
}
} else {
ret = 1;
- W_REG(NULL, &cc->flashaddress, offset);
- W_REG(NULL, &cc->flashdata, *buf);
+ W_REG(osh, &cc->flashaddress, offset);
+ W_REG(osh, &cc->flashdata, *buf);
/* Page program */
- sflash_cmd(cc, SFLASH_ST_PP);
+ sflash_cmd(osh, cc, SFLASH_ST_PP);
}
break;
case SFLASH_AT:
byte = offset & mask;
/* Read main memory page into buffer 1 */
if (byte || (len < sfl->blocksize)) {
- W_REG(NULL, &cc->flashaddress, page);
- sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
+ W_REG(osh, &cc->flashaddress, page);
+ sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD);
/* 250 us for AT45DB321B */
- SPINWAIT(sflash_poll(cc, offset), 1000);
- ASSERT(!sflash_poll(cc, offset));
+ SPINWAIT(sflash_poll(sbh, cc, offset), 1000);
+ ASSERT(!sflash_poll(sbh, cc, offset));
}
/* Write into buffer 1 */
for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
- W_REG(NULL, &cc->flashaddress, byte++);
- W_REG(NULL, &cc->flashdata, *buf++);
- sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
+ W_REG(osh, &cc->flashaddress, byte++);
+ W_REG(osh, &cc->flashdata, *buf++);
+ sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE);
}
/* Write buffer 1 into main memory page */
- W_REG(NULL, &cc->flashaddress, page);
- sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
+ W_REG(osh, &cc->flashaddress, page);
+ sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM);
break;
}
* Caller should poll for completion.
*/
int
-sflash_erase(chipcregs_t *cc, uint offset)
+sflash_erase(sb_t *sbh, chipcregs_t *cc, uint offset)
{
struct sflash *sfl;
+ osl_t *osh;
+
+ ASSERT(sbh);
+
+ osh = sb_osh(sbh);
if (offset >= sflash.size)
return -22;
sfl = &sflash;
switch (sfl->type) {
case SFLASH_ST:
- sflash_cmd(cc, SFLASH_ST_WREN);
- W_REG(NULL, &cc->flashaddress, offset);
- sflash_cmd(cc, SFLASH_ST_SE);
+ sflash_cmd(osh, cc, SFLASH_ST_WREN);
+ W_REG(osh, &cc->flashaddress, offset);
+ sflash_cmd(osh, cc, SFLASH_ST_SE);
return sfl->blocksize;
case SFLASH_AT:
- W_REG(NULL, &cc->flashaddress, offset << 1);
- sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
+ W_REG(osh, &cc->flashaddress, offset << 1);
+ sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE);
return sfl->blocksize;
}
* the region of flash
*/
int
-sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
+sflash_commit(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf)
{
struct sflash *sfl;
uchar *block = NULL, *cur_ptr, *blk_ptr;
uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
uint blk_offset, blk_len, copied;
int bytes, ret = 0;
+ osl_t *osh;
+
+ ASSERT(sbh);
+
+ osh = sb_osh(sbh);
/* Check address range */
if (len <= 0)
mask = blocksize - 1;
/* Allocate a block of mem */
- if (!(block = MALLOC(NULL, blocksize)))
+ if (!(block = MALLOC(osh, blocksize)))
return -1;
while (len) {
/* Copy entire block */
while (blk_len) {
- copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
+ copied = sflash_read(sbh, cc, blk_offset, blk_len, blk_ptr);
blk_offset += copied;
blk_len -= copied;
blk_ptr += copied;
}
/* Erase block */
- if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
+ if ((ret = sflash_erase(sbh, cc, (uint) cur_offset)) < 0)
goto done;
- while (sflash_poll(cc, (uint) cur_offset));
+ while (sflash_poll(sbh, cc, (uint) cur_offset));
/* buf == NULL means erase only */
if (!buf) {
/* Write holding block */
while (cur_length > 0) {
- if ((bytes = sflash_write(cc,
+ if ((bytes = sflash_write(sbh, cc,
(uint) cur_offset,
(uint) cur_length,
(uchar *) cur_ptr)) < 0) {
ret = bytes;
goto done;
}
- while (sflash_poll(cc, (uint) cur_offset));
+ while (sflash_poll(sbh, cc, (uint) cur_offset));
cur_offset += bytes;
cur_length -= bytes;
cur_ptr += bytes;
ret = len;
done:
if (block)
- MFREE(NULL, block, blocksize);
+ MFREE(osh, block, blocksize);
return ret;
}