"Das U-Boot" Source Tree
at master 143 lines 3.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * UART support for U-Boot when launched from Coreboot 4 * 5 * Copyright 2019 Google LLC 6 */ 7 8#define LOG_CATGEGORY UCLASS_SERIAL 9 10#include <dm.h> 11#include <log.h> 12#include <ns16550.h> 13#include <serial.h> 14#include <acpi/acpi_table.h> 15#include <asm/cb_sysinfo.h> 16 17DECLARE_GLOBAL_DATA_PTR; 18 19static int read_dbg2(struct ns16550_plat *plat) 20{ 21 struct acpi_table_header *tab; 22 struct acpi_dbg2_header *hdr; 23 struct acpi_dbg2_device *dbg; 24 struct acpi_gen_regaddr *addr; 25 u32 *addr_size; 26 27 log_debug("Looking for DBG2 in ACPI tables\n"); 28 if (!gd->acpi_start) { 29 log_debug("No ACPI tables\n"); 30 return -ENOENT; 31 } 32 33 tab = acpi_find_table("DBG2"); 34 if (!tab) { 35 log_debug("No DBG2 table\n"); 36 return -ENOENT; 37 } 38 hdr = container_of(tab, struct acpi_dbg2_header, header); 39 40 /* We only use the first device, but check that there is at least one */ 41 if (!hdr->devices_count) { 42 log_debug("No devices\n"); 43 return -ENOENT; 44 } 45 if (hdr->devices_offset >= tab->length) { 46 log_debug("Invalid offset\n"); 47 return -EINVAL; 48 } 49 dbg = (void *)hdr + hdr->devices_offset; 50 if (dbg->revision) { 51 log_debug("Invalid revision %d\n", dbg->revision); 52 return -EINVAL; 53 } 54 if (!dbg->address_count) { 55 log_debug("No addresses\n"); 56 return -EINVAL; 57 } 58 if (dbg->port_type != ACPI_DBG2_SERIAL_PORT) { 59 log_debug("Not a serial port\n"); 60 return -EPROTOTYPE; 61 } 62 if (dbg->port_subtype != ACPI_DBG2_16550_COMPATIBLE) { 63 log_debug("Incompatible serial port\n"); 64 return -EPROTOTYPE; 65 } 66 if (dbg->base_address_offset >= dbg->length || 67 dbg->address_size_offset >= dbg->length) { 68 log_debug("Invalid base address/size offsets %d, %d\n", 69 dbg->base_address_offset, dbg->address_size_offset); 70 return -EINVAL; 71 } 72 addr_size = (void *)dbg + dbg->address_size_offset; 73 if (!*addr_size) { 74 log_debug("Zero address size\n"); 75 return -EINVAL; 76 } 77 addr = (void *)dbg + dbg->base_address_offset; 78 if (addr->space_id != ACPI_ADDRESS_SPACE_MEMORY) { 79 log_debug("Incompatible space %d\n", addr->space_id); 80 return -EPROTOTYPE; 81 } 82 83 plat->base = addr->addrl; 84 85 /* ACPI_ACCESS_SIZE_DWORD_ACCESS is 3; we want 2 */ 86 plat->reg_shift = addr->access_size - 1; 87 plat->reg_width = 4; /* coreboot sets bit_width to 0 */ 88 plat->clock = 1843200; 89 plat->fcr = UART_FCR_DEFVAL; 90 plat->flags = 0; 91 log_debug("Collected UART from ACPI DBG2 table\n"); 92 93 return 0; 94} 95 96static int coreboot_of_to_plat(struct udevice *dev) 97{ 98 struct ns16550_plat *plat = dev_get_plat(dev); 99 struct cb_serial *cb_info = lib_sysinfo.serial; 100 int ret = -ENOENT; 101 102 if (cb_info) { 103 plat->base = cb_info->baseaddr; 104 plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0; 105 plat->reg_width = cb_info->regwidth; 106 plat->clock = cb_info->input_hertz; 107 plat->fcr = UART_FCR_DEFVAL; 108 plat->flags = 0; 109 if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED) 110 plat->flags |= NS16550_FLAG_IO; 111 ret = 0; 112 } else if (IS_ENABLED(CONFIG_COREBOOT_SERIAL_FROM_DBG2)) { 113 ret = read_dbg2(plat); 114 } 115 116 if (ret) { 117 /* 118 * Returning an error will cause U-Boot to complain that 119 * there is no UART, which may panic. So stay silent and 120 * pray that the video console will work. 121 */ 122 log_debug("Cannot detect UART\n"); 123 } 124 125 return 0; 126} 127 128static const struct udevice_id coreboot_serial_ids[] = { 129 { .compatible = "coreboot-serial" }, 130 { }, 131}; 132 133U_BOOT_DRIVER(coreboot_uart) = { 134 .name = "coreboot_uart", 135 .id = UCLASS_SERIAL, 136 .of_match = coreboot_serial_ids, 137 .priv_auto = sizeof(struct ns16550), 138 .plat_auto = sizeof(struct ns16550_plat), 139 .of_to_plat = coreboot_of_to_plat, 140 .probe = ns16550_serial_probe, 141 .ops = &ns16550_serial_ops, 142 .flags = DM_FLAG_PRE_RELOC, 143};