mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-16 23:43:23 +00:00
205 lines
4.5 KiB
C
205 lines
4.5 KiB
C
/*
|
|
* sys-spi-flash.c
|
|
*
|
|
* Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
|
|
* Official site: http://xboot.org
|
|
* Mobile phone: +86-18665388956
|
|
* QQ: 8192542
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <types.h>
|
|
#include <string.h>
|
|
#include <io.h>
|
|
|
|
enum {
|
|
SPI_GCR = 0x04,
|
|
SPI_TCR = 0x08,
|
|
SPI_IER = 0x10,
|
|
SPI_ISR = 0x14,
|
|
SPI_FCR = 0x18,
|
|
SPI_FSR = 0x1c,
|
|
SPI_WCR = 0x20,
|
|
SPI_CCR = 0x24,
|
|
SPI_MBC = 0x30,
|
|
SPI_MTC = 0x34,
|
|
SPI_BCC = 0x38,
|
|
SPI_TXD = 0x200,
|
|
SPI_RXD = 0x300,
|
|
};
|
|
|
|
void sys_spi_flash_init(void)
|
|
{
|
|
virtual_addr_t addr;
|
|
uint32_t val;
|
|
|
|
/* Config GPIOC0, GPIOC1, GPIOC2 and GPIOC3 */
|
|
addr = 0x01c20848 + 0x00;
|
|
val = read32(addr);
|
|
val &= ~(0xf << ((0 & 0x7) << 2));
|
|
val |= ((0x2 & 0x7) << ((0 & 0x7) << 2));
|
|
write32(addr, val);
|
|
|
|
val = read32(addr);
|
|
val &= ~(0xf << ((1 & 0x7) << 2));
|
|
val |= ((0x2 & 0x7) << ((1 & 0x7) << 2));
|
|
write32(addr, val);
|
|
|
|
val = read32(addr);
|
|
val &= ~(0xf << ((2 & 0x7) << 2));
|
|
val |= ((0x2 & 0x7) << ((2 & 0x7) << 2));
|
|
write32(addr, val);
|
|
|
|
val = read32(addr);
|
|
val &= ~(0xf << ((3 & 0x7) << 2));
|
|
val |= ((0x2 & 0x7) << ((3 & 0x7) << 2));
|
|
write32(addr, val);
|
|
|
|
/* Deassert spi0 reset */
|
|
addr = 0x01c202c0;
|
|
val = read32(addr);
|
|
val |= (1 << 20);
|
|
write32(addr, val);
|
|
|
|
/* Open the spi0 bus gate */
|
|
addr = 0x01c20000 + 0x60;
|
|
val = read32(addr);
|
|
val |= (1 << 20);
|
|
write32(addr, val);
|
|
|
|
/* Set spi clock rate control register, divided by 4 */
|
|
addr = 0x01c05000;
|
|
write32(addr + SPI_CCR, 0x00001001);
|
|
|
|
/* Enable spi0 and do a soft reset */
|
|
addr = 0x01c05000;
|
|
val = read32(addr + SPI_GCR);
|
|
val |= (1 << 31) | (1 << 7) | (1 << 1) | (1 << 0);
|
|
write32(addr + SPI_GCR, val);
|
|
while(read32(addr + SPI_GCR) & (1 << 31));
|
|
|
|
val = read32(addr + SPI_TCR);
|
|
val &= ~(0x3 << 0);
|
|
val |= (1 << 6) | (1 << 2);
|
|
write32(addr + SPI_TCR, val);
|
|
|
|
val = read32(addr + SPI_FCR);
|
|
val |= (1 << 31) | (1 << 15);
|
|
write32(addr + SPI_FCR, val);
|
|
}
|
|
|
|
void sys_spi_flash_exit(void)
|
|
{
|
|
virtual_addr_t addr = 0x01c05000;
|
|
uint32_t val;
|
|
|
|
/* Disable the spi0 controller */
|
|
val = read32(addr + SPI_GCR);
|
|
val &= ~((1 << 1) | (1 << 0));
|
|
write32(addr + SPI_GCR, val);
|
|
}
|
|
|
|
static void sys_spi_select(void)
|
|
{
|
|
virtual_addr_t addr = 0x01c05000;
|
|
uint32_t val;
|
|
|
|
val = read32(addr + SPI_TCR);
|
|
val &= ~((0x3 << 4) | (0x1 << 7));
|
|
val |= ((0 & 0x3) << 4) | (0x0 << 7);
|
|
write32(addr + SPI_TCR, val);
|
|
}
|
|
|
|
static void sys_spi_deselect(void)
|
|
{
|
|
virtual_addr_t addr = 0x01c05000;
|
|
uint32_t val;
|
|
|
|
val = read32(addr + SPI_TCR);
|
|
val &= ~((0x3 << 4) | (0x1 << 7));
|
|
val |= ((0 & 0x3) << 4) | (0x1 << 7);
|
|
write32(addr + SPI_TCR, val);
|
|
}
|
|
|
|
static void sys_spi_write_txbuf(uint8_t * buf, int len)
|
|
{
|
|
virtual_addr_t addr = 0x01c05000;
|
|
int i;
|
|
|
|
if(!buf)
|
|
len = 0;
|
|
|
|
write32(addr + SPI_MTC, len & 0xffffff);
|
|
write32(addr + SPI_BCC, len & 0xffffff);
|
|
for(i = 0; i < len; ++i)
|
|
write8(addr + SPI_TXD, *buf++);
|
|
}
|
|
|
|
static int sys_spi_transfer(void * txbuf, void * rxbuf, int len)
|
|
{
|
|
virtual_addr_t addr = 0x01c05000;
|
|
int count = len;
|
|
uint8_t * tx = txbuf;
|
|
uint8_t * rx = rxbuf;
|
|
uint8_t val;
|
|
unsigned int n, i;
|
|
|
|
while(count > 0)
|
|
{
|
|
n = (count <= 64) ? count : 64;
|
|
write32(addr + SPI_MBC, n);
|
|
sys_spi_write_txbuf(tx, n);
|
|
write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31));
|
|
|
|
while((read32(addr + SPI_FSR) & 0xff) < n);
|
|
for(i = 0; i < n; i++)
|
|
{
|
|
val = read8(addr + SPI_RXD);
|
|
if(rx)
|
|
*rx++ = val;
|
|
}
|
|
|
|
if(tx)
|
|
tx += n;
|
|
count -= n;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static int sys_spi_write_then_read(void * txbuf, int txlen, void * rxbuf, int rxlen)
|
|
{
|
|
if(sys_spi_transfer(txbuf, NULL, txlen) != txlen)
|
|
return -1;
|
|
if(sys_spi_transfer(NULL, rxbuf, rxlen) != rxlen)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void sys_spi_flash_read(int addr, void * buf, int count)
|
|
{
|
|
uint8_t tx[4];
|
|
|
|
tx[0] = 0x03;
|
|
tx[1] = (uint8_t)(addr >> 16);
|
|
tx[2] = (uint8_t)(addr >> 8);
|
|
tx[3] = (uint8_t)(addr >> 0);
|
|
sys_spi_select();
|
|
sys_spi_write_then_read(tx, 4, buf, count);
|
|
sys_spi_deselect();
|
|
}
|