platform/mosys: Add initial Puff support

V.2: Fix up misc reviewers comments.
V.3: Fix license headers.

BUG=b:143335657
BRANCH=none
TEST=emerge-puff mosys

Change-Id: I9e5aa22bd83eddfe402f317c309b888136dcc7ea
Signed-off-by: Edward O'Callaghan <quasisec@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1879637
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Reviewed-by: Sam McNally <sammc@chromium.org>
diff --git a/platform/meson.build b/platform/meson.build
index d9001b9..49cb5c3 100644
--- a/platform/meson.build
+++ b/platform/meson.build
@@ -25,6 +25,7 @@
 endif
 subdir('pinky')
 subdir('poppy')
+subdir('puff')
 subdir('rambi')
 subdir('reef')
 subdir('samus')
diff --git a/platform/platform_list.c b/platform/platform_list.c
index b7132af..ad71b97 100644
--- a/platform/platform_list.c
+++ b/platform/platform_list.c
@@ -58,6 +58,7 @@
 extern struct platform_intf platform_octopus;
 extern struct platform_intf platform_pinky;
 extern struct platform_intf platform_poppy;
+extern struct platform_intf platform_puff;
 extern struct platform_intf platform_rambi;
 extern struct platform_intf platform_reef;
 extern struct platform_intf platform_samus;
@@ -84,6 +85,7 @@
 	&platform_hatch,
 	&platform_nami,
 	&platform_poppy,
+	&platform_puff,
 	&platform_octopus,
 	&platform_sarien,
 	&platform_drallion,
