Files
rtl8710_openocd/spi_flash.c
2016-08-22 21:28:14 +03:00

147 lines
4.8 KiB
C

/*
*
* Copyright (C) 2016 Rebane, rebane@alkohol.ee
*
* 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., 51 Franklin
* Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "spi_flash.h"
#include "rtl8710.h"
#include "mask.h"
static void spi_flash_send(uint8_t byte){
// while(!(SPI_FLASH->SR & SPI_SR_TFNF));
SPI_FLASH->DR = byte;
}
static uint8_t spi_flash_recv(){
while(!(SPI_FLASH->RXFLR & 0x0FFF));
return(SPI_FLASH->DR);
}
void spi_flash_init(){
PERI_ON->PESOC_CLK_CTRL |= PERI_ON_CLK_CTRL_ACTCK_FLASH_EN | PERI_ON_CLK_CTRL_SLPCK_FLASH_EN; // enable spi flash peripheral clock
PERI_ON->SOC_FUNC_EN |= PERI_ON_SOC_FUNC_EN_FLASH; // enable spi flash peripheral
mask32_set(PERI_ON->CPU_PERIPHERAL_CTRL, PERI_ON_CPU_PERIPHERAL_CTRL_SPI_FLASH_PIN_SEL, 0); // select spi flash pinout (0 - internal)
PERI_ON->CPU_PERIPHERAL_CTRL |= PERI_ON_CPU_PERIPHERAL_CTRL_SPI_FLASH_PIN_EN; // enable spi flash pins
SPI_FLASH->SSIENR = 0; // disable SPI FLASH operation
SPI_FLASH->IMR = 0; // disable all interrupts
SPI_FLASH->SER = SPI_SER_SS0; // use first "slave select" pin
SPI_FLASH->BAUDR = 2; // baud rate, default value
SPI_FLASH->TXFTLR = 0; // tx fifo threshold
SPI_FLASH->RXFTLR = 0; // rx fifo threshold
SPI_FLASH->DMACR = 0; // disable DMA
}
uint16_t spi_flash_read(uint32_t address, void *buf, uint16_t count){
uint16_t i;
if(!count)return(0);
if(count > 16)count = 16;
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 3) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->CTRLR1 = count;
spi_flash_send(0x03); // flash command "read"
spi_flash_send((address >> 16) & 0xFF); // address * 3
spi_flash_send((address >> 8) & 0xFF);
spi_flash_send((address >> 0) & 0xFF);
SPI_FLASH->SSIENR = 1;
for(i = 0; i < count; i++){
((uint8_t *)buf)[i] = spi_flash_recv();
}
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
return(count);
}
uint32_t spi_flash_jedec_id(){
uint32_t id;
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 3) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->CTRLR1 = 3;
SPI_FLASH->SSIENR = 1;
spi_flash_send(0x9F); // jedec id
id = spi_flash_recv();
id |= ((uint32_t)spi_flash_recv() << 8);
id |= ((uint32_t)spi_flash_recv() << 16);
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
return(id);
}
uint8_t spi_flash_status(){
uint8_t status;
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 3) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->CTRLR1 = 1;
SPI_FLASH->SSIENR = 1;
spi_flash_send(0x05); // read status
status = spi_flash_recv();
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
return(status);
}
void spi_flash_cmd(uint8_t cmd){
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 1) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->SSIENR = 1;
spi_flash_send(cmd);
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
}
void spi_flash_sector_erase(uint32_t address){
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 1) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->SSIENR = 1;
spi_flash_send(0x20); // sector erase
spi_flash_send((address >> 16) & 0xFF);
spi_flash_send((address >> 8) & 0xFF);
spi_flash_send((address >> 0) & 0xFF);
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
}
uint16_t spi_flash_write(uint32_t address, const void *buf, uint16_t count){
uint16_t i;
if(!count)return(0);
if(count > 256)count = 256;
SPI_FLASH->CTRLR0 = mask32(SPI_CTRLR0_TMOD, 1) | mask32(SPI_CTRLR0_CMD_CH, 0) | mask32(SPI_CTRLR0_ADDR_CH, 0) | mask32(SPI_CTRLR0_DATA_CH, 0);
SPI_FLASH->SSIENR = 1;
spi_flash_send(0x02); // write
spi_flash_send((address >> 16) & 0xFF);
spi_flash_send((address >> 8) & 0xFF);
spi_flash_send((address >> 0) & 0xFF);
for(i = 0; i < count; i++){
spi_flash_send(((uint8_t *)buf)[i]);
}
while(!(SPI_FLASH->SR & SPI_SR_TFE));
while(SPI_FLASH->SR & SPI_SR_SSI);
SPI_FLASH->SSIENR = 0;
return(count);
}
void spi_flash_wait_busy(){
while(spi_flash_status() & 0x01);
}
void spi_flash_wait_wel(){
while(!(spi_flash_status() & 0x02));
}