Ejemplo n.º 1
0
Archivo: sflash.c Proyecto: ariavie/bcm
/* Poll for command completion. Returns zero when complete. */
int
sflash_poll(si_t *sih, chipcregs_t *cc, uint offset)
{
    osl_t *osh;
    
    ASSERT(sih);
    
    osh = si_osh(sih);
    
    if (offset >= sflash.size)
        return -22;
    
    switch (sflash.type) {
    case SFLASH_ST:
          /* Check for ST Write In Progress bit */
          sflash_cmd(osh, cc, SFLASH_ST_RDSR);
          return R_REG(osh, &cc->sflashdata) & SFLASH_ST_WIP;
    case SFLASH_AT:
          /* Check for Atmel Ready bit */
          sflash_cmd(osh, cc, SFLASH_AT_STATUS);
          return !(R_REG(osh, &cc->sflashdata) & SFLASH_AT_READY);
    }
    
    return 0;
}
Ejemplo n.º 2
0
/* Erase a region. Returns number of bytes scheduled for erasure.
 * Caller should poll for completion.
 */
int
sflash_erase(si_t *sih, chipcregs_t *cc, uint offset)
{
	struct sflash *sfl;
	osl_t *osh;

	ASSERT(sih);

	osh = si_osh(sih);

	sfl = &sflash;
	if (offset >= sfl->size)
		return -22;

	switch (sfl->type) {
	case SFLASH_ST:
		sflash_cmd(osh, cc, SFLASH_ST_WREN);
		W_REG(osh, &cc->flashaddress, offset);
		/* Newer flashes have "sub-sectors" which can be erased independently
		 * with a new command: ST_SSE. The ST_SE command erases 64KB just as
		 * before.
		 */
		sflash_cmd(osh, cc, (sfl->blocksize < (64 * 1024)) ? SFLASH_ST_SSE : SFLASH_ST_SE);
		return sfl->blocksize;
	case SFLASH_AT:
		W_REG(osh, &cc->flashaddress, offset << 1);
		sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE);
		return sfl->blocksize;
	}

	return 0;
}
Ejemplo n.º 3
0
/* Erase a region. Returns number of bytes scheduled for erasure.
 * Caller should poll for completion.
 */
int
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(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(osh, &cc->flashaddress, offset << 1);
		sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE);
		return sfl->blocksize;
	}

	return 0;
}
Ejemplo n.º 4
0
/* Poll for command completion. Returns zero when complete. */
int
sflash_poll(chipcregs_t *cc, uint offset)
{
	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;
	case SFLASH_AT:
		/* Check for Atmel Ready bit */
		sflash_cmd(cc, SFLASH_AT_STATUS);
		return !(R_REG(NULL, &cc->flashdata) & SFLASH_AT_READY);
	}

	return 0;
}
Ejemplo n.º 5
0
/* Erase a region. Returns number of bytes scheduled for erasure.
 * Caller should poll for completion.
 */
