[U-Boot] [PATCH 0/3] Add support for SPI based DataImage LCD panel

This patch ports the Linux driver for DataImage SCF0403852GGU04 and SCF0403526GGU20 LCD panels into U-Boot. As a preparation step, variable SPI word length support is added to omap3_spi and the generic SPI interface. Finally, the driver is used in cm_t35 board.
The SPI changes were tested with a Beagle I2C/SPI/MDIO Protocol Analyzer, and also with a DataImage SCF0403 lcd as part of the DataImage driver test.
Patch number 3 depends on http://patchwork.ozlabs.org/patch/275283/
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Cc: Jagannadha Sutradharudu Teki jagannadh.teki@gmail.com
Nikita Kiryanov (3): spi: omap3: add support for more word lengths lcd: add DataImage SCF0403x LCD panel support cm_t35: use scf0403 driver
arch/arm/include/asm/arch-omap3/dss.h | 9 +- board/compulab/cm_t35/cm_t35.c | 12 ++ board/compulab/common/omap3_display.c | 46 +++++- drivers/spi/omap3_spi.c | 78 +++++++-- drivers/spi/omap3_spi.h | 11 +- drivers/video/Makefile | 1 + drivers/video/scf0403_lcd.c | 298 ++++++++++++++++++++++++++++++++++ include/configs/cm_t35.h | 3 + include/scf0403_lcd.h | 22 +++ include/spi.h | 14 ++ 10 files changed, 467 insertions(+), 27 deletions(-) create mode 100644 drivers/video/scf0403_lcd.c create mode 100644 include/scf0403_lcd.h

