/* write a word to the PCMCIA srom */ static int sprom_write_pcmcia(void *osh, uint16 addr, uint16 data) { uint8 addr_l, addr_h, data_l, data_h; addr_l = (uint8)((addr * 2) & 0xff); addr_h = (uint8)(((addr * 2) >> 8) & 0xff); data_l = (uint8)(data & 0xff); data_h = (uint8)((data >> 8) & 0xff); /* set address */ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); /* write data */ OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1); OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1); /* do write */ return sprom_cmd_pcmcia(osh, SROM_WRITE); }
/* read a word from the PCMCIA srom */ static int sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data) { uint8 addr_l, addr_h, data_l, data_h; addr_l = (uint8)((addr * 2) & 0xff); addr_h = (uint8)(((addr * 2) >> 8) & 0xff); /* set address */ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); /* do read */ if (sprom_cmd_pcmcia(osh, SROM_READ)) return 1; /* read data */ OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1); OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1); *data = (data_h << 8) | data_l; return 0; }
/* support only 16-bit word write into srom */ int srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf) { uint16 *srom; uint i, off, nw, crc_range; uint16 image[SPROM_SIZE], *p; uint8 crc; volatile uint32 val32; /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; crc_range = ((bus == PCMCIA_BUS) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2; /* if changes made inside crc cover range */ if (byteoff < crc_range) { nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2; /* read data including entire first 64 words from srom */ if (srom_read(bus, curmap, osh, 0, nw * 2, image)) return 1; /* make changes */ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes); /* calculate crc */ htol16_buf(image, crc_range); crc = ~crc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); ltoh16_buf(image, crc_range); image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff); p = image; off = 0; } else { p = buf; off = byteoff / 2; nw = nbytes / 2; } if (bus == PCI_BUS) { srom = (uint16*)((uint)curmap + PCI_BAR0_SPROM_OFFSET); /* enable writes to the SPROM */ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); val32 |= SPROM_WRITEEN; OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); bcm_mdelay(500); /* write srom */ for (i = 0; i < nw; i++) { W_REG(&srom[off + i], p[i]); bcm_mdelay(20); } /* disable writes to the SPROM */ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN); } else if (bus == PCMCIA_BUS) { /* enable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WEN)) return 1; bcm_mdelay(500); /* write srom */ for (i = 0; i < nw; i++) { sprom_write_pcmcia(osh, (uint16)(off + i), p[i]); bcm_mdelay(20); } /* disable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WDS)) return 1; } else { return 1; } bcm_mdelay(500); return 0; }
/* support only 16-bit word write into srom */ int srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf) { uint16 *srom; uint i, nw, crc_range; uint16 image[SPROM_SIZE]; uint8 crc; volatile uint32 val32; ASSERT(bustype == BUSTYPE(bustype)); /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) return 1; /* Are we writing the whole thing at once? */ if ((byteoff == 0) && ((nbytes == SPROM_SIZE) || (nbytes == (SPROM_CRC_RANGE * 2)) || (nbytes == (SROM4_WORDS * 2)))) { crc_range = nbytes; bcopy((void*)buf, (void*)image, nbytes); nw = nbytes / 2; } else { if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS)) crc_range = SPROM_SIZE; else crc_range = SPROM_CRC_RANGE * 2; /* Tentative */ nw = crc_range / 2; /* read first 64 words from srom */ if (srom_read(bustype, curmap, osh, 0, crc_range, image)) return 1; if (image[SROM4_SIGN] == SROM4_SIGNATURE) { crc_range = SROM4_WORDS; nw = crc_range / 2; if (srom_read(bustype, curmap, osh, 0, crc_range, image)) return 1; } /* make changes */ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes); } /* calculate crc */ htol16_buf(image, crc_range); crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); ltoh16_buf(image, crc_range); image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff); if (BUSTYPE(bustype) == PCI_BUS) { srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET); /* enable writes to the SPROM */ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); val32 |= SPROM_WRITEEN; OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { W_REG(osh, &srom[i], image[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN); } else if (BUSTYPE(bustype) == PCMCIA_BUS) { /* enable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WEN)) return 1; bcm_mdelay(WRITE_ENABLE_DELAY); /* write srom */ for (i = 0; i < nw; i++) { sprom_write_pcmcia(osh, (uint16)(i), image[i]); bcm_mdelay(WRITE_WORD_DELAY); } /* disable writes to the SPROM */ if (sprom_cmd_pcmcia(osh, SROM_WDS)) return 1; } else { return 1; } bcm_mdelay(WRITE_ENABLE_DELAY); return 0; }