Newer
Older
mbed-os / features / netsocket / emac-drivers / TARGET_RDA_EMAC / lwip-wifi / arch / TARGET_RDA / TARGET_UNO_91H / src / wland_flash_wp.c
/* Copyright (c) 2019 Unisoc Communications Inc.
 * 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.
 */

#include "mbed_interface.h"
#include "wland_flash.h"

//#define FLASH_PROTECT_ENABLE

#define FLASH_CTL_REG_BASE              0x17fff000
#define FLASH_CTL_TX_CMD_ADDR_REG       (FLASH_CTL_REG_BASE + 0x00)
#define FLASH_CTL_TX_BLOCK_SIZE_REG     (FLASH_CTL_REG_BASE + 0x04)
#define FLAHS_CTL_TX_FIFO_DATA_REG      (FLASH_CTL_REG_BASE + 0x08)
#define FLASH_CTL_STATUS_REG            (FLASH_CTL_REG_BASE + 0x0c)
#define FLAHS_CTL_RX_FIFO_DATA_REG      (FLASH_CTL_REG_BASE + 0x10)

#define WRITE_REG32(REG, VAL) ((*(volatile unsigned int*)(REG)) = (unsigned int)(VAL))
#define WRITE_REG8(REG, VAL) ((*(volatile unsigned char*)(REG)) = (unsigned char)(VAL))
#define MREAD_WORD(addr)      *((volatile unsigned int *)(addr))

#define MID_GD      0xC8
#define MID_WINBOND 0xEF

#define FLASH_1M    0x100000
#define FLASH_2M    0x200000
#define FLASH_4M    0x400000
extern unsigned int flash_size;

#ifdef FLASH_PROTECT_ENABLE

#define FLASH_WP_MASK           0x407c
#define FLASH_WP_NONE           0x0000
#define FLASH_WP_ALL            0x1c

#define FLASH_4M_WP_4K          0x0064
#define FLASH_4M_WP_8K          0x0068
#define FLASH_4M_WP_16K         0x006c
#define FLASH_4M_WP_32K         0x0070
#define FLASH_4M_WP_1_64        0x0024
#define FLASH_4M_WP_1_32        0x0028
#define FLASH_4M_WP_1_16        0x002c
#define FLASH_4M_WP_1_8         0x0030
#define FLASH_4M_WP_1_4         0x0034
#define FLASH_4M_WP_1_2         0x0038
#define FLASH_4M_WP_3_4         0x4014
#define FLASH_4M_WP_7_8         0x4010
#define FLASH_4M_WP_15_16       0x400c
#define FLASH_4M_WP_31_32       0x4008
#define FLASH_4M_WP_63_64       0x4004
#define FLASH_4M_WP_127_128     0x4058
#define FLASH_4M_WP_255_256     0x404C
#define FLASH_4M_WP_1023_1024   0x4044

#define FLASH_2M_WP_4K          0x0064
#define FLASH_2M_WP_8K          0x0068
#define FLASH_2M_WP_16K         0x006c
#define FLASH_2M_WP_32K         0x0070
#define FLASH_2M_WP_1_32        0x0024
#define FLASH_2M_WP_1_16        0x0028
#define FLASH_2M_WP_1_8         0x002c
#define FLASH_2M_WP_1_4         0x0050
#define FLASH_2M_WP_1_2         0x0051
#define FLASH_2M_WP_3_4         0x4010
#define FLASH_2M_WP_7_8         0x400c
#define FLASH_2M_WP_15_16       0x4004
#define FLASH_2M_WP_31_32       0x4000
#define FLASH_2M_WP_63_64       0x4050
#define FLASH_2M_WP_127_128     0x404c
#define FLASH_2M_WP_255_256     0x4048
#define FLASH_2M_WP_511_512     0x4044


#define FLASH_1M_WP_4K          0x0064
#define FLASH_1M_WP_8K          0x0068
#define FLASH_1M_WP_16K         0x006c
#define FLASH_1M_WP_32K         0x0070
#define FLASH_1M_WP_1_16        0x0024
#define FLASH_1M_WP_1_8         0x0028
#define FLASH_1M_WP_1_4         0x002c
#define FLASH_1M_WP_1_2         0x0050
#define FLASH_1M_WP_3_4         0x400C
#define FLASH_1M_WP_7_8         0x4008
#define FLASH_1M_WP_15_16       0x4004
#define FLASH_1M_WP_31_32       0x4050
#define FLASH_1M_WP_63_64       0x404C
#define FLASH_1M_WP_127_128     0x4048
#define FLASH_1M_WP_255_256     0x4044

static unsigned short flash_wrtie_protect_4M(unsigned short status, unsigned int offset)
{
    unsigned int wp = FLASH_WP_NONE;
    if (offset >= flash_size - flash_size/1024) {
        wp = FLASH_4M_WP_1023_1024;
    } else if(offset >= flash_size - flash_size/256) {
        wp = FLASH_4M_WP_255_256;
    } else if(offset >= flash_size - flash_size/128) {
        wp = FLASH_4M_WP_127_128;
    } else if(offset >= flash_size - flash_size/64) {
        wp = FLASH_4M_WP_63_64;
    } else if(offset >= flash_size - flash_size/32) {
        wp = FLASH_4M_WP_31_32;
    } else if(offset >= flash_size - flash_size/16) {
        wp = FLASH_4M_WP_15_16;
    } else if(offset >= flash_size - flash_size/8) {
        wp = FLASH_4M_WP_7_8;
    } else if(offset >= flash_size - flash_size/4) {
        wp = FLASH_4M_WP_3_4;
    } else if(offset >= flash_size/2) {
        wp = FLASH_4M_WP_1_2;
    } else if(offset >= flash_size/4) {
        wp = FLASH_4M_WP_1_4;
    } else if(offset >= flash_size/8) {
        wp = FLASH_4M_WP_1_8;
    } else if(offset >= flash_size/16) {
        wp = FLASH_4M_WP_1_16;
    } else if(offset >= flash_size/32) {
        wp = FLASH_4M_WP_1_32;
    } else if(offset >= flash_size/64) {
        wp = FLASH_4M_WP_1_64;
    } else if(offset >= 32 * 1024) {
        wp = FLASH_4M_WP_32K;
    } else if(offset >= 16 * 1024) {
        wp = FLASH_4M_WP_16K;
    } else if(offset >= 8 * 1024) {
        wp = FLASH_4M_WP_8K;
    } else if(offset >= 4 * 1024) {
        wp = FLASH_4M_WP_4K;
    }

    return (status & ~FLASH_WP_MASK) | wp;
    
}

static unsigned short flash_wrtie_protect_2M(unsigned short status, unsigned int offset)
{
    unsigned int wp = FLASH_WP_NONE;
    if (offset >= flash_size - flash_size/256) {
        wp = FLASH_2M_WP_255_256;
    } else if(offset >= flash_size - flash_size/128) {
        wp = FLASH_2M_WP_127_128;
    } else if(offset >= flash_size - flash_size/64) {
        wp = FLASH_2M_WP_63_64;
    } else if(offset >= flash_size - flash_size/32) {
        wp = FLASH_2M_WP_31_32;
    } else if(offset >= flash_size - flash_size/16) {
        wp = FLASH_2M_WP_15_16;
    } else if(offset >= flash_size - flash_size/8) {
        wp = FLASH_2M_WP_7_8;
    } else if(offset >= flash_size - flash_size/4) {
        wp = FLASH_2M_WP_3_4;
    } else if(offset >= flash_size/2) {
        wp = FLASH_2M_WP_1_2;
    } else if(offset >= flash_size/4) {
        wp = FLASH_2M_WP_1_4;
    } else if(offset >= flash_size/8) {
        wp = FLASH_2M_WP_1_8;
    } else if(offset >= flash_size/16) {
        wp = FLASH_2M_WP_1_16;
    } else if(offset >= flash_size/32) {
        wp = FLASH_2M_WP_1_32;
    } else if(offset >= 32 * 1024) {
        wp = FLASH_2M_WP_32K;
    } else if(offset >= 16 * 1024) {
        wp = FLASH_2M_WP_16K;
    } else if(offset >= 8 * 1024) {
        wp = FLASH_2M_WP_8K;
    } else if(offset >= 4 * 1024) {
        wp = FLASH_2M_WP_4K;
    }

    return (status & ~FLASH_WP_MASK) | wp;
    
}

static unsigned short flash_wrtie_protect_1M(unsigned short status, unsigned int offset)
{
    unsigned int wp = FLASH_WP_NONE;

    if (offset >= flash_size - flash_size/256) {
        wp = FLASH_1M_WP_255_256;
    } else if(offset >= flash_size - flash_size/128) {
        wp = FLASH_1M_WP_127_128;
    } else if(offset >= flash_size - flash_size/64) {
        wp = FLASH_1M_WP_63_64;
    } else if(offset >= flash_size - flash_size/32) {
        wp = FLASH_1M_WP_31_32;
    } else if(offset >= flash_size - flash_size/16) {
        wp = FLASH_1M_WP_15_16;
    } else if(offset >= flash_size - flash_size/8) {
        wp = FLASH_1M_WP_7_8;
    } else if(offset >= flash_size - flash_size/4) {
        wp = FLASH_1M_WP_3_4;
    } else if(offset >= flash_size/2) {
        wp = FLASH_1M_WP_1_2;
    } else if(offset >= flash_size/4) {
        wp = FLASH_1M_WP_1_4;
    } else if(offset >= flash_size/8) {
        wp = FLASH_1M_WP_1_8;
    } else if(offset >= flash_size/16) {
        wp = FLASH_1M_WP_1_16;
    } else if(offset >= 32 * 1024) {
        wp = FLASH_1M_WP_32K;
    } else if(offset >= 16 * 1024) {
        wp = FLASH_1M_WP_16K;
    } else if(offset >= 8 * 1024) {
        wp = FLASH_1M_WP_8K;
    } else if(offset >= 4 * 1024) {
        wp = FLASH_1M_WP_4K;
    } 

    return (status & ~FLASH_WP_MASK) | wp;
    
}