int
sflash_erase(chipcregs_t *cc, uint offset)
{
	struct sflash *sfl;

	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);
		return sfl->blocksize;
	case SFLASH_AT:
		W_REG(NULL, &cc->flashaddress, offset << 1);
		sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
		return sfl->blocksize;
	}

	return 0;
}
Ejemplo n.º 6
0
/* Initialize serial flash access */
struct sflash *
sflash_init(si_t *sih, chipcregs_t *cc)
{
	uint32 id, id2;
	char *name = "";
	osl_t *osh;

	ASSERT(sih);

	osh = si_osh(sih);

	bzero(&sflash, sizeof(sflash));

	sflash.type = sih->cccaps & CC_CAP_FLASH_MASK;

	switch (sflash.type) {
	case SFLASH_ST:
		/* Probe for ST chips */
		name = "ST compatible";
		sflash_cmd(osh, cc, SFLASH_ST_DP);
		W_REG(osh, &cc->flashaddress, 0);
		sflash_cmd(osh, cc, SFLASH_ST_RES);
		id = R_REG(osh, &cc->flashdata);
		sflash.blocksize = 64 * 1024;
		switch (id) {
		case 0x11:
			/* ST M25P20 2 Mbit Serial Flash */
			sflash.numblocks = 4;
			break;
		case 0x12:
			/* ST M25P40 4 Mbit Serial Flash */
			sflash.numblocks = 8;
			break;
		case 0x13:
			/* ST M25P80 8 Mbit Serial Flash */
			sflash.numblocks = 16;
			break;
		case 0x14:
			/* ST M25P16 16 Mbit Serial Flash */
			sflash.numblocks = 32;
			break;
		case 0x15:
			/* ST M25P32 32 Mbit Serial Flash */
			sflash.numblocks = 64;
			break;
		case 0x16:
			/* ST M25P64 64 Mbit Serial Flash */
			sflash.numblocks = 128;
			break;
		case 0x17:
			/* ST M25FL128 128 Mbit Serial Flash */
			sflash.numblocks = 256;
			break;
		case 0xbf:
			/* All of the following flashes are SST with
			 * 4KB subsectors. Others should be added but
			 * We'll have to revamp the way we identify them
			 * since RES is not eough to disambiguate them.
			 */
			name = "SST";
			sflash.blocksize = 4 * 1024;
			W_REG(osh, &cc->flashaddress, 1);
			sflash_cmd(osh, cc, SFLASH_ST_RES);
			id2 = R_REG(osh, &cc->flashdata);
			switch (id2) {
			case 1:
				/* SST25WF512 512 Kbit Serial Flash */
				sflash.numblocks = 16;
				break;
			case 0x48:
				/* SST25VF512 512 Kbit Serial Flash */
				sflash.numblocks = 16;
				break;
			case 2:
				/* SST25WF010 1 Mbit Serial Flash */
				sflash.numblocks = 32;
				break;
			case 0x49:
				/* SST25VF010 1 Mbit Serial Flash */
				sflash.numblocks = 32;
				break;
			case 3:
				/* SST25WF020 2 Mbit Serial Flash */
				sflash.numblocks = 64;
				break;
			case 0x43:
				/* SST25VF020 2 Mbit Serial Flash */
				sflash.numblocks = 64;
				break;
			case 4:
				/* SST25WF040 4 Mbit Serial Flash */
				sflash.numblocks = 128;
				break;
			case 0x44:
				/* SST25VF040 4 Mbit Serial Flash */
				sflash.numblocks = 128;
				break;
			case 0x8d:
				/* SST25VF040B 4 Mbit Serial Flash */
				sflash.numblocks = 128;
				break;
			case 5:
				/* SST25WF080 8 Mbit Serial Flash */
				sflash.numblocks = 256;
				break;
			case 0x8e:
				/* SST25VF080B 8 Mbit Serial Flash */
				sflash.numblocks = 256;
				break;
			case 0x41:
				/* SST25VF016 16 Mbit Serial Flash */
				sflash.numblocks = 512;
				break;
			case 0x4a:
				/* SST25VF032 32 Mbit Serial Flash */
				sflash.numblocks = 1024;
				break;
			case 0x4b:
				/* SST25VF064 64 Mbit Serial Flash */
				sflash.numblocks = 2048;
				break;
			}
			break;
		}
		break;

	case SFLASH_AT:
		/* Probe for Atmel chips */
		name = "Atmel";
		sflash_cmd(osh, cc, SFLASH_AT_STATUS);
		id = R_REG(osh, &cc->flashdata) & 0x3c;
		switch (id) {
		case 0xc:
			/* Atmel AT45DB011 1Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 512;
			break;
		case 0x14:
			/* Atmel AT45DB021 2Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 1024;
			break;
		case 0x1c:
			/* Atmel AT45DB041 4Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 2048;
			break;
		case 0x24:
			/* Atmel AT45DB081 8Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 4096;
			break;
		case 0x2c:
			/* Atmel AT45DB161 16Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 4096;
			break;
		case 0x34:
			/* Atmel AT45DB321 32Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 8192;
			break;
		case 0x3c:
			/* Atmel AT45DB642 64Mbit Serial Flash */
			sflash.blocksize = 1024;
			sflash.numblocks = 8192;
			break;
		}
		break;
	}

	sflash.size = sflash.blocksize * sflash.numblocks;

	if (firsttime)
		printf("Found an %s serial flash with %d %dKB blocks; total size %dMB\n",
		       name, sflash.numblocks, sflash.blocksize / 1024,
		       sflash.size / (1024 * 1024));

	firsttime = FALSE;
	return sflash.size ? &sflash : NULL;
}
Ejemplo n.º 7
0
int
sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer)
{
	struct sflash *sfl;
	uint off = offset, len = length;
	const uint8 *buf = buffer;
	uint8 data;
	int ret = 0, ntry = 0;
	bool is4712b0;
	uint32 page, byte, mask;
	osl_t *osh;

	ASSERT(sih);

	osh = si_osh(sih);

	if (!len)
		return 0;

	sfl = &sflash;
	if ((off + len) > sfl->size)
		return -22;

	switch (sfl->type) {
	case SFLASH_ST:
		is4712b0 = (CHIPID(sih->chip) == BCM4712_CHIP_ID) && (CHIPREV(sih->chiprev) == 3);
		/* Enable writes */
retry:		sflash_cmd(osh, cc, SFLASH_ST_WREN);
		off = offset;
		len = length;
		buf = buffer;
		ntry++;
		if (is4712b0) {
			mask = 1 << 14;
			W_REG(osh, &cc->flashaddress, off);
			data = GET_BYTE(buf);
			buf++;
			W_REG(osh, &cc->flashdata, data);
			/* Set chip select */
			OR_REG(osh, &cc->gpioout, mask);
			/* Issue a page program with the first byte */
			sflash_cmd(osh, cc, SFLASH_ST_PP);
			ret = 1;
			off++;
			len--;
			while (len > 0) {
				if ((off & 255) == 0) {
					/* Page boundary, drop cs and return */
					AND_REG(osh, &cc->gpioout, ~mask);
					OSL_DELAY(1);
					if (!sflash_poll(sih, cc, off)) {
						/* Flash rejected command */
						if (ntry <= ST_RETRIES)
							goto retry;
						else
							return -11;
					}
					return ret;
				} else {
					/* Write single byte */
					data = GET_BYTE(buf);
					buf++;
					sflash_cmd(osh, cc, data);
				}
				ret++;
				off++;
				len--;
			}
			/* All done, drop cs */
			AND_REG(osh, &cc->gpioout, ~mask);
			OSL_DELAY(1);
			if (!sflash_poll(sih, cc, off)) {
				/* Flash rejected command */
				if (ntry <= ST_RETRIES)
					goto retry;
				else
					return -12;
			}
		} else if (sih->ccrev >= 20) {
			W_REG(osh, &cc->flashaddress, off);
			data = GET_BYTE(buf);
			buf++;
			W_REG(osh, &cc->flashdata, data);
			/* Issue a page program with CSA bit set */
			sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP);
			ret = 1;
			off++;
			len--;
			while (len > 0) {
				if ((off & 255) == 0) {
					/* Page boundary, poll droping cs and return */
					W_REG(NULL, &cc->flashcontrol, 0);
					OSL_DELAY(1);
					if (sflash_poll(sih, cc, off) == 0) {
						/* Flash rejected command */
						SFL_MSG(("sflash: pp rejected, ntry: %d,"
						         " off: %d/%d, len: %d/%d, ret:"
						         "%d\n", ntry, off, offset, len,
						         length, ret));
						if (ntry <= ST_RETRIES)
							goto retry;
						else
							return -11;
					}
					return ret;
				} else {
					/* Write single byte */
					data = GET_BYTE(buf);
					buf++;
					sflash_cmd(osh, cc, SFLASH_ST_CSA | data);
				}
				ret++;
				off++;
				len--;
			}
			/* All done, drop cs & poll */
			W_REG(NULL, &cc->flashcontrol, 0);
			OSL_DELAY(1);
			if (sflash_poll(sih, cc, off) == 0) {
				/* Flash rejected command */
				SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d,"
				         " len: %d/%d, ret: %d\n",
				         ntry, off, offset, len, length, ret));
				if (ntry <= ST_RETRIES)
					goto retry;
				else
					return -12;
			}
		} else {
			ret = 1;
			W_REG(osh, &cc->flashaddress, off);
			data = GET_BYTE(buf);
			buf++;
			W_REG(osh, &cc->flashdata, data);
			/* Page program */
			sflash_cmd(osh, cc, SFLASH_ST_PP);
		}
		break;
	case SFLASH_AT:
		mask = sfl->blocksize - 1;
		page = (off & ~mask) << 1;
		byte = off & mask;
		/* Read main memory page into buffer 1 */
		if (byte || (len < sfl->blocksize)) {
			W_REG(osh, &cc->flashaddress, page);
			sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD);
			/* 250 us for AT45DB321B */
			SPINWAIT(sflash_poll(sih, cc, off), 1000);
			ASSERT(!sflash_poll(sih, cc, off));
		}
		/* Write into buffer 1 */
		for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
			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(osh, &cc->flashaddress, page);
		sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM);
		break;
	}

	return ret;
}
Ejemplo n.º 8
0
Archivo: sflash.c Proyecto: ariavie/bcm
/* Initialize serial flash access */
struct sflash *
sflash_init(si_t *sih, chipcregs_t *cc)
{
    uint32 id;
    osl_t *osh;
    uint32  mem_type, mem_cap;
    
    ASSERT(sih);
    
    osh = si_osh(sih);
    
    bzero(&sflash, sizeof(sflash));
    
    sflash.type = sih->cccaps & CC_CAP_FLASH_MASK;
    
    switch (sflash.type) {
    case SFLASH_ST:
          /* Probe for ST chips */
          sflash_cmd(osh, cc, (SFLASH_ST_RDID | SFLASH_ST_CSA));
          sflash_cmd(osh, cc, (SFLASH_ST_RDID_READ | SFLASH_ST_CSA));
          id = R_REG(osh, &cc->sflashdata);
          sflash_cmd(osh, cc, (SFLASH_ST_RDID_READ | SFLASH_ST_CSA));
          mem_type = R_REG(osh, &cc->sflashdata);
          sflash_cmd(osh, cc, (SFLASH_ST_RDID_READ | SFLASH_ST_CSA));
          mem_cap = R_REG(osh, &cc->sflashdata);
          switch (id) {
          case 0x20: /* Micron */
              switch(mem_type) {
              case 0x20: /* M25P series */
              case 0xba: /* N25Q series */
                switch (mem_cap) {
                case 0x12:
                    /* ST M25P20 2 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 4;
                    break;
                case 0x13:
                    /* ST M25P40 4 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 8;
                    break;
                case 0x14:
                    /* ST M25P80 8 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 16;
                    break;
                case 0x15:
                    /* ST M25P16 16 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 32;
                    break;
                case 0x16:
                    /* ST M25P32 32 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 64;
                    break;
                case 0x17:
                    /* ST M25P64 64 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 128;
                    break;
                case 0x18:
                    /* ST M25P 128 Mbit Serial Flash */
                    sflash.blocksize = 64 * 1024;
                    sflash.numblocks = 256;
                    break;
                }
                break;
              }
              break;
          case 0x01: /* Spansion */
              if ((mem_type == 0x20) && (mem_cap == 0x18)) {
                /* ST S25FL128P00M 128 Mbit */
                sflash.blocksize = 64 * 1024;
                sflash.numblocks = 256;
              } else if ((mem_type == 0x02) && (mem_cap == 0x15)) {
                /* ST S25FL032P */
                sflash.blocksize = 64 * 1024;
                sflash.numblocks = 64;
              }
              break;
          case 0xbf: /* SST */
              if ((mem_type == 0x25) && (mem_cap == 0x8e)) {
                /* SST 25VF80 */
                sflash.blocksize = 64 * 1024;
                sflash.numblocks = 8;
              }
              break;
          }
          /* All done, drop cs & read */
          W_REG(osh, &cc->sflashcontrol, 0);
          break;
    
    case SFLASH_AT:
          /* Probe for Atmel chips */
          sflash_cmd(osh, cc, SFLASH_AT_STATUS);
          id = R_REG(osh, &cc->sflashdata) & 0x3c;
          switch (id) {
          case 0xc:
              /* Atmel AT45DB011 1Mbit Serial Flash */
              sflash.blocksize = 256;
              sflash.numblocks = 512;
              break;
          case 0x14:
              /* Atmel AT45DB021 2Mbit Serial Flash */
              sflash.blocksize = 256;
              sflash.numblocks = 1024;
              break;
          case 0x1c:
              /* Atmel AT45DB041 4Mbit Serial Flash */
              sflash.blocksize = 256;
              sflash.numblocks = 2048;
              break;
          case 0x24:
              /* Atmel AT45DB081 8Mbit Serial Flash */
              sflash.blocksize = 256;
              sflash.numblocks = 4096;
              break;
          case 0x2c:
              /* Atmel AT45DB161 16Mbit Serial Flash */
              sflash.blocksize = 512;
              sflash.numblocks = 4096;
              break;
          case 0x34:
              /* Atmel AT45DB321 32Mbit Serial Flash */
              sflash.blocksize = 512;
              sflash.numblocks = 8192;
              break;
          case 0x3c:
              /* Atmel AT45DB642 64Mbit Serial Flash */
              sflash.blocksize = 1024;
              sflash.numblocks = 8192;
              break;
          }
          break;
    }
    
    sflash.size = sflash.blocksize * sflash.numblocks;
    return sflash.size ? &sflash : NULL;
}
Ejemplo n.º 9
0
Archivo: sflash.c Proyecto: ariavie/bcm
int
sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer)
{
    struct sflash *sfl;
    uint off = offset, len = length;
#if SFLASH_ST_PAGE_MODE_WRITE
    int tryn = 0;
#else /* !SFLASH_ST_PAGE_MODE_WRITE */
    uint quot = 0, remain = 0, wlen = 0;
    uint32 reg_val = 0;
#endif /* SFLASH_ST_PAGE_MODE_WRITE */
    const uchar *buf = buffer;
    int ret = 0;
    uint32 page, byte, mask;
    osl_t *osh;
    
    ASSERT(sih);
    
    osh = si_osh(sih);
    
    if (!len)
        return 0;
    
    sfl = &sflash;
    if ((off + len) > sfl->size)
        return -22;
    
    switch (sfl->type) {
    case SFLASH_ST:
#if SFLASH_ST_PAGE_MODE_WRITE
          /* Enable writes */
retry:      sflash_cmd(osh, cc, SFLASH_ST_WREN);
          off = offset;
          len = length;
          buf = buffer;
          tryn++;
          if (sih->ccrev >= 20) {
              W_REG(osh, &cc->sflashaddress, off);
              W_REG(osh, &cc->sflashdata, *buf++);
              /* Issue a page program with CSA bit set */
              sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP);
              ret = 1;
              off++;
              len--;
              while (len > 0) {
                  if ((off & 255) == 0) {
                      /* Page boundary, poll droping cs and return */
                      W_REG(osh, &cc->sflashcontrol, 0);
                      OSL_DELAY(1);
                      if (sflash_poll(sih, cc, offset) != 0) {
                          /* Flash rejected command */
                          SFL_MSG(("sflash: pp rejected, tryn: %d,"
                                   " off: %d/%d, len: %d/%d, ret:"
                                   "%d\n", tryn, off, offset, len,
                                   length, ret));
                          if (tryn <= ST_RETRIES)
                              goto retry;
                          else
                              return -11;
                      }
                      return ret;
                  } else {
                      /* Write single byte */
                      sflash_cmd(osh, cc, SFLASH_ST_CSA | *buf++);
                  }
                  ret++;
                  off++;
                  len--;
              }
              /* All done, drop cs & poll */
              W_REG(osh, &cc->sflashcontrol, 0);
              OSL_DELAY(1);
              if (sflash_poll(sih, cc, offset) != 0) {
                  /* Flash rejected command */
                  SFL_MSG(("sflash: pp rejected, tryn: %d, off: %d/%d,"
                           " len: %d/%d, ret: %d\n",
                           tryn, off, offset, len, length, ret));
                  if (tryn <= ST_RETRIES)
                      goto retry;
                  else
                      return -12;
              }
          } else {
              ret = 1;
              W_REG(osh, &cc->sflashaddress, off);
              W_REG(osh, &cc->sflashdata, *buf);
              /* Page program */
              sflash_cmd(osh, cc, SFLASH_ST_PP);
          }
#else /* !SFLASH_ST_PAGE_MODE_WRITE */
          off = offset;
          len = length;
          buf = buffer;
          if (sih->ccrev >= 20) {
              ret = 0;
              while (len > 0) {
                  /* Enable writes */
                  sflash_cmd(osh, cc, SFLASH_ST_WREN);
                  /* Drop cs before starting a page program */
                  W_REG(osh, &cc->sflashcontrol, 0);

                  W_REG(osh, &cc->sflashaddress, off);
                  quot = (len / 4);
                  remain = (len % 4);
                  if (quot != 0) { /* len >= 4 bytes */
                      wlen = 4;
                      reg_val = (*buf << 24);
                      buf++;
                      reg_val |= (*buf << 16);
                      buf++;
                      reg_val |= (*buf << 8);
                      buf++;
                      reg_val |= (*buf);
                      buf++;
                      W_REG(osh, &cc->sflashdata, reg_val);
                      /* Issue a page program with CSA bit set : opcode+3 addres & 4 data bytes */
                      sflash_cmd(osh, cc, (SFLASH_ST_CSA | SFLASH_ST_PP3A4D));
                  } else { /* len < 4 bytes */
                      wlen = 1;
                      W_REG(osh, &cc->sflashdata, *buf++);
                      /* Issue a page program with CSA bit set : opcode+3 addres & 1 data bytes */
                      sflash_cmd(osh, cc, (SFLASH_ST_CSA | SFLASH_ST_PP));
                  }
                  ret += wlen;
                  off += wlen;
                  len -= wlen;

                  /* A page program done(1 or 4 data bytes), drop cs & poll */
                  W_REG(osh, &cc->sflashcontrol, 0);
                  while (sflash_poll(sih, cc, offset) != 0) {
                      /* Poll until command completion */
                  }

                  /* Page boundary and return for 256 bytes write */
                  if ((off & 255) == 0) {
                      return ret;
                  }
              }
          } else {
              /* Enable writes */
              sflash_cmd(osh, cc, SFLASH_ST_WREN);
              ret = 1;
              W_REG(osh, &cc->sflashaddress, off);
              W_REG(osh, &cc->sflashdata, *buf);
              /* Page program */
              sflash_cmd(osh, cc, SFLASH_ST_PP);
          }
#endif  /* SFLASH_ST_PAGE_MODE_WRITE */
          break;
    case SFLASH_AT:
          mask = sfl->blocksize - 1;
          page = (off & ~mask) << 1;
          byte = off & mask;
          /* Read main memory page into buffer 1 */
          if (byte || (len < sfl->blocksize)) {
              W_REG(osh, &cc->sflashaddress, page);
              sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD);
              /* 250 us for AT45DB321B */
              SPINWAIT(sflash_poll(sih, cc, offset), 1000);
              ASSERT(!sflash_poll(sih, cc, offset));
          }
          /* Write into buffer 1 */
          for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
              W_REG(osh, &cc->sflashaddress, byte++);
              W_REG(osh, &cc->sflashdata, *buf++);
              sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE);
          }
          /* Write buffer 1 into main memory page */
          W_REG(osh, &cc->sflashaddress, page);
          sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM);
          break;
    }
    
    return ret;
}
Ejemplo n.º 10
0
/* Initialize serial flash access */
struct sflash *
sflash_init(chipcregs_t *cc)
{
	uint32 id, id2;

	bzero(&sflash, sizeof(sflash));

	sflash.type = R_REG(NULL, &cc->capabilities) & 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);
		switch (id) {
		case 0x11:
			/* ST M25P20 2 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 4;
			break;
		case 0x12:
			/* ST M25P40 4 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 8;
			break;
		case 0x13:
			/* ST M25P80 8 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 16;
			break;
		case 0x14:
			/* ST M25P16 16 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 32;
			break;
		case 0x15:
			/* ST M25P32 32 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 64;
			break;
		case 0x16:
			/* ST M25P64 64 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 128;
			break;
		case 0xbf:
			W_REG(NULL, &cc->flashaddress, 1);
			sflash_cmd(cc, SFLASH_ST_RES);
			id2 = R_REG(NULL, &cc->flashdata);
			if (id2 == 0x44) {
				/* SST M25VF80 4 Mbit Serial Flash */
				sflash.blocksize = 64 * 1024;
				sflash.numblocks = 8;
			}
			break;
		}
		break;

	case SFLASH_AT:
		/* Probe for Atmel chips */
		sflash_cmd(cc, SFLASH_AT_STATUS);
		id = R_REG(NULL, &cc->flashdata) & 0x3c;
		switch (id) {
		case 0xc:
			/* Atmel AT45DB011 1Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 512;
			break;
		case 0x14:
			/* Atmel AT45DB021 2Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 1024;
			break;
		case 0x1c:
			/* Atmel AT45DB041 4Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 2048;
			break;
		case 0x24:
			/* Atmel AT45DB081 8Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 4096;
			break;
		case 0x2c:
			/* Atmel AT45DB161 16Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 4096;
			break;
		case 0x34:
			/* Atmel AT45DB321 32Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 8192;
			break;
		case 0x3c:
			/* Atmel AT45DB642 64Mbit Serial Flash */
			sflash.blocksize = 1024;
			sflash.numblocks = 8192;
			break;
		}
		break;
	}

	sflash.size = sflash.blocksize * sflash.numblocks;
	return sflash.size ? &sflash : NULL;
}
Ejemplo n.º 11
0
/* Write len bytes starting at offset into buf. Returns number of bytes
 * written. Caller should poll for completion.
 */
