From c309365089283da1cb32c2a6eeaea9eb3f638f7c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:52 -0700 Subject: exynos: Allow tizen to be built without an LCD This file currently requires an LCD. Adjust it to work without one. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang --- lib/tizen/tizen.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/tizen/tizen.c b/lib/tizen/tizen.c index 814ed18329e..d207f77d0b3 100644 --- a/lib/tizen/tizen.c +++ b/lib/tizen/tizen.c @@ -12,6 +12,7 @@ #include "tizen_logo_16bpp.h" #include "tizen_logo_16bpp_gzip.h" +#ifdef CONFIG_LCD void get_tizen_logo_info(vidinfo_t *vid) { switch (vid->vl_bpix) { @@ -31,3 +32,4 @@ void get_tizen_logo_info(vidinfo_t *vid) break; } } +#endif -- cgit v1.2.3 From 1fb67608b309bd7f49842fbdfb1dc2b18a250965 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:52 -0600 Subject: tiny-printf: Tidy up a few nits - Rename 'w' to 'width' to make it more obvious what it is used for - Use bool and int types instead of char to avoid register-masking on 32-bit machines Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- lib/tiny-printf.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index a06abed4959..fbd5368c0b3 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -52,8 +52,8 @@ int vprintf(const char *fmt, va_list va) if (ch != '%') { putc(ch); } else { - char lz = 0; - char w = 0; + bool lz = false; + int width = 0; ch = *(fmt++); if (ch == '0') { @@ -62,9 +62,9 @@ int vprintf(const char *fmt, va_list va) } if (ch >= '0' && ch <= '9') { - w = 0; + width = 0; while (ch >= '0' && ch <= '9') { - w = (w * 10) + ch - '0'; + width = (width * 10) + ch - '0'; ch = *fmt++; } } @@ -73,7 +73,7 @@ int vprintf(const char *fmt, va_list va) zs = 0; switch (ch) { - case 0: + case '\0': goto abort; case 'u': case 'd': @@ -112,9 +112,9 @@ int vprintf(const char *fmt, va_list va) *bf = 0; bf = p; - while (*bf++ && w > 0) - w--; - while (w-- > 0) + while (*bf++ && width > 0) + width--; + while (width-- > 0) putc(lz ? '0' : ' '); if (p) { while ((ch = *p++)) -- cgit v1.2.3 From 5c411d88be8df5f6a8a1ea0c961f7c35ba82c064 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:53 -0600 Subject: tiny-printf: Support snprintf() Add a simple version of this function for SPL. It does not check the buffer size as this would add to the code size. Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- lib/tiny-printf.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index fbd5368c0b3..4b70263df7d 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -16,6 +16,9 @@ static char *bf; static char zs; +/* Current position in sprintf() output string */ +static char *outstr; + static void out(char c) { *bf++ = c; @@ -40,7 +43,7 @@ static void div_out(unsigned int *num, unsigned int div) out_dgt(dgt); } -int vprintf(const char *fmt, va_list va) +int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) { char ch; char *p; @@ -133,8 +136,28 @@ int printf(const char *fmt, ...) int ret; va_start(va, fmt); - ret = vprintf(fmt, va); + ret = _vprintf(fmt, va, putc); + va_end(va); + + return ret; +} + +static void putc_outstr(char ch) +{ + *outstr++ = ch; +} + +/* Note that size is ignored */ +int snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list va; + int ret; + + va_start(va, fmt); + outstr = buf; + ret = _vprintf(fmt, va, putc_outstr); va_end(va); + *outstr = '\0'; return ret; } -- cgit v1.2.3 From 0efe1bcf5c2ce89d7c2467550e2823d7f95733e0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 6 May 2016 21:01:01 +0200 Subject: efi_loader: Add network access support We can now successfully boot EFI applications from disk, but users may want to also run them from a PXE setup. This patch implements rudimentary network support, allowing a payload to send and receive network packets. With this patch, I was able to successfully run grub2 with network access inside of QEMU's -M xlnx-ep108. Signed-off-by: Alexander Graf --- lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_net.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 lib/efi_loader/efi_net.c (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 83e31f6d1f6..2a3849e31b9 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -11,3 +11,4 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o +obj-$(CONFIG_NET) += efi_net.o diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c new file mode 100644 index 00000000000..dd3b48570d8 --- /dev/null +++ b/lib/efi_loader/efi_net.c @@ -0,0 +1,291 @@ +/* + * EFI application network access support + * + * Copyright (c) 2016 Alexander Graf + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID; +static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID; +static struct efi_pxe_packet *dhcp_ack; +static bool new_rx_packet; +static void *new_tx_packet; + +struct efi_net_obj { + /* Generic EFI object parent class data */ + struct efi_object parent; + /* EFI Interface callback struct for network */ + struct efi_simple_network net; + struct efi_simple_network_mode net_mode; + /* Device path to the network adapter */ + struct efi_device_path_file_path dp[2]; + /* PXE struct to transmit dhcp data */ + struct efi_pxe pxe; + struct efi_pxe_mode pxe_mode; +}; + +static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) +{ + EFI_ENTRY("%p", this); + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) +{ + EFI_ENTRY("%p", this); + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, + ulong extra_rx, ulong extra_tx) +{ + EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); + + eth_init(); + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this, + int extended_verification) +{ + EFI_ENTRY("%p, %x", this, extended_verification); + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) +{ + EFI_ENTRY("%p", this); + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_receive_filters( + struct efi_simple_network *this, u32 enable, u32 disable, + int reset_mcast_filter, ulong mcast_filter_count, + struct efi_mac_address *mcast_filter) +{ + EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, + reset_mcast_filter, mcast_filter_count, mcast_filter); + + /* XXX Do we care? */ + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_station_address( + struct efi_simple_network *this, int reset, + struct efi_mac_address *new_mac) +{ + EFI_ENTRY("%p, %x, %p", this, reset, new_mac); + + return EFI_EXIT(EFI_INVALID_PARAMETER); +} + +static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, + int reset, ulong *stat_size, + void *stat_table) +{ + EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table); + + return EFI_EXIT(EFI_INVALID_PARAMETER); +} + +static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, + int ipv6, + struct efi_ip_address *ip, + struct efi_mac_address *mac) +{ + EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac); + + return EFI_EXIT(EFI_INVALID_PARAMETER); +} + +static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, + int read_write, ulong offset, + ulong buffer_size, char *buffer) +{ + EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size, + buffer); + + return EFI_EXIT(EFI_INVALID_PARAMETER); +} + +static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, + u32 *int_status, void **txbuf) +{ + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); + + /* We send packets synchronously, so nothing is outstanding */ + if (int_status) + *int_status = 0; + if (txbuf) + *txbuf = new_tx_packet; + + new_tx_packet = NULL; + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, + ulong header_size, ulong buffer_size, void *buffer, + struct efi_mac_address *src_addr, + struct efi_mac_address *dest_addr, u16 *protocol) +{ + EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, + buffer_size, buffer, src_addr, dest_addr, protocol); + + if (header_size) { + /* We would need to create the header if header_size != 0 */ + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + + net_send_packet(buffer, buffer_size); + new_tx_packet = buffer; + + return EFI_EXIT(EFI_SUCCESS); +} + +static void efi_net_push(void *pkt, int len) +{ + new_rx_packet = true; +} + +static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, + ulong *header_size, ulong *buffer_size, void *buffer, + struct efi_mac_address *src_addr, + struct efi_mac_address *dest_addr, u16 *protocol) +{ + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, + buffer_size, buffer, src_addr, dest_addr, protocol); + + push_packet = efi_net_push; + eth_rx(); + push_packet = NULL; + + if (!new_rx_packet) + return EFI_EXIT(EFI_NOT_READY); + + if (*buffer_size < net_rx_packet_len) { + /* Packet doesn't fit, try again with bigger buf */ + *buffer_size = net_rx_packet_len; + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + memcpy(buffer, net_rx_packet, net_rx_packet_len); + *buffer_size = net_rx_packet_len; + new_rx_packet = false; + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t efi_net_open_dp(void *handle, efi_guid_t *protocol, + void **protocol_interface, void *agent_handle, + void *controller_handle, uint32_t attributes) +{ + struct efi_simple_network *net = handle; + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); + + *protocol_interface = netobj->dp; + + return EFI_SUCCESS; +} + +static efi_status_t efi_net_open_pxe(void *handle, efi_guid_t *protocol, + void **protocol_interface, void *agent_handle, + void *controller_handle, uint32_t attributes) +{ + struct efi_simple_network *net = handle; + struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); + + *protocol_interface = &netobj->pxe; + + return EFI_SUCCESS; +} + +void efi_net_set_dhcp_ack(void *pkt, int len) +{ + int maxsize = sizeof(*dhcp_ack); + + if (!dhcp_ack) + dhcp_ack = malloc(maxsize); + + memcpy(dhcp_ack, pkt, min(len, maxsize)); +} + +/* This gets called from do_bootefi_exec(). */ +int efi_net_register(void **handle) +{ + struct efi_net_obj *netobj; + struct efi_device_path_file_path dp_net = { + .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, + .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, + .dp.length = sizeof(dp_net), + .str = { 'N', 'e', 't' }, + }; + struct efi_device_path_file_path dp_end = { + .dp.type = DEVICE_PATH_TYPE_END, + .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, + .dp.length = sizeof(dp_end), + }; + + if (!eth_get_dev()) { + /* No eth device active, don't expose any */ + return 0; + } + + /* We only expose the "active" eth device, so one is enough */ + netobj = calloc(1, sizeof(*netobj)); + + /* Fill in object data */ + netobj->parent.protocols[0].guid = &efi_net_guid; + netobj->parent.protocols[0].open = efi_return_handle; + netobj->parent.protocols[1].guid = &efi_guid_device_path; + netobj->parent.protocols[1].open = efi_net_open_dp; + netobj->parent.protocols[2].guid = &efi_pxe_guid; + netobj->parent.protocols[2].open = efi_net_open_pxe; + netobj->parent.handle = &netobj->net; + netobj->net.start = efi_net_start; + netobj->net.stop = efi_net_stop; + netobj->net.initialize = efi_net_initialize; + netobj->net.reset = efi_net_reset; + netobj->net.shutdown = efi_net_shutdown; + netobj->net.receive_filters = efi_net_receive_filters; + netobj->net.station_address = efi_net_station_address; + netobj->net.statistics = efi_net_statistics; + netobj->net.mcastiptomac = efi_net_mcastiptomac; + netobj->net.nvdata = efi_net_nvdata; + netobj->net.get_status = efi_net_get_status; + netobj->net.transmit = efi_net_transmit; + netobj->net.receive = efi_net_receive; + netobj->net.mode = &netobj->net_mode; + netobj->net_mode.state = EFI_NETWORK_STARTED; + netobj->dp[0] = dp_net; + netobj->dp[1] = dp_end; + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); + netobj->net_mode.max_packet_size = PKTSIZE; + + netobj->pxe.mode = &netobj->pxe_mode; + if (dhcp_ack) + netobj->pxe_mode.dhcp_ack = *dhcp_ack; + + /* Hook net up to the device list */ + list_add_tail(&netobj->parent.link, &efi_obj_list); + + if (handle) + *handle = &netobj->net; + + return 0; +} -- cgit v1.2.3 From 487d756f78629f5e9465c7ace2c14ef51401bc3b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:05 -0600 Subject: dm: efi: Update for CONFIG_BLK This code does not currently build with driver model enabled for block devices. Update it to correct this. Signed-off-by: Simon Glass Reviewed-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 61 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 075fd340145..3095bcfa2bf 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -96,9 +97,9 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, return EFI_EXIT(EFI_DEVICE_ERROR); if (direction == EFI_DISK_READ) - n = desc->block_read(desc, lba, blocks, buffer); + n = blk_dread(desc, lba, blocks, buffer); else - n = desc->block_write(desc, lba, blocks, buffer); + n = blk_dwrite(desc, lba, blocks, buffer); /* We don't do interrupts, so check for timers cooperatively */ efi_timer_check(); @@ -142,8 +143,8 @@ static const struct efi_block_io block_io_disk_template = { .flush_blocks = &efi_disk_flush_blocks, }; -static void efi_disk_add_dev(char *name, - const struct blk_driver *cur_drvr, +static void efi_disk_add_dev(const char *name, + const char *if_typename, const struct blk_desc *desc, int dev_index, lbaint_t offset) @@ -161,7 +162,7 @@ static void efi_disk_add_dev(char *name, diskobj->parent.protocols[1].open = efi_disk_open_dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; - diskobj->ifname = cur_drvr->if_typename; + diskobj->ifname = if_typename; diskobj->dev_index = dev_index; diskobj->offset = offset; @@ -190,7 +191,7 @@ static void efi_disk_add_dev(char *name, } static int efi_disk_create_eltorito(struct blk_desc *desc, - const struct blk_driver *cur_drvr, + const char *if_typename, int diskid) { int disks = 0; @@ -203,9 +204,10 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, return 0; while (!part_get_info(desc, part, &info)) { - snprintf(devname, sizeof(devname), "%s%d:%d", - cur_drvr->if_typename, diskid, part); - efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start); + snprintf(devname, sizeof(devname), "%s%d:%d", if_typename, + diskid, part); + efi_disk_add_dev(devname, if_typename, desc, diskid, + info.start); part++; disks++; } @@ -219,21 +221,49 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, * EFI payload, we scan through all of the potentially available ones and * store them in our object pool. * + * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this. + * Consider converting the code to look up devices as needed. The EFI device + * could be a child of the UCLASS_BLK block device, perhaps. + * * This gets called from do_bootefi_exec(). */ int efi_disk_register(void) { - const struct blk_driver *cur_drvr; - int i, if_type; int disks = 0; +#ifdef CONFIG_BLK + struct udevice *dev; + + for (uclass_first_device(UCLASS_BLK, &dev); + dev; + uclass_next_device(&dev)) { + struct blk_desc *desc = dev_get_uclass_platdata(dev); + const char *if_typename = dev->driver->name; + + printf("Scanning disk %s...\n", dev->name); + efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0); + disks++; + + /* + * El Torito images show up as block devices in an EFI world, + * so let's create them here + */ + disks += efi_disk_create_eltorito(desc, if_typename, + desc->devnum); + } +#else + int i, if_type; /* Search for all available disk devices */ for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { + const struct blk_driver *cur_drvr; + const char *if_typename; + cur_drvr = blk_driver_lookup_type(if_type); if (!cur_drvr) continue; - printf("Scanning disks on %s...\n", cur_drvr->if_typename); + if_typename = cur_drvr->if_typename; + printf("Scanning disks on %s...\n", if_typename); for (i = 0; i < 4; i++) { struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ @@ -245,17 +275,18 @@ int efi_disk_register(void) continue; snprintf(devname, sizeof(devname), "%s%d", - cur_drvr->if_typename, i); - efi_disk_add_dev(devname, cur_drvr, desc, i, 0); + if_typename, i); + efi_disk_add_dev(devname, if_typename, desc, i, 0); disks++; /* * El Torito images show up as block devices * in an EFI world, so let's create them here */ - disks += efi_disk_create_eltorito(desc, cur_drvr, i); + disks += efi_disk_create_eltorito(desc, if_typename, i); } } +#endif printf("Found %d disks\n", disks); return 0; -- cgit v1.2.3 From 51735ae0ea2f5d67c0f7cc4d1f938f36955e1fe7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 May 2016 18:25:48 +0200 Subject: efi_loader: Add bounce buffer support Some hardware that is supported by U-Boot can not handle DMA above 32bits. For these systems, we need to come up with a way to expose the disk interface in a safe way. This patch implements EFI specific bounce buffers. For non-EFI cases, this apparently was no issue so far, since we can just define our environment variables conveniently. Signed-off-by: Alexander Graf --- lib/efi_loader/Kconfig | 9 ++++++ lib/efi_loader/efi_disk.c | 70 +++++++++++++++++++++++++++++++++++++++------ lib/efi_loader/efi_memory.c | 16 +++++++++++ 3 files changed, 86 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 14c99ec9cf9..37a0dd60a5e 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -7,3 +7,12 @@ config EFI_LOADER on top of U-Boot. If this option is enabled, U-Boot will expose EFI interfaces to a loaded EFI application, enabling it to reuse U-Boot's device drivers. + +config EFI_LOADER_BOUNCE_BUFFER + bool "EFI Applications use bounce buffers for DMA operations" + depends on EFI_LOADER && ARM64 + default n + help + Some hardware does not support DMA to full 64bit addresses. For this + hardware we can create a bounce buffer so that payloads don't have to + worry about platform details. diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 075fd340145..c7d4515321e 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -76,9 +76,6 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, int blocks; unsigned long n; - EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, - buffer_size, buffer); - diskobj = container_of(this, struct efi_disk_obj, ops); if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index))) return EFI_EXIT(EFI_DEVICE_ERROR); @@ -95,10 +92,11 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, if (buffer_size & (blksz - 1)) return EFI_EXIT(EFI_DEVICE_ERROR); - if (direction == EFI_DISK_READ) + if (direction == EFI_DISK_READ) { n = desc->block_read(desc, lba, blocks, buffer); - else + } else { n = desc->block_write(desc, lba, blocks, buffer); + } /* We don't do interrupts, so check for timers cooperatively */ efi_timer_check(); @@ -116,16 +114,70 @@ static efi_status_t efi_disk_read_blocks(struct efi_block_io *this, u32 media_id, u64 lba, unsigned long buffer_size, void *buffer) { - return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, - EFI_DISK_READ); + void *real_buffer = buffer; + efi_status_t r; + +#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER + if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { + r = efi_disk_read_blocks(this, media_id, lba, + EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); + if (r != EFI_SUCCESS) + return r; + return efi_disk_read_blocks(this, media_id, lba + + EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, + buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, + buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); + } + + real_buffer = efi_bounce_buffer; +#endif + + EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, + buffer_size, buffer); + + r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, + EFI_DISK_READ); + + /* Copy from bounce buffer to real buffer if necessary */ + if ((r == EFI_SUCCESS) && (real_buffer != buffer)) + memcpy(buffer, real_buffer, buffer_size); + + return EFI_EXIT(r); } static efi_status_t efi_disk_write_blocks(struct efi_block_io *this, u32 media_id, u64 lba, unsigned long buffer_size, void *buffer) { - return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, - EFI_DISK_WRITE); + void *real_buffer = buffer; + efi_status_t r; + +#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER + if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { + r = efi_disk_write_blocks(this, media_id, lba, + EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); + if (r != EFI_SUCCESS) + return r; + return efi_disk_write_blocks(this, media_id, lba + + EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, + buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, + buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); + } + + real_buffer = efi_bounce_buffer; +#endif + + EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, + buffer_size, buffer); + + /* Populate bounce buffer if necessary */ + if (real_buffer != buffer) + memcpy(real_buffer, buffer, buffer_size); + + r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, + EFI_DISK_WRITE); + + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 71a3d192696..9e669f51026 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -27,6 +27,10 @@ struct efi_mem_list { /* This list contains all memory map items */ LIST_HEAD(efi_mem); +#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER +void *efi_bounce_buffer; +#endif + /* * Sorts the memory list from highest address to lowest address * @@ -349,5 +353,17 @@ int efi_memory_init(void) efi_add_memory_map(runtime_start, runtime_pages, EFI_RUNTIME_SERVICES_CODE, false); +#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER + /* Request a 32bit 64MB bounce buffer region */ + uint64_t efi_bounce_buffer_addr = 0xffffffff; + + if (efi_allocate_pages(1, EFI_LOADER_DATA, + (64 * 1024 * 1024) >> EFI_PAGE_SHIFT, + &efi_bounce_buffer_addr) != EFI_SUCCESS) + return -1; + + efi_bounce_buffer = (void*)(uintptr_t)efi_bounce_buffer_addr; +#endif + return 0; } -- cgit v1.2.3 From ae87440578369456b55e54125e101d27c332bc5a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 18 May 2016 00:54:47 +0200 Subject: efi_loader: Clean up system table on exit We put the system table into our runtime services data section so that payloads may still access it after exit_boot_services. However, most fields in it are quite useless once we're in that state, so let's just patch them out. With this patch we don't get spurious warnings when running EFI binaries anymore. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 3ee27ca9cc6..11d01268d8c 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -125,6 +125,22 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { /* RTC accessors are gone */ .ptr = &efi_runtime_services.get_time, .patchto = &efi_device_error, + }, { + /* Clean up system table */ + .ptr = &systab.con_in, + .patchto = NULL, + }, { + /* Clean up system table */ + .ptr = &systab.con_out, + .patchto = NULL, + }, { + /* Clean up system table */ + .ptr = &systab.std_err, + .patchto = NULL, + }, { + /* Clean up system table */ + .ptr = &systab.boottime, + .patchto = NULL, }, }; -- cgit v1.2.3 From c9cfac5d3023e9b2993578400fbc7f03aa6919af Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 18 May 2016 02:04:24 +0200 Subject: efi_loader: gop: Don't expose fb address Recently Linux is gaining support for efifb on AArch64 and that support actually tries to make use of the frame buffer address we expose to it via gop. While this wouldn't be bad in theory, in practice it means a few bad things 1) We expose 16bit frame buffers as 32bit today 2) Linux can't deal with overlapping non-PCI regions between efifb and a different frame buffer driver For now, let's just disable exposure of the frame buffer address. Most OSs that get booted will have a native driver for the GPU anyway. Signed-off-by: Alexander Graf [trini: Remove line_len entirely] Signed-off-by: Tom Rini --- lib/efi_loader/efi_gop.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index bdd62bc5575..dc6e2615ccc 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -111,7 +111,6 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, int efi_gop_register(void) { struct efi_gop_obj *gopobj; - int line_len; switch (panel_info.vl_bpix) { case LCD_COLOR32: @@ -136,8 +135,6 @@ int efi_gop_register(void) gopobj->mode.max_mode = 1; gopobj->mode.info = &gopobj->info; gopobj->mode.info_size = sizeof(gopobj->info); - gopobj->mode.fb_base = gd->fb_base; - gopobj->mode.fb_size = lcd_get_size(&line_len); gopobj->info.version = 0; gopobj->info.width = panel_info.vl_col; -- cgit v1.2.3 From 39f633320c569a5d975d2d051ff2683db27bd021 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 12 May 2016 12:11:23 -0600 Subject: mmc: tegra: add basic Tegra186 support Tegra186's MMC controller needs to be explicitly identified. Add another compatible value for it. Tegra186 will use an entirely different clock/reset control mechanism to existing chips, and will use standard clock/reset APIs rather than the existing Tegra-specific custom APIs. The driver support for that isn't ready yet, so simply disable all clock/reset usage if compiling for Tegra186. This must happen at compile time rather than run-time since the custom APIs won't even be compiled in on Tegra186. In the long term, the plan would be to convert the existing custom APIs to standard APIs and get rid of the ifdefs completely. The system's main eMMC will work without any clock/reset support, since the firmware will have already initialized the controller in order to load U-Boot. Hence the driver is useful even in this apparently crippled state. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- lib/fdtdec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 70acc29c924..ab002e9fa3e 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -30,6 +30,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA124_SOR, "nvidia,tegra124-sor"), COMPAT(NVIDIA_TEGRA124_PMC, "nvidia,tegra124-pmc"), COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), + COMPAT(NVIDIA_TEGRA186_SDMMC, "nvidia,tegra186-sdhci"), COMPAT(NVIDIA_TEGRA210_SDMMC, "nvidia,tegra210-sdhci"), COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"), COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"), -- cgit v1.2.3 From abeb272d22217481c214495818c3ceabad57b9c0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 31 May 2016 23:12:46 +0200 Subject: tiny-printf: Support sprintf() Add a simple version of this function for SPL. It does not check the buffer size as this would add to the code size. Signed-off-by: Marek Vasut Cc: Simon Glass Cc: Stefan Roese Cc: Tom Rini Cc: lesne@alse-fr.com Reviewed-by: Tom Rini Reviewed-by: Sylvain Lesne Tested-by: Sylvain Lesne --- lib/tiny-printf.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index 4b70263df7d..5ea2555280b 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -147,8 +147,7 @@ static void putc_outstr(char ch) *outstr++ = ch; } -/* Note that size is ignored */ -int snprintf(char *buf, size_t size, const char *fmt, ...) +int sprintf(char *buf, const char *fmt, ...) { va_list va; int ret; @@ -161,3 +160,16 @@ int snprintf(char *buf, size_t size, const char *fmt, ...) return ret; } + +/* Note that size is ignored */ +int snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list va; + int ret; + + va_start(va, fmt); + ret = sprintf(buf, fmt, va); + va_end(va); + + return ret; +} -- cgit v1.2.3 From 91b86e21564de01c0e3deafc72702897993d63ae Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 26 May 2016 18:01:47 +0200 Subject: lib: Enable private libgcc by default This patch decouples U-Boot binary from the toolchain on systems where private libgcc is available. Instead of pulling in functions provided by the libgcc from the toolchain, U-Boot will use it's own set of libgcc functions. These functions are usually imported from Linux kernel, which also uses it's own libgcc functions instead of the ones provided by the toolchain. This patch solves a rather common problem. The toolchain can usually generate code for many variants of target architecture and often even different endianness. The libgcc on the other hand is usually compiled for one particular configuration and the functions provided by it may or may not be suited for use in U-Boot. This can manifest in two ways, either the U-Boot fails to compile altogether and linker will complain or, in the much worse case, the resulting U-Boot will build, but will misbehave in very subtle and hard to debug ways. Signed-off-by: Marek Vasut Cc: Albert Aribaud Cc: Masahiro Yamada Cc: Simon Glass Cc: Tom Rini Reviewed-by: Tom Rini --- lib/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/Kconfig b/lib/Kconfig index 2b97c2b0a47..02ca4058d37 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -14,6 +14,7 @@ config HAVE_PRIVATE_LIBGCC config USE_PRIVATE_LIBGCC bool "Use private libgcc" depends on HAVE_PRIVATE_LIBGCC + default y if HAVE_PRIVATE_LIBGCC && ((ARM && !ARM64) || MIPS) help This option allows you to use the built-in libgcc implementation of U-Boot instead of the one provided by the compiler. -- cgit v1.2.3 From a86aeaf228da739bce6bc40927949efc33672050 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 20 May 2016 23:28:23 +0200 Subject: efi_loader: Add exit support Some times you may want to exit an EFI payload again, for example to default boot into a PXE installation and decide that you would rather want to boot from the local disk instead. This patch adds exit functionality to the EFI implementation, allowing EFI payloads to exit. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9daca50a72f..15a1b90d65a 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -458,19 +458,30 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, efi_is_direct_boot = false; /* call the image! */ + if (setjmp(&info->exit_jmp)) { + /* We returned from the child image */ + return EFI_EXIT(info->exit_status); + } + entry(image_handle, &systab); /* Should usually never get here */ return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_exit(void *image_handle, long exit_status, - unsigned long exit_data_size, - uint16_t *exit_data) +static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, + efi_status_t exit_status, unsigned long exit_data_size, + int16_t *exit_data) { + struct efi_loaded_image *loaded_image_info = (void*)image_handle; + EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, exit_data_size, exit_data); - return EFI_EXIT(efi_unsupported(__func__)); + + loaded_image_info->exit_status = exit_status; + longjmp(&loaded_image_info->exit_jmp); + + panic("EFI application exited"); } static struct efi_object *efi_search_obj(void *handle) @@ -746,7 +757,7 @@ static const struct efi_boot_services efi_boot_services = { .install_configuration_table = efi_install_configuration_table, .load_image = efi_load_image, .start_image = efi_start_image, - .exit = (void*)efi_exit, + .exit = efi_exit, .unload_image = efi_unload_image, .exit_boot_services = efi_exit_boot_services, .get_next_monotonic_count = efi_get_next_monotonic_count, -- cgit v1.2.3 From edcef3ba1d2d5beb92fcd7df253e196e77ba174d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 2 Jun 2016 11:38:27 +0200 Subject: efi_loader: Move to normal debug infrastructure We introduced special "DEBUG_EFI" defines when the efi loader support was new. After giving it a bit of thought, turns out we really didn't have to - the normal #define DEBUG infrastructure works well enough for efi loader as well. So this patch switches to the common debug() and #define DEBUG way of printing debug information. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 6 +----- lib/efi_loader/efi_disk.c | 11 ++++------- lib/efi_loader/efi_memory.c | 2 -- lib/efi_loader/efi_runtime.c | 14 +++----------- 4 files changed, 8 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 15a1b90d65a..be6f5e81124 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -6,8 +6,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -/* #define DEBUG_EFI */ - #include #include #include @@ -76,9 +74,7 @@ efi_status_t efi_exit_func(efi_status_t ret) static efi_status_t efi_unsupported(const char *funcname) { -#ifdef DEBUG_EFI - printf("EFI: App called into unimplemented function %s\n", funcname); -#endif + debug("EFI: App called into unimplemented function %s\n", funcname); return EFI_EXIT(EFI_UNSUPPORTED); } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index f9ad6156b71..c434c92250a 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -84,10 +84,8 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, blocks = buffer_size / blksz; lba += diskobj->offset; -#ifdef DEBUG_EFI - printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, - __LINE__, blocks, lba, blksz, direction); -#endif + debug("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, + __LINE__, blocks, lba, blksz, direction); /* We only support full block access */ if (buffer_size & (blksz - 1)) @@ -101,9 +99,8 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, /* We don't do interrupts, so check for timers cooperatively */ efi_timer_check(); -#ifdef DEBUG_EFI - printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); -#endif + debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); + if (n != blocks) return EFI_EXIT(EFI_DEVICE_ERROR); diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 9e669f51026..ad713d0e8be 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -6,8 +6,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -/* #define DEBUG_EFI */ - #include #include #include diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 11d01268d8c..99b5ef11c2e 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -165,9 +165,7 @@ static void efi_runtime_detach(ulong offset) ulong *p = efi_runtime_detach_list[i].ptr; ulong newaddr = patchto ? (patchto + patchoff) : 0; -#ifdef DEBUG_EFI - printf("%s: Setting %p to %lx\n", __func__, p, newaddr); -#endif + debug("%s: Setting %p to %lx\n", __func__, p, newaddr); *p = newaddr; } } @@ -182,10 +180,7 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) static ulong lastoff = CONFIG_SYS_TEXT_BASE; #endif -#ifdef DEBUG_EFI - printf("%s: Relocating to offset=%lx\n", __func__, offset); -#endif - + debug("%s: Relocating to offset=%lx\n", __func__, offset); for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) { ulong base = CONFIG_SYS_TEXT_BASE; ulong *p; @@ -212,10 +207,7 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) continue; } -#ifdef DEBUG_EFI - printf("%s: Setting %p to %lx\n", __func__, p, newaddr); -#endif - + debug("%s: Setting %p to %lx\n", __func__, p, newaddr); *p = newaddr; flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1), ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE)); -- cgit v1.2.3 From 74c16acce30bb882ad5951829d8dafef8eea564c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 27 May 2016 12:25:03 +0200 Subject: efi_loader: Don't allocate from memory holes When a payload calls our memory allocator with the exact address hint, we happily allocate memory from completely unpopulated regions. Payloads however expect this to only succeed if they would be allocating from free conventional memory. This patch makes the logic behind those checks a bit more obvious and ensures that we always allocate from known good free conventional memory regions if we want to allocate ram. Reported-by: Jonathan Gray Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 55 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ad713d0e8be..df2381e42c2 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -22,6 +22,10 @@ struct efi_mem_list { struct efi_mem_desc desc; }; +#define EFI_CARVE_NO_OVERLAP -1 +#define EFI_CARVE_LOOP_AGAIN -2 +#define EFI_CARVE_OVERLAPS_NONRAM -3 + /* This list contains all memory map items */ LIST_HEAD(efi_mem); @@ -76,11 +80,11 @@ static int efi_mem_carve_out(struct efi_mem_list *map, /* check whether we're overlapping */ if ((carve_end <= map_start) || (carve_start >= map_end)) - return 0; + return EFI_CARVE_NO_OVERLAP; /* We're overlapping with non-RAM, warn the caller if desired */ if (overlap_only_ram && (map_desc->type != EFI_CONVENTIONAL_MEMORY)) - return -1; + return EFI_CARVE_OVERLAPS_NONRAM; /* Sanitize carve_start and carve_end to lie within our bounds */ carve_start = max(carve_start, map_start); @@ -95,7 +99,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map, map_desc->physical_start = carve_end; map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; - return 1; + return (carve_end - carve_start) >> EFI_PAGE_SHIFT; } /* @@ -115,7 +119,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map, /* Shrink the map to [ map_start ... carve_start ] */ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; - return 1; + return EFI_CARVE_LOOP_AGAIN; } uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, @@ -123,7 +127,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, { struct list_head *lhandle; struct efi_mem_list *newlist; - bool do_carving; + bool carve_again; + uint64_t carved_pages = 0; if (!pages) return start; @@ -150,7 +155,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, /* Add our new map */ do { - do_carving = false; + carve_again = false; list_for_each(lhandle, &efi_mem) { struct efi_mem_list *lmem; int r; @@ -158,14 +163,44 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, lmem = list_entry(lhandle, struct efi_mem_list, link); r = efi_mem_carve_out(lmem, &newlist->desc, overlap_only_ram); - if (r < 0) { + switch (r) { + case EFI_CARVE_OVERLAPS_NONRAM: + /* + * The user requested to only have RAM overlaps, + * but we hit a non-RAM region. Error out. + */ return 0; - } else if (r) { - do_carving = true; + case EFI_CARVE_NO_OVERLAP: + /* Just ignore this list entry */ + break; + case EFI_CARVE_LOOP_AGAIN: + /* + * We split an entry, but need to loop through + * the list again to actually carve it. + */ + carve_again = true; + break; + default: + /* We carved a number of pages */ + carved_pages += r; + carve_again = true; + break; + } + + if (carve_again) { + /* The list changed, we need to start over */ break; } } - } while (do_carving); + } while (carve_again); + + if (overlap_only_ram && (carved_pages != pages)) { + /* + * The payload wanted to have RAM overlaps, but we overlapped + * with an unallocated region. Error out. + */ + return 0; + } /* Add our new map */ list_add_tail(&newlist->link, &efi_mem); -- cgit v1.2.3 From a812241091cec09c4a214c57776eefb8f19d81a9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 5 Jun 2016 22:34:31 +0200 Subject: efi_loader: Add DM_VIDEO support Some systems are starting to shift to support DM_VIDEO which exposes the frame buffer through a slightly different interface. This is a poor man's effort to support the dm video interface instead of the lcd one. We still only support a single display device. Signed-off-by: Alexander Graf [trini: Remove fb_size / fb_base as they were not used] Signed-off-by: Tom Rini --- lib/efi_loader/efi_gop.c | 57 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index dc6e2615ccc..33a3d717671 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -7,10 +7,12 @@ */ #include +#include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -24,6 +26,8 @@ struct efi_gop_obj { /* The only mode we support */ struct efi_gop_mode_info info; struct efi_gop_mode mode; + /* Fields we only have acces to during init */ + u32 bpix; }; static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, @@ -57,6 +61,7 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, unsigned long dy, unsigned long width, unsigned long height, unsigned long delta) { + struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops); int i, j, line_len16, line_len32; void *fb; @@ -67,13 +72,17 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, return EFI_EXIT(EFI_INVALID_PARAMETER); fb = (void*)gd->fb_base; - line_len16 = panel_info.vl_col * sizeof(u16); - line_len32 = panel_info.vl_col * sizeof(u32); + line_len16 = gopobj->info.width * sizeof(u16); + line_len32 = gopobj->info.width * sizeof(u32); /* Copy the contents line by line */ - switch (panel_info.vl_bpix) { + switch (gopobj->bpix) { +#ifdef CONFIG_DM_VIDEO + case VIDEO_BPP32: +#else case LCD_COLOR32: +#endif for (i = 0; i < height; i++) { u32 *dest = fb + ((i + dy) * line_len32) + (dx * sizeof(u32)); @@ -84,7 +93,11 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, memcpy(dest, src, width * sizeof(u32)); } break; +#ifdef CONFIG_DM_VIDEO + case VIDEO_BPP16: +#else case LCD_COLOR16: +#endif for (i = 0; i < height; i++) { u16 *dest = fb + ((i + dy) * line_len16) + (dx * sizeof(u16)); @@ -102,7 +115,11 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, break; } +#ifdef CONFIG_DM_VIDEO + video_sync_all(); +#else lcd_sync(); +#endif return EFI_EXIT(EFI_SUCCESS); } @@ -111,10 +128,34 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, int efi_gop_register(void) { struct efi_gop_obj *gopobj; + u32 bpix, col, row; - switch (panel_info.vl_bpix) { +#ifdef CONFIG_DM_VIDEO + struct udevice *vdev; + + /* We only support a single video output device for now */ + if (uclass_first_device(UCLASS_VIDEO, &vdev)) + return -1; + + struct video_priv *priv = dev_get_uclass_priv(vdev); + bpix = priv->bpix; + col = video_get_xsize(vdev); + row = video_get_ysize(vdev); +#else + + bpix = panel_info.vl_bpix; + col = panel_info.vl_col; + row = panel_info.vl_row; +#endif + + switch (bpix) { +#ifdef CONFIG_DM_VIDEO + case VIDEO_BPP16: + case VIDEO_BPP32: +#else case LCD_COLOR32: case LCD_COLOR16: +#endif break; default: /* So far, we only work in 16 or 32 bit mode */ @@ -137,10 +178,12 @@ int efi_gop_register(void) gopobj->mode.info_size = sizeof(gopobj->info); gopobj->info.version = 0; - gopobj->info.width = panel_info.vl_col; - gopobj->info.height = panel_info.vl_row; + gopobj->info.width = col; + gopobj->info.height = row; gopobj->info.pixel_format = EFI_GOT_RGBA8; - gopobj->info.pixels_per_scanline = panel_info.vl_col; + gopobj->info.pixels_per_scanline = col; + + gopobj->bpix = bpix; /* Hook up to the device list */ list_add_tail(&gopobj->parent.link, &efi_obj_list); -- cgit v1.2.3 From 25bab53ab26efdb9e2024477f896be65b6e7191e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 30 May 2016 06:55:53 -0400 Subject: Remove unneeded remnants of bcopy(). Since bcopy() is no longer used, delete all remaining references to it. Signed-off-by: Robert P. J. Day --- lib/string.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'lib') diff --git a/lib/string.c b/lib/string.c index 87c9a408e62..67d5f6a4213 100644 --- a/lib/string.c +++ b/lib/string.c @@ -461,30 +461,6 @@ void * memset(void * s,int c,size_t count) } #endif -#ifndef __HAVE_ARCH_BCOPY -/** - * bcopy - Copy one area of memory to another - * @src: Where to copy from - * @dest: Where to copy to - * @count: The size of the area. - * - * Note that this is the same as memcpy(), with the arguments reversed. - * memcpy() is the standard, bcopy() is a legacy BSD function. - * - * You should not use this function to access IO space, use memcpy_toio() - * or memcpy_fromio() instead. - */ -char * bcopy(const char * src, char * dest, int count) -{ - char *tmp = dest; - - while (count--) - *tmp++ = *src++; - - return dest; -} -#endif - #ifndef __HAVE_ARCH_MEMCPY /** * memcpy - Copy one area of memory to another -- cgit v1.2.3 From be86492bdaeb8fdfd8d66bba79a9bd899531b8b0 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 31 May 2016 20:30:59 +1200 Subject: lib: make strmhz available in SPL When setting up a DDR controller it is useful to be able to display frequencies in a readable form. Make the strmhz() function available in SPL builds provided there is full vsprintf available. Reviewed-by: Tony O'Brien Reviewed-by: Simon Glass Signed-off-by: Chris Packham --- lib/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 02dfa295073..f77befe03c2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -42,7 +42,6 @@ obj-y += rc4.o obj-$(CONFIG_SHA1) += sha1.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o obj-$(CONFIG_SHA256) += sha256.o -obj-y += strmhz.o obj-$(CONFIG_TPM) += tpm.o obj-$(CONFIG_RBTREE) += rbtree.o obj-$(CONFIG_BITREVERSE) += bitrev.o @@ -85,11 +84,11 @@ ifdef CONFIG_SPL_BUILD ifdef CONFIG_USE_TINY_PRINTF obj-$(CONFIG_SPL_SERIAL_SUPPORT) += tiny-printf.o panic.o strto.o else -obj-$(CONFIG_SPL_SERIAL_SUPPORT) += vsprintf.o panic.o strto.o +obj-$(CONFIG_SPL_SERIAL_SUPPORT) += vsprintf.o panic.o strto.o strmhz.o endif else # Main U-Boot always uses the full printf support -obj-y += vsprintf.o panic.o strto.o +obj-y += vsprintf.o panic.o strto.o strmhz.o endif subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2 -- cgit v1.2.3 From 3191d8408053674c1b9bb79a82e3973add48830c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 8 Jun 2016 20:55:15 -0600 Subject: tiny-printf: Correct the snprintf() implementation This current code passes the variable arguments list to sprintf(). This is not correct. Fix it by calling _vprintf() directly. This makes firefly-rk3288 boot again. Fixes: abeb272 ("tiny-printf: Support snprintf()") Reviewed-by: Stefan Roese Acked-by: Marek Vasut Signed-off-by: Simon Glass --- lib/tiny-printf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index 5ea2555280b..3c65fc90bf2 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -168,8 +168,10 @@ int snprintf(char *buf, size_t size, const char *fmt, ...) int ret; va_start(va, fmt); - ret = sprintf(buf, fmt, va); + outstr = buf; + ret = _vprintf(fmt, va, putc_outstr); va_end(va); + *outstr = '\0'; return ret; } -- cgit v1.2.3