Skip to content

Commit

Permalink
plat-rz: g2l: Add SPI flash write driver
Browse files Browse the repository at this point in the history
  • Loading branch information
takunoriotsuka committed Aug 8, 2023
1 parent 7c48d90 commit 86a4f20
Show file tree
Hide file tree
Showing 22 changed files with 2,049 additions and 1 deletion.
112 changes: 112 additions & 0 deletions core/arch/arm/plat-rz/g2l/drivers/cpg.c
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);
12 changes: 12 additions & 0 deletions core/arch/arm/plat-rz/g2l/drivers/cpg.h
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_ */
707 changes: 707 additions & 0 deletions core/arch/arm/plat-rz/g2l/drivers/cpg_regs.h

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions core/arch/arm/plat-rz/g2l/drivers/sflash.c
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);
14 changes: 14 additions & 0 deletions core/arch/arm/plat-rz/g2l/drivers/sflash.h
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_ */
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);
}
}
Loading

0 comments on commit 86a4f20

Please sign in to comment.