[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/scatter/scripts/dev-info-hdr-tool.py b/src/bsp/scatter/scripts/dev-info-hdr-tool.py
new file mode 100644
index 0000000..3084eef
--- /dev/null
+++ b/src/bsp/scatter/scripts/dev-info-hdr-tool.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import struct
+import sys
+
+def read(path):
+	with open(path, "rb") as f:
+		return f.read()
+
+def write(path, data):
+	with open(path, "wb") as f:
+		f.write(data)
+
+def padding(data, size, pattern = b'\0'):
+	return data + pattern * (size - len(data))
+
+def align(data, size, pattern = b'\0'):
+	return padding(data, (len(data) + (size - 1)) & ~(size - 1), pattern)
+
+def gen_nor_bl_img(data):
+	data = align(data, 512, '\xff')
+	header = (padding(struct.pack("<12sII", "SF_BOOT", 1, 512), 512, '\xff') +
+		  padding(struct.pack("<8sIIIIIIII", "BRLYT", 1, 2048, 2048 + len(data),
+			0x42424242, 0x00010007, 2048, 2048 + len(data), 1) + '\0' * 140, 512, '\xff') +
+		  '\0' * 1024)
+	return header + data
+
+def gen_emmc_bl_img(data):
+	data = align(data, 512, b'\xff')
+	header = (padding(struct.pack("<12sII", b"EMMC_BOOT", 1, 512), 512, b'\xff') +
+	          padding(struct.pack("<8sIIIIIIII", b"BRLYT", 1, 2048, 2048 + len(data),
+	          0x42424242, 0x00010005, 2048, 2048 + len(data), 1) + b'\0' * 140, 512, b'\xff') +
+	          b'\0' * 1024)
+	return header + data
+
+def gen_sdcard_bl_img(data):
+	data = align(data, 512, '\xff')
+	header = (padding(struct.pack("<12sII", "SDMMC_BOOT", 1, 512), 512, '\xff') +
+		  padding(struct.pack("<8sIIIIIIII", "BRLYT", 1, 2048, 2048 + len(data),
+			0x42424242, 0x00010008, 2048, 2048 + len(data), 1) + '\0' * 140, 512, '\xff') +
+			'\0' * 1024)
+	return header + data
+
+def get_page_size(nand_name):
+	with open("scripts/nand-setting.txt", "r") as f:
+		for l in f:
+			s = l.split("\t")
+			if s[0] == nand_name:
+				return int(s[1])
+	raise KeyError("not support " + nand_name)
+
+def gen_nand_bl_img(data, nand_name, page_number_bl1, page_number_bl2):
+	hdr1 = "temp1.hdr"
+	hdr2 = "temp2.hdr"
+	page_size = get_page_size(nand_name)
+	data = align(data, 128*page_size, '\xff')
+	os.system("./tools/bch h {0} null {1} 1 {2} 0 0".format(nand_name, hdr1, page_number_bl1))
+	os.system("./tools/bch h {0} null {1} 1 {2} 0 0".format(nand_name, hdr2, page_number_bl2))
+	header1 = padding(read(hdr1), 256*page_size, '\xff')
+	header2 = padding(read(hdr2), 256*page_size, '\xff')
+	os.remove(hdr1)
+	os.remove(hdr2)
+	return header1 + header2 + data + data
+
+def main(argv):
+	parser = argparse.ArgumentParser()
+	parser.add_argument('type', default='emmc', help='emmc | nand | nor | sdcard')
+	parser.add_argument('in_image', help='input file path')
+	parser.add_argument('out_image', help='output image path')
+	parser.add_argument('nand_name', nargs='?', help='nand chip name')
+	parser.add_argument('bl1', type=int, nargs='?', default=0, help='page number of bl1. default=0')
+	parser.add_argument('bl2', type=int, nargs='?', default=0, help='page number of bl2. default=0')
+	args = parser.parse_args()
+
+	if args.type == 'emmc':
+		r = gen_emmc_bl_img(read(args.in_image))
+	elif args.type == 'nor':
+		r = gen_nor_bl_img(read(args.in_image))
+	elif args.type == 'sdcard':
+		r = gen_sdcard_bl_img(read(args.in_image))
+	elif args.type == 'nand':
+		r = gen_nand_bl_img(read(args.in_image), args.nand_name, args.bl1, args.bl2)
+	else:
+		print("unknown type: " + args.type)
+		return 1
+
+	write(args.out_image, r)
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main(sys.argv))
diff --git a/src/bsp/scatter/scripts/gen-partition-nand.py b/src/bsp/scatter/scripts/gen-partition-nand.py
new file mode 100755
index 0000000..365a0ea
--- /dev/null
+++ b/src/bsp/scatter/scripts/gen-partition-nand.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import binascii
+import json
+import os
+import struct
+import sys
+import uuid
+import xml.dom.minidom
+
+NumberOfPartitionEntries = 128
+SizeOfPartitionEntry = 128
+
+def write(path, data):
+	with open(path, "wb+") as f:
+		f.write(data)
+
+def crc32(data):
+        return binascii.crc32(data) & 0xffffffff
+
+def padding(data, size):
+	return data + b'\0' * (size - len(data))
+
+def gen_gpt(partition):
+	pmbr = (b'\0' * 446 +
+		b"\x00\x00\x02\x00\xee\xff\xff\xff\x01\x00\x00\x00\xff\xff\xff\xff" +
+		b'\0' * 48 + b"\x55\xaa")
+	entries = b''
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		type = uuid.UUID(node.getAttribute("type"))
+		uniq = node.getAttribute("uuid")
+		uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		attr = node.getAttribute("attributes")
+		attr = attr and eval(attr) or 0
+		name = node.getAttribute("name")
+		entries += struct.pack("<16s16sQQQ72s",
+			type.bytes_le,
+			uniq.bytes_le,
+			int(start), end, attr,
+			name.encode("utf-16le"))
+	entries = padding(entries, NumberOfPartitionEntries * SizeOfPartitionEntry)
+	lba = eval(partition.getAttribute("lba"))
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 512
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+	uniq = partition.getAttribute("uuid")
+	uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+	pmbr = padding(pmbr, lbs)
+	header = struct.pack("<8sIIIIQQQQ16sQIII",
+		b"EFI PART", 0x00010000, 92, 0, 0,
+		1, # MyLBA
+		1, #lba - 1, # AlternateLBA
+		int(FirstUsableLBA),
+		int(lba - FirstUsableLBA), # LastUsableLBA
+		uniq.bytes_le,
+		2, int(NumberOfPartitionEntries), int(SizeOfPartitionEntry), crc32(entries))
+	header = padding(header[:16] +
+		struct.pack('I', crc32(header)) +
+		header[20:], lbs)
+	return pmbr + header + entries
+
+def write_scatter_partition(f, entry):
+	if entry.get("file_name", "NONE") != "NONE":
+		entry.setdefault("is_download", True)
+		entry.setdefault("operation_type", "UPDATE")
+		entry.setdefault("type", "NORMAL_ROM")
+	f.write(
+"""- partition_index: %s
+  partition_name: %s
+  file_name: %s
+  is_download: %s
+  type: %s
+  linear_start_addr: %s
+  physical_start_addr: %s
+  partition_size: %s
+  region: %s
+  storage: %s
+  boundary_check: %s
+  is_reserved: %s
+  operation_type: %s
+  d_type: LOW_PAGE
+  slc_percentage: 0
+  is_upgradable: true
+  reserve: %s
+
+""" % (entry["partition_index"], entry["partition_name"], entry.get("file_name", "NONE"),
+entry.get("is_download", False) and "true" or "false", entry.get("type", "NONE"), hex(entry["linear_start_addr"]),
+hex(entry["physical_start_addr"]), hex(entry["partition_size"]), entry.get("region", "NONE"),
+entry.get("storage", "HW_STORAGE_NAND"), entry.get("boundary_check", True) and "true" or "false",
+entry.get("is_reserved", False) and "true" or "false", entry.get("operation_type", "PROTECTED"),
+hex(entry.get("reserve", 0))))
+
+def write_scatter(f, partition, d):
+	f.write(
+"""############################################################################################################
+#
+#  General Setting
+#
+############################################################################################################
+- general: MTK_PLATFORM_CFG
+  info:
+    - config_version: %s
+      platform: %s
+      project: %s
+      storage: %s
+      boot_channel: %s
+      block_size: %s
+      skip_pmt_operate: %s
+############################################################################################################
+#
+#  Layout Setting
+#
+############################################################################################################
+""" % (d["MTK_PLATFORM_CFG"]["config_version"], d["MTK_PLATFORM_CFG"]["platform"], d["MTK_PLATFORM_CFG"]["project"],
+       d["MTK_PLATFORM_CFG"]["storage"], d["MTK_PLATFORM_CFG"]["boot_channel"], d["MTK_PLATFORM_CFG"]["block_size"],
+       d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false"))
+#	d["PRELOADER"]["partition_index"] = "SYS0"
+	d["MBR"]["partition_index"] = "SYS0"
+#	write_scatter_partition(f, d["PRELOADER"])
+	write_scatter_partition(f, d["MBR"])
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 512
+	i = 1
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		name = node.getAttribute("name")
+		if name not in d:
+			continue
+		entry = d[name]
+		entry["partition_name"] = name
+		entry["partition_index"] = "SYS%d" % i
+		i += 1
+		entry["linear_start_addr"] = start * lbs
+		entry["physical_start_addr"] = start * lbs
+		if end != start:
+			entry["partition_size"] = (end + 1 - start) * lbs
+		else:
+			entry["partition_size"] = 0
+		write_scatter_partition(f, entry)
+	if (d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false") == "false":
+		d["sgpt"]["partition_index"] = "SYS%d" % i
+		write_scatter_partition(f, d["sgpt"])
+
+
+def sanity_check(path, partition):
+	err = 0
+	lba = eval(partition.getAttribute("lba"))
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 512
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+	usable = (FirstUsableLBA, lba - FirstUsableLBA)
+	used = {}
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		name = node.getAttribute("name")
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		if start > end:
+			print("%s: error: partition '%s': start lba (%d) > end lba (%d)" %
+				(path, name, start, end), file = sys.stderr)
+			err += 1
+		if start < usable[0] or end > usable[1]:
+			print("%s: error: partition '%s': (%d...%d) out of usable range (%d...%d)" %
+				(path, name, start, end, usable[0], usable[1]), file = sys.stderr)
+			err += 1
+		for i in used:
+			if (used[i][0] <= start and start <= used[i][1] or
+				used[i][0] <= end and end <= used[i][1]):
+				print("%s: error: partition '%s': (%d...%d) overlapped with partition '%s' (%d...%d)" %
+					(path, name, start, end, i, used[i][0], used[i][1]), file = sys.stderr)
+				err += 1
+		used[name] = (start, end)
+	return err
+
+def main(argv):
+	if len(argv) == 5: # normal argument list len(argv) = 5 #
+		print ("len:%d .py=%s .xml=%s .json=%s MBR=%s .txt=%s" %
+			(len(argv), argv[0], argv[1], argv[2], argv[3], argv[4]))
+	if len(argv) <= 3: # len(argv) = 4 for mt2701 spi nor boot (scatter.txt isn't needed) #
+		print("Usage: len:%d,%s partition_*.xml scatter_*.json [MBR] [scatter.txt] " % (len(argv), argv[0]))
+		exit(1)
+	root = xml.dom.minidom.parse(argv[1])
+	for partition in root.childNodes:
+		if partition.nodeName == "partition":
+			break
+	else:
+		raise Exception("partition not found")
+	if sanity_check(argv[1], partition):
+		return 1
+	write(argv[3], gen_gpt(partition))
+	if len(argv) == 5:
+		with open(os.path.join(os.path.dirname(__file__), argv[2]), "r") as f:
+			d = json.load(f)
+		with open(argv[4], "w") as f:
+			write_scatter(f, partition, d)
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main(sys.argv))
diff --git a/src/bsp/scatter/scripts/gen-partition-nand_merge.py b/src/bsp/scatter/scripts/gen-partition-nand_merge.py
new file mode 100755
index 0000000..3ce67f0
--- /dev/null
+++ b/src/bsp/scatter/scripts/gen-partition-nand_merge.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import binascii
+import json
+import os
+import struct
+import sys
+import uuid
+import xml.dom.minidom
+
+NumberOfPartitionEntries = 64
+SizeOfPartitionEntry = 128
+
+def write(path, data):
+	with open(path, "wb+") as f:
+		f.write(data)
+
+def crc32(data):
+        return binascii.crc32(data) & 0xffffffff
+
+def padding(data, size):
+	return data + b'\0' * (size - len(data))
+
+def gen_gpt(partition):
+	pmbr = (b'\0' * 446 +
+		b"\x00\x00\x02\x00\xee\xff\xff\xff\x01\x00\x00\x00\xff\xff\xff\xff" +
+		b'\0' * 48 + b"\x55\xaa")
+	entries = b''
+	entries2k = b''
+	lba = partition.getAttribute("lba")
+	lba = lba and eval(lba) or 130560
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 4096
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		type = uuid.UUID(node.getAttribute("type"))
+		uniq = node.getAttribute("uuid")
+		uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		attr = node.getAttribute("attributes")
+		attr = attr and eval(attr) or 0
+		name = node.getAttribute("name")
+		if (name == b"userdata") and (end == 0):
+			end = lba - 1
+		if attr == 4:
+			start2k = (start / 256) * 256 + 8
+			entries2k += struct.pack("<16s16sQQQ72s",
+				type.bytes_le,
+				uniq.bytes_le,
+				int(start2k), end, 4,
+				name.encode("utf-16le"))
+			if ((start % 256) == 0):
+				start = (start / 256) * 256 + 4
+		entries += struct.pack("<16s16sQQQ72s",
+			type.bytes_le,
+			uniq.bytes_le,
+			int(start), end, attr,
+			name.encode("utf-16le"))
+	entries = padding(entries, NumberOfPartitionEntries * SizeOfPartitionEntry)
+	entries2k = padding(entries2k, 2048)
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+	uniq = partition.getAttribute("uuid")
+	uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+	if lbs == 4096:
+		pmbr = padding(pmbr, 2048)
+	else:
+		pmbr = padding(pmbr, lbs)
+	header2k = struct.pack("<8sIIIIQQQQ16sQIII",
+		b"EFI PART", 0x00010000, 92, 0, 0,
+		1, # MyLBA
+		1, #lba - 1, # AlternateLBA
+		int(FirstUsableLBA),
+		int(lba - FirstUsableLBA), # LastUsableLBA
+		uniq.bytes_le,
+		3, 4, int(SizeOfPartitionEntry), crc32(entries2k))
+	header2k = padding(header2k[:16] +
+		struct.pack('I', crc32(header2k)) +
+		header2k[20:], 2048)
+	header = struct.pack("<8sIIIIQQQQ16sQIII",
+		b"EFI PART", 0x00010000, 92, 0, 0,
+		1, # MyLBA
+		1, #lba - 1, # AlternateLBA
+		int(FirstUsableLBA),
+		int(lba - FirstUsableLBA), # LastUsableLBA
+		uniq.bytes_le,
+		2, int(NumberOfPartitionEntries), int(SizeOfPartitionEntry), crc32(entries))
+	if lbs == 4096:
+		header = padding(header[:16] +
+			struct.pack('I', crc32(header)) +
+			header[20:], 2048)
+	else:
+		header = padding(header[:16] +
+			struct.pack('I', crc32(header)) +
+			header[20:], lbs)
+	if lbs == 4096:
+		return pmbr + header2k + header + entries2k + entries
+	else:
+		return pmbr + header + entries
+
+def write_scatter_partition(f, entry):
+	if entry.get("file_name", "NONE") != "NONE":
+		entry.setdefault("is_download", True)
+		entry.setdefault("operation_type", "UPDATE")
+		entry.setdefault("type", "NORMAL_ROM")
+	f.write(
+"""- partition_index: %s
+  partition_name: %s
+  file_name: %s
+  is_download: %s
+  type: %s
+  linear_start_addr: %s
+  physical_start_addr: %s
+  partition_size: %s
+  region: %s
+  storage: %s
+  boundary_check: %s
+  is_reserved: %s
+  operation_type: %s
+  d_type: LOW_PAGE
+  slc_percentage: 0
+  is_upgradable: true
+  reserve: %s
+
+""" % (entry["partition_index"], entry["partition_name"], entry.get("file_name", "NONE"),
+entry.get("is_download", False) and "true" or "false", entry.get("type", "NONE"), hex(entry["linear_start_addr"]),
+hex(entry["physical_start_addr"]), hex(entry["partition_size"]), entry.get("region", "NONE"),
+entry.get("storage", "HW_STORAGE_NAND"), entry.get("boundary_check", True) and "true" or "false",
+entry.get("is_reserved", False) and "true" or "false", entry.get("operation_type", "PROTECTED"),
+hex(entry.get("reserve", 0))))
+
+def write_scatter(f, partition, d):
+	f.write(
+"""############################################################################################################
+#
+#  General Setting
+#
+############################################################################################################
+- general: MTK_PLATFORM_CFG
+  info:
+    - config_version: %s
+      platform: %s
+      project: %s
+      storage: %s
+      boot_channel: %s
+      block_size: %s
+      skip_pmt_operate: %s
+############################################################################################################
+#
+#  Layout Setting
+#
+############################################################################################################
+""" % (d["MTK_PLATFORM_CFG"]["config_version"], d["MTK_PLATFORM_CFG"]["platform"], d["MTK_PLATFORM_CFG"]["project"],
+       d["MTK_PLATFORM_CFG"]["storage"], d["MTK_PLATFORM_CFG"]["boot_channel"], d["MTK_PLATFORM_CFG"]["block_size"],
+       d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false"))
+#	d["PRELOADER"]["partition_index"] = "SYS0"
+	d["MBR"]["partition_index"] = "SYS0"
+#	write_scatter_partition(f, d["PRELOADER"])
+	write_scatter_partition(f, d["MBR"])
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 4096
+	i = 1
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		name = node.getAttribute("name")
+		if name not in d:
+			continue
+		entry = d[name]
+		entry["partition_name"] = name
+		entry["partition_index"] = "SYS%d" % i
+		i += 1
+		entry["linear_start_addr"] = start * lbs
+		entry["physical_start_addr"] = start * lbs
+		if end != start:
+			entry["partition_size"] = (end + 1 - start) * lbs
+		else:
+			entry["partition_size"] = 0
+		write_scatter_partition(f, entry)
+	if (d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false") == "false":
+		d["sgpt"]["partition_index"] = "SYS%d" % i
+		write_scatter_partition(f, d["sgpt"])
+
+
+def sanity_check(path, partition):
+	err = 0
+	lba = partition.getAttribute("lba")
+	lba = lba and eval(lba) or 130560
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 4096
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+#	usable = (FirstUsableLBA, lba - FirstUsableLBA)
+	usable = (0, lba)
+	used = {}
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		name = node.getAttribute("name")
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		if (name == "userdata") and (end == 0):
+			end = lba - 1
+		if start > end:
+			print("%s: error: partition '%s': start lba (%d) > end lba (%d)" %
+				(path, name, start, end), file = sys.stderr)
+			err += 1
+		if start < usable[0] or end > usable[1]:
+			print("%s: error: partition '%s': (%d...%d) out of usable range (%d...%d)" %
+				(path, name, start, end, usable[0], usable[1]), file = sys.stderr)
+			err += 1
+		for i in used:
+			if (used[i][0] <= start and start <= used[i][1] or
+				used[i][0] <= end and end <= used[i][1]):
+				print("%s: error: partition '%s': (%d...%d) overlapped with partition '%s' (%d...%d)" %
+					(path, name, start, end, i, used[i][0], used[i][1]), file = sys.stderr)
+				err += 1
+		used[name] = (start, end)
+	return err
+
+def main(argv):
+	if len(argv) == 5: # normal argument list len(argv) = 5 #
+		print ("len:%d .py=%s .xml=%s .json=%s MBR=%s .txt=%s" %
+			(len(argv), argv[0], argv[1], argv[2], argv[3], argv[4]))
+	if len(argv) <= 3: # len(argv) = 4 for mt2701 spi nor boot (scatter.txt isn't needed) #
+		print("Usage: len:%d,%s partition_*.xml scatter_*.json [MBR] [scatter.txt] " % (len(argv), argv[0]))
+		exit(1)
+	root = xml.dom.minidom.parse(argv[1])
+	for partition in root.childNodes:
+		if partition.nodeName == "partition":
+			break
+	else:
+		raise Exception("partition not found")
+	if sanity_check(argv[1], partition):
+		return 1
+	write(argv[3], gen_gpt(partition))
+	if len(argv) == 5:
+		with open(os.path.join(os.path.dirname(__file__), argv[2]), "r") as f:
+			d = json.load(f)
+		with open(argv[4], "w") as f:
+			write_scatter(f, partition, d)
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main(sys.argv))
\ No newline at end of file
diff --git a/src/bsp/scatter/scripts/gen-partition.py b/src/bsp/scatter/scripts/gen-partition.py
new file mode 100755
index 0000000..42d0b82
--- /dev/null
+++ b/src/bsp/scatter/scripts/gen-partition.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+import binascii
+import json
+import os
+import struct
+import sys
+import uuid
+import xml.dom.minidom
+
+NumberOfPartitionEntries = 128
+SizeOfPartitionEntry = 128
+
+def write(path, data):
+	with open(path, "wb+") as f:
+		f.write(data)
+
+def crc32(data):
+        return binascii.crc32(data) & 0xffffffff
+
+def padding(data, size):
+	return data + b'\0' * (size - len(data))
+
+def gen_gpt(partition):
+	pmbr = (b'\0' * 446 +
+		b"\x00\x00\x02\x00\xee\xff\xff\xff\x01\x00\x00\x00\xff\xff\xff\xff" +
+		b'\0' * 48 + b"\x55\xaa")
+	entries = b''
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		type = uuid.UUID(node.getAttribute("type"))
+		uniq = node.getAttribute("uuid")
+		uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		attr = node.getAttribute("attributes")
+		attr = attr and eval(attr) or 0
+		name = node.getAttribute("name")
+		entries += struct.pack("<16s16sQQQ72s",
+			type.bytes_le,
+			uniq.bytes_le,
+			start, end, attr,
+			name.encode("utf-16le"))
+	entries = padding(entries, NumberOfPartitionEntries * SizeOfPartitionEntry)
+	lba = eval(partition.getAttribute("lba"))
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 512
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+	uniq = partition.getAttribute("uuid")
+	uniq = uniq and uuid.UUID(uniq) or uuid.uuid4()
+	pmbr = padding(pmbr, lbs)
+	header = struct.pack("<8sIIIIQQQQ16sQIII",
+		b"EFI PART", 0x00010000, 92, 0, 0,
+		1, # MyLBA
+		1, #lba - 1, # AlternateLBA
+		int(FirstUsableLBA),
+		int(lba - FirstUsableLBA), # LastUsableLBA
+		uniq.bytes_le,
+		2, NumberOfPartitionEntries, SizeOfPartitionEntry, crc32(entries))
+	header = padding(header[:16] +
+		struct.pack('I', crc32(header)) +
+		header[20:], lbs)
+	return pmbr + header + entries
+
+def write_scatter_partition(f, entry):
+	if entry.get("file_name", "NONE") != "NONE":
+		entry.setdefault("is_download", True)
+		entry.setdefault("operation_type", "UPDATE")
+		entry.setdefault("type", "NORMAL_ROM")
+	f.write(
+"""- partition_index: %s
+  partition_name: %s
+  file_name: %s
+  is_download: %s
+  type: %s
+  linear_start_addr: %s
+  physical_start_addr: %s
+  partition_size: %s
+  region: %s
+  storage: %s
+  boundary_check: %s
+  is_reserved: %s
+  operation_type: %s
+  d_type: FALSE
+  reserve: %s
+
+""" % (entry["partition_index"], entry["partition_name"], entry.get("file_name", "NONE"),
+entry.get("is_download", False) and "true" or "false", entry.get("type", "NONE"), hex(entry["linear_start_addr"]),
+hex(entry["physical_start_addr"]), hex(entry["partition_size"]), entry.get("region", "EMMC_USER"),
+entry.get("storage", "HW_STORAGE_EMMC"), entry.get("boundary_check", True) and "true" or "false",
+entry.get("is_reserved", False) and "true" or "false", entry.get("operation_type", "PROTECTED"),
+hex(entry.get("reserve", 0))))
+
+def write_scatter(f, partition, d):
+	f.write(
+"""############################################################################################################
+#
+#  General Setting
+#
+############################################################################################################
+- general: MTK_PLATFORM_CFG
+  info:
+    - config_version: %s
+      platform: %s
+      project: %s
+      storage: %s
+      boot_channel: %s
+      block_size: %s
+      skip_pmt_operate: %s
+############################################################################################################
+#
+#  Layout Setting
+#
+############################################################################################################
+""" % (d["MTK_PLATFORM_CFG"]["config_version"], d["MTK_PLATFORM_CFG"]["platform"], d["MTK_PLATFORM_CFG"]["project"],
+       d["MTK_PLATFORM_CFG"]["storage"], d["MTK_PLATFORM_CFG"]["boot_channel"], d["MTK_PLATFORM_CFG"]["block_size"],
+       d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false"))
+	d["PRELOADER"]["partition_index"] = "SYS0"
+	d["MBR"]["partition_index"] = "SYS1"
+	write_scatter_partition(f, d["PRELOADER"])
+	write_scatter_partition(f, d["MBR"])
+	i = 2
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		name = node.getAttribute("name")
+		if name not in d:
+			continue
+		entry = d[name]
+		entry["partition_name"] = name
+		entry["partition_index"] = "SYS%d" % i
+		i += 1
+		entry["linear_start_addr"] = start * 512
+		entry["physical_start_addr"] = start * 512
+		if (end != start and name != "userdata"):
+			entry["partition_size"] = (end + 1 - start) * 512
+		else:
+			entry["partition_size"] = 0
+		write_scatter_partition(f, entry)
+	if (d["MTK_PLATFORM_CFG"].get("skip_pmt_operate", True) and "true" or "false") == "false":
+		d["sgpt"]["partition_index"] = "SYS%d" % i
+		d["sgpt"]["linear_start_addr"] = 0xffff0080
+		d["sgpt"]["physical_start_addr"] = 0xffff0080
+		write_scatter_partition(f, d["sgpt"])
+
+
+def sanity_check(path, partition):
+	err = 0
+	lba = eval(partition.getAttribute("lba"))
+	lbs = partition.getAttribute("lbs")
+	lbs = lbs and eval(lbs) or 512
+	FirstUsableLBA = 2 + (NumberOfPartitionEntries * SizeOfPartitionEntry / lbs)
+	usable = (FirstUsableLBA, lba - FirstUsableLBA)
+	used = {}
+	for node in partition.childNodes:
+		if node.nodeName != "entry":
+			continue
+		name = node.getAttribute("name")
+		start = eval(node.getAttribute("start"))
+		end = eval(node.getAttribute("end"))
+		if start > end:
+			print("%s: error: partition '%s': start lba (%d) > end lba (%d)" %
+				(path, name, start, end), file = sys.stderr)
+			err += 1
+		if start < usable[0] or end > usable[1]:
+			print("%s: error: partition '%s': (%d...%d) out of usable range (%d...%d)" %
+				(path, name, start, end, usable[0], usable[1]), file = sys.stderr)
+			err += 1
+		for i in used:
+			if (used[i][0] <= start and start <= used[i][1] or
+				used[i][0] <= end and end <= used[i][1]):
+				print("%s: error: partition '%s': (%d...%d) overlapped with partition '%s' (%d...%d)" %
+					(path, name, start, end, i, used[i][0], used[i][1]), file = sys.stderr)
+				err += 1
+		used[name] = (start, end)
+	return err
+
+def main(argv):
+	if len(argv) == 5: # normal argument list len(argv) = 5 #
+		print ("len:%d .py=%s .xml=%s .json=%s MBR=%s .txt=%s" %
+			(len(argv), argv[0], argv[1], argv[2], argv[3], argv[4]))
+	if len(argv) <= 3: # len(argv) = 4 for mt2701 spi nor boot (scatter.txt isn't needed) #
+		print("Usage: len:%d,%s partition_*.xml scatter_*.json [MBR] [scatter.txt] " % (len(argv), argv[0]))
+		exit(1)
+	root = xml.dom.minidom.parse(argv[1])
+	for partition in root.childNodes:
+		if partition.nodeName == "partition":
+			break
+	else:
+		raise Exception("partition not found")
+	if sanity_check(argv[1], partition):
+		return 1
+	write(argv[3], gen_gpt(partition))
+	if len(argv) == 5:
+		with open(os.path.join(os.path.dirname(__file__), argv[2]), "r") as f:
+			d = json.load(f)
+		with open(argv[4], "w") as f:
+			write_scatter(f, partition, d)
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main(sys.argv))
diff --git a/src/bsp/scatter/scripts/gen-partitions.sh b/src/bsp/scatter/scripts/gen-partitions.sh
new file mode 100755
index 0000000..4cbee84
--- /dev/null
+++ b/src/bsp/scatter/scripts/gen-partitions.sh
@@ -0,0 +1,119 @@
+#! /bin/sh
+
+PROJECT=$1
+OUT=$2
+BOOTDEV_TYPE=$3
+SCATTER_SRC=$4
+NAND_CHIP_NAME=$5
+NAND_HEADER_VERSION=$6
+HEADER_LK_MERGE=$7
+
+
+if [ ! -e ${PROJECT}/gen-partitions.ini ]; then
+	echo ERROR: can not find $1
+	exit 1
+fi
+
+mkdir -p ${OUT}
+cat ${PROJECT}/gen-partitions.ini | while read p s m t
+do
+	if [ "$t" = "" ]; then
+		if [ "${BOOTDEV_TYPE}" = "nand" ]; then
+			if [ "${HEADER_LK_MERGE}" = "yes" ]; then
+				python3 scripts/gen-partition-nand_merge.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m
+			else
+				python3 scripts/gen-partition-nand.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m
+			fi
+		else
+			python3 ${SCATTER_SRC}/gen-partition.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m
+		fi
+	else
+		if [ "${BOOTDEV_TYPE}" = "nand" ]; then
+			if [ "${HEADER_LK_MERGE}" = "yes" ]; then
+				python3 scripts/gen-partition-nand_merge.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m ${OUT}/$t
+			else
+				python3 scripts/gen-partition-nand.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m ${OUT}/$t
+			fi
+		else
+			python3 ${SCATTER_SRC}/gen-partition.py ${PROJECT}/$p ${PROJECT}/$s ${OUT}/$m ${OUT}/$t
+		fi
+	fi
+
+	if [ "${BOOTDEV_TYPE}" = "nand" ]; then
+		if [ "${NAND_HEADER_VERSION}" = "2.0" ]; then
+			if [ "$m" = "MBR_NAND" ]; then
+				python3 -B ${PWD}/tools/nand-utils/gen_nand_header.py ${NAND_CHIP_NAME} ${OUT}/$m
+			fi
+		elif [ "${NAND_HEADER_VERSION}" = "1.1" ]; then
+			lk_start=$(grep 'name="bl2"' ${PROJECT}/$p | grep -o 'start="[0-9]*"' | grep -o [0-9]*)
+			if [ "${lk_start}" = "" ]; then
+				echo ERROR: can not find UBOOT in ${PROJECT}/$p
+				exit 1
+			fi
+			temp_header_file="temp_nand_header.bin"
+			python3 -B ${PWD}/tools/nand-utils/gen_nand_header_v11.py ${NAND_CHIP_NAME} ${lk_start} ${OUT}/${temp_header_file}
+			cat ${OUT}/$m >> ${OUT}/${temp_header_file}
+			rm ${OUT}/$m
+			mv ${OUT}/${temp_header_file} ${OUT}/$m
+		elif [ "${NAND_HEADER_VERSION}" = "1.2" ]; then
+			temp_header_file="temp_nand_header.bin"
+			python3 -B ${PWD}/tools/nand-utils/gen_nand_header_v12.py ${NAND_CHIP_NAME} ${OUT}/${temp_header_file}
+			dd if=${OUT}/${temp_header_file} of=${OUT}/$m conv=notrunc
+			rm ${OUT}/${temp_header_file}
+		elif [ "${NAND_HEADER_VERSION}" = "1.3" ]; then
+			preloader_start=$(grep 'name="preloader"' ${PROJECT}/$p | grep -o 'start="[0-9]*"' | grep -o [0-9]*)
+			if [ "${preloader_start}" = "" ]; then
+					echo ERROR: can not find preloader in ${PROJECT}/$p
+					exit 1
+			fi
+			temp_header_file="temp_nand_header.bin"
+			python3 -B ${PWD}/tools/nand-utils/gen_nand_header_v13.py ${NAND_CHIP_NAME} ${preloader_start} ${OUT}/${temp_header_file}
+			cat ${OUT}/$m >> ${OUT}/${temp_header_file}
+			rm ${OUT}/$m
+			mv ${OUT}/${temp_header_file} ${OUT}/$m
+		elif [ "${NAND_HEADER_VERSION}" = "1.4" ]; then
+			temp_header_file="temp_nand_header.bin"
+			python -B ${PWD}/tools/nand-utils/gen_nand_header_v14.py ${NAND_CHIP_NAME} ${OUT}/${temp_header_file}
+			dd if=${OUT}/${temp_header_file} of=${OUT}/$m conv=notrunc
+			rm ${OUT}/${temp_header_file}
+		elif [ "${NAND_HEADER_VERSION}" = "3.0" ]; then
+			if [ "$m" = "MBR_NAND" ]; then
+				python -B ${PWD}/tools/nand-utils/gen_nand_header_mt2731.py ${NAND_CHIP_NAME} ${OUT}/$m
+			fi
+		elif [ "${NAND_HEADER_VERSION}" = "4.0" ]; then
+			if [ "$m" = "MBR_NAND" ]; then
+				python3 -B ${PWD}/tools/nand-utils/gen_nand_header_v4.py ${NAND_CHIP_NAME} ${OUT}/$m
+			fi
+		elif [ "${NAND_HEADER_VERSION}" = "5.0" ]; then
+			if [ "$m" = "MBR_NAND" ]; then
+				python -B ${PWD}/tools/nand-utils/gen_nand_header_mt2735_hsm.py ${NAND_CHIP_NAME} ${OUT}/$m
+			fi
+		else
+			if [ "${NAND_CHIP_NAME}" = "" ]; then
+				echo ERROR: please check NAND_CHIP_NAME ${NAND_CHIP_NAME}
+				exit 2
+			fi
+
+			PAGE_SIZE=$(grep -o '^'${NAND_CHIP_NAME}'	[0-9]*' nand-setting.txt | grep -o '[0-9]*$')
+			LBS=$(grep -o 'lbs="[0-9]*"' ${PROJECT}/$p | grep -o [0-9]*)
+			if [ "${PAGE_SIZE}" != "${LBS}" ]; then
+				echo ERROR: PAGE_SIZE ${PAGE_SIZE} of NAND ${NAND_CHIP_NAME} != LBS ${LBS} of partition table ${PROJECT}/$p
+				exit 3
+			fi
+
+			LK1=$(grep 'name="LK1"' ${PROJECT}/$p | grep -o 'start="[0-9]*"' | grep -o [0-9]*)
+			if [ "${LK1}" = "" ]; then
+				echo ERROR: can not find LK1 in ${PROJECT}/$p
+				exit 4
+			fi
+
+			LK2=$(grep 'name="LK2"' ${PROJECT}/$p | grep -o 'start="[0-9]*"' | grep -o [0-9]*)
+			if [ "${LK2}" = "" ]; then
+				echo ERROR: can not find LK2 in ${PROJECT}/$p
+				exit 5
+			fi
+
+			python3 scripts/dev-info-hdr-tool.py ${BOOTDEV_TYPE} ${OUT}/$m ${OUT}/$m ${NAND_CHIP_NAME} ${LK1} ${LK2}
+		fi
+	fi
+done
diff --git a/src/bsp/scatter/scripts/nand-setting.txt b/src/bsp/scatter/scripts/nand-setting.txt
new file mode 100644
index 0000000..5d76981
--- /dev/null
+++ b/src/bsp/scatter/scripts/nand-setting.txt
@@ -0,0 +1,2 @@
+MX30LF1G18AC	2048
+MX30LF4G18AC	2048