Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/console.h>
0003 #include <linux/kernel.h>
0004 #include <linux/init.h>
0005 #include <linux/string.h>
0006 #include <linux/screen_info.h>
0007 #include <linux/usb/ch9.h>
0008 #include <linux/pci_regs.h>
0009 #include <linux/pci_ids.h>
0010 #include <linux/errno.h>
0011 #include <linux/pgtable.h>
0012 #include <asm/io.h>
0013 #include <asm/processor.h>
0014 #include <asm/fcntl.h>
0015 #include <asm/setup.h>
0016 #include <xen/hvc-console.h>
0017 #include <asm/pci-direct.h>
0018 #include <asm/fixmap.h>
0019 #include <linux/usb/ehci_def.h>
0020 #include <linux/usb/xhci-dbgp.h>
0021 #include <asm/pci_x86.h>
0022 
0023 /* Simple VGA output */
0024 #define VGABASE     (__ISA_IO_base + 0xb8000)
0025 
0026 static int max_ypos = 25, max_xpos = 80;
0027 static int current_ypos = 25, current_xpos;
0028 
0029 static void early_vga_write(struct console *con, const char *str, unsigned n)
0030 {
0031     char c;
0032     int  i, k, j;
0033 
0034     while ((c = *str++) != '\0' && n-- > 0) {
0035         if (current_ypos >= max_ypos) {
0036             /* scroll 1 line up */
0037             for (k = 1, j = 0; k < max_ypos; k++, j++) {
0038                 for (i = 0; i < max_xpos; i++) {
0039                     writew(readw(VGABASE+2*(max_xpos*k+i)),
0040                            VGABASE + 2*(max_xpos*j + i));
0041                 }
0042             }
0043             for (i = 0; i < max_xpos; i++)
0044                 writew(0x720, VGABASE + 2*(max_xpos*j + i));
0045             current_ypos = max_ypos-1;
0046         }
0047 #ifdef CONFIG_KGDB_KDB
0048         if (c == '\b') {
0049             if (current_xpos > 0)
0050                 current_xpos--;
0051         } else if (c == '\r') {
0052             current_xpos = 0;
0053         } else
0054 #endif
0055         if (c == '\n') {
0056             current_xpos = 0;
0057             current_ypos++;
0058         } else if (c != '\r')  {
0059             writew(((0x7 << 8) | (unsigned short) c),
0060                    VGABASE + 2*(max_xpos*current_ypos +
0061                         current_xpos++));
0062             if (current_xpos >= max_xpos) {
0063                 current_xpos = 0;
0064                 current_ypos++;
0065             }
0066         }
0067     }
0068 }
0069 
0070 static struct console early_vga_console = {
0071     .name =     "earlyvga",
0072     .write =    early_vga_write,
0073     .flags =    CON_PRINTBUFFER,
0074     .index =    -1,
0075 };
0076 
0077 /* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
0078 
0079 static unsigned long early_serial_base = 0x3f8;  /* ttyS0 */
0080 
0081 #define XMTRDY          0x20
0082 
0083 #define DLAB        0x80
0084 
0085 #define TXR             0       /*  Transmit register (WRITE) */
0086 #define RXR             0       /*  Receive register  (READ)  */
0087 #define IER             1       /*  Interrupt Enable          */
0088 #define IIR             2       /*  Interrupt ID              */
0089 #define FCR             2       /*  FIFO control              */
0090 #define LCR             3       /*  Line control              */
0091 #define MCR             4       /*  Modem control             */
0092 #define LSR             5       /*  Line Status               */
0093 #define MSR             6       /*  Modem Status              */
0094 #define DLL             0       /*  Divisor Latch Low         */
0095 #define DLH             1       /*  Divisor latch High        */
0096 
0097 static unsigned int io_serial_in(unsigned long addr, int offset)
0098 {
0099     return inb(addr + offset);
0100 }
0101 
0102 static void io_serial_out(unsigned long addr, int offset, int value)
0103 {
0104     outb(value, addr + offset);
0105 }
0106 
0107 static unsigned int (*serial_in)(unsigned long addr, int offset) = io_serial_in;
0108 static void (*serial_out)(unsigned long addr, int offset, int value) = io_serial_out;
0109 
0110 static int early_serial_putc(unsigned char ch)
0111 {
0112     unsigned timeout = 0xffff;
0113 
0114     while ((serial_in(early_serial_base, LSR) & XMTRDY) == 0 && --timeout)
0115         cpu_relax();
0116     serial_out(early_serial_base, TXR, ch);
0117     return timeout ? 0 : -1;
0118 }
0119 
0120 static void early_serial_write(struct console *con, const char *s, unsigned n)
0121 {
0122     while (*s && n-- > 0) {
0123         if (*s == '\n')
0124             early_serial_putc('\r');
0125         early_serial_putc(*s);
0126         s++;
0127     }
0128 }
0129 
0130 static __init void early_serial_hw_init(unsigned divisor)
0131 {
0132     unsigned char c;
0133 
0134     serial_out(early_serial_base, LCR, 0x3);    /* 8n1 */
0135     serial_out(early_serial_base, IER, 0);  /* no interrupt */
0136     serial_out(early_serial_base, FCR, 0);  /* no fifo */
0137     serial_out(early_serial_base, MCR, 0x3);    /* DTR + RTS */
0138 
0139     c = serial_in(early_serial_base, LCR);
0140     serial_out(early_serial_base, LCR, c | DLAB);
0141     serial_out(early_serial_base, DLL, divisor & 0xff);
0142     serial_out(early_serial_base, DLH, (divisor >> 8) & 0xff);
0143     serial_out(early_serial_base, LCR, c & ~DLAB);
0144 }
0145 
0146 #define DEFAULT_BAUD 9600
0147 
0148 static __init void early_serial_init(char *s)
0149 {
0150     unsigned divisor;
0151     unsigned long baud = DEFAULT_BAUD;
0152     char *e;
0153 
0154     if (*s == ',')
0155         ++s;
0156 
0157     if (*s) {
0158         unsigned port;
0159         if (!strncmp(s, "0x", 2)) {
0160             early_serial_base = simple_strtoul(s, &e, 16);
0161         } else {
0162             static const int __initconst bases[] = { 0x3f8, 0x2f8 };
0163 
0164             if (!strncmp(s, "ttyS", 4))
0165                 s += 4;
0166             port = simple_strtoul(s, &e, 10);
0167             if (port > 1 || s == e)
0168                 port = 0;
0169             early_serial_base = bases[port];
0170         }
0171         s += strcspn(s, ",");
0172         if (*s == ',')
0173             s++;
0174     }
0175 
0176     if (*s) {
0177         baud = simple_strtoull(s, &e, 0);
0178 
0179         if (baud == 0 || s == e)
0180             baud = DEFAULT_BAUD;
0181     }
0182 
0183     /* Convert from baud to divisor value */
0184     divisor = 115200 / baud;
0185 
0186     /* These will always be IO based ports */
0187     serial_in = io_serial_in;
0188     serial_out = io_serial_out;
0189 
0190     /* Set up the HW */
0191     early_serial_hw_init(divisor);
0192 }
0193 
0194 #ifdef CONFIG_PCI
0195 static void mem32_serial_out(unsigned long addr, int offset, int value)
0196 {
0197     u32 __iomem *vaddr = (u32 __iomem *)addr;
0198     /* shift implied by pointer type */
0199     writel(value, vaddr + offset);
0200 }
0201 
0202 static unsigned int mem32_serial_in(unsigned long addr, int offset)
0203 {
0204     u32 __iomem *vaddr = (u32 __iomem *)addr;
0205     /* shift implied by pointer type */
0206     return readl(vaddr + offset);
0207 }
0208 
0209 /*
0210  * early_pci_serial_init()
0211  *
0212  * This function is invoked when the early_printk param starts with "pciserial"
0213  * The rest of the param should be "[force],B:D.F,baud", where B, D & F describe
0214  * the location of a PCI device that must be a UART device. "force" is optional
0215  * and overrides the use of an UART device with a wrong PCI class code.
0216  */
0217 static __init void early_pci_serial_init(char *s)
0218 {
0219     unsigned divisor;
0220     unsigned long baud = DEFAULT_BAUD;
0221     u8 bus, slot, func;
0222     u32 classcode, bar0;
0223     u16 cmdreg;
0224     char *e;
0225     int force = 0;
0226 
0227     if (*s == ',')
0228         ++s;
0229 
0230     if (*s == 0)
0231         return;
0232 
0233     /* Force the use of an UART device with wrong class code */
0234     if (!strncmp(s, "force,", 6)) {
0235         force = 1;
0236         s += 6;
0237     }
0238 
0239     /*
0240      * Part the param to get the BDF values
0241      */
0242     bus = (u8)simple_strtoul(s, &e, 16);
0243     s = e;
0244     if (*s != ':')
0245         return;
0246     ++s;
0247     slot = (u8)simple_strtoul(s, &e, 16);
0248     s = e;
0249     if (*s != '.')
0250         return;
0251     ++s;
0252     func = (u8)simple_strtoul(s, &e, 16);
0253     s = e;
0254 
0255     /* A baud might be following */
0256     if (*s == ',')
0257         s++;
0258 
0259     /*
0260      * Find the device from the BDF
0261      */
0262     cmdreg = read_pci_config(bus, slot, func, PCI_COMMAND);
0263     classcode = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
0264     bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
0265 
0266     /*
0267      * Verify it is a UART type device
0268      */
0269     if (((classcode >> 16 != PCI_CLASS_COMMUNICATION_MODEM) &&
0270          (classcode >> 16 != PCI_CLASS_COMMUNICATION_SERIAL)) ||
0271        (((classcode >> 8) & 0xff) != 0x02)) /* 16550 I/F at BAR0 */ {
0272         if (!force)
0273             return;
0274     }
0275 
0276     /*
0277      * Determine if it is IO or memory mapped
0278      */
0279     if (bar0 & 0x01) {
0280         /* it is IO mapped */
0281         serial_in = io_serial_in;
0282         serial_out = io_serial_out;
0283         early_serial_base = bar0&0xfffffffc;
0284         write_pci_config(bus, slot, func, PCI_COMMAND,
0285                         cmdreg|PCI_COMMAND_IO);
0286     } else {
0287         /* It is memory mapped - assume 32-bit alignment */
0288         serial_in = mem32_serial_in;
0289         serial_out = mem32_serial_out;
0290         /* WARNING! assuming the address is always in the first 4G */
0291         early_serial_base =
0292             (unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10);
0293         write_pci_config(bus, slot, func, PCI_COMMAND,
0294                         cmdreg|PCI_COMMAND_MEMORY);
0295     }
0296 
0297     /*
0298      * Initialize the hardware
0299      */
0300     if (*s) {
0301         if (strcmp(s, "nocfg") == 0)
0302             /* Sometimes, we want to leave the UART alone
0303              * and assume the BIOS has set it up correctly.
0304              * "nocfg" tells us this is the case, and we
0305              * should do no more setup.
0306              */
0307             return;
0308         if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
0309             baud = DEFAULT_BAUD;
0310     }
0311 
0312     /* Convert from baud to divisor value */
0313     divisor = 115200 / baud;
0314 
0315     /* Set up the HW */
0316     early_serial_hw_init(divisor);
0317 }
0318 #endif
0319 
0320 static struct console early_serial_console = {
0321     .name =     "earlyser",
0322     .write =    early_serial_write,
0323     .flags =    CON_PRINTBUFFER,
0324     .index =    -1,
0325 };
0326 
0327 static void early_console_register(struct console *con, int keep_early)
0328 {
0329     if (con->index != -1) {
0330         printk(KERN_CRIT "ERROR: earlyprintk= %s already used\n",
0331                con->name);
0332         return;
0333     }
0334     early_console = con;
0335     if (keep_early)
0336         early_console->flags &= ~CON_BOOT;
0337     else
0338         early_console->flags |= CON_BOOT;
0339     register_console(early_console);
0340 }
0341 
0342 static int __init setup_early_printk(char *buf)
0343 {
0344     int keep;
0345 
0346     if (!buf)
0347         return 0;
0348 
0349     if (early_console)
0350         return 0;
0351 
0352     keep = (strstr(buf, "keep") != NULL);
0353 
0354     while (*buf != '\0') {
0355         if (!strncmp(buf, "serial", 6)) {
0356             buf += 6;
0357             early_serial_init(buf);
0358             early_console_register(&early_serial_console, keep);
0359             if (!strncmp(buf, ",ttyS", 5))
0360                 buf += 5;
0361         }
0362         if (!strncmp(buf, "ttyS", 4)) {
0363             early_serial_init(buf + 4);
0364             early_console_register(&early_serial_console, keep);
0365         }
0366 #ifdef CONFIG_PCI
0367         if (!strncmp(buf, "pciserial", 9)) {
0368             early_pci_serial_init(buf + 9);
0369             early_console_register(&early_serial_console, keep);
0370             buf += 9; /* Keep from match the above "serial" */
0371         }
0372 #endif
0373         if (!strncmp(buf, "vga", 3) &&
0374             boot_params.screen_info.orig_video_isVGA == 1) {
0375             max_xpos = boot_params.screen_info.orig_video_cols;
0376             max_ypos = boot_params.screen_info.orig_video_lines;
0377             current_ypos = boot_params.screen_info.orig_y;
0378             early_console_register(&early_vga_console, keep);
0379         }
0380 #ifdef CONFIG_EARLY_PRINTK_DBGP
0381         if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4))
0382             early_console_register(&early_dbgp_console, keep);
0383 #endif
0384 #ifdef CONFIG_HVC_XEN
0385         if (!strncmp(buf, "xen", 3))
0386             early_console_register(&xenboot_console, keep);
0387 #endif
0388 #ifdef CONFIG_EARLY_PRINTK_USB_XDBC
0389         if (!strncmp(buf, "xdbc", 4))
0390             early_xdbc_parse_parameter(buf + 4, keep);
0391 #endif
0392 
0393         buf++;
0394     }
0395     return 0;
0396 }
0397 
0398 early_param("earlyprintk", setup_early_printk);