x86: apl: Use devicetree for FSP-M configuration

A the moment the FSP-M configuration is a mix of hard coded values and
devicetree properties.

This patch makes FSP-M full configurable from devicetree by adding
binding properties for all FSP-M parameters.

Co-developed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
Signed-off-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
Signed-off-by: Bernhard Messerklinger <bernhard.messerklinger@br-automation.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org> (Tested on coral)
[sjg: Fix a build error for coral]
Signed-off-by: Simon Glass <sjg@chromium.org>
[bmeng: Add __maybe_unused to fsp_update_config_from_dtb()]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
index 578e15c..3aa2a55 100644
--- a/arch/x86/cpu/apollolake/Makefile
+++ b/arch/x86/cpu/apollolake/Makefile
@@ -10,6 +10,7 @@
 ifndef CONFIG_TPL_BUILD
 obj-y += cpu.o
 obj-y += punit.o
+obj-y += fsp_bindings.o
 ifdef CONFIG_SPL_BUILD
 obj-y += fsp_m.o
 endif
diff --git a/arch/x86/cpu/apollolake/fsp_bindings.c b/arch/x86/cpu/apollolake/fsp_bindings.c
new file mode 100644
index 0000000..6b97060
--- /dev/null
+++ b/arch/x86/cpu/apollolake/fsp_bindings.c
@@ -0,0 +1,616 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020 B&R Industrial Automation GmbH - http://www.br-automation.com
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/arch/fsp_bindings.h>
+
+/**
+ * read_u8_prop() - Read an u8 property from devicetree (scalar or array)
+ * @node:  Valid node reference to read property from
+ * @name:  Name of the property to read from
+ * @count: If the property is expected to be an array, this is the
+ *         number of expected elements
+ *         Set to 0 if the property is expected to be a scalar
+ * @dst:   Pointer to destination of where to save the value(s) read
+ *         from devicetree
+ */
+static void read_u8_prop(ofnode node, char *name, size_t count, u8 *dst)
+{
+	u32 tmp;
+	const u8 *buf;
+	int ret;
+
+	if (count == 0) {
+		ret = ofnode_read_u32(node, name, &tmp);
+		if (ret == 0)
+			*dst = tmp;
+	} else {
+		buf = ofnode_read_u8_array_ptr(node, name, count);
+		if (buf)
+			memcpy(dst, buf, count);
+	}
+}
+
+/**
+ * read_u16_prop() - Read an u16 property from devicetree (scalar or array)
+ * @node:  Valid node reference to read property from
+ * @name:  Name of the property to read from
+ * @count: If the property is expected to be an array, this is the
+ *         number of expected elements
+ *         Set to 0 if the property is expected to be a scalar
+ * @dst:   Pointer to destination of where to save the value(s) read
+ *         from devicetree
+ * @return 0 on success, -ve on error
+ */
+static int read_u16_prop(ofnode node, char *name, size_t count, u16 *dst)
+{
+	u32 tmp;
+	u32 buf[32];
+	int ret;
+
+	if (ARRAY_SIZE(buf) < count) {
+		debug("ERROR: %s buffer to small!\n", __func__);
+		return -ENOSPC;
+	}
+
+	if (count == 0) {
+		ret = ofnode_read_u32(node, name, &tmp);
+		if (ret == 0)
+			*dst = tmp;
+	} else {
+		ret = ofnode_read_u32_array(node, name, buf, count);
+		if (ret == 0)
+			for (int i = 0; i < count; i++)
+				dst[i] = buf[i];
+	}
+
+	return 0;
+}
+
+/**
+ * read_u32_prop() - Read an u32 property from devicetree (scalar or array)
+ * @node:  Valid node reference to read property from
+ * @name:  Name of the property to read from
+ * @count: If the property is expected to be an array, this is the
+ *         number of expected elements
+ *         set to 0 if the property is expected to be a scalar
+ * @dst:   Pointer to destination of where to save the value(s) read
+ *         from devicetree
+ */
+static void read_u32_prop(ofnode node, char *name, size_t count, u32 *dst)
+{
+	if (count == 0)
+		ofnode_read_u32(node, name, dst);
+	else
+		ofnode_read_u32_array(node, name, dst, count);
+}
+
+/**
+ * read_string_prop() - Read a string property from devicetree
+ * @node:  Valid node reference to read property from
+ * @name:  Name of the property to read from
+ * @count: Size of the destination buffer
+ * @dst:   Pointer to destination of where to save the values read
+ *         from devicetree
+ */
+static void read_string_prop(ofnode node, char *name, size_t count, char *dst)
+{
+	const char *string_buf;
+
+	if (count > 0) {
+		string_buf = ofnode_read_string(node, name);
+		if (string_buf)
+			strlcpy(dst, string_buf, count);
+	}
+}
+
+/**
+ * read_swizzle_prop() - Read a swizzle property from devicetree
+ * @node:  Valid node reference to read property from
+ * @name:  Name of the property to read from
+ * @count: Number of elements in the swizzle configuration
+ * @dst:   pointer to destination of where to save the values read
+ *         from devicetree
+ */
+static void read_swizzle_prop(ofnode node, char *name, size_t count, u8 *dst)
+{
+	const struct lpddr4_chan_swizzle_cfg *sch;
+	/* Number of bytes to copy per DQS */
+	const size_t sz = DQ_BITS_PER_DQS;
+	const struct lpddr4_swizzle_cfg *swizzle_cfg;
+
+	swizzle_cfg = (const struct lpddr4_swizzle_cfg *)
+			ofnode_read_u8_array_ptr(node, name, count);
+
+	if (!swizzle_cfg)
+		return;
+	/*
+	 * CH0_DQB byte lanes in the bit swizzle configuration field are
+	 * not 1:1. The mapping within the swizzling field is:
+	 *   indices [0:7]   - byte lane 1 (DQS1) DQ[8:15]
+	 *   indices [8:15]  - byte lane 0 (DQS0) DQ[0:7]
+	 *   indices [16:23] - byte lane 3 (DQS3) DQ[24:31]
+	 *   indices [24:31] - byte lane 2 (DQS2) DQ[16:23]
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH0B];
+	memcpy(&dst[0 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&dst[1 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&dst[2 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS3], sz);
+	memcpy(&dst[3 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS2], sz);
+
+	/*
+	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH0A];
+	memcpy(&dst[4 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&dst[5 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&dst[6 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS2], sz);
+	memcpy(&dst[7 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS3], sz);
+
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH1B];
+	memcpy(&dst[8 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&dst[9 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&dst[10 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS3], sz);
+	memcpy(&dst[11 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS2], sz);
+
+	/*
+	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH1A];
+	memcpy(&dst[12 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&dst[13 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&dst[14 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS2], sz);
+	memcpy(&dst[15 * DQ_BITS_PER_DQS], &sch->dqs[LP4_DQS3], sz);
+}
+
+/**
+ * fsp_update_config_from_dtb() - Read FSP config from devicetree node
+ * @node: Valid node reference to read property from
+ * @cfg:  Pointer to FSP config structure
+ * @fsp_bindings: Binding describing which devicetree properties should
+ *                be stored where in the FSP configuration structure
+ *                The end of the list is declared by a NULL pointer in propname
+ * @return 0 on success, -ve on error
+ *
+ * This function reads the configuration for FSP from the provided
+ * devicetree node and saves it in the FSP configuration structure.
+ * Configuration options that are not present in the devicetree are
+ * left at their current value.
+ */
+__maybe_unused
+static int fsp_update_config_from_dtb(ofnode node, u8 *cfg,
+				      const struct fsp_binding *fsp_bindings)
+{
+	const struct fsp_binding *fspb;
+	int ret;
+
+	for (int i = 0; fsp_bindings[i].propname; i++) {
+		fspb = &fsp_bindings[i];
+
+		switch (fspb->type) {
+		case FSP_UINT8:
+			read_u8_prop(node, fspb->propname, fspb->count,
+				     &cfg[fspb->offset]);
+		break;
+		case FSP_UINT16:
+			ret = read_u16_prop(node, fspb->propname, fspb->count,
+					    (u16 *)&cfg[fspb->offset]);
+			if (ret)
+				return ret;
+		break;
+		case FSP_UINT32:
+			read_u32_prop(node, fspb->propname, fspb->count,
+				      (u32 *)&cfg[fspb->offset]);
+		break;
+		case FSP_STRING:
+			read_string_prop(node, fspb->propname, fspb->count,
+					 (char *)&cfg[fspb->offset]);
+		break;
+		case FSP_LPDDR4_SWIZZLE:
+			read_swizzle_prop(node, fspb->propname, fspb->count,
+					  &cfg[fspb->offset]);
+		break;
+		}
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_SPL_BUILD)
+const struct fsp_binding fsp_m_bindings[] = {
+	{
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, serial_debug_port_address),
+	.propname = "fspm,serial-debug-port-address",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, serial_debug_port_type),
+	.propname = "fspm,serial-debug-port-type",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, serial_debug_port_device),
+	.propname = "fspm,serial-debug-port-device",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, serial_debug_port_stride_size),
+	.propname = "fspm,serial-debug-port-stride-size",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, mrc_fast_boot),
+	.propname = "fspm,mrc-fast-boot",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, igd),
+	.propname = "fspm,igd",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, igd_dvmt50_pre_alloc),
+	.propname = "fspm,igd-dvmt50-pre-alloc",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, igd_aperture_size),
+	.propname = "fspm,igd-aperture-size",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, gtt_size),
+	.propname = "fspm,gtt-size",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, primary_video_adaptor),
+	.propname = "fspm,primary-video-adaptor",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, package),
+	.propname = "fspm,package",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, profile),
+	.propname = "fspm,profile",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, memory_down),
+	.propname = "fspm,memory-down",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, ddr3_l_page_size),
+	.propname = "fspm,ddr3-l-page-size",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, ddr3_lasr),
+	.propname = "fspm,ddr3-lasr",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, scrambler_support),
+	.propname = "fspm,scrambler-support",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, interleaved_mode),
+	.propname = "fspm,interleaved-mode",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config, channel_hash_mask),
+	.propname = "fspm,channel-hash-mask",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config, slice_hash_mask),
+	.propname = "fspm,slice-hash-mask",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, channels_slices_enable),
+	.propname = "fspm,channels-slices-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, min_ref_rate2x_enable),
+	.propname = "fspm,min-ref-rate2x-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, dual_rank_support_enable),
+	.propname = "fspm,dual-rank-support-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, rmt_mode),
+	.propname = "fspm,rmt-mode",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config, memory_size_limit),
+	.propname = "fspm,memory-size-limit",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config, low_memory_max_value),
+	.propname = "fspm,low-memory-max-value",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config, high_memory_max_value),
+	.propname = "fspm,high-memory-max-value",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, disable_fast_boot),
+	.propname = "fspm,disable-fast-boot",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, dimm0_spd_address),
+	.propname = "fspm,dimm0-spd-address",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, dimm1_spd_address),
+	.propname = "fspm,dimm1-spd-address",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].rank_enable),
+	.propname = "fspm,ch0-rank-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].device_width),
+	.propname = "fspm,ch0-device-width",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].dram_density),
+	.propname = "fspm,ch0-dram-density",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].option),
+	.propname = "fspm,ch0-option",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].odt_config),
+	.propname = "fspm,ch0-odt-config",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].tristate_clk1),
+	.propname = "fspm,ch0-tristate-clk1",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].mode2_n),
+	.propname = "fspm,ch0-mode2-n",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[0].odt_levels),
+	.propname = "fspm,ch0-odt-levels",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].rank_enable),
+	.propname = "fspm,ch1-rank-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].device_width),
+	.propname = "fspm,ch1-device-width",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].dram_density),
+	.propname = "fspm,ch1-dram-density",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].option),
+	.propname = "fspm,ch1-option",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].odt_config),
+	.propname = "fspm,ch1-odt-config",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].tristate_clk1),
+	.propname = "fspm,ch1-tristate-clk1",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].mode2_n),
+	.propname = "fspm,ch1-mode2-n",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[1].odt_levels),
+	.propname = "fspm,ch1-odt-levels",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].rank_enable),
+	.propname = "fspm,ch2-rank-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].device_width),
+	.propname = "fspm,ch2-device-width",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].dram_density),
+	.propname = "fspm,ch2-dram-density",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].option),
+	.propname = "fspm,ch2-option",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].odt_config),
+	.propname = "fspm,ch2-odt-config",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].tristate_clk1),
+	.propname = "fspm,ch2-tristate-clk1",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].mode2_n),
+	.propname = "fspm,ch2-mode2-n",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[2].odt_levels),
+	.propname = "fspm,ch2-odt-levels",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].rank_enable),
+	.propname = "fspm,ch3-rank-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].device_width),
+	.propname = "fspm,ch3-device-width",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].dram_density),
+	.propname = "fspm,ch3-dram-density",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].option),
+	.propname = "fspm,ch3-option",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].odt_config),
+	.propname = "fspm,ch3-odt-config",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].tristate_clk1),
+	.propname = "fspm,ch3-tristate-clk1",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].mode2_n),
+	.propname = "fspm,ch3-mode2-n",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, chan[3].odt_levels),
+	.propname = "fspm,ch3-odt-levels",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, rmt_check_run),
+	.propname = "fspm,rmt-check-run",
+	}, {
+	.type = FSP_UINT16,
+	.offset = offsetof(struct fsp_m_config,
+			   rmt_margin_check_scale_high_threshold),
+	.propname = "fspm,rmt-margin-check-scale-high-threshold",
+	}, {
+	.type = FSP_LPDDR4_SWIZZLE,
+	.offset = offsetof(struct fsp_m_config, ch_bit_swizzling),
+	.propname = "fspm,ch-bit-swizzling",
+	.count = SIZE_OF_MEMBER(struct fsp_m_config, ch_bit_swizzling) /
+		 SIZE_OF_MEMBER(struct fsp_m_config, ch_bit_swizzling[0][0])
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, msg_level_mask),
+	.propname = "fspm,msg-level-mask",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pre_mem_gpio_table_pin_num),
+	.propname = "fspm,pre-mem-gpio-table-pin-num",
+	.count = ARRAY_SIZE_OF_MEMBER(struct fsp_m_config,
+				      pre_mem_gpio_table_pin_num),
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, pre_mem_gpio_table_ptr),
+	.propname = "fspm,pre-mem-gpio-table-ptr",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pre_mem_gpio_table_entry_num),
+	.propname = "fspm,pre-mem-gpio-table-entry-num",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, enhance_port8xh_decoding),
+	.propname = "fspm,enhance-port8xh-decoding",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, spd_write_enable),
+	.propname = "fspm,spd-write-enable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, mrc_data_saving),
+	.propname = "fspm,mrc-data-saving",
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, oem_loading_base),
+	.propname = "fspm,oem-loading-base",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, oem_file_name),
+	.propname = "fspm,oem-file-name",
+	.count = ARRAY_SIZE_OF_MEMBER(struct fsp_m_config, oem_file_name),
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, mrc_boot_data_ptr),
+	.propname = "fspm,mrc-boot-data-ptr",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, e_mmc_trace_len),
+	.propname = "fspm,e-mmc-trace-len",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, skip_cse_rbp),
+	.propname = "fspm,skip-cse-rbp",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, npk_en),
+	.propname = "fspm,npk-en",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, fw_trace_en),
+	.propname = "fspm,fw-trace-en",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, fw_trace_destination),
+	.propname = "fspm,fw-trace-destination",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, recover_dump),
+	.propname = "fspm,recover-dump",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, msc0_wrap),
+	.propname = "fspm,msc0-wrap",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, msc1_wrap),
+	.propname = "fspm,msc1-wrap",
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, msc0_size),
+	.propname = "fspm,msc0-size",
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, msc1_size),
+	.propname = "fspm,msc1-size",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pti_mode),
+	.propname = "fspm,pti-mode",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pti_training),
+	.propname = "fspm,pti-training",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pti_speed),
+	.propname = "fspm,pti-speed",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, punit_mlvl),
+	.propname = "fspm,punit-mlvl",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, pmc_mlvl),
+	.propname = "fspm,pmc-mlvl",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, sw_trace_en),
+	.propname = "fspm,sw-trace-en",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, periodic_retraining_disable),
+	.propname = "fspm,periodic-retraining-disable",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, enable_reset_system),
+	.propname = "fspm,enable-reset-system",
+	}, {
+	.type = FSP_UINT8,
+	.offset = offsetof(struct fsp_m_config, enable_s3_heci2),
+	.propname = "fspm,enable-s3-heci2",
+	}, {
+	.type = FSP_UINT32,
+	.offset = offsetof(struct fsp_m_config, variable_nvs_buffer_ptr),
+	.propname = "fspm,variable-nvs-buffer-ptr",
+	}, {
+	.propname = NULL
+	}
+};
+
+int fsp_m_update_config_from_dtb(ofnode node, struct fsp_m_config *cfg)
+{
+	return fsp_update_config_from_dtb(node, (u8 *)cfg, fsp_m_bindings);
+}
+#endif
diff --git a/arch/x86/cpu/apollolake/fsp_m.c b/arch/x86/cpu/apollolake/fsp_m.c
index 56ce59d..1301100 100644
--- a/arch/x86/cpu/apollolake/fsp_m.c
+++ b/arch/x86/cpu/apollolake/fsp_m.c
@@ -8,184 +8,27 @@
 #include <dm.h>
 #include <log.h>
 #include <asm/arch/iomap.h>
-#include <asm/arch/fsp/fsp_configs.h>
-#include <asm/arch/fsp/fsp_m_upd.h>
+#include <asm/arch/fsp_bindings.h>
 #include <asm/fsp2/fsp_internal.h>
 #include <dm/uclass-internal.h>
 
-/*
- * ODT settings:
- * If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A and HIGH for ODT_B,
- * choose ODT_A_B_HIGH_HIGH. If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A
- * and LOW for ODT_B, choose ODT_A_B_HIGH_LOW.
- *
- * Note that the enum values correspond to the interpreted UPD fields
- * within Ch[3:0]_OdtConfig parameters.
- */
-enum {
-	ODT_A_B_HIGH_LOW	= 0 << 1,
-	ODT_A_B_HIGH_HIGH	= 1 << 1,
-	N_WR_24			= 1 << 5,
-};
-
-/*
- * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation.
- * There are four physical LPDDR4 channels, each 32-bits wide. There are two
- * logical channels using two physical channels together to form a 64-bit
- * interface to memory for each logical channel.
- */
-
-enum {
-	LP4_PHYS_CH0A,
-	LP4_PHYS_CH0B,
-	LP4_PHYS_CH1A,
-	LP4_PHYS_CH1B,
-
-	LP4_NUM_PHYS_CHANNELS,
-};
-
-/*
- * The DQs within a physical channel can be bit-swizzled within each byte.
- * Within a channel the bytes can be swapped, but the DQs need to be routed
- * with the corresponding DQS (strobe).
- */
-enum {
-	LP4_DQS0,
-	LP4_DQS1,
-	LP4_DQS2,
-	LP4_DQS3,
-
-	LP4_NUM_BYTE_LANES,
-	DQ_BITS_PER_DQS		= 8,
-};
-
-/* Provide bit swizzling per DQS and byte swapping within a channel */
-struct lpddr4_chan_swizzle_cfg {
-	u8 dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS];
-};
-
-struct lpddr4_swizzle_cfg {
-	struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS];
-};
-
-static void setup_sdram(struct fsp_m_config *cfg,
-			const struct lpddr4_swizzle_cfg *swizzle_cfg)
-{
-	const struct lpddr4_chan_swizzle_cfg *sch;
-	/* Number of bytes to copy per DQS */
-	const size_t sz = DQ_BITS_PER_DQS;
-	int chan;
-
-	cfg->memory_down = 1;
-	cfg->scrambler_support = 1;
-	cfg->channel_hash_mask = 0x36;
-	cfg->slice_hash_mask = 9;
-	cfg->interleaved_mode = 2;
-	cfg->channels_slices_enable = 0;
-	cfg->min_ref_rate2x_enable = 0;
-	cfg->dual_rank_support_enable = 1;
-
-	/* LPDDR4 is memory down so no SPD addresses */
-	cfg->dimm0_spd_address = 0;
-	cfg->dimm1_spd_address = 0;
-
-	for (chan = 0; chan < 4; chan++) {
-		struct fsp_ram_channel *ch = &cfg->chan[chan];
-
-		ch->rank_enable = 1;
-		ch->device_width = 1;
-		ch->dram_density = 2;
-		ch->option = 3;
-		ch->odt_config = ODT_A_B_HIGH_HIGH;
-	}
-
-	/*
-	 * CH0_DQB byte lanes in the bit swizzle configuration field are
-	 * not 1:1. The mapping within the swizzling field is:
-	 *   indices [0:7]   - byte lane 1 (DQS1) DQ[8:15]
-	 *   indices [8:15]  - byte lane 0 (DQS0) DQ[0:7]
-	 *   indices [16:23] - byte lane 3 (DQS3) DQ[24:31]
-	 *   indices [24:31] - byte lane 2 (DQS2) DQ[16:23]
-	 */
-	sch = &swizzle_cfg->phys[LP4_PHYS_CH0B];
-	memcpy(&cfg->ch_bit_swizzling[0][0], &sch->dqs[LP4_DQS1], sz);
-	memcpy(&cfg->ch_bit_swizzling[0][8], &sch->dqs[LP4_DQS0], sz);
-	memcpy(&cfg->ch_bit_swizzling[0][16], &sch->dqs[LP4_DQS3], sz);
-	memcpy(&cfg->ch_bit_swizzling[0][24], &sch->dqs[LP4_DQS2], sz);
-
-	/*
-	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
-	 */
-	sch = &swizzle_cfg->phys[LP4_PHYS_CH0A];
-	memcpy(&cfg->ch_bit_swizzling[1][0], &sch->dqs[LP4_DQS0], sz);
-	memcpy(&cfg->ch_bit_swizzling[1][8], &sch->dqs[LP4_DQS1], sz);
-	memcpy(&cfg->ch_bit_swizzling[1][16], &sch->dqs[LP4_DQS2], sz);
-	memcpy(&cfg->ch_bit_swizzling[1][24], &sch->dqs[LP4_DQS3], sz);
-
-	sch = &swizzle_cfg->phys[LP4_PHYS_CH1B];
-	memcpy(&cfg->ch_bit_swizzling[2][0], &sch->dqs[LP4_DQS1], sz);
-	memcpy(&cfg->ch_bit_swizzling[2][8], &sch->dqs[LP4_DQS0], sz);
-	memcpy(&cfg->ch_bit_swizzling[2][16], &sch->dqs[LP4_DQS3], sz);
-	memcpy(&cfg->ch_bit_swizzling[2][24], &sch->dqs[LP4_DQS2], sz);
-
-	/*
-	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
-	 */
-	sch = &swizzle_cfg->phys[LP4_PHYS_CH1A];
-	memcpy(&cfg->ch_bit_swizzling[3][0], &sch->dqs[LP4_DQS0], sz);
-	memcpy(&cfg->ch_bit_swizzling[3][8], &sch->dqs[LP4_DQS1], sz);
-	memcpy(&cfg->ch_bit_swizzling[3][16], &sch->dqs[LP4_DQS2], sz);
-	memcpy(&cfg->ch_bit_swizzling[3][24], &sch->dqs[LP4_DQS3], sz);
-}
-
 int fspm_update_config(struct udevice *dev, struct fspm_upd *upd)
 {
 	struct fsp_m_config *cfg = &upd->config;
 	struct fspm_arch_upd *arch = &upd->arch;
+	ofnode node;
 
 	arch->nvs_buffer_ptr = NULL;
 	prepare_mrc_cache(upd);
 	arch->stack_base = (void *)0xfef96000;
 	arch->boot_loader_tolum_size = 0;
-
 	arch->boot_mode = FSP_BOOT_WITH_FULL_CONFIGURATION;
-	cfg->serial_debug_port_type = 2;
-	cfg->serial_debug_port_device = 2;
-	cfg->serial_debug_port_stride_size = 2;
-	cfg->serial_debug_port_address = 0;
-
-	cfg->package = 1;
-	/* Don't enforce a memory size limit */
-	cfg->memory_size_limit = 0;
-	cfg->low_memory_max_value = 2048;  /* 2 GB */
-	/* No restrictions on memory above 4GiB */
-	cfg->high_memory_max_value = 0;
 
-	/* Always default to attempt to use saved training data */
-	cfg->disable_fast_boot = 0;
-
-	const u8 *swizzle_data;
-
-	swizzle_data = dev_read_u8_array_ptr(dev, "lpddr4-swizzle",
-					     LP4_NUM_BYTE_LANES *
-					     DQ_BITS_PER_DQS *
-					     LP4_NUM_PHYS_CHANNELS);
-	if (!swizzle_data)
-		return log_msg_ret("Cannot read swizzel data", -EINVAL);
-
-	setup_sdram(cfg, (struct lpddr4_swizzle_cfg *)swizzle_data);
-
-	cfg->pre_mem_gpio_table_ptr = 0;
-
-	cfg->profile = 0xb;
-	cfg->msg_level_mask = 0;
-
-	/* other */
-	cfg->skip_cse_rbp = 1;
-	cfg->periodic_retraining_disable = 0;
-	cfg->enable_s3_heci2 = 0;
+	node = dev_ofnode(dev);
+	if (!ofnode_valid(node))
+		return log_msg_ret("fsp-m settings", -ENOENT);
 
-	return 0;
+	return fsp_m_update_config_from_dtb(node, cfg);
 }
 
 /*
diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts
index d48ef35..a34e2d7 100644
--- a/arch/x86/dts/chromebook_coral.dts
+++ b/arch/x86/dts/chromebook_coral.dts
@@ -21,6 +21,7 @@
 #include <asm/arch-apollolake/iomap.h>
 #include <asm/arch-apollolake/pm.h>
 #include <dt-bindings/clock/intel-clock.h>
+#include <asm/arch-apollolake/fsp/fsp_m_upd.h>
 
 / {
 	model = "Google Coral";
@@ -436,7 +437,42 @@
 		PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */
 		>;
 
-	lpddr4-swizzle = /bits/ 8 <
+	fspm,package = <PACKAGE_BGA>;
+	fspm,profile = <PROFILE_LPDDR4_2400_24_22_22>;
+	fspm,memory-down = <MEMORY_DOWN_YES>;
+	fspm,scrambler-support = <1>;
+	fspm,interleaved-mode = <INTERLEAVED_MODE_ENABLE>;
+	fspm,channel-hash-mask = <0x36>;
+	fspm,slice-hash-mask = <0x9>;
+	fspm,dual-rank-support-enable = <1>;
+	fspm,low-memory-max-value = <2048>;
+	fspm,ch0-rank-enable = <1>;
+	fspm,ch0-device-width = <CHX_DEVICE_WIDTH_X16>;
+	fspm,ch0-dram-density = <CHX_DEVICE_DENSITY_8GB>;
+	fspm,ch0-option = <(CHX_OPTION_RANK_INTERLEAVING |
+			   CHX_OPTION_BANK_ADDRESS_HASHING_ENABLE)>;
+	fspm,ch0-odt-config = <CHX_ODT_CONFIG_DDR4_CA_ODT>;
+	fspm,ch1-rank-enable = <1>;
+	fspm,ch1-device-width = <CHX_DEVICE_WIDTH_X16>;
+	fspm,ch1-dram-density = <CHX_DEVICE_DENSITY_8GB>;
+	fspm,ch1-option = <(CHX_OPTION_RANK_INTERLEAVING |
+			   CHX_OPTION_BANK_ADDRESS_HASHING_ENABLE)>;
+	fspm,ch1-odt-config = <CHX_ODT_CONFIG_DDR4_CA_ODT>;
+	fspm,ch2-rank-enable = <1>;
+	fspm,ch2-device-width = <CHX_DEVICE_WIDTH_X16>;
+	fspm,ch2-dram-density = <CHX_DEVICE_DENSITY_8GB>;
+	fspm,ch2-option = <(CHX_OPTION_RANK_INTERLEAVING |
+			   CHX_OPTION_BANK_ADDRESS_HASHING_ENABLE)>;
+	fspm,ch2-odt-config = <CHX_ODT_CONFIG_DDR4_CA_ODT>;
+	fspm,ch3-rank-enable = <1>;
+	fspm,ch3-device-width = <CHX_DEVICE_WIDTH_X16>;
+	fspm,ch3-dram-density = <CHX_DEVICE_DENSITY_8GB>;
+	fspm,ch3-option = <(CHX_OPTION_RANK_INTERLEAVING |
+			   CHX_OPTION_BANK_ADDRESS_HASHING_ENABLE)>;
+	fspm,ch3-odt-config = <CHX_ODT_CONFIG_DDR4_CA_ODT>;
+	fspm,fspm,skip-cse-rbp = <1>;
+
+	fspm,ch-bit-swizzling = /bits/ 8 <
 		/* LP4_PHYS_CH0A */
 
 		/* DQA[0:7] pins of LPDDR4 module */
diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h
index 93bee5b..a77964f 100644
--- a/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h
+++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h
@@ -7,6 +7,7 @@
 #ifndef	__ASM_ARCH_FSP_M_UDP_H
 #define	__ASM_ARCH_FSP_M_UDP_H
 
+#ifndef __ASSEMBLY__
 #include <asm/fsp2/fsp_api.h>
 
 #define FSP_DRAM_CHANNELS	4
@@ -119,5 +120,172 @@
 	u8 unused_upd_space2[158];
 	u16 upd_terminator;
 };
+#endif
+
+#define SERIAL_DEBUG_PORT_TYPE_NONE 0
+#define SERIAL_DEBUG_PORT_TYPE_IO 1
+#define SERIAL_DEBUG_PORT_TYPE_MMIO 2
+
+#define SERIAL_DEBUG_PORT_DEVICE_UART0 0
+#define SERIAL_DEBUG_PORT_DEVICE_UART1 1
+#define SERIAL_DEBUG_PORT_DEVICE_UART2 2
+#define SERIAL_DEBUG_PORT_DEVICE_EXTERNAL 3
+
+#define SERIAL_DEBUG_PORT_STRIDE_SIZE_1 0
+#define SERIAL_DEBUG_PORT_STRIDE_SIZE_4 2
+
+#define IGD_DVMT_50_PRE_ALLOC_64M 0x02
+#define IGD_DVMT_50_PRE_ALLOC_96M 0x03
+#define IGD_DVMT_50_PRE_ALLOC_128M 0x04
+#define IGD_DVMT_50_PRE_ALLOC_160M 0x05
+#define IGD_DVMT_50_PRE_ALLOC_192M 0x06
+#define IGD_DVMT_50_PRE_ALLOC_224M 0x07
+#define IGD_DVMT_50_PRE_ALLOC_256M 0x08
+#define IGD_DVMT_50_PRE_ALLOC_288M 0x09
+#define IGD_DVMT_50_PRE_ALLOC_320M 0x0a
+#define IGD_DVMT_50_PRE_ALLOC_352M 0x0b
+#define IGD_DVMT_50_PRE_ALLOC_384M 0x0c
+#define IGD_DVMT_50_PRE_ALLOC_416M 0x0d
+#define IGD_DVMT_50_PRE_ALLOC_448M 0x0e
+#define IGD_DVMT_50_PRE_ALLOC_480M 0x0f
+#define IGD_DVMT_50_PRE_ALLOC_512M 0x10
+
+#define IGD_APERTURE_SIZE_128M 0x1
+#define IGD_APERTURE_SIZE_256M 0x2
+#define IGD_APERTURE_SIZE_512M 0x3
+
+#define GTT_SIZE_2M 1
+#define GTT_SIZE_4M 2
+#define GTT_SIZE_8M 3
+
+#define PRIMARY_VIDEO_ADAPTER_AUTO 0
+#define PRIMARY_VIDEO_ADAPTER_IGD 2
+#define PRIMARY_VIDEO_ADAPTER_PCI 3
+
+#define PACKAGE_SODIMM 0
+#define PACKAGE_BGA 1
+#define PACKAGE_BGA_MIRRORED 2
+#define PACKAGE_SODIMM_UDIMM_RANK_MIRRORED 3
+
+#define PROFILE_WIO2_800_7_8_8 0x1
+#define PROFILE_WIO2_1066_9_10_10 0x2
+#define PROFILE_LPDDR3_1066_8_10_10 0x3
+#define PROFILE_LPDDR3_1333_10_12_12 0x4
+#define PROFILE_LPDDR3_1600_12_15_15 0x5
+#define PROFILE_LPDDR3_1866_14_17_17 0x6
+#define PROFILE_LPDDR3_2133_16_20_20 0x7
+#define PROFILE_LPDDR4_1066_10_10_10 0x8
+#define PROFILE_LPDDR4_1600_14_15_15 0x9
+#define PROFILE_LPDDR4_2133_20_20_20 0xa
+#define PROFILE_LPDDR4_2400_24_22_22 0xb
+#define PROFILE_LPDDR4_2666_24_24_24 0xc
+#define PROFILE_LPDDR4_2933_28_27_27 0xd
+#define PROFILE_LPDDR4_3200_28_29_29 0xe
+#define PROFILE_DDR3_1066_6_6_6 0xf
+#define PROFILE_DDR3_1066_7_7_7 0x10
+#define PROFILE_DDR3_1066_8_8_8 0x11
+#define PROFILE_DDR3_1333_7_7_7 0x12
+#define PROFILE_DDR3_1333_8_8_8 0x13
+#define PROFILE_DDR3_1333_9_9_9 0x14
+#define PROFILE_DDR3_1333_10_10_10 0x15
+#define PROFILE_DDR3_1600_8_8_8 0x16
+#define PROFILE_DDR3_1600_9_9_9 0x17
+#define PROFILE_DDR3_1600_10_10_10 0x18
+#define PROFILE_DDR3_1600_11_11_11 0x19
+#define PROFILE_DDR3_1866_10_10_10 0x1a
+#define PROFILE_DDR3_1866_11_11_11 0x1b
+#define PROFILE_DDR3_1866_12_12_12 0x1c
+#define PROFILE_DDR3_1866_13_13_13 0x1d
+#define PROFILE_DDR3_2133_11_11_11 0x1e
+#define PROFILE_DDR3_2133_12_12_12 0x1f
+#define PROFILE_DDR3_2133_13_13_13 0x20
+#define PROFILE_DDR3_2133_14_14_14 0x21
+#define PROFILE_DDR4_1333_10_10_10 0x22
+#define PROFILE_DDR4_1600_10_10_10 0x23
+#define PROFILE_DDR4_1600_11_11_11 0x24
+#define PROFILE_DDR4_1600_12_12_12 0x25
+#define PROFILE_DDR4_1866_12_12_12 0x26
+#define PROFILE_DDR4_1866_13_13_13 0x27
+#define PROFILE_DDR4_1866_14_14_14 0x28
+#define PROFILE_DDR4_2133_14_14_14 0x29
+#define PROFILE_DDR4_2133_15_15_15 0x2a
+#define PROFILE_DDR4_2133_16_16_16 0x2b
+#define PROFILE_DDR4_2400_15_15_15 0x2c
+#define PROFILE_DDR4_2400_16_16_16 0x2d
+#define PROFILE_DDR4_2400_17_17_17 0x2e
+#define PROFILE_DDR4_2400_18_18_18 0x2f
+
+#define MEMORY_DOWN_NO 0
+#define MEMORY_DOWN_YES 1
+#define MEMORY_DOWN_MD_SODIMM 2
+#define MEMORY_DOWN_LPDDR4 3
+
+#define DDR3L_PAGE_SIZE_1KB 1
+#define DDR3L_PAGE_SIZE_2KB 2
+
+#define INTERLEAVED_MODE_DISABLE 0
+#define INTERLEAVED_MODE_ENABLE 2
+
+#define RMT_MODE_DISABLE 0
+#define RMT_MODE_ENABLE 3
+
+#define CHX_DEVICE_WIDTH_X8 0
+#define CHX_DEVICE_WIDTH_X16 1
+#define CHX_DEVICE_WIDTH_X32 2
+#define CHX_DEVICE_WIDTH_X64 3
+
+#define CHX_DEVICE_DENSITY_4GB 0
+#define CHX_DEVICE_DENSITY_6GB 1
+#define CHX_DEVICE_DENSITY_8GB 2
+#define CHX_DEVICE_DENSITY_12GB 3
+#define CHX_DEVICE_DENSITY_16GB 4
+#define CHX_DEVICE_DENSITY_2GB 5
+
+#define CHX_OPTION_RANK_INTERLEAVING 0x1
+#define CHX_OPTION_BANK_ADDRESS_HASHING_ENABLE 0x2
+#define CHX_OPTION_CH1_CLK_DISABLE 0x4
+#define CHX_OPTION_ADDRESS_MAP_2KB 0x10
+
+#define CHX_ODT_CONFIG_DDR3_RX_ODT 0x1
+#define CHX_ODT_CONFIG_DDR4_CA_ODT 0x2
+#define CHX_ODT_CONFIG_DDR3L_TX_ODT 0x10
+
+#define CHX_MODE2N_AUTO 0
+#define CHX_MODE2N_FORCE 1
+
+#define CHX_ODT_LEVELS_CONNECTED_TO_SOC 0x0
+#define CHX_ODT_LEVELS_HELD_HIGH 0x1
+
+#define NPK_EN_DISABLE 0
+#define NPK_EN_ENABLE 1
+#define NPK_EN_DEBUGGER 2
+#define NPK_EN_AUTO 3
+
+#define FW_TRACE_DESTINATION_NPK_TRACE_TO_MEMORY 1
+#define FW_TRACE_DESTINATION_NPK_TRACE_TO_DCI 2
+#define FW_TRACE_DESTINATION_NPK_NPK_TRACE_TO_BSSB 3
+#define FW_TRACE_DESTINATION_NPK_TRACE_TO_PTI 4
+
+#define MSC_X_WRAP_0 0
+#define MSC_X_WRAP_1 1
+
+#define MSC_X_SIZE_0M 0
+#define MSC_X_SIZE_1M 1
+#define MSC_X_SIZE_8M 2
+#define MSC_X_SIZE_64M 3
+#define MSC_X_SIZE_128M 4
+#define MSC_X_SIZE_256M 5
+#define MSC_X_SIZE_512M 6
+#define MSC_X_SIZE_1GB 7
+
+#define PTI_MODE_0 0
+#define PTI_MODE_x4 1
+#define PTI_MODE_x8 2
+#define PTI_MODE_x12 3
+#define PTI_MODE_x16 4
+
+#define PTI_SPEED_FULL 0
+#define PTI_SPEED_HALF 1
+#define PTI_SPEED_QUARTER 2
 
 #endif
diff --git a/arch/x86/include/asm/arch-apollolake/fsp_bindings.h b/arch/x86/include/asm/arch-apollolake/fsp_bindings.h
new file mode 100644
index 0000000..7f778ea
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/fsp_bindings.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ * Copyright 2020 B&R Industrial Automation GmbH - http://www.br-automation.com
+ */
+
+#ifndef __ASM_ARCH_FSP_BINDINGS_H
+#define __ASM_ARCH_FSP_BINDINGS_H
+
+#include <asm/arch/fsp/fsp_m_upd.h>
+
+#define ARRAY_SIZE_OF_MEMBER(s, m) (ARRAY_SIZE((((s *)0)->m)))
+#define SIZE_OF_MEMBER(s, m) (sizeof((((s *)0)->m)))
+
+enum conf_type {
+	FSP_UINT8,
+	FSP_UINT16,
+	FSP_UINT32,
+	FSP_STRING,
+	FSP_LPDDR4_SWIZZLE,
+};
+
+/**
+ * struct fsp_binding - Binding describing devicetree/FSP relationships
+ * @offset:   Offset within the FSP config structure
+ * @propname: Name of property to read
+ * @type:     Type of the property to read
+ * @count:    If the property is expected to be an array, this is the
+ *            number of expected elements
+ *            Set to 0 if the property is expected to be a scalar
+ *
+ * The struct fsp_binding is used to describe the relationship between
+ * values stored in devicetree and where they are placed in the FSP
+ * configuration structure.
+ */
+struct fsp_binding {
+	size_t offset;
+	char *propname;
+	enum conf_type type;
+	size_t count;
+};
+
+/*
+ * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation.
+ * There are four physical LPDDR4 channels, each 32-bits wide. There are two
+ * logical channels using two physical channels together to form a 64-bit
+ * interface to memory for each logical channel.
+ */
+
+enum {
+	LP4_PHYS_CH0A,
+	LP4_PHYS_CH0B,
+	LP4_PHYS_CH1A,
+	LP4_PHYS_CH1B,
+
+	LP4_NUM_PHYS_CHANNELS,
+};
+
+/*
+ * The DQs within a physical channel can be bit-swizzled within each byte.
+ * Within a channel the bytes can be swapped, but the DQs need to be routed
+ * with the corresponding DQS (strobe).
+ */
+enum {
+	LP4_DQS0,
+	LP4_DQS1,
+	LP4_DQS2,
+	LP4_DQS3,
+
+	LP4_NUM_BYTE_LANES,
+	DQ_BITS_PER_DQS		= 8,
+};
+
+/* Provide bit swizzling per DQS and byte swapping within a channel */
+struct lpddr4_chan_swizzle_cfg {
+	u8 dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS];
+};
+
+struct lpddr4_swizzle_cfg {
+	struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS];
+};
+
+/**
+ * fsp_m_update_config_from_dtb() - Read FSP-M config from devicetree node
+ * @node: Valid node reference to read property from
+ * @cfg:  Pointer to FSP-M config structure
+ * @return 0 on success, -ve on error
+ *
+ * This function reads the configuration for FSP-M from the provided
+ * devicetree node and saves it in the FSP-M configuration structure.
+ * Configuration options that are not present in the devicetree are
+ * left at their current value.
+ */
+int fsp_m_update_config_from_dtb(ofnode node, struct fsp_m_config *cfg);
+
+#endif