btext.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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/console.h>
  11. #include <linux/font.h>
  12. #include <asm/btext.h>
  13. #include <asm/oplib.h>
  14. #include <asm/io.h>
  15. #define NO_SCROLL
  16. #ifndef NO_SCROLL
  17. static void scrollscreen(void);
  18. #endif
  19. static void draw_byte(unsigned char c, long locX, long locY);
  20. static void draw_byte_32(const unsigned char *bits, unsigned int *base, int rb);
  21. static void draw_byte_16(const unsigned char *bits, unsigned int *base, int rb);
  22. static void draw_byte_8(const unsigned char *bits, unsigned int *base, int rb);
  23. #define __force_data __section(".data")
  24. static int g_loc_X __force_data;
  25. static int g_loc_Y __force_data;
  26. static int g_max_loc_X __force_data;
  27. static int g_max_loc_Y __force_data;
  28. static int dispDeviceRowBytes __force_data;
  29. static int dispDeviceDepth __force_data;
  30. static int dispDeviceRect[4] __force_data;
  31. static unsigned char *dispDeviceBase __force_data;
  32. static int __init btext_initialize(phandle node)
  33. {
  34. unsigned int width, height, depth, pitch;
  35. unsigned long address = 0;
  36. u32 prop;
  37. if (prom_getproperty(node, "width", (char *)&width, 4) < 0)
  38. return -EINVAL;
  39. if (prom_getproperty(node, "height", (char *)&height, 4) < 0)
  40. return -EINVAL;
  41. if (prom_getproperty(node, "depth", (char *)&depth, 4) < 0)
  42. return -EINVAL;
  43. pitch = width * ((depth + 7) / 8);
  44. if (prom_getproperty(node, "linebytes", (char *)&prop, 4) >= 0 &&
  45. prop != 0xffffffffu)
  46. pitch = prop;
  47. if (pitch == 1)
  48. pitch = 0x1000;
  49. if (prom_getproperty(node, "address", (char *)&prop, 4) >= 0)
  50. address = prop;
  51. /* FIXME: Add support for PCI reg properties. Right now, only
  52. * reliable on macs
  53. */
  54. if (address == 0)
  55. return -EINVAL;
  56. g_loc_X = 0;
  57. g_loc_Y = 0;
  58. g_max_loc_X = width / 8;
  59. g_max_loc_Y = height / 16;
  60. dispDeviceBase = (unsigned char *)address;
  61. dispDeviceRowBytes = pitch;
  62. dispDeviceDepth = depth == 15 ? 16 : depth;
  63. dispDeviceRect[0] = dispDeviceRect[1] = 0;
  64. dispDeviceRect[2] = width;
  65. dispDeviceRect[3] = height;
  66. return 0;
  67. }
  68. /* Calc the base address of a given point (x,y) */
  69. static unsigned char * calc_base(int x, int y)
  70. {
  71. unsigned char *base = dispDeviceBase;
  72. base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
  73. base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
  74. return base;
  75. }
  76. static void btext_clearscreen(void)
  77. {
  78. unsigned int *base = (unsigned int *)calc_base(0, 0);
  79. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  80. (dispDeviceDepth >> 3)) >> 2;
  81. int i,j;
  82. for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
  83. {
  84. unsigned int *ptr = base;
  85. for(j=width; j; --j)
  86. *(ptr++) = 0;
  87. base += (dispDeviceRowBytes >> 2);
  88. }
  89. }
  90. #ifndef NO_SCROLL
  91. static void scrollscreen(void)
  92. {
  93. unsigned int *src = (unsigned int *)calc_base(0,16);
  94. unsigned int *dst = (unsigned int *)calc_base(0,0);
  95. unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
  96. (dispDeviceDepth >> 3)) >> 2;
  97. int i,j;
  98. for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
  99. {
  100. unsigned int *src_ptr = src;
  101. unsigned int *dst_ptr = dst;
  102. for(j=width; j; --j)
  103. *(dst_ptr++) = *(src_ptr++);
  104. src += (dispDeviceRowBytes >> 2);
  105. dst += (dispDeviceRowBytes >> 2);
  106. }
  107. for (i=0; i<16; i++)
  108. {
  109. unsigned int *dst_ptr = dst;
  110. for(j=width; j; --j)
  111. *(dst_ptr++) = 0;
  112. dst += (dispDeviceRowBytes >> 2);
  113. }
  114. }
  115. #endif /* ndef NO_SCROLL */
  116. static void btext_drawchar(char c)
  117. {
  118. int cline = 0;
  119. #ifdef NO_SCROLL
  120. int x;
  121. #endif
  122. switch (c) {
  123. case '\b':
  124. if (g_loc_X > 0)
  125. --g_loc_X;
  126. break;
  127. case '\t':
  128. g_loc_X = (g_loc_X & -8) + 8;
  129. break;
  130. case '\r':
  131. g_loc_X = 0;
  132. break;
  133. case '\n':
  134. g_loc_X = 0;
  135. g_loc_Y++;
  136. cline = 1;
  137. break;
  138. default:
  139. draw_byte(c, g_loc_X++, g_loc_Y);
  140. }
  141. if (g_loc_X >= g_max_loc_X) {
  142. g_loc_X = 0;
  143. g_loc_Y++;
  144. cline = 1;
  145. }
  146. #ifndef NO_SCROLL
  147. while (g_loc_Y >= g_max_loc_Y) {
  148. scrollscreen();
  149. g_loc_Y--;
  150. }
  151. #else
  152. /* wrap around from bottom to top of screen so we don't
  153. waste time scrolling each line. -- paulus. */
  154. if (g_loc_Y >= g_max_loc_Y)
  155. g_loc_Y = 0;
  156. if (cline) {
  157. for (x = 0; x < g_max_loc_X; ++x)
  158. draw_byte(' ', x, g_loc_Y);
  159. }
  160. #endif
  161. }
  162. static void btext_drawtext(const char *c, unsigned int len)
  163. {
  164. while (len--)
  165. btext_drawchar(*c++);
  166. }
  167. static void draw_byte(unsigned char c, long locX, long locY)
  168. {
  169. unsigned char *base = calc_base(locX << 3, locY << 4);
  170. unsigned int font_index = c * 16;
  171. const unsigned char *font = font_sun_8x16.data + font_index;
  172. int rb = dispDeviceRowBytes;
  173. switch(dispDeviceDepth) {
  174. case 24:
  175. case 32:
  176. draw_byte_32(font, (unsigned int *)base, rb);
  177. break;
  178. case 15:
  179. case 16:
  180. draw_byte_16(font, (unsigned int *)base, rb);
  181. break;
  182. case 8:
  183. draw_byte_8(font, (unsigned int *)base, rb);
  184. break;
  185. }
  186. }
  187. static unsigned int expand_bits_8[16] = {
  188. 0x00000000,
  189. 0x000000ff,
  190. 0x0000ff00,
  191. 0x0000ffff,
  192. 0x00ff0000,
  193. 0x00ff00ff,
  194. 0x00ffff00,
  195. 0x00ffffff,
  196. 0xff000000,
  197. 0xff0000ff,
  198. 0xff00ff00,
  199. 0xff00ffff,
  200. 0xffff0000,
  201. 0xffff00ff,
  202. 0xffffff00,
  203. 0xffffffff
  204. };
  205. static unsigned int expand_bits_16[4] = {
  206. 0x00000000,
  207. 0x0000ffff,
  208. 0xffff0000,
  209. 0xffffffff
  210. };
  211. static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
  212. {
  213. int l, bits;
  214. int fg = 0xFFFFFFFFUL;
  215. int bg = 0x00000000UL;
  216. for (l = 0; l < 16; ++l)
  217. {
  218. bits = *font++;
  219. base[0] = (-(bits >> 7) & fg) ^ bg;
  220. base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
  221. base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
  222. base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
  223. base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
  224. base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
  225. base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
  226. base[7] = (-(bits & 1) & fg) ^ bg;
  227. base = (unsigned int *) ((char *)base + rb);
  228. }
  229. }
  230. static void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
  231. {
  232. int l, bits;
  233. int fg = 0xFFFFFFFFUL;
  234. int bg = 0x00000000UL;
  235. unsigned int *eb = (int *)expand_bits_16;
  236. for (l = 0; l < 16; ++l)
  237. {
  238. bits = *font++;
  239. base[0] = (eb[bits >> 6] & fg) ^ bg;
  240. base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
  241. base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
  242. base[3] = (eb[bits & 3] & fg) ^ bg;
  243. base = (unsigned int *) ((char *)base + rb);
  244. }
  245. }
  246. static void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
  247. {
  248. int l, bits;
  249. int fg = 0x0F0F0F0FUL;
  250. int bg = 0x00000000UL;
  251. unsigned int *eb = (int *)expand_bits_8;
  252. for (l = 0; l < 16; ++l)
  253. {
  254. bits = *font++;
  255. base[0] = (eb[bits >> 4] & fg) ^ bg;
  256. base[1] = (eb[bits & 0xf] & fg) ^ bg;
  257. base = (unsigned int *) ((char *)base + rb);
  258. }
  259. }
  260. static void btext_console_write(struct console *con, const char *s,
  261. unsigned int n)
  262. {
  263. btext_drawtext(s, n);
  264. }
  265. static struct console btext_console = {
  266. .name = "btext",
  267. .write = btext_console_write,
  268. .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
  269. .index = 0,
  270. };
  271. int __init btext_find_display(void)
  272. {
  273. phandle node;
  274. char type[32];
  275. int ret;
  276. node = prom_inst2pkg(prom_stdout);
  277. if (prom_getproperty(node, "device_type", type, 32) < 0)
  278. return -ENODEV;
  279. if (strcmp(type, "display"))
  280. return -ENODEV;
  281. ret = btext_initialize(node);
  282. if (!ret) {
  283. btext_clearscreen();
  284. register_console(&btext_console);
  285. }
  286. return ret;
  287. }