fizz: Enable ddr4 DRAM support

First step in enabling mosys for Fizz with
DDR4.

BUG=b:37674370
BRANCH=None
TEST=mosys memory spd print all
     mosys memory spd dump 0

Change-Id: I2713089ce91232862726d4c4ef81a2c1077419b7
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/503550
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
diff --git a/configs/x86_defconfig b/configs/x86_defconfig
index f1113ed..bc92283 100644
--- a/configs/x86_defconfig
+++ b/configs/x86_defconfig
@@ -36,6 +36,7 @@
 CONFIG_PLATFORM_AURON=y
 CONFIG_PLATFORM_BELTINO=y
 CONFIG_PLATFORM_CYAN=y
+CONFIG_PLATFORM_FIZZ=y
 CONFIG_PLATFORM_GLADOS=y
 CONFIG_PLATFORM_LINK=y
 CONFIG_PLATFORM_MARIO=y
diff --git a/include/lib/ddr4.h b/include/lib/ddr4.h
new file mode 100644
index 0000000..9072bf3
--- /dev/null
+++ b/include/lib/ddr4.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * DDR4 register map.
+ */
+
+#ifndef LIB_DDR4_H_
+#define LIB_DDR4_H_
+
+enum ddr4_reg_map {
+	/* Base Configuration and DRAM Parameters */
+	DDR4_SPD_REG_SIZE_CRC,
+	DDR4_SPD_REG_REVISION,
+	DDR4_SPD_REG_DEVICE_TYPE,
+	DDR4_SPD_REG_MODULE_TYPE,
+	DDR4_SPD_REG_DENSITY_BANKS,
+	DDR4_SPD_REG_ADDRESSING,
+	DDR4_SPD_REG_VOLTAGE = 11,
+	DDR4_SPD_REG_MODULE_ORG,
+	DDR4_SPD_REG_MODULE_BUS_WIDTH,
+	DDR4_SPD_REG_FTB_MTB_TIMEBASE = 17,
+	DDR4_SPD_REG_TCK_MIN = 18,
+	DDR4_SPD_REG_FINE_OFFSET_TCK_MIN = 125,
+	DDR4_SPD_REG_CRC_0,
+	DDR4_SPD_REG_CRC_1,
+	/* Manufacturing Information */
+	DDR4_SPD_REG_MODULE_MANUF_JEDEC_ID_LSB = 320,
+	DDR4_SPD_REG_MODULE_MANUF_JEDEC_ID_MSB,
+	DDR4_SPD_REG_MODULE_MANUF_LOC,
+	DDR4_SPD_REG_MODULE_MANUF_DATE_YEAR,
+	DDR4_SPD_REG_MODULE_MANUF_DATE_WEEK,
+	DDR4_SPD_REG_MODULE_MANUF_SERIAL_0,
+	DDR4_SPD_REG_MODULE_MANUF_SERIAL_1,
+	DDR4_SPD_REG_MODULE_MANUF_SERIAL_2,
+	DDR4_SPD_REG_MODULE_MANUF_SERIAL_3,
+	DDR4_SPD_REG_MODULE_PART_NUM_0,
+	DDR4_SPD_REG_MODULE_PART_NUM_1,
+	DDR4_SPD_REG_MODULE_PART_NUM_2,
+	DDR4_SPD_REG_MODULE_PART_NUM_3,
+	DDR4_SPD_REG_MODULE_PART_NUM_4,
+	DDR4_SPD_REG_MODULE_PART_NUM_5,
+	DDR4_SPD_REG_MODULE_PART_NUM_6,
+	DDR4_SPD_REG_MODULE_PART_NUM_7,
+	DDR4_SPD_REG_MODULE_PART_NUM_8,
+	DDR4_SPD_REG_MODULE_PART_NUM_9,
+	DDR4_SPD_REG_MODULE_PART_NUM_10,
+	DDR4_SPD_REG_MODULE_PART_NUM_11,
+	DDR4_SPD_REG_MODULE_PART_NUM_12,
+	DDR4_SPD_REG_MODULE_PART_NUM_13,
+	DDR4_SPD_REG_MODULE_PART_NUM_14,
+	DDR4_SPD_REG_MODULE_PART_NUM_15,
+	DDR4_SPD_REG_MODULE_PART_NUM_16,
+	DDR4_SPD_REG_MODULE_PART_NUM_17,
+	DDR4_SPD_REG_MODULE_REVISION_0,
+	DDR4_SPD_REG_DRAM_MANUF_JEDEC_ID_LSB,
+	DDR4_SPD_REG_DRAM_MANUF_JEDEC_ID_MSB,
+};
+
+#endif /* LIB_DDR4_H_ */
diff --git a/include/lib/spd.h b/include/lib/spd.h
index 2722622..5fba093 100644
--- a/include/lib/spd.h
+++ b/include/lib/spd.h
@@ -41,7 +41,7 @@
 
 #define SPD_READ          0
 #define SPD_WRITE         1
-#define SPD_MAX_LENGTH    256
+#define SPD_MAX_LENGTH    384
 
 /* forward declarations */
 struct kv_pair;
@@ -55,6 +55,7 @@
 	SPD_DRAM_TYPE_FBDIMM	= 0x09,
 	SPD_DRAM_TYPE_DDR3	= 0x0b,
 	SPD_DRAM_TYPE_LPDDR3	= 0xf1,
+	SPD_DRAM_TYPE_DDR4      = 0x0c,
 	SPD_DRAM_TYPE_LPDDR4	= 0x10,
 };
 
@@ -338,6 +339,22 @@
                                 const void *data, enum spd_field_type type);
 
 /*
+ * spd_print_field_ddr4  -  add common DDR SPD fields into key=value pair
+ *
+ * @intf:       platform interface
+ * @kv:         key=value pair
+ * @data:       raw spd data
+ * @type:       type of field to retrieve
+ *
+ * returns 1 to indicate data added to key=value pair
+ * returns 0 to indicate no data added
+ * returns <0 to indicate error
+ *
+ */
+extern int spd_print_field_ddr4(struct platform_intf *intf, struct kv_pair *kv,
+                                const void *data, enum spd_field_type type);
+
+/*
  * spd_read_from_cbfs  -  retrieve SPD info from CBFS
  *
  * @intf:	platform interface
diff --git a/intf/i2c.c b/intf/i2c.c
index cfc455d..06acd23 100644
--- a/intf/i2c.c
+++ b/intf/i2c.c
@@ -50,6 +50,7 @@
 
 #include "lib/math.h"
 #include "lib/string.h"
+#include "lib/spd.h"
 
 /* these are exposed only to make testing easier */
 #define I2C_DEV_ROOT	"/dev"
@@ -216,8 +217,7 @@
 	int32_t result;
 	static int read_words = 1;
 
-	/* limit to 256 bytes at a time */
-	if (length < 1 || length > 256) {
+	if (length < 1 || length > SPD_MAX_LENGTH) {
 		lprintf(LOG_NOTICE, "Invalid I2C read length: %d\n", length);
 		return -1;
 	}
diff --git a/lib/spd/Makefile b/lib/spd/Makefile
index 00688ae..e4f622f 100644
--- a/lib/spd/Makefile
+++ b/lib/spd/Makefile
@@ -1,6 +1,7 @@
 #obj-y		+= ddr1.o
 obj-y		+= ddr2.o
 obj-y		+= ddr3.o
+obj-y		+= ddr4.o
 #obj-y		+= fbdimm.o
 obj-y		+= nonspd.o
 obj-y		+= nonspd_modules.o
diff --git a/lib/spd/ddr4.c b/lib/spd/ddr4.c
new file mode 100644
index 0000000..e9279bd
--- /dev/null
+++ b/lib/spd/ddr4.c
@@ -0,0 +1,287 @@
+/* Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * DDR4 field access for DDR4 SPDs.
+ */
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <valstr.h>
+
+#include "mosys/platform.h"
+#include "mosys/kv_pair.h"
+#include "mosys/log.h"
+
+#include "lib/string.h"
+
+#include "lib/ddr4.h"
+#include "lib/spd.h"
+
+#include "jedec_id.h"
+
+/*
+ * spd_print_field_ddr4  -  add common DDR SPD fields into key=value pair
+ *
+ * @intf:       platform interface
+ * @kv:         key=value pair
+ * @data:       raw spd data
+ * @type:       type of field to retrieve
+ *
+ * returns 1 to indicate data added to key=value pair
+ * returns 0 to indicate no data added
+ * returns <0 to indicate error
+ *
+ */
+int spd_print_field_ddr4(struct platform_intf *intf, struct kv_pair *kv,
+                         const void *data, enum spd_field_type type)
+{
+	int ret;
+	const uint8_t *byte = data;
+
+	ret =  0;
+	switch (type) {
+	case SPD_GET_DRAM_TYPE:
+		kv_pair_add(kv, "dram",
+			    (byte[DDR4_SPD_REG_DEVICE_TYPE] ==
+			     SPD_DRAM_TYPE_LPDDR4) ? "LPDDR4" : "DDR4");
+		ret = 1;
+		break;
+	case SPD_GET_MODULE_TYPE:
+		kv_pair_add(kv, "module",
+		            val2str(byte[DDR4_SPD_REG_MODULE_TYPE],
+		            ddr3_module_type_lut));
+		ret = 1;
+		break;
+	case SPD_GET_MFG_ID:
+	{
+		uint8_t manuf_lsb;
+		uint8_t manuf_msb;
+		const char *tstr;
+
+		manuf_lsb = byte[DDR4_SPD_REG_MODULE_MANUF_JEDEC_ID_LSB] & 0x7f;
+		manuf_msb = byte[DDR4_SPD_REG_MODULE_MANUF_JEDEC_ID_MSB] & 0x7f;
+		tstr = jedec_manufacturer(manuf_lsb, manuf_msb);
+
+		if (tstr != NULL) {
+			kv_pair_fmt(kv, "module_mfg", "%u-%u: %s", manuf_lsb + 1,
+			            manuf_msb, tstr);
+		} else {
+			kv_pair_fmt(kv, "module_mfg", "%u-%u", manuf_lsb + 1,
+			            manuf_msb);
+		}
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_MFG_ID_DRAM:
+	{
+		uint8_t manuf_lsb;
+		uint8_t manuf_msb;
+		const char *tstr;
+
+		manuf_lsb = byte[DDR4_SPD_REG_DRAM_MANUF_JEDEC_ID_LSB] & 0x7f;
+		manuf_msb = byte[DDR4_SPD_REG_DRAM_MANUF_JEDEC_ID_MSB] & 0x7f;
+
+		tstr = jedec_manufacturer(manuf_lsb, manuf_msb);
+
+		if (tstr != NULL) {
+			kv_pair_fmt(kv, "dram_mfg", "%u-%u: %s",
+			            manuf_lsb + 1, manuf_msb, tstr);
+		} else {
+			kv_pair_fmt(kv, "dram_mfg", "%u-%u",
+			            manuf_lsb + 1, manuf_msb);
+		}
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_MFG_LOC:
+	{
+		kv_pair_fmt(kv, "mfg_loc", "0x%02x",
+		            byte[DDR4_SPD_REG_MODULE_MANUF_LOC]);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_MFG_DATE: /* manufacturing date (BCD values) */
+	{
+		uint8_t year;
+		uint8_t week;
+
+		year = byte[DDR4_SPD_REG_MODULE_MANUF_DATE_YEAR];
+		week = byte[DDR4_SPD_REG_MODULE_MANUF_DATE_YEAR];
+		kv_pair_fmt(kv, "mfg_date", "20%02x-wk%02x", week, year);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_SERIAL_NUMBER:
+	{
+		kv_pair_fmt(kv, "serial_number", "%02x%02x%02x%02x",
+		            byte[DDR4_SPD_REG_MODULE_MANUF_SERIAL_0],
+		            byte[DDR4_SPD_REG_MODULE_MANUF_SERIAL_1],
+		            byte[DDR4_SPD_REG_MODULE_MANUF_SERIAL_2],
+		            byte[DDR4_SPD_REG_MODULE_MANUF_SERIAL_3]);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_PART_NUMBER:
+	{
+		char part[19];
+
+		memcpy(part, &byte[DDR4_SPD_REG_MODULE_PART_NUM_0], 18);
+		part[18] = '\0';
+		kv_pair_fmt(kv, "part_number", "%s", part);
+
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_REVISION_CODE:
+	{
+		kv_pair_fmt(kv, "revision_code", "0x%02x",
+		            byte[DDR4_SPD_REG_MODULE_REVISION_0]);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_SIZE:
+	{
+		/* See "Calculating Module Capacity" section in DDR4 SPD
+		 * specification for details. */
+		unsigned int size;
+
+		/* calculate the total size in MB */
+		size = 256 << (byte[DDR4_SPD_REG_DENSITY_BANKS] & 0xf);
+		size >>= 3; /* in terms of bytes instead of bits. */
+		size *= 8 << (byte[DDR4_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
+		size /= 4 << (byte[DDR4_SPD_REG_MODULE_ORG] & 0x7);
+		size *= 1 + ((byte[DDR4_SPD_REG_MODULE_ORG] >> 3) & 0x7);
+
+		kv_pair_fmt(kv, "size_mb", "%u", size);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_ECC:
+	{
+		uint8_t bus_ext_width = byte[DDR4_SPD_REG_MODULE_BUS_WIDTH];
+		bus_ext_width >>= 3;
+		bus_ext_width &= 0x7;
+		kv_pair_add_bool(kv, "ecc", bus_ext_width);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_RANKS:
+	{
+		kv_pair_fmt(kv, "ranks", "%d",
+		            1 + ((byte[DDR4_SPD_REG_MODULE_ORG] >> 3) & 0x7));
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_WIDTH:
+	{
+		/* Total width including ECC. */
+		uint8_t width;
+		width = 8 << (byte[DDR4_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
+		width += 8 * ((byte[DDR4_SPD_REG_MODULE_BUS_WIDTH] >> 3) & 0x7);
+		kv_pair_fmt(kv, "width", "%d", width);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_CHECKSUM:
+	{
+		kv_pair_fmt(kv, "checksum", "0x%02x%02x",
+		            byte[DDR4_SPD_REG_CRC_1],
+		            byte[DDR4_SPD_REG_CRC_0]);
+		ret = 1;
+		break;
+	}
+
+	case SPD_GET_SPEEDS:
+	{
+		int i, mhz, first_entry;
+		char speeds[128];
+		const struct valstr possible_mhz[] = {
+			{ 667,  "DDR4-1333" },
+			{ 800,  "DDR4-1600" },
+			{ 1200, "DDR4-2400" },
+			{ 0 }
+		};
+		int tck_mtb = byte[DDR4_SPD_REG_TCK_MIN];
+		double tck_ns, mtb_ns = 0.0, ftb_ns = 0.0;
+		/* fine offset is encoded in 2's complement format */
+		int8_t ftb_offset = byte[DDR4_SPD_REG_FINE_OFFSET_TCK_MIN];
+
+		mtb_ns = (double) 0.125;
+		ftb_ns = (double) 0.001;
+		tck_ns = tck_mtb * mtb_ns + (ftb_offset * ftb_ns);
+		mhz = (int)((double)1000/tck_ns);
+
+		lprintf(LOG_DEBUG, "%s: %d * %.03fns + %d * %.03fns = %.02fns,"
+				" mhz = %d\n", __func__,
+				tck_mtb, mtb_ns, ftb_offset, ftb_ns, tck_ns, mhz);
+		memset(speeds, 0, sizeof(speeds));
+		first_entry = 1;
+		for (i = 0; possible_mhz[i].val != 0; i++) {
+			double min = possible_mhz[i].val * 0.99;
+
+			if (min <= mhz) {
+				if (!first_entry)
+					strcat(speeds, ", ");
+				first_entry = 0;
+				if (byte[DDR4_SPD_REG_DEVICE_TYPE] ==
+				    SPD_DRAM_TYPE_LPDDR4)
+					strcat(speeds, "LP");
+				strcat(speeds, possible_mhz[i].str);
+			}
+		}
+
+		kv_pair_add(kv, "speeds", speeds);
+		ret = 1;
+		break;
+	}
+
+	default:
+	{
+		ret = 0;	/* force "we don't handle this here */
+		break;
+	}
+	}
+
+	return ret;
+}
diff --git a/lib/spd/spd_fields.c b/lib/spd/spd_fields.c
index 57ea0d4..c2a6c30 100644
--- a/lib/spd/spd_fields.c
+++ b/lib/spd/spd_fields.c
@@ -94,6 +94,9 @@
 
 		break;
 	}
+	case SPD_DRAM_TYPE_DDR4:
+	  size = 384;
+	  break;
 	default:
 		lprintf(LOG_ERR, "SPD type %02x not supported\n", data[2]);
 		return -1;
@@ -161,6 +164,9 @@
 	case SPD_DRAM_TYPE_DDR3:
 	case SPD_DRAM_TYPE_LPDDR3:
 		return spd_print_field_ddr3(intf, kv, data, type);
+	case SPD_DRAM_TYPE_DDR4:
+	  return spd_print_field_ddr4(intf, kv, data, type);
+	  break;
 	default:
 		lprintf(LOG_ERR, "SPD type %02x not supported\n", byte[2]);
 	}
diff --git a/platform/google/Kconfig b/platform/google/Kconfig
index 2d26a04..204c8a4 100644
--- a/platform/google/Kconfig
+++ b/platform/google/Kconfig
@@ -29,6 +29,12 @@
 	bool "Cyclone"
 	default n
 
+config PLATFORM_FIZZ
+	depends on PLATFORM_ARCH_X86
+	select CROS_EC_LPC
+	bool "fizz"
+	default n
+
 config PLATFORM_GLADOS
 	depends on PLATFORM_ARCH_X86
 	select CROS_EC_LPC
diff --git a/platform/google/Makefile b/platform/google/Makefile
index 45dcbdb..e373e15 100644
--- a/platform/google/Makefile
+++ b/platform/google/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_PLATFORM_BELTINO)	+= beltino/
 obj-$(CONFIG_PLATFORM_CYAN)	+= cyan/
 obj-$(CONFIG_PLATFORM_CYCLONE)	+= cyclone/
+obj-$(CONFIG_PLATFORM_FIZZ)	+= fizz/
 obj-$(CONFIG_PLATFORM_GLADOS)	+= glados/
 obj-$(CONFIG_PLATFORM_GRU)      += gru/
 obj-$(CONFIG_PLATFORM_MARIO)	+= mario/
diff --git a/platform/google/fizz/Makefile b/platform/google/fizz/Makefile
new file mode 100644
index 0000000..3eb8d46
--- /dev/null
+++ b/platform/google/fizz/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_PLATFORM_FIZZ)	+= eeprom.o
+#obj-$(CONFIG_PLATFORM_FIZZ)	+= gpio.o
+obj-$(CONFIG_PLATFORM_FIZZ)	+= memory.o
+obj-$(CONFIG_PLATFORM_FIZZ)	+= nvram.o
+obj-$(CONFIG_PLATFORM_FIZZ)	+= sys.o
+obj-$(CONFIG_PLATFORM_FIZZ)	+= fizz.o
diff --git a/platform/google/fizz/eeprom.c b/platform/google/fizz/eeprom.c
new file mode 100644
index 0000000..c29b9e4
--- /dev/null
+++ b/platform/google/fizz/eeprom.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fmap.h>
+
+#include "mosys/alloc.h"
+#include "mosys/platform.h"
+#include "mosys/log.h"
+
+#include "lib/eeprom.h"
+#include "lib/flashrom.h"
+#include "lib/smbios.h"
+
+#include "fizz.h"
+
+
+static int fizz_host_firmware_size(struct platform_intf *intf)
+{
+	return FIZZ_HOST_FIRMWARE_ROM_SIZE;
+}
+
+static int host_firmware_read(struct platform_intf *intf,
+			      struct eeprom *eeprom,
+			      unsigned int offset,
+			      unsigned int len,
+			      void *data)
+{
+	uint8_t *buf;
+	size_t rom_size;
+
+	rom_size = eeprom->device->size(intf);
+	buf = mosys_malloc(rom_size);
+
+	if (flashrom_read(buf, rom_size, HOST_FIRMWARE, NULL) < 0)
+		return -1;
+
+	memcpy(data, &buf[offset], len);
+	free(buf);
+	return 0;
+}
+
+static int host_firmware_read_by_name(struct platform_intf *intf,
+				      struct eeprom *eeprom,
+				      const char *name,
+				      uint8_t **data)
+{
+	return flashrom_read_by_name(data, HOST_FIRMWARE, name);
+}
+
+static int host_firmware_write_by_name(struct platform_intf *intf,
+				       struct eeprom *eeprom,
+				       const char *name,
+				       unsigned int len,
+				       uint8_t *data)
+{
+	return flashrom_write_by_name(len, data, HOST_FIRMWARE, name);
+}
+
+static struct eeprom_dev host_firmware = {
+	.size		= fizz_host_firmware_size,
+	.read		= host_firmware_read,
+	.read_by_name	= host_firmware_read_by_name,
+	.write_by_name	= host_firmware_write_by_name,
+	.get_map	= eeprom_get_fmap,
+};
+
+static struct eeprom_region host_firmware_regions[] = {
+	{
+		.name	= "RW_NVRAM",
+		.flag	= EEPROM_FLAG_VBNV,
+	},
+	{ 0 },
+};
+
+static struct eeprom eeproms[] = {
+	{
+		.name		= "host_firmware",
+		.type		= EEPROM_TYPE_FW,
+		.flags		= EEPROM_FLAG_RDWR | EEPROM_FLAG_FMAP,
+		.device		= &host_firmware,
+		.regions	= &host_firmware_regions[0],
+	},
+	{ 0 },
+};
+
+struct eeprom_cb fizz_eeprom_cb = {
+	.eeprom_list	= eeproms,
+};
diff --git a/platform/google/fizz/fizz.c b/platform/google/fizz/fizz.c
new file mode 100644
index 0000000..cabc1b2
--- /dev/null
+++ b/platform/google/fizz/fizz.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "mosys/alloc.h"
+#include "mosys/command_list.h"
+#include "mosys/platform.h"
+#include "mosys/intf_list.h"
+#include "mosys/log.h"
+
+#include "drivers/google/cros_ec.h"
+
+#include "lib/probe.h"
+#include "lib/smbios.h"
+#include "lib/elog.h"
+
+#include "fizz.h"
+
+struct probe_ids {
+	const char *names[2];
+	const char *hwids[2];
+	const char *frids[2];
+};
+
+static const struct probe_ids probe_id_list[] = {
+        { { "Fizz", NULL },
+          { "FIZZ", NULL },
+          { "Fizz", NULL },
+        },
+	{ { NULL } }
+};
+
+struct platform_cmd *fizz_sub[] = {
+	&cmd_ec,
+	&cmd_eeprom,
+	&cmd_fp,
+	&cmd_memory,
+	&cmd_nvram,
+	&cmd_pd,
+	&cmd_platform,
+	&cmd_smbios,
+	&cmd_eventlog,
+	NULL
+};
+
+int fizz_probe(struct platform_intf *intf)
+{
+	static int status, probed;
+	const struct probe_ids *pid;
+
+	if (probed)
+		return status;
+
+	for (pid = probe_id_list; pid && pid->names[0]; pid++) {
+		/* HWID */
+		if (probe_hwid((const char **)pid->hwids)) {
+			status = 1;
+			goto fizz_probe_exit;
+		}
+
+		/* FRID */
+		if (probe_frid((const char **)pid->frids)) {
+			status = 1;
+			goto fizz_probe_exit;
+		}
+
+		/* SMBIOS */
+		if (probe_smbios(intf, (const char **)pid->names)) {
+			status = 1;
+			goto fizz_probe_exit;
+		}
+	}
+	return 0;
+
+fizz_probe_exit:
+	probed = 1;
+	/* Update canonical platform name */
+	intf->name = pid->names[0];
+	return status;
+}
+
+/* late setup routine; not critical to core functionality */
+static int fizz_setup_post(struct platform_intf *intf)
+{
+	if (cros_ec_setup(intf) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int fizz_destroy(struct platform_intf *intf)
+{
+	return 0;
+}
+
+struct eventlog_cb fizz_eventlog_cb = {
+	.print_type	= &elog_print_type,
+	.print_data	= &elog_print_data,
+	.print_multi	= &elog_print_multi,
+	.verify		= &elog_verify,
+	.verify_header	= &elog_verify_header,
+	.fetch		= &elog_fetch_from_smbios,
+};
+
+struct platform_cb fizz_cb = {
+	.ec		= &cros_ec_cb,
+	.pd		= &cros_pd_cb,
+	.fp		= &cros_fp_cb,
+	.eeprom		= &fizz_eeprom_cb,
+	.memory		= &fizz_memory_cb,
+	.nvram		= &fizz_nvram_cb,
+	.smbios		= &smbios_sysinfo_cb,
+	.sys 		= &fizz_sys_cb,
+	.eventlog	= &fizz_eventlog_cb,
+};
+
+struct platform_intf platform_fizz = {
+	.type		= PLATFORM_X86_64,
+	.name		= "Fizz",
+	.sub		= fizz_sub,
+	.cb		= &fizz_cb,
+	.probe		= &fizz_probe,
+	.setup_post	= &fizz_setup_post,
+	.destroy	= &fizz_destroy,
+};
diff --git a/platform/google/fizz/fizz.h b/platform/google/fizz/fizz.h
new file mode 100644
index 0000000..13045c9
--- /dev/null
+++ b/platform/google/fizz/fizz.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FIZZ_H__
+#define FIZZ_H__
+
+#include <inttypes.h>
+#include "mosys/platform.h"
+
+#define FIZZ_HOST_FIRMWARE_ROM_SIZE		(16384 * 1024)
+
+/* platform callbacks */
+extern struct eeprom_cb fizz_eeprom_cb;	/* eeprom.c */
+extern struct gpio_cb fizz_gpio_cb;		/* gpio.c */
+extern struct memory_cb fizz_memory_cb;	/* memory.c */
+extern struct nvram_cb fizz_nvram_cb;		/* nvram.c */
+extern struct sys_cb fizz_sys_cb;		/* sys.c */
+
+/* functions called by setup routines */
+extern int fizz_vpd_setup(struct platform_intf *intf);
+
+#endif /* FIZZ_H_ */
diff --git a/platform/google/fizz/memory.c b/platform/google/fizz/memory.c
new file mode 100644
index 0000000..695ab48
--- /dev/null
+++ b/platform/google/fizz/memory.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mosys/callbacks.h"
+#include "mosys/globals.h"
+#include "mosys/log.h"
+#include "mosys/platform.h"
+
+#include "drivers/gpio.h"
+#include "drivers/intel/series6.h"
+
+#include "lib/file.h"
+#include "lib/flashrom.h"
+#include "lib/spd.h"
+#include "lib/smbios.h"
+
+#include "fizz.h"
+
+#define FIZZ_DIMM_COUNT	2
+
+static int fizz_spd_read(struct platform_intf *intf,
+		 int dimm, int reg, int spd_len, uint8_t *spd_buf)
+{
+	int bus;
+	int address;
+
+	bus = intf->cb->memory->dimm_map(intf, DIMM_TO_BUS, dimm);
+	address = intf->cb->memory->dimm_map(intf, DIMM_TO_ADDRESS, dimm);
+
+	return spd_read_i2c(intf, bus, address, reg, spd_len, spd_buf);
+}
+
+/*
+ * dimm_auron_dimm_count  -  return total number of dimm slots
+ *
+ * @intf:       platform interface
+ *
+ * returns dimm slot count
+ */
+static int dimm_fizz_dimm_count(struct platform_intf *intf)
+{
+	return FIZZ_DIMM_COUNT;
+}
+
+/*
+ * dimm_map  -  Convert logical dimm number to useful values
+ *
+ * @intf:       platform interface
+ * @dimm:       logical dimm number
+ * @type:       conversion type
+ *
+ * returns specified converted value
+ * returns <0 to indicate error
+ */
+static int dimm_fizz_dimm_map(struct platform_intf *intf,
+			      enum dimm_map_type type, int dimm)
+{
+	int ret = -1;
+	static struct dimm_map {
+		int node;
+		int channel;
+		int slot;
+		int bus;
+		int address;
+	} fizz_dimm_map[FIZZ_DIMM_COUNT] = {
+		/* Node 0 */
+		{ 0, 0, 0, 17, 0x50 },
+		{ 0, 0, 0, 17, 0x52 }
+	};
+	static unsigned int first_run = 1;
+	static int bus_offset = 0;
+
+	if (dimm < 0 || dimm >= intf->cb->memory->dimm_count(intf)) {
+		lprintf(LOG_ERR, "Invalid DIMM: %d\n", dimm);
+		return -1;
+	}
+
+	/*
+	 * Determine offset for smbus numbering:
+	 * 1. Scan known bus numbers for lowest value.
+	 * 2. Scan /sys for SMBus entries that match the adapter name.
+	 * 3. Calculate the difference between the lowest expected bus number
+	 *    and the lowest bus number seen in sysfs matching the criteria.
+	 */
+	if (first_run) {
+		char path[PATH_MAX];
+		int lowest_known_bus = INT_MAX, x;
+
+		for (x = 0; x < intf->cb->memory->dimm_count(intf); x++) {
+			if (fizz_dimm_map[x].bus < lowest_known_bus)
+				lowest_known_bus = fizz_dimm_map[x].bus;
+		}
+
+		snprintf(path, sizeof(path), "%s/%s",
+		         mosys_get_root_prefix(), "/sys/bus/i2c/devices");
+		x = sysfs_lowest_smbus(path, SERIES6_SMBUS_ADAPTER);
+		if (x >= 0) {
+			bus_offset = x - lowest_known_bus;
+			lprintf(LOG_DEBUG, "%s: bus_offset: %d\n",
+			        __func__, bus_offset);
+		} else {
+			lprintf(LOG_DEBUG, "%s: unable to determine "
+			                   "bus offset\n", __func__);
+			bus_offset = 0;
+		}
+
+		first_run = 0;
+	}
+
+	switch (type) {
+	case DIMM_TO_BUS:
+		ret = fizz_dimm_map[dimm].bus + bus_offset;
+		break;
+	case DIMM_TO_ADDRESS:
+		ret = fizz_dimm_map[dimm].address;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int dimm_fizz_spd_read(struct platform_intf *intf,
+                          int dimm, int reg, int len, uint8_t *buf)
+{
+	int bus;
+	int address;
+
+	bus = intf->cb->memory->dimm_map(intf, DIMM_TO_BUS, dimm);
+	address = intf->cb->memory->dimm_map(intf, DIMM_TO_ADDRESS, dimm);
+
+	return spd_read_i2c(intf, bus, address, reg, len, buf);
+}
+
+static struct memory_spd_cb fizz_spd_cb = {
+	.read		= fizz_spd_read,
+};
+
+static struct memory_spd_cb dimm_fizz_spd_cb = {
+	.read		= dimm_fizz_spd_read,
+};
+
+struct memory_cb fizz_memory_cb = {
+	.dimm_count	= smbios_dimm_count,
+	.dimm_speed	= smbios_dimm_speed,
+	.dimm_map	= dimm_fizz_dimm_map,
+	.spd		= &fizz_spd_cb,
+};
diff --git a/platform/google/fizz/nvram.c b/platform/google/fizz/nvram.c
new file mode 100644
index 0000000..b1d76a7
--- /dev/null
+++ b/platform/google/fizz/nvram.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <valstr.h>
+
+#include "mosys/kv_pair.h"
+#include "mosys/log.h"
+#include "mosys/platform.h"
+#include "mosys/output.h"
+
+#include "intf/io.h"
+
+#include "lib/eeprom.h"
+#include "lib/math.h"
+
+enum cmos_device {
+	CMOS_DEVICE_PCH,
+};
+
+struct cmos_var_map {
+	uint8_t offset;
+	uint8_t length;
+	char *desc;
+};
+
+struct cmos_map {
+	enum cmos_device type;
+	const char *device;
+	int bank;
+	int length;
+	int clear_start;	/* first bytes are usually reserved for RTC */
+	struct cmos_var_map *var_list;
+};
+
+static struct cmos_var_map coreboot_cmos_bank0_vars[] = {
+	{ 0x70, 1, "Post Code Bank" },
+	{ 0x71, 1, "Post Code Bank 0" },
+	{ 0x72, 1, "Post Code Bank 1" },
+	{ 0x73, 4, "Post Extra Bank 0" },
+	{ 0x77, 4, "Post Extra Bank 1" },
+	{ 0 }
+};
+
+static struct cmos_var_map coreboot_cmos_bank1_vars[] = {
+	{ 0x12, 4, "Boot Count" }, /* 0x92 */
+	{ 0 }
+};
+
+struct cmos_map fizz_cmos_map[] = {
+	{ CMOS_DEVICE_PCH, "LPSS0", 0, 128, 0x29, coreboot_cmos_bank0_vars },
+	{ CMOS_DEVICE_PCH, "LPSS1", 1, 128, 0x00, coreboot_cmos_bank1_vars },
+};
+
+static const uint16_t fizz_cmos_port[] = { 0x70, 0x72 };
+
+static uint8_t fizz_read_cmos(struct platform_intf *intf,
+				 int addr, int reg)
+{
+	uint8_t data;
+
+	io_write8(intf, fizz_cmos_port[addr], reg);
+	io_read8(intf, fizz_cmos_port[addr] + 1, &data);
+	return data;
+}
+
+static void fizz_write_cmos(struct platform_intf *intf,
+			       int addr, int reg, uint8_t val)
+{
+	io_write8(intf, fizz_cmos_port[addr], reg);
+	io_write8(intf, fizz_cmos_port[addr] + 1, val);
+}
+
+static int fizz_nvram_list_bank(struct platform_intf *intf,
+				  struct cmos_map *map)
+{
+	struct cmos_var_map *var;
+	int i;
+
+	/* handle each cmos bank */
+	for (var = map->var_list; var && var->desc; var++) {
+		struct kv_pair *kv = kv_pair_new();
+		uint32_t val = 0;
+
+		switch (map->type) {
+		case CMOS_DEVICE_PCH:
+			for (i = 0; i < var->length; i++)
+				val |= fizz_read_cmos(
+					intf, map->bank,
+					var->offset + i) << (i*8);
+			break;
+		}
+
+		kv_pair_add(kv, "device", map->device);
+		kv_pair_add(kv, "name", var->desc);
+		kv_pair_fmt(kv, "value", "0x%x", val);
+		kv_pair_print(kv);
+		kv_pair_free(kv);
+	}
+
+	return 0;
+}
+
+static int fizz_nvram_list(struct platform_intf *intf)
+{
+	int dev, rc = 0;
+
+	/* handle each cmos bank */
+	for (dev = 0; dev < ARRAY_SIZE(fizz_cmos_map); dev++)
+		rc |= fizz_nvram_list_bank(intf, &fizz_cmos_map[dev]);
+
+	return rc;
+}
+
+static int fizz_nvram_dump(struct platform_intf *intf)
+{
+	struct cmos_map *map;
+	int off, dev;
+	uint8_t cmos_data[128];
+
+	/* handle each cmos bank */
+	for (dev = 0; dev < ARRAY_SIZE(fizz_cmos_map); dev++) {
+		map = &fizz_cmos_map[dev];
+
+		if (map->length > sizeof(cmos_data))
+			continue;
+		memset(cmos_data, 0, sizeof(cmos_data));
+
+		mosys_printf("%s CMOS Bank %d (%d bytes)\n",
+		       map->device, map->bank, map->length);
+
+		switch (map->type) {
+		case CMOS_DEVICE_PCH:
+			for (off = 0; off < map->length; off++)
+				cmos_data[off] = fizz_read_cmos(
+					intf, map->bank, off);
+			break;
+		}
+
+		print_buffer(cmos_data, map->length);
+		mosys_printf("\n");
+	}
+
+	return 0;
+}
+
+static int fizz_nvram_clear(struct platform_intf *intf)
+{
+	struct cmos_map *map;
+	int off, dev;
+
+	/* handle each cmos bank */
+	for (dev = 0;
+	     dev < (sizeof(fizz_cmos_map) / sizeof(struct cmos_map));
+	     dev++) {
+		map = &fizz_cmos_map[dev];
+
+		switch (map->type) {
+		case CMOS_DEVICE_PCH:
+			for (off = map->clear_start; off < map->length; off++)
+				fizz_write_cmos(intf, map->bank, off, 0x00);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+struct nvram_cb fizz_nvram_cb = {
+	.list		= fizz_nvram_list,
+	.dump		= fizz_nvram_dump,
+	.clear		= fizz_nvram_clear,
+	.vboot_read	= vbnv_flash_vboot_read,
+	.vboot_write	= vbnv_flash_vboot_write,
+};
diff --git a/platform/google/fizz/sys.c b/platform/google/fizz/sys.c
new file mode 100644
index 0000000..4765102
--- /dev/null
+++ b/platform/google/fizz/sys.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mosys/alloc.h"
+#include "mosys/platform.h"
+
+#include "drivers/google/cros_ec.h"
+
+#include "lib/smbios.h"
+
+static char *fizz_get_name(struct platform_intf *intf)
+{
+	return mosys_strdup(intf->name);
+}
+
+struct sys_cb fizz_sys_cb = {
+	.version		= &cros_ec_board_version_str,
+	.vendor			= &smbios_sysinfo_get_vendor,
+	.name			= &fizz_get_name,
+	.family			= &smbios_sysinfo_get_family,
+	.firmware_vendor	= &smbios_bios_get_vendor,
+};
diff --git a/platform/platform_list.c b/platform/platform_list.c
index 662e30e..435e7a3 100644
--- a/platform/platform_list.c
+++ b/platform/platform_list.c
@@ -44,6 +44,7 @@
 extern struct platform_intf platform_cyan;
 extern struct platform_intf platform_cyclone;
 extern struct platform_intf platform_daisy;
+extern struct platform_intf platform_fizz;
 extern struct platform_intf platform_glados;
 extern struct platform_intf platform_gru;
 extern struct platform_intf platform_link;
@@ -90,6 +91,9 @@
 #ifdef CONFIG_PLATFORM_DAISY
 	&platform_daisy,
 #endif
+#ifdef CONFIG_PLATFORM_FIZZ
+	&platform_fizz,
+#endif
 #ifdef CONFIG_PLATFORM_GLADOS
 	&platform_glados,
 #endif