Current implementation only supports 8 bit word lengths, even though omap3 can handle anything between 4 and 32.
Update the spi interface to support changing the SPI word length, and implement it in omap3_spi driver to support the full range of possible word lengths. This implementation is backwards compatible by defaulting to the old behavior of 8 bit word lengths. Also, it required a change to the omap3_spi non static I/O functions, but since they are not used anywhere else, no collateral changes are required.
Cc: Tom Rini trini@ti.com Cc: Igor Grinberg grinberg@compulab.co.il Cc: Jagannadha Sutradharudu Teki jagannadh.teki@gmail.com Signed-off-by: Nikita Kiryanov nikita@compulab.co.il --- drivers/spi/omap3_spi.c | 78 ++++++++++++++++++++++++++++++++++++++----------- drivers/spi/omap3_spi.h | 11 ++++--- include/spi.h | 13 +++++++++ 3 files changed, 81 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 6bac245..add98e1 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define WORD_LEN 8 +#define SPI_DEFAULT_WORDLEN 8; #define SPI_WAIT_TIMEOUT 3000000;
static void spi_reset(struct omap3_spi_slave *ds) @@ -128,10 +128,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, ds->regs = regs; ds->freq = max_hz; ds->mode = mode; + ds->wordlen = SPI_DEFAULT_WORDLEN;
return &ds->slave; }
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{ + struct omap3_spi_slave *ds; + int chconf; + + if (wordlen < 4 || wordlen > 32) { + printf("SPI error: unsupported wordlen %d\n", wordlen); + return -1; + } + + ds = to_omap3_spi(slave); + ds->wordlen = wordlen; + + chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); + chconf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; + chconf |= (wordlen - 1) << 7; + omap3_spi_write_chconf(ds, chconf); + + return 0; +} + void spi_free_slave(struct spi_slave *slave) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -185,7 +207,7 @@ int spi_claim_bus(struct spi_slave *slave)
/* wordlength */ conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; - conf |= (WORD_LEN - 1) << 7; + conf |= (ds->wordlen - 1) << 7;
/* set chipselect polarity; manage with FORCE */ if (!(ds->mode & SPI_CS_HIGH)) @@ -223,7 +245,7 @@ void spi_release_bus(struct spi_slave *slave) spi_reset(ds); }
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -250,7 +272,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); }
/* wait to finish of transfer */ @@ -268,7 +296,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, return 0; }
-int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -302,7 +330,13 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
/* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); }
if (flags & SPI_XFER_END) { @@ -314,8 +348,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, }
/*McSPI Transmit Receive Mode*/ -int omap3_spi_txrx(struct spi_slave *slave, - unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags) +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, + const void *txp, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); int timeout = SPI_WAIT_TIMEOUT; @@ -344,7 +378,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx);
/*Read: wait for RX containing data (RXS == 1)*/ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & @@ -356,7 +396,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } /* Disable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); @@ -375,14 +421,12 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct omap3_spi_slave *ds = to_omap3_spi(slave); unsigned int len; - const u8 *txp = dout; - u8 *rxp = din; int ret = -1;
- if (bitlen % 8) + if (bitlen % ds->wordlen) return -1;
- len = bitlen / 8; + len = bitlen / ds->wordlen;
if (bitlen == 0) { /* only change CS */ int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); @@ -400,11 +444,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, ret = 0; } else { if (dout != NULL && din != NULL) - ret = omap3_spi_txrx(slave, len, txp, rxp, flags); + ret = omap3_spi_txrx(slave, len, dout, din, flags); else if (dout != NULL) - ret = omap3_spi_write(slave, len, txp, flags); + ret = omap3_spi_write(slave, len, dout, flags); else if (din != NULL) - ret = omap3_spi_read(slave, len, rxp, flags); + ret = omap3_spi_read(slave, len, din, flags); } return ret; } diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h index 01537b6..aeddb53 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -92,6 +92,7 @@ struct omap3_spi_slave { struct mcspi *regs; unsigned int freq; unsigned int mode; + unsigned int wordlen; };
static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) @@ -99,11 +100,13 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_slave, slave); }
-int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp, - u8 *rxp, unsigned long flags); -int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); + +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp, + void *rxp, unsigned long flags); +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags); -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags);
#endif /* _OMAP3_SPI_H_ */ diff --git a/include/spi.h b/include/spi.h index c0dab57..ae318ff 100644 --- a/include/spi.h +++ b/include/spi.h @@ -149,6 +149,19 @@ int spi_claim_bus(struct spi_slave *slave); void spi_release_bus(struct spi_slave *slave);
/*----------------------------------------------------------------------- + * Set the word length for SPI transactions + * + * Set the word length (number of bits per word) for SPI transactions. + * This setting is persistent until changed. + * + * slave: The SPI slave + * wordlen: The number of bits in a word + * + * Returns: 0 on success, -1 on failure. + */ +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); + +/*----------------------------------------------------------------------- * SPI transfer * * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks

On Wed, Oct 09, 2013 at 17:46 +0300, Nikita Kiryanov wrote:
--- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define WORD_LEN 8 +#define SPI_DEFAULT_WORDLEN 8; #define SPI_WAIT_TIMEOUT 3000000;
static void spi_reset(struct omap3_spi_slave *ds)
This is strictly speaking unrelated to your change, but might be worth getting fixed in a separate submission. I haven't read your patch in the meaning of a review, just happened to spot this nit before skipping to the next message ...
The semicolon in a #define for a constant is certainly wrong. This applies to both your new line as well as the context which already was in place. The code may appear to work, but for sanity and to avoid future problems the defines should get fixed. You might add the separate cleanup patch in front of the new feature should feedback make you send another version of your series, or send a fix individually (and check for other occurances for bonus points).
virtually yours Gerhard Sittig

Hi Nikita,
On 10/09/13 16:46, Nikita Kiryanov wrote:
Current implementation only supports 8 bit word lengths, even though omap3 can handle anything between 4 and 32.
Update the spi interface to support changing the SPI word length, and implement it in omap3_spi driver to support the full range of possible word lengths. This implementation is backwards compatible by defaulting to the old behavior of 8 bit word lengths. Also, it required a change to the omap3_spi non static I/O functions, but since they are not used anywhere else, no collateral changes are required.
Cc: Tom Rini trini@ti.com Cc: Igor Grinberg grinberg@compulab.co.il Cc: Jagannadha Sutradharudu Teki jagannadh.teki@gmail.com Signed-off-by: Nikita Kiryanov nikita@compulab.co.il
drivers/spi/omap3_spi.c | 78 ++++++++++++++++++++++++++++++++++++++----------- drivers/spi/omap3_spi.h | 11 ++++--- include/spi.h | 13 +++++++++ 3 files changed, 81 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 6bac245..add98e1 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define WORD_LEN 8 +#define SPI_DEFAULT_WORDLEN 8;
As already pointed out, the semicolon should not be there...
#define SPI_WAIT_TIMEOUT 3000000;
While at this, can you please, send a separate patch to fix the above semicolon?
static void spi_reset(struct omap3_spi_slave *ds) @@ -128,10 +128,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, ds->regs = regs; ds->freq = max_hz; ds->mode = mode;
- ds->wordlen = SPI_DEFAULT_WORDLEN;
While we know, OMAP SPI controller supports this, I think many other controllers can also support this feature and thus their drivers can benefit from this option.
Wouldn't it be better to add the wordlen field to the generic slave structure instead of the OMAP specific structure?
return &ds->slave; }
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{
- struct omap3_spi_slave *ds;
- int chconf;
- if (wordlen < 4 || wordlen > 32) {
printf("SPI error: unsupported wordlen %d\n", wordlen);
return -1;
- }
- ds = to_omap3_spi(slave);
- ds->wordlen = wordlen;
- chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
- chconf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
- chconf |= (wordlen - 1) << 7;
- omap3_spi_write_chconf(ds, chconf);
I would recommend to update the controller just before the transaction takes place, e.g. in spi_xfer() function, so the spi_set_wordlen() function will only update the slave structure and will not touch the hardware. Thus spi_set_wordlen() can be placed in the generic SPI code.
- return 0;
+}
void spi_free_slave(struct spi_slave *slave) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -185,7 +207,7 @@ int spi_claim_bus(struct spi_slave *slave)
/* wordlength */ conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
- conf |= (WORD_LEN - 1) << 7;
conf |= (ds->wordlen - 1) << 7;
/* set chipselect polarity; manage with FORCE */ if (!(ds->mode & SPI_CS_HIGH))
@@ -223,7 +245,7 @@ void spi_release_bus(struct spi_slave *slave) spi_reset(ds); }
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -250,7 +272,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, } } /* Write the data */
writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
if (ds->wordlen > 16)
writel(((u32 *)txp)[i], tx);
else if (ds->wordlen > 8)
writel(((u16 *)txp)[i], tx);
else
writel(((u8 *)txp)[i], tx);
Can we always have u32 for the txp and use masks ans shifts instead of the ugly castings?
}
/* wait to finish of transfer */
@@ -268,7 +296,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, return 0; }
-int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -302,7 +330,13 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
/* Read the data */
rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
if (ds->wordlen > 16)
((u32 *)rxp)[i] = readl(rx);
else if (ds->wordlen > 8)
((u16 *)rxp)[i] = (u16)readl(rx);
else
((u8 *)rxp)[i] = (u8)readl(rx);
same here...
}
if (flags & SPI_XFER_END) { @@ -314,8 +348,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, }
/*McSPI Transmit Receive Mode*/ -int omap3_spi_txrx(struct spi_slave *slave,
unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
+int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
const void *txp, void *rxp, unsigned long flags)
{ struct omap3_spi_slave *ds = to_omap3_spi(slave); int timeout = SPI_WAIT_TIMEOUT; @@ -344,7 +378,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Write the data */
writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
if (ds->wordlen > 16)
writel(((u32 *)txp)[i], tx);
else if (ds->wordlen > 8)
writel(((u16 *)txp)[i], tx);
else
writel(((u8 *)txp)[i], tx);
and here...
/*Read: wait for RX containing data (RXS == 1)*/ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
@@ -356,7 +396,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Read the data */
rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
if (ds->wordlen > 16)
((u32 *)rxp)[i] = readl(rx);
else if (ds->wordlen > 8)
((u16 *)rxp)[i] = (u16)readl(rx);
else
((u8 *)rxp)[i] = (u8)readl(rx);
and here...
} /* Disable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); @@ -375,14 +421,12 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct omap3_spi_slave *ds = to_omap3_spi(slave); unsigned int len;
const u8 *txp = dout;
u8 *rxp = din; int ret = -1;
if (bitlen % 8)
- if (bitlen % ds->wordlen) return -1;
- len = bitlen / 8;
len = bitlen / ds->wordlen;
if (bitlen == 0) { /* only change CS */ int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
@@ -400,11 +444,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, ret = 0; } else { if (dout != NULL && din != NULL)
ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
else if (dout != NULL)ret = omap3_spi_txrx(slave, len, dout, din, flags);
ret = omap3_spi_write(slave, len, txp, flags);
else if (din != NULL)ret = omap3_spi_write(slave, len, dout, flags);
ret = omap3_spi_read(slave, len, rxp, flags);
} return ret;ret = omap3_spi_read(slave, len, din, flags);
} diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h index 01537b6..aeddb53 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -92,6 +92,7 @@ struct omap3_spi_slave { struct mcspi *regs; unsigned int freq; unsigned int mode;
- unsigned int wordlen;
See above.
};
static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) @@ -99,11 +100,13 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_slave, slave); }
-int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp,
u8 *rxp, unsigned long flags);
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
+int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp,
void *rxp, unsigned long flags);
+int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags); -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags);
u32 *?
#endif /* _OMAP3_SPI_H_ */
[...]
diff --git a/include/spi.h b/include/spi.h index c0dab57..ae318ff 100644 --- a/include/spi.h +++ b/include/spi.h @@ -149,6 +149,19 @@ int spi_claim_bus(struct spi_slave *slave); void spi_release_bus(struct spi_slave *slave);
/*-----------------------------------------------------------------------
- Set the word length for SPI transactions
- Set the word length (number of bits per word) for SPI transactions.
- This setting is persistent until changed.
- slave: The SPI slave
- wordlen: The number of bits in a word
- Returns: 0 on success, -1 on failure.
- */
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
+/*-----------------------------------------------------------------------
- SPI transfer
- This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks

On 10/14/2013 05:18 PM, Igor Grinberg wrote:
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 6bac245..add98e1 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include <asm/io.h> #include "omap3_spi.h"
-#define WORD_LEN 8 +#define SPI_DEFAULT_WORDLEN 8;
As already pointed out, the semicolon should not be there...
Will fix
#define SPI_WAIT_TIMEOUT 3000000;
While at this, can you please, send a separate patch to fix the above semicolon?
Will do
static void spi_reset(struct omap3_spi_slave *ds) @@ -128,10 +128,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, ds->regs = regs; ds->freq = max_hz; ds->mode = mode;
- ds->wordlen = SPI_DEFAULT_WORDLEN;
While we know, OMAP SPI controller supports this, I think many other controllers can also support this feature and thus their drivers can benefit from this option.
Wouldn't it be better to add the wordlen field to the generic slave structure instead of the OMAP specific structure?
Makes sense. Will move wordlen to struct spi_slave.
return &ds->slave; }
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{
- struct omap3_spi_slave *ds;
- int chconf;
- if (wordlen < 4 || wordlen > 32) {
printf("SPI error: unsupported wordlen %d\n", wordlen);
return -1;
- }
- ds = to_omap3_spi(slave);
- ds->wordlen = wordlen;
- chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
- chconf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
- chconf |= (wordlen - 1) << 7;
- omap3_spi_write_chconf(ds, chconf);
I would recommend to update the controller just before the transaction takes place, e.g. in spi_xfer() function, so the spi_set_wordlen() function will only update the slave structure and will not touch the hardware. Thus spi_set_wordlen() can be placed in the generic SPI code.
Yes that is better. Will do.
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -250,7 +272,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, } } /* Write the data */
writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
if (ds->wordlen > 16)
writel(((u32 *)txp)[i], tx);
else if (ds->wordlen > 8)
writel(((u16 *)txp)[i], tx);
else
writel(((u8 *)txp)[i], tx);
Can we always have u32 for the txp and use masks ans shifts instead of the ugly castings?
Working with masks and shifts will basically do the same thing that the casts do, but in a more complicated way. The best way to get rid of the casts will be to store SPI words in u32 arrays to begin with, regardless of the size of SPI word. Unfortunately, this is actually a difficult change:
If we change omap3_spi implementation to work with u32 arrays we also have to change cmd_spi.c, which stores data in byte arrays, and then we will be forced to change all the other U-Boot SPI implementations.
Due to the scope of this change I think it should be done in another patch series.

