|
@@ -37,12 +37,14 @@
|
|
|
|
|
|
#include <cybook.h>
|
|
|
|
|
|
-#define DEBUG_MESSAGES
|
|
|
-#define DEBUG_TRACEFUNC
|
|
|
+//#define DEBUG_MESSAGES
|
|
|
+//#define DEBUG_TRACEFUNC
|
|
|
+//#define VERBOSE_LEVEL INFO_WARNING
|
|
|
+//#define DEBUG_SPI
|
|
|
|
|
|
#define MODULE_NAME "AUO-TCON"
|
|
|
|
|
|
-#define BUSY_WAIT_TIMEOUT (40*5*2) //panel time out = 1s
|
|
|
+#define BUSY_WAIT_TIMEOUT (40*5*2) //panel time out = 1s
|
|
|
#define SYS_WR_CON (1<<6)
|
|
|
#define SYS_OE_CON (1<<7)
|
|
|
|
|
@@ -57,12 +59,12 @@ enum InfoLevel
|
|
|
INFO_ERROR = 0,
|
|
|
INFO_WARNING,
|
|
|
INFO_NORMAL,
|
|
|
- INFO_DEBUG,
|
|
|
INFO_VERBOSE,
|
|
|
+ INFO_DEBUG,
|
|
|
};
|
|
|
|
|
|
# ifndef VERBOSE_LEVEL
|
|
|
-# define VERBOSE_LEVEL INFO_VERBOSE
|
|
|
+# define VERBOSE_LEVEL INFO_WARNING
|
|
|
# endif
|
|
|
|
|
|
# ifdef DEBUG_TRACEFUNC
|
|
@@ -168,7 +170,7 @@ static int _dbg_FunctionLevel = 0;
|
|
|
#define VIDTCON2_LINEVAL_S (11)
|
|
|
|
|
|
static int tcon_inPortraitMode = 0;
|
|
|
-
|
|
|
+static int tcon_lastModeWas = 0;
|
|
|
typedef enum Tcon_Speedclasses
|
|
|
{
|
|
|
EN_I80_NONE = -1,
|
|
@@ -186,6 +188,14 @@ typedef struct Tcon_SpeedclasseValue
|
|
|
u8 wr_hold;
|
|
|
} Tcon_SpeedclasseValue;
|
|
|
|
|
|
+typedef enum Tcon_PowerMode
|
|
|
+{
|
|
|
+ TCON_POWER_NORMALMODE,
|
|
|
+ TCON_POWER_STANDBYMODE,
|
|
|
+ TCON_POWER_SLEEPMODE,
|
|
|
+ TCON_POWER_OFF,
|
|
|
+} Tcon_PowerMode;
|
|
|
+
|
|
|
static Tcon_SpeedclasseValue tcon_speedtable[] =
|
|
|
{
|
|
|
[EN_I80_LANDSCAPE] =
|
|
@@ -202,6 +212,7 @@ static Tcon_SpeedclasseValue tcon_speedtable[] =
|
|
|
.wr_act = 8,
|
|
|
.wr_hold = 3,
|
|
|
},
|
|
|
+#if 1
|
|
|
[EN_I80_LANDSCAPE_HANDWRITING] =
|
|
|
{
|
|
|
.cs_setup = 0,
|
|
@@ -216,10 +227,26 @@ static Tcon_SpeedclasseValue tcon_speedtable[] =
|
|
|
.wr_act = 6,
|
|
|
.wr_hold = 2,
|
|
|
},
|
|
|
+#else
|
|
|
+ [EN_I80_PORTRAIT_HANDWRITING] =
|
|
|
+ {
|
|
|
+ .cs_setup = 0,
|
|
|
+ .wr_setup = 1,
|
|
|
+ .wr_act = 1,
|
|
|
+ .wr_hold = 0,
|
|
|
+ },
|
|
|
+ [EN_I80_LANDSCAPE_HANDWRITING] =
|
|
|
+ {
|
|
|
+ .cs_setup = 0,
|
|
|
+ .wr_setup = 2,
|
|
|
+ .wr_act = 6,
|
|
|
+ .wr_hold = 2,
|
|
|
+ },
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static Tcon_Speedclasses tcon_currentSpeedClass = EN_I80_NONE;
|
|
|
-
|
|
|
+static Tcon_PowerMode tcon_currentPowerMode = TCON_POWER_NORMALMODE;
|
|
|
// ===========================================================================
|
|
|
// TCON Related functions
|
|
|
// ===========================================================================
|
|
@@ -311,6 +338,8 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed,
|
|
|
|
|
|
FUNC_IN();
|
|
|
|
|
|
+ INFOL(INFO_WARNING, ("speedclass: %d\n", i80_speed));
|
|
|
+
|
|
|
if ( tcon_currentSpeedClass == EN_I80_NONE)
|
|
|
set_clock = true;
|
|
|
|
|
@@ -318,7 +347,7 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed,
|
|
|
|
|
|
if (set_clock == true)
|
|
|
{
|
|
|
- INFOL(INFO_VERBOSE, ("Will set clocks..."));
|
|
|
+ INFOL(INFO_DEBUG, ("Will set clocks..."));
|
|
|
|
|
|
tmp = __raw_readl(S3C_VIDCON0);
|
|
|
tmp = VIDCON0_S_CPU_IF_MAIN | VIDCON0_S_RGB_PAR | \
|
|
@@ -371,8 +400,12 @@ static inline void tcon_i80bus_write (int data)
|
|
|
tmp |= SYS_WR_CON;
|
|
|
__raw_writel(tmp, S3C_SIFCCON0);
|
|
|
|
|
|
- if ( !tcon_inPortraitMode )
|
|
|
+ if (( !tcon_inPortraitMode ) && (tcon_lastModeWas != 4))
|
|
|
tcon_ndelay(25);
|
|
|
+ else if (( tcon_inPortraitMode ) && (tcon_lastModeWas == 4))
|
|
|
+ tcon_ndelay(15);
|
|
|
+
|
|
|
+
|
|
|
|
|
|
__raw_writel(data, S3C_SIFCCON1); //rSIFCCON1 = CMD;
|
|
|
|
|
@@ -381,6 +414,49 @@ static inline void tcon_i80bus_write (int data)
|
|
|
__raw_writel(tmp, S3C_SIFCCON0);
|
|
|
}
|
|
|
|
|
|
+static inline void tcon_i80bus_write_LUT(int data)
|
|
|
+{
|
|
|
+ int tmp;
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+ tmp = __raw_readl(S3C_SIFCCON0); // nWE enable
|
|
|
+ tmp |= SYS_WR_CON;
|
|
|
+ __raw_writel(tmp, S3C_SIFCCON0);
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+
|
|
|
+ __raw_writel(data, S3C_SIFCCON1); //rSIFCCON1 = CMD;
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+
|
|
|
+ tmp = __raw_readl(S3C_SIFCCON0); // nWE disable
|
|
|
+ tmp &= ~SYS_WR_CON;
|
|
|
+ __raw_writel(tmp, S3C_SIFCCON0);
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static inline void tcon_i80bus_read (unsigned short *data)
|
|
|
+{
|
|
|
+ int tmp;
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+
|
|
|
+ tmp = __raw_readl(S3C_SIFCCON0); // nRD enable
|
|
|
+ tmp |= SYS_OE_CON;
|
|
|
+ __raw_writel(tmp, S3C_SIFCCON0);
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+
|
|
|
+ *data = __raw_readl(S3C_SIFCCON2); //CMD = rSIFCCON2;
|
|
|
+
|
|
|
+ tcon_delay(1);
|
|
|
+
|
|
|
+ tmp = __raw_readl(S3C_SIFCCON0); // nRD disable
|
|
|
+ tmp &= ~SYS_OE_CON;
|
|
|
+ __raw_writel(tmp, S3C_SIFCCON0);
|
|
|
+}
|
|
|
+
|
|
|
static inline void tcon_set_write_to_data(void)
|
|
|
{
|
|
|
unsigned long tmp;
|
|
@@ -469,55 +545,108 @@ static inline void tcon_unselect_chip(void)
|
|
|
FUNC_OUT();
|
|
|
}
|
|
|
|
|
|
+static inline void tcon_set_power_on(void)
|
|
|
+{
|
|
|
+ unsigned long tmp = __raw_readl(S3C2410_GPBDAT);
|
|
|
+ tmp |= (1 << 3);
|
|
|
+ __raw_writel(tmp, S3C2410_GPBDAT);
|
|
|
+
|
|
|
+ tcon_currentPowerMode = TCON_POWER_NORMALMODE;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void tcon_set_power_off(void)
|
|
|
+{
|
|
|
+ unsigned long tmp = __raw_readl(S3C2410_GPBDAT);
|
|
|
+ tmp &= ~(1 << 3);
|
|
|
+ __raw_writel(tmp, S3C2410_GPBDAT);
|
|
|
+
|
|
|
+ tcon_currentPowerMode = TCON_POWER_OFF;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
int tcon_send_command_start(sAUOCommand *cmd)
|
|
|
{
|
|
|
FUNC_IN();
|
|
|
- INFOL(INFO_VERBOSE,("cmd #%08lX", cmd->cmd));
|
|
|
+ INFOL(INFO_DEBUG,("cmd #%08lX", cmd->cmd));
|
|
|
/* First: verify that the K1900 is ready */
|
|
|
|
|
|
- INFOL(INFO_VERBOSE, ("/* First: verify that the K1900 is ready */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* First: verify that the K1900 is ready */"));
|
|
|
if (GET_COMMAND_NEED_WAIT(cmd->cmd) != 0x00)
|
|
|
{
|
|
|
- INFOL(INFO_VERBOSE, ("Wait for non BUSY..."));
|
|
|
+ INFOL(INFO_DEBUG, ("Wait for non BUSY..."));
|
|
|
tcon_wait_ready();
|
|
|
}
|
|
|
|
|
|
- if (cmd->cmd == AUOCMD_INIT_SET)
|
|
|
+ if (cmd->cmd == AUOCMD_STANDBY)
|
|
|
+ tcon_currentPowerMode = TCON_POWER_STANDBYMODE;
|
|
|
+ else if (cmd->cmd == AUOCMD_WAKEUP)
|
|
|
+ tcon_currentPowerMode = TCON_POWER_NORMALMODE;
|
|
|
+ else if (cmd->cmd == AUOCMD_INIT_SET)
|
|
|
{
|
|
|
tcon_inPortraitMode = ~(cmd->params[0]) & (0x1 << 10);
|
|
|
- if (tcon_inPortraitMode)
|
|
|
- tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false);
|
|
|
- else
|
|
|
- tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false);
|
|
|
- INFOL(INFO_VERBOSE, ("Rotation set to 0x%08X...", tcon_inPortraitMode));
|
|
|
+ if (tcon_lastModeWas != 4)
|
|
|
+ {
|
|
|
+ if (tcon_inPortraitMode)
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false);
|
|
|
+ else
|
|
|
+ tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (tcon_inPortraitMode)
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false);
|
|
|
+ else
|
|
|
+ tcon_i80bus_set_speed(EN_I80_LANDSCAPE_HANDWRITING, 600, 800, false);
|
|
|
+ }
|
|
|
+ INFOL(INFO_DEBUG, ("Rotation set to 0x%08X...", tcon_inPortraitMode));
|
|
|
+ }
|
|
|
+ else if (cmd->cmd == AUOCMD_DISPLAY_START)
|
|
|
+ {
|
|
|
+ INFOL(INFO_VERBOSE, ("Display Start (lastMode: %d)...", tcon_lastModeWas));
|
|
|
+ if (((cmd->params[0] >> 12) & 0x07) == 4) /* Handwriting mode... */
|
|
|
+ {
|
|
|
+ INFOL(INFO_VERBOSE, ("Mode 4"));
|
|
|
+ if (tcon_inPortraitMode)
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false);
|
|
|
+ else
|
|
|
+ tcon_i80bus_set_speed(EN_I80_LANDSCAPE_HANDWRITING, 600, 800, false);
|
|
|
+ }
|
|
|
+ else if (tcon_lastModeWas == 4)
|
|
|
+ {
|
|
|
+ INFOL(INFO_VERBOSE, ("--- NOT --- mode 4 (%d)", ((cmd->params[0] >> 12) & 0x07)));
|
|
|
+ if (tcon_inPortraitMode)
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false);
|
|
|
+ else
|
|
|
+ tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false);
|
|
|
+ }
|
|
|
+ tcon_lastModeWas = ((cmd->params[0] >> 12) & 0x07);
|
|
|
}
|
|
|
-
|
|
|
/* Second: init the i80 interface */
|
|
|
- INFOL(INFO_VERBOSE, ("/* Second: init the i80 interface */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Second: init the i80 interface */"));
|
|
|
tcon_i80bus_init_interface();
|
|
|
/* Third: Select the chip and set to Command mode */
|
|
|
- INFOL(INFO_VERBOSE, ("/* Third: Select the chip and set to Command mode */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Third: Select the chip and set to Command mode */"));
|
|
|
tcon_select_chip();
|
|
|
tcon_set_write_to_command();
|
|
|
|
|
|
/* Fourth: Send command */
|
|
|
- INFOL(INFO_VERBOSE, ("/* Fourth: Send command */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Fourth: Send command */"));
|
|
|
tcon_i80bus_write(cmd->cmd & 0xFFFF); /* This function already manage
|
|
|
* no need to do it here. */
|
|
|
|
|
|
/* Sixth: If parameters is needed, send them */
|
|
|
- INFOL(INFO_VERBOSE, ("/* Sixth: If parameters is needed, send them */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Sixth: If parameters is needed, send them */"));
|
|
|
if (GET_COMMAND_PARAM_NUM(cmd->cmd) > 0)
|
|
|
{
|
|
|
int i, paramNumbers = GET_COMMAND_PARAM_NUM(cmd->cmd);
|
|
|
|
|
|
- INFOL(INFO_VERBOSE, ("YES! We have %d parameters", paramNumbers));
|
|
|
+ INFOL(INFO_DEBUG, ("YES! We have %d parameters", paramNumbers));
|
|
|
|
|
|
tcon_set_write_to_data();
|
|
|
|
|
|
for (i = 0; i < paramNumbers; i++)
|
|
|
{
|
|
|
- INFOL(INFO_VERBOSE, (" parameter [%02d] = 0x%04X", i, cmd->params[i]));
|
|
|
+ INFOL(INFO_DEBUG, (" parameter [%02d] = 0x%04X", i, cmd->params[i]));
|
|
|
tcon_i80bus_write(cmd->params[i]);
|
|
|
}
|
|
|
|
|
@@ -544,20 +673,60 @@ int tcon_send_data(unsigned short *buffer, unsigned long bufferLen)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int tcon_send_lut_data(unsigned short *buffer, unsigned long bufferLen)
|
|
|
+{
|
|
|
+ /* Seventh: Send data if needed */
|
|
|
+ unsigned long i;
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ INFOL(INFO_DEBUG, ("Bufferlen: %ld", bufferLen));
|
|
|
+
|
|
|
+ tcon_set_write_to_data();
|
|
|
+
|
|
|
+ for (i = 0; i < bufferLen; i++)
|
|
|
+ {
|
|
|
+ tcon_delay(1);
|
|
|
+ tcon_wait_ready();
|
|
|
+ tcon_delay(1);
|
|
|
+ tcon_i80bus_write_LUT(buffer[i]);
|
|
|
+ }
|
|
|
+ INFOL(INFO_DEBUG, ("Done."));
|
|
|
+ FUNC_OUT();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int tcon_read_data(unsigned short *buffer, unsigned long bufferLen)
|
|
|
+{
|
|
|
+ unsigned long i;
|
|
|
+ //FUNC_IN();
|
|
|
+
|
|
|
+ //INFOL(INFO_VERBOSE, ("Bufferlen: %ld", bufferLen));
|
|
|
+
|
|
|
+ tcon_set_write_to_data();
|
|
|
+
|
|
|
+ for (i = 0; i < bufferLen; i++)
|
|
|
+ {
|
|
|
+ tcon_i80bus_read(&(buffer[i]));
|
|
|
+ }
|
|
|
+ //FUNC_OUT();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int tcon_send_command_end(sAUOCommand *cmd)
|
|
|
{
|
|
|
FUNC_IN();
|
|
|
|
|
|
- INFOL(INFO_VERBOSE,("cmd #%08lX START:[#%08X]", cmd->cmd, AUOCMD_DISPLAY_START));
|
|
|
+ INFOL(INFO_DEBUG,("cmd #%08lX START:[#%08X]", cmd->cmd, AUOCMD_DISPLAY_START));
|
|
|
if (cmd->cmd == AUOCMD_DISPLAY_START)
|
|
|
{
|
|
|
tcon_set_write_to_command();
|
|
|
- INFOL(INFO_VERBOSE, ("/* Eight: Send STOP command */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Eight: Send STOP command */"));
|
|
|
tcon_i80bus_write(AUOCMD_DISPLAY_STOP & 0xFFFF);
|
|
|
tcon_set_write_to_data();
|
|
|
}
|
|
|
|
|
|
- INFOL(INFO_VERBOSE, ("/* Nineth: Close all */"));
|
|
|
+ INFOL(INFO_DEBUG, ("/* Nineth: Close all */"));
|
|
|
tcon_unselect_chip();
|
|
|
tcon_i80bus_deinit_interface();
|
|
|
|
|
@@ -565,6 +734,234 @@ int tcon_send_command_end(sAUOCommand *cmd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+// ===========================================================================
|
|
|
+// Bit Bang SPI Interface
|
|
|
+// ===========================================================================
|
|
|
+#define TCON_SPI_CLK S3C2410_GPE13
|
|
|
+#define TCON_SPI_DI S3C2410_GPE11
|
|
|
+#define TCON_SPI_DO S3C2410_GPE12
|
|
|
+#define TCON_SPI_CS S3C2410_GPL13
|
|
|
+
|
|
|
+static void tcon_spi_init(void)
|
|
|
+{
|
|
|
+ FUNC_IN();
|
|
|
+ /* First be sure that the Wifi is off */
|
|
|
+ /* GPK5 = PA 3.3V */
|
|
|
+ writel((readl(S3C2416_GPKDAT) & ~(1<<5)), S3C2416_GPKDAT);
|
|
|
+ /* GPK6 = PA 1.8V */
|
|
|
+ writel((readl(S3C2416_GPKDAT) & ~(1<<6)), S3C2416_GPKDAT);
|
|
|
+
|
|
|
+ /* Next, shutdown the TCON */
|
|
|
+ tcon_set_power_off();
|
|
|
+ mdelay(2000);
|
|
|
+
|
|
|
+ //GPD8, RESET
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPD8, S3C2410_GPD8_OUTP);
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPD8, 0);
|
|
|
+ /* Next, Switch the SPI */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPH6, S3C2410_GPH6_OUTP);
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPH6, 1);
|
|
|
+ mdelay(200);
|
|
|
+
|
|
|
+ /* Next, init GPIOs */
|
|
|
+
|
|
|
+ /* GPL13 = SPI Chip Select */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPL13, S3C2410_GPL13_OUTP);
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPL13, 1);
|
|
|
+
|
|
|
+ /* GPE11 = SPI DI */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_INP);
|
|
|
+ s3c2410_gpio_pullup(S3C2410_GPE11, 0);
|
|
|
+
|
|
|
+ /* GPE12 = SPI DO */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_OUTP);
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPE12, 1);
|
|
|
+
|
|
|
+ /* GPE13 = SPI CLK */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_OUTP);
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPE13, 0);
|
|
|
+
|
|
|
+ mdelay(50);
|
|
|
+
|
|
|
+ /* We are ready ! */
|
|
|
+ FUNC_OUT();
|
|
|
+}
|
|
|
+
|
|
|
+static void tcon_spi_deinit(void)
|
|
|
+{
|
|
|
+ FUNC_IN();
|
|
|
+ /* First, switch the SPI */
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPH6, 1);
|
|
|
+
|
|
|
+ /* Then, restore GPIOs */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPL13, S3C2410_GPL13_SS0);
|
|
|
+ /* GPE11 = SPI DI */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
|
|
|
+ /* GPE12 = SPI DO */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
|
|
|
+ /* GPE13 = SPI CLK */
|
|
|
+ s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
|
|
|
+
|
|
|
+ /* Next, switch back on the TCON */
|
|
|
+ tcon_set_power_on();
|
|
|
+ s3c2410_gpio_setpin(S3C2410_GPD8, 1);
|
|
|
+ mdelay(100);
|
|
|
+ /* The calling must restore the TCON status, we only set it back on */
|
|
|
+ FUNC_OUT();
|
|
|
+}
|
|
|
+
|
|
|
+static inline unsigned char tcon_spi_read (void)
|
|
|
+{
|
|
|
+ unsigned char k,
|
|
|
+ tmp_data = 0,
|
|
|
+ i = 0;
|
|
|
+ u32 read_pin;
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ char strobe_str[9];
|
|
|
+ strobe_str[8] = 0;
|
|
|
+#endif
|
|
|
+ /* sure that the clock is low */
|
|
|
+ for ( k = 0; k < 8; k++ )
|
|
|
+ {
|
|
|
+ /* Strobe clock */
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CLK, 1);
|
|
|
+ udelay(2);
|
|
|
+
|
|
|
+ /* Sample */
|
|
|
+ read_pin = s3c2410_gpio_getpin(TCON_SPI_DI);//(readl(S3C2410_GPEDAT) & (1 << 11));
|
|
|
+
|
|
|
+ if ( read_pin )
|
|
|
+ {
|
|
|
+ i = (0x80 >> k);
|
|
|
+ tmp_data = (tmp_data | i);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ strobe_str[k] = (read_pin?'-':'_');
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* ACK bit read */
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CLK, 0);
|
|
|
+ udelay(2);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ INFOL(INFO_VERBOSE, ("WFM:[%s] return %d", strobe_str, tmp_data));
|
|
|
+#endif
|
|
|
+
|
|
|
+ return (tmp_data);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void tcon_spi_write(unsigned char value)
|
|
|
+{
|
|
|
+ unsigned char k;
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ char strobe_str[9];
|
|
|
+ strobe_str[8] = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+ for ( k = 0; k < 8; k++ )
|
|
|
+ {
|
|
|
+ if ( (value & 0x80) )
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_DO, 1);
|
|
|
+ else
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_DO, 0);
|
|
|
+
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ strobe_str[k] = ((value&0x80)?'-':'_');
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Strobe clock */
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CLK, 1);
|
|
|
+ udelay(2);
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CLK, 0);
|
|
|
+ udelay(2);
|
|
|
+
|
|
|
+ value = (value << 1);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_SPI
|
|
|
+ INFOL(INFO_VERBOSE, ("WFM:[%s]", strobe_str));
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned char tcon_spi_flash_read(unsigned char value)
|
|
|
+{
|
|
|
+ unsigned char ret;
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 0);
|
|
|
+ udelay(50);
|
|
|
+
|
|
|
+ tcon_spi_write(value);
|
|
|
+ udelay(2);
|
|
|
+ ret = tcon_spi_read();
|
|
|
+
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 1);
|
|
|
+ udelay(50);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void tcon_spi_flash_write(unsigned char value)
|
|
|
+{
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 0);
|
|
|
+ udelay(50);
|
|
|
+
|
|
|
+ tcon_spi_write(value);
|
|
|
+
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 1);
|
|
|
+ udelay(50);
|
|
|
+}
|
|
|
+
|
|
|
+static void tcon_spi_flash_waitready(void)
|
|
|
+{
|
|
|
+ unsigned char r_data;
|
|
|
+ FUNC_IN();
|
|
|
+ do
|
|
|
+ {
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 0);
|
|
|
+ udelay(50);
|
|
|
+ tcon_spi_write(0x05); //Write Read Status command
|
|
|
+ udelay(2);
|
|
|
+ r_data = tcon_spi_read();
|
|
|
+ udelay(50);
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 1);
|
|
|
+ INFOL(INFO_DEBUG, ("r_data: 0x%02x [SRWD:%c BP2:%d BP1:%d BP0:%d, WEL:%c, WIP:%c]\n", r_data,
|
|
|
+ (r_data & 0x80)?'E':'D',
|
|
|
+ (r_data & 0x10)?1:0,
|
|
|
+ (r_data & 0x08)?1:0,
|
|
|
+ (r_data & 0x04)?1:0,
|
|
|
+ (r_data & 0x02)?'E':'D',
|
|
|
+ (r_data & 0x01)?'W':'r'));
|
|
|
+ msleep(20);
|
|
|
+
|
|
|
+ } while ( r_data & 0x01 );
|
|
|
+ FUNC_OUT();
|
|
|
+}
|
|
|
+
|
|
|
+static void tcon_spi_flash_writepage(unsigned long addr, unsigned char *buffer, unsigned short buffer_len)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ FUNC_IN();
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 0);
|
|
|
+ udelay(50);
|
|
|
+
|
|
|
+ tcon_spi_write(0x02); //Write Page Program command
|
|
|
+ tcon_spi_write( (addr & 0xFF0000) >> 16 );
|
|
|
+ tcon_spi_write( (addr & 0xFF00) >> 8 );
|
|
|
+ tcon_spi_write( (addr & 0xFF) );
|
|
|
+
|
|
|
+ for(i=0; i<buffer_len; i++)
|
|
|
+ {
|
|
|
+ tcon_spi_write(buffer[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ s3c2410_gpio_setpin(TCON_SPI_CS, 1);
|
|
|
+ mdelay(10);
|
|
|
+
|
|
|
+ tcon_spi_flash_waitready();
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
+}
|
|
|
|
|
|
// ===========================================================================
|
|
|
// Device related functions
|
|
@@ -604,17 +1001,28 @@ int tcon_ioctl (struct inode *inode, struct file *file,
|
|
|
unsigned char *user_buffer;
|
|
|
unsigned long user_buflen, copysize, copysize16;
|
|
|
unsigned short *ptr16;
|
|
|
+ unsigned long tmp;
|
|
|
void __user *argp = (void __user *)arg;
|
|
|
+ int block_id = 0;
|
|
|
+ int flash_addr;
|
|
|
+ int ret = -EINVAL;
|
|
|
|
|
|
FUNC_IN();
|
|
|
-
|
|
|
+ INFOL(INFO_VERBOSE, ("Receive IOTCL #08%X", ioctl_cmd));
|
|
|
switch ( ioctl_cmd )
|
|
|
{
|
|
|
- /* [MTR] */
|
|
|
case IOCTL_AUO_SENDCOMMAND:
|
|
|
if ( copy_from_user(&cmd, argp, sizeof (cmd)) )
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ /* Prevent to send command if the user don't provide a buffer */
|
|
|
+ if ((GET_COMMAND_READ_WRITE(cmd.cmd) != 0) && (cmd.datalen == 0))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ /* Prevent if we set data and data prt is NULL */
|
|
|
+ if (( GET_COMMAND_HAVE_DATA(cmd.cmd) != 0 ) && (cmd.datalen > 0) && (cmd.data == NULL))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
/* Now execute the command */
|
|
|
tcon_send_command_start(&cmd);
|
|
|
|
|
@@ -631,16 +1039,30 @@ int tcon_ioctl (struct inode *inode, struct file *file,
|
|
|
|
|
|
if ( user_buflen > sizeof (buffer) )
|
|
|
copysize = sizeof (buffer);
|
|
|
-
|
|
|
- if ( copy_from_user(buffer, user_buffer, copysize) )
|
|
|
- return -EFAULT;
|
|
|
+ if (GET_COMMAND_READ_WRITE(cmd.cmd) == 0)
|
|
|
+ { /* Write mode */
|
|
|
+ if ( copy_from_user(buffer, user_buffer, copysize) )
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
|
|
|
copysize16 = (copysize + 1) / 2;
|
|
|
//printk(KERN_ERR "cp16=%ld cp=%ld\n", copysize16, copysize);
|
|
|
|
|
|
ptr16 = (unsigned short *)buffer;
|
|
|
-
|
|
|
- tcon_send_data((unsigned short *)buffer, copysize16);
|
|
|
+ if (GET_COMMAND_READ_WRITE(cmd.cmd) == 0)
|
|
|
+ { /* Write mode */
|
|
|
+ INFOL(INFO_DEBUG, ("Will send block %d", block_id++));
|
|
|
+ if (cmd.cmd == AUOCMD_LUT_START)
|
|
|
+ tcon_send_lut_data((unsigned short *)buffer, copysize16);
|
|
|
+ else
|
|
|
+ tcon_send_data((unsigned short *)buffer, copysize16);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ tcon_read_data((unsigned short *)buffer, copysize16);
|
|
|
+ if ( copy_to_user(user_buffer, buffer, copysize) )
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
|
|
|
user_buflen -= copysize;
|
|
|
user_buffer += copysize;
|
|
@@ -649,12 +1071,134 @@ int tcon_ioctl (struct inode *inode, struct file *file,
|
|
|
|
|
|
|
|
|
tcon_send_command_end(&cmd);
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
|
|
|
+ case IOCTL_AUO_RESET:
|
|
|
+ tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to LOW
|
|
|
+ tmp &= ~(1 << 9);
|
|
|
+ __raw_writel(tmp, S3C2410_GPDDAT);
|
|
|
+
|
|
|
+ tcon_delay(5);
|
|
|
+
|
|
|
+ tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to HIGH
|
|
|
+ tmp |= (1 << 9);
|
|
|
+ __raw_writel(tmp, S3C2410_GPDDAT);
|
|
|
+
|
|
|
+ // delay about 10ms
|
|
|
+ msleep(10);
|
|
|
+
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false);
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IOCTL_AUO_SLEEP:
|
|
|
+ /* Only accept go to sleep if we are in standby, or else it will fail */
|
|
|
+ if (tcon_currentPowerMode == TCON_POWER_STANDBYMODE)
|
|
|
+ {
|
|
|
+ tcon_currentPowerMode = TCON_POWER_SLEEPMODE;
|
|
|
+
|
|
|
+ /* Set GPIO accordingly */
|
|
|
+ tmp = __raw_readl(S3C2410_GPBDAT);
|
|
|
+ tmp &= ~(1 << 1); //Set SLP_N to low
|
|
|
+ __raw_writel(tmp, S3C2410_GPBDAT);
|
|
|
+ msleep(10);
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ ret = -ENAVAIL;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IOCTL_AUO_WAKEUP:
|
|
|
+ /* Only accept go to sleep if we are in standby, or else it will fail */
|
|
|
+ if (tcon_currentPowerMode == TCON_POWER_SLEEPMODE)
|
|
|
+ {
|
|
|
+ tcon_currentPowerMode = TCON_POWER_STANDBYMODE;
|
|
|
+ /* Set GPIO accordingly */
|
|
|
+ tmp = __raw_readl(S3C2410_GPBDAT);
|
|
|
+ tmp |= (1 << 1); //Set SLP_N to high
|
|
|
+ __raw_writel(tmp, S3C2410_GPBDAT);
|
|
|
+ msleep(10);
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ ret = -ENAVAIL;
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case IOCTL_AUO_UPDATEFW:
|
|
|
+ INFOL(INFO_VERBOSE, ("Starting update of TCON firmware..."));
|
|
|
+ if ( copy_from_user(&cmd, argp, sizeof (cmd)) )
|
|
|
+ {
|
|
|
+ INFOL(INFO_ERROR, ("Copy from User error..."));
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
+
|
|
|
+ INFOL(INFO_VERBOSE, ("Starting update of TCON firmware..."));
|
|
|
+
|
|
|
+ if ((cmd.data == NULL) || (cmd.datalen == 0))
|
|
|
+ {
|
|
|
+ INFOL(INFO_ERROR, ("Parameters error..."));
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* First init SPI */
|
|
|
+ INFOL(INFO_VERBOSE, ("Will init BitBang SPI..."));
|
|
|
+ tcon_spi_init();
|
|
|
+
|
|
|
+ mdelay(3000);
|
|
|
+
|
|
|
+ flash_addr = 0;
|
|
|
+ INFOL(INFO_VERBOSE, ("Erasing SPI flash..."));
|
|
|
+ /* Erase Flash */
|
|
|
+ tcon_spi_flash_write(0x06); //Setting Write Enable Latch bit
|
|
|
+ tcon_spi_flash_write(0x60); //Write Chip Erase command
|
|
|
+ msleep(100);
|
|
|
+
|
|
|
+ tcon_spi_flash_waitready();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ user_buflen = cmd.datalen;
|
|
|
+ user_buffer = (unsigned char *)cmd.data;
|
|
|
+ INFOL(INFO_VERBOSE, ("Will start write of TCON firmware..."));
|
|
|
+ /* Now, Write new Flash content */
|
|
|
+ while ( user_buflen != 0 )
|
|
|
+ {
|
|
|
+ copysize = user_buflen;
|
|
|
+ INFOL(INFO_DEBUG, ("Flash page @ addr 0x%08X", flash_addr));
|
|
|
+
|
|
|
+ if ( user_buflen > 256 )
|
|
|
+ copysize = 256;
|
|
|
+
|
|
|
+ if ( copy_from_user(buffer, user_buffer, copysize) )
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ /* Send Buffer data */
|
|
|
+ tcon_spi_flash_write(0x06); /* Enable write... */
|
|
|
+ tcon_spi_flash_writepage(flash_addr, buffer, copysize);
|
|
|
+
|
|
|
+ flash_addr += copysize;
|
|
|
+ user_buflen -= copysize;
|
|
|
+ user_buffer += copysize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Restore SPI */
|
|
|
+ tcon_spi_deinit();
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "Invalid ioctl");
|
|
|
+ ret = -EINVAL;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
FUNC_OUT();
|
|
|
- return -EINVAL;
|
|
|
+ return ret;
|
|
|
}
|
|
|
// ===========================================================================
|
|
|
static struct file_operations s_tcon_fops =
|
|
@@ -733,13 +1277,13 @@ static int tcon_probe (struct platform_device *dev)
|
|
|
tmp |= (1 << 9);
|
|
|
__raw_writel(tmp, S3C2410_GPDDAT);
|
|
|
|
|
|
- tmp = __raw_readl(S3C2410_GPDDAT); // goes to LOW
|
|
|
+ tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to LOW
|
|
|
tmp &= ~(1 << 9);
|
|
|
__raw_writel(tmp, S3C2410_GPDDAT);
|
|
|
|
|
|
tcon_delay(5);
|
|
|
|
|
|
- tmp = __raw_readl(S3C2410_GPDDAT); // goes to HIGH
|
|
|
+ tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to HIGH
|
|
|
tmp |= (1 << 9);
|
|
|
__raw_writel(tmp, S3C2410_GPDDAT);
|
|
|
|
|
@@ -769,6 +1313,11 @@ static int tcon_resume (struct platform_device *dev)
|
|
|
{
|
|
|
FUNC_IN();
|
|
|
|
|
|
+ if (tcon_inPortraitMode)
|
|
|
+ tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, true);
|
|
|
+ else
|
|
|
+ tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, true);
|
|
|
+
|
|
|
FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|