void flash_wrtie_protect_all()
{
    unsigned short status;
    unsigned char r1, r2;
    core_util_critical_section_enter();
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x05);
    wait_busy_down();
    r1 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);

    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x35);
    wait_busy_down();
    r2 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    //mbed_error_printf("status %x %x\r\n", r2, r1);
    
    status = (r2 << 8) | r1;
    status = (status & ~FLASH_WP_MASK) | FLASH_WP_ALL;
    //mbed_error_printf("status %04x\r\n", status);
    
    spi_write_reset();
    wait_busy_down();
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, (status&0xff));
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, ((status>>8)&0xff));
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x01);
    wait_busy_down();
    spi_wip_reset();
    core_util_critical_section_exit();
    return;
}

void flash_wrtie_protect_none()
{
    unsigned short status;
    unsigned char r1, r2;
    core_util_critical_section_enter();
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x05);
    wait_busy_down();
    r1 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);

    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x35);
    wait_busy_down();
    r2 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    //mbed_error_printf("status %x %x\r\n", r2, r1);
    
    status = (r2 << 8) | r1;
    status = status & ~FLASH_WP_MASK;
    //mbed_error_printf("status %04x\r\n", status);

    spi_write_reset();
    wait_busy_down();
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, (status&0xff));
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, ((status>>8)&0xff));
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x01);
    wait_busy_down();
    spi_wip_reset();
    core_util_critical_section_exit();
    return;
}

void flash_wrtie_protect(unsigned int offset)
{
    unsigned short status;
    unsigned char r1, r2;
    core_util_critical_section_enter();
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x05);
    wait_busy_down();
    r1 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);

    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x35);
    wait_busy_down();
    r2 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    //mbed_error_printf("status %x %x\r\n", r2, r1);
    
    status = (r2 << 8) | r1;
    if (flash_size == FLASH_4M) {
        status = flash_wrtie_protect_4M(status, offset);
    } else if(flash_size == FLASH_2M) {
        status = flash_wrtie_protect_2M(status, offset);
    } else if(flash_size == FLASH_1M) {
        status = flash_wrtie_protect_1M(status, offset);
    } else [
        LWIP_DEBUGF(NETIF_DEBUG,"flash_size is error\r\n");
    }
    //mbed_error_printf("status %04x\r\n", status);
    
    spi_write_reset();
    wait_busy_down();
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, (status&0xff));
    WRITE_REG8(FLAHS_CTL_TX_FIFO_DATA_REG, ((status>>8)&0xff));
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x01);
    wait_busy_down();
    spi_wip_reset();
    core_util_critical_section_exit();
    return;
}
#else
void flash_wrtie_protect_all()
{
    return;
}

void flash_wrtie_protect_none()
{
    return;
}

void flash_wrtie_protect(unsigned int offset)
{
    return;
}

#endif
void rda5981_flash_init()
{
    unsigned int status3, status4, status5;
    core_util_critical_section_enter();
    WRITE_REG32(FLASH_CTL_TX_BLOCK_SIZE_REG, 3<<8);
    status3 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    status4 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    status5 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);

    wait_busy_down();
    spi_wip_reset();
    WRITE_REG32(FLASH_CTL_TX_CMD_ADDR_REG, 0x9F);
    wait_busy_down();
    //WRITE_REG32(FLASH_CTL_TX_BLOCK_SIZE_REG, 3<<8);
    //wait_busy_down();
    status3 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    status4 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    status5 = MREAD_WORD(FLAHS_CTL_RX_FIFO_DATA_REG);
    core_util_critical_section_exit();
   
    if ((status5&0xff != 0x14) && (status5&0xff != 0x15) && (status5&0xff != 0x16)) {
        mbed_error_printf("flash size error\r\n");
        return;
    }
    flash_size = (1 << (status5&0xff));
    flash_wrtie_protect_all();
    
    return;
}