/*
 ************************************************************************************************
 * RX-Flash
 *      Emulation of the internal flash of Renesas RX  series
 *
 * Status: untested 
 *
 * Copyright 2012 Jochen Karrer. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 * 
 *   1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 * 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY Jochen Karrer ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Jochen Karrer.
 ************************************************************************************************
 */

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>

#include "flash_rx.h"
#include "configfile.h"
#include "cycletimer.h"
#include "bus.h"
#include "signode.h"
#include "diskimage.h"
#include "sgstring.h"


#define REG_FMODR(base)		(0x007FC402)
#define		FMODR_FRDMD	(1 << 4)
#define REG_FASTAT(base)	(0x007FC410) 
#define		FASTAT_DFLWPE	(1 << 0)
#define		FASTAT_DFLRPE	(1 << 1)
#define		FASTAT_DFLAE	(1 << 3)
#define 	FASTAT_CMDLK	(1 << 4)
#define		FASTAT_ROMAE	(1 << 7)
#define REG_FAEINT(base)	(0x007FC411)
#define		FAEINT_DFLWPEIE	(1 << 0)
#define		FAEINT_DFLRPEIE	(1 << 1)
#define		FAEINT_DFLAEIE	(1 << 3)
#define 	FAEINT_CMDLKIE	(1 << 4)
#define		FAEINT_ROMAEIE	(1 << 7)
#define REG_FRDYIE(base)	(0x007FC412)
#define		FRDYIE_FRDYIE	(1 << 0)

#define	REG_DFLRE0(base)	(0x007FC440)
#define		DFLRE0_DBRE00		(1 << 0)
#define		DFLRE0_DREB01		(1 << 1)
#define		DFLRE0_DREB02		(1 << 2)
#define		DFLRE0_DREB03		(1 << 3)
#define		DFLRE0_DREB04		(1 << 4)
#define		DFLRE0_DREB05		(1 << 5)
#define		DFLRE0_DREB06		(1 << 6)
#define		DFLRE0_DREB07		(1 << 7)
#define		DFLRE0_KEY_MSK		(0xff << 8)
#define		DFLRE0_KEY_SHIFT	(8)
#define	REG_DFLRE1(base)	(0x007FC442)
#define		DFLRE1_DBRE08		(1 << 0)
#define		DFLRE1_DREB09		(1 << 1)
#define		DFLRE1_DREB10		(1 << 2)
#define		DFLRE1_DREB11		(1 << 3)
#define		DFLRE1_DREB12		(1 << 4)
#define		DFLRE1_DREB13		(1 << 5)
#define		DFLRE1_DREB14		(1 << 6)
#define		DFLRE1_DREB15		(1 << 7)
#define		DFLRE1_KEY_MSK		(0xff << 8)
#define		DFLRE1_KEY_SHIFT	(8)
#define REG_DFLWE0(base)	(0x007FC450)
#define		DFLWE0_DBWE00		(1 << 0)
#define		DFLWE0_DBWE01		(1 << 1)
#define		DFLWE0_DBWE02		(1 << 2)
#define		DFLWE0_DBWE03		(1 << 3)
#define		DFLWE0_DBWE04		(1 << 4)
#define		DFLWE0_DBWE05		(1 << 5)
#define		DFLWE0_DBWE06		(1 << 6)
#define		DFLWE0_DBWE07		(1 << 7)
#define REG_DFLWE1(base)	(0x007FC452)
#define		DFLWE1_DBWE08		(1 << 0)
#define		DFLWE1_DBWE09		(1 << 1)
#define		DFLWE1_DBWE10		(1 << 2)
#define		DFLWE1_DBWE11		(1 << 3)
#define		DFLWE1_DBWE12		(1 << 4)
#define		DFLWE1_DBWE13		(1 << 5)
#define		DFLWE1_DBWE14		(1 << 6)
#define		DFLWE1_DBWE15		(1 << 7)

#define REG_FCURAME(base) 	(0x007FC454)
#define		FCURAME_FCRME		(1 << 0)
#define		FCURAME_KEY_SHIFT	(8)
#define		FCURAME_KEY_MSK		(0xff << 8)

#define REG_FSTATR0(base)	(0x007FFFB0)
#define 	FSTATR0_PRGSPD		(1 << 0)
#define		FSTATR0_ERSSPD		(1 << 1)
#define		FSTATR0_SUSRDY		(1 << 3)
#define		FSTATR0_PRGERR		(1 << 4)
#define 	FSTATR0_ERSERR		(1 << 5)
#define		FSTATR0_ILGLERR		(1 << 6)
#define		FSTATR0_FRDY		(1 << 7)

#define REG_FSTATR1(base)	(0x007FFFB1)
#define		FSTATR1_FLOCKST		(1 << 4)
#define		FSTATR1_FCUERR		(1 << 7)

#define REG_FENTRYR(base)	(0x007FFFB2)
#define		FENTRYR_FENTRY0		(1 << 0)
#define		FENTRYR_FEKEY_SHIFT	(8)
#define		FENTRYR_FEKEY_MSK	(0xff << 8)

#define REG_FPROTR(base)	(0x007FFFB4)
#define		FPROTR_FPROTCN		(1 <<0)
#define		FPROTR_FPKEY_SHIFT	(8)
#define		FPROTR_FPKEY_MSK	(0xff << 8)

