/*******************************************************************************
 * Copyright (c) 2018 Renesas Electronics Corporation. All rights reserved.
 *
 * DESCRIPTION   : SCIF driver
 ******************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <scif_register.h>
#include <rcar_def.h>
#include <scif.h>
#include <mem_io.h>
#include <micro_wait.h>
#include <rst_register.h>

/* Define  */
#define	SCIF_SCSCR_TE_EN	(uint16_t)((uint16_t)1U << 5U)
#define	SCIF_SCSCR_RE_EN	(uint16_t)((uint16_t)1U << 4U)
#define	SCIF_SCSCR_CKE_EXT_CLK	(uint16_t)((uint16_t)2U << 0U)
#define SCIF_SCSCR_INIT_DATA	(uint16_t)(SCIF_SCSCR_TE_EN | SCIF_SCSCR_RE_EN)
#define SCIF_SCSCR_HW_INIT	(uint16_t)(0x0000U)

#define	SCIF_SCFCR_TFRST_EN	(uint16_t)((uint16_t)1U << 2U)
#define	SCIF_SCFCR_RFRS_EN	(uint16_t)((uint16_t)1U << 1U)
#define SCIF_SCFCR_RESET_FIFO	(uint16_t)(SCIF_SCFCR_TFRST_EN | SCIF_SCFCR_RFRS_EN)
#define SCIF_SCFCR_INIT_DATA	(uint16_t)(0x0000U)

#define SCIF_SCFSR_TEND		(uint16_t)((uint16_t)1U << 6U)
#define SCIF_SCFSR_TDFE		(uint16_t)((uint16_t)1U << 5U)
#define TRANS_END_CHECK		(uint16_t)(SCIF_SCFSR_TEND | SCIF_SCFSR_TDFE)
#define SCIF_SCFSR_INIT_DATA	(uint16_t)(0x0000U)

#define SCIF_SCLSR_INIT_DATA	(uint16_t)(0x0000U)

#define SCIF_SCSMR_INIT_DATA	(uint16_t)(0x0000U)

/* Pclk(66MHz)/1, 115.2kBps*/
/* N = 66/(66/2*115200)*10^4-1 =17=> 0x11 */
#define	SCIF_SCBRR_115200BPS	(uint8_t)(0x11U)
/* Pclk(266MHz)/1, 921.6kBps*/
/* N = 266/(8*2*921600)*10^6-1 =17=> 0x11 */
#define	HSCIF_SCBRR_921600BPS	(uint8_t)(0x11U)
/* Pclk(266MHz)/1, 1.8432MBps*/
/* N = 266/(8*2*1843200)*10^6-1 =8=> 0x08 */
#define	HSCIF_SCBRR_1843200BPS	(uint8_t)(0x08U)
#define SCIF_SCBRR_HW_INIT	(uint8_t)(0xFFU)

#define HSCIF_HSSRR_SRE		(uint16_t)(1U << 15U)
#define HSCIF_HSSRR_SRCYC8	(uint16_t)(7U << 0U)	/* Sampling rate 8-1 */
#define HSCIF_HSSRR_VAL		(uint16_t)(HSCIF_HSSRR_SRE | HSCIF_HSSRR_SRCYC8)

#define HSCIF_DL_DIV1		(uint16_t)(1U << 0U)
#define HSCIF_CKS_SC_CLK_EXT	(uint16_t)(0x0000U)


#define MODEMR_SCIF_DLMODE		(0x00000000U)
#define MODEMR_HSCIF_DLMODE_921600	(0x00000001U)
#define MODEMR_HSCIF_DLMODE_1843200	(0x00000002U)
#define MODEMR_HSCIF_DLMODE_3000000	(0x00000003U)

static void (*put_char)(uint8_t);

static void scif_console_putc(uint8_t outchar);
static void hscif_console_putc(uint8_t outchar);

