sunxi_display.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Display driver for Allwinner SoCs.
  4. *
  5. * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
  6. * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
  7. */
  8. #include <common.h>
  9. #include <efi_loader.h>
  10. #include <asm/arch/clock.h>
  11. #include <asm/arch/display.h>
  12. #include <asm/arch/gpio.h>
  13. #include <asm/arch/lcdc.h>
  14. #include <asm/arch/pwm.h>
  15. #include <asm/arch/tve.h>
  16. #include <asm/global_data.h>
  17. #include <asm/gpio.h>
  18. #include <asm/io.h>
  19. #include <axp_pmic.h>
  20. #include <errno.h>
  21. #include <fdtdec.h>
  22. #include <fdt_support.h>
  23. #include <i2c.h>
  24. #include <malloc.h>
  25. #include <video_fb.h>
  26. #include "../videomodes.h"
  27. #include "../anx9804.h"
  28. #include "../hitachi_tx18d42vm_lcd.h"
  29. #include "../ssd2828.h"
  30. #include "simplefb_common.h"
  31. #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
  32. #define PWM_ON 0
  33. #define PWM_OFF 1
  34. #else
  35. #define PWM_ON 1
  36. #define PWM_OFF 0
  37. #endif
  38. DECLARE_GLOBAL_DATA_PTR;
  39. enum sunxi_monitor {
  40. sunxi_monitor_none,
  41. sunxi_monitor_dvi,
  42. sunxi_monitor_hdmi,
  43. sunxi_monitor_lcd,
  44. sunxi_monitor_vga,
  45. sunxi_monitor_composite_pal,
  46. sunxi_monitor_composite_ntsc,
  47. sunxi_monitor_composite_pal_m,
  48. sunxi_monitor_composite_pal_nc,
  49. };
  50. #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
  51. struct sunxi_display {
  52. GraphicDevice graphic_device;
  53. enum sunxi_monitor monitor;
  54. unsigned int depth;
  55. unsigned int fb_addr;
  56. unsigned int fb_size;
  57. } sunxi_display;
  58. const struct ctfb_res_modes composite_video_modes[2] = {
  59. /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
  60. { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
  61. { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
  62. };
  63. #ifdef CONFIG_VIDEO_HDMI
  64. /*
  65. * Wait up to 200ms for value to be set in given part of reg.
  66. */
  67. static int await_completion(u32 *reg, u32 mask, u32 val)
  68. {
  69. unsigned long tmo = timer_get_us() + 200000;
  70. while ((readl(reg) & mask) != val) {
  71. if (timer_get_us() > tmo) {
  72. printf("DDC: timeout reading EDID\n");
  73. return -ETIME;
  74. }
  75. }
  76. return 0;
  77. }
  78. static int sunxi_hdmi_hpd_detect(int hpd_delay)
  79. {
  80. struct sunxi_ccm_reg * const ccm =
  81. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  82. struct sunxi_hdmi_reg * const hdmi =
  83. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  84. unsigned long tmo = timer_get_us() + hpd_delay * 1000;
  85. /* Set pll3 to 300MHz */
  86. clock_set_pll3(300000000);
  87. /* Set hdmi parent to pll3 */
  88. clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
  89. CCM_HDMI_CTRL_PLL3);
  90. /* Set ahb gating to pass */
  91. #ifdef CONFIG_SUNXI_GEN_SUN6I
  92. setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
  93. #endif
  94. setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
  95. /* Clock on */
  96. setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
  97. writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
  98. writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
  99. while (timer_get_us() < tmo) {
  100. if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
  101. return 1;
  102. }
  103. return 0;
  104. }
  105. static void sunxi_hdmi_shutdown(void)
  106. {
  107. struct sunxi_ccm_reg * const ccm =
  108. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  109. struct sunxi_hdmi_reg * const hdmi =
  110. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  111. clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
  112. clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
  113. clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
  114. #ifdef CONFIG_SUNXI_GEN_SUN6I
  115. clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
  116. #endif
  117. clock_set_pll3(0);
  118. }
  119. static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
  120. {
  121. struct sunxi_hdmi_reg * const hdmi =
  122. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  123. setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
  124. writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
  125. SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
  126. SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
  127. SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
  128. #ifndef CONFIG_MACH_SUN6I
  129. writel(n, &hdmi->ddc_byte_count);
  130. writel(cmnd, &hdmi->ddc_cmnd);
  131. #else
  132. writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
  133. #endif
  134. setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
  135. return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
  136. }
  137. static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
  138. {
  139. struct sunxi_hdmi_reg * const hdmi =
  140. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  141. int i, n;
  142. while (count > 0) {
  143. if (count > 16)
  144. n = 16;
  145. else
  146. n = count;
  147. if (sunxi_hdmi_ddc_do_command(
  148. SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
  149. offset, n))
  150. return -ETIME;
  151. for (i = 0; i < n; i++)
  152. *buf++ = readb(&hdmi->ddc_fifo_data);
  153. offset += n;
  154. count -= n;
  155. }
  156. return 0;
  157. }
  158. static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
  159. {
  160. int r, retries = 2;
  161. do {
  162. r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
  163. if (r)
  164. continue;
  165. r = edid_check_checksum(buf);
  166. if (r) {
  167. printf("EDID block %d: checksum error%s\n",
  168. block, retries ? ", retrying" : "");
  169. }
  170. } while (r && retries--);
  171. return r;
  172. }
  173. static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
  174. {
  175. struct edid1_info edid1;
  176. struct edid_cea861_info cea681[4];
  177. struct edid_detailed_timing *t =
  178. (struct edid_detailed_timing *)edid1.monitor_details.timing;
  179. struct sunxi_hdmi_reg * const hdmi =
  180. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  181. struct sunxi_ccm_reg * const ccm =
  182. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  183. int i, r, ext_blocks = 0;
  184. /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
  185. writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
  186. &hdmi->pad_ctrl1);
  187. writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
  188. &hdmi->pll_ctrl);
  189. writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
  190. /* Reset i2c controller */
  191. setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
  192. writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
  193. SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
  194. SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
  195. SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
  196. if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
  197. return -EIO;
  198. writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
  199. #ifndef CONFIG_MACH_SUN6I
  200. writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
  201. SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
  202. #endif
  203. r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
  204. if (r == 0) {
  205. r = edid_check_info(&edid1);
  206. if (r) {
  207. printf("EDID: invalid EDID data\n");
  208. r = -EINVAL;
  209. }
  210. }
  211. if (r == 0) {
  212. ext_blocks = edid1.extension_flag;
  213. if (ext_blocks > 4)
  214. ext_blocks = 4;
  215. for (i = 0; i < ext_blocks; i++) {
  216. if (sunxi_hdmi_edid_get_block(1 + i,
  217. (u8 *)&cea681[i]) != 0) {
  218. ext_blocks = i;
  219. break;
  220. }
  221. }
  222. }
  223. /* Disable DDC engine, no longer needed */
  224. clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
  225. clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
  226. if (r)
  227. return r;
  228. /* We want version 1.3 or 1.2 with detailed timing info */
  229. if (edid1.version != 1 || (edid1.revision < 3 &&
  230. !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
  231. printf("EDID: unsupported version %d.%d\n",
  232. edid1.version, edid1.revision);
  233. return -EINVAL;
  234. }
  235. /* Take the first usable detailed timing */
  236. for (i = 0; i < 4; i++, t++) {
  237. r = video_edid_dtd_to_ctfb_res_modes(t, mode);
  238. if (r == 0)
  239. break;
  240. }
  241. if (i == 4) {
  242. printf("EDID: no usable detailed timing found\n");
  243. return -ENOENT;
  244. }
  245. /* Check for basic audio support, if found enable hdmi output */
  246. sunxi_display.monitor = sunxi_monitor_dvi;
  247. for (i = 0; i < ext_blocks; i++) {
  248. if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
  249. cea681[i].revision < 2)
  250. continue;
  251. if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
  252. sunxi_display.monitor = sunxi_monitor_hdmi;
  253. }
  254. return 0;
  255. }
  256. #endif /* CONFIG_VIDEO_HDMI */
  257. #ifdef CONFIG_MACH_SUN4I
  258. /*
  259. * Testing has shown that on sun4i the display backend engine does not have
  260. * deep enough fifo-s causing flickering / tearing in full-hd mode due to
  261. * fifo underruns. So on sun4i we use the display frontend engine to do the
  262. * dma from memory, as the frontend does have deep enough fifo-s.
  263. */
  264. static const u32 sun4i_vert_coef[32] = {
  265. 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
  266. 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
  267. 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
  268. 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
  269. 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
  270. 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
  271. 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
  272. 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
  273. };
  274. static const u32 sun4i_horz_coef[64] = {
  275. 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
  276. 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
  277. 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
  278. 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
  279. 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
  280. 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
  281. 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
  282. 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
  283. 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
  284. 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
  285. 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
  286. 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
  287. 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
  288. 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
  289. 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
  290. 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
  291. };
  292. static void sunxi_frontend_init(void)
  293. {
  294. struct sunxi_ccm_reg * const ccm =
  295. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  296. struct sunxi_de_fe_reg * const de_fe =
  297. (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
  298. int i;
  299. /* Clocks on */
  300. setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
  301. setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
  302. clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
  303. setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
  304. for (i = 0; i < 32; i++) {
  305. writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
  306. writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
  307. writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
  308. writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
  309. writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
  310. writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
  311. }
  312. setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
  313. }
  314. static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
  315. unsigned int address)
  316. {
  317. struct sunxi_de_fe_reg * const de_fe =
  318. (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
  319. setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
  320. writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
  321. writel(mode->xres * 4, &de_fe->ch0_stride);
  322. writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
  323. writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
  324. writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
  325. &de_fe->ch0_insize);
  326. writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
  327. &de_fe->ch0_outsize);
  328. writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
  329. writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
  330. writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
  331. &de_fe->ch1_insize);
  332. writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
  333. &de_fe->ch1_outsize);
  334. writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
  335. writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
  336. setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
  337. }
  338. static void sunxi_frontend_enable(void)
  339. {
  340. struct sunxi_de_fe_reg * const de_fe =
  341. (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
  342. setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
  343. }
  344. #else
  345. static void sunxi_frontend_init(void) {}
  346. static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
  347. unsigned int address) {}
  348. static void sunxi_frontend_enable(void) {}
  349. #endif
  350. static bool sunxi_is_composite(void)
  351. {
  352. switch (sunxi_display.monitor) {
  353. case sunxi_monitor_none:
  354. case sunxi_monitor_dvi:
  355. case sunxi_monitor_hdmi:
  356. case sunxi_monitor_lcd:
  357. case sunxi_monitor_vga:
  358. return false;
  359. case sunxi_monitor_composite_pal:
  360. case sunxi_monitor_composite_ntsc:
  361. case sunxi_monitor_composite_pal_m:
  362. case sunxi_monitor_composite_pal_nc:
  363. return true;
  364. }
  365. return false; /* Never reached */
  366. }
  367. /*
  368. * This is the entity that mixes and matches the different layers and inputs.
  369. * Allwinner calls it the back-end, but i like composer better.
  370. */
  371. static void sunxi_composer_init(void)
  372. {
  373. struct sunxi_ccm_reg * const ccm =
  374. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  375. struct sunxi_de_be_reg * const de_be =
  376. (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
  377. int i;
  378. sunxi_frontend_init();
  379. #ifdef CONFIG_SUNXI_GEN_SUN6I
  380. /* Reset off */
  381. setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
  382. #endif
  383. /* Clocks on */
  384. setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
  385. #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
  386. setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
  387. #endif
  388. clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
  389. /* Engine bug, clear registers after reset */
  390. for (i = 0x0800; i < 0x1000; i += 4)
  391. writel(0, SUNXI_DE_BE0_BASE + i);
  392. setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
  393. }
  394. static u32 sunxi_rgb2yuv_coef[12] = {
  395. 0x00000107, 0x00000204, 0x00000064, 0x00000108,
  396. 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
  397. 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
  398. };
  399. static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
  400. unsigned int address)
  401. {
  402. struct sunxi_de_be_reg * const de_be =
  403. (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
  404. int i;
  405. sunxi_frontend_mode_set(mode, address);
  406. writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
  407. &de_be->disp_size);
  408. writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
  409. &de_be->layer0_size);
  410. #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
  411. writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
  412. writel(address << 3, &de_be->layer0_addr_low32b);
  413. writel(address >> 29, &de_be->layer0_addr_high4b);
  414. #else
  415. writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
  416. #endif
  417. writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
  418. setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
  419. if (mode->vmode == FB_VMODE_INTERLACED)
  420. setbits_le32(&de_be->mode,
  421. #ifndef CONFIG_MACH_SUN5I
  422. SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
  423. #endif
  424. SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
  425. if (sunxi_is_composite()) {
  426. writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
  427. &de_be->output_color_ctrl);
  428. for (i = 0; i < 12; i++)
  429. writel(sunxi_rgb2yuv_coef[i],
  430. &de_be->output_color_coef[i]);
  431. }
  432. }
  433. static void sunxi_composer_enable(void)
  434. {
  435. struct sunxi_de_be_reg * const de_be =
  436. (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
  437. sunxi_frontend_enable();
  438. setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
  439. setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
  440. }
  441. static void sunxi_lcdc_init(void)
  442. {
  443. struct sunxi_ccm_reg * const ccm =
  444. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  445. struct sunxi_lcdc_reg * const lcdc =
  446. (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
  447. /* Reset off */
  448. #ifdef CONFIG_SUNXI_GEN_SUN6I
  449. setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
  450. #else
  451. setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
  452. #endif
  453. /* Clock on */
  454. setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
  455. #ifdef CONFIG_VIDEO_LCD_IF_LVDS
  456. #ifdef CONFIG_SUNXI_GEN_SUN6I
  457. setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
  458. #else
  459. setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
  460. #endif
  461. #endif
  462. lcdc_init(lcdc);
  463. }
  464. static void sunxi_lcdc_panel_enable(void)
  465. {
  466. int pin, reset_pin;
  467. /*
  468. * Start with backlight disabled to avoid the screen flashing to
  469. * white while the lcd inits.
  470. */
  471. pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
  472. if (pin >= 0) {
  473. gpio_request(pin, "lcd_backlight_enable");
  474. gpio_direction_output(pin, 0);
  475. }
  476. pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
  477. if (pin >= 0) {
  478. gpio_request(pin, "lcd_backlight_pwm");
  479. gpio_direction_output(pin, PWM_OFF);
  480. }
  481. reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
  482. if (reset_pin >= 0) {
  483. gpio_request(reset_pin, "lcd_reset");
  484. gpio_direction_output(reset_pin, 0); /* Assert reset */
  485. }
  486. /* Give the backlight some time to turn off and power up the panel. */
  487. mdelay(40);
  488. pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
  489. if (pin >= 0) {
  490. gpio_request(pin, "lcd_power");
  491. gpio_direction_output(pin, 1);
  492. }
  493. if (reset_pin >= 0)
  494. gpio_direction_output(reset_pin, 1); /* De-assert reset */
  495. }
  496. static void sunxi_lcdc_backlight_enable(void)
  497. {
  498. int pin;
  499. /*
  500. * We want to have scanned out at least one frame before enabling the
  501. * backlight to avoid the screen flashing to white when we enable it.
  502. */
  503. mdelay(40);
  504. pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
  505. if (pin >= 0)
  506. gpio_direction_output(pin, 1);
  507. pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
  508. #ifdef SUNXI_PWM_PIN0
  509. if (pin == SUNXI_PWM_PIN0) {
  510. writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
  511. SUNXI_PWM_CTRL_ENABLE0 |
  512. SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
  513. writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
  514. sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
  515. return;
  516. }
  517. #endif
  518. if (pin >= 0)
  519. gpio_direction_output(pin, PWM_ON);
  520. }
  521. static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
  522. struct display_timing *timing)
  523. {
  524. timing->pixelclock.typ = mode->pixclock_khz * 1000;
  525. timing->hactive.typ = mode->xres;
  526. timing->hfront_porch.typ = mode->right_margin;
  527. timing->hback_porch.typ = mode->left_margin;
  528. timing->hsync_len.typ = mode->hsync_len;
  529. timing->vactive.typ = mode->yres;
  530. timing->vfront_porch.typ = mode->lower_margin;
  531. timing->vback_porch.typ = mode->upper_margin;
  532. timing->vsync_len.typ = mode->vsync_len;
  533. timing->flags = 0;
  534. if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
  535. timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
  536. else
  537. timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
  538. if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
  539. timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
  540. else
  541. timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
  542. if (mode->vmode == FB_VMODE_INTERLACED)
  543. timing->flags |= DISPLAY_FLAGS_INTERLACED;
  544. }
  545. static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
  546. bool for_ext_vga_dac)
  547. {
  548. struct sunxi_lcdc_reg * const lcdc =
  549. (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
  550. struct sunxi_ccm_reg * const ccm =
  551. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  552. int clk_div, clk_double, pin;
  553. struct display_timing timing;
  554. #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
  555. for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
  556. #else
  557. for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
  558. #endif
  559. #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
  560. sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
  561. #endif
  562. #ifdef CONFIG_VIDEO_LCD_IF_LVDS
  563. sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
  564. #endif
  565. #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
  566. sunxi_gpio_set_drv(pin, 3);
  567. #endif
  568. }
  569. lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
  570. sunxi_is_composite());
  571. sunxi_ctfb_mode_to_display_timing(mode, &timing);
  572. lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
  573. sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
  574. }
  575. #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
  576. static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
  577. int *clk_div, int *clk_double,
  578. bool use_portd_hvsync)
  579. {
  580. struct sunxi_lcdc_reg * const lcdc =
  581. (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
  582. struct sunxi_ccm_reg * const ccm =
  583. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  584. struct display_timing timing;
  585. sunxi_ctfb_mode_to_display_timing(mode, &timing);
  586. lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
  587. sunxi_is_composite());
  588. if (use_portd_hvsync) {
  589. sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
  590. sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
  591. }
  592. lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
  593. sunxi_is_composite());
  594. }
  595. #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
  596. #ifdef CONFIG_VIDEO_HDMI
  597. static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
  598. {
  599. struct sunxi_hdmi_reg * const hdmi =
  600. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  601. u8 checksum = 0;
  602. u8 avi_info_frame[17] = {
  603. 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
  604. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  605. 0x00
  606. };
  607. u8 vendor_info_frame[19] = {
  608. 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
  609. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  610. 0x00, 0x00, 0x00
  611. };
  612. int i;
  613. if (mode->pixclock_khz <= 27000)
  614. avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
  615. else
  616. avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
  617. if (mode->xres * 100 / mode->yres < 156)
  618. avi_info_frame[5] |= 0x18; /* 4 : 3 */
  619. else
  620. avi_info_frame[5] |= 0x28; /* 16 : 9 */
  621. for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
  622. checksum += avi_info_frame[i];
  623. avi_info_frame[3] = 0x100 - checksum;
  624. for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
  625. writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
  626. writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
  627. writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
  628. for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
  629. writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
  630. writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
  631. writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
  632. setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
  633. }
  634. static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
  635. int clk_div, int clk_double)
  636. {
  637. struct sunxi_hdmi_reg * const hdmi =
  638. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  639. int x, y;
  640. /* Write clear interrupt status bits */
  641. writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
  642. if (sunxi_display.monitor == sunxi_monitor_hdmi)
  643. sunxi_hdmi_setup_info_frames(mode);
  644. /* Set input sync enable */
  645. writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
  646. /* Init various registers, select pll3 as clock source */
  647. writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
  648. writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
  649. writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
  650. writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
  651. writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
  652. /* Setup clk div and doubler */
  653. clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
  654. SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
  655. if (!clk_double)
  656. setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
  657. /* Setup timing registers */
  658. writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
  659. &hdmi->video_size);
  660. x = mode->hsync_len + mode->left_margin;
  661. y = mode->vsync_len + mode->upper_margin;
  662. writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
  663. x = mode->right_margin;
  664. y = mode->lower_margin;
  665. writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
  666. x = mode->hsync_len;
  667. y = mode->vsync_len;
  668. writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
  669. if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
  670. setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
  671. if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
  672. setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
  673. }
  674. static void sunxi_hdmi_enable(void)
  675. {
  676. struct sunxi_hdmi_reg * const hdmi =
  677. (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
  678. udelay(100);
  679. setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
  680. }
  681. #endif /* CONFIG_VIDEO_HDMI */
  682. #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
  683. static void sunxi_tvencoder_mode_set(void)
  684. {
  685. struct sunxi_ccm_reg * const ccm =
  686. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  687. struct sunxi_tve_reg * const tve =
  688. (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
  689. /* Reset off */
  690. setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
  691. /* Clock on */
  692. setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
  693. switch (sunxi_display.monitor) {
  694. case sunxi_monitor_vga:
  695. tvencoder_mode_set(tve, tve_mode_vga);
  696. break;
  697. case sunxi_monitor_composite_pal_nc:
  698. tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
  699. break;
  700. case sunxi_monitor_composite_pal:
  701. tvencoder_mode_set(tve, tve_mode_composite_pal);
  702. break;
  703. case sunxi_monitor_composite_pal_m:
  704. tvencoder_mode_set(tve, tve_mode_composite_pal_m);
  705. break;
  706. case sunxi_monitor_composite_ntsc:
  707. tvencoder_mode_set(tve, tve_mode_composite_ntsc);
  708. break;
  709. case sunxi_monitor_none:
  710. case sunxi_monitor_dvi:
  711. case sunxi_monitor_hdmi:
  712. case sunxi_monitor_lcd:
  713. break;
  714. }
  715. }
  716. #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
  717. static void sunxi_drc_init(void)
  718. {
  719. #ifdef CONFIG_SUNXI_GEN_SUN6I
  720. struct sunxi_ccm_reg * const ccm =
  721. (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  722. /* On sun6i the drc must be clocked even when in pass-through mode */
  723. #ifdef CONFIG_MACH_SUN8I_A33
  724. setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
  725. #endif
  726. setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
  727. clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
  728. #endif
  729. }
  730. #ifdef CONFIG_VIDEO_VGA_VIA_LCD
  731. static void sunxi_vga_external_dac_enable(void)
  732. {
  733. int pin;
  734. pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
  735. if (pin >= 0) {
  736. gpio_request(pin, "vga_enable");
  737. gpio_direction_output(pin, 1);
  738. }
  739. }
  740. #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
  741. #ifdef CONFIG_VIDEO_LCD_SSD2828
  742. static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
  743. {
  744. struct ssd2828_config cfg = {
  745. .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
  746. .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
  747. .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
  748. .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
  749. .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
  750. .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
  751. .ssd2828_color_depth = 24,
  752. #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
  753. .mipi_dsi_number_of_data_lanes = 4,
  754. .mipi_dsi_bitrate_per_data_lane_mbps = 513,
  755. .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
  756. .mipi_dsi_delay_after_set_display_on_ms = 200
  757. #else
  758. #error MIPI LCD panel needs configuration parameters
  759. #endif
  760. };
  761. if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
  762. printf("SSD2828: SPI pins are not properly configured\n");
  763. return 1;
  764. }
  765. if (cfg.reset_pin == -1) {
  766. printf("SSD2828: Reset pin is not properly configured\n");
  767. return 1;
  768. }
  769. return ssd2828_init(&cfg, mode);
  770. }
  771. #endif /* CONFIG_VIDEO_LCD_SSD2828 */
  772. static void sunxi_engines_init(void)
  773. {
  774. sunxi_composer_init();
  775. sunxi_lcdc_init();
  776. sunxi_drc_init();
  777. }
  778. static void sunxi_mode_set(const struct ctfb_res_modes *mode,
  779. unsigned int address)
  780. {
  781. int __maybe_unused clk_div, clk_double;
  782. struct sunxi_lcdc_reg * const lcdc =
  783. (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
  784. struct sunxi_tve_reg * __maybe_unused const tve =
  785. (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
  786. switch (sunxi_display.monitor) {
  787. case sunxi_monitor_none:
  788. break;
  789. case sunxi_monitor_dvi:
  790. case sunxi_monitor_hdmi:
  791. #ifdef CONFIG_VIDEO_HDMI
  792. sunxi_composer_mode_set(mode, address);
  793. sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
  794. sunxi_hdmi_mode_set(mode, clk_div, clk_double);
  795. sunxi_composer_enable();
  796. lcdc_enable(lcdc, sunxi_display.depth);
  797. sunxi_hdmi_enable();
  798. #endif
  799. break;
  800. case sunxi_monitor_lcd:
  801. sunxi_lcdc_panel_enable();
  802. if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
  803. /*
  804. * The anx9804 needs 1.8V from eldo3, we do this here
  805. * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
  806. * to avoid turning this on when using hdmi output.
  807. */
  808. axp_set_eldo(3, 1800);
  809. anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
  810. ANX9804_DATA_RATE_1620M,
  811. sunxi_display.depth);
  812. }
  813. if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
  814. mdelay(50); /* Wait for lcd controller power on */
  815. hitachi_tx18d42vm_init();
  816. }
  817. if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
  818. unsigned int orig_i2c_bus = i2c_get_bus_num();
  819. i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
  820. i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
  821. i2c_set_bus_num(orig_i2c_bus);
  822. }
  823. sunxi_composer_mode_set(mode, address);
  824. sunxi_lcdc_tcon0_mode_set(mode, false);
  825. sunxi_composer_enable();
  826. lcdc_enable(lcdc, sunxi_display.depth);
  827. #ifdef CONFIG_VIDEO_LCD_SSD2828
  828. sunxi_ssd2828_init(mode);
  829. #endif
  830. sunxi_lcdc_backlight_enable();
  831. break;
  832. case sunxi_monitor_vga:
  833. #ifdef CONFIG_VIDEO_VGA
  834. sunxi_composer_mode_set(mode, address);
  835. sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
  836. sunxi_tvencoder_mode_set();
  837. sunxi_composer_enable();
  838. lcdc_enable(lcdc, sunxi_display.depth);
  839. tvencoder_enable(tve);
  840. #elif defined CONFIG_VIDEO_VGA_VIA_LCD
  841. sunxi_composer_mode_set(mode, address);
  842. sunxi_lcdc_tcon0_mode_set(mode, true);
  843. sunxi_composer_enable();
  844. lcdc_enable(lcdc, sunxi_display.depth);
  845. sunxi_vga_external_dac_enable();
  846. #endif
  847. break;
  848. case sunxi_monitor_composite_pal:
  849. case sunxi_monitor_composite_ntsc:
  850. case sunxi_monitor_composite_pal_m:
  851. case sunxi_monitor_composite_pal_nc:
  852. #ifdef CONFIG_VIDEO_COMPOSITE
  853. sunxi_composer_mode_set(mode, address);
  854. sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
  855. sunxi_tvencoder_mode_set();
  856. sunxi_composer_enable();
  857. lcdc_enable(lcdc, sunxi_display.depth);
  858. tvencoder_enable(tve);
  859. #endif
  860. break;
  861. }
  862. }
  863. static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
  864. {
  865. switch (monitor) {
  866. case sunxi_monitor_none: return "none";
  867. case sunxi_monitor_dvi: return "dvi";
  868. case sunxi_monitor_hdmi: return "hdmi";
  869. case sunxi_monitor_lcd: return "lcd";
  870. case sunxi_monitor_vga: return "vga";
  871. case sunxi_monitor_composite_pal: return "composite-pal";
  872. case sunxi_monitor_composite_ntsc: return "composite-ntsc";
  873. case sunxi_monitor_composite_pal_m: return "composite-pal-m";
  874. case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
  875. }
  876. return NULL; /* never reached */
  877. }
  878. ulong board_get_usable_ram_top(ulong total_size)
  879. {
  880. return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
  881. }
  882. static bool sunxi_has_hdmi(void)
  883. {
  884. #ifdef CONFIG_VIDEO_HDMI
  885. return true;
  886. #else
  887. return false;
  888. #endif
  889. }
  890. static bool sunxi_has_lcd(void)
  891. {
  892. char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
  893. return lcd_mode[0] != 0;
  894. }
  895. static bool sunxi_has_vga(void)
  896. {
  897. #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
  898. return true;
  899. #else
  900. return false;
  901. #endif
  902. }
  903. static bool sunxi_has_composite(void)
  904. {
  905. #ifdef CONFIG_VIDEO_COMPOSITE
  906. return true;
  907. #else
  908. return false;
  909. #endif
  910. }
  911. static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
  912. {
  913. if (allow_hdmi && sunxi_has_hdmi())
  914. return sunxi_monitor_dvi;
  915. else if (sunxi_has_lcd())
  916. return sunxi_monitor_lcd;
  917. else if (sunxi_has_vga())
  918. return sunxi_monitor_vga;
  919. else if (sunxi_has_composite())
  920. return sunxi_monitor_composite_pal;
  921. else
  922. return sunxi_monitor_none;
  923. }
  924. void *video_hw_init(void)
  925. {
  926. static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
  927. const struct ctfb_res_modes *mode;
  928. struct ctfb_res_modes custom;
  929. const char *options;
  930. #ifdef CONFIG_VIDEO_HDMI
  931. int ret, hpd, hpd_delay, edid;
  932. #endif
  933. int i, overscan_offset, overscan_x, overscan_y;
  934. unsigned int fb_dma_addr;
  935. char mon[16];
  936. char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
  937. memset(&sunxi_display, 0, sizeof(struct sunxi_display));
  938. video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
  939. &sunxi_display.depth, &options);
  940. #ifdef CONFIG_VIDEO_HDMI
  941. hpd = video_get_option_int(options, "hpd", 1);
  942. hpd_delay = video_get_option_int(options, "hpd_delay", 500);
  943. edid = video_get_option_int(options, "edid", 1);
  944. #endif
  945. overscan_x = video_get_option_int(options, "overscan_x", -1);
  946. overscan_y = video_get_option_int(options, "overscan_y", -1);
  947. sunxi_display.monitor = sunxi_get_default_mon(true);
  948. video_get_option_string(options, "monitor", mon, sizeof(mon),
  949. sunxi_get_mon_desc(sunxi_display.monitor));
  950. for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
  951. if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
  952. sunxi_display.monitor = i;
  953. break;
  954. }
  955. }
  956. if (i > SUNXI_MONITOR_LAST)
  957. printf("Unknown monitor: '%s', falling back to '%s'\n",
  958. mon, sunxi_get_mon_desc(sunxi_display.monitor));
  959. #ifdef CONFIG_VIDEO_HDMI
  960. /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
  961. if (sunxi_display.monitor == sunxi_monitor_dvi ||
  962. sunxi_display.monitor == sunxi_monitor_hdmi) {
  963. /* Always call hdp_detect, as it also enables clocks, etc. */
  964. ret = sunxi_hdmi_hpd_detect(hpd_delay);
  965. if (ret) {
  966. printf("HDMI connected: ");
  967. if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
  968. mode = &custom;
  969. } else if (hpd) {
  970. sunxi_hdmi_shutdown();
  971. sunxi_display.monitor = sunxi_get_default_mon(false);
  972. } /* else continue with hdmi/dvi without a cable connected */
  973. }
  974. #endif
  975. switch (sunxi_display.monitor) {
  976. case sunxi_monitor_none:
  977. return NULL;
  978. case sunxi_monitor_dvi:
  979. case sunxi_monitor_hdmi:
  980. if (!sunxi_has_hdmi()) {
  981. printf("HDMI/DVI not supported on this board\n");
  982. sunxi_display.monitor = sunxi_monitor_none;
  983. return NULL;
  984. }
  985. break;
  986. case sunxi_monitor_lcd:
  987. if (!sunxi_has_lcd()) {
  988. printf("LCD not supported on this board\n");
  989. sunxi_display.monitor = sunxi_monitor_none;
  990. return NULL;
  991. }
  992. sunxi_display.depth = video_get_params(&custom, lcd_mode);
  993. mode = &custom;
  994. break;
  995. case sunxi_monitor_vga:
  996. if (!sunxi_has_vga()) {
  997. printf("VGA not supported on this board\n");
  998. sunxi_display.monitor = sunxi_monitor_none;
  999. return NULL;
  1000. }
  1001. sunxi_display.depth = 18;
  1002. break;
  1003. case sunxi_monitor_composite_pal:
  1004. case sunxi_monitor_composite_ntsc:
  1005. case sunxi_monitor_composite_pal_m:
  1006. case sunxi_monitor_composite_pal_nc:
  1007. if (!sunxi_has_composite()) {
  1008. printf("Composite video not supported on this board\n");
  1009. sunxi_display.monitor = sunxi_monitor_none;
  1010. return NULL;
  1011. }
  1012. if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
  1013. sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
  1014. mode = &composite_video_modes[0];
  1015. else
  1016. mode = &composite_video_modes[1];
  1017. sunxi_display.depth = 24;
  1018. break;
  1019. }
  1020. /* Yes these defaults are quite high, overscan on composite sucks... */
  1021. if (overscan_x == -1)
  1022. overscan_x = sunxi_is_composite() ? 32 : 0;
  1023. if (overscan_y == -1)
  1024. overscan_y = sunxi_is_composite() ? 20 : 0;
  1025. sunxi_display.fb_size =
  1026. (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
  1027. overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
  1028. /* We want to keep the fb_base for simplefb page aligned, where as
  1029. * the sunxi dma engines will happily accept an unaligned address. */
  1030. if (overscan_offset)
  1031. sunxi_display.fb_size += 0x1000;
  1032. if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
  1033. printf("Error need %dkB for fb, but only %dkB is reserved\n",
  1034. sunxi_display.fb_size >> 10,
  1035. CONFIG_SUNXI_MAX_FB_SIZE >> 10);
  1036. return NULL;
  1037. }
  1038. printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
  1039. mode->xres, mode->yres,
  1040. (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
  1041. sunxi_get_mon_desc(sunxi_display.monitor),
  1042. overscan_x, overscan_y);
  1043. gd->fb_base = gd->bd->bi_dram[0].start +
  1044. gd->bd->bi_dram[0].size - sunxi_display.fb_size;
  1045. sunxi_engines_init();
  1046. #ifdef CONFIG_EFI_LOADER
  1047. efi_add_memory_map(gd->fb_base,
  1048. ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
  1049. EFI_PAGE_SHIFT,
  1050. EFI_RESERVED_MEMORY_TYPE, false);
  1051. #endif
  1052. fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
  1053. sunxi_display.fb_addr = gd->fb_base;
  1054. if (overscan_offset) {
  1055. fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
  1056. sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
  1057. memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
  1058. flush_cache(gd->fb_base, sunxi_display.fb_size);
  1059. }
  1060. sunxi_mode_set(mode, fb_dma_addr);
  1061. /*
  1062. * These are the only members of this structure that are used. All the
  1063. * others are driver specific. The pitch is stored in plnSizeX.
  1064. */
  1065. graphic_device->frameAdrs = sunxi_display.fb_addr;
  1066. graphic_device->gdfIndex = GDF_32BIT_X888RGB;
  1067. graphic_device->gdfBytesPP = 4;
  1068. graphic_device->winSizeX = mode->xres - 2 * overscan_x;
  1069. graphic_device->winSizeY = mode->yres - 2 * overscan_y;
  1070. graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
  1071. return graphic_device;
  1072. }
  1073. /*
  1074. * Simplefb support.
  1075. */
  1076. #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
  1077. int sunxi_simplefb_setup(void *blob)
  1078. {
  1079. static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
  1080. int offset, ret;
  1081. u64 start, size;
  1082. const char *pipeline = NULL;
  1083. #ifdef CONFIG_MACH_SUN4I
  1084. #define PIPELINE_PREFIX "de_fe0-"
  1085. #else
  1086. #define PIPELINE_PREFIX
  1087. #endif
  1088. switch (sunxi_display.monitor) {
  1089. case sunxi_monitor_none:
  1090. return 0;
  1091. case sunxi_monitor_dvi:
  1092. case sunxi_monitor_hdmi:
  1093. pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
  1094. break;
  1095. case sunxi_monitor_lcd:
  1096. pipeline = PIPELINE_PREFIX "de_be0-lcd0";
  1097. break;
  1098. case sunxi_monitor_vga:
  1099. #ifdef CONFIG_VIDEO_VGA
  1100. pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
  1101. #elif defined CONFIG_VIDEO_VGA_VIA_LCD
  1102. pipeline = PIPELINE_PREFIX "de_be0-lcd0";
  1103. #endif
  1104. break;
  1105. case sunxi_monitor_composite_pal:
  1106. case sunxi_monitor_composite_ntsc:
  1107. case sunxi_monitor_composite_pal_m:
  1108. case sunxi_monitor_composite_pal_nc:
  1109. pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
  1110. break;
  1111. }
  1112. offset = sunxi_simplefb_fdt_match(blob, pipeline);
  1113. if (offset < 0) {
  1114. eprintf("Cannot setup simplefb: node not found\n");
  1115. return 0; /* Keep older kernels working */
  1116. }
  1117. /*
  1118. * Do not report the framebuffer as free RAM to the OS, note we cannot
  1119. * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
  1120. * and e.g. Linux refuses to iomap RAM on ARM, see:
  1121. * linux/arch/arm/mm/ioremap.c around line 301.
  1122. */
  1123. start = gd->bd->bi_dram[0].start;
  1124. size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
  1125. ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
  1126. if (ret) {
  1127. eprintf("Cannot setup simplefb: Error reserving memory\n");
  1128. return ret;
  1129. }
  1130. ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
  1131. graphic_device->winSizeX, graphic_device->winSizeY,
  1132. graphic_device->plnSizeX, "x8r8g8b8");
  1133. if (ret)
  1134. eprintf("Cannot setup simplefb: Error setting properties\n");
  1135. return ret;
  1136. }
  1137. #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */