mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/modem/shmem_save.cpp

350 lines
11 KiB
C++

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "mbed.h"
#include "shmem_save.h"
#include "modem_io_device.h"
#include "s5js100_pwr.h"
#include "sflash_api.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define FLASH_CS_BASE_OLD 0x40EAA000
#define FLASH_NV_BASE_OLD 0x40E47000
#define FLASH_CAL_BASE_OLD 0x40E87000
#define FLASH_CS_BASE 0x4059B000
#define FLASH_NV_BASE 0x4055B000
#define FLASH_CAL_BASE 0x4001B000
#define FLASH_CS_SIZE (1024 * 300)
#define FLASH_NV_SIZE (1024 * 256)
#define FLASH_CAL_SIZE (1024 * 128)
#define REQ_CS_MSG 0x0000A20B
#define REQ_NV_MSG 0x0000A21B
#define REQ_CAL_MSG 0x0000A22B
#define BUFFER_SIZE 256
#define SFLASH_SECTOR_SIZE 256
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
static ModemIoDevice *shmem_mio;
static unsigned int cur_save_target;
static unsigned char *save_cached;
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
extern int nbsleep_req;
unsigned int g_flash_cs_base;
unsigned int g_flash_nv_base;
unsigned int g_flash_cal_base;
unsigned int g_flash_cs_size = FLASH_CS_SIZE;
unsigned int g_flash_nv_size = FLASH_NV_SIZE;
unsigned int g_flash_cal_size = FLASH_CAL_SIZE;
/****************************************************************************
* Private Functions
****************************************************************************/
#define SHMEM_SECTION_MAGIC (0x06313184)
typedef struct {
unsigned int magic0;
unsigned int version;
unsigned int start;
unsigned int magic1;
} shmem_section_data;
static shmem_section_data next_shmem_section[3] = {
{SHMEM_SECTION_MAGIC, 1, g_flash_cs_base + (48 * 1024), SHMEM_SECTION_MAGIC},
{SHMEM_SECTION_MAGIC, 1, g_flash_nv_base + (48 * 1024), SHMEM_SECTION_MAGIC},
{SHMEM_SECTION_MAGIC, 1, g_flash_cal_base + (48 * 1024), SHMEM_SECTION_MAGIC},
};
static shmem_section_data *find_section_data(unsigned int start, unsigned int size)
{
unsigned int a, max;
shmem_section_data *d, *m;
max = 0;
m = NULL;
for (a = start; a < start + size; a += 0x1000) {
d = (shmem_section_data *)(a + 0x1000 - sizeof(shmem_section_data));
if (d->magic0 != 0x06313184 || d->magic1 != 0x06313184) {
continue;
}
if (d->version > max) {
max = d->version;
m = d;
}
}
return m;
}
extern uint32_t s5js100_sflash_read_capacity(void);
void shmem_get_data(unsigned int *cs, unsigned int *nv, unsigned int *cal)
{
struct {
unsigned int start;
unsigned int size;
} section[3];
unsigned int i;
shmem_section_data *m;
unsigned int ret[3] = {0, 0, 0};
//unsigned int FLASH16MB = 0, oldstart, oldsize;
//unsigned int psize, poffset;
//unsigned char *tmpbuf;
//shmem_section_data *tmpsection;
//initialize SHMEM section depending on FLASH capacity
if (s5js100_sflash_read_capacity() == 16 * 1024 * 1024) {
g_flash_cs_base = FLASH_CS_BASE_OLD;
g_flash_nv_base = FLASH_NV_BASE_OLD;
g_flash_cal_base = FLASH_CAL_BASE_OLD;
} else if (s5js100_sflash_read_capacity() == 8 * 1024 * 1024) {
g_flash_cs_base = FLASH_CS_BASE;
g_flash_nv_base = FLASH_NV_BASE;
g_flash_cal_base = FLASH_CAL_BASE;
} else {
mbed_error_printf("no support FLASH size..\n");
}
section[0].start = g_flash_cs_base;
section[1].start = g_flash_nv_base;
section[2].start = g_flash_cal_base;
section[0].size = g_flash_cs_size;
section[1].size = g_flash_nv_size;
section[2].size = g_flash_cal_size;
for (i = 0; i < 3; i++) {
m = find_section_data(section[i].start, section[i].size);
if (m == NULL) {
ret[i] = section[i].start;
next_shmem_section[i].start = section[i].start + (48 * 1024);
} else {
ret[i] = m->start;
next_shmem_section[i].start = (unsigned int)m + sizeof(shmem_section_data);
next_shmem_section[i].version = m->version + 1;
}
}
*cs = ret[0];
*nv = ret[1];
*cal = ret[2];
}
int shmem_data_save(unsigned int msg, uint8_t *buffer, uint16_t real_len, uint32_t t_size, uint32_t s_size)
{
unsigned int flash_start_addr;
unsigned int offset;
unsigned int poffset;
unsigned int psize;
unsigned char *buf;
unsigned int cached_size;
unsigned int wlen;
unsigned int wsize;
unsigned int section_idx;
switch (msg) {
case REQ_CS_MSG:
section_idx = 0;
if (next_shmem_section[0].start + t_size + sizeof(shmem_section_data) < g_flash_cs_base + FLASH_CS_SIZE) {
flash_start_addr = next_shmem_section[0].start;
} else {
flash_start_addr = g_flash_cs_base;
}
next_shmem_section[0].start = flash_start_addr;
break;
case REQ_NV_MSG:
section_idx = 1;
if (next_shmem_section[1].start + t_size + sizeof(shmem_section_data) < g_flash_nv_base + FLASH_NV_SIZE) {
flash_start_addr = next_shmem_section[1].start;
} else {
flash_start_addr = g_flash_nv_base;
}
next_shmem_section[1].start = flash_start_addr;
break;
case REQ_CAL_MSG:
section_idx = 2;
if (next_shmem_section[2].start + t_size + sizeof(shmem_section_data) < g_flash_cal_base + FLASH_CAL_SIZE) {
flash_start_addr = next_shmem_section[2].start;
} else {
flash_start_addr = g_flash_cal_base;
}
next_shmem_section[2].start = flash_start_addr;
break;
default:
return -1;
}
psize = up_progmem_blocksize();
offset = s_size;
cached_size = s_size & (psize - 1);
wlen = 0;
while (1) {
wsize = (real_len - wlen + cached_size > psize) ? psize - cached_size : real_len - wlen;
if (wsize != psize) {
memcpy(save_cached + cached_size, buffer + wlen, wsize);
buf = save_cached;
} else {
buf = buffer + wlen;
}
cached_size += wsize;
wlen += wsize;
poffset = (offset / psize) * psize;
offset += wsize;
if (cached_size != psize) {
break;
}
cached_size = 0;
sflash_erase(flash_start_addr + poffset);
sflash_write(flash_start_addr + poffset, buf, psize);
}
if (real_len + s_size >= t_size) {
poffset = (offset / psize) * psize;
if (cached_size + sizeof(shmem_section_data) <= psize) {
memcpy(save_cached + 0xFF0, (unsigned char *)(&(next_shmem_section[section_idx])), 0x10);
sflash_erase(flash_start_addr + poffset);
sflash_write(flash_start_addr + poffset, save_cached, psize);
} else {
sflash_erase(flash_start_addr + poffset);
sflash_write(flash_start_addr + poffset, save_cached, cached_size);
memcpy(save_cached + 0xFF0, (unsigned char *)(&(next_shmem_section[section_idx])), 0x10);
sflash_erase(flash_start_addr + poffset + psize);
sflash_write(flash_start_addr + poffset, save_cached, psize);
}
}
return 0;
}
void shmem_factory_reset(void)
{
unsigned int flash_start_addr;
unsigned int poffset = 0;
/* erase NV */
flash_start_addr = g_flash_nv_base;
for (poffset = 0; poffset < 64; poffset++) {
sflash_erase(flash_start_addr + poffset * 4096);
}
/* erase CS */
flash_start_addr = g_flash_cs_base;
for (poffset = 0; poffset < 75; poffset++) {
sflash_erase(flash_start_addr + poffset * 4096);
}
}
void shmem_save_read_cb(mio_buf *buf, void *data);
void shmem_initiate_cb(mio_buf *buf, void *data)
{
save_cached = (unsigned char *)malloc(4096);
shmem_mio->register_ReadCb(shmem_save_read_cb, NULL);
shmem_mio->write((char *)(&cur_save_target), 4);
free_mio_buf(buf);
}
void shmem_save_read_cb(mio_buf *buf, void *data)
{
uint16_t msg_len;
uint32_t remain_len, real_len;
uint8_t *buffer = (uint8_t *)(buf->data);
uint32_t total_size, sent_size;
unsigned long long nbsleep_sec;
msg_len = *(uint16_t *)(buffer + 2);
if (msg_len != 0) {
real_len = msg_len - 8;
total_size = *(uint32_t *)(buffer + 4);
sent_size = *(uint32_t *)(buffer + 8);
remain_len = *(uint32_t *)(buffer + 4) - *(uint32_t *)(buffer + 8);
shmem_data_save(cur_save_target, buffer + 12, real_len, total_size, sent_size);
} else {
remain_len = 0;
real_len = 0;
}
free_mio_buf(buf);
if (remain_len == real_len) {
if (cur_save_target == REQ_CAL_MSG) {
free(save_cached);
cur_save_target = REQ_CS_MSG;
shmem_mio->register_ReadCb(shmem_initiate_cb, NULL);
nbsleep_req = 1;
nbsleep_sec = ((((unsigned long long)(getreg32(0x81000000 + 0xE4))) << 32) + getreg32(0x81000000 + 0xE8)) / 32768;
}
cur_save_target += 0x10;
if (cur_save_target > REQ_CAL_MSG) {
cur_save_target = REQ_CS_MSG;
shmem_mio->register_ReadCb(shmem_initiate_cb, NULL);
}
}
shmem_mio->write((char *)(&cur_save_target), 4);
}
extern "C" {
void shmem_save_init(void)
{
char mio_name[32] = "shmem_save";
cur_save_target = REQ_CS_MSG;
shmem_mio = getModemIoDeviceByName(mio_name);
shmem_mio->register_ReadCb(shmem_initiate_cb, NULL);
}
void shmem_save_stop(void)
{
}
}