int
sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
{
	struct sflash *sfl;
	int ret = 0;
	bool is4712b0;
	uint32 page, byte, mask;

	if (!len)
		return 0;

	if ((offset + len) > sflash.size)
		return -22;

	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)));
		/* Enable writes */
		sflash_cmd(cc, SFLASH_ST_WREN);
		if (is4712b0) {
			mask = 1 << 14;
			W_REG(NULL, &cc->flashaddress, offset);
			W_REG(NULL, &cc->flashdata, *buf++);
			/* Set chip select */
			OR_REG(NULL, &cc->gpioout, mask);
			/* Issue a page program with the first byte */
			sflash_cmd(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)) {
						/* Flash rejected command */
						return -11;
					}
					return ret;
				} else {
					/* Write single byte */
					sflash_cmd(cc, *buf++);
				}
				ret++;
				offset++;
				len--;
			}
			/* All done, drop cs if needed */
			if ((offset & 255) != 1) {
				/* Drop cs */
				AND_REG(NULL, &cc->gpioout, ~mask);
				if (!sflash_poll(cc, offset)) {
					/* Flash rejected command */
					return -12;
				}
			}
		} else {
			ret = 1;
			W_REG(NULL, &cc->flashaddress, offset);
			W_REG(NULL, &cc->flashdata, *buf);
		/* Page program */
		sflash_cmd(cc, SFLASH_ST_PP);
		}
		break;
	case SFLASH_AT:
		mask = sfl->blocksize - 1;
		page = (offset & ~mask) << 1;
		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);
			/* 250 us for AT45DB321B */
			SPINWAIT(sflash_poll(cc, offset), 1000);
			ASSERT(!sflash_poll(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);
		}
		/* Write buffer 1 into main memory page */
		W_REG(NULL, &cc->flashaddress, page);
		sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
		break;
	}

	return ret;
}
Ejemplo n.º 12
0
/* Initialize serial flash access */
struct sflash *
sflash_init(si_t *sih, chipcregs_t *cc)
{
	uint32 id, id2;
	char *name = "";
	osl_t *osh;
	static bool firsttime = TRUE;

	ASSERT(sih);

	osh = si_osh(sih);

	bzero(&sflash, sizeof(sflash));

	sflash.type = sih->cccaps & CC_CAP_FLASH_MASK;

	switch (sflash.type) {
	case SFLASH_ST:
		/* Probe for ST chips */
		name = "ST compatible";
		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.blocksize = 64 * 1024;
			sflash.numblocks = 4;
			break;
		case 0x12:
			/* ST M25P40 4 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 8;
			break;
		case 0x13:
			/* ST M25P80 8 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 16;
			break;
		case 0x14:
			/* ST M25P16 16 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 32;
			break;
		case 0x15:
			/* ST M25P32 32 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 64;
			break;
		case 0x16:
			/* ST M25P64 64 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 128;
			break;
		case 0x17:
			/* ST M25FL128 128 Mbit Serial Flash */
			sflash.blocksize = 64 * 1024;
			sflash.numblocks = 256;
			break;
		case 0xbf:
			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 */
				name = "SST";
				sflash.blocksize = 64 * 1024;
				sflash.numblocks = 8;
			}
			break;
		}
		break;

	case SFLASH_AT:
		/* Probe for Atmel chips */
		name = "Atmel";
		sflash_cmd(osh, cc, SFLASH_AT_STATUS);
		id = R_REG(osh, &cc->flashdata) & 0x3c;
		switch (id) {
		case 0xc:
			/* Atmel AT45DB011 1Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 512;
			break;
		case 0x14:
			/* Atmel AT45DB021 2Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 1024;
			break;
		case 0x1c:
			/* Atmel AT45DB041 4Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 2048;
			break;
		case 0x24:
			/* Atmel AT45DB081 8Mbit Serial Flash */
			sflash.blocksize = 256;
			sflash.numblocks = 4096;
			break;
		case 0x2c:
			/* Atmel AT45DB161 16Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 4096;
			break;
		case 0x34:
			/* Atmel AT45DB321 32Mbit Serial Flash */
			sflash.blocksize = 512;
			sflash.numblocks = 8192;
			break;
		case 0x3c:
			/* Atmel AT45DB642 64Mbit Serial Flash */
			sflash.blocksize = 1024;
			sflash.numblocks = 8192;
			break;
		}
		break;
	}

	sflash.size = sflash.blocksize * sflash.numblocks;

	if (firsttime)
		printf("Found a %dMB %s serial flash\n",
		       sflash.size / (1024 * 1024), name);

	/* 4716A0 hack */
	if (((sih->chip == BCM4716_CHIP_ID) || (sih->chip == BCM4748_CHIP_ID)) &&
		(sih->chiprev == 0)) {
		if (sflash.size > (4 * 1024 * 1024)) {
			sflash.size = 4 * 1024 * 1024;
			if (firsttime)
				printf("Using only 4MB in BCM4716a0\n");
		}
	}
	firsttime = FALSE;
	return sflash.size ? &sflash : NULL;
}