summaryrefslogtreecommitdiff
path: root/fw/fe310/eos/eve/eve.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/fe310/eos/eve/eve.c')
-rw-r--r--fw/fe310/eos/eve/eve.c476
1 files changed, 476 insertions, 0 deletions
diff --git a/fw/fe310/eos/eve/eve.c b/fw/fe310/eos/eve/eve.c
new file mode 100644
index 0000000..d625fec
--- /dev/null
+++ b/fw/fe310/eos/eve/eve.c
@@ -0,0 +1,476 @@
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "eve.h"
+
+#define EVE_MEM_WRITE 0x800000
+#define EVE_SPI_FLAGS(b) ( (b) ? (EVE_SPI_FLAG_TX | EVE_SPI_FLAG_BSWAP) : EVE_SPI_FLAG_BSWAP )
+
+static char cmd_burst;
+static uint16_t cmd_offset;
+
+static char dl_burst;
+static uint32_t dl_addr;
+
+static uint8_t brigtness;
+static uint8_t power_state;
+
+void eve_command(uint8_t command, uint8_t parameter) {
+ eve_spi_cs_set();
+ eve_spi_xchg24(((uint32_t)command << 16) | ((uint32_t)parameter << 8), 0);
+ eve_spi_cs_clear();
+}
+
+uint8_t eve_read8(uint32_t addr) {
+ uint8_t r;
+ eve_spi_cs_set();
+ eve_spi_xchg32(addr << 8, 0);
+ r = eve_spi_xchg8(0, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+
+ return r;
+}
+
+uint16_t eve_read16(uint32_t addr) {
+ uint16_t r;
+ eve_spi_cs_set();
+ eve_spi_xchg32(addr << 8, 0);
+ r = eve_spi_xchg16(0, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+
+ return r;
+}
+
+uint32_t eve_read32(uint32_t addr) {
+ uint32_t r;
+ eve_spi_cs_set();
+ eve_spi_xchg32(addr << 8, 0);
+ r = eve_spi_xchg32(0, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+
+ return r;
+}
+
+void eve_write8(uint32_t addr, uint8_t data) {
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, 0);
+ eve_spi_xchg8(data, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+}
+
+void eve_write16(uint32_t addr, uint16_t data) {
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, 0);
+ eve_spi_xchg16(data, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+}
+
+void eve_write32(uint32_t addr, uint32_t data) {
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, 0);
+ eve_spi_xchg32(data, EVE_SPI_FLAG_BSWAP);
+ eve_spi_cs_clear();
+}
+
+void eve_readb(uint32_t addr, uint8_t *buf, size_t size) {
+ int i;
+
+ eve_spi_cs_set();
+ eve_spi_xchg32(addr << 8, 0);
+ for (i=0; i<size; i++) {
+ buf[i] = eve_spi_xchg8(0, 0);
+ }
+ eve_spi_cs_clear();
+}
+
+void eve_writeb(uint32_t addr, uint8_t *buf, size_t size) {
+ int i;
+
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, 0);
+ for (i=0; i<size; i++) {
+ eve_spi_xchg8(buf[i], 0);
+ }
+ eve_spi_cs_clear();
+}
+
+static void dl_inc(uint32_t i) {
+ dl_addr += i;
+}
+
+void eve_dl_start(uint32_t addr, char burst) {
+ dl_addr = addr;
+ dl_burst = burst;
+ if (burst) {
+ eve_spi_lock();
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, EVE_SPI_FLAG_TX);
+ }
+}
+
+void eve_dl_write(uint32_t dl) {
+ if (dl_burst) {
+ eve_spi_xchg32(dl, EVE_SPI_FLAGS(dl_burst));
+ } else {
+ eve_write32(dl_addr, dl);
+ }
+ dl_inc(4);
+}
+
+void eve_dl_end(void) {
+ if (dl_burst) {
+ eve_spi_flush();
+ eve_spi_cs_clear();
+ eve_spi_unlock();
+ dl_burst = 0;
+ }
+}
+
+void eve_dl_swap(void) {
+ eve_write8(REG_DLSWAP, EVE_DLSWAP_FRAME);
+}
+
+uint32_t eve_dl_get_addr(void) {
+ return dl_addr;
+}
+
+static void cmd_inc(uint16_t i) {
+ cmd_offset += i;
+ cmd_offset &= 0x0fff;
+}
+
+static void cmd_begin(uint32_t command, uint8_t flags) {
+ if (!cmd_burst) {
+ uint32_t addr = EVE_RAM_CMD + cmd_offset;
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, 0);
+ }
+ eve_spi_xchg32(command, flags);
+ cmd_inc(4);
+}
+
+static void cmd_end(void) {
+ if (!cmd_burst) eve_spi_cs_clear();
+}
+
+static void cmd_string(const char *str, uint8_t flags) {
+ int i = 0;
+
+ while (str[i] != 0) {
+ eve_spi_xchg8(str[i], flags);
+ i++;
+ }
+ eve_spi_xchg8(0, flags);
+ i++;
+ cmd_inc(i);
+}
+
+static void cmd_buffer(const char *buf, int size, uint8_t flags) {
+ int i = 0;
+
+ for (i=0; i<size; i++) {
+ eve_spi_xchg8(buf[i], flags);
+ }
+ cmd_inc(size);
+}
+
+static void cmd_padding(uint8_t flags) {
+ int i = cmd_offset & 3; /* equivalent to cmd_offset % 4 */
+
+ if (i) {
+ i = 4 - i; /* 3, 2 or 1 */
+ cmd_inc(i);
+
+ while (i > 0) {
+ eve_spi_xchg8(0, flags);
+ i--;
+ }
+ }
+}
+
+void eve_cmd(uint32_t cmd, const char *fmt, ...) {
+ uint8_t flags = EVE_SPI_FLAGS(cmd_burst);
+ va_list argv;
+ uint16_t *p;
+ int i = 0;
+ int cont = 0;
+
+ va_start(argv, fmt);
+ cmd_begin(cmd, flags);
+ while (fmt[i]) {
+ switch (fmt[i]) {
+ case 'b':
+ eve_spi_xchg8(va_arg(argv, int), flags);
+ cmd_inc(1);
+ break;
+ case 'h':
+ eve_spi_xchg16(va_arg(argv, int), flags);
+ cmd_inc(2);
+ break;
+ case 'w':
+ eve_spi_xchg32(va_arg(argv, int), flags);
+ cmd_inc(4);
+ break;
+ case '&':
+ p = va_arg(argv, uint16_t *);
+ *p = cmd_offset;
+ eve_spi_xchg32(0, flags);
+ cmd_inc(4);
+ break;
+ case 's':
+ cmd_string(va_arg(argv, const char *), flags);
+ break;
+ case 'p':
+ cmd_buffer(va_arg(argv, const char *), va_arg(argv, int), flags);
+ break;
+ case '+':
+ cont = 1;
+ break;
+ }
+ if (cont) break;
+ i++;
+ }
+ va_end(argv);
+ if (!cont) eve_cmd_end();
+}
+
+void eve_cmd_write(uint8_t *buffer, size_t size) {
+ cmd_buffer(buffer, size, EVE_SPI_FLAGS(cmd_burst));
+}
+
+void eve_cmd_end(void) {
+ cmd_padding(EVE_SPI_FLAGS(cmd_burst));
+ cmd_end();
+}
+
+uint32_t eve_cmd_result(uint16_t offset) {
+ return eve_read32(EVE_RAM_CMD + offset);
+}
+
+void eve_cmd_dl(uint32_t dl) {
+ cmd_begin(dl, EVE_SPI_FLAGS(cmd_burst));
+ cmd_end();
+}
+
+int eve_cmd_done(void) {
+ uint16_t r = eve_read16(REG_CMD_READ);
+ if (r == 0xfff) {
+ cmd_offset = 0;
+ eve_write8(REG_CPURESET, 1);
+ eve_write16(REG_CMD_READ, 0);
+ eve_write16(REG_CMD_WRITE, 0);
+ eve_write16(REG_CMD_DL, 0);
+ eve_write8(REG_CPURESET, 0);
+ return -1;
+ }
+ return (r == cmd_offset);
+}
+
+int eve_cmd_exec(int w) {
+ eve_write16(REG_CMD_WRITE, cmd_offset);
+ if (w) {
+ int r;
+ do {
+ r = eve_cmd_done();
+ } while (!r);
+ if (r < 0) return EVE_ERR;
+ }
+ return EVE_OK;
+}
+
+void eve_cmd_burst_start(void) {
+ uint32_t addr = EVE_RAM_CMD + cmd_offset;
+ eve_spi_lock();
+ eve_spi_cs_set();
+ eve_spi_xchg24(addr | EVE_MEM_WRITE, EVE_SPI_FLAG_TX);
+ cmd_burst = 1;
+}
+
+void eve_cmd_burst_end(void) {
+ eve_spi_flush();
+ eve_spi_cs_clear();
+ eve_spi_unlock();
+ cmd_burst = 0;
+}
+
+int eve_gpio_get(int gpio) {
+ uint16_t reg = eve_read16(REG_GPIOX);
+ return !!(reg & (1 << gpio));
+}
+
+void eve_gpio_set(int gpio, int val) {
+ uint16_t reg = eve_read16(REG_GPIOX);
+ uint16_t reg_val = (1 << gpio);
+ if (val) {
+ reg |= reg_val;
+ } else {
+ reg &= ~reg_val;
+ }
+ eve_write16(REG_GPIOX, reg);
+}
+
+uint8_t eve_gpio_get_dir(void) {
+ uint16_t reg = eve_read16(REG_GPIOX_DIR);
+ return reg & 0x000f;
+}
+
+void eve_gpio_set_dir(uint8_t dir) {
+ uint16_t reg = eve_read16(REG_GPIOX_DIR);
+ reg &= 0xfff0;
+ reg |= dir & 0x0f;
+ eve_write16(REG_GPIOX_DIR, reg);
+}
+
+void eve_active(void) {
+ eve_command(EVE_ACTIVE, 0);
+ if (power_state == EVE_PSTATE_SLEEP) eve_time_sleep(40);
+
+ eve_write8(REG_PWM_DUTY, brigtness);
+ if (power_state != EVE_PSTATE_SLEEP) return;
+
+ eve_write8(REG_TOUCH_MODE, EVE_TMODE_CONTINUOUS);
+ eve_write8(REG_CTOUCH_EXTENDED, 0x00);
+
+ power_state = EVE_PSTATE_ACTIVE;
+}
+
+void eve_standby(void) {
+ if (power_state != EVE_PSTATE_ACTIVE) return;
+
+ brigtness = eve_read8(REG_PWM_DUTY);
+ eve_command(EVE_STANDBY, 0);
+
+ power_state = EVE_PSTATE_STANDBY;
+}
+
+void eve_sleep(void) {
+ if (power_state != EVE_PSTATE_ACTIVE) return;
+
+ brigtness = eve_read8(REG_PWM_DUTY);
+ eve_write8(REG_PWM_DUTY, 0x0);
+
+ eve_write8(REG_CTOUCH_EXTENDED, 0x01);
+ eve_write8(REG_TOUCH_MODE, EVE_TMODE_OFF);
+
+ eve_time_sleep(500);
+ eve_command(EVE_SLEEP, 0);
+
+ power_state = EVE_PSTATE_SLEEP;
+}
+
+void eve_brightness(uint8_t b) {
+ eve_write8(REG_PWM_DUTY, b);
+}
+
+static int _init(int touch_calibrate, uint32_t *touch_matrix, uint8_t gpio_dir) {
+ uint8_t chipid = 0;
+ uint16_t timeout = 0;
+
+ eve_command(EVE_RST_PULSE, 0);
+ eve_command(EVE_CLKEXT, 0);
+ eve_command(EVE_ACTIVE, 0); /* start EVE */
+
+ while (chipid != 0x7C) { /* if chipid is not 0x7c, continue to read it until it is, EVE needs a moment for it's power on self-test and configuration */
+ eve_time_sleep(1);
+ chipid = eve_read8(REG_ID);
+ timeout++;
+ if (timeout > 400) return EVE_ERR;
+ }
+
+ eve_write8(REG_PWM_DUTY, 0);
+ eve_write16(REG_GPIOX_DIR, 0x8000 | (gpio_dir & 0x0f));
+ eve_write16(REG_GPIOX, 0);
+
+ /* Initialize Display */
+ eve_write16(REG_HCYCLE, EVE_HCYCLE); /* total number of clocks per line, incl front/back porch */
+ eve_write16(REG_HOFFSET, EVE_HOFFSET); /* start of active line */
+ eve_write16(REG_HSYNC0, EVE_HSYNC0); /* start of horizontal sync pulse */
+ eve_write16(REG_HSYNC1, EVE_HSYNC1); /* end of horizontal sync pulse */
+ eve_write16(REG_VCYCLE, EVE_VCYCLE); /* total number of lines per screen, including pre/post */
+ eve_write16(REG_VOFFSET, EVE_VOFFSET); /* start of active screen */
+ eve_write16(REG_VSYNC0, EVE_VSYNC0); /* start of vertical sync pulse */
+ eve_write16(REG_VSYNC1, EVE_VSYNC1); /* end of vertical sync pulse */
+ eve_write8(REG_SWIZZLE, EVE_SWIZZLE); /* FT8xx output to LCD - pin order */
+ eve_write8(REG_PCLK_POL, EVE_PCLKPOL); /* LCD data is clocked in on this PCLK edge */
+ eve_write8(REG_CSPREAD, EVE_CSPREAD); /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */
+ eve_write16(REG_HSIZE, EVE_HSIZE); /* active display width */
+ eve_write16(REG_VSIZE, EVE_VSIZE); /* active display height */
+
+ /* do not set PCLK yet - wait for just after the first display list */
+
+ /* disable Audio */
+ eve_write16(REG_SOUND, 0x0000); /* set synthesizer to silence */
+ eve_write8(REG_VOL_SOUND, 0x00); /* turn synthesizer volume off */
+ eve_write8(REG_VOL_PB, 0x00); /* turn recorded audio volume off */
+
+ /* write a basic display-list to get things started */
+ eve_dl_start(EVE_RAM_DL, 0);
+ eve_dl_write(CLEAR_COLOR_RGB(0,0,0));
+ eve_dl_write(CLEAR(1,1,1));
+ eve_dl_write(DISPLAY());
+ eve_dl_swap();
+
+ /* nothing is being displayed yet... the pixel clock is still 0x00 */
+ eve_write16(REG_GPIOX, 0x8000); /* enable the DISP signal to the LCD panel, it is set to output in REG_GPIOX_DIR by default */
+ eve_write8(REG_PCLK, EVE_PCLK); /* now start clocking data to the LCD panel */
+
+ /* configure Touch */
+ eve_write16(REG_TOUCH_CONFIG, 0xb81); /* enable touch low power mode: 0xb81 - default: 0x381 */
+ eve_write8(REG_TOUCH_MODE, EVE_TMODE_CONTINUOUS); /* enable touch */
+ eve_write16(REG_TOUCH_RZTHRESH, EVE_TOUCH_RZTHRESH); /* eliminate any false touches */
+
+ if (touch_calibrate) {
+ eve_write8(REG_PWM_DUTY, 0x40);
+ eve_cmd_dl(CMD_DLSTART);
+ eve_cmd_dl(CLEAR_COLOR_RGB(0,0,0));
+ eve_cmd_dl(CLEAR(1,1,1));
+ eve_cmd(CMD_TEXT, "hhhhs", EVE_HSIZE/2, EVE_VSIZE/2, 27, EVE_OPT_CENTER, "Please tap on the dot.");
+ eve_cmd(CMD_CALIBRATE, "w", 0);
+ eve_cmd_dl(DISPLAY());
+ eve_cmd_dl(CMD_SWAP);
+ eve_cmd_exec(1);
+ eve_write8(REG_PWM_DUTY, 0);
+
+ touch_matrix[0] = eve_read32(REG_TOUCH_TRANSFORM_A);
+ touch_matrix[1] = eve_read32(REG_TOUCH_TRANSFORM_B);
+ touch_matrix[2] = eve_read32(REG_TOUCH_TRANSFORM_C);
+ touch_matrix[3] = eve_read32(REG_TOUCH_TRANSFORM_D);
+ touch_matrix[4] = eve_read32(REG_TOUCH_TRANSFORM_E);
+ touch_matrix[5] = eve_read32(REG_TOUCH_TRANSFORM_F);
+ } else {
+ eve_write32(REG_TOUCH_TRANSFORM_A, touch_matrix[0]);
+ eve_write32(REG_TOUCH_TRANSFORM_B, touch_matrix[1]);
+ eve_write32(REG_TOUCH_TRANSFORM_C, touch_matrix[2]);
+ eve_write32(REG_TOUCH_TRANSFORM_D, touch_matrix[3]);
+ eve_write32(REG_TOUCH_TRANSFORM_E, touch_matrix[4]);
+ eve_write32(REG_TOUCH_TRANSFORM_F, touch_matrix[5]);
+ }
+
+ eve_write8(REG_CTOUCH_EXTENDED, 0x00);
+
+ eve_cmd(CMD_SETROTATE, "w", 2);
+ eve_cmd_exec(1);
+
+ return EVE_OK;
+}
+
+int eve_init(int pwr_on, int touch_calibrate, uint32_t *touch_matrix, uint8_t gpio_dir) {
+ eve_spi_start();
+
+ pwr_on = 1; // override this for now
+
+ if (pwr_on) {
+ int rv = _init(touch_calibrate, touch_matrix, gpio_dir);
+ if (rv) return rv;
+ } else {
+ power_state = EVE_PSTATE_SLEEP;
+ eve_active();
+ }
+
+ eve_touch_init();
+ eve_platform_init();
+
+ eve_spi_stop();
+
+ return EVE_OK;
+}