18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *   Octeon Bootbus flash setup
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
58c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
68c2ecf20Sopenharmony_ci * for more details.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008 Cavium Networks
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/semaphore.h>
138c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
148c2ecf20Sopenharmony_ci#include <linux/mtd/map.h>
158c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
168c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic struct map_info flash_map;
218c2ecf20Sopenharmony_cistatic struct mtd_info *mymtd;
228c2ecf20Sopenharmony_cistatic const char *part_probe_types[] = {
238c2ecf20Sopenharmony_ci	"cmdlinepart",
248c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_REDBOOT_PARTS
258c2ecf20Sopenharmony_ci	"RedBoot",
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci	NULL
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic map_word octeon_flash_map_read(struct map_info *map, unsigned long ofs)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	map_word r;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	down(&octeon_bootbus_sem);
358c2ecf20Sopenharmony_ci	r = inline_map_read(map, ofs);
368c2ecf20Sopenharmony_ci	up(&octeon_bootbus_sem);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	return r;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic void octeon_flash_map_write(struct map_info *map, const map_word datum,
428c2ecf20Sopenharmony_ci				   unsigned long ofs)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	down(&octeon_bootbus_sem);
458c2ecf20Sopenharmony_ci	inline_map_write(map, datum, ofs);
468c2ecf20Sopenharmony_ci	up(&octeon_bootbus_sem);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void octeon_flash_map_copy_from(struct map_info *map, void *to,
508c2ecf20Sopenharmony_ci				       unsigned long from, ssize_t len)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	down(&octeon_bootbus_sem);
538c2ecf20Sopenharmony_ci	inline_map_copy_from(map, to, from, len);
548c2ecf20Sopenharmony_ci	up(&octeon_bootbus_sem);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void octeon_flash_map_copy_to(struct map_info *map, unsigned long to,
588c2ecf20Sopenharmony_ci				     const void *from, ssize_t len)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	down(&octeon_bootbus_sem);
618c2ecf20Sopenharmony_ci	inline_map_copy_to(map, to, from, len);
628c2ecf20Sopenharmony_ci	up(&octeon_bootbus_sem);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/**
668c2ecf20Sopenharmony_ci * Module/ driver initialization.
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * Returns Zero on success
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistatic int octeon_flash_probe(struct platform_device *pdev)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	union cvmx_mio_boot_reg_cfgx region_cfg;
738c2ecf20Sopenharmony_ci	u32 cs;
748c2ecf20Sopenharmony_ci	int r;
758c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	r = of_property_read_u32(np, "reg", &cs);
788c2ecf20Sopenharmony_ci	if (r)
798c2ecf20Sopenharmony_ci		return r;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/*
828c2ecf20Sopenharmony_ci	 * Read the bootbus region 0 setup to determine the base
838c2ecf20Sopenharmony_ci	 * address of the flash.
848c2ecf20Sopenharmony_ci	 */
858c2ecf20Sopenharmony_ci	region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
868c2ecf20Sopenharmony_ci	if (region_cfg.s.en) {
878c2ecf20Sopenharmony_ci		/*
888c2ecf20Sopenharmony_ci		 * The bootloader always takes the flash and sets its
898c2ecf20Sopenharmony_ci		 * address so the entire flash fits below
908c2ecf20Sopenharmony_ci		 * 0x1fc00000. This way the flash aliases to
918c2ecf20Sopenharmony_ci		 * 0x1fc00000 for booting. Software can access the
928c2ecf20Sopenharmony_ci		 * full flash at the true address, while core boot can
938c2ecf20Sopenharmony_ci		 * access 4MB.
948c2ecf20Sopenharmony_ci		 */
958c2ecf20Sopenharmony_ci		/* Use this name so old part lines work */
968c2ecf20Sopenharmony_ci		flash_map.name = "phys_mapped_flash";
978c2ecf20Sopenharmony_ci		flash_map.phys = region_cfg.s.base << 16;
988c2ecf20Sopenharmony_ci		flash_map.size = 0x1fc00000 - flash_map.phys;
998c2ecf20Sopenharmony_ci		/* 8-bit bus (0 + 1) or 16-bit bus (1 + 1) */
1008c2ecf20Sopenharmony_ci		flash_map.bankwidth = region_cfg.s.width + 1;
1018c2ecf20Sopenharmony_ci		flash_map.virt = ioremap(flash_map.phys, flash_map.size);
1028c2ecf20Sopenharmony_ci		pr_notice("Bootbus flash: Setting flash for %luMB flash at "
1038c2ecf20Sopenharmony_ci			  "0x%08llx\n", flash_map.size >> 20, flash_map.phys);
1048c2ecf20Sopenharmony_ci		WARN_ON(!map_bankwidth_supported(flash_map.bankwidth));
1058c2ecf20Sopenharmony_ci		flash_map.read = octeon_flash_map_read;
1068c2ecf20Sopenharmony_ci		flash_map.write = octeon_flash_map_write;
1078c2ecf20Sopenharmony_ci		flash_map.copy_from = octeon_flash_map_copy_from;
1088c2ecf20Sopenharmony_ci		flash_map.copy_to = octeon_flash_map_copy_to;
1098c2ecf20Sopenharmony_ci		mymtd = do_map_probe("cfi_probe", &flash_map);
1108c2ecf20Sopenharmony_ci		if (mymtd) {
1118c2ecf20Sopenharmony_ci			mymtd->owner = THIS_MODULE;
1128c2ecf20Sopenharmony_ci			mtd_device_parse_register(mymtd, part_probe_types,
1138c2ecf20Sopenharmony_ci						  NULL, NULL, 0);
1148c2ecf20Sopenharmony_ci		} else {
1158c2ecf20Sopenharmony_ci			pr_err("Failed to register MTD device for flash\n");
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	return 0;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const struct of_device_id of_flash_match[] = {
1228c2ecf20Sopenharmony_ci	{
1238c2ecf20Sopenharmony_ci		.compatible	= "cfi-flash",
1248c2ecf20Sopenharmony_ci	},
1258c2ecf20Sopenharmony_ci	{ },
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_flash_match);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic struct platform_driver of_flash_driver = {
1308c2ecf20Sopenharmony_ci	.driver = {
1318c2ecf20Sopenharmony_ci		.name = "octeon-of-flash",
1328c2ecf20Sopenharmony_ci		.of_match_table = of_flash_match,
1338c2ecf20Sopenharmony_ci	},
1348c2ecf20Sopenharmony_ci	.probe		= octeon_flash_probe,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int octeon_flash_init(void)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return platform_driver_register(&of_flash_driver);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_cilate_initcall(octeon_flash_init);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
144