/* * Disk driver for serial RAM chips connected via SPI port. */ #include #include #include #include #include #include #include #include #include #include #define SPIRAM_WREN 0x06 #define SPIRAM_WRDI 0x04 #define SPIRAM_RDSR 0x05 #define SPIRAM_WRSR 0x01 #define SPIRAM_READ 0x03 #define SPIRAM_WRITE 0x02 #define SPIRAM_SLEEP 0xB9 #define SPIRAM_WAKE 0xAB #ifndef SPIRAMS_MHZ #define SPIRAMS_MHZ 10 #endif struct spiio spirams_io[SPIRAMS_CHIPS]; int spirams_dkindex; /* disk index for statistics */ /* * Size of RAM disk. */ #define SPIRAMS_TOTAL_KBYTES (SPIRAMS_CHIPS * SPIRAMS_CHIPSIZE) #define MRBSIZE 1024 #define MRBLOG2 10 unsigned int spir_read_block(unsigned int chip, unsigned int address, unsigned int length, char *data) { struct spiio *io = &spirams_io[chip]; register unsigned int cs = 0; switch (chip) { case 0: #ifdef SPIRAMS_LED0_PORT TRIS_CLR(SPIRAMS_LED0_PORT) = 1<> 16); spi_transfer(io, address >> 8); spi_transfer(io, address); // If the length is a multiple of 32 bits, then do a 32 bit transfer #if 0 if ((length & 3) == 0) spi_bulk_read_32(io, length, data); else if ((length & 1) == 0) spi_bulk_read_16(io, length, data); else #endif spi_bulk_read(io, length, (unsigned char *)data); spi_deselect(io); switch (chip) { case 0: #ifdef SPIRAMS_LED0_PORT LAT_CLR(SPIRAMS_LED0_PORT) = 1< 0) { pass++; toread = bcount; if (toread > MRBSIZE) toread = MRBSIZE; chip = offset / SPIRAMS_CHIPSIZE; address = (offset<<10) - (chip * (SPIRAMS_CHIPSIZE*1024)); if (chip >= SPIRAMS_CHIPS) { printf("!!!EIO\n"); return EIO; } spir_read_block(chip, address, toread, data); bcount -= toread; offset += (toread>>MRBLOG2); data += toread; } return 1; } unsigned int spir_write_block(unsigned int chip, unsigned int address, unsigned int length, char *data) { struct spiio *io = &spirams_io[chip]; register unsigned int cs = 0; char blank __attribute__((unused)); switch (chip) { case 0: #ifdef SPIRAMS_LED0_PORT TRIS_CLR(SPIRAMS_LED0_PORT) = 1<> 16); spi_transfer(io, address >> 8); spi_transfer(io, address); #if 0 if ((length & 3) == 0) spi_bulk_write_32(io, length, data); else if ((length & 1) == 0) spi_bulk_write_16(io, length, data); else #endif spi_bulk_write(io, length, (unsigned char *)data); spi_deselect(io); switch (chip) { case 0: #ifdef SPIRAMS_LED0_PORT LAT_CLR(SPIRAMS_LED0_PORT) = 1< 0) { pass++; towrite = bcount; if (towrite > MRBSIZE) towrite = MRBSIZE; chip = offset / SPIRAMS_CHIPSIZE; address = (offset<<10) - (chip * (SPIRAMS_CHIPSIZE*MRBSIZE)); if (chip >= SPIRAMS_CHIPS) { printf("!!!EIO\n"); return EIO; } spir_write_block(chip, address, towrite, data); bcount -= towrite; offset += (towrite>>MRBLOG2); data += towrite; } return 1; } /* * Initialize hardware. */ static int spirams_init(int spi_port, char cs[]) { struct spiio *io = &spirams_io[0]; if (spi_setup(io, spi_port, cs[0]) != 0) { printf("sr0: cannot open SPI%u port\n", spi_port); return 0; } spi_brg(io, SPIRAMS_MHZ * 1000); spi_set(io, PIC32_SPICON_CKE); #if SPIRAMS_CHIPS >= 1 spi_setup(io+1, spi_port, cs[1]); spi_brg(io+1, SPIRAMS_MHZ * 1000); spi_set(io+1, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 2 spi_setup(io+2, spi_port, cs[2]); spi_brg(io+2, SPIRAMS_MHZ * 1000); spi_set(io+2, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 3 spi_setup(io+3, spi_port, cs[3]); spi_brg(io+3, SPIRAMS_MHZ * 1000); spi_set(io+3, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 4 spi_setup(io+4, spi_port, cs[4]); spi_brg(io+4, SPIRAMS_MHZ * 1000); spi_set(io+4, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 5 spi_setup(io+5, spi_port, cs[5]); spi_brg(io+5, SPIRAMS_MHZ * 1000); spi_set(io+5, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 6 spi_setup(io+6, spi_port, cs[6]); spi_brg(io+6, SPIRAMS_MHZ * 1000); spi_set(io+6, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 7 spi_setup(io+7, spi_port, cs[7]); spi_brg(io+7, SPIRAMS_MHZ * 1000); spi_set(io+7, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 8 spi_setup(io+8, spi_port, cs[8]); spi_brg(io+8, SPIRAMS_MHZ * 1000); spi_set(io+8, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 9 spi_setup(io+9, spi_port, cs[9]); spi_brg(io+9, SPIRAMS_MHZ * 1000); spi_set(io+9, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 10 spi_setup(io+10, spi_port, cs[10]); spi_brg(io+10, SPIRAMS_MHZ * 1000); spi_set(io+10, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 11 spi_setup(io+11, spi_port, cs[11]); spi_brg(io+11, SPIRAMS_MHZ * 1000); spi_set(io+11, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 12 spi_setup(io+12, spi_port, cs[12]); spi_brg(io+12, SPIRAMS_MHZ * 1000); spi_set(io+12, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 13 spi_setup(io+13, spi_port, cs[13]); spi_brg(io+13, SPIRAMS_MHZ * 1000); spi_set(io+13, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 14 spi_setup(io+14, spi_port, cs[14]); spi_brg(io+14, SPIRAMS_MHZ * 1000); spi_set(io+14, PIC32_SPICON_CKE); #endif #if SPIRAMS_CHIPS >= 15 spi_setup(io+15, spi_port, cs[15]); spi_brg(io+15, SPIRAMS_MHZ * 1000); spi_set(io+15, PIC32_SPICON_CKE); #endif printf("spirams0: size %dKB, speed %d Mbit/sec\n", SPIRAMS_CHIPS * SPIRAMS_CHIPSIZE, spi_get_brg(io) / 1000); return 1; } /* * Open the disk. */ int spirams_open(dev_t dev, int flag, int mode) { return 0; } int spirams_close(dev_t dev, int flag, int mode) { return 0; } /* * Return the size of the device in kbytes. */ daddr_t spirams_size(dev_t dev) { return SPIRAMS_TOTAL_KBYTES; } void spirams_strategy(struct buf *bp) { int offset = bp->b_blkno; long nblk = btod(bp->b_bcount); int s; /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. */ if (bp->b_blkno + nblk > SPIRAMS_TOTAL_KBYTES) { /* if exactly at end of partition, return an EOF */ if (bp->b_blkno == SPIRAMS_TOTAL_KBYTES) { bp->b_resid = bp->b_bcount; biodone(bp); return; } /* or truncate if part of it fits */ nblk = SPIRAMS_TOTAL_KBYTES - bp->b_blkno; if (nblk <= 0) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; biodone(bp); return; } bp->b_bcount = nblk << DEV_BSHIFT; } led_control(LED_SWAP, 1); s = splbio(); #ifdef UCB_METER if (spirams_dkindex >= 0) { dk_busy |= 1 << spirams_dkindex; dk_xfer[spirams_dkindex]++; dk_bytes[spirams_dkindex] += bp->b_bcount; } #endif if (bp->b_flags & B_READ) { spirams_read(offset, bp->b_addr, bp->b_bcount); } else { spirams_write(offset, bp->b_addr, bp->b_bcount); } biodone(bp); led_control(LED_SWAP, 0); #ifdef UCB_METER if (spirams_dkindex >= 0) dk_busy &= ~(1 << spirams_dkindex); #endif splx(s); } int spirams_ioctl(dev_t dev, u_int cmd, caddr_t addr, int flag) { int error = 0; switch (cmd) { case DIOCGETMEDIASIZE: /* Get disk size in kbytes. */ *(int*) addr = SPIRAMS_TOTAL_KBYTES; break; default: error = EINVAL; break; } return error; } /* * Test to see if device is present. * Return true if found and initialized ok. */ static int spirams_probe(config) struct conf_device *config; { int i; /* Only one device unit is supported. */ if (config->dev_unit != 0) return 0; printf("sr0: port SPI%d, pins ", config->dev_ctlr); for (i=0; idev_pins[i]; if (i > 0) printf("/"); if (i == 7) printf("\n "); printf("R%c%d", gpio_portname(cs), gpio_pinno(cs)); } printf("\n"); if (spirams_init(config->dev_ctlr, config->dev_pins) != 0) return 0; #ifdef UCB_METER dk_alloc(&spirams_dkindex, 1, "sr0"); #endif return 1; } struct driver srdriver = { "sr", spirams_probe, };