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