panel_device.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. /*
  2. * Copyright (c) 2020 Actions Technology Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <device.h>
  7. #include <tracing/tracing.h>
  8. #include "panel_device.h"
  9. #include <logging/log.h>
  10. LOG_MODULE_REGISTER(lcd_panel, CONFIG_DISPLAY_LOG_LEVEL);
  11. /*********************
  12. * DEFINES
  13. *********************/
  14. /* time to wait between pixel transfer and next command */
  15. #ifdef CONFIG_PANEL_FULL_SCREEN_OPT_AREA
  16. # define CONFIG_PANEL_PIXEL_WR_DELAY_US (0)
  17. #else
  18. # define CONFIG_PANEL_PIXEL_WR_DELAY_US (0)
  19. #endif
  20. /**********************
  21. * TYPEDEFS
  22. **********************/
  23. /**********************
  24. * STATIC PROTOTYPES
  25. **********************/
  26. static int _lcd_panel_blanking_on(const struct device *dev);
  27. static int _lcd_panel_blanking_off(const struct device *dev);
  28. static int _lcd_panel_set_orientation(const struct device *dev,
  29. const enum display_orientation orientation);
  30. static int _panel_te_set_enable(const struct device *dev, bool enabled);
  31. static void _panel_submit_esd_check_work(struct lcd_panel_data *data);
  32. static void _panel_cancel_esd_check_work(struct lcd_panel_data *data);
  33. __unused static int _panel_pm_early_suspend(const struct device *dev, bool in_turnoff);
  34. static int _panel_pm_late_resume(const struct device *dev);
  35. static void _panel_pm_resume_handler(struct k_work *work);
  36. /**********************
  37. * STATIC VARIABLES
  38. **********************/
  39. #ifdef CONFIG_LCD_WORK_QUEUE
  40. K_THREAD_STACK_DEFINE(pm_workq_stack, CONFIG_LCD_WORK_Q_STACK_SIZE);
  41. #endif
  42. static const struct lcd_panel_config *const lcd_panel_configs[] = {
  43. #ifdef CONFIG_PANEL_ER76288A
  44. &lcd_panel_er76288a_config,
  45. #endif
  46. #ifdef CONFIG_PANEL_FT2308
  47. &lcd_panel_ft2308_config,
  48. #endif
  49. #ifdef CONFIG_PANEL_GC9C01
  50. &lcd_panel_gc9c01_config,
  51. #endif
  52. #ifdef CONFIG_PANEL_ICNA3310B
  53. &lcd_panel_icna3310b_config,
  54. #endif
  55. #ifdef CONFIG_PANEL_ICNA3311
  56. &lcd_panel_icna3311_config,
  57. #endif
  58. #ifdef CONFIG_PANEL_RM690B0
  59. &lcd_panel_rm690b0_config,
  60. #endif
  61. #ifdef CONFIG_PANEL_RM69090
  62. &lcd_panel_rm69090_config,
  63. #endif
  64. #ifdef CONFIG_PANEL_SH8601Z0
  65. &lcd_panel_sh8601z0_config,
  66. #endif
  67. /* TR-panels */
  68. #ifdef CONFIG_PANEL_LPM015M135A
  69. &lcd_panel_lpm015m135a_config,
  70. #endif
  71. };
  72. /**********************
  73. * MACROS
  74. **********************/
  75. /**********************
  76. * STATIC FUNCTIONS
  77. **********************/
  78. #if IS_TR_PANEL
  79. static inline void _panel_reset_pin_set(const struct device *dev, bool active)
  80. {
  81. #ifdef CONFIG_PANEL_RESET_GPIO
  82. struct lcd_panel_data *data = dev->data;
  83. const struct lcd_panel_pincfg *pincfg = dev->config;
  84. gpio_pin_set(data->reset_gpio, pincfg->reset_cfg.gpion, active ? 1 : 0);
  85. #endif
  86. }
  87. #endif /* IS_TR_PANEL */
  88. static void _panel_reset(const struct device *dev)
  89. {
  90. struct lcd_panel_data *data = dev->data;
  91. const struct lcd_panel_config *config = data->config;
  92. const struct lcd_panel_pincfg *pincfg = dev->config;
  93. display_controller_enable(data->lcdc_dev, &config->videoport);
  94. display_controller_set_mode(data->lcdc_dev, &config->videomode);
  95. LOG_DBG("Resetting display");
  96. #ifdef CONFIG_PANEL_RESET_GPIO
  97. gpio_pin_set(data->reset_gpio, pincfg->reset_cfg.gpion, 1);
  98. #endif
  99. #ifdef CONFIG_PANEL_POWER_GPIO
  100. gpio_pin_set(data->power_gpio, pincfg->power_cfg.gpion, 1);
  101. #endif
  102. #ifdef CONFIG_PANEL_POWER1_GPIO
  103. gpio_pin_set(data->power1_gpio, pincfg->power1_cfg.gpion, 1);
  104. #endif
  105. #if IS_TR_PANEL == 0
  106. #ifdef CONFIG_PANEL_RESET_GPIO
  107. k_msleep(config->tw_reset);
  108. gpio_pin_set(data->reset_gpio, pincfg->reset_cfg.gpion, 0);
  109. k_msleep(config->ts_reset);
  110. #endif
  111. #endif /* IS_TR_PANEL == 0 */
  112. }
  113. static int _panel_detect(const struct device *dev)
  114. {
  115. struct lcd_panel_data *data = dev->data;
  116. if (0 == ARRAY_SIZE(lcd_panel_configs))
  117. return -ENODEV;
  118. if (1 == ARRAY_SIZE(lcd_panel_configs)) {
  119. data->config = lcd_panel_configs[0];
  120. return 0;
  121. }
  122. for (int i = 0; i < ARRAY_SIZE(lcd_panel_configs); i++) {
  123. data->config = lcd_panel_configs[i];
  124. if (data->config->ops->detect == NULL)
  125. return 0;
  126. _panel_reset(dev);
  127. if (!data->config->ops->detect(dev))
  128. return 0;
  129. }
  130. /* FIXME: fallback to the frist panel */
  131. data->config = lcd_panel_configs[0];
  132. return 0;
  133. }
  134. static void _panel_power_on(const struct device *dev)
  135. {
  136. struct lcd_panel_data *data = dev->data;
  137. const struct lcd_panel_config *config = data->config;
  138. _panel_reset(dev);
  139. if (config->ops->init)
  140. config->ops->init(dev);
  141. /* Display On */
  142. _lcd_panel_blanking_off(dev);
  143. }
  144. static void _panel_power_off(const struct device *dev, bool in_turnoff)
  145. {
  146. struct lcd_panel_data *data = dev->data;
  147. const struct lcd_panel_config *config = data->config;
  148. const struct lcd_panel_pincfg *pincfg = dev->config;
  149. _lcd_panel_blanking_on(dev);
  150. /* FIXME: place it in config->ops->blanking_on() ? */
  151. if (config->td_slpin > 0) {
  152. if (in_turnoff) {
  153. k_busy_wait(config->td_slpin * 1000u);
  154. } else {
  155. k_msleep(config->td_slpin);
  156. }
  157. }
  158. #ifdef CONFIG_PANEL_RESET_GPIO
  159. gpio_pin_set(data->reset_gpio, pincfg->reset_cfg.gpion, 1);
  160. #endif
  161. #ifdef CONFIG_PANEL_POWER_GPIO
  162. gpio_pin_set(data->power_gpio, pincfg->power_cfg.gpion, 0);
  163. #endif
  164. #ifdef CONFIG_PANEL_POWER1_GPIO
  165. gpio_pin_set(data->power1_gpio, pincfg->power1_cfg.gpion, 0);
  166. #endif
  167. }
  168. static void _panel_apply_brightness(const struct device *dev, uint8_t brightness)
  169. {
  170. struct lcd_panel_data *data = dev->data;
  171. const struct lcd_panel_config *config = data->config;
  172. bool ready;
  173. if (data->brightness == brightness)
  174. return;
  175. ready = (data->brightness_delay == 0) && (data->first_frame_cplt > 0);
  176. if (!ready) {
  177. data->brightness_delay -= data->first_frame_cplt;
  178. }
  179. if (ready || brightness == 0) {
  180. if (config->ops->set_brightness) {
  181. config->ops->set_brightness(dev, brightness);
  182. } else {
  183. #ifdef CONFIG_PANEL_BACKLIGHT_CTRL
  184. const struct lcd_panel_pincfg *pincfg = dev->config;
  185. #ifdef CONFIG_PANEL_BACKLIGHT_PWM
  186. pwm_pin_set_cycles(data->backlight_dev, pincfg->backlight_cfg.chan, pincfg->backlight_cfg.period,
  187. (uint32_t)brightness * pincfg->backlight_cfg.period / 255, pincfg->backlight_cfg.flag);
  188. #else
  189. gpio_pin_set(data->backlight_dev, pincfg->backlight_cfg.gpion, brightness ? 1 : 0);
  190. #endif
  191. #endif /* CONFIG_PANEL_BACKLIGHT_CTRL */
  192. }
  193. data->brightness = brightness;
  194. }
  195. }
  196. static void _panel_apply_post_change(const struct device *dev)
  197. {
  198. struct lcd_panel_data *data = dev->data;
  199. _panel_apply_brightness(dev, data->pending_brightness);
  200. }
  201. /**********************
  202. * DEVICE DECLARATION
  203. **********************/
  204. DEVICE_DECLARE(lcd_panel);
  205. /**********************
  206. * ESD CHECK
  207. **********************/
  208. #if CONFIG_PANEL_ESD_CHECK_PERIOD > 0
  209. static void _panel_esd_check_custom(const struct device *dev)
  210. {
  211. struct lcd_panel_data *data = dev->data;
  212. const struct lcd_panel_config *config = data->config;
  213. if (config->ops->check_esd) {
  214. data->esd_check_pended = data->transfering;
  215. if (!data->transfering) {
  216. int res = config->ops->check_esd(dev);
  217. data->esd_check_failed = res ? 1 : 0;
  218. }
  219. }
  220. }
  221. static void _panel_esd_check_handler(struct k_work *work)
  222. {
  223. const struct device *dev = DEVICE_GET(lcd_panel);
  224. struct lcd_panel_data *data = dev->data;
  225. const struct lcd_panel_config *config = data->config;
  226. if (config->ops->check_esd) {
  227. unsigned int key = irq_lock();
  228. _panel_esd_check_custom(dev);
  229. irq_unlock(key);
  230. }
  231. if (data->esd_check_failed) {
  232. LOG_ERR("ESD check fail, reboot panel");
  233. goto fail_exit;
  234. }
  235. if (!data->te_active) {
  236. LOG_ERR("TE no signal, reboot panel");
  237. goto fail_exit;
  238. }
  239. data->te_active = 0;
  240. _panel_submit_esd_check_work(data);
  241. return;
  242. fail_exit:
  243. lcd_panel_wake_lock();
  244. _panel_pm_early_suspend(dev, false);
  245. _panel_pm_late_resume(dev);
  246. lcd_panel_wake_unlock();
  247. }
  248. #endif /* CONFIG_TPKEY_ESD_CHECK_PERIOD > 0 */
  249. static void _panel_submit_esd_check_work(struct lcd_panel_data *data)
  250. {
  251. #if CONFIG_PANEL_ESD_CHECK_PERIOD > 0
  252. #ifdef CONFIG_LCD_WORK_QUEUE
  253. k_delayed_work_submit_to_queue(&data->pm_workq, &data->esd_check_work,
  254. K_MSEC(CONFIG_PANEL_ESD_CHECK_PERIOD));
  255. #else
  256. k_delayed_work_submit(&data->esd_check_work, K_MSEC(CONFIG_PANEL_ESD_CHECK_PERIOD));
  257. #endif
  258. #endif /* CONFIG_PANEL_ESD_CHECK_PERIOD > 0 */
  259. }
  260. static void _panel_cancel_esd_check_work(struct lcd_panel_data *data)
  261. {
  262. #if CONFIG_PANEL_ESD_CHECK_PERIOD > 0
  263. data->esd_check_pended = 0;
  264. data->esd_check_failed = 0;
  265. k_delayed_work_cancel(&data->esd_check_work);
  266. #endif /* CONFIG_PANEL_ESD_CHECK_PERIOD > 0 */
  267. }
  268. /**********************
  269. * TE CALLBACK
  270. **********************/
  271. static void _panel_te_handler(void)
  272. {
  273. const struct device *dev = DEVICE_GET(lcd_panel);
  274. struct lcd_panel_data *data = dev->data;
  275. uint32_t timestamp = k_cycle_get_32();
  276. sys_trace_void(SYS_TRACE_ID_VSYNC);
  277. data->te_active = 1;
  278. if (data->transfering) {
  279. sys_trace_void(SYS_TRACE_ID_LCD_POST_OVERTIME);
  280. } else {
  281. _panel_apply_post_change(dev);
  282. #if CONFIG_PANEL_ESD_CHECK_PERIOD > 0
  283. if (data->esd_check_pended)
  284. _panel_esd_check_custom(dev);
  285. #endif
  286. }
  287. if (data->callback && data->callback->vsync) {
  288. data->callback->vsync(data->callback, timestamp);
  289. }
  290. sys_trace_end_call(SYS_TRACE_ID_VSYNC);
  291. }
  292. #ifdef CONFIG_PANEL_TE_GPIO
  293. static void _panel_te_gpio_handler(const struct device *port,
  294. struct gpio_callback *cb, gpio_port_pins_t pins)
  295. {
  296. _panel_te_handler();
  297. }
  298. static int _panel_te_set_enable(const struct device *dev, bool enabled)
  299. {
  300. struct lcd_panel_data *data = dev->data;
  301. const struct lcd_panel_pincfg *pincfg = dev->config;
  302. if (gpio_pin_interrupt_configure(data->te_gpio, pincfg->te_cfg.gpion,
  303. enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE)) {
  304. LOG_ERR("Couldn't config te interrupt (en=%d)", enabled);
  305. return -ENODEV;
  306. }
  307. return 0;
  308. }
  309. #else /* CONFIG_PANEL_TE_GPIO */
  310. static void _panel_te_timer_handler(struct k_timer *timer)
  311. {
  312. _panel_te_handler();
  313. }
  314. static int _panel_te_set_enable(const struct device *dev, bool enabled)
  315. {
  316. struct lcd_panel_data *data = dev->data;
  317. if (enabled) {
  318. k_timer_start(&data->te_timer, K_MSEC(0), K_MSEC(CONFIG_PANEL_VSYNC_PERIOD_MS));
  319. } else {
  320. k_timer_stop(&data->te_timer);
  321. }
  322. return 0;
  323. }
  324. #endif /* CONFIG_PANEL_TE_GPIO */
  325. /**********************
  326. * DE/LCDC CALLBACK
  327. **********************/
  328. static void _panel_prepare_de_transfer(void *arg, const display_rect_t *area)
  329. {
  330. const struct device *dev = arg;
  331. struct lcd_panel_data *data = dev->data;
  332. const struct lcd_panel_config *config = data->config;
  333. uint8_t bytes_per_pixel;
  334. assert(data->disp_on == 1 && data->transfering == 0);
  335. sys_trace_u32x4(SYS_TRACE_ID_LCD_POST,
  336. area->x, area->y, area->x + area->w - 1, area->y + area->h - 1);
  337. if (data->pm_state == PM_DEVICE_STATE_LOW_POWER)
  338. board_lcd_resume(true, false);
  339. if (config->ops->write_prepare) {
  340. int res = config->ops->write_prepare(dev, area->x, area->y, area->w, area->h);
  341. if (res) {
  342. LOG_ERR("write area (%u, %u, %u, %u) failed", area->x, area->y, area->w, area->h);
  343. }
  344. }
  345. if (config->videomode.pixel_format == PIXEL_FORMAT_BGR_565) {
  346. bytes_per_pixel = 2;
  347. } else if (config->videomode.pixel_format == PIXEL_FORMAT_RGB_888) {
  348. bytes_per_pixel = 3;
  349. } else {
  350. bytes_per_pixel = 4;
  351. }
  352. data->refr_desc.pixel_format = config->videomode.pixel_format;
  353. data->refr_desc.width = area->w;
  354. data->refr_desc.height = area->h;
  355. data->refr_desc.pitch = area->w * bytes_per_pixel;
  356. data->transfering = 1;
  357. data->transfering_last = (area->y + area->h >= CONFIG_PANEL_VER_RES);
  358. /* source from DE */
  359. display_controller_set_source(data->lcdc_dev, DISPLAY_CONTROLLER_SOURCE_ENGINE, NULL);
  360. }
  361. static void _panel_start_de_transfer(void *arg)
  362. {
  363. const struct device *dev = arg;
  364. struct lcd_panel_data *data = dev->data;
  365. const struct lcd_panel_config *config = data->config;
  366. int res;
  367. #if IS_TR_PANEL
  368. _panel_reset_pin_set(dev, false);
  369. #endif
  370. res = display_controller_write_pixels(data->lcdc_dev, config->cmd_ramwr, DC_INVALID_CMD,
  371. &data->refr_desc, NULL);
  372. if (res) {
  373. LOG_ERR("write pixels failed");
  374. data->transfering = 0;
  375. }
  376. }
  377. static void _panel_complete_transfer(void *arg)
  378. {
  379. const struct device *dev = arg;
  380. struct lcd_panel_data *data = dev->data;
  381. #if IS_TR_PANEL
  382. _panel_reset_pin_set(dev, true);
  383. #endif
  384. if (data->pm_state == PM_DEVICE_STATE_LOW_POWER)
  385. board_lcd_suspend(true, false);
  386. sys_trace_end_call(SYS_TRACE_ID_LCD_POST);
  387. data->transfering = 0;
  388. if (data->transfering_last) {
  389. data->first_frame_cplt = 1;
  390. }
  391. #if CONFIG_PANEL_PIXEL_WR_DELAY_US > 0
  392. if (data->transfering_last == 0) {
  393. k_busy_wait(CONFIG_PANEL_PIXEL_WR_DELAY_US);
  394. }
  395. #endif
  396. if (data->callback && data->callback->complete) {
  397. data->callback->complete(data->callback);
  398. }
  399. }
  400. /**********************
  401. * DEVICE API
  402. **********************/
  403. static int _lcd_panel_blanking_on(const struct device *dev)
  404. {
  405. struct lcd_panel_data *data = dev->data;
  406. const struct lcd_panel_config *config = data->config;
  407. if (data->pm_state != PM_DEVICE_STATE_ACTIVE &&
  408. data->pm_state != PM_DEVICE_STATE_LOW_POWER)
  409. return -EPERM;
  410. if (data->disp_on == 0)
  411. return 0;
  412. LOG_INF("display blanking on");
  413. data->disp_on = 0;
  414. data->in_sleep = 1;
  415. data->first_frame_cplt = 0;
  416. data->brightness_delay = CONFIG_PANEL_BRIGHTNESS_DELAY_PERIODS;
  417. _panel_te_set_enable(dev, false);
  418. _panel_apply_brightness(dev, 0);
  419. if (config->ops->blanking_on)
  420. config->ops->blanking_on(dev);
  421. display_controller_disable(data->lcdc_dev);
  422. return 0;
  423. }
  424. static int _lcd_panel_blanking_off(const struct device *dev)
  425. {
  426. struct lcd_panel_data *data = dev->data;
  427. const struct lcd_panel_config *config = data->config;
  428. if (data->pm_state != PM_DEVICE_STATE_ACTIVE &&
  429. data->pm_state != PM_DEVICE_STATE_LOW_POWER)
  430. return -EPERM;
  431. if (data->disp_on == 1)
  432. return 0;
  433. LOG_INF("display blanking off");
  434. display_controller_enable(data->lcdc_dev, &config->videoport);
  435. display_controller_set_mode(data->lcdc_dev, &config->videomode);
  436. data->disp_on = 1;
  437. if (config->ops->blanking_off)
  438. config->ops->blanking_off(dev);
  439. _panel_te_set_enable(dev, true);
  440. return 0;
  441. }
  442. static int _lcd_panel_read(const struct device *dev,
  443. const uint16_t x,
  444. const uint16_t y,
  445. const struct display_buffer_descriptor *desc,
  446. void *buf)
  447. {
  448. return -ENOTSUP;
  449. }
  450. static int _lcd_panel_write(const struct device *dev,
  451. const uint16_t x,
  452. const uint16_t y,
  453. const struct display_buffer_descriptor *desc,
  454. const void *buf)
  455. {
  456. struct lcd_panel_data *data = dev->data;
  457. const struct lcd_panel_config *config = data->config;
  458. int res;
  459. #if IS_TR_PANEL
  460. if (desc->width != CONFIG_PANEL_HOR_RES || desc->height != CONFIG_PANEL_VER_RES) {
  461. LOG_ERR("TR panel requires full-screen write");
  462. return -EINVAL;
  463. }
  464. #endif
  465. if (data->disp_on == 0 || data->transfering != 0) {
  466. LOG_ERR("disp not ready");
  467. return -EBUSY;
  468. }
  469. sys_trace_u32x4(SYS_TRACE_ID_LCD_POST,
  470. x, y, x + desc->width - 1, y + desc->height - 1);
  471. if (data->pm_state == PM_DEVICE_STATE_LOW_POWER)
  472. board_lcd_resume(true, false);
  473. if (config->ops->write_prepare) {
  474. res = config->ops->write_prepare(dev, x, y, desc->width, desc->height);
  475. if (res) {
  476. LOG_ERR("write area (%u, %u, %u, %u) failed", x, y, desc->width, desc->height);
  477. return res;
  478. }
  479. }
  480. data->transfering = 1;
  481. data->transfering_last = (y + desc->height >= CONFIG_PANEL_VER_RES);
  482. #if IS_TR_PANEL
  483. _panel_reset_pin_set(dev, false);
  484. #endif
  485. /**
  486. * CARE:
  487. * For QSPI (Sync) series interface, RAMWR cmd will send automatically by LCDC.
  488. * For other interfaces, RAMWR cmd must send in write_prepare() ops manually.
  489. */
  490. #if 0
  491. _panel_transmit(dev, DDIC_CMD_RAMWR, NULL, 0);
  492. display_controller_set_source(data->lcdc_dev, DISPLAY_CONTROLLER_SOURCE_MCU, NULL);
  493. res = display_controller_write_pixels(data->lcdc_dev,
  494. config->cmd_ramwc, DC_INVALID_CMD, desc, buf);
  495. #else
  496. display_controller_set_source(data->lcdc_dev, DISPLAY_CONTROLLER_SOURCE_DMA, NULL);
  497. res = display_controller_write_pixels(data->lcdc_dev, config->cmd_ramwr,
  498. DC_INVALID_CMD, desc, buf);
  499. #endif
  500. if (res) {
  501. LOG_ERR("write pixels failed");
  502. data->transfering = 0;
  503. }
  504. return res;
  505. }
  506. static void *_lcd_panel_get_framebuffer(const struct device *dev)
  507. {
  508. return NULL;
  509. }
  510. static int _lcd_panel_set_brightness(const struct device *dev,
  511. const uint8_t brightness)
  512. {
  513. struct lcd_panel_data *data = dev->data;
  514. if (data->disp_on == 0)
  515. return -EPERM;
  516. if (brightness == data->pending_brightness)
  517. return 0;
  518. LOG_INF("display set_brightness %u", brightness);
  519. data->pending_brightness = brightness;
  520. /* delayed set in TE interrupt handler */
  521. return 0;
  522. }
  523. static int _lcd_panel_get_brightness(const struct device *dev)
  524. {
  525. struct lcd_panel_data *data = dev->data;
  526. return data->brightness;
  527. }
  528. static int _lcd_panel_set_contrast(const struct device *dev, const uint8_t contrast)
  529. {
  530. return -ENOTSUP;
  531. }
  532. static void _lcd_panel_get_capabilities(const struct device *dev,
  533. struct display_capabilities *capabilities)
  534. {
  535. struct lcd_panel_data *data = dev->data;
  536. const struct lcd_panel_config *config = data->config;
  537. memset(capabilities, 0, sizeof(struct display_capabilities));
  538. capabilities->x_resolution = CONFIG_PANEL_HOR_RES;
  539. capabilities->y_resolution = CONFIG_PANEL_VER_RES;
  540. capabilities->refresh_rate = config->videomode.refresh_rate;
  541. capabilities->supported_pixel_formats = SUPPORTED_PANEL_PIXEL_FORMATS;
  542. capabilities->current_pixel_format = config->videomode.pixel_format;
  543. capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL;
  544. capabilities->screen_info = (CONFIG_PANEL_ROUND_SHAPE ? SCREEN_INFO_ROUND_SHAPE : 0);
  545. #if IS_TR_PANEL
  546. capabilities->screen_info |= (SCREEN_INFO_X_ALIGNMENT_WIDTH | SCREEN_INFO_Y_ALIGNMENT_HEIGHT);
  547. #endif
  548. }
  549. static int _lcd_panel_set_pixel_format(const struct device *dev,
  550. const enum display_pixel_format pixel_format)
  551. {
  552. struct lcd_panel_data *data = dev->data;
  553. const struct lcd_panel_config *config = data->config;
  554. if (pixel_format == config->videomode.pixel_format) {
  555. return 0;
  556. }
  557. LOG_ERR("Pixel format change not implemented");
  558. return -ENOTSUP;
  559. }
  560. static int _lcd_panel_set_orientation(const struct device *dev,
  561. const enum display_orientation orientation)
  562. {
  563. if (orientation == DISPLAY_ORIENTATION_NORMAL) {
  564. return 0;
  565. }
  566. LOG_ERR("Changing display orientation not implemented");
  567. return -ENOTSUP;
  568. }
  569. static int _lcd_panel_register_callback(const struct device *dev,
  570. const struct display_callback *callback)
  571. {
  572. struct lcd_panel_data *data = dev->data;
  573. if (data->callback == NULL) {
  574. data->callback = callback;
  575. return 0;
  576. }
  577. return -EBUSY;
  578. }
  579. static int _lcd_panel_unregister_callback(const struct device *dev,
  580. const struct display_callback *callback)
  581. {
  582. struct lcd_panel_data *data = dev->data;
  583. if (data->callback == callback) {
  584. data->callback = NULL;
  585. return 0;
  586. }
  587. return -EINVAL;
  588. }
  589. static int _lcd_panel_init(const struct device *dev)
  590. {
  591. struct lcd_panel_data *data = dev->data;
  592. const struct lcd_panel_pincfg *pincfg = dev->config;
  593. const struct device *de_dev = NULL;
  594. #ifdef CONFIG_PANEL_BACKLIGHT_PWM
  595. data->backlight_dev = device_get_binding(pincfg->backlight_cfg.dev_name);
  596. if (data->backlight_dev == NULL) {
  597. LOG_ERR("Couldn't find pwm device\n");
  598. return -ENODEV;
  599. }
  600. pwm_pin_set_cycles(data->backlight_dev, pincfg->backlight_cfg.chan,
  601. pincfg->backlight_cfg.period, 0, pincfg->backlight_cfg.flag);
  602. #elif defined(CONFIG_PANEL_BACKLIGHT_GPIO)
  603. data->backlight_dev = device_get_binding(pincfg->backlight_cfg.gpio_dev_name);
  604. if (data->backlight_dev == NULL) {
  605. LOG_ERR("Couldn't find backlight pin");
  606. return -ENODEV;
  607. }
  608. if (gpio_pin_configure(data->backlight_dev, pincfg->backlight_cfg.gpion,
  609. GPIO_OUTPUT_INACTIVE | pincfg->backlight_cfg.flag)) {
  610. LOG_ERR("Couldn't configure backlight pin");
  611. return -ENODEV;
  612. }
  613. #endif /* CONFIG_PANEL_BACKLIGHT_PWM */
  614. #ifdef CONFIG_PANEL_RESET_GPIO
  615. data->reset_gpio = device_get_binding(pincfg->reset_cfg.gpio_dev_name);
  616. if (data->reset_gpio == NULL) {
  617. LOG_ERR("Couldn't find reset pin");
  618. return -ENODEV;
  619. }
  620. if (gpio_pin_configure(data->reset_gpio, pincfg->reset_cfg.gpion,
  621. GPIO_OUTPUT_ACTIVE | pincfg->reset_cfg.flag)) {
  622. LOG_ERR("Couldn't configure reset pin");
  623. return -ENODEV;
  624. }
  625. #endif /* CONFIG_PANEL_RESET_GPIO */
  626. #ifdef CONFIG_PANEL_POWER_GPIO
  627. data->power_gpio = device_get_binding(pincfg->power_cfg.gpio_dev_name);
  628. if (data->power_gpio == NULL) {
  629. LOG_ERR("Couldn't find power pin");
  630. return -ENODEV;
  631. }
  632. if (gpio_pin_configure(data->power_gpio, pincfg->power_cfg.gpion,
  633. GPIO_OUTPUT_INACTIVE | pincfg->power_cfg.flag)) {
  634. LOG_ERR("Couldn't configure power pin");
  635. return -ENODEV;
  636. }
  637. #endif /* CONFIG_PANEL_POWER_GPIO */
  638. #ifdef CONFIG_PANEL_POWER1_GPIO
  639. data->power1_gpio = device_get_binding(pincfg->power1_cfg.gpio_dev_name);
  640. if (data->power1_gpio == NULL) {
  641. LOG_ERR("Couldn't find power1 pin");
  642. return -ENODEV;
  643. }
  644. if (gpio_pin_configure(data->power1_gpio, pincfg->power1_cfg.gpion,
  645. GPIO_OUTPUT_INACTIVE | pincfg->power1_cfg.flag)) {
  646. LOG_ERR("Couldn't configure power1 pin");
  647. return -ENODEV;
  648. }
  649. #endif /* CONFIG_PANEL_POWER1_GPIO */
  650. #ifdef CONFIG_PANEL_TE_GPIO
  651. data->te_gpio = device_get_binding(pincfg->te_cfg.gpio_dev_name);
  652. if (data->te_gpio == NULL) {
  653. LOG_ERR("Couldn't find te pin");
  654. return -ENODEV;
  655. }
  656. if (gpio_pin_configure(data->te_gpio, pincfg->te_cfg.gpion,
  657. GPIO_INPUT | pincfg->te_cfg.flag)) {
  658. LOG_ERR("Couldn't configure te pin");
  659. return -ENODEV;
  660. }
  661. /* FIXME: make sure interrupt disabled */
  662. gpio_pin_interrupt_configure(data->te_gpio, pincfg->te_cfg.gpion, GPIO_INT_DISABLE);
  663. gpio_init_callback(&data->te_gpio_cb, _panel_te_gpio_handler, BIT(pincfg->te_cfg.gpion));
  664. gpio_add_callback(data->te_gpio, &data->te_gpio_cb);
  665. #else
  666. k_timer_init(&data->te_timer, _panel_te_timer_handler, NULL);
  667. #endif /* CONFIG_PANEL_TE_GPIO */
  668. data->lcdc_dev = device_get_binding(CONFIG_LCDC_DEV_NAME);
  669. if (data->lcdc_dev == NULL) {
  670. LOG_ERR("Could not get LCD controller device");
  671. return -EPERM;
  672. }
  673. display_controller_control(data->lcdc_dev,
  674. DISPLAY_CONTROLLER_CTRL_COMPLETE_CB, _panel_complete_transfer, (void *)dev);
  675. if (_panel_detect(dev)) {
  676. LOG_ERR("No panel connected");
  677. return -ENODEV;
  678. }
  679. de_dev = device_get_binding(CONFIG_DISPLAY_ENGINE_DEV_NAME);
  680. if (de_dev == NULL) {
  681. LOG_WRN("Could not get display engine device");
  682. } else {
  683. display_engine_control(de_dev,
  684. DISPLAY_ENGINE_CTRL_DISPLAY_PORT, (void *)&data->config->videoport, NULL);
  685. display_engine_control(de_dev,
  686. DISPLAY_ENGINE_CTRL_DISPLAY_MODE, (void *)&data->config->videomode, NULL);
  687. display_engine_control(de_dev,
  688. DISPLAY_ENGINE_CTRL_DISPLAY_PREPARE_CB, _panel_prepare_de_transfer, (void *)dev);
  689. display_engine_control(de_dev,
  690. DISPLAY_ENGINE_CTRL_DISPLAY_START_CB, _panel_start_de_transfer, (void *)dev);
  691. }
  692. data->disp_on = 0;
  693. data->in_sleep = 1;
  694. data->te_active = 0;
  695. data->pending_brightness = CONFIG_PANEL_BRIGHTNESS;
  696. data->brightness_delay = CONFIG_PANEL_BRIGHTNESS_DELAY_PERIODS;
  697. data->pm_state = PM_DEVICE_STATE_SUSPENDED;
  698. #if CONFIG_PANEL_ESD_CHECK_PERIOD > 0
  699. k_delayed_work_init(&data->esd_check_work, _panel_esd_check_handler);
  700. #endif
  701. k_work_init(&data->resume_work, _panel_pm_resume_handler);
  702. #ifdef CONFIG_LCD_WORK_QUEUE
  703. k_work_queue_start(&data->pm_workq, pm_workq_stack, K_THREAD_STACK_SIZEOF(pm_workq_stack), 6, NULL);
  704. #endif
  705. _panel_pm_late_resume(dev);
  706. return 0;
  707. }
  708. /**********************
  709. * POWER MANAGEMENT
  710. **********************/
  711. static void _panel_pm_notify(struct lcd_panel_data *data, uint32_t pm_action)
  712. {
  713. if (data->callback && data->callback->pm_notify) {
  714. data->callback->pm_notify(data->callback, pm_action);
  715. }
  716. }
  717. static int _panel_pm_early_suspend(const struct device *dev, bool in_turnoff)
  718. {
  719. struct lcd_panel_data *data = dev->data;
  720. if (data->pm_state != PM_DEVICE_STATE_ACTIVE &&
  721. data->pm_state != PM_DEVICE_STATE_LOW_POWER) {
  722. return -EPERM;
  723. }
  724. LOG_INF("panel early-suspend");
  725. _panel_cancel_esd_check_work(data);
  726. _panel_pm_notify(data, PM_DEVICE_ACTION_EARLY_SUSPEND);
  727. _panel_power_off(dev, in_turnoff);
  728. data->pm_state = PM_DEVICE_STATE_SUSPENDED;
  729. return 0;
  730. }
  731. static int _panel_pm_late_resume(const struct device *dev)
  732. {
  733. struct lcd_panel_data *data = dev->data;
  734. if (data->pm_state != PM_DEVICE_STATE_SUSPENDED) {
  735. return -EPERM;
  736. }
  737. LOG_INF("panel late-resume");
  738. data->pm_changing = 1;
  739. #ifdef CONFIG_LCD_WORK_QUEUE
  740. k_work_submit_to_queue(&data->pm_workq, &data->resume_work);
  741. #else
  742. k_work_submit(&data->resume_work);
  743. #endif
  744. return 0;
  745. }
  746. static void _panel_pm_resume_handler(struct k_work *work)
  747. {
  748. const struct device *dev = DEVICE_GET(lcd_panel);
  749. struct lcd_panel_data *data = dev->data;
  750. LOG_INF("panel resuming");
  751. lcd_panel_wake_lock();
  752. data->pm_state = PM_DEVICE_STATE_ACTIVE;
  753. data->transfering = 0; /* reset flag in case fail again */
  754. data->pm_changing = 0;
  755. _panel_power_on(dev);
  756. _panel_pm_notify(data, PM_DEVICE_ACTION_LATE_RESUME);
  757. _panel_submit_esd_check_work(data);
  758. lcd_panel_wake_unlock();
  759. LOG_INF("panel active");
  760. }
  761. #ifdef CONFIG_PM_DEVICE
  762. static void _panel_pm_change_low_power(const struct device *dev, uint32_t pm_state)
  763. {
  764. struct lcd_panel_data *data = dev->data;
  765. const struct lcd_panel_config *config = data->config;
  766. unsigned int key;
  767. while (1) {
  768. key = irq_lock();
  769. if (!data->transfering)
  770. break;
  771. irq_unlock(key);
  772. k_msleep(1); /* wait transfer finish */
  773. }
  774. data->pm_state = pm_state;
  775. if (data->pm_state == PM_DEVICE_STATE_LOW_POWER) {
  776. if (config->ops->lowpower_enter)
  777. config->ops->lowpower_enter(dev);
  778. if (config->ops->set_aod_brightness) {
  779. config->ops->set_aod_brightness(dev, CONFIG_PANEL_AOD_BRIGHTNESS);
  780. } else {
  781. _panel_apply_brightness(dev, CONFIG_PANEL_AOD_BRIGHTNESS);
  782. }
  783. _panel_te_set_enable(dev, false);
  784. board_lcd_suspend(true, true);
  785. } else {
  786. board_lcd_resume(true, true);
  787. if (config->ops->lowpower_exit)
  788. config->ops->lowpower_exit(dev);
  789. _panel_te_set_enable(dev, true);
  790. }
  791. irq_unlock(key);
  792. }
  793. static int _panel_pm_enter_low_power(const struct device *dev)
  794. {
  795. struct lcd_panel_data *data = dev->data;
  796. if (data->pm_state != PM_DEVICE_STATE_ACTIVE) {
  797. return -EPERM;
  798. }
  799. _panel_cancel_esd_check_work(data);
  800. _panel_pm_notify(data, PM_DEVICE_ACTION_LOW_POWER);
  801. _panel_pm_change_low_power(dev, PM_DEVICE_STATE_LOW_POWER);
  802. LOG_INF("panel enter low-power");
  803. return 0;
  804. }
  805. static int _panel_pm_exit_low_power(const struct device *dev)
  806. {
  807. struct lcd_panel_data *data = dev->data;
  808. if (data->pm_state != PM_DEVICE_STATE_LOW_POWER) {
  809. return -EPERM;
  810. }
  811. _panel_pm_notify(data, PM_DEVICE_ACTION_LATE_RESUME);
  812. _panel_pm_change_low_power(dev, PM_DEVICE_STATE_ACTIVE);
  813. _panel_submit_esd_check_work(data);
  814. LOG_INF("panel exit low-power");
  815. return 0;
  816. }
  817. static int _lcd_panel_pm_control(const struct device *dev, enum pm_device_action action)
  818. {
  819. struct lcd_panel_data *data = dev->data;
  820. int ret = 0;
  821. if (data->pm_state == PM_DEVICE_STATE_OFF)
  822. return -EPERM;
  823. switch (action) {
  824. case PM_DEVICE_ACTION_EARLY_SUSPEND:
  825. if (soc_get_aod_mode()) {
  826. ret = _panel_pm_enter_low_power(dev);
  827. } else {
  828. ret = _panel_pm_early_suspend(dev, false);
  829. board_lcd_suspend(false, true);
  830. }
  831. break;
  832. case PM_DEVICE_ACTION_LATE_RESUME:
  833. if (data->pm_state == PM_DEVICE_STATE_LOW_POWER) {
  834. ret = _panel_pm_exit_low_power(dev);
  835. } else {
  836. board_lcd_resume(false, true);
  837. ret = _panel_pm_late_resume(dev);
  838. }
  839. break;
  840. case PM_DEVICE_ACTION_SUSPEND:
  841. if (data->pm_changing || data->pm_state == PM_DEVICE_STATE_ACTIVE) {
  842. ret = -EPERM;
  843. }
  844. break;
  845. case PM_DEVICE_ACTION_TURN_OFF:
  846. _panel_pm_early_suspend(dev, true);
  847. data->pm_state = PM_DEVICE_STATE_OFF;
  848. LOG_INF("panel turn-off");
  849. break;
  850. default:
  851. break;
  852. }
  853. return ret;
  854. }
  855. #endif /* CONFIG_PM_DEVICE */
  856. /**********************
  857. * DEVICE DEFINITION
  858. **********************/
  859. static const struct display_driver_api lcd_panel_driver_api = {
  860. .blanking_on = _lcd_panel_blanking_on,
  861. .blanking_off = _lcd_panel_blanking_off,
  862. .write = _lcd_panel_write,
  863. .read = _lcd_panel_read,
  864. .get_framebuffer = _lcd_panel_get_framebuffer,
  865. .set_brightness = _lcd_panel_set_brightness,
  866. .get_brightness = _lcd_panel_get_brightness,
  867. .set_contrast = _lcd_panel_set_contrast,
  868. .get_capabilities = _lcd_panel_get_capabilities,
  869. .set_pixel_format = _lcd_panel_set_pixel_format,
  870. .set_orientation = _lcd_panel_set_orientation,
  871. .register_callback = _lcd_panel_register_callback,
  872. .unregister_callback = _lcd_panel_unregister_callback,
  873. };
  874. static const struct lcd_panel_pincfg lcd_panel_pin_config = {
  875. #ifdef CONFIG_PANEL_POWER_GPIO
  876. .power_cfg = CONFIG_PANEL_POWER_GPIO,
  877. #endif
  878. #ifdef CONFIG_PANEL_POWER1_GPIO
  879. .power1_cfg = CONFIG_PANEL_POWER1_GPIO,
  880. #endif
  881. #ifdef CONFIG_PANEL_RESET_GPIO
  882. .reset_cfg = CONFIG_PANEL_RESET_GPIO,
  883. #endif
  884. #ifdef CONFIG_PANEL_TE_GPIO
  885. .te_cfg = CONFIG_PANEL_TE_GPIO,
  886. #endif
  887. #ifdef CONFIG_PANEL_BACKLIGHT_PWM
  888. .backlight_cfg = CONFIG_PANEL_BACKLIGHT_PWM,
  889. #elif defined(CONFIG_PANEL_BACKLIGHT_GPIO)
  890. .backlight_cfg = CONFIG_PANEL_BACKLIGHT_GPIO,
  891. #endif
  892. };
  893. static struct lcd_panel_data lcd_panel_data;
  894. #if IS_ENABLED(CONFIG_PANEL)
  895. DEVICE_DEFINE(lcd_panel, CONFIG_LCD_DISPLAY_DEV_NAME, _lcd_panel_init, _lcd_panel_pm_control,
  896. &lcd_panel_data, &lcd_panel_pin_config, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY,
  897. &lcd_panel_driver_api);
  898. #endif