diff --git a/Makefile b/Makefile
index d634b336b971324be64ad814e19837f41ff78228..01f33d433f3cc07eb99d92163936ebd0a1ae87f3 100644
--- a/Makefile
+++ b/Makefile
@@ -204,6 +204,18 @@ LD			=	$(LINKER)
 AS			=	$(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH))
 CPP			=	$(CC) -E
 PP			=	$(CC) -E
+else ifneq ($(findstring gcc,$(notdir $(CC))),)
+TF_CFLAGS_aarch32	=	$(march32-directive)
+TF_CFLAGS_aarch64	=	$(march64-directive)
+ifeq ($(ENABLE_LTO),1)
+	# Enable LTO only for aarch64
+	ifeq (${ARCH},aarch64)
+		LTO_CFLAGS	=	-flto
+		# Use gcc as a wrapper for the ld, recommended for LTO
+		LINKER		:=	${CROSS_COMPILE}gcc
+	endif
+endif
+LD			=	$(LINKER)
 else
 TF_CFLAGS_aarch32	=	$(march32-directive)
 TF_CFLAGS_aarch64	=	$(march64-directive)
@@ -301,11 +313,28 @@ GCC_V_OUTPUT		:=	$(shell $(CC) -v 2>&1)
 ifneq ($(findstring armlink,$(notdir $(LD))),)
 TF_LDFLAGS		+=	--diag_error=warning --lto_level=O1
 TF_LDFLAGS		+=	--remove --info=unused,unusedsymbols
+TF_LDFLAGS		+=	$(TF_LDFLAGS_$(ARCH))
+else ifneq ($(findstring gcc,$(notdir $(LD))),)
+# Pass ld options with Wl or Xlinker switches
+TF_LDFLAGS		+=	-Wl,--fatal-warnings -O1
+TF_LDFLAGS		+=	-Wl,--gc-sections
+ifeq ($(ENABLE_LTO),1)
+	ifeq (${ARCH},aarch64)
+		TF_LDFLAGS	+=	-flto -fuse-linker-plugin
+	endif
+endif
+# GCC automatically adds fix-cortex-a53-843419 flag when used to link
+# which breaks some builds, so disable if errata fix is not explicitly enabled
+ifneq (${ERRATA_A53_843419},1)
+	TF_LDFLAGS	+= 	-mno-fix-cortex-a53-843419
+endif
+TF_LDFLAGS		+= 	-nostdlib
+TF_LDFLAGS		+=	$(subst --,-Xlinker --,$(TF_LDFLAGS_$(ARCH)))
 else
 TF_LDFLAGS		+=	--fatal-warnings -O1
 TF_LDFLAGS		+=	--gc-sections
-endif
 TF_LDFLAGS		+=	$(TF_LDFLAGS_$(ARCH))
+endif
 
 DTC_FLAGS		+=	-I dts -O dtb
 DTC_CPPFLAGS		+=	-nostdinc -Iinclude -undef -x assembler-with-cpp
@@ -406,7 +435,11 @@ endif
 
 ifeq ($(ENABLE_PIE),1)
     TF_CFLAGS		+=	-fpie
-    TF_LDFLAGS		+=	-pie --no-dynamic-linker
+	ifneq ($(findstring gcc,$(notdir $(LD))),)
+		TF_LDFLAGS	+=	-Wl,-pie -Wl,--no-dynamic-linker
+	else
+		TF_LDFLAGS	+=	-pie --no-dynamic-linker
+	endif
 else
     PIE_FOUND		:=	$(findstring --enable-default-pie,${GCC_V_OUTPUT})
     ifneq ($(PIE_FOUND),)
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index fded1e0c923bd226e281e968c5547207545a8ad9..051586bc349ece0784dd60e67d49106f68cd028e 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -196,6 +196,10 @@ Common build options
    builds, but this behaviour can be overridden in each platform's Makefile or
    in the build command line.
 
+ -  ``ENABLE_LTO``: Boolean option to enable Link Time Optimization (LTO)
+   support in GCC for TF-A. This option is currently only supported for
+   AArch64. Default is 0.
+
 -  ``ENABLE_MPAM_FOR_LOWER_ELS``: Boolean option to enable lower ELs to use MPAM
    feature. MPAM is an optional Armv8.4 extension that enables various memory
    system components and resources to define partitions; software running at
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index b89d87ea6087f2ce01f837938561a33eafef7d5b..47f3ebd8610b214ef1736a1f970c9106f7c030d8 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -236,7 +236,7 @@ $(eval BL_CFLAGS := $(BL$(call uppercase,$(3))_CFLAGS))
 
 $(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
 	$$(ECHO) "  CC      $$<"
-	$$(Q)$$(CC) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@
+	$$(Q)$$(CC) $$(LTO_CFLAGS) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@
 
 -include $(DEP)
 
@@ -433,6 +433,10 @@ ifneq ($(findstring armlink,$(notdir $(LD))),)
 		--map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/bl${1}.scat \
 		$(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) \
 		$(BUILD_DIR)/build_message.o $(OBJS)
+else ifneq ($(findstring gcc,$(notdir $(LD))),)
+	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Wl,-Map=$(MAPFILE) \
+		-Wl,-T$(LINKERFILE) $(BUILD_DIR)/build_message.o \
+		$(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS)
 else
 	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Map=$(MAPFILE) \
 		--script $(LINKERFILE) $(BUILD_DIR)/build_message.o \
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index b7fb173b16c402c356d805915d1c078d20717e31..348b3e52b9df962fe82497440a9a72c868d5fe66 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -239,3 +239,6 @@ SANITIZE_UB := off
 # implementation variant using the ARMv8.1-LSE compare-and-swap instruction.
 # Default: disabled
 USE_SPINLOCK_CAS := 0
+
+# Enable Link Time Optimization
+ENABLE_LTO			:= 0