#define REG_FRESETR(base)	(0x007FFFB6)
#define		FRESETR_FRESET		(1 << 0)
#define		FRESETR_KEY_SHIFT	(8)
#define		FRESETR_KEY_MSK		(0xff << 8)

#define REG_FCMDR(base)		(0x007FFFBA)
#define		FCMDR_PCMDR_SHIFT	(0)
#define		FCMDR_PCMDR_MSK		(0xff)
#define		FCMDR_CMDR_SHIFT	(8)
#define		FCMDR_CMDR_MSK		(0xff << 8)

#define REG_FCPSR(base)		(0x007FFFC8)
#define		FCPSR_ESUSPMD		(1 << 0)

#define	REG_DFLBCCNT(base)	(0x007FFFCA)
#define		DFLBCCNT_BCSIZE		(1 << 0)
#define		DFLBCCNT_BCADR_MSK	(0xff << 3)
#define		DFLBCCNT_BCADR_SHIFT	(3)

#define REG_DFLBCSTAT(base)	(0x007FFFCE)
#define		DFLBCSTAT_BCST		(1 << 0)

#define REG_FPESTAT(base)	(0x007FFFCC)
#define		FPESTAT_PEERRST_SHIFT	(0)
#define		FPESTAT_PEERRST_MSK	(0xff)

#define REG_PCKAR(base)		(0x007FFFE8)
#define		PCKAR_PCKA_SHIFT	(0)
#define		PCKAR_PCKA_MSK		(0xff)
#define REG_FWEPROR(base)	(0x0008C289)
#define		FWEPROR_FLWE_SHIFT	(0)
#define		FWEPROR_FLWE_MSK	(3)

typedef struct RXFlash {
	/* State space from two variables */
        BusDevice bdev;
        DiskImage *disk_image;
        uint8_t *host_mem;
        uint32_t size;
	bool dbgMode; 
} RXFlash;


static void
Flash_Map(void *module_owner,uint32_t base,uint32_t mapsize,uint32_t flags)
{
        RXFlash *rxflash = module_owner;
        uint8_t *host_mem=rxflash->host_mem;
	//if(rxflash->mode == MAP_READ_ARRAY) {
		if(!rxflash->dbgMode) {
                	flags &= ~MEM_FLAG_WRITABLE;
		}	
        	Mem_MapRange(base,host_mem,rxflash->size,mapsize,flags);
		//fprintf(stderr,"Mapped %p size %d, mapsize %d\n",host_mem,rxflash->size,mapsize); 
        //}
}

static void
Flash_UnMap(void *module_owner,uint32_t base,uint32_t mapsize)
{
        Mem_UnMapRange(base,mapsize);
}

/*
 * Should be moved to some common place
 */
static uint32_t
parse_memsize (char *str)
{
        uint32_t size;
        unsigned char c;
        if(sscanf(str,"%d",&size)!=1) {
                return 0;
        }
        if(sscanf(str,"%d%c",&size,&c)==1) {
                return size;
        }
        switch(tolower(c)) {
                case 'm':
                        return size*1024*1024;
                case 'k':
                        return size*1024;
        }
        return 0;
}

BusDevice *
RXFlash_New(const char *flash_name)
{
        RXFlash *rxflash = sg_new(RXFlash);
        char *imagedir;
	char *sizestr;
	uint32_t debugmode = 0;
        imagedir = Config_ReadVar("global","imagedir");
	sizestr = Config_ReadVar(flash_name,"size");
	if(sizestr) {
                rxflash->size = parse_memsize(sizestr);
                if(rxflash->size == 0) {
                        fprintf(stderr,"RX Flash \"%s\" has zero size\n",flash_name);
                        return NULL;
                }
	} else {
		fprintf(stderr,"Flash size for CPU is not conigured\n");
		return NULL;
	}
	Config_ReadUInt32(&debugmode,flash_name,"debug");
	rxflash->dbgMode = debugmode;
        if(imagedir) {
                char *mapfile = alloca(strlen(imagedir) + strlen(flash_name) + 20);
                sprintf(mapfile,"%s/%s.img",imagedir,flash_name);
                rxflash->disk_image = DiskImage_Open(mapfile,rxflash->size,DI_RDWR | DI_CREAT_FF);
                if(!rxflash->disk_image) {
                        fprintf(stderr,"Open disk image failed\n");
                        exit(1);
                }
                rxflash->host_mem = DiskImage_Mmap(rxflash->disk_image);
		fprintf(stderr,"Mapped to %p\n",rxflash->host_mem);
        } else {
                rxflash->host_mem = sg_calloc(rxflash->size);
                memset(rxflash->host_mem,0xff,rxflash->size);
        }
        rxflash->bdev.first_mapping = NULL;
        rxflash->bdev.Map = Flash_Map;
        rxflash->bdev.UnMap = Flash_UnMap;
        rxflash->bdev.owner = rxflash;
	if(rxflash->dbgMode) {
        	rxflash->bdev.hw_flags = MEM_FLAG_READABLE | MEM_FLAG_WRITABLE;
	} else {
        	rxflash->bdev.hw_flags = MEM_FLAG_READABLE;
	}
        fprintf(stderr,"Created RX Flash with size %d bytes\n",rxflash->size);
        return &rxflash->bdev;
}
