-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
plat-rz: g2l: Add SPI flash write driver
- Loading branch information
1 parent
7c48d90
commit 86a4f20
Showing
22 changed files
with
2,049 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* Copyright (c) 2023, Renesas Electronics Corporation. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <assert.h> | ||
#include <io.h> | ||
#include <initcall.h> | ||
#include <mm/core_memprot.h> | ||
#include <platform_config.h> | ||
#include <cpg.h> | ||
#include <cpg_regs.h> | ||
|
||
#define CPG_T_CLK (0) | ||
#define CPG_T_RST (1) | ||
|
||
typedef struct { | ||
uintptr_t reg; | ||
uintptr_t mon; | ||
uint32_t val; | ||
uint32_t type; | ||
} st_cpg_clkrst_t; | ||
|
||
register_phys_mem_pgdir(MEM_AREA_IO_NSEC, CPG_REG_BASE, CPG_REG_SIZE); | ||
|
||
static vaddr_t cpg_base; | ||
|
||
inline static void cpg_io_write(uint32_t reg, uint32_t data) | ||
{ | ||
io_write32(cpg_base + reg, data); | ||
} | ||
|
||
inline static uint32_t cpg_io_read(uint32_t reg) | ||
{ | ||
return io_read32(cpg_base + reg); | ||
} | ||
|
||
static const st_cpg_clkrst_t cpg_spi_multi[] = { | ||
{ | ||
(uintptr_t)CPG_CLKON_SPI_MULTI, | ||
(uintptr_t)CPG_CLKMON_SPI_MULTI, | ||
0x00030003, | ||
CPG_T_CLK | ||
}, | ||
{ | ||
(uintptr_t)CPG_RST_SPI, | ||
(uintptr_t)CPG_RSTMON_SPI, | ||
0x00010001, | ||
CPG_T_RST | ||
} | ||
}; | ||
|
||
static void cpg_clkrst_start(const st_cpg_clkrst_t *tbl, const uint32_t size) | ||
{ | ||
uint32_t cnt; | ||
uint32_t mask; | ||
uint32_t cmp; | ||
|
||
for (cnt = 0; cnt < size; cnt++, tbl++) { | ||
cpg_io_write(tbl->reg, tbl->val); | ||
|
||
mask = (tbl->val >> 16) & 0xFFFF; | ||
cmp = tbl->val & 0xFFFF; | ||
if (tbl->type == CPG_T_RST) { | ||
cmp = ~(cmp); | ||
} | ||
while ((cpg_io_read(tbl->mon) & mask) != (cmp & mask)) | ||
; | ||
} | ||
} | ||
|
||
static void cpg_clkrst_stop(const st_cpg_clkrst_t *tbl, const uint32_t size) | ||
{ | ||
uint32_t cnt; | ||
uint32_t mask; | ||
uint32_t cmp; | ||
|
||
for (cnt = 0; cnt < size; cnt++, tbl++) { | ||
cpg_io_write(tbl->reg, tbl->val & 0xFFFF0000); | ||
|
||
mask = (tbl->val >> 16) & 0xFFFF; | ||
cmp = 0; | ||
if (tbl->type == CPG_T_RST) { | ||
cmp = ~(cmp); | ||
} | ||
while ((cpg_io_read(tbl->mon) & mask) != (cmp & mask)) | ||
; | ||
} | ||
} | ||
|
||
void cpg_spi_multi_start(void) | ||
{ | ||
cpg_clkrst_start(cpg_spi_multi, ARRAY_SIZE(cpg_spi_multi)); | ||
cpg_io_write(CPG_BUS_MCPU1_MSTOP, 0x00020000); | ||
} | ||
|
||
void cpg_spi_multi_stop(void) | ||
{ | ||
cpg_clkrst_stop(cpg_spi_multi, ARRAY_SIZE(cpg_spi_multi)); | ||
cpg_io_write(CPG_BUS_MCPU1_MSTOP, 0x00020002); | ||
} | ||
|
||
static TEE_Result cpg_init(void) | ||
{ | ||
cpg_base = (vaddr_t)phys_to_virt_io(CPG_REG_BASE, CPG_REG_SIZE); | ||
|
||
return TEE_SUCCESS; | ||
} | ||
|
||
driver_init(cpg_init); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* Copyright (c) 2023, Renesas Electronics Corporation. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
#ifndef _CPG_H_ | ||
#define _CPG_H_ | ||
|
||
extern void cpg_spi_multi_start(void); | ||
extern void cpg_spi_multi_stop(void); | ||
|
||
#endif /* _CPG_H_ */ |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
* Copyright (c) 2023, Renesas Electronics Corporation. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <string.h> | ||
#include <io.h> | ||
#include <initcall.h> | ||
#include <mm/core_memprot.h> | ||
#include <platform_config.h> | ||
#include <cpg.h> | ||
#include <sflash.h> | ||
#include <spi_multi.h> | ||
#include <spi_multi_regs.h> | ||
#include <spi_multi_reg_values.h> | ||
|
||
register_phys_mem_pgdir(MEM_AREA_IO_NSEC, SPI_FLASH_BASE, SPI_FLASH_SIZE); | ||
|
||
static vaddr_t sflash_base; | ||
static uint32_t sflash_work[SPI_SECTOR_SIZE / sizeof(uint32_t)]; | ||
|
||
static vaddr_t sflash_phys_to_virt(uint32_t addr) | ||
{ | ||
return (vaddr_t)(sflash_base + (addr & 0x00FFFFFF)); | ||
} | ||
|
||
static void sflash_page_program(uint32_t addr, uintptr_t buff, size_t len) | ||
{ | ||
for (size_t i = 0; i < len; i += SPI_PAGE_SIZE) | ||
spi_multi_page_program(addr + i, buff + i); | ||
|
||
spi_multi_setup(); | ||
} | ||
|
||
static void sflash_sector_erase(uint32_t addr, size_t len) | ||
{ | ||
for (size_t i = 0; i < len; i += SPI_SECTOR_SIZE) | ||
spi_multi_erase_sector(addr + i); | ||
|
||
spi_multi_setup(); | ||
} | ||
|
||
void sflash_write_buffer(uint32_t addr, uintptr_t buff, size_t len) | ||
{ | ||
uintptr_t sflash_work_base = (uintptr_t)&sflash_work[0]; | ||
uintptr_t base_sector_addr = ROUNDDOWN(addr, SPI_SECTOR_SIZE); | ||
uintptr_t last_sector_addr = ROUNDDOWN(addr + len - 1, SPI_SECTOR_SIZE); | ||
uint32_t write_offset; | ||
uint32_t write_length; | ||
int32_t secotr_count; | ||
|
||
secotr_count = ((last_sector_addr - base_sector_addr) / SPI_SECTOR_SIZE) + 1; | ||
write_offset = addr - base_sector_addr; | ||
write_length = MIN(len, SPI_SECTOR_SIZE - write_offset); | ||
|
||
if (write_offset != 0) { | ||
|
||
vaddr_t virt_addr = sflash_phys_to_virt(base_sector_addr); | ||
|
||
memcpy((void *)sflash_work_base, (void *)virt_addr, SPI_SECTOR_SIZE); | ||
|
||
memcpy((void *)(sflash_work_base + write_offset), (void *)buff, write_length); | ||
|
||
sflash_sector_erase(base_sector_addr, SPI_SECTOR_SIZE); | ||
|
||
sflash_page_program(base_sector_addr, sflash_work_base, SPI_SECTOR_SIZE); | ||
|
||
base_sector_addr += SPI_SECTOR_SIZE; | ||
|
||
secotr_count--; | ||
} | ||
|
||
write_length = (addr + len) - last_sector_addr; | ||
|
||
if ((secotr_count > 0) && ((write_length % SPI_SECTOR_SIZE) > 0)) { | ||
|
||
vaddr_t virt_addr = sflash_phys_to_virt(last_sector_addr); | ||
|
||
memcpy((void *)sflash_work_base, (void *)virt_addr, SPI_SECTOR_SIZE); | ||
|
||
memcpy((void *)sflash_work_base, (void *)((buff + len) - write_length), write_length); | ||
|
||
sflash_sector_erase(last_sector_addr, SPI_SECTOR_SIZE); | ||
|
||
sflash_page_program(last_sector_addr, sflash_work_base, SPI_SECTOR_SIZE); | ||
|
||
secotr_count--; | ||
} | ||
|
||
write_length = secotr_count * SPI_SECTOR_SIZE; | ||
|
||
if(secotr_count > 0) { | ||
|
||
sflash_sector_erase(base_sector_addr, write_length); | ||
|
||
sflash_page_program(base_sector_addr, buff + (base_sector_addr - addr), write_length); | ||
} | ||
} | ||
|
||
void sflash_open(void) | ||
{ | ||
cpg_spi_multi_start(); | ||
|
||
spi_multi_setup(); | ||
} | ||
|
||
void sflash_close(void) | ||
{ | ||
cpg_spi_multi_stop(); | ||
} | ||
|
||
static TEE_Result sflash_init(void) | ||
{ | ||
sflash_base = (vaddr_t)phys_to_virt_io(SPI_FLASH_BASE, SPI_FLASH_SIZE); | ||
|
||
return TEE_SUCCESS; | ||
} | ||
|
||
driver_init(sflash_init); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright (c) 2023, Renesas Electronics Corporation. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
#ifndef _SFLASH_H_ | ||
#define _SFLASH_H_ | ||
|
||
extern void sflash_open(void); | ||
extern void sflash_close(void); | ||
extern void sflash_write_buffer(uint32_t addr, uintptr_t buff, size_t len); | ||
|
||
#endif /* _SFLASH_H_ */ |
65 changes: 65 additions & 0 deletions
65
core/arch/arm/plat-rz/g2l/drivers/spi_multi/AT25QL128A/spi_multi_device.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright (c) 2020-2023, Renesas Electronics Corporation. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <io.h> | ||
#include <kernel/delay.h> | ||
#include <spi_multi.h> | ||
#include <spi_multi_regs.h> | ||
#include <spi_multi_reg_values.h> | ||
#include <spi_multi_device.h> | ||
|
||
void spi_multi_setup_device(void) | ||
{ | ||
uint32_t val; | ||
uint8_t read_status; | ||
|
||
spi_io_write(SPIM_PHYOFFSET1, SPIM_PHYOFFSET1_SET_VALUE); | ||
spi_io_write(SPIM_PHYOFFSET2, SPIM_PHYOFFSET2_SET_VALUE); | ||
spi_multi_timing_set(); | ||
|
||
/* Set Data read option */ | ||
/* Required when command 0xEB is specified. | ||
* Not required when a command other than is specified, | ||
* but there is no problem in operation. | ||
*/ | ||
val = SPIM_DROPR_SET_VALUE; | ||
spi_io_write(SPIM_DROPR, val); | ||
|
||
read_status = spi_multi_cmd_read(SMCMR_CMD_READ_STATUS_REGISTER_2); | ||
if ((read_status & STATUS_2_QE) == STATUS_2_QE) { | ||
return; | ||
} | ||
/* Write Enable Command */ | ||
spi_multi_cmd_write(SMCMR_CMD_WRITE_ENABLE, SPI_MANUAL_COMMAND_SIZE_0, 0); | ||
/* Write Status Register-2 Command Quad Enable */ | ||
val = ((STATUS_2_QE | read_status) << SMWDR0_1BYTE_DATA_BIT_SHIFT); | ||
spi_multi_cmd_write(SMCMR_CMD_WRITE_STATUS_REGISTER_2, SPI_MANUAL_COMMAND_SIZE_8_BIT, val); | ||
/* status 1 BUSY check */ | ||
while (1) { | ||
read_status = spi_multi_cmd_read(SMCMR_CMD_READ_STATUS_REGISTER_1); | ||
if ((read_status & STATUS_1_BUSY_BIT) == STATUS_1_BUSY) { | ||
udelay(STATUS_BUSY_READ_DELAY_TIME); | ||
continue; | ||
} else { | ||
break; | ||
} | ||
} | ||
return; | ||
} | ||
|
||
void spi_multi_busy_wait(void) | ||
{ | ||
while(1) { | ||
|
||
uint8_t read_status = spi_multi_cmd_read(SMCMR_CMD_READ_STATUS_REGISTER_1); | ||
|
||
if ((read_status & STATUS_1_BUSY_BIT) != STATUS_1_BUSY) | ||
break; | ||
|
||
udelay(STATUS_BUSY_READ_DELAY_TIME); | ||
} | ||
} |
Oops, something went wrong.