/*
 * This file is subject to the terms of the GFX License. If a copy of
 * the license was not distributed with this file, you can obtain one at:
 *
 *              http://ugfx.io/license.html
 */

#ifndef _GDISP_LLD_BOARD_H
#define _GDISP_LLD_BOARD_H

static const LCD_Parameters	DisplayTimings[] = {
	// You need one of these array elements per display
	{
		480, 272,								// Panel width and height
		2, 2, 41,								// Horizontal Timings (back porch, front porch, pulse)
		CALC_PERIOD(480,2,2,41),				// Total Horizontal Period (calculated from above line)
		2, 2, 10,								// Vertical Timings (back porch, front porch, pulse)
		CALC_PERIOD(272,2,2,10), 				// Total Vertical Period (calculated from above line)
		CALC_FPR(480,272,2,2,41,2,2,10,73ULL),	// FPR - the 60ULL is the frames per second. Note the ULL!
		LCD_PANEL_DATA_WIDTH_24BIT | LCD_PANEL_ENABLE_DITHERING
	},
};

/* GPIO Pin Config */
#define GDISP_CMD_PORT          GPIOF
#define GDISP_DATA_LO_PORT      GPIOG
#define GDISP_DATA_HI_PORT      GPIOE

#define GDISP_WR                11
#define GDISP_RD                12
#define GDISP_CS                13
#define GDISP_RST               14
#define GDISP_DC                15

#define SET_CS                  palSetPad(GDISP_CMD_PORT, GDISP_CS);
#define CLR_CS                  palClearPad(GDISP_CMD_PORT, GDISP_CS);
#define SET_RST                 palSetPad(GDISP_CMD_PORT, GDISP_RST);
#define CLR_RST                 palClearPad(GDISP_CMD_PORT, GDISP_RST);
#define SET_WR                  palSetPad(GDISP_CMD_PORT, GDISP_WR);
#define CLR_WR                  palClearPad(GDISP_CMD_PORT, GDISP_WR);
#define SET_RD                  palSetPad(GDISP_CMD_PORT, GDISP_RD);
#define CLR_RD                  palClearPad(GDISP_CMD_PORT, GDISP_RD);
#define SET_DC                  palSetPad(GDISP_CMD_PORT, GDISP_DC);
#define CLR_DC                  palClearPad(GDISP_CMD_PORT, GDISP_DC);

#define writeStrobe             { CLR_WR; /*asm volatile ("nop;");*/ SET_WR; }

IOBus busCMD    = { GDISP_CMD_PORT, (1 << GDISP_CS) | (1 << GDISP_RST) | (1 << GDISP_WR) | (1 << GDISP_RD) | (1 << GDISP_DC), 11 };
IOBus busDataLo = { GDISP_DATA_LO_PORT, 0xFF, 0 };
IOBus busDataHi = { GDISP_DATA_HI_PORT, 0xFF, 8 };


static GFXINLINE void init_board(GDisplay *g) {
	g->board = 0;
	switch(g->controllerdisplay) {
	case 0:
		palSetBusMode(&busCMD, PAL_MODE_OUTPUT_PUSHPULL);
		palSetBusMode(&busDataLo, PAL_MODE_OUTPUT_PUSHPULL);
		palSetBusMode(&busDataHi, PAL_MODE_OUTPUT_PUSHPULL);
		SET_CS; SET_WR; SET_RD; SET_DC; SET_RST;
		break;
	default:
		break;
	}
}

static GFXINLINE void post_init_board(GDisplay *g) {
	(void) g;
}

static GFXINLINE void setpin_reset(GDisplay *g, gBool state) {
	(void) g;
	if (state) {
		CLR_RST;
	} else {
		SET_RST;
	}
}

static GFXINLINE void acquire_bus(GDisplay *g) {
	(void) g;
	CLR_CS;
}

static GFXINLINE void release_bus(GDisplay *g) {
	(void) g;
	SET_CS;
}

static GFXINLINE void write_index(GDisplay *g, uint16_t index) {
	(void) g;

	CLR_DC;
	palWriteBus(&busDataLo, (index & 0xFF));
	palWriteBus(&busDataHi, (index >> 8));
	writeStrobe;
	SET_DC;
}

static GFXINLINE void write_data(GDisplay *g, uint16_t data) {
	(void) g;

	palWriteBus(&busDataLo, (data & 0xFF));
	palWriteBus(&busDataHi, (data >> 8));
	writeStrobe;
}

static GFXINLINE void setreadmode(GDisplay *g) {
	(void) g;
	palSetBusMode(&busDataLo, PAL_MODE_INPUT_PULLUP);
	palSetBusMode(&busDataHi, PAL_MODE_INPUT_PULLUP);
}

static GFXINLINE void setwritemode(GDisplay *g) {
	(void) g;
	palSetBusMode(&busDataLo, PAL_MODE_OUTPUT_PUSHPULL);
	palSetBusMode(&busDataHi, PAL_MODE_OUTPUT_PUSHPULL);
}

static GFXINLINE uint16_t read_data(GDisplay *g) {
	uint16_t data;
	(void) g;

	CLR_RD;
	data = (palReadBus(&busDataHi) << 8) | palReadBus(&busDataLo);
	SET_RD;
	return data;
}

#endif /* _GDISP_LLD_BOARD_H */