ssd1289.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356
  1. /**************************************************************************************
  2. * drivers/lcd/ssd1289.c
  3. *
  4. * Generic LCD driver for LCDs based on the Solomon Systech SSD1289 LCD controller.
  5. * Think of this as a template for an LCD driver that you will probably have to
  6. * customize for any particular LCD hardware.
  7. *
  8. * Copyright (C) 2012 Gregory Nutt. All rights reserved.
  9. * Authors: Gregory Nutt <gnutt@nuttx.org>
  10. *
  11. * References: SSD1289, Rev 1.3, Apr 2007, Solomon Systech Limited
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. *
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in
  21. * the documentation and/or other materials provided with the
  22. * distribution.
  23. * 3. Neither the name NuttX nor the names of its contributors may be
  24. * used to endorse or promote products derived from this software
  25. * without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  33. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  34. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  35. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. **************************************************************************************/
  41. /**************************************************************************************
  42. * Included Files
  43. **************************************************************************************/
  44. #include <nuttx/config.h>
  45. #include <sys/types.h>
  46. #include <stdint.h>
  47. #include <stdbool.h>
  48. #include <string.h>
  49. #include <errno.h>
  50. #include <debug.h>
  51. #include <nuttx/arch.h>
  52. #include <nuttx/spi/spi.h>
  53. #include <nuttx/lcd/lcd.h>
  54. #include <nuttx/lcd/ssd1289.h>
  55. #include "ssd1289.h"
  56. #ifdef CONFIG_LCD_SSD1289
  57. /**************************************************************************************
  58. * Pre-processor Definitions
  59. **************************************************************************************/
  60. /* Configuration **********************************************************************/
  61. /* Check contrast selection */
  62. #if !defined(CONFIG_LCD_MAXCONTRAST)
  63. # define CONFIG_LCD_MAXCONTRAST 1
  64. #endif
  65. /* Check power setting */
  66. #if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1
  67. # define CONFIG_LCD_MAXPOWER 1
  68. #endif
  69. #if CONFIG_LCD_MAXPOWER > 255
  70. # error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t"
  71. #endif
  72. /* Check orientation */
  73. #if defined(CONFIG_LCD_PORTRAIT)
  74. # if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) || defined(CONFIG_LCD_RPORTRAIT)
  75. # error "Cannot define both portrait and any other orientations"
  76. # endif
  77. #elif defined(CONFIG_LCD_RPORTRAIT)
  78. # if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
  79. # error "Cannot define both rportrait and any other orientations"
  80. # endif
  81. #elif defined(CONFIG_LCD_LANDSCAPE)
  82. # ifdef CONFIG_LCD_RLANDSCAPE
  83. # error "Cannot define both landscape and any other orientations"
  84. # endif
  85. #elif !defined(CONFIG_LCD_RLANDSCAPE)
  86. # define CONFIG_LCD_LANDSCAPE 1
  87. #endif
  88. /* Display/Color Properties ***********************************************************/
  89. /* Display Resolution */
  90. #if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
  91. # define SSD1289_XRES 320
  92. # define SSD1289_YRES 240
  93. #else
  94. # define SSD1289_XRES 240
  95. # define SSD1289_YRES 320
  96. #endif
  97. /* Color depth and format */
  98. #define SSD1289_BPP 16
  99. #define SSD1289_COLORFMT FB_FMT_RGB16_565
  100. /* LCD Profiles ***********************************************************************/
  101. /* Many details of the controller initialization must, unfortunately, vary from LCD to
  102. * LCD. I have looked at the spec and at three different drivers for LCDs that have
  103. * SSD1289 controllers. I have tried to summarize these differences as "LCD profiles"
  104. *
  105. * Most of the differences between LCDs are nothing more than a few minor bit
  106. * settings. The most significant difference betwen LCD drivers in is the
  107. * manner in which the LCD is powered up and in how the power controls are set.
  108. * My suggestion is that if you have working LCD initialization code, you should
  109. * simply replace the code in ssd1289_hwinitialize with your working code.
  110. */
  111. #if defined (CONFIG_SSD1289_PROFILE2)
  112. # undef SSD1289_USE_SIMPLE_INIT
  113. /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
  114. # define PWRCTRL1_SETTING \
  115. (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \
  116. SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24)
  117. /* PWRCTRL2: 5.1v */
  118. # define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V
  119. /* PWRCTRL3: x 2.165
  120. * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
  121. */
  122. # define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165
  123. /* PWRCTRL4: VDV=9 + VCOMG */
  124. # define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG)
  125. /* PWRCTRL5: VCM=56 + NOTP */
  126. # define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP)
  127. #elif defined (CONFIG_SSD1289_PROFILE3)
  128. # undef SSD1289_USE_SIMPLE_INIT
  129. /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
  130. # define PWRCTRL1_SETTING \
  131. (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \
  132. SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24)
  133. /* PWRCTRL2: 5.1v */
  134. # define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V
  135. /* PWRCTRL3: x 2.165
  136. * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
  137. */
  138. # define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165
  139. /* PWRCTRL4: VDV=9 + VCOMG */
  140. # define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG)
  141. /* PWRCTRL5: VCM=56 + NOTP */
  142. # define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP)
  143. #else /* if defined (CONFIG_SSD1289_PROFILE1) */
  144. # undef SSD1289_USE_SIMPLE_INIT
  145. # define SSD1289_USE_SIMPLE_INIT 1
  146. /* PWRCTRL1: AP=medium-to-large, DC=Fosc/4, BT=+5/-4, DCT=Fosc/4 */
  147. # define PWRCTRL1_SETTING \
  148. (SSD1289_PWRCTRL1_AP_MEDLG | SSD1289_PWRCTRL1_DC_FOSd4 | \
  149. SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FOSd4)
  150. /* PWRCTRL2: 5.3v */
  151. # define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p3V
  152. /* PWRCTRL3: x 2.570
  153. * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
  154. */
  155. # define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p570
  156. /* PWRCTRL4: VDV=12 + VCOMG */
  157. # define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(12) | SSD1289_PWRCTRL4_VCOMG)
  158. /* PWRCTRL5: VCM=60 + NOTP */
  159. # define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(60) | SSD1289_PWRCTRL5_NOTP)
  160. #endif
  161. /**************************************************************************************
  162. * Private Type Definition
  163. **************************************************************************************/
  164. /* This structure describes the state of this driver */
  165. struct ssd1289_dev_s
  166. {
  167. /* Publically visible device structure */
  168. struct lcd_dev_s dev;
  169. /* Private LCD-specific information follows */
  170. FAR struct ssd1289_lcd_s *lcd; /* The contained platform-specific, LCD interface */
  171. uint8_t power; /* Current power setting */
  172. /* These fields simplify and reduce debug output */
  173. #ifdef CONFIG_DEBUG_LCD
  174. bool put; /* Last raster operation was a putrun */
  175. fb_coord_t firstrow; /* First row of the run */
  176. fb_coord_t lastrow; /* Last row of the run */
  177. fb_coord_t col; /* Column of the run */
  178. size_t npixels; /* Length of the run */
  179. #endif
  180. /* This is working memory allocated by the LCD driver for each LCD device
  181. * and for each color plane. This memory will hold one raster line of data.
  182. * The size of the allocated run buffer must therefore be at least
  183. * (bpp * xres / 8). Actual alignment of the buffer must conform to the
  184. * bitwidth of the underlying pixel type.
  185. *
  186. * If there are multiple planes, they may share the same working buffer
  187. * because different planes will not be operate on concurrently. However,
  188. * if there are multiple LCD devices, they must each have unique run buffers.
  189. */
  190. uint16_t runbuffer[SSD1289_XRES];
  191. };
  192. /**************************************************************************************
  193. * Private Function Protototypes
  194. **************************************************************************************/
  195. /* Low Level LCD access */
  196. static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr,
  197. uint16_t regval);
  198. #ifndef CONFIG_LCD_NOGETRUN
  199. static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr);
  200. #endif
  201. static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t rgbcolor);
  202. #ifndef CONFIG_LCD_NOGETRUN
  203. static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum);
  204. static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum);
  205. #endif
  206. static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column,
  207. uint16_t row);
  208. /* LCD Data Transfer Methods */
  209. #if 0 /* Sometimes useful */
  210. static void ssd1289_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels);
  211. #else
  212. # define ssd1289_dumprun(m,r,n)
  213. #endif
  214. #ifdef CONFIG_DEBUG_LCD
  215. static void ssd1289_showrun(FAR struct ssd1289_dev_s *priv, fb_coord_t row,
  216. fb_coord_t col, size_t npixels, bool put);
  217. #else
  218. # define ssd1289_showrun(p,r,c,n,b)
  219. #endif
  220. static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
  221. size_t npixels);
  222. static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
  223. size_t npixels);
  224. /* LCD Configuration */
  225. static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev,
  226. FAR struct fb_videoinfo_s *vinfo);
  227. static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
  228. FAR struct lcd_planeinfo_s *pinfo);
  229. /* LCD RGB Mapping */
  230. #ifdef CONFIG_FB_CMAP
  231. # error "RGB color mapping not supported by this driver"
  232. #endif
  233. /* Cursor Controls */
  234. #ifdef CONFIG_FB_HWCURSOR
  235. # error "Cursor control not supported by this driver"
  236. #endif
  237. /* LCD Specific Controls */
  238. static int ssd1289_getpower(FAR struct lcd_dev_s *dev);
  239. static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power);
  240. static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev);
  241. static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast);
  242. /* Initialization */
  243. static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv);
  244. /**************************************************************************************
  245. * Private Data
  246. **************************************************************************************/
  247. /* This driver can support only a signal SSD1289 device. This is due to an
  248. * unfortunate decision made whent he getrun and putrun methods were designed. The
  249. * following is the single SSD1289 driver state instance:
  250. */
  251. static struct ssd1289_dev_s g_lcddev;
  252. /**************************************************************************************
  253. * Private Functions
  254. **************************************************************************************/
  255. /**************************************************************************************
  256. * Name: ssd1289_putreg(lcd,
  257. *
  258. * Description:
  259. * Write to an LCD register
  260. *
  261. **************************************************************************************/
  262. static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr, uint16_t regval)
  263. {
  264. /* Set the index register to the register address and write the register contents */
  265. lcd->index(lcd, regaddr);
  266. lcd->write(lcd, regval);
  267. }
  268. /**************************************************************************************
  269. * Name: ssd1289_readreg
  270. *
  271. * Description:
  272. * Read from an LCD register
  273. *
  274. **************************************************************************************/
  275. #ifndef CONFIG_LCD_NOGETRUN
  276. static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr)
  277. {
  278. /* Set the index register to the register address and read the register contents */
  279. lcd->index(lcd, regaddr);
  280. return lcd->read(lcd);
  281. }
  282. #endif
  283. /**************************************************************************************
  284. * Name: ssd1289_gramselect
  285. *
  286. * Description:
  287. * Setup to read or write multiple pixels to the GRAM memory
  288. *
  289. **************************************************************************************/
  290. static inline void ssd1289_gramselect(FAR struct ssd1289_lcd_s *lcd)
  291. {
  292. lcd->index(lcd, SSD1289_DATA);
  293. }
  294. /**************************************************************************************
  295. * Name: ssd1289_gramwrite
  296. *
  297. * Description:
  298. * Setup to read or write multiple pixels to the GRAM memory
  299. *
  300. **************************************************************************************/
  301. static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t data)
  302. {
  303. lcd->write(lcd, data);
  304. }
  305. /**************************************************************************************
  306. * Name: ssd1289_readsetup
  307. *
  308. * Description:
  309. * Prime the operation by reading one pixel from the GRAM memory if necessary for
  310. * this LCD type. When reading 16-bit gram data, there may be some shifts in the
  311. * returned data:
  312. *
  313. * - ILI932x: Discard first dummy read; no shift in the return data
  314. *
  315. **************************************************************************************/
  316. #ifndef CONFIG_LCD_NOGETRUN
  317. static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum)
  318. {
  319. /* Read-ahead one pixel */
  320. *accum = lcd->read(lcd);
  321. }
  322. #endif
  323. /**************************************************************************************
  324. * Name: ssd1289_gramread
  325. *
  326. * Description:
  327. * Read one correctly aligned pixel from the GRAM memory. Possibly shifting the
  328. * data and possibly swapping red and green components.
  329. *
  330. * - ILI932x: Unknown -- assuming colors are in the color order
  331. *
  332. **************************************************************************************/
  333. #ifndef CONFIG_LCD_NOGETRUN
  334. static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum)
  335. {
  336. /* Read the value (GRAM register already selected) */
  337. return lcd->read(lcd);
  338. }
  339. #endif
  340. /**************************************************************************************
  341. * Name: ssd1289_setcursor
  342. *
  343. * Description:
  344. * Set the cursor position. In landscape mode, the "column" is actually the physical
  345. * Y position and the "row" is the physical X position.
  346. *
  347. **************************************************************************************/
  348. static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column, uint16_t row)
  349. {
  350. #if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
  351. ssd1289_putreg(lcd, SSD1289_XADDR, column); /* 0-239 */
  352. ssd1289_putreg(lcd, SSD1289_YADDR, row); /* 0-319 */
  353. #elif defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
  354. ssd1289_putreg(lcd, SSD1289_XADDR, row); /* 0-239 */
  355. ssd1289_putreg(lcd, SSD1289_YADDR, column); /* 0-319 */
  356. #endif
  357. }
  358. /**************************************************************************************
  359. * Name: ssd1289_dumprun
  360. *
  361. * Description:
  362. * Dump the contexts of the run buffer:
  363. *
  364. * run - The buffer in containing the run read to be dumped
  365. * npixels - The number of pixels to dump
  366. *
  367. **************************************************************************************/
  368. #if 0 /* Sometimes useful */
  369. static void ssd1289_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels)
  370. {
  371. int i, j;
  372. syslog(LOG_INFO, "\n%s:\n", msg);
  373. for (i = 0; i < npixels; i += 16)
  374. {
  375. up_putc(' ');
  376. syslog(LOG_INFO, " ");
  377. for (j = 0; j < 16; j++)
  378. {
  379. syslog(LOG_INFO, " %04x", *run++);
  380. }
  381. up_putc('\n');
  382. }
  383. }
  384. #endif
  385. /**************************************************************************************
  386. * Name: ssd1289_showrun
  387. *
  388. * Description:
  389. * When LCD debug is enabled, try to reduce then amount of ouptut data generated by
  390. * ssd1289_putrun and ssd1289_getrun
  391. *
  392. **************************************************************************************/
  393. #ifdef CONFIG_DEBUG_LCD
  394. static void ssd1289_showrun(FAR struct ssd1289_dev_s *priv, fb_coord_t row,
  395. fb_coord_t col, size_t npixels, bool put)
  396. {
  397. fb_coord_t nextrow = priv->lastrow + 1;
  398. /* Has anything changed (other than the row is the next row in the sequence)? */
  399. if (put == priv->put && row == nextrow && col == priv->col &&
  400. npixels == priv->npixels)
  401. {
  402. /* No, just update the last row */
  403. priv->lastrow = nextrow;
  404. }
  405. else
  406. {
  407. /* Yes... then this is the end of the preceding sequence. Output the last run
  408. * (if there were more than one run in the sequence).
  409. */
  410. if (priv->firstrow != priv->lastrow)
  411. {
  412. lcdinfo("...\n");
  413. lcdinfo("%s row: %d col: %d npixels: %d\n",
  414. priv->put ? "PUT" : "GET",
  415. priv->lastrow, priv->col, priv->npixels);
  416. }
  417. /* And we are starting a new sequence. Output the first run of the
  418. * new sequence
  419. */
  420. lcdinfo("%s row: %d col: %d npixels: %d\n",
  421. put ? "PUT" : "GET", row, col, npixels);
  422. /* And save information about the run so that we can detect continuations
  423. * of the sequence.
  424. */
  425. priv->put = put;
  426. priv->firstrow = row;
  427. priv->lastrow = row;
  428. priv->col = col;
  429. priv->npixels = npixels;
  430. }
  431. }
  432. #endif
  433. /**************************************************************************************
  434. * Name: ssd1289_putrun
  435. *
  436. * Description:
  437. * This method can be used to write a partial raster line to the LCD:
  438. *
  439. * row - Starting row to write to (range: 0 <= row < yres)
  440. * col - Starting column to write to (range: 0 <= col <= xres-npixels)
  441. * buffer - The buffer containing the run to be written to the LCD
  442. * npixels - The number of pixels to write to the LCD
  443. * (range: 0 < npixels <= xres-col)
  444. *
  445. **************************************************************************************/
  446. static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
  447. size_t npixels)
  448. {
  449. FAR struct ssd1289_dev_s *priv = &g_lcddev;
  450. FAR struct ssd1289_lcd_s *lcd = priv->lcd;
  451. FAR const uint16_t *src = (FAR const uint16_t *)buffer;
  452. int i;
  453. /* Buffer must be provided and aligned to a 16-bit address boundary */
  454. ssd1289_showrun(priv, row, col, npixels, true);
  455. DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
  456. /* Select the LCD */
  457. lcd->select(lcd);
  458. /* Write the run to GRAM. */
  459. #ifdef CONFIG_LCD_LANDSCAPE
  460. /* Convert coordinates -- Here the edge away from the row of buttons on
  461. * the STM3240G-EVAL is used as the top.
  462. */
  463. /* Write the GRAM data, manually incrementing X */
  464. for (i = 0; i < npixels; i++)
  465. {
  466. /* Write the next pixel to this position */
  467. ssd1289_setcursor(lcd, col, row);
  468. ssd1289_gramselect(lcd);
  469. ssd1289_gramwrite(lcd, *src);
  470. /* Increment to the next column */
  471. src++;
  472. col++;
  473. }
  474. #elif defined(CONFIG_LCD_RLANDSCAPE)
  475. /* Convert coordinates -- Here the edge next to the row of buttons on
  476. * the STM3240G-EVAL is used as the top.
  477. */
  478. col = (SSD1289_XRES-1) - col;
  479. row = (SSD1289_YRES-1) - row;
  480. /* Set the cursor position */
  481. ssd1289_setcursor(lcd, col, row);
  482. /* Then write the GRAM data, auto-decrementing X */
  483. ssd1289_gramselect(lcd);
  484. for (i = 0; i < npixels; i++)
  485. {
  486. /* Write the next pixel to this position (auto-decrements to the next column) */
  487. ssd1289_gramwrite(lcd, *src);
  488. src++;
  489. }
  490. #elif defined(CONFIG_LCD_PORTRAIT)
  491. /* Convert coordinates. In this configuration, the top of the display is to the left
  492. * of the buttons (if the board is held so that the buttons are at the botton of the
  493. * board).
  494. */
  495. col = (SSD1289_XRES-1) - col;
  496. /* Then write the GRAM data, manually incrementing Y (which is col) */
  497. for (i = 0; i < npixels; i++)
  498. {
  499. /* Write the next pixel to this position */
  500. ssd1289_setcursor(lcd, row, col);
  501. ssd1289_gramselect(lcd);
  502. ssd1289_gramwrite(lcd, *src);
  503. /* Increment to the next column */
  504. src++;
  505. col--;
  506. }
  507. #else /* CONFIG_LCD_RPORTRAIT */
  508. /* Convert coordinates. In this configuration, the top of the display is to the right
  509. * of the buttons (if the board is held so that the buttons are at the botton of the
  510. * board).
  511. */
  512. row = (SSD1289_YRES-1) - row;
  513. /* Then write the GRAM data, manually incrementing Y (which is col) */
  514. for (i = 0; i < npixels; i++)
  515. {
  516. /* Write the next pixel to this position */
  517. ssd1289_setcursor(lcd, row, col);
  518. ssd1289_gramselect(lcd);
  519. ssd1289_gramwrite(lcd, *src);
  520. /* Decrement to the next column */
  521. src++;
  522. col++;
  523. }
  524. #endif
  525. /* De-select the LCD */
  526. lcd->deselect(lcd);
  527. return OK;
  528. }
  529. /**************************************************************************************
  530. * Name: ssd1289_getrun
  531. *
  532. * Description:
  533. * This method can be used to read a partial raster line from the LCD:
  534. *
  535. * row - Starting row to read from (range: 0 <= row < yres)
  536. * col - Starting column to read read (range: 0 <= col <= xres-npixels)
  537. * buffer - The buffer in which to return the run read from the LCD
  538. * npixels - The number of pixels to read from the LCD
  539. * (range: 0 < npixels <= xres-col)
  540. *
  541. **************************************************************************************/
  542. static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
  543. size_t npixels)
  544. {
  545. #ifndef CONFIG_LCD_NOGETRUN
  546. FAR struct ssd1289_dev_s *priv = &g_lcddev;
  547. FAR struct ssd1289_lcd_s *lcd = priv->lcd;
  548. FAR uint16_t *dest = (FAR uint16_t *)buffer;
  549. uint16_t accum;
  550. int i;
  551. /* Buffer must be provided and aligned to a 16-bit address boundary */
  552. ssd1289_showrun(priv, row, col, npixels, false);
  553. DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
  554. /* Select the LCD */
  555. lcd->select(lcd);
  556. /* Read the run from GRAM. */
  557. #ifdef CONFIG_LCD_LANDSCAPE
  558. /* Convert coordinates -- Here the edge away from the row of buttons on
  559. * the STM3240G-EVAL is used as the top.
  560. */
  561. for (i = 0; i < npixels; i++)
  562. {
  563. /* Read the next pixel from this position */
  564. ssd1289_setcursor(lcd, row, col);
  565. ssd1289_gramselect(lcd);
  566. ssd1289_readsetup(lcd, &accum);
  567. *dest++ = ssd1289_gramread(lcd, &accum);
  568. /* Increment to the next column */
  569. col++;
  570. }
  571. #elif defined(CONFIG_LCD_RLANDSCAPE)
  572. /* Convert coordinates -- Here the edge next to the row of buttons on
  573. * the STM3240G-EVAL is used as the top.
  574. */
  575. col = (SSD1289_XRES-1) - col;
  576. row = (SSD1289_YRES-1) - row;
  577. /* Set the cursor position */
  578. ssd1289_setcursor(lcd, col, row);
  579. /* Then read the GRAM data, auto-decrementing Y */
  580. ssd1289_gramselect(lcd);
  581. /* Prime the pump for unaligned read data */
  582. ssd1289_readsetup(lcd, &accum);
  583. for (i = 0; i < npixels; i++)
  584. {
  585. /* Read the next pixel from this position (autoincrements to the next row) */
  586. *dest++ = ssd1289_gramread(lcd, &accum);
  587. }
  588. #elif defined(CONFIG_LCD_PORTRAIT)
  589. /* Convert coordinates. In this configuration, the top of the display is to the left
  590. * of the buttons (if the board is held so that the buttons are at the botton of the
  591. * board).
  592. */
  593. col = (SSD1289_XRES-1) - col;
  594. /* Then read the GRAM data, manually incrementing Y (which is col) */
  595. for (i = 0; i < npixels; i++)
  596. {
  597. /* Read the next pixel from this position */
  598. ssd1289_setcursor(lcd, row, col);
  599. ssd1289_gramselect(lcd);
  600. ssd1289_readsetup(lcd, &accum);
  601. *dest++ = ssd1289_gramread(lcd, &accum);
  602. /* Increment to the next column */
  603. col--;
  604. }
  605. #else /* CONFIG_LCD_RPORTRAIT */
  606. /* Convert coordinates. In this configuration, the top of the display is to the right
  607. * of the buttons (if the board is held so that the buttons are at the botton of the
  608. * board).
  609. */
  610. row = (SSD1289_YRES-1) - row;
  611. /* Then write the GRAM data, manually incrementing Y (which is col) */
  612. for (i = 0; i < npixels; i++)
  613. {
  614. /* Write the next pixel to this position */
  615. ssd1289_setcursor(lcd, row, col);
  616. ssd1289_gramselect(lcd);
  617. ssd1289_readsetup(lcd, &accum);
  618. *dest++ = ssd1289_gramread(lcd, &accum);
  619. /* Decrement to the next column */
  620. col++;
  621. }
  622. #endif
  623. /* De-select the LCD */
  624. lcd->deselect(lcd);
  625. return OK;
  626. #else
  627. return -ENOSYS;
  628. #endif
  629. }
  630. /**************************************************************************************
  631. * Name: ssd1289_getvideoinfo
  632. *
  633. * Description:
  634. * Get information about the LCD video controller configuration.
  635. *
  636. **************************************************************************************/
  637. static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev,
  638. FAR struct fb_videoinfo_s *vinfo)
  639. {
  640. DEBUGASSERT(dev && vinfo);
  641. lcdinfo("fmt: %d xres: %d yres: %d nplanes: 1\n",
  642. SSD1289_COLORFMT, SSD1289_XRES, SSD1289_YRES);
  643. vinfo->fmt = SSD1289_COLORFMT; /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
  644. vinfo->xres = SSD1289_XRES; /* Horizontal resolution in pixel columns */
  645. vinfo->yres = SSD1289_YRES; /* Vertical resolution in pixel rows */
  646. vinfo->nplanes = 1; /* Number of color planes supported */
  647. return OK;
  648. }
  649. /**************************************************************************************
  650. * Name: ssd1289_getplaneinfo
  651. *
  652. * Description:
  653. * Get information about the configuration of each LCD color plane.
  654. *
  655. **************************************************************************************/
  656. static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
  657. FAR struct lcd_planeinfo_s *pinfo)
  658. {
  659. FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
  660. DEBUGASSERT(dev && pinfo && planeno == 0);
  661. lcdinfo("planeno: %d bpp: %d\n", planeno, SSD1289_BPP);
  662. pinfo->putrun = ssd1289_putrun; /* Put a run into LCD memory */
  663. pinfo->getrun = ssd1289_getrun; /* Get a run from LCD memory */
  664. pinfo->buffer = (FAR uint8_t *)priv->runbuffer; /* Run scratch buffer */
  665. pinfo->bpp = SSD1289_BPP; /* Bits-per-pixel */
  666. return OK;
  667. }
  668. /**************************************************************************************
  669. * Name: ssd1289_getpower
  670. *
  671. * Description:
  672. * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On
  673. * backlit LCDs, this setting may correspond to the backlight setting.
  674. *
  675. **************************************************************************************/
  676. static int ssd1289_getpower(FAR struct lcd_dev_s *dev)
  677. {
  678. lcdinfo("power: %d\n", 0);
  679. return g_lcddev.power;
  680. }
  681. /**************************************************************************************
  682. * Name: ssd1289_poweroff
  683. *
  684. * Description:
  685. * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
  686. * backlit LCDs, this setting may correspond to the backlight setting.
  687. *
  688. **************************************************************************************/
  689. static int ssd1289_poweroff(FAR struct ssd1289_lcd_s *lcd)
  690. {
  691. /* Set the backlight off */
  692. lcd->backlight(lcd, 0);
  693. /* Turn the display off */
  694. ssd1289_putreg(lcd, SSD1289_DSPCTRL, 0);
  695. /* Remember the power off state */
  696. g_lcddev.power = 0;
  697. return OK;
  698. }
  699. /**************************************************************************************
  700. * Name: ssd1289_setpower
  701. *
  702. * Description:
  703. * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
  704. * backlit LCDs, this setting may correspond to the backlight setting.
  705. *
  706. **************************************************************************************/
  707. static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power)
  708. {
  709. FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
  710. FAR struct ssd1289_lcd_s *lcd = priv->lcd;
  711. lcdinfo("power: %d\n", power);
  712. DEBUGASSERT((unsigned)power <= CONFIG_LCD_MAXPOWER);
  713. /* Set new power level */
  714. if (power > 0)
  715. {
  716. /* Set the backlight level */
  717. lcd->backlight(lcd, power);
  718. /* Then turn the display on:
  719. * D=ON(3) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
  720. */
  721. ssd1289_putreg(lcd, SSD1289_DSPCTRL,
  722. (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON |
  723. SSD1289_DSPCTRL_DTE | SSD1289_DSPCTRL_VLE(0)));
  724. g_lcddev.power = power;
  725. }
  726. else
  727. {
  728. /* Turn the display off */
  729. ssd1289_poweroff(lcd);
  730. }
  731. return OK;
  732. }
  733. /**************************************************************************************
  734. * Name: ssd1289_getcontrast
  735. *
  736. * Description:
  737. * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
  738. *
  739. **************************************************************************************/
  740. static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev)
  741. {
  742. lcdinfo("Not implemented\n");
  743. return -ENOSYS;
  744. }
  745. /**************************************************************************************
  746. * Name: ssd1289_setcontrast
  747. *
  748. * Description:
  749. * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
  750. *
  751. **************************************************************************************/
  752. static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast)
  753. {
  754. lcdinfo("contrast: %d\n", contrast);
  755. return -ENOSYS;
  756. }
  757. /**************************************************************************************
  758. * Name: ssd1289_hwinitialize
  759. *
  760. * Description:
  761. * Initialize the LCD hardware.
  762. *
  763. **************************************************************************************/
  764. static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv)
  765. {
  766. FAR struct ssd1289_lcd_s *lcd = priv->lcd;
  767. #ifndef CONFIG_LCD_NOGETRUN
  768. uint16_t id;
  769. #endif
  770. int ret;
  771. /* Select the LCD */
  772. lcd->select(lcd);
  773. /* Read the device ID. Skip verification of the device ID is the LCD is
  774. * write-only. What choice do we have?
  775. */
  776. #ifndef CONFIG_LCD_NOGETRUN
  777. id = ssd1289_readreg(lcd, SSD1289_DEVCODE);
  778. if (id != 0)
  779. {
  780. lcdinfo("LCD ID: %04x\n", id);
  781. }
  782. /* If we could not get the ID, then let's just assume that this is an SSD1289.
  783. * Perhaps we have some early register access issues. This seems to happen.
  784. * But then perhaps we should not even bother to read the device ID at all?
  785. */
  786. else
  787. {
  788. lcdwarn("WARNING: No LCD ID, assuming SSD1289\n");
  789. id = SSD1289_DEVCODE_VALUE;
  790. }
  791. /* Check if the ID is for the SSD1289 */
  792. if (id == SSD1289_DEVCODE_VALUE)
  793. #endif
  794. {
  795. /* LCD controller configuration. Many details of the controller initialization
  796. * must, unfortunately, vary from LCD to LCD. I have looked at the spec and at
  797. * three different drivers for LCDs that have SSD1289 controllers. I have tried
  798. * to summarize these differences as profiles (defined above). Some other
  799. * alternatives are noted below.
  800. *
  801. * Most of the differences between LCDs are nothing more than a few minor bit
  802. * settings. The most significant difference betwen LCD drivers in is the
  803. * manner in which the LCD is powered up and in how the power controls are set.
  804. * My suggestion is that if you have working LCD initialization code, you should
  805. * simply replace the following guesses with your working code.
  806. */
  807. /* Most drivers just enable the oscillator */
  808. #ifdef SSD1289_USE_SIMPLE_INIT
  809. ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);
  810. #else
  811. /* But one goes through a more complex start-up sequence. Something like the
  812. * following:
  813. *
  814. * First, put the display in INTERNAL operation:
  815. * D=INTERNAL(1) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
  816. */
  817. ssd1289_putreg(lcd, SSD1289_DSPCTRL,
  818. (SSD1289_DSPCTRL_INTERNAL | SSD1289_DSPCTRL_GON |
  819. SSD1289_DSPCTRL_VLE(0)));
  820. /* Then enable the oscillator */
  821. ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);
  822. /* Turn the display on:
  823. * D=ON(3) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
  824. */
  825. ssd1289_putreg(lcd, SSD1289_DSPCTRL,
  826. (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON |
  827. SSD1289_DSPCTRL_VLE(0)));
  828. /* Take the LCD out of sleep mode */
  829. ssd1289_putreg(lcd, SSD1289_SLEEP, 0);
  830. up_mdelay(30);
  831. /* Turn the display on:
  832. * D=INTERNAL(1) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
  833. */
  834. ssd1289_putreg(lcd, SSD1289_DSPCTRL,
  835. (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE |
  836. SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(0)));
  837. #endif
  838. /* Set up power control registers. There is a lot of variability
  839. * from LCD-to-LCD in how the power registers are configured.
  840. */
  841. ssd1289_putreg(lcd, SSD1289_PWRCTRL1, PWRCTRL1_SETTING);
  842. ssd1289_putreg(lcd, SSD1289_PWRCTRL2, PWRCTRL2_SETTING);
  843. /* One driver adds a delay here.. I doubt that this is really necessary. */
  844. /* up_mdelay(15); */
  845. ssd1289_putreg(lcd, SSD1289_PWRCTRL3, PWRCTRL3_SETTING);
  846. ssd1289_putreg(lcd, SSD1289_PWRCTRL4, PWRCTRL4_SETTING);
  847. ssd1289_putreg(lcd, SSD1289_PWRCTRL5, PWRCTRL5_SETTING);
  848. /* One driver does an odd setting of the driver output control.
  849. * No idea why.
  850. */
  851. #if 0
  852. ssd1289_putreg(lcd, SSD1289_OUTCTRL,
  853. (SSD1289_OUTCTRL_MUX(12) | SSD1289_OUTCTRL_TB |
  854. SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_CAD));
  855. /* The same driver does another small delay here */
  856. up_mdelay(15);
  857. #endif
  858. /* After this point, the drivers differ only in some varying register
  859. * bit settings.
  860. */
  861. /* Set the driver output control.
  862. * PORTRAIT MODES:
  863. * MUX=319, TB=1, SM=0, BGR=1, CAD=0, REV=1, RL=0
  864. * LANDSCAPE MODES:
  865. * MUX=319, TB=0, SM=0, BGR=1, CAD=0, REV=1, RL=0
  866. */
  867. #if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
  868. ssd1289_putreg(lcd, SSD1289_OUTCTRL,
  869. (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_TB |
  870. SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_REV));
  871. #else
  872. ssd1289_putreg(lcd, SSD1289_OUTCTRL,
  873. (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_BGR |
  874. SSD1289_OUTCTRL_REV));
  875. #endif
  876. /* Set the LCD driving AC waveform
  877. * NW=0, WSMD=0, EOR=1, BC=1, ENWD=0, FLD=0
  878. */
  879. ssd1289_putreg(lcd, SSD1289_ACCTRL,
  880. (SSD1289_ACCTRL_EOR | SSD1289_ACCTRL_BC));
  881. /* Take the LCD out of sleep mode (isn't this redundant in the non-
  882. * simple case?)
  883. */
  884. ssd1289_putreg(lcd, SSD1289_SLEEP, 0);
  885. /* Set entry mode */
  886. #if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
  887. /* LG=0, AM=0, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3
  888. * Alternative TY=2 (But TY only applies in 262K color mode anyway)
  889. */
  890. ssd1289_putreg(lcd, SSD1289_ENTRY,
  891. (SSD1289_ENTRY_ID_HINCVINC | SSD1289_ENTRY_TY_C |
  892. SSD1289_ENTRY_DMODE_RAM | SSD1289_ENTRY_DFM_65K));
  893. #else
  894. /* LG=0, AM=1, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3 */
  895. /* Alternative TY=2 (But TY only applies in 262K color mode anyway) */
  896. ssd1289_putreg(lcd, SSD1289_ENTRY,
  897. (SSD1289_ENTRY_AM | SSD1289_ENTRY_ID_HINCVINC |
  898. SSD1289_ENTRY_TY_C | SSD1289_ENTRY_DMODE_RAM |
  899. SSD1289_ENTRY_DFM_65K));
  900. #endif
  901. /* Clear compare registers */
  902. ssd1289_putreg(lcd, SSD1289_CMP1, 0);
  903. ssd1289_putreg(lcd, SSD1289_CMP2, 0);
  904. /* One driver puts a huge, 100 millisecond delay here */
  905. /* up_mdelay(100); */
  906. /* Set Horizontal and vertical porch.
  907. * Horizontal porch: 239 pixels per line, delay=28
  908. * Vertical porch: VBP=3, XFP=0
  909. */
  910. ssd1289_putreg(lcd, SSD1289_HPORCH,
  911. (28 << SSD1289_HPORCH_HBP_SHIFT) | (239 << SSD1289_HPORCH_XL_SHIFT));
  912. ssd1289_putreg(lcd, SSD1289_VPORCH,
  913. (3 << SSD1289_VPORCH_VBP_SHIFT) | (0 << SSD1289_VPORCH_XFP_SHIFT));
  914. /* Set display control.
  915. * D=ON(3), CM=0 (not 8-color), DTE=1, GON=1, SPT=0, VLE=1 PT=0
  916. */
  917. ssd1289_putreg(lcd, SSD1289_DSPCTRL,
  918. (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE |
  919. SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(1)));
  920. /* Frame cycle control. Alternative: SSD1289_FCYCCTRL_DIV8 */
  921. ssd1289_putreg(lcd, SSD1289_FCYCCTRL, 0);
  922. /* Gate scan start position = 0 */
  923. ssd1289_putreg(lcd, SSD1289_GSTART, 0);
  924. /* Clear vertical scrolling */
  925. ssd1289_putreg(lcd, SSD1289_VSCROLL1, 0);
  926. ssd1289_putreg(lcd, SSD1289_VSCROLL2, 0);
  927. /* Setup window 1 (0-319) */
  928. ssd1289_putreg(lcd, SSD1289_W1START, 0);
  929. ssd1289_putreg(lcd, SSD1289_W1END, 319);
  930. /* Disable window 2 (0-0) */
  931. ssd1289_putreg(lcd, SSD1289_W2START, 0);
  932. ssd1289_putreg(lcd, SSD1289_W2END, 0);
  933. /* Horizontal start and end (0-239) */
  934. ssd1289_putreg(lcd, SSD1289_HADDR,
  935. (0 << SSD1289_HADDR_HSA_SHIFT) | (239 << SSD1289_HADDR_HEA_SHIFT));
  936. /* Vertical start and end (0-319) */
  937. ssd1289_putreg(lcd, SSD1289_VSTART, 0);
  938. ssd1289_putreg(lcd, SSD1289_VEND, 319);
  939. /* Gamma controls */
  940. ssd1289_putreg(lcd, SSD1289_GAMMA1, 0x0707);
  941. ssd1289_putreg(lcd, SSD1289_GAMMA2, 0x0204); /* Alternative: 0x0704 */
  942. ssd1289_putreg(lcd, SSD1289_GAMMA3, 0x0204);
  943. ssd1289_putreg(lcd, SSD1289_GAMMA4, 0x0502);
  944. ssd1289_putreg(lcd, SSD1289_GAMMA5, 0x0507);
  945. ssd1289_putreg(lcd, SSD1289_GAMMA6, 0x0204);
  946. ssd1289_putreg(lcd, SSD1289_GAMMA7, 0x0204);
  947. ssd1289_putreg(lcd, SSD1289_GAMMA8, 0x0502);
  948. ssd1289_putreg(lcd, SSD1289_GAMMA9, 0x0302);
  949. ssd1289_putreg(lcd, SSD1289_GAMMA10, 0x0302); /* Alternative: 0x1f00 */
  950. /* Clear write mask */
  951. ssd1289_putreg(lcd, SSD1289_WRMASK1, 0);
  952. ssd1289_putreg(lcd, SSD1289_WRMASK2, 0);
  953. /* Set frame frequency = 65Hz (This should not be necessary since this
  954. * is the default POR value)
  955. */
  956. ssd1289_putreg(lcd, SSD1289_FFREQ, SSD1289_FFREQ_OSC_FF65);
  957. /* Set the cursor at the home position and set the index register to
  958. * the gram data register (I can't imagine these are necessary).
  959. */
  960. ssd1289_setcursor(lcd, 0, 0);
  961. ssd1289_gramselect(lcd);
  962. /* One driver has a 50 msec delay here */
  963. /* up_mdelay(50); */
  964. ret = OK;
  965. }
  966. #ifndef CONFIG_LCD_NOGETRUN
  967. else
  968. {
  969. lcderr("ERROR: Unsupported LCD type\n");
  970. ret = -ENODEV;
  971. }
  972. #endif
  973. /* De-select the LCD */
  974. lcd->deselect(lcd);
  975. return ret;
  976. }
  977. /**************************************************************************************
  978. * Public Functions
  979. **************************************************************************************/
  980. /**************************************************************************************
  981. * Name: ssd1289_lcdinitialize
  982. *
  983. * Description:
  984. * Initialize the LCD video hardware. The initial state of the LCD is fully
  985. * initialized, display memory cleared, and the LCD ready to use, but with the power
  986. * setting at 0 (full off).
  987. *
  988. **************************************************************************************/
  989. FAR struct lcd_dev_s *ssd1289_lcdinitialize(FAR struct ssd1289_lcd_s *lcd)
  990. {
  991. int ret;
  992. lcdinfo("Initializing\n");
  993. /* If we ccould support multiple SSD1289 devices, this is where we would allocate
  994. * a new driver data structure... but we can't. Why not? Because of a bad should
  995. * the form of the getrun() and putrun methods.
  996. */
  997. FAR struct ssd1289_dev_s *priv = &g_lcddev;
  998. /* Initialize the driver data structure */
  999. priv->dev.getvideoinfo = ssd1289_getvideoinfo;
  1000. priv->dev.getplaneinfo = ssd1289_getplaneinfo;
  1001. priv->dev.getpower = ssd1289_getpower;
  1002. priv->dev.setpower = ssd1289_setpower;
  1003. priv->dev.getcontrast = ssd1289_getcontrast;
  1004. priv->dev.setcontrast = ssd1289_setcontrast;
  1005. priv->lcd = lcd;
  1006. /* Configure and enable LCD */
  1007. ret = ssd1289_hwinitialize(priv);
  1008. if (ret == OK)
  1009. {
  1010. /* Clear the display (setting it to the color 0=black) */
  1011. ssd1289_clear(&priv->dev, 0);
  1012. /* Turn the display off */
  1013. ssd1289_poweroff(lcd);
  1014. return &g_lcddev.dev;
  1015. }
  1016. return NULL;
  1017. }
  1018. /**************************************************************************************
  1019. * Name: ssd1289_clear
  1020. *
  1021. * Description:
  1022. * This is a non-standard LCD interface just for the stm3240g-EVAL board. Because
  1023. * of the various rotations, clearing the display in the normal way by writing a
  1024. * sequences of runs that covers the entire display can be very slow. Here the
  1025. * display is cleared by simply setting all GRAM memory to the specified color.
  1026. *
  1027. **************************************************************************************/
  1028. void ssd1289_clear(FAR struct lcd_dev_s *dev, uint16_t color)
  1029. {
  1030. FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
  1031. FAR struct ssd1289_lcd_s *lcd = priv->lcd;
  1032. uint32_t i;
  1033. /* Select the LCD and home the cursor position */
  1034. lcd->select(lcd);
  1035. ssd1289_setcursor(lcd, 0, 0);
  1036. /* Prepare to write GRAM data */
  1037. ssd1289_gramselect(lcd);
  1038. /* Copy color into all of GRAM. Orientation does not matter in this case. */
  1039. for (i = 0; i < SSD1289_XRES * SSD1289_YRES; i++)
  1040. {
  1041. ssd1289_gramwrite(lcd, color);
  1042. }
  1043. /* De-select the LCD */
  1044. lcd->deselect(lcd);
  1045. }
  1046. #endif /* CONFIG_LCD_SSD1289 */