blob: 1fcf36dee6b534124291e46e50e514dd30242d84 [file] [log] [blame]
Jordan Crousef6145c32008-03-19 23:56:58 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
Ulf Jordanb4d4bac2008-08-11 20:34:28 +00005 * Copyright (C) 2008 Ulf Jordan <jordan@chalmers.se>
Jordan Crousef6145c32008-03-19 23:56:58 +00006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
Jordan Crousedb8c0ab2008-11-24 17:54:46 +000031#include <libpayload-config.h>
Jordan Crousef6145c32008-03-19 23:56:58 +000032#include <libpayload.h>
Jordan Crousef6145c32008-03-19 23:56:58 +000033
Gabe Black5ab20052012-08-28 16:38:34 -070034#define IOBASE lib_sysinfo.serial->baseaddr
Gabe Black1c117122013-01-18 18:04:44 -080035#define MEMBASE (phys_to_virt(IOBASE))
Jordan Crousef6145c32008-03-19 23:56:58 +000036
Kyösti Mälkki48e9eb82014-05-13 12:57:26 +030037static int serial_hardware_is_present = 0;
Gabe Black1c117122013-01-18 18:04:44 -080038static int serial_is_mem_mapped = 0;
Dave Frodin5056b6e2012-12-15 13:24:02 -070039
Gabe Black1c117122013-01-18 18:04:44 -080040static uint8_t serial_read_reg(int offset)
Stefan Reinauere75c3d82008-09-26 18:36:26 +000041{
Vadim Bendebury6cc5e522015-01-09 16:54:19 -080042 offset *= lib_sysinfo.serial->regwidth;
43
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070044#if IS_ENABLED(CONFIG_LP_IO_ADDRESS_SPACE)
Gabe Blackb7b57d92013-01-18 18:37:29 -080045 if (!serial_is_mem_mapped)
Gabe Black1c117122013-01-18 18:04:44 -080046 return inb(IOBASE + offset);
Gabe Blackb7b57d92013-01-18 18:37:29 -080047 else
48#endif
Patrick Georgid4adf582016-02-08 21:17:12 +010049 if (lib_sysinfo.serial->regwidth == 4)
50 return readl(MEMBASE + offset) & 0xff;
51 else
52 return readb(MEMBASE + offset);
Stefan Reinauere75c3d82008-09-26 18:36:26 +000053}
Jordan Crousef6145c32008-03-19 23:56:58 +000054
Gabe Black1c117122013-01-18 18:04:44 -080055static void serial_write_reg(uint8_t val, int offset)
56{
Vadim Bendebury6cc5e522015-01-09 16:54:19 -080057 offset *= lib_sysinfo.serial->regwidth;
58
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070059#if IS_ENABLED(CONFIG_LP_IO_ADDRESS_SPACE)
Gabe Blackb7b57d92013-01-18 18:37:29 -080060 if (!serial_is_mem_mapped)
Gabe Black1c117122013-01-18 18:04:44 -080061 outb(val, IOBASE + offset);
Gabe Blackb7b57d92013-01-18 18:37:29 -080062 else
63#endif
Patrick Georgid4adf582016-02-08 21:17:12 +010064 if (lib_sysinfo.serial->regwidth == 4)
65 writel(val & 0xff, MEMBASE + offset);
66 else
67 writeb(val, MEMBASE + offset);
Gabe Black1c117122013-01-18 18:04:44 -080068}
69
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070070#if IS_ENABLED(CONFIG_LP_SERIAL_SET_SPEED)
Gabe Black1c117122013-01-18 18:04:44 -080071static void serial_hardware_init(int speed, int word_bits,
72 int parity, int stop_bits)
Stefan Reinauer4e677312011-04-16 00:13:17 +000073{
74 unsigned char reg;
75
Nico Hubera7c609c2015-09-09 13:27:09 +020076#if !IS_ENABLED(CONFIG_LP_PL011_SERIAL_CONSOLE)
Stefan Reinauer4e677312011-04-16 00:13:17 +000077 /* Disable interrupts. */
Gabe Black1c117122013-01-18 18:04:44 -080078 serial_write_reg(0, 0x01);
Stefan Reinauer4e677312011-04-16 00:13:17 +000079
80 /* Assert RTS and DTR. */
Gabe Black1c117122013-01-18 18:04:44 -080081 serial_write_reg(3, 0x04);
Stefan Reinauer4e677312011-04-16 00:13:17 +000082
83 /* Set the divisor latch. */
Gabe Black1c117122013-01-18 18:04:44 -080084 reg = serial_read_reg(0x03);
85 serial_write_reg(reg | 0x80, 0x03);
Stefan Reinauer4e677312011-04-16 00:13:17 +000086
87 /* Write the divisor. */
Gabe Black1c117122013-01-18 18:04:44 -080088 uint16_t divisor = 115200 / speed;
89 serial_write_reg(divisor & 0xFF, 0x00);
90 serial_write_reg(divisor >> 8, 0x01);
Stefan Reinauer4e677312011-04-16 00:13:17 +000091
Anton Kochkov93a8b272012-09-26 22:31:04 +040092 /* Restore the previous value of the divisor.
93 * And set 8 bits per character */
Gabe Black1c117122013-01-18 18:04:44 -080094 serial_write_reg((reg & ~0x80) | 3, 0x03);
Nico Hubera7c609c2015-09-09 13:27:09 +020095#endif
Stefan Reinauer4e677312011-04-16 00:13:17 +000096}
97#endif
98
Patrick Georgi657a6dc2008-10-21 15:08:18 +000099static struct console_input_driver consin = {
Gabe Black1c117122013-01-18 18:04:44 -0800100 .havekey = &serial_havechar,
101 .getchar = &serial_getchar
Patrick Georgi657a6dc2008-10-21 15:08:18 +0000102};
103
104static struct console_output_driver consout = {
Gabe Black1c117122013-01-18 18:04:44 -0800105 .putchar = &serial_putchar
Patrick Georgi657a6dc2008-10-21 15:08:18 +0000106};
107
Jordan Crousef6145c32008-03-19 23:56:58 +0000108void serial_init(void)
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000109{
Gabe Black5ab20052012-08-28 16:38:34 -0700110 if (!lib_sysinfo.serial)
111 return;
Stefan Reinauer4e677312011-04-16 00:13:17 +0000112
Gabe Black1c117122013-01-18 18:04:44 -0800113 serial_is_mem_mapped =
114 (lib_sysinfo.serial->type == CB_SERIAL_TYPE_MEMORY_MAPPED);
115
Gabe Blackd8d4d112013-01-18 18:24:46 -0800116 if (!serial_is_mem_mapped) {
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700117#if IS_ENABLED(CONFIG_LP_IO_ADDRESS_SPACE)
Gabe Blackd8d4d112013-01-18 18:24:46 -0800118 if ((inb(IOBASE + 0x05) == 0xFF) &&
119 (inb(IOBASE + 0x06) == 0xFF)) {
Kyösti Mälkki48e9eb82014-05-13 12:57:26 +0300120 printf("IO space mapped serial not present.");
121 return;
Gabe Blackd8d4d112013-01-18 18:24:46 -0800122 }
123#else
124 printf("IO space mapped serial not supported.");
Gabe Black1c117122013-01-18 18:04:44 -0800125 return;
Gabe Blackd8d4d112013-01-18 18:24:46 -0800126#endif
Gabe Black1c117122013-01-18 18:04:44 -0800127 }
128
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700129#if IS_ENABLED(CONFIG_LP_SERIAL_SET_SPEED)
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700130 serial_hardware_init(CONFIG_LP_SERIAL_BAUD_RATE, 8, 0, 1);
Jordan Crousef6145c32008-03-19 23:56:58 +0000131#endif
Gabe Black9ed8a822013-12-03 21:25:35 -0800132}
133
134void serial_console_init(void)
135{
136 if (!lib_sysinfo.serial)
137 return;
138
139 serial_init();
140
Patrick Georgi657a6dc2008-10-21 15:08:18 +0000141 console_add_input_driver(&consin);
142 console_add_output_driver(&consout);
Kyösti Mälkki48e9eb82014-05-13 12:57:26 +0300143 serial_hardware_is_present = 1;
Jordan Crousef6145c32008-03-19 23:56:58 +0000144}
Uwe Hermann6a441bf2008-03-20 19:54:59 +0000145
Stefan Reinauer4e677312011-04-16 00:13:17 +0000146void serial_putchar(unsigned int c)
147{
Kyösti Mälkki48e9eb82014-05-13 12:57:26 +0300148 if (!serial_hardware_is_present)
149 return;
Nico Hubera7c609c2015-09-09 13:27:09 +0200150#if !IS_ENABLED(CONFIG_LP_PL011_SERIAL_CONSOLE)
Kyösti Mälkki48e9eb82014-05-13 12:57:26 +0300151 while ((serial_read_reg(0x05) & 0x20) == 0) ;
Nico Hubera7c609c2015-09-09 13:27:09 +0200152#endif
Gabe Black1c117122013-01-18 18:04:44 -0800153 serial_write_reg(c, 0x00);
Julius Werner2fe505b2014-04-17 20:00:20 -0700154 if (c == '\n')
155 serial_putchar('\r');
Stefan Reinauer4e677312011-04-16 00:13:17 +0000156}
157
158int serial_havechar(void)
159{
Gabe Black1c117122013-01-18 18:04:44 -0800160 if (!serial_hardware_is_present)
Gabe Black5ab20052012-08-28 16:38:34 -0700161 return 0;
Gabe Black1c117122013-01-18 18:04:44 -0800162 return serial_read_reg(0x05) & 0x01;
Stefan Reinauer4e677312011-04-16 00:13:17 +0000163}
164
Jordan Crousef6145c32008-03-19 23:56:58 +0000165int serial_getchar(void)
166{
Gabe Black1c117122013-01-18 18:04:44 -0800167 if (!serial_hardware_is_present)
Gabe Black5ab20052012-08-28 16:38:34 -0700168 return -1;
Gabe Black1c117122013-01-18 18:04:44 -0800169 while (!serial_havechar()) ;
170 return serial_read_reg(0x00);
Jordan Crousef6145c32008-03-19 23:56:58 +0000171}