void scif_init(void)
{
//	volatile uint16_t reg;
	uint32_t modemr;
	uint32_t product;

	product = *((volatile uint32_t*)PRR) & PRR_PRODUCT_MASK;

	switch (product) {
	case PRR_PRODUCT_S4:
		modemr = (((mem_read32(RST_MODEMR0) & RST_MODEMR0_MD31) >> 31U)
			| ((mem_read32(RST_MODEMR1) & RST_MODEMR1_MD32) << 1U));
		if(modemr == MODEMR_SCIF_DLMODE)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(SCIF_SCSCR_3, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(SCIF_SCFCR_3, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(SCIF_SCLSR_3, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(SCIF_SCFSR_3, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(SCIF_SCSCR_3, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(SCIF_SCSMR_3, SCIF_SCSMR_INIT_DATA);

			/* Baud rate 115200bps*/
			mem_write16(SCIF_SCBRR_3, SCIF_SCBRR_115200BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(SCIF_SCFCR_3, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(SCIF_SCSCR_3, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = scif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_921600)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);
			/* Baud rate 921600bps*/
			mem_write16(HSCIF_HSBRR, HSCIF_SCBRR_921600BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_1843200)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);
			/* Baud rate 1843200bps*/
			mem_write16(HSCIF_HSBRR, HSCIF_SCBRR_1843200BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_3000000)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* external clock, SC_CLK pin used for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_CKE_EXT_CLK);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* 24MHz / (3000000 * 8) = 1 */
			mem_write16(HSCIF_DL, HSCIF_DL_DIV1);
			
			mem_write16(HSCIF_CKS, HSCIF_CKS_SC_CLK_EXT);
			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=external */
			mem_write16(HSCIF_HSSCR, mem_read16(HSCIF_HSSCR) | SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else
		{
			/* No process */
		}
		break;
	case PRR_PRODUCT_V4H:
	case PRR_PRODUCT_V4M:
		modemr = (((mem_read32(RST_MODEMR0) & RST_MODEMR0_MD31) >> 31U)
			| ((mem_read32(RST_MODEMR1) & RST_MODEMR1_MD32) << 1U));
		if(modemr == MODEMR_SCIF_DLMODE)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(SCIF_SCSCR_0, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(SCIF_SCFCR_0, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(SCIF_SCLSR_0, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(SCIF_SCFSR_0, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(SCIF_SCSCR_0, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(SCIF_SCSMR_0, SCIF_SCSMR_INIT_DATA);

			/* Baud rate 115200bps*/
			mem_write16(SCIF_SCBRR_0, SCIF_SCBRR_115200BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(SCIF_SCFCR_0, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(SCIF_SCSCR_0, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = scif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_921600)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);
			/* Baud rate 921600bps*/
			mem_write16(HSCIF_HSBRR, HSCIF_SCBRR_921600BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_1843200)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* internal clock, SC_CLK pin unused for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);
			/* Baud rate 1843200bps*/
			mem_write16(HSCIF_HSBRR, HSCIF_SCBRR_1843200BPS);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=no output */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else if(modemr == MODEMR_HSCIF_DLMODE_3000000)
		{
			/* clear SCR.TE & SCR.RE*/
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_HW_INIT);
			/* reset tx-fifo, reset rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_RESET_FIFO);

			/* clear ORER bit */
			mem_write16(HSCIF_HSLSR, SCIF_SCLSR_INIT_DATA);
			/* clear all error bit	*/
			mem_write16(HSCIF_HSFSR, SCIF_SCFSR_INIT_DATA);

			/* external clock, SC_CLK pin used for output pin */
			mem_write16(HSCIF_HSSCR, SCIF_SCSCR_CKE_EXT_CLK);
			/* 8bit data, no-parity, 1 stop, Po/1 */
			mem_write16(HSCIF_HSSMR, SCIF_SCSMR_INIT_DATA);

			/* 24MHz / (3000000 * 8) = 1 */
			mem_write16(HSCIF_DL, HSCIF_DL_DIV1);
			
			mem_write16(HSCIF_CKS, HSCIF_CKS_SC_CLK_EXT);
			/* Sampling rate 8  */
			mem_write16(HSCIF_HSSRR, HSCIF_HSSRR_VAL);

			micro_wait(10U); /* 10us */

			/* reset-off tx-fifo, rx-fifo. */
			mem_write16(HSCIF_HSFCR, SCIF_SCFCR_INIT_DATA);
			/* enable TE, RE; SC_CLK=external */
			mem_write16(HSCIF_HSSCR, mem_read16(HSCIF_HSSCR) | SCIF_SCSCR_INIT_DATA);
			
			/* Set the pointer to a function that outputs one character. */
			put_char = hscif_console_putc;
		}
		else
		{
			/* No process */
		}
		break;
	default:
		break;
	}
}

void console_puts(char *str,char rtn)
{
	while (*str) {
		console_putc(*str);
		str++;
	}

	if(rtn == 1){
		console_putc(CR_CODE);
		console_putc(LF_CODE);
	}
}

void console_putc(uint8_t outchar)
{
	put_char(outchar);
}


static void scif_console_putc(uint8_t outchar)
{
	uint16_t reg;
	uint32_t product;

	product = *((volatile uint32_t*)PRR) & PRR_PRODUCT_MASK;

	switch (product) {
	case PRR_PRODUCT_S4:
		/* Check that transfer of SCIF0 is completed */
		while (!((TRANS_END_CHECK & mem_read16(SCIF_SCFSR_3)) == TRANS_END_CHECK)){
		}

		mem_write8(SCIF_SCFTDR_3, outchar);	/* Transfer one character */
		reg = mem_read16(SCIF_SCFSR_3);
		reg &= (uint16_t)(~(TRANS_END_CHECK)); /* TEND,TDFE clear */
		mem_write16(SCIF_SCFSR_3, reg);
		break;
	case PRR_PRODUCT_V4H:
	case PRR_PRODUCT_V4M:
		/* Check that transfer of SCIF0 is completed */
		while (!((TRANS_END_CHECK & mem_read16(SCIF_SCFSR_0)) == TRANS_END_CHECK)){
		}

		mem_write8(SCIF_SCFTDR_0, outchar);	/* Transfer one character */
		reg = mem_read16(SCIF_SCFSR_0);
		reg &= (uint16_t)(~(TRANS_END_CHECK)); /* TEND,TDFE clear */
		mem_write16(SCIF_SCFSR_0, reg);
		break;
	}
}

static void hscif_console_putc(uint8_t outchar)
{
	uint16_t reg;

	/* Check that transfer of SCIF0 is completed */
	while (!((TRANS_END_CHECK & mem_read16(HSCIF_HSFSR)) == TRANS_END_CHECK)){
	}

	mem_write8(HSCIF_HSFTDR, outchar);	/* Transfer one character */
	reg = mem_read16(HSCIF_HSFSR);
	reg &= (uint16_t)(~(TRANS_END_CHECK)); /* TEND,TDFE clear */
	mem_write16(HSCIF_HSFSR, reg);
}
