diff --git a/core/init.c b/core/init.c
index 983ead5d4c..d9d62ee96f 100644
--- a/core/init.c
+++ b/core/init.c
@@ -49,6 +49,7 @@
 #include <libstb/container.h>
 
 enum proc_gen proc_gen;
+unsigned int pcie_max_link_speed;
 
 static uint64_t kernel_entry;
 static size_t kernel_size;
@@ -700,6 +701,20 @@ static void per_thread_sanity_checks(void)
 	assert(cpu->state != cpu_state_no_cpu);
 }
 
+static void pci_nvram_init(void)
+{
+	const char *nvram_speed;
+
+	pcie_max_link_speed = 0;
+
+	nvram_speed = nvram_query("pcie-max-link-speed");
+	if (nvram_speed) {
+		pcie_max_link_speed = atoi(nvram_speed);
+		prlog(PR_NOTICE, "PHB: NVRAM set max link speed to GEN%i\n",
+		      pcie_max_link_speed);
+	}
+}
+
 /* Called from head.S, thus no prototype. */
 void main_cpu_entry(const void *fdt);
 
@@ -917,6 +932,8 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
 
 	op_display(OP_LOG, OP_MOD_INIT, 0x0002);
 
+	pci_nvram_init();
+
 	phb3_preload_vpd();
 	phb3_preload_capp_ucode();
 	start_preload_kernel();
diff --git a/hw/phb3.c b/hw/phb3.c
index 89d66f3c99..fa2500b058 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -4671,7 +4671,6 @@ static void phb3_create(struct dt_node *np)
 	p->phb.ops = &phb3_ops;
 	p->phb.phb_type = phb_type_pcie_v3;
 	p->phb.scan_map = 0x1; /* Only device 0 to scan */
-	p->max_link_speed = dt_prop_get_u32_def(np, "ibm,max-link-speed", 3);
 	p->state = PHB3_STATE_UNINITIALIZED;
 
 	if (!phb3_calculate_windows(p))
@@ -4737,6 +4736,16 @@ static void phb3_create(struct dt_node *np)
 	if (!p->phb.base_loc_code)
 		PHBERR(p, "Base location code not found !\n");
 
+	/* Priority order: NVRAM -> dt -> GEN3 */
+	p->max_link_speed = 3;
+	if (dt_has_node_property(np, "ibm,max-link-speed", NULL))
+		p->max_link_speed = dt_prop_get_u32(np, "ibm,max-link-speed");
+	if (pcie_max_link_speed)
+		p->max_link_speed = pcie_max_link_speed;
+	if (p->max_link_speed > 3) /* clamp to 3 */
+		p->max_link_speed = 3;
+	PHBINF(p, "Max link speed: GEN%i\n", p->max_link_speed);
+
 	/* Check for lane equalization values from HB or HDAT */
 	p->lane_eq = dt_prop_get_def_size(np, "ibm,lane-eq", NULL, &lane_eq_len);
 	if (p->lane_eq && lane_eq_len != (8 * 4)) {
@@ -4966,8 +4975,10 @@ static void phb3_probe_pbcq(struct dt_node *pbcq)
 		capp_ucode_base = dt_prop_get_u32(pbcq, "ibm,capp-ucode");
 		dt_add_property_cells(np, "ibm,capp-ucode", capp_ucode_base);
 	}
-	max_link_speed = dt_prop_get_u32_def(pbcq, "ibm,max-link-speed", 3);
-	dt_add_property_cells(np, "ibm,max-link-speed", max_link_speed);
+	if (dt_has_node_property(pbcq, "ibm,max-link-speed", NULL)) {
+		max_link_speed = dt_prop_get_u32(pbcq, "ibm,max-link-speed");
+		dt_add_property_cells(np, "ibm,max-link-speed", max_link_speed);
+	}
 	dt_add_property_cells(np, "ibm,capi-flags",
 			      OPAL_PHB_CAPI_FLAG_SNOOP_CONTROL);
 
diff --git a/hw/phb4.c b/hw/phb4.c
index 314e0f79ae..694a475aa7 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -3092,7 +3092,6 @@ static void phb4_create(struct dt_node *np)
 	p->phb.ops = &phb4_ops;
 	p->phb.phb_type = phb_type_pcie_v4;
 	p->phb.scan_map = 0x1; /* Only device 0 to scan */
-	p->max_link_speed = dt_prop_get_u32_def(np, "ibm,max-link-speed", 4);
 	p->state = PHB4_STATE_UNINITIALIZED;
 
 	if (!phb4_calculate_windows(p))
@@ -3169,6 +3168,16 @@ static void phb4_create(struct dt_node *np)
 	if (!phb4_read_capabilities(p))
 		goto failed;
 
+	/* Priority order: NVRAM -> dt -> GEN4 */
+	p->max_link_speed = 4;
+	if (dt_has_node_property(np, "ibm,max-link-speed", NULL))
+		p->max_link_speed = dt_prop_get_u32(np, "ibm,max-link-speed");
+	if (pcie_max_link_speed)
+		p->max_link_speed = pcie_max_link_speed;
+	if (p->max_link_speed > 4) /* clamp to 4 */
+		p->max_link_speed = 4;
+	PHBINF(p, "Max link speed: GEN%i\n", p->max_link_speed);
+
 	/* Check for lane equalization values from HB or HDAT */
 	p->lane_eq = dt_prop_get_def_size(np, "ibm,lane-eq", NULL, &lane_eq_len);
 	if (p->lane_eq) {
@@ -3446,8 +3455,10 @@ static void phb4_probe_stack(struct dt_node *stk_node, uint32_t pec_index,
 		capp_ucode_base = dt_prop_get_u32(stk_node, "ibm,capp-ucode");
 		dt_add_property_cells(np, "ibm,capp-ucode", capp_ucode_base);
 	}
-	max_link_speed = dt_prop_get_u32_def(stk_node, "ibm,max-link-speed", 4);
-	dt_add_property_cells(np, "ibm,max-link-speed", max_link_speed);
+	if (dt_has_node_property(stk_node, "ibm,max-link-speed", NULL)) {
+		max_link_speed = dt_prop_get_u32(stk_node, "ibm,max-link-speed");
+		dt_add_property_cells(np, "ibm,max-link-speed", max_link_speed);
+	}
 	dt_add_property_cells(np, "ibm,capi-flags",
 			      OPAL_PHB_CAPI_FLAG_SNOOP_CONTROL);
 
diff --git a/include/skiboot.h b/include/skiboot.h
index bb0a7b53e8..c55995b733 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -132,6 +132,8 @@ enum proc_gen {
 };
 extern enum proc_gen proc_gen;
 
+extern unsigned int pcie_max_link_speed;
+
 /* Convert a 4-bit number to a hex char */
 extern char __attrconst tohex(uint8_t nibble);
 