Add SPI-based driver for DataImage SCF0403852GGU04 and SCF0403526GGU20 LCD panels.
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Signed-off-by: Nikita Kiryanov nikita@compulab.co.il --- drivers/video/Makefile | 1 + drivers/video/scf0403_lcd.c | 298 ++++++++++++++++++++++++++++++++++++++++++++ include/scf0403_lcd.h | 22 ++++ include/spi.h | 1 + 4 files changed, 322 insertions(+) create mode 100644 drivers/video/scf0403_lcd.c create mode 100644 include/scf0403_lcd.h
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 6c208c5..e7324d1 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -22,6 +22,7 @@ COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o COBJS-$(CONFIG_L5F31188) += l5f31188.o COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o +COBJS-$(CONFIG_SCF0403_LCD) += scf0403_lcd.o COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o COBJS-$(CONFIG_S6E63D6) += s6e63d6.o COBJS-$(CONFIG_LD9040) += ld9040.o diff --git a/drivers/video/scf0403_lcd.c b/drivers/video/scf0403_lcd.c new file mode 100644 index 0000000..1d1c3ff --- /dev/null +++ b/drivers/video/scf0403_lcd.c @@ -0,0 +1,298 @@ +/* + * scf0403.c -- support for DataImage SCF0403 LCD + * + * Copyright (c) 2013 Adapted from Linux driver: + * Copyright (c) 2012 Anders Electronics plc. All Rights Reserved. + * Copyright (c) 2012 CompuLab, Ltd + * Dmitry Lifshitz lifshitz@compulab.co.il + * Ilya Ledvich ilya@compulab.co.il + * Inspired by Alberto Panizzo maramaopercheseimorto@gmail.com & + * Marek Vasut work in l4f00242t03.c + * + * U-Boot port: Nikita Kiryanov nikita@compulab.co.il + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/gpio.h> +#include <spi.h> + +struct scf0403_cmd { + u16 cmd; + u16 *params; + int count; +}; + +struct scf0403_initseq_entry { + struct scf0403_cmd cmd; + int delay_ms; +}; + +struct scf0403_priv { + struct spi_slave *spi; + unsigned int reset_gpio; + u32 rddid; + struct scf0403_initseq_entry *init_seq; + int seq_size; +}; + +struct scf0403_priv priv; + +#define SCF0403852GGU04_ID 0x000080 + +/* SCF0403526GGU20 model commands parameters */ +static u16 extcmd_params_sn20[] = {0xff, 0x98, 0x06}; +static u16 spiinttype_params_sn20[] = {0x60}; +static u16 bc_params_sn20[] = { + 0x01, 0x10, 0x61, 0x74, 0x01, 0x01, 0x1B, + 0x12, 0x71, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x05, 0x00, 0xFF, 0xF2, 0x01, 0x00, 0x40, +}; +static u16 bd_params_sn20[] = {0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67}; +static u16 be_params_sn20[] = { + 0x01, 0x22, 0x22, 0xBA, 0xDC, 0x26, 0x28, 0x22, 0x22, +}; +static u16 vcom_params_sn20[] = {0x74}; +static u16 vmesur_params_sn20[] = {0x7F, 0x0F, 0x00}; +static u16 powerctl_params_sn20[] = {0x03, 0x0b, 0x00}; +static u16 lvglvolt_params_sn20[] = {0x08}; +static u16 engsetting_params_sn20[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; +static u16 dispfunc_params_sn20[] = {0xa0}; +static u16 dvddvolt_params_sn20[] = {0x74}; +static u16 dispinv_params_sn20[] = {0x00, 0x00, 0x00}; +static u16 panelres_params_sn20[] = {0x82}; +static u16 framerate_params_sn20[] = {0x00, 0x13, 0x13}; +static u16 timing_params_sn20[] = {0x80, 0x05, 0x40, 0x28}; +static u16 powerctl2_params_sn20[] = {0x17, 0x75, 0x79, 0x20}; +static u16 memaccess_params_sn20[] = {0x00}; +static u16 pixfmt_params_sn20[] = {0x66}; +static u16 pgamma_params_sn20[] = { + 0x00, 0x03, 0x0b, 0x0c, 0x0e, 0x08, 0xc5, 0x04, + 0x08, 0x0c, 0x13, 0x11, 0x11, 0x14, 0x0c, 0x10, +}; +static u16 ngamma_params_sn20[] = { + 0x00, 0x0d, 0x11, 0x0c, 0x0c, 0x04, 0x76, 0x03, + 0x08, 0x0b, 0x16, 0x10, 0x0d, 0x16, 0x0a, 0x00, +}; +static u16 tearing_params_sn20[] = {0x00}; + +/* SCF0403852GGU04 model commands parameters */ +static u16 memaccess_params_sn04[] = {0x08}; +static u16 pixfmt_params_sn04[] = {0x66}; +static u16 modectl_params_sn04[] = {0x01}; +static u16 dispfunc_params_sn04[] = {0x22, 0xe2, 0xFF, 0x04}; +static u16 vcom_params_sn04[] = {0x00, 0x6A}; +static u16 pgamma_params_sn04[] = { + 0x00, 0x07, 0x0d, 0x10, 0x13, 0x19, 0x0f, 0x0c, + 0x05, 0x08, 0x06, 0x13, 0x0f, 0x30, 0x20, 0x1f, +}; +static u16 ngamma_params_sn04[] = { + 0x1F, 0x20, 0x30, 0x0F, 0x13, 0x06, 0x08, 0x05, + 0x0C, 0x0F, 0x19, 0x13, 0x10, 0x0D, 0x07, 0x00, +}; +static u16 dispinv_params_sn04[] = {0x02}; + +/* Common commands */ +static struct scf0403_cmd scf0403_cmd_slpout = {0x11, NULL, 0}; +static struct scf0403_cmd scf0403_cmd_dison = {0x29, NULL, 0}; + +/* SCF0403852GGU04 init sequence */ +static struct scf0403_initseq_entry scf0403_initseq_sn04[] = { + {{0x36, memaccess_params_sn04, ARRAY_SIZE(memaccess_params_sn04)}, 0}, + {{0x3A, pixfmt_params_sn04, ARRAY_SIZE(pixfmt_params_sn04)}, 0}, + {{0xB6, dispfunc_params_sn04, ARRAY_SIZE(dispfunc_params_sn04)}, 0}, + {{0xC5, vcom_params_sn04, ARRAY_SIZE(vcom_params_sn04)}, 0}, + {{0xE0, pgamma_params_sn04, ARRAY_SIZE(pgamma_params_sn04)}, 0}, + {{0xE1, ngamma_params_sn04, ARRAY_SIZE(ngamma_params_sn04)}, 20}, + {{0xB0, modectl_params_sn04, ARRAY_SIZE(modectl_params_sn04)}, 0}, + {{0xB4, dispinv_params_sn04, ARRAY_SIZE(dispinv_params_sn04)}, 100}, +}; + +/* SCF0403526GGU20 init sequence */ +static struct scf0403_initseq_entry scf0403_initseq_sn20[] = { + {{0xff, extcmd_params_sn20, ARRAY_SIZE(extcmd_params_sn20)}, 0}, + {{0xba, spiinttype_params_sn20, ARRAY_SIZE(spiinttype_params_sn20)}, 0}, + {{0xbc, bc_params_sn20, ARRAY_SIZE(bc_params_sn20)}, 0}, + {{0xbd, bd_params_sn20, ARRAY_SIZE(bd_params_sn20)}, 0}, + {{0xbe, be_params_sn20, ARRAY_SIZE(be_params_sn20)}, 0}, + {{0xc7, vcom_params_sn20, ARRAY_SIZE(vcom_params_sn20)}, 0}, + {{0xed, vmesur_params_sn20, ARRAY_SIZE(vmesur_params_sn20)}, 0}, + {{0xc0, powerctl_params_sn20, ARRAY_SIZE(powerctl_params_sn20)}, 0}, + {{0xfc, lvglvolt_params_sn20, ARRAY_SIZE(lvglvolt_params_sn20)}, 0}, + {{0xb6, dispfunc_params_sn20, ARRAY_SIZE(dispfunc_params_sn20)}, 0}, + {{0xdf, engsetting_params_sn20, ARRAY_SIZE(engsetting_params_sn20)}, 0}, + {{0xf3, dvddvolt_params_sn20, ARRAY_SIZE(dvddvolt_params_sn20)}, 0}, + {{0xb4, dispinv_params_sn20, ARRAY_SIZE(dispinv_params_sn20)}, 0}, + {{0xf7, panelres_params_sn20, ARRAY_SIZE(panelres_params_sn20)}, 0}, + {{0xb1, framerate_params_sn20, ARRAY_SIZE(framerate_params_sn20)}, 0}, + {{0xf2, timing_params_sn20, ARRAY_SIZE(timing_params_sn20)}, 0}, + {{0xc1, powerctl2_params_sn20, ARRAY_SIZE(powerctl2_params_sn20)}, 0}, + {{0x36, memaccess_params_sn20, ARRAY_SIZE(memaccess_params_sn20)}, 0}, + {{0x3a, pixfmt_params_sn20, ARRAY_SIZE(pixfmt_params_sn20)}, 0}, + {{0xe0, pgamma_params_sn20, ARRAY_SIZE(pgamma_params_sn20)}, 0}, + {{0xe1, ngamma_params_sn20, ARRAY_SIZE(ngamma_params_sn20)}, 0}, + {{0x35, tearing_params_sn20, ARRAY_SIZE(tearing_params_sn20)}, 0}, +}; + +static void scf0403_gpio_reset(unsigned int gpio) +{ + if (!gpio_is_valid(gpio)) + return; + + gpio_set_value(gpio, 1); + mdelay(100); + gpio_set_value(gpio, 0); + mdelay(40); + gpio_set_value(gpio, 1); + mdelay(100); +} + +static int scf0403_spi_read_rddid(struct spi_slave *spi, u32 *rddid) +{ + int error = 0; + u8 ids_buf = 0x00; + u16 dummy_buf = 0x00; + u16 cmd = 0x04; + + error = spi_set_wordlen(spi, 9); + if (error) + return error; + + /* Here 9 bits required to transmit a command */ + error = spi_xfer(spi, 9, &cmd, NULL, SPI_XFER_ONCE); + if (error) + return error; + + /* + * Here 8 + 1 bits required to arrange extra clock cycle + * before the first data bit. + * According to the datasheet - first parameter is the dummy data. + */ + error = spi_xfer(spi, 9, NULL, &dummy_buf, SPI_XFER_ONCE); + if (error) + return error; + + error = spi_set_wordlen(spi, 8); + if (error) + return error; + + /* Read rest of the data */ + error = spi_xfer(spi, 8, NULL, &ids_buf, SPI_XFER_ONCE); + if (error) + return error; + + *rddid = ids_buf; + + return 0; +} + +static int scf0403_spi_transfer(struct spi_slave *spi, struct scf0403_cmd *cmd) +{ + int i, error; + u32 command = cmd->cmd; + u32 msg; + + error = spi_set_wordlen(spi, 9); + if (error) + return error; + + error = spi_xfer(spi, 9, &command, NULL, SPI_XFER_ONCE); + if (error) + return error; + + for (i = 0; i < cmd->count; i++) { + msg = (cmd->params[i] | 0x100); + error = spi_xfer(spi, 9, &msg, NULL, SPI_XFER_ONCE); + if (error) + return error; + } + + return 0; +} + +static void scf0403_lcd_init(struct scf0403_priv *priv) +{ + int i; + + /* reset LCD */ + scf0403_gpio_reset(priv->reset_gpio); + + for (i = 0; i < priv->seq_size; i++) { + if (scf0403_spi_transfer(priv->spi, &priv->init_seq[i].cmd) < 0) + printf("SPI transfer failed\n"); + + mdelay(priv->init_seq[i].delay_ms); + } +} + +static int scf0403_request_reset_gpio(unsigned gpio) +{ + int err = gpio_request(gpio, "lcd reset"); + + if (err) + return err; + + err = gpio_direction_output(gpio, 0); + if (err) + gpio_free(gpio); + + return err; +} + +int scf0403_init(int reset_gpio) +{ + int error; + + if (!gpio_is_valid(reset_gpio)) { + printf("scf0403 reset_gpio not valid\n"); + return -1; + } + + priv.reset_gpio = reset_gpio; + error = scf0403_request_reset_gpio(reset_gpio); + if (error) { + printf("Failed requesting reset GPIO%d: %d\n", + reset_gpio, error); + return error; + } + + priv.spi = spi_setup_slave(3, 0, 1000000, SPI_MODE_0); + error = spi_claim_bus(priv.spi); + if (error) { + gpio_free(priv.reset_gpio); + return error; + } + + /* reset LCD */ + scf0403_gpio_reset(reset_gpio); + + error = scf0403_spi_read_rddid(priv.spi, &priv.rddid); + if (error) { + printf("IDs read failed\n"); + gpio_free(priv.reset_gpio); + spi_release_bus(priv.spi); + + return error; + } + + if (priv.rddid == SCF0403852GGU04_ID) { + priv.init_seq = scf0403_initseq_sn04; + priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn04); + } else { + priv.init_seq = scf0403_initseq_sn20; + priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn20); + } + + scf0403_lcd_init(&priv); + + /* Start operation */ + scf0403_spi_transfer(priv.spi, &scf0403_cmd_dison); + mdelay(100); + scf0403_spi_transfer(priv.spi, &scf0403_cmd_slpout); + spi_release_bus(priv.spi); + + return 0; +} diff --git a/include/scf0403_lcd.h b/include/scf0403_lcd.h new file mode 100644 index 0000000..1185d29 --- /dev/null +++ b/include/scf0403_lcd.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013, Compulab Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ +#ifndef SCF0403_LCD_H_ +#define SCF0403_LCD_H_ + +int scf0403_init(int reset_gpio); + +#endif diff --git a/include/spi.h b/include/spi.h index ae318ff..4441527 100644 --- a/include/spi.h +++ b/include/spi.h @@ -27,6 +27,7 @@ /* SPI transfer flags */ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +#define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END)
/* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec

On Wed, 9 Oct 2013 17:46:04 +0300 Nikita Kiryanov nikita@compulab.co.il wrote: ...
diff --git a/drivers/video/scf0403_lcd.c b/drivers/video/scf0403_lcd.c new file mode 100644 index 0000000..1d1c3ff --- /dev/null +++ b/drivers/video/scf0403_lcd.c @@ -0,0 +1,298 @@ +/*
- scf0403.c -- support for DataImage SCF0403 LCD
- Copyright (c) 2013 Adapted from Linux driver:
- Copyright (c) 2012 Anders Electronics plc. All Rights Reserved.
- Copyright (c) 2012 CompuLab, Ltd
Dmitry Lifshitz <lifshitz@compulab.co.il>
Ilya Ledvich <ilya@compulab.co.il>
- Inspired by Alberto Panizzo maramaopercheseimorto@gmail.com &
- Marek Vasut work in l4f00242t03.c
- U-Boot port: Nikita Kiryanov nikita@compulab.co.il
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
please use "SPDX-License-Identifier: GPL-2.0" here. See Licenses/README for more info.
...
- for (i = 0; i < priv->seq_size; i++) {
if (scf0403_spi_transfer(priv->spi, &priv->init_seq[i].cmd) < 0)
printf("SPI transfer failed\n");
using puts() for not formatted strings is preferred, please check in other places, too.
+++ b/include/scf0403_lcd.h @@ -0,0 +1,22 @@
...
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc.
also please use SPDX license identifier here, too.
Thanks,
Anatolij

Hi Nikita,
On 10/09/13 16:46, Nikita Kiryanov wrote:
Add SPI-based driver for DataImage SCF0403852GGU04 and SCF0403526GGU20 LCD panels.
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Signed-off-by: Nikita Kiryanov nikita@compulab.co.il
drivers/video/Makefile | 1 + drivers/video/scf0403_lcd.c | 298 ++++++++++++++++++++++++++++++++++++++++++++ include/scf0403_lcd.h | 22 ++++ include/spi.h | 1 + 4 files changed, 322 insertions(+) create mode 100644 drivers/video/scf0403_lcd.c create mode 100644 include/scf0403_lcd.h
[...]
diff --git a/drivers/video/scf0403_lcd.c b/drivers/video/scf0403_lcd.c new file mode 100644 index 0000000..1d1c3ff --- /dev/null +++ b/drivers/video/scf0403_lcd.c @@ -0,0 +1,298 @@
[...]
+static void scf0403_gpio_reset(unsigned int gpio) +{
- if (!gpio_is_valid(gpio))
return;
- gpio_set_value(gpio, 1);
- mdelay(100);
- gpio_set_value(gpio, 0);
- mdelay(40);
- gpio_set_value(gpio, 1);
- mdelay(100);
+}
[...]
+int scf0403_init(int reset_gpio) +{
- int error;
- if (!gpio_is_valid(reset_gpio)) {
printf("scf0403 reset_gpio not valid\n");
return -1;
The LCD reset pin does not have to be connected to a GPIO. Instead, it can be handled in another manner (e.g. by hardware). So, I don't think you should fail the LCD initialization if some kind of -EINVAL is passed.
- }
- priv.reset_gpio = reset_gpio;
- error = scf0403_request_reset_gpio(reset_gpio);
- if (error) {
printf("Failed requesting reset GPIO%d: %d\n",
reset_gpio, error);
return error;
- }
- priv.spi = spi_setup_slave(3, 0, 1000000, SPI_MODE_0);
- error = spi_claim_bus(priv.spi);
- if (error) {
gpio_free(priv.reset_gpio);
return error;
- }
- /* reset LCD */
- scf0403_gpio_reset(reset_gpio);
- error = scf0403_spi_read_rddid(priv.spi, &priv.rddid);
- if (error) {
printf("IDs read failed\n");
gpio_free(priv.reset_gpio);
spi_release_bus(priv.spi);
return error;
- }
- if (priv.rddid == SCF0403852GGU04_ID) {
priv.init_seq = scf0403_initseq_sn04;
priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn04);
- } else {
priv.init_seq = scf0403_initseq_sn20;
priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn20);
- }
- scf0403_lcd_init(&priv);
- /* Start operation */
- scf0403_spi_transfer(priv.spi, &scf0403_cmd_dison);
- mdelay(100);
- scf0403_spi_transfer(priv.spi, &scf0403_cmd_slpout);
- spi_release_bus(priv.spi);
- return 0;
+}
[...]
diff --git a/include/spi.h b/include/spi.h index ae318ff..4441527 100644 --- a/include/spi.h +++ b/include/spi.h @@ -27,6 +27,7 @@ /* SPI transfer flags */ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +#define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END)
This bit does not belong to the patch.
/* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec

Use scf0403 driver to add scf0403x LCD support for cm-t35 and cm-t3730 boards.
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Signed-off-by: Nikita Kiryanov nikita@compulab.co.il --- NOTE: This patch depends on http://patchwork.ozlabs.org/patch/275283/
arch/arm/include/asm/arch-omap3/dss.h | 9 ++++--- board/compulab/cm_t35/cm_t35.c | 12 +++++++++ board/compulab/common/omap3_display.c | 46 +++++++++++++++++++++++++++++++++-- include/configs/cm_t35.h | 3 +++ 4 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/arch/arm/include/asm/arch-omap3/dss.h b/arch/arm/include/asm/arch-omap3/dss.h index ae0babf..8bf6b48 100644 --- a/arch/arm/include/asm/arch-omap3/dss.h +++ b/arch/arm/include/asm/arch-omap3/dss.h @@ -178,10 +178,11 @@ struct venc_regs { #define LCD_INTERFACE_24_BIT 3
/* Polarity */ -#define DSS_IVS (1 << 12) -#define DSS_IHS (1 << 13) -#define DSS_IPC (1 << 14) -#define DSS_IEO (1 << 15) +#define DSS_IVS (1 << 12) +#define DSS_IHS (1 << 13) +#define DSS_IPC (1 << 14) +#define DSS_IEO (1 << 15) +#define DSS_ONOFF (1 << 17)
/* GFX format */ #define GFXFORMAT_BITMAP1 (0x0 << 1) diff --git a/board/compulab/cm_t35/cm_t35.c b/board/compulab/cm_t35/cm_t35.c index a6d4aba..51dd4a4 100644 --- a/board/compulab/cm_t35/cm_t35.c +++ b/board/compulab/cm_t35/cm_t35.c @@ -268,6 +268,9 @@ static void cm_t3x_set_common_muxconf(void) /* DVI enable */ MUX_VAL(CP(GPMC_NCS3), (IDIS | PTU | DIS | M4));/*GPMC_nCS3*/
+ /* DataImage backlight */ + MUX_VAL(CP(GPMC_NCS7), (IDIS | PTU | DIS | M4));/*GPIO_58*/ + /* CM-T3x Ethernet */ MUX_VAL(CP(GPMC_NCS5), (IDIS | PTU | DIS | M0)); /*GPMC_nCS5*/ MUX_VAL(CP(GPMC_CLK), (IEN | PTD | DIS | M4)); /*GPIO_59*/ @@ -374,6 +377,15 @@ static void cm_t3x_set_common_muxconf(void) MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); /*MMC1_DAT1*/ MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); /*MMC1_DAT2*/ MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); /*MMC1_DAT3*/ + + /* SPI */ + MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M1)); /*MCSPI4_CLK*/ + MUX_VAL(CP(MCBSP1_DX), (IEN | PTD | DIS | M1)); /*MCSPI4_SIMO*/ + MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M1)); /*MCSPI4_SOMI*/ + MUX_VAL(CP(MCBSP1_FSX), (IEN | PTU | EN | M1)); /*MCSPI4_CS0*/ + + /* display controls */ + MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | DIS | M4)); /*GPIO_157*/ }
static void cm_t35_set_muxconf(void) diff --git a/board/compulab/common/omap3_display.c b/board/compulab/common/omap3_display.c index ead821e..61707f5 100644 --- a/board/compulab/common/omap3_display.c +++ b/board/compulab/common/omap3_display.c @@ -14,6 +14,7 @@ #include <stdio_dev.h> #include <asm/arch/dss.h> #include <lcd.h> +#include <scf0403_lcd.h> #include <asm/arch-omap3/dss.h>
DECLARE_GLOBAL_DATA_PTR; @@ -22,6 +23,7 @@ enum display_type { NONE, DVI, DVI_CUSTOM, + DATA_IMAGE, /* #define CONFIG_SCF0403_LCD to use */ };
#define CMAP_ADDR 0x80100000 @@ -119,6 +121,18 @@ static const struct panel_config preset_dvi_1280X1024 = { .gfx_format = GFXFORMAT_RGB16, };
+static const struct panel_config preset_dataimage_480X800 = { + .lcd_size = PANEL_LCD_SIZE(480, 800), + .timing_h = DSS_HBP(2) | DSS_HFP(2) | DSS_HSW(2), + .timing_v = DSS_VBP(17) | DSS_VFP(20) | DSS_VSW(3), + .pol_freq = DSS_IVS | DSS_IHS | DSS_IPC | DSS_ONOFF, + .divisor = 10 | (1 << 10), + .data_lines = LCD_INTERFACE_18_BIT, + .panel_type = ACTIVE_DISPLAY, + .load_mode = 2, + .gfx_format = GFXFORMAT_RGB16, +}; + /* * set_resolution_params() * @@ -146,6 +160,13 @@ static enum display_type set_dvi_preset(const struct panel_config preset, return DVI; }
+static enum display_type set_dataimage_preset(const struct panel_config preset, + int x_res, int y_res) +{ + set_preset(preset, x_res, y_res); + return DATA_IMAGE; +} + /* * parse_mode() - parse the mode parameter of custom lcd settings * @@ -369,6 +390,8 @@ static enum display_type env_parse_displaytype(char *displaytype) return set_dvi_preset(preset_dvi_1280X960, 1280, 960); else if (!strncmp(displaytype, "dvi1280x1024", 12)) return set_dvi_preset(preset_dvi_1280X1024, 1280, 1024); + else if (!strncmp(displaytype, "dataimage480x800", 16)) + return set_dataimage_preset(preset_dataimage_480X800, 480, 800);
return NONE; } @@ -401,12 +424,31 @@ void lcd_ctrl_init(void *lcdbase) clrsetbits_le32(&prcm->clksel_dss, 0xF, 3); }
+#ifdef CONFIG_SCF0403_LCD +static void scf0403_enable(void) +{ + gpio_direction_output(58, 1); + scf0403_init(157); +} +#else +static inline void scf0403_enable(void) {} +#endif + void lcd_enable(void) { - if (lcd_def == DVI || lcd_def == DVI_CUSTOM) { + switch (lcd_def) { + case NONE: + return; + case DVI: + case DVI_CUSTOM: gpio_direction_output(54, 0); /* Turn on DVI */ - omap3_dss_enable(); + break; + case DATA_IMAGE: + scf0403_enable(); + break; } + + omap3_dss_enable(); }
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) {} diff --git a/include/configs/cm_t35.h b/include/configs/cm_t35.h index 1260367..0a5e81f 100644 --- a/include/configs/cm_t35.h +++ b/include/configs/cm_t35.h @@ -327,5 +327,8 @@ #define CONFIG_SPLASH_SCREEN #define CONFIG_CMD_BMP #define CONFIG_BMP_16BPP +#define CONFIG_SCF0403_LCD + +#define CONFIG_OMAP3_SPI
#endif /* __CONFIG_H */

On Wed, 9 Oct 2013 17:46:05 +0300 Nikita Kiryanov nikita@compulab.co.il wrote:
Use scf0403 driver to add scf0403x LCD support for cm-t35 and cm-t3730 boards.
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Signed-off-by: Nikita Kiryanov nikita@compulab.co.il
NOTE: This patch depends on http://patchwork.ozlabs.org/patch/275283/
arch/arm/include/asm/arch-omap3/dss.h | 9 ++++--- board/compulab/cm_t35/cm_t35.c | 12 +++++++++ board/compulab/common/omap3_display.c | 46 +++++++++++++++++++++++++++++++++-- include/configs/cm_t35.h | 3 +++ 4 files changed, 64 insertions(+), 6 deletions(-)
Acked-by: Anatolij Gustschin agust@denx.de

On 10/09/13 16:46, Nikita Kiryanov wrote:
Use scf0403 driver to add scf0403x LCD support for cm-t35 and cm-t3730 boards.
Cc: Tom Rini trini@ti.com Cc: Anatolij Gustschin agust@denx.de Cc: Igor Grinberg grinberg@compulab.co.il Signed-off-by: Nikita Kiryanov nikita@compulab.co.il
Acked-by: Igor Grinberg grinberg@compulab.co.il
participants (4)
-
Anatolij Gustschin
-
Gerhard Sittig
-
Igor Grinberg
-
Nikita Kiryanov