xref: /rk3399_rockchip-uboot/lib/tiny-printf.c (revision 59d07ee08e858bf2c121d0cdc6c8ddd3b26ee5b1)
17d9cde10SStefan Roese /*
27d9cde10SStefan Roese  * Tiny printf version for SPL
37d9cde10SStefan Roese  *
47d9cde10SStefan Roese  * Copied from:
57d9cde10SStefan Roese  * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
67d9cde10SStefan Roese  *
77d9cde10SStefan Roese  * Copyright (C) 2004,2008  Kustaa Nyholm
87d9cde10SStefan Roese  *
97d9cde10SStefan Roese  * SPDX-License-Identifier:	LGPL-2.1+
107d9cde10SStefan Roese  */
117d9cde10SStefan Roese 
127d9cde10SStefan Roese #include <common.h>
137d9cde10SStefan Roese #include <stdarg.h>
147d9cde10SStefan Roese #include <serial.h>
157d9cde10SStefan Roese 
16*59d07ee0SAndre Przywara /*
17*59d07ee0SAndre Przywara  * This code in here may execute before the DRAM is initialised, so
18*59d07ee0SAndre Przywara  * we should make sure that it doesn't touch BSS, which some boards
19*59d07ee0SAndre Przywara  * put in DRAM.
20*59d07ee0SAndre Przywara  */
21*59d07ee0SAndre Przywara static char *bf __attribute__ ((section(".data")));
22*59d07ee0SAndre Przywara static char zs __attribute__ ((section(".data")));
237d9cde10SStefan Roese 
245c411d88SSimon Glass /* Current position in sprintf() output string */
25*59d07ee0SAndre Przywara static char *outstr __attribute__ ((section(".data")));
265c411d88SSimon Glass 
277d9cde10SStefan Roese static void out(char c)
287d9cde10SStefan Roese {
297d9cde10SStefan Roese 	*bf++ = c;
307d9cde10SStefan Roese }
317d9cde10SStefan Roese 
327d9cde10SStefan Roese static void out_dgt(char dgt)
337d9cde10SStefan Roese {
34a5ecdd08SStefan Roese 	out(dgt + (dgt < 10 ? '0' : 'a' - 10));
357d9cde10SStefan Roese 	zs = 1;
367d9cde10SStefan Roese }
377d9cde10SStefan Roese 
38a5ecdd08SStefan Roese static void div_out(unsigned int *num, unsigned int div)
397d9cde10SStefan Roese {
407d9cde10SStefan Roese 	unsigned char dgt = 0;
417d9cde10SStefan Roese 
42a5ecdd08SStefan Roese 	while (*num >= div) {
43a5ecdd08SStefan Roese 		*num -= div;
447d9cde10SStefan Roese 		dgt++;
457d9cde10SStefan Roese 	}
467d9cde10SStefan Roese 
477d9cde10SStefan Roese 	if (zs || dgt > 0)
487d9cde10SStefan Roese 		out_dgt(dgt);
497d9cde10SStefan Roese }
507d9cde10SStefan Roese 
515c411d88SSimon Glass int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
527d9cde10SStefan Roese {
537d9cde10SStefan Roese 	char ch;
547d9cde10SStefan Roese 	char *p;
55a5ecdd08SStefan Roese 	unsigned int num;
56a5ecdd08SStefan Roese 	char buf[12];
57a5ecdd08SStefan Roese 	unsigned int div;
587d9cde10SStefan Roese 
597d9cde10SStefan Roese 	while ((ch = *(fmt++))) {
607d9cde10SStefan Roese 		if (ch != '%') {
617d9cde10SStefan Roese 			putc(ch);
627d9cde10SStefan Roese 		} else {
631fb67608SSimon Glass 			bool lz = false;
641fb67608SSimon Glass 			int width = 0;
657d9cde10SStefan Roese 
667d9cde10SStefan Roese 			ch = *(fmt++);
677d9cde10SStefan Roese 			if (ch == '0') {
687d9cde10SStefan Roese 				ch = *(fmt++);
697d9cde10SStefan Roese 				lz = 1;
707d9cde10SStefan Roese 			}
717d9cde10SStefan Roese 
727d9cde10SStefan Roese 			if (ch >= '0' && ch <= '9') {
731fb67608SSimon Glass 				width = 0;
747d9cde10SStefan Roese 				while (ch >= '0' && ch <= '9') {
751fb67608SSimon Glass 					width = (width * 10) + ch - '0';
767d9cde10SStefan Roese 					ch = *fmt++;
777d9cde10SStefan Roese 				}
787d9cde10SStefan Roese 			}
797d9cde10SStefan Roese 			bf = buf;
807d9cde10SStefan Roese 			p = bf;
817d9cde10SStefan Roese 			zs = 0;
827d9cde10SStefan Roese 
837d9cde10SStefan Roese 			switch (ch) {
841fb67608SSimon Glass 			case '\0':
857d9cde10SStefan Roese 				goto abort;
867d9cde10SStefan Roese 			case 'u':
877d9cde10SStefan Roese 			case 'd':
887d9cde10SStefan Roese 				num = va_arg(va, unsigned int);
897d9cde10SStefan Roese 				if (ch == 'd' && (int)num < 0) {
907d9cde10SStefan Roese 					num = -(int)num;
917d9cde10SStefan Roese 					out('-');
927d9cde10SStefan Roese 				}
9374b1320aSSimon Glass 				if (!num) {
9474b1320aSSimon Glass 					out_dgt(0);
9574b1320aSSimon Glass 				} else {
96a5ecdd08SStefan Roese 					for (div = 1000000000; div; div /= 10)
97a5ecdd08SStefan Roese 						div_out(&num, div);
9874b1320aSSimon Glass 				}
997d9cde10SStefan Roese 				break;
1007d9cde10SStefan Roese 			case 'x':
1017d9cde10SStefan Roese 				num = va_arg(va, unsigned int);
10274b1320aSSimon Glass 				if (!num) {
10374b1320aSSimon Glass 					out_dgt(0);
10474b1320aSSimon Glass 				} else {
105a5ecdd08SStefan Roese 					for (div = 0x10000000; div; div /= 0x10)
106a5ecdd08SStefan Roese 						div_out(&num, div);
10774b1320aSSimon Glass 				}
1087d9cde10SStefan Roese 				break;
1097d9cde10SStefan Roese 			case 'c':
1107d9cde10SStefan Roese 				out((char)(va_arg(va, int)));
1117d9cde10SStefan Roese 				break;
1127d9cde10SStefan Roese 			case 's':
1137d9cde10SStefan Roese 				p = va_arg(va, char*);
1147d9cde10SStefan Roese 				break;
1157d9cde10SStefan Roese 			case '%':
1167d9cde10SStefan Roese 				out('%');
1177d9cde10SStefan Roese 			default:
1187d9cde10SStefan Roese 				break;
1197d9cde10SStefan Roese 			}
1207d9cde10SStefan Roese 
1217d9cde10SStefan Roese 			*bf = 0;
1227d9cde10SStefan Roese 			bf = p;
1231fb67608SSimon Glass 			while (*bf++ && width > 0)
1241fb67608SSimon Glass 				width--;
1251fb67608SSimon Glass 			while (width-- > 0)
1267d9cde10SStefan Roese 				putc(lz ? '0' : ' ');
1278e31681cSSimon Glass 			if (p) {
1287d9cde10SStefan Roese 				while ((ch = *p++))
1297d9cde10SStefan Roese 					putc(ch);
1307d9cde10SStefan Roese 			}
1317d9cde10SStefan Roese 		}
1328e31681cSSimon Glass 	}
1337d9cde10SStefan Roese 
1347d9cde10SStefan Roese abort:
1357d9cde10SStefan Roese 	return 0;
1367d9cde10SStefan Roese }
137962a43ccSSjoerd Simons 
138da70b4d1SHans de Goede int vprintf(const char *fmt, va_list va)
139da70b4d1SHans de Goede {
140da70b4d1SHans de Goede 	return _vprintf(fmt, va, putc);
141da70b4d1SHans de Goede }
142da70b4d1SHans de Goede 
143962a43ccSSjoerd Simons int printf(const char *fmt, ...)
144962a43ccSSjoerd Simons {
145962a43ccSSjoerd Simons 	va_list va;
146962a43ccSSjoerd Simons 	int ret;
147962a43ccSSjoerd Simons 
148962a43ccSSjoerd Simons 	va_start(va, fmt);
1495c411d88SSimon Glass 	ret = _vprintf(fmt, va, putc);
150962a43ccSSjoerd Simons 	va_end(va);
151962a43ccSSjoerd Simons 
152962a43ccSSjoerd Simons 	return ret;
153962a43ccSSjoerd Simons }
1545c411d88SSimon Glass 
1555c411d88SSimon Glass static void putc_outstr(char ch)
1565c411d88SSimon Glass {
1575c411d88SSimon Glass 	*outstr++ = ch;
1585c411d88SSimon Glass }
1595c411d88SSimon Glass 
160abeb272dSMarek Vasut int sprintf(char *buf, const char *fmt, ...)
1615c411d88SSimon Glass {
1625c411d88SSimon Glass 	va_list va;
1635c411d88SSimon Glass 	int ret;
1645c411d88SSimon Glass 
1655c411d88SSimon Glass 	va_start(va, fmt);
1665c411d88SSimon Glass 	outstr = buf;
1675c411d88SSimon Glass 	ret = _vprintf(fmt, va, putc_outstr);
1685c411d88SSimon Glass 	va_end(va);
1695c411d88SSimon Glass 	*outstr = '\0';
1705c411d88SSimon Glass 
1715c411d88SSimon Glass 	return ret;
1725c411d88SSimon Glass }
173abeb272dSMarek Vasut 
174abeb272dSMarek Vasut /* Note that size is ignored */
175abeb272dSMarek Vasut int snprintf(char *buf, size_t size, const char *fmt, ...)
176abeb272dSMarek Vasut {
177abeb272dSMarek Vasut 	va_list va;
178abeb272dSMarek Vasut 	int ret;
179abeb272dSMarek Vasut 
180abeb272dSMarek Vasut 	va_start(va, fmt);
1813191d840SSimon Glass 	outstr = buf;
1823191d840SSimon Glass 	ret = _vprintf(fmt, va, putc_outstr);
183abeb272dSMarek Vasut 	va_end(va);
1843191d840SSimon Glass 	*outstr = '\0';
185abeb272dSMarek Vasut 
186abeb272dSMarek Vasut 	return ret;
187abeb272dSMarek Vasut }
188