ark1668e_lcd.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. */
  4. #include <common.h>
  5. #include <asm/io.h>
  6. #include <asm-generic/gpio.h>
  7. #include <dm.h>
  8. #include <fdtdec.h>
  9. #include <lcd.h>
  10. #include <display.h>
  11. #include <pwm.h>
  12. #include <mach/clock.h>
  13. #include <mach/ark1668e_lcdc_regs.h>
  14. #include <mach/ark1668e-sysreg.h>
  15. DECLARE_GLOBAL_DATA_PTR;
  16. /* enum {
  17. LCD_MAX_WIDTH = 1920,
  18. LCD_MAX_HEIGHT = 1080,
  19. LCD_MAX_LOG2_BPP = VIDEO_BPP32,
  20. }; */
  21. #define BACKLIGHT_PWM_PERIOD 50000
  22. #define BACKLIGHT_MAX_BRIGHTNESS 100
  23. #define SYS_REG_BASE 0xe4900000
  24. #define SYS_LCD_CLK_CFG 0x54
  25. #define SYS_CLK_DELAY 0x70
  26. #define SYS_CTL_2A 0xa8
  27. #define SYS_PIXEL_CLK_INV_OFFSET 16
  28. #define SYS_ANALOG_REG1 0x144
  29. #define SYS_LVDS_CTRL_CFG 0x190
  30. #define SYS_LVDS_CTRL_CFG1 0x194
  31. #define SWITCH_LVDS_TO_TTL 0x80000000
  32. #define SWITCH_TTL_TO_LVDS 0x00000000
  33. #define BALCK_BACKCOLOR 0x000000
  34. #define RED_BACKCOLOR 0xFF0000
  35. enum ark1668e_interface_type {
  36. ARK1668E_LCDC_INTERFACE_TTL,
  37. ARK1668E_LCDC_INTERFACE_LVDS,
  38. ARK1668E_LCDC_INTERFACE_DUAL_LVDS,
  39. };
  40. typedef enum ark1668e_lcdc_format {
  41. ARK1668E_LCDC_FORMAT_OSD_PALETTE_VIDEO_YUV422 = 0, //osd layer is palette, video layer is y_u_v422.
  42. ARK1668E_LCDC_FORMAT_OSD_BMP24BIT_VIDEO_YUV420 = 1, //osd layer isbmp24bit, video layer is y_u_v420.
  43. ARK1668E_LCDC_FORMAT_YUYV = 2, //Both osd and video layer support.
  44. ARK1668E_LCDC_FORMAT_YUV = 3,
  45. ARK1668E_LCDC_FORMAT_RGBI555 = 4,
  46. ARK1668E_LCDC_FORMAT_R5G6B5 = 5,
  47. ARK1668E_LCDC_FORMAT_RGBA888 = 6,
  48. ARK1668E_LCDC_FORMAT_RGB888 = 7,
  49. ARK1668E_LCDC_FORMAT_RGBA1555 = 8,
  50. ARK1668E_LCDC_FORMAT_RGBA1888 = 9,
  51. ARK1668E_LCDC_FORMAT_RGBA4888 = 10,
  52. ARK1668E_LCDC_FORMAT_RGB666 = 11,
  53. ARK1668E_LCDC_FORMAT_ARGA1666 = 12,
  54. ARK1668E_LCDC_FORMAT_MAX,
  55. //add which is not belong to lcdc register.Only used for video layer.
  56. ARK1668E_LCDC_FORMAT_Y_UV422 = 0x10,
  57. ARK1668E_LCDC_FORMAT_Y_UV420 = 0x11,
  58. ARK1668E_LCDC_FORMAT_END
  59. } ARK1668E_LCDC_FORMAT;
  60. typedef enum ark1668e_lcdc_ycbcr_foramt {
  61. ARK1668E_LCDC_YCBCR_FORMAT_Y_U_V, //Y_U_V422 or Y_U_V420
  62. ARK1668E_LCDC_YCBCR_FORMAT_Y_UV, //Y_UV422 or Y_UV420
  63. ARK1668E_LCDC_YCBCR_FORMAT_END
  64. } ARK1668E_LCDC_YCBCR_FORMAT;
  65. /* Way LCD wires are connected to the chip:
  66. * A swapped wiring onboard can bring to RGB mode.
  67. */
  68. #define ARK1668E_LCDC_WIRING_BGR 0
  69. #define ARK1668E_LCDC_WIRING_GBR 1
  70. #define ARK1668E_LCDC_WIRING_RBG 2
  71. #define ARK1668E_LCDC_WIRING_BRG 3
  72. #define ARK1668E_LCDC_WIRING_GRB 4
  73. #define ARK1668E_LCDC_WIRING_RGB 5
  74. struct ark_lcdc_priv {
  75. void __iomem *mmio;
  76. void __iomem *sysreg;
  77. unsigned int fb_addr;
  78. struct display_timing timing;
  79. struct gpio_desc bl_power_gpio;
  80. int bl_power;
  81. unsigned int bl_pwm;
  82. unsigned int bl_val;
  83. unsigned int bl_delay;
  84. int lcd_wiring_mode;
  85. int interface_type;
  86. unsigned int lvds_con;
  87. unsigned int lvds_con2;
  88. ulong clk_rate;
  89. };
  90. #define lcdc_readl(priv, reg) readl((priv)->mmio+(reg))
  91. #define lcdc_writel(priv, reg, val) writel((val), (priv)->mmio+(reg))
  92. #define lcdc_readl_sys(priv, reg) readl((priv)->sysreg+(reg))
  93. #define lcdc_writel_sys(priv, reg, val) writel((val), (priv)->sysreg+(reg))
  94. static int ark_lcdc_set_clk(struct udevice *dev)
  95. {
  96. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  97. unsigned int srcclk = ark_get_lcdpll_clock();
  98. unsigned int val;
  99. int div;
  100. val = lcdc_readl_sys(priv, SYS_LCD_CLK_CFG);
  101. /* select lcdpll src */
  102. val &= ~(0x7f << 4) | (0xf << 19);
  103. div = DIV_ROUND_UP(srcclk, priv->timing.pixelclock.typ) & 0xf;
  104. val |= div << 19;
  105. lcdc_writel_sys(priv, SYS_LCD_CLK_CFG, val);
  106. printf("lcdpll %dHz, div=%d, lcdclk %dHz.\n", srcclk, div, srcclk / div);
  107. return 0;
  108. }
  109. static const char *ark1668e_lcdfb_interface_types[] = {
  110. [ARK1668E_LCDC_INTERFACE_TTL] = "TTL",
  111. [ARK1668E_LCDC_INTERFACE_LVDS] = "LVDS",
  112. [ARK1668E_LCDC_INTERFACE_DUAL_LVDS] = "DLVDS",
  113. };
  114. static int ark1668e_lcdfb_get_of_interface_types(struct udevice *dev)
  115. {
  116. const char *type;
  117. int i;
  118. type = dev_read_string(dev, "interface-type");
  119. if (!type)
  120. return ARK1668E_LCDC_INTERFACE_TTL;
  121. for (i = 0; i < ARRAY_SIZE(ark1668e_lcdfb_interface_types); i++)
  122. if (!strcasecmp(type, ark1668e_lcdfb_interface_types[i]))
  123. return i;
  124. return -ENODEV;
  125. }
  126. static const char *ark1668e_lcdfb_wiring_modes[] = {
  127. [ARK1668E_LCDC_WIRING_BGR] = "BGR",
  128. [ARK1668E_LCDC_WIRING_GBR] = "GBR",
  129. [ARK1668E_LCDC_WIRING_RBG] = "RBG",
  130. [ARK1668E_LCDC_WIRING_BRG] = "BRG",
  131. [ARK1668E_LCDC_WIRING_GRB] = "GRB",
  132. [ARK1668E_LCDC_WIRING_RGB] = "RGB",
  133. };
  134. static int ark1668e_lcdfb_get_of_wiring_modes(struct udevice *dev)
  135. {
  136. const char *str;
  137. int i;
  138. str = dev_read_string(dev, "lcd-wiring-mode");
  139. if (!str)
  140. return ARK1668E_LCDC_WIRING_BGR;
  141. for (i = 0; i < ARRAY_SIZE(ark1668e_lcdfb_wiring_modes); i++)
  142. if (!strcasecmp(str, ark1668e_lcdfb_wiring_modes[i]))
  143. return i;
  144. return -ENODEV;
  145. }
  146. static void ark_lcdc_init(struct udevice *dev)
  147. {
  148. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  149. struct display_timing *timing = &priv->timing;
  150. unsigned long value;
  151. ark_lcdc_set_clk(dev);
  152. /* set lcd back color */
  153. lcdc_writel(priv, ARK1668E_LCDC_BACK_COLOR, BALCK_BACKCOLOR);
  154. /* set layer1(fb0) vp */
  155. /* reserve the layer enable */
  156. value = lcdc_readl(priv, ARK1668E_LCDC_CONTROL);
  157. value &= 0x1f << 5;
  158. value |= (6 << 23) | (1 << 0);
  159. /* set interrupt at the start of the front porch when vfp is not zero */
  160. if (timing->vfront_porch.typ)
  161. value |= (3 << 21);
  162. value |= priv->lcd_wiring_mode << 18;
  163. lcdc_writel(priv, ARK1668E_LCDC_CONTROL, value);
  164. /* timing */
  165. value = lcdc_readl_sys(priv, SYS_CLK_DELAY);
  166. if (!!(timing->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
  167. value |= (1 << SYS_PIXEL_CLK_INV_OFFSET);
  168. else
  169. value &= ~(1 << SYS_PIXEL_CLK_INV_OFFSET);
  170. lcdc_writel_sys(priv, SYS_CLK_DELAY, value);
  171. value = (timing->hsync_len.typ - 1) << ARK1668E_LCDC_HPW_OFFSET;
  172. value |= (timing->hback_porch.typ - 1) << ARK1668E_LCDC_HBP_OFFSET;
  173. value |= (timing->hfront_porch.typ - 1);
  174. lcdc_writel(priv, ARK1668E_LCDC_TIMING0, value);
  175. value = timing->vfront_porch.typ << ARK1668E_LCDC_VFP_OFFSET;
  176. value |= (timing->vsync_len.typ - 1) << ARK1668E_LCDC_VPW_OFFSET;
  177. value |= (timing->hactive.typ - 1);
  178. lcdc_writel(priv, ARK1668E_LCDC_TIMING1, value);
  179. value = !!(timing->flags & DISPLAY_FLAGS_DE_HIGH) << ARK1668E_LCDC_IOE_OFFSET;
  180. value |= !!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH) << ARK1668E_LCDC_IHS_OFFSET;
  181. value |= !!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH) << ARK1668E_LCDC_IVS_OFFSET;
  182. value |= (timing->vactive.typ - 1) << ARK1668E_LCDC_LPS_OFFSET;
  183. value |= timing->vback_porch.typ;
  184. lcdc_writel(priv, ARK1668E_LCDC_TIMING2, value);
  185. /* Initialize specific screen type */
  186. if (priv->interface_type == ARK1668E_LCDC_INTERFACE_LVDS) {
  187. lcdc_writel_sys(priv, SYS_CTL_2A, SWITCH_TTL_TO_LVDS);
  188. /* value = lcdc_readl_sys(priv, SYS_ANALOG_REG1);
  189. value |= (1 << 26);
  190. lcdc_writel_sys(priv, SYS_ANALOG_REG1, value);
  191. lcdc_writel_sys(priv, SYS_LVDS_CTRL_CFG, priv->lvds_con); */
  192. } else if (priv->interface_type == ARK1668E_LCDC_INTERFACE_DUAL_LVDS) {
  193. lcdc_writel_sys(priv, SYS_CTL_2A, SWITCH_TTL_TO_LVDS);
  194. lcdc_writel_sys(priv, SYS_LVDS_CTRL_CFG, priv->lvds_con);
  195. lcdc_writel_sys(priv, SYS_LVDS_CTRL_CFG1, priv->lvds_con2);
  196. }
  197. else if(priv->interface_type == ARK1668E_LCDC_INTERFACE_TTL)
  198. {
  199. lcdc_writel_sys(priv, SYS_CTL_2A, SWITCH_LVDS_TO_TTL);
  200. /* pad config */
  201. value = lcdc_readl_sys(priv, SYS_PAD_CTRL05);
  202. value &= ~(0x3ffff << 12);
  203. value |= (1 << 27) | (1 << 24) | (1 << 21) | (1 << 18) | (1 << 15) | (1 << 12);
  204. lcdc_writel_sys(priv, SYS_PAD_CTRL05, value);
  205. value = (1<<27) | (1<<24) | (1<<21) | (1<<18) | (1<<15) | (1<<12) | (1<<9) | (1<<6) | (1<<3) | (1<<0);
  206. lcdc_writel_sys(priv, SYS_PAD_CTRL06, value);
  207. lcdc_writel_sys(priv, SYS_PAD_CTRL07, value);
  208. value = lcdc_readl_sys(priv, SYS_PAD_CTRL08);
  209. value &= ~((7 << 3) | (7 << 0));
  210. value |= (1 << 3) | (1 << 0);
  211. lcdc_writel_sys(priv, SYS_PAD_CTRL08, value);
  212. }
  213. /* sync always on */
  214. lcdc_writel(priv, ARK1668E_LCDC_PARAMTERS_SYNC_SWITCH, 0x7f);
  215. /* Display osd layer1(fb0) size,pos,format,addr... */
  216. lcdc_writel(priv, ARK1668E_LCDC_OSD2_ADDR, priv->fb_addr);
  217. value = (timing->vactive.typ << ARK1668E_LCDC_HEIGHT_OFFSET) | timing->hactive.typ;
  218. lcdc_writel(priv, ARK1668E_LCDC_OSD2_SIZE, value);
  219. lcdc_writel(priv, ARK1668E_LCDC_OSD2_SOURCE_SIZE, value);
  220. lcdc_writel(priv, ARK1668E_LCDC_OSD2_POSITION, 0);
  221. lcdc_writel(priv, ARK1668E_LCDC_OSD2_WIN_POINT, 0);
  222. value = (1 << 17) | (ARK1668E_LCDC_FORMAT_RGBA888 << 12) | 0xff;
  223. lcdc_writel(priv, ARK1668E_LCDC_OSD2_CTL, value);
  224. /* open osd layer1 */
  225. value = lcdc_readl(priv, ARK1668E_LCDC_CONTROL);
  226. value |= (1 << ARK1668E_LCDC_OSD2_EN_OFFSET);
  227. lcdc_writel(priv, ARK1668E_LCDC_CONTROL, value);
  228. /* Clear all interrupts */
  229. lcdc_writel(priv, ARK1668E_LCDC_INTERRUPT_STATUS, 0);
  230. /* Disable interrupt */
  231. lcdc_writel(priv, ARK1668E_LCDC_INTERRUPT_CTL, 0);
  232. /* set layer priority and blend mode */
  233. lcdc_writel(priv, ARK1668E_LCDC_BLD_MODE_LCD_REG0, 0x04030200);
  234. lcdc_writel(priv, ARK1668E_LCDC_BLD_MODE_LCD_REG1, 0x0003f001);
  235. }
  236. static int ark_lcdc_probe(struct udevice *dev)
  237. {
  238. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  239. int ret;
  240. priv->sysreg = (void __iomem *)SYS_REG_BASE;
  241. if (!priv->sysreg) {
  242. printf("%s: Warning: cannot get sys base addr\n",
  243. __func__);
  244. return -1;
  245. }
  246. priv->mmio = (void __iomem *)dev_read_addr_index(dev, 0);
  247. if (!priv->mmio) {
  248. printf("%s: Warning: cannot get lcd base addr\n",
  249. __func__);
  250. return -1;
  251. }
  252. priv->fb_addr = dev_read_addr_index(dev, 1);
  253. if (!priv->fb_addr) {
  254. printf("%s: Warning: cannot get lcd framebuffer addr\n",
  255. __func__);
  256. return -1;
  257. }
  258. ret = gpio_request_by_name(dev, "power-control-gpio", 0, &priv->bl_power_gpio,
  259. GPIOD_IS_OUT);
  260. if (ret) {
  261. printf("%s: Warning: cannot get GPIO: ret=%d\n",
  262. __func__, ret);
  263. } else {
  264. priv->bl_power = 1;
  265. }
  266. ret = dev_read_u32(dev, "backlight-pwm", &priv->bl_pwm);
  267. if (!ret) {
  268. u32 duty;
  269. priv->bl_val = dev_read_u32_default(dev, "backlight-value", 30);
  270. duty = priv->bl_val * BACKLIGHT_PWM_PERIOD / BACKLIGHT_MAX_BRIGHTNESS;
  271. pwm_config(priv->bl_pwm, duty, BACKLIGHT_PWM_PERIOD);
  272. pwm_enable(priv->bl_pwm);
  273. dev_read_u32(dev, "backlight-delay", &priv->bl_delay);
  274. }
  275. priv->lcd_wiring_mode = ark1668e_lcdfb_get_of_wiring_modes(dev);
  276. priv->interface_type = ark1668e_lcdfb_get_of_interface_types(dev);
  277. if (priv->interface_type == ARK1668E_LCDC_INTERFACE_LVDS) {
  278. ret = dev_read_u32(dev, "lvds-con", &priv->lvds_con);
  279. if (ret < 0) {
  280. printf("failed to get property lvds-con\n");
  281. }
  282. } else if (priv->interface_type == ARK1668E_LCDC_INTERFACE_DUAL_LVDS) {
  283. ret = dev_read_u32(dev, "lvds-con", &priv->lvds_con);
  284. if (ret < 0) {
  285. printf("failed to get property lvds-con\n");
  286. }
  287. ret = dev_read_u32(dev, "lvds-con2", &priv->lvds_con2);
  288. if (ret < 0) {
  289. printf("failed to get property lvds-con2\n");
  290. }
  291. }
  292. ark_lcdc_init(dev);
  293. return 0;
  294. }
  295. static int ark_lcdc_ofdata_to_platdata(struct udevice *dev)
  296. {
  297. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  298. const void *blob = gd->fdt_blob;
  299. if (fdtdec_decode_display_timing(blob, dev_of_offset(dev),
  300. 0, &priv->timing)) {
  301. printf("%s: Failed to decode display timing\n", __func__);
  302. return -EINVAL;
  303. }
  304. return 0;
  305. }
  306. static int ark_lcdc_bind(struct udevice *dev)
  307. {
  308. return 0;
  309. }
  310. static int ark_lcdc_read_timing(struct udevice *dev,
  311. struct display_timing *timing)
  312. {
  313. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  314. memcpy(timing, &priv->timing, sizeof(struct display_timing));
  315. return 0;
  316. }
  317. static int ark_lcdc_enable(struct udevice *dev, int panel_bpp,
  318. const struct display_timing *timing)
  319. {
  320. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  321. lcdc_writel(priv, ARK1668E_LCDC_EANBLE, 1);
  322. if (priv->bl_power) {
  323. mdelay(priv->bl_delay);
  324. dm_gpio_set_value(&priv->bl_power_gpio, 1);
  325. }
  326. return 0;
  327. }
  328. static int ark_lcdc_disable(struct udevice *dev)
  329. {
  330. struct ark_lcdc_priv *priv = dev_get_priv(dev);
  331. if (priv->bl_power)
  332. dm_gpio_set_value(&priv->bl_power_gpio, 0);
  333. if (priv->bl_val)
  334. pwm_disable(priv->bl_pwm);
  335. lcdc_writel(priv, ARK1668E_LCDC_EANBLE, 0);
  336. return 0;
  337. }
  338. static const struct dm_display_ops ark_lcdc_ops = {
  339. .read_timing = ark_lcdc_read_timing,
  340. .enable = ark_lcdc_enable,
  341. .disable = ark_lcdc_disable,
  342. };
  343. static const struct udevice_id ark_lcdc_ids[] = {
  344. { .compatible = "arkmicro,ark1668e-lcdc" },
  345. { }
  346. };
  347. U_BOOT_DRIVER(ark1668e_lcd) = {
  348. .name = "ark1668e_lcdc",
  349. .id = UCLASS_DISPLAY,
  350. .of_match = ark_lcdc_ids,
  351. .bind = ark_lcdc_bind,
  352. .probe = ark_lcdc_probe,
  353. .ops = &ark_lcdc_ops,
  354. .ofdata_to_platdata = ark_lcdc_ofdata_to_platdata,
  355. .priv_auto_alloc_size = sizeof(struct ark_lcdc_priv),
  356. };