From 54c649697b3959d8f74888bd7ec9af0206f7670c Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Tue, 18 May 2010 23:50:00 +0000 Subject: Gigabeat S: Implement LCD contrast, invert and flip modes. Enhance LCD power management. Include init data but it's not needed yet (identical to Gigabeat F). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26154 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/config/gigabeats.h | 17 +- firmware/export/imx31l.h | 154 +++++++++++++---- .../target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c | 183 ++++++++++++++++++--- firmware/target/arm/imx31/spi-imx31.c | 6 + firmware/target/arm/imx31/spi-imx31.h | 3 + 5 files changed, 308 insertions(+), 55 deletions(-) (limited to 'firmware') diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h index b3e7dc31bd..f096fb07d6 100644 --- a/firmware/export/config/gigabeats.h +++ b/firmware/export/config/gigabeats.h @@ -120,6 +120,21 @@ #ifndef BOOTLOADER +/* define this if you can flip your LCD */ +#define HAVE_LCD_FLIP + +/* define this if you can invert the colours on your LCD */ +#define HAVE_LCD_INVERT + +/* Define this if your LCD can set contrast */ +#define HAVE_LCD_CONTRAST + +/* Main LCD contrast range and defaults */ +#define MIN_CONTRAST_SETTING 0 +#define MAX_CONTRAST_SETTING 63 +#define DEFAULT_CONTRAST_SETTING 47 /* Match boot contrast */ + +/* Define this for LCD backlight brightness available */ #define HAVE_BACKLIGHT_BRIGHTNESS /* Main LCD backlight brightness range and defaults */ @@ -139,7 +154,7 @@ #define CONFIG_I2C I2C_IMX31L /* Define the bitmask of modules used */ -#define SPI_MODULE_MASK (USE_CSPI2_MODULE) +#define SPI_MODULE_MASK (USE_CSPI2_MODULE | USE_CSPI3_MODULE) #define I2C_MODULE_MASK (USE_I2C1_MODULE | USE_I2C2_MODULE) #define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h index 3f3a0140c8..7cb452d3cb 100644 --- a/firmware/export/imx31l.h +++ b/firmware/export/imx31l.h @@ -197,36 +197,128 @@ #define RNGA_CONTROL_SLEEP (1 << 4) /* IPU */ -#define IPU_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x00)) -#define IPU_CHA_BUF0_RDY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x04)) -#define IPU_CHA_BUF1_RDY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x08)) -#define IPU_CHA_DB_MODE_SEL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0C)) -#define IPU_CHA_CUR_BUF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x10)) -#define IPU_FS_PROC_FLOW (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x14)) -#define IPU_FS_DISP_FLOW (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x18)) -#define IPU_TASKS_STAT (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1C)) -#define IPU_IMA_ADDR (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x20)) -#define IPU_IMA_DATA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x24)) -#define IPU_INT_CTRL_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x28)) -#define IPU_INT_CTRL_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x2C)) -#define IPU_INT_CTRL_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x30)) -#define IPU_INT_CTRL_4 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x34)) -#define IPU_INT_CTRL_5 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x38)) -#define IPU_INT_STAT_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x3C)) -#define IPU_INT_STAT_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x40)) -#define IPU_INT_STAT_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x44)) -#define IPU_INT_STAT_4 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x48)) -#define IPU_INT_STAT_5 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x4C)) -#define IPU_BRK_CTRL_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x50)) -#define IPU_BRK_CTRL_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x54)) -#define IPU_BRK_STAT (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x58)) -#define IPU_DIAGB_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x60)) -#define IPU_IDMAC_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0xA4)) -#define IPU_IDMAC_CHA_EN (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0xA8)) -#define IPU_IDMAC_CHA_PRI (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0xAC)) -#define IPU_IDMAC_CHA_BUSY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0xB0)) - - +#define IPU_IPU_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x000)) +#define IPU_IPU_CHA_BUF0_RDY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x004)) +#define IPU_IPU_CHA_BUF1_RDY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x008)) +#define IPU_IPU_CHA_DB_MODE_SEL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x00C)) +#define IPU_IPU_CHA_CUR_BUF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x010)) +#define IPU_IPU_FS_PROC_FLOW (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x014)) +#define IPU_IPU_FS_DISP_FLOW (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x018)) +#define IPU_IPU_TASKS_STAT (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x01C)) +#define IPU_IPU_IMA_ADDR (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x020)) +#define IPU_IPU_IMA_DATA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x024)) +#define IPU_IPU_INT_CTRL_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x028)) +#define IPU_IPU_INT_CTRL_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x02C)) +#define IPU_IPU_INT_CTRL_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x030)) +#define IPU_IPU_INT_CTRL_4 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x034)) +#define IPU_IPU_INT_CTRL_5 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x038)) +#define IPU_IPU_INT_STAT_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x03C)) +#define IPU_IPU_INT_STAT_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x040)) +#define IPU_IPU_INT_STAT_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x044)) +#define IPU_IPU_INT_STAT_4 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x048)) +#define IPU_IPU_INT_STAT_5 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x04C)) +#define IPU_IPU_BRK_CTRL_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x050)) +#define IPU_IPU_BRK_CTRL_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x054)) +#define IPU_IPU_BRK_STAT (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x058)) +#define IPU_IPU_DIAGB_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x060)) +#define IPU_CSI_SENS_FRM_SIZE (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x064)) +#define IPU_CSI_ACT_FRM_SIZE (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x068)) +#define IPU_CSI_OUT_FRM_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x06C)) +#define IPU_CSI_TST_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x070)) +#define IPU_CSI_CCIR_CODE_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x074)) +#define IPU_CSI_CCIR_CODE_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x078)) +#define IPU_CSI_CCIR_CODE_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x07C)) +#define IPU_CSI_FLASH_STROBE_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x080)) +#define IPU_CSI_FLASH_STROBE_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x084)) +#define IPU_IC_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x088)) +#define IPU_IC_PRP_ENC_RSC (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x08C)) +#define IPU_IC_PRP_VF_RSC (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x090)) +#define IPU_IC_PP_RSC (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x094)) +#define IPU_IC_CMBP_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x098)) +#define IPU_IC_CMBP_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x09C)) +#define IPU_PF_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0A0)) +#define IPU_IDMAC_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0A4)) +#define IPU_IDMAC_CHA_EN (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0A8)) +#define IPU_IDMAC_CHA_PRI (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0AC)) +#define IPU_IDMAC_CHA_BUSY (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0B0)) +#define IPU_SDC_COM_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0B4)) +#define IPU_SDC_GRAPH_WIND_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0B8)) +#define IPU_SDC_FG_POS (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0BC)) +#define IPU_SDC_BG_POS (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0C0)) +#define IPU_SDC_CUR_POS (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0C4)) +#define IPU_SDC_CUR_BLINK_PWM_CTRL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0C8)) +#define IPU_SDC_CUR_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0CC)) +#define IPU_SDC_HOR_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0D0)) +#define IPU_SDC_VER_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0D4)) +#define IPU_SDC_SHARP_CONF_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0D8)) +#define IPU_SDC_SHARP_CONF_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0DC)) +#define IPU_SDC_ADC_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0E0)) +#define IPU_ADC_SYSCHA1_SA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0E4)) +#define IPU_ADC_SYSCHA2_SA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0E8)) +#define IPU_ADC_PRPCHAN_SA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0EC)) +#define IPU_ADC_PPCHAN_SA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0F0)) +#define IPU_ADC_DISP0_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0F4)) +#define IPU_ADC_DISP0_RD_AP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0F8)) +#define IPU_ADC_DISP0_RDM (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x0FC)) +#define IPU_ADC_DISP0_SS (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x100)) +#define IPU_ADC_DISP1_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x104)) +#define IPU_ADC_DISP1_RD_AP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x108)) +#define IPU_ADC_DISP1_RDM (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x10C)) +#define IPU_ADC_DISP2_SS (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x110)) +#define IPU_ADC_DISP2_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x114)) +#define IPU_ADC_DISP2_RD_AP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x118)) +#define IPU_ADC_DISP2_RDM (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x11C)) +#define IPU_ADC_DISP_VSYNC (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x120)) +#define IPU_ADC_DISP_IF_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x124)) +#define IPU_ADC_DISP_SIG_POL (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x128)) +#define IPU_DI_SER_DISP1_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x12C)) +#define IPU_DI_SER_DISP2_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x130)) +#define IPU_DI_HSP_CLK_PER (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x134)) +#define IPU_DI_DISP0_TIME_CONF_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x138)) +#define IPU_DI_DISP0_TIME_CONF_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x13C)) +#define IPU_DI_DISP0_TIME_CONF_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x140)) +#define IPU_DI_DISP1_TIME_CONF_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x144)) +#define IPU_DI_DISP1_TIME_CONF_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x148)) +#define IPU_DI_DISP1_TIME_CONF_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x14C)) +#define IPU_DI_DISP2_TIME_CONF_1 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x150)) +#define IPU_DI_DISP2_TIME_CONF_2 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x154)) +#define IPU_DI_DISP2_TIME_CONF_3 (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x158)) +#define IPU_DI_DISP3_TIME_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x15C)) +#define IPU_DI_DISP0_DB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x160)) +#define IPU_DI_DISP0_DB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x164)) +#define IPU_DI_DISP0_DB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x168)) +#define IPU_DI_DISP0_CB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x16C)) +#define IPU_DI_DISP0_CB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x170)) +#define IPU_DI_DISP0_CB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x174)) +#define IPU_DI_DISP1_DB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x178)) +#define IPU_DI_DISP1_DB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x17C)) +#define IPU_DI_DISP1_DB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x180)) +#define IPU_DI_DISP1_CB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x184)) +#define IPU_DI_DISP1_CB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x188)) +#define IPU_DI_DISP1_CB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x18C)) +#define IPU_DI_DISP2_DB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x190)) +#define IPU_DI_DISP2_DB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x194)) +#define IPU_DI_DISP2_DB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x198)) +#define IPU_DI_DISP2_CB0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x19C)) +#define IPU_DI_DISP2_CB1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1A0)) +#define IPU_DI_DISP2_CB2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1A4)) +#define IPU_DI_DISP3_B0_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1A8)) +#define IPU_DI_DISP3_B1_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1AC)) +#define IPU_DI_DISP3_B2_MAP (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1B0)) +#define IPU_DI_DISP_ACC_CC (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1B4)) +#define IPU_DI_DISP_LLA_CONF (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1B8)) +#define IPU_DI_DISP_LLA_DATA (*(REG32_PTR_T)(IPU_CTRL_BASE_ADDR+0x1BC)) + +/* IPU_CONF */ +#define IPU_IPU_CONF_PXL_ENDIAN (1 << 8) +#define IPU_IPU_CONF_DU_EN (1 << 7) +#define IPU_IPU_CONF_DI_EN (1 << 6) +#define IPU_IPU_CONF_ADC_EN (1 << 5) +#define IPU_IPU_CONF_SDC_EN (1 << 4) +#define IPU_IPU_CONF_PF_EN (1 << 3) +#define IPU_IPU_CONF_ROT_EN (1 << 2) +#define IPU_IPU_CONF_IC_EN (1 << 1) +#define IPU_IPU_CONF_CSI_EN (1 << 0) /* ATA */ #define ATA_TIME_OFF (*(REG8_PTR_T)(ATA_BASE_ADDR+0x00)) @@ -493,7 +585,7 @@ #define CSPI_BITCOUNT(n) ((n) << 8) #define CSPI_CONREG_SSPOL (1 << 7) #define CSPI_CONREG_SSCTL (1 << 6) -#define CSPI_CONREG_PHA (1 << 6) +#define CSPI_CONREG_PHA (1 << 5) #define CSPI_CONREG_POL (1 << 4) #define CSPI_CONREG_SMC (1 << 3) #define CSPI_CONREG_XCH (1 << 2) diff --git a/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c index fd0aebe3a2..fbcd54059e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/lcd-gigabeat-s.c @@ -22,7 +22,10 @@ #include "inttypes.h" #include "config.h" +#include "system.h" #include "cpu.h" +#include "spi-imx31.h" +#include "mc13783.h" #include "string.h" #include "lcd.h" #include "kernel.h" @@ -32,16 +35,117 @@ #define MAIN_LCD_IDMAC_CHANNEL 14 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) -static bool lcd_on = true; -static bool lcd_powered = true; -static unsigned lcd_yuv_options = 0; - /* Copies a rectangle from one framebuffer to another. Can be used in single transfer mode with width = num pixels, and height = 1 which allows a full-width rectangle to be copied more efficiently. */ extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, int width, int height); +static bool lcd_on = true; +static bool lcd_powered = true; +static unsigned lcd_yuv_options = 0; + +#if 0 +/* Initialization data from OF bootloader. Identical to Gigabeat F/X. */ +static const unsigned char lcd_init_data[50] = +{ + /* Reg Val */ + 0x0f, 0x01, + 0x09, 0x06, + 0x16, 0xa6, + 0x1e, 0x49, + 0x1f, 0x26, + 0x0b, 0x2f, /* Set contrast 0-63 */ + 0x0c, 0x2b, + 0x19, 0x5e, + 0x1a, 0x15, + 0x1b, 0x15, + 0x1d, 0x01, + 0x00, 0x03, + 0x01, 0x10, + 0x02, 0x0a, + 0x06, 0x04, /* Set the orientation 2=upside down, 4=normal */ + 0x08, 0x2e, + 0x24, 0x12, + 0x25, 0x3f, + 0x26, 0x0b, + 0x27, 0x00, + 0x28, 0x00, + 0x29, 0xf6, + 0x2a, 0x03, + 0x2b, 0x0a, + 0x04, 0x01, /* Display ON */ +}; +#endif + +static const struct spi_node lcd_spi_node = +{ + /* Original firmware settings for LCD panel commication */ + CSPI3_NUM, /* CSPI module 3 */ + CSPI_CONREG_CHIP_SELECT_SS1 | /* Chip select 1 */ + CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */ + CSPI_CONREG_DATA_RATE_DIV_16 | /* Clock = IPG_CLK/16 = 4,125,000Hz. */ + CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */ + CSPI_CONREG_SSPOL | /* SS active high */ + CSPI_CONREG_PHA | /* Phase 1 operation */ + CSPI_CONREG_POL | /* Active low polarity */ + CSPI_CONREG_MODE, /* Master mode */ + 0, /* SPI clock - no wait states */ +}; + +static void lcd_write_reg(unsigned reg, unsigned val) +{ + /* packet: |00|rr|01|vv| */ + uint32_t packet = ((reg & 0xff) << 16) | 0x0100 | (val & 0xff); + + struct spi_transfer_desc xfer; + + xfer.node = &lcd_spi_node; + xfer.txbuf = &packet; + xfer.rxbuf = NULL; + xfer.count = 1; + xfer.callback = NULL; + xfer.next = NULL; + + if (spi_transfer(&xfer)) + { + /* Just busy wait; the interface is not used very much */ + while (!spi_transfer_complete(&xfer)); + } +} + +static void lcd_enable_interface(bool enable) +{ + if (enable) + { + spi_enable_module(&lcd_spi_node); + } + else + { + spi_disable_module(&lcd_spi_node); + } +} + +static void lcd_set_power(bool powered) +{ + if (powered) + { + lcd_powered = false; + lcd_write_reg(0x04, 0x00); + lcd_enable_interface(false); + imx31_regclr32(&GPIO3_DR, (1 << 12)); + mc13783_clear(MC13783_REGULATOR_MODE1, MC13783_VCAMEN); + } + else + { + mc13783_set(MC13783_REGULATOR_MODE1, MC13783_VCAMEN); + imx31_regset32(&GPIO3_DR, (1 << 12)); + lcd_enable_interface(true); + lcd_write_reg(0x04, 0x01); + lcd_powered = true; + } +} + /* LCD init */ void lcd_init_device(void) { @@ -50,8 +154,19 @@ void lcd_init_device(void) /* Only do this once to avoid flicker */ memset(FRAME, 0x00, FRAME_SIZE); #endif - IPU_IMA_ADDR = ((0x1 << 16) | (MAIN_LCD_IDMAC_CHANNEL << 4)) + (1 << 3); - IPU_IMA_DATA = FRAME_PHYS_ADDR; + IPU_IPU_IMA_ADDR = ((0x1 << 16) | (MAIN_LCD_IDMAC_CHANNEL << 4)) + (1 << 3); + IPU_IPU_IMA_DATA = FRAME_PHYS_ADDR; + + lcd_enable_interface(true); +#ifdef HAVE_LCD_CONTRAST + lcd_set_contrast(DEFAULT_CONTRAST_SETTING); +#endif +#ifdef HAVE_LCD_INVERT + lcd_set_invert_display(false); +#endif +#ifdef HAVE_LCD_FLIP + lcd_set_flip(false); +#endif } /* Update a fraction of the display. */ @@ -96,13 +211,14 @@ void lcd_update_rect(int x, int y, int width, int height) void lcd_sleep(void) { - if (lcd_powered) - { - lcd_enable(false); - lcd_powered = false; - IPU_IDMAC_CHA_EN &= ~(1ul << MAIN_LCD_IDMAC_CHANNEL); - _backlight_lcd_sleep(); - } + if (!lcd_powered) + return; + + IPU_IDMAC_CHA_EN &= ~(1ul << MAIN_LCD_IDMAC_CHANNEL); + IPU_IPU_CONF &= ~IPU_IPU_CONF_ADC_EN; + lcd_enable(false); + lcd_set_power(false); + _backlight_lcd_sleep(); } void lcd_enable(bool state) @@ -112,9 +228,11 @@ void lcd_enable(bool state) if (state) { + if (!lcd_powered) + lcd_set_power(true); + IPU_IPU_CONF |= IPU_IPU_CONF_ADC_EN; IPU_IDMAC_CHA_EN |= 1ul << MAIN_LCD_IDMAC_CHANNEL; sleep(HZ/50); - lcd_powered = true; lcd_on = true; lcd_update(); send_event(LCD_EVENT_ACTIVATION, NULL); @@ -211,18 +329,37 @@ void lcd_blit_yuv(unsigned char * const src[3], } } -void lcd_set_contrast(int val) { - (void) val; - // TODO: +#ifdef HAVE_LCD_CONTRAST +void lcd_set_contrast(int val) +{ + if (!lcd_on) + return; + + lcd_write_reg(0x0b, val); } -void lcd_set_invert_display(bool yesno) { - (void) yesno; - // TODO: +int lcd_default_contrast(void) +{ + return DEFAULT_CONTRAST_SETTING; } +#endif /* HAVE_LCD_CONTRAST */ -void lcd_set_flip(bool yesno) { - (void) yesno; - // TODO: +#ifdef HAVE_LCD_INVERT +void lcd_set_invert_display(bool yesno) +{ + if (!lcd_on) + return; + + lcd_write_reg(0x27, yesno ? 0x10 : 00); } +#endif /* HAVE_LCD_INVERT */ +#ifdef HAVE_LCD_FLIP +void lcd_set_flip(bool yesno) +{ + if (!lcd_on) + return; + + lcd_write_reg(0x06, yesno ? 0x02 : 0x04); +} +#endif /* HAVE_LCD_FLIP */ diff --git a/firmware/target/arm/imx31/spi-imx31.c b/firmware/target/arm/imx31/spi-imx31.c index e6dddd65c1..e0187e4388 100644 --- a/firmware/target/arm/imx31/spi-imx31.c +++ b/firmware/target/arm/imx31/spi-imx31.c @@ -435,3 +435,9 @@ bool spi_transfer(struct spi_transfer_desc *xfer) return retval; } + +/* Returns 'true' if the descriptor is not busy */ +bool spi_transfer_complete(const struct spi_transfer_desc *xfer) +{ + return xfer->next == NULL; +} diff --git a/firmware/target/arm/imx31/spi-imx31.h b/firmware/target/arm/imx31/spi-imx31.h index 71f9512103..35b7d514cf 100644 --- a/firmware/target/arm/imx31/spi-imx31.h +++ b/firmware/target/arm/imx31/spi-imx31.h @@ -83,4 +83,7 @@ void spi_disable_module(const struct spi_node *node); /* Send and/or receive data on the specified node (asychronous) */ bool spi_transfer(struct spi_transfer_desc *xfer); +/* Returns 'true' if the descriptor is not busy */ +bool spi_transfer_complete(const struct spi_transfer_desc *xfer); + #endif /* SPI_IMX31_H */ -- cgit v1.2.3