btext.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Procedures for drawing on the screen early on in the boot process.
  4. *
  5. * Benjamin Herrenschmidt <benh@kernel.crashing.org>
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/string.h>
  9. #include <linux/init.h>
  10. #include <linux/export.h>
  11. #include <linux/font.h>
  12. #include <linux/memblock.h>
  13. #include <linux/pgtable.h>
  14. #include <linux/of.h>
  15. #include <asm/sections.h>
  16. #include <asm/btext.h>
  17. #include <asm/page.h>
  18. #include <asm/mmu.h>
  19. #include <asm/io.h>
  20. #include <asm/processor.h>
  21. #include <asm/udbg.h>
  22. #define NO_SCROLL
  23. #ifndef NO_SCROLL
  24. static void scrollscreen(void);
  25. #endif
  26. #define __force_data __section(".data")
  27. static int g_loc_X __force_data;
  28. static int g_loc_Y __force_data;
  29. static int g_max_loc_X __force_data;
  30. static int g_max_loc_Y __force_data;
  31. static int dispDeviceRowBytes __force_data;
  32. static int dispDeviceDepth __force_data;
  33. static int dispDeviceRect[4] __force_data;
  34. static unsigned char *dispDeviceBase __force_data;
  35. static unsigned char *logicalDisplayBase __force_data;
  36. unsigned long disp_BAT[2] __initdata = {0, 0};
  37. static int boot_text_mapped __force_data;
  38. extern void rmci_on(void);
  39. extern void rmci_off(void);
  40. static inline void rmci_maybe_on(void)
  41. {
  42. #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
  43. if (!(mfmsr() & MSR_DR))
  44. rmci_on();
  45. #endif
  46. }
  47. static inline void rmci_maybe_off(void)
  48. {
  49. #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
  50. if (!(mfmsr() & MSR_DR))
  51. rmci_off();
  52. #endif
  53. }
  54. #ifdef CONFIG_PPC32
  55. /* Calc BAT values for mapping the display and store them
  56. * in disp_BAT. Those values are then used from head.S to map
  57. * the display during identify_machine() and MMU_Init()
  58. *
  59. * The display is mapped to virtual address 0xD0000000, rather
  60. * than 1:1, because some CHRP machines put the frame buffer
  61. * in the region starting at 0xC0000000 (PAGE_OFFSET).
  62. * This mapping is temporary and will disappear as soon as the
  63. * setup done by MMU_Init() is applied.
  64. *
  65. * For now, we align the BAT and then map 8Mb on 601 and 16Mb
  66. * on other PPCs. This may cause trouble if the framebuffer
  67. * is really badly aligned, but I didn't encounter this case
  68. * yet.
  69. */
  70. void __init btext_prepare_BAT(void)
  71. {
  72. unsigned long vaddr = PAGE_OFFSET + 0x10000000;
  73. unsigned long addr;
  74. unsigned long lowbits;
  75. addr = (unsigned long)dispDeviceBase;
  76. if (!addr) {
  77. boot_text_mapped = 0;
  78. return;
  79. }
  80. lowbits = addr & ~0xFF000000UL;
  81. addr &= 0xFF000000UL;
  82. disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
  83. disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
  84. logicalDisplayBase = (void *) (vaddr + lowbits);
  85. }
  86. #endif
  87. /* This function can be used to enable the early boot text when doing
  88. * OF booting or within bootx init. It must be followed by a btext_unmap()
  89. * call before the logical address becomes unusable
  90. */
  91. void __init btext_setup_display(int width, int height, int depth, int pitch,
  92. unsigned long address)
  93. {
  94. g_loc_X = 0;
  95. g_loc_Y = 0;
  96. g_max_loc_X = width / 8;
  97. g_max_loc_Y = height / 16;
  98. logicalDisplayBase = (unsigned char *)address;
  99. dispDeviceBase = (unsigned char *)address;
  100. dispDeviceRowBytes = pitch;
  101. dispDeviceDepth = depth == 15 ? 16 : depth;
  102. dispDeviceRect[0] = dispDeviceRect[1] = 0;
  103. dispDeviceRect[2] = width;
  104. dispDeviceRect[3] = height;
  105. boot_text_mapped = 1;
  106. }
  107. void __init btext_unmap(void)
  108. {
  109. boot_text_mapped = 0;
  110. }
  111. /* Here's a small text engine to use during early boot
  112. * or for debugging purposes
  113. *
  114. * todo:
  115. *
  116. * - build some kind of vgacon with it to enable early printk
  117. * - move to a separate file
  118. * - add a few video driver hooks to keep in sync with display
  119. * changes.
  120. */
  121. void btext_map(void)
  122. {
  123. unsigned long base, offset, size;
  124. unsigned char *vbase;
  125. /* By default, we are no longer mapped */
  126. boot_text_mapped = 0;
  127. if (!dispDeviceBase)
  128. return;
  129. base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL;
  130. offset = ((unsigned long) dispDeviceBase) - base;
  131. size = dispDeviceRowBytes * dispDeviceRect[3] + offset
  132. + dispDeviceRect[0];
  133. vbase = ioremap_wc(base, size);
  134. if (!vbase)
  135. return;
  136. logicalDisplayBase = vbase + offset;
  137. boot_text_mapped = 1;
  138. }
  139. static int __init btext_initialize(struct device_node *np)
  140. {
  141. unsigned int width, height, depth, pitch;
  142. unsigned long address = 0;
  143. const u32 *prop;
  144. prop = of_get_property(np, "linux,bootx-width", NULL);
  145. if (prop == NULL)
  146. prop = of_get_property(np, "width", NULL);
  147. if (prop == NULL)
  148. return -EINVAL;
  149. width = *prop;
  150. prop = of_get_property(np, "linux,bootx-height", NULL);
  151. if (prop == NULL)
  152. prop = of_get_property(np, "height", NULL);
  153. if (prop == NULL)
  154. return -EINVAL;
  155. height = *prop;
  156. prop = of_get_property(np, "linux,bootx-depth", NULL);
  157. if (prop == NULL)
  158. prop = of_get_property(np, "depth", NULL);
  159. if (prop == NULL)
  160. return -EINVAL;
  161. depth = *prop;
  162. pitch = width * ((depth + 7) / 8);
  163. prop = of_get_property(np, "linux,bootx-linebytes", NULL);
  164. if (prop == NULL)
  165. prop = of_get_property(np, "linebytes", NULL);
  166. if (prop && *prop != 0xffffffffu)
  167. pitch = *prop;
  168. if (pitch == 1)
  169. pitch = 0x1000;
  170. prop = of_get_property(np, "linux,bootx-addr", NULL);
  171. if (prop == NULL)
  172. prop = of_get_property(np, "address", NULL);
  173. if (prop)
  174. address = *prop;
  175. /* FIXME: Add support for PCI reg properties. Right now, only
  176. * reliable on macs
  177. */
  178. if (address == 0)
  179. return -EINVAL;
  180. g_loc_X = 0;
  181. g_loc_Y = 0;
  182. g_max_loc_X = width / 8;
  183. g_max_loc_Y = height / 16;
  184. dispDeviceBase = (unsigned char *)address;
  185. dispDeviceRowBytes = pitch;
  186. dispDeviceDepth = depth == 15 ? 16 : depth;
  187. dispDeviceRect[0] = dispDeviceRect[1] = 0;
  188. dispDeviceRect[2] = width;
  189. dispDeviceRect[3] = height;
  190. btext_map();
  191. return 0;
  192. }
  193. int __init btext_find_display(int allow_nonstdout)
  194. {
  195. struct device_node *np = of_stdout;
  196. int rc = -ENODEV;
  197. if (!of_node_is_type(np, "display")) {
  198. printk("boot stdout isn't a display !\n");
  199. np = NULL;
  200. }
  201. if (np)
  202. rc = btext_initialize(np);
  203. if (rc == 0 || !allow_nonstdout)
  204. return rc;
  205. for_each_node_by_type(np, "display") {
  206. if (of_property_read_bool(np, "linux,opened")) {
  207. printk("trying %pOF ...\n", np);
  208. rc = btext_initialize(np);
  209. printk("result: %d\n", rc);
  210. }
  211. if (rc == 0) {
  212. of_node_put(np);
  213. break;
  214. }
  215. }
  216. return rc;
  217. }
  218. /* Calc the base address of a given point (x,y) */
  219. static unsigned char * calc_base(int x, int y)
  220. {
  221. unsigned char *base;
  222. base = logicalDisplayBase;
  223. if (!base)
  224. base = dispDeviceBase;
  225. base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
  226. base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
  227. return base;
  228. }
  229. /* Adjust the display to a new resolution */
  230. void btext_update_display(unsigned long phys, int width, int height,
  231. int depth, int pitch)
  232. {
  233. if (!dispDeviceBase)
  234. return;
  235. /* check it's the same frame buffer (within 256MB) */
  236. if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000)
  237. return;
  238. dispDeviceBase = (__u8 *) phys;
  239. dispDeviceRect[0] = 0;
  240. dispDeviceRect[1] = 0;
  241. dispDeviceRect[2] = width;
  242. dispDeviceRect[3] = height;
  243. dispDeviceDepth = depth;
  244. dispDeviceRowBytes = pitch;
  245. if (boot_text_mapped) {
  246. iounmap(logicalDisplayBase);
  247. boot_text_mapped = 0;
  248. }
  249. btext_map();
  250. g_loc_X = 0;
  251. g_loc_Y = 0;
  252. g_max_loc_X = width / 8;
  253. g_max_loc_Y = height / 16;
  254. }
  255. EXPORT_SYMBOL(btext_update_display);
  256. void __init btext_clearscreen(void)
  257. {
  258. unsigned int *base = (unsigned int *)calc_base(0, 0);
  259. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  260. (dispDeviceDepth >> 3)) >> 2;
  261. int i,j;
  262. rmci_maybe_on();
  263. for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
  264. {
  265. unsigned int *ptr = base;
  266. for(j=width; j; --j)
  267. *(ptr++) = 0;
  268. base += (dispDeviceRowBytes >> 2);
  269. }
  270. rmci_maybe_off();
  271. }
  272. void __init btext_flushscreen(void)
  273. {
  274. unsigned int *base = (unsigned int *)calc_base(0, 0);
  275. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  276. (dispDeviceDepth >> 3)) >> 2;
  277. int i,j;
  278. for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
  279. {
  280. unsigned int *ptr = base;
  281. for(j = width; j > 0; j -= 8) {
  282. __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
  283. ptr += 8;
  284. }
  285. base += (dispDeviceRowBytes >> 2);
  286. }
  287. __asm__ __volatile__ ("sync" ::: "memory");
  288. }
  289. void __init btext_flushline(void)
  290. {
  291. unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4);
  292. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  293. (dispDeviceDepth >> 3)) >> 2;
  294. int i,j;
  295. for (i=0; i < 16; i++)
  296. {
  297. unsigned int *ptr = base;
  298. for(j = width; j > 0; j -= 8) {
  299. __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
  300. ptr += 8;
  301. }
  302. base += (dispDeviceRowBytes >> 2);
  303. }
  304. __asm__ __volatile__ ("sync" ::: "memory");
  305. }
  306. #ifndef NO_SCROLL
  307. static void scrollscreen(void)
  308. {
  309. unsigned int *src = (unsigned int *)calc_base(0,16);
  310. unsigned int *dst = (unsigned int *)calc_base(0,0);
  311. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  312. (dispDeviceDepth >> 3)) >> 2;
  313. int i,j;
  314. rmci_maybe_on();
  315. for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
  316. {
  317. unsigned int *src_ptr = src;
  318. unsigned int *dst_ptr = dst;
  319. for(j=width; j; --j)
  320. *(dst_ptr++) = *(src_ptr++);
  321. src += (dispDeviceRowBytes >> 2);
  322. dst += (dispDeviceRowBytes >> 2);
  323. }
  324. for (i=0; i<16; i++)
  325. {
  326. unsigned int *dst_ptr = dst;
  327. for(j=width; j; --j)
  328. *(dst_ptr++) = 0;
  329. dst += (dispDeviceRowBytes >> 2);
  330. }
  331. rmci_maybe_off();
  332. }
  333. #endif /* ndef NO_SCROLL */
  334. static unsigned int expand_bits_8[16] = {
  335. 0x00000000,
  336. 0x000000ff,
  337. 0x0000ff00,
  338. 0x0000ffff,
  339. 0x00ff0000,
  340. 0x00ff00ff,
  341. 0x00ffff00,
  342. 0x00ffffff,
  343. 0xff000000,
  344. 0xff0000ff,
  345. 0xff00ff00,
  346. 0xff00ffff,
  347. 0xffff0000,
  348. 0xffff00ff,
  349. 0xffffff00,
  350. 0xffffffff
  351. };
  352. static unsigned int expand_bits_16[4] = {
  353. 0x00000000,
  354. 0x0000ffff,
  355. 0xffff0000,
  356. 0xffffffff
  357. };
  358. static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
  359. {
  360. int l, bits;
  361. int fg = 0xFFFFFFFFUL;
  362. int bg = 0x00000000UL;
  363. for (l = 0; l < 16; ++l)
  364. {
  365. bits = *font++;
  366. base[0] = (-(bits >> 7) & fg) ^ bg;
  367. base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
  368. base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
  369. base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
  370. base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
  371. base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
  372. base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
  373. base[7] = (-(bits & 1) & fg) ^ bg;
  374. base = (unsigned int *) ((char *)base + rb);
  375. }
  376. }
  377. static inline void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
  378. {
  379. int l, bits;
  380. int fg = 0xFFFFFFFFUL;
  381. int bg = 0x00000000UL;
  382. unsigned int *eb = (int *)expand_bits_16;
  383. for (l = 0; l < 16; ++l)
  384. {
  385. bits = *font++;
  386. base[0] = (eb[bits >> 6] & fg) ^ bg;
  387. base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
  388. base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
  389. base[3] = (eb[bits & 3] & fg) ^ bg;
  390. base = (unsigned int *) ((char *)base + rb);
  391. }
  392. }
  393. static inline void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
  394. {
  395. int l, bits;
  396. int fg = 0x0F0F0F0FUL;
  397. int bg = 0x00000000UL;
  398. unsigned int *eb = (int *)expand_bits_8;
  399. for (l = 0; l < 16; ++l)
  400. {
  401. bits = *font++;
  402. base[0] = (eb[bits >> 4] & fg) ^ bg;
  403. base[1] = (eb[bits & 0xf] & fg) ^ bg;
  404. base = (unsigned int *) ((char *)base + rb);
  405. }
  406. }
  407. static noinline void draw_byte(unsigned char c, long locX, long locY)
  408. {
  409. unsigned char *base = calc_base(locX << 3, locY << 4);
  410. unsigned int font_index = c * 16;
  411. const unsigned char *font = font_sun_8x16.data + font_index;
  412. int rb = dispDeviceRowBytes;
  413. rmci_maybe_on();
  414. switch(dispDeviceDepth) {
  415. case 24:
  416. case 32:
  417. draw_byte_32(font, (unsigned int *)base, rb);
  418. break;
  419. case 15:
  420. case 16:
  421. draw_byte_16(font, (unsigned int *)base, rb);
  422. break;
  423. case 8:
  424. draw_byte_8(font, (unsigned int *)base, rb);
  425. break;
  426. }
  427. rmci_maybe_off();
  428. }
  429. void btext_drawchar(char c)
  430. {
  431. int cline = 0;
  432. #ifdef NO_SCROLL
  433. int x;
  434. #endif
  435. if (!boot_text_mapped)
  436. return;
  437. switch (c) {
  438. case '\b':
  439. if (g_loc_X > 0)
  440. --g_loc_X;
  441. break;
  442. case '\t':
  443. g_loc_X = (g_loc_X & -8) + 8;
  444. break;
  445. case '\r':
  446. g_loc_X = 0;
  447. break;
  448. case '\n':
  449. g_loc_X = 0;
  450. g_loc_Y++;
  451. cline = 1;
  452. break;
  453. default:
  454. draw_byte(c, g_loc_X++, g_loc_Y);
  455. }
  456. if (g_loc_X >= g_max_loc_X) {
  457. g_loc_X = 0;
  458. g_loc_Y++;
  459. cline = 1;
  460. }
  461. #ifndef NO_SCROLL
  462. while (g_loc_Y >= g_max_loc_Y) {
  463. scrollscreen();
  464. g_loc_Y--;
  465. }
  466. #else
  467. /* wrap around from bottom to top of screen so we don't
  468. waste time scrolling each line. -- paulus. */
  469. if (g_loc_Y >= g_max_loc_Y)
  470. g_loc_Y = 0;
  471. if (cline) {
  472. for (x = 0; x < g_max_loc_X; ++x)
  473. draw_byte(' ', x, g_loc_Y);
  474. }
  475. #endif
  476. }
  477. void btext_drawstring(const char *c)
  478. {
  479. if (!boot_text_mapped)
  480. return;
  481. while (*c)
  482. btext_drawchar(*c++);
  483. }
  484. void __init btext_drawtext(const char *c, unsigned int len)
  485. {
  486. if (!boot_text_mapped)
  487. return;
  488. while (len--)
  489. btext_drawchar(*c++);
  490. }
  491. void __init btext_drawhex(unsigned long v)
  492. {
  493. if (!boot_text_mapped)
  494. return;
  495. #ifdef CONFIG_PPC64
  496. btext_drawchar(hex_asc_hi(v >> 56));
  497. btext_drawchar(hex_asc_lo(v >> 56));
  498. btext_drawchar(hex_asc_hi(v >> 48));
  499. btext_drawchar(hex_asc_lo(v >> 48));
  500. btext_drawchar(hex_asc_hi(v >> 40));
  501. btext_drawchar(hex_asc_lo(v >> 40));
  502. btext_drawchar(hex_asc_hi(v >> 32));
  503. btext_drawchar(hex_asc_lo(v >> 32));
  504. #endif
  505. btext_drawchar(hex_asc_hi(v >> 24));
  506. btext_drawchar(hex_asc_lo(v >> 24));
  507. btext_drawchar(hex_asc_hi(v >> 16));
  508. btext_drawchar(hex_asc_lo(v >> 16));
  509. btext_drawchar(hex_asc_hi(v >> 8));
  510. btext_drawchar(hex_asc_lo(v >> 8));
  511. btext_drawchar(hex_asc_hi(v));
  512. btext_drawchar(hex_asc_lo(v));
  513. btext_drawchar(' ');
  514. }
  515. void __init udbg_init_btext(void)
  516. {
  517. /* If btext is enabled, we might have a BAT setup for early display,
  518. * thus we do enable some very basic udbg output
  519. */
  520. udbg_putc = btext_drawchar;
  521. }