diff --git a/platform/puff/eeprom.c b/platform/puff/eeprom.c
new file mode 100644
index 0000000..b17a881
--- /dev/null
+++ b/platform/puff/eeprom.c
@@ -0,0 +1,90 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "mosys/alloc.h"
+#include "mosys/platform.h"
+
+#include "lib/eeprom.h"
+#include "lib/flashrom.h"
+#include "lib/smbios.h"
+
+#include "puff.h"
+
+
+static int host_firmware_size(struct platform_intf *intf)
+{
+	return PUFF_HOST_FIRMWARE_ROM_SIZE_32MB;
+}
+
+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		= 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 puff_eeprom_cb = {
+	.eeprom_list	= eeproms,
+};
diff --git a/platform/puff/memory.c b/platform/puff/memory.c
new file mode 100644
index 0000000..0b5ef28
--- /dev/null
+++ b/platform/puff/memory.c
@@ -0,0 +1,14 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "lib/nonspd.h"
+#include "lib/smbios.h"
+#include "puff.h"
+
+struct memory_cb puff_memory_cb = {
+	.dimm_count		= smbios_dimm_count,
+	.dimm_speed		= smbios_dimm_speed,
+	.nonspd_mem_info	= &spd_set_nonspd_info,
+};
diff --git a/platform/puff/meson.build b/platform/puff/meson.build
new file mode 100644
index 0000000..3b6ee45
--- /dev/null
+++ b/platform/puff/meson.build
@@ -0,0 +1,7 @@
+libmosys_src += files(
+  'eeprom.c',
+  'nvram.c',
+  'memory.c',
+  'sys.c',
+  'puff.c',
+)
diff --git a/platform/puff/nvram.c b/platform/puff/nvram.c
new file mode 100644
index 0000000..61ee0c2
--- /dev/null
+++ b/platform/puff/nvram.c
@@ -0,0 +1,179 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#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 puff_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 puff_cmos_port[] = { 0x70, 0x72 };
+
+static uint8_t puff_read_cmos(struct platform_intf *intf, int addr, int reg)
+{
+	uint8_t data;
+
+	io_write8(intf, puff_cmos_port[addr], reg);
+	io_read8(intf, puff_cmos_port[addr] + 1, &data);
+	return data;
+}
+
+static void puff_write_cmos(struct platform_intf *intf,
+			    int addr, int reg, uint8_t val)
+{
+	io_write8(intf, puff_cmos_port[addr], reg);
+	io_write8(intf, puff_cmos_port[addr] + 1, val);
+}
+
+static int puff_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 |= puff_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 puff_nvram_list(struct platform_intf *intf)
+{
+	int dev, rc = 0;
+
+	/* handle each cmos bank */
+	for (dev = 0; dev < ARRAY_SIZE(puff_cmos_map); dev++)
+		rc |= puff_nvram_list_bank(intf, &puff_cmos_map[dev]);
+
+	return rc;
+}
+
+static int puff_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(puff_cmos_map); dev++) {
+		map = &puff_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] = puff_read_cmos(
+					intf, map->bank, off);
+			break;
+		}
+
+		print_buffer(cmos_data, map->length);
+		mosys_printf("\n");
+	}
+
+	return 0;
+}
+
+static int puff_nvram_clear(struct platform_intf *intf)
+{
+	struct cmos_map *map;
+	int off, dev;
+
+	/* handle each cmos bank */
+	for (dev = 0;
+	     dev < (sizeof(puff_cmos_map) / sizeof(struct cmos_map));
+	     dev++) {
+		map = &puff_cmos_map[dev];
+
+		switch (map->type) {
+		case CMOS_DEVICE_PCH:
+			for (off = map->clear_start; off < map->length; off++)
+				puff_write_cmos(intf, map->bank, off, 0x00);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+struct nvram_cb puff_nvram_cb = {
+	.list		= puff_nvram_list,
+	.dump		= puff_nvram_dump,
+	.clear		= puff_nvram_clear,
+	.vboot_read	= vbnv_flash_vboot_read,
+	.vboot_write	= vbnv_flash_vboot_write,
+};
diff --git a/platform/puff/puff.c b/platform/puff/puff.c
new file mode 100644
index 0000000..7fe10ed
--- /dev/null
+++ b/platform/puff/puff.c
@@ -0,0 +1,71 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "mosys/command_list.h"
+#include "mosys/platform.h"
+#include "mosys/intf_list.h"
+
+#include "drivers/google/cros_ec.h"
+
+#include "lib/cros_config.h"
+#include "lib/smbios.h"
+#include "lib/elog.h"
+
+#include "puff.h"
+
+static struct platform_cmd *puff_sub[] = {
+	&cmd_ec,
+	&cmd_eeprom,
+	&cmd_memory,
+	&cmd_nvram,
+	&cmd_pd,
+	&cmd_platform,
+	&cmd_smbios,
+	&cmd_eventlog,
+	NULL
+};
+
+static int puff_probe(struct platform_intf *intf)
+{
+	/* cros_config model.yaml 'platform-name' should match intf.name. */
+	return cros_config_probe(intf, NULL);
+}
+
+/* late setup routine; not critical to core functionality */
+static int puff_setup_post(struct platform_intf *intf)
+{
+	if (cros_ec_setup(intf) < 0)
+		return -1;
+
+	return 0;
+}
+
+static struct eventlog_cb puff_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,
+};
+
+static struct platform_cb puff_cb = {
+	.ec		= &cros_ec_cb,
+	.eeprom		= &puff_eeprom_cb,
+	.memory		= &puff_memory_cb,
+	.nvram		= &puff_nvram_cb,
+	.smbios		= &smbios_sysinfo_cb,
+	.sys 		= &puff_sys_cb,
+	.eventlog	= &puff_eventlog_cb,
+};
+
+struct platform_intf platform_puff = {
+	.type		= PLATFORM_X86_64,
+	.name		= "Puff",
+	.sub		= puff_sub,
+	.cb		= &puff_cb,
+	.probe		= &puff_probe,
+	.setup_post	= &puff_setup_post,
+};
diff --git a/platform/puff/puff.h b/platform/puff/puff.h
new file mode 100644
index 0000000..ab34786
--- /dev/null
+++ b/platform/puff/puff.h
@@ -0,0 +1,20 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PLATFORM_PUFF_H__
+#define PLATFORM_PUFF_H__
+
+#include <inttypes.h>
+#include "mosys/platform.h"
+
+#define PUFF_HOST_FIRMWARE_ROM_SIZE_32MB	(32768 * 1024)
+
+/* platform callbacks */
+extern struct eeprom_cb puff_eeprom_cb;	/* eeprom.c */
+extern struct memory_cb puff_memory_cb;	/* memory.c */
+extern struct nvram_cb puff_nvram_cb;		/* nvram.c */
+extern struct sys_cb puff_sys_cb;		/* sys.c */
+
+#endif /* PLATFORM_PUFF_H_ */
diff --git a/platform/puff/sys.c b/platform/puff/sys.c
new file mode 100644
index 0000000..22fbc5c
--- /dev/null
+++ b/platform/puff/sys.c
@@ -0,0 +1,27 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "mosys/alloc.h"
+#include "mosys/platform.h"
+
+#include "lib/acpi.h"
+#include "lib/sku.h"
+#include "lib/smbios.h"
+#include "lib/string.h"
+
+static char *puff_get_name(struct platform_intf *intf)
+{
+	return mosys_strdup(intf->name);
+}
+
+struct sys_cb puff_sys_cb = {
+	.version		= &smbios_sysinfo_get_version,
+	.vendor			= &smbios_sysinfo_get_vendor,
+	.name			= &puff_get_name,
+	.family			= &smbios_sysinfo_get_family,
+	.firmware_vendor	= &smbios_bios_get_vendor,
+	.sku_number		= &smbios_sysinfo_get_sku_number,
+	.signature_id           = sku_get_signature_id,
+};