xref: /linux/drivers/mtd/maps/physmap-gemini.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
256ff337eSLinus Walleij /*
356ff337eSLinus Walleij  * Cortina Systems Gemini OF physmap add-on
456ff337eSLinus Walleij  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
556ff337eSLinus Walleij  *
656ff337eSLinus Walleij  * This SoC has an elaborate flash control register, so we need to
756ff337eSLinus Walleij  * detect and set it up when booting on this platform.
856ff337eSLinus Walleij  */
956ff337eSLinus Walleij #include <linux/export.h>
1056ff337eSLinus Walleij #include <linux/of.h>
1156ff337eSLinus Walleij #include <linux/of_device.h>
1256ff337eSLinus Walleij #include <linux/mtd/map.h>
139d3b5086SLinus Walleij #include <linux/mtd/xip.h>
1456ff337eSLinus Walleij #include <linux/mfd/syscon.h>
1556ff337eSLinus Walleij #include <linux/regmap.h>
1656ff337eSLinus Walleij #include <linux/bitops.h>
179d3b5086SLinus Walleij #include <linux/pinctrl/consumer.h>
186ca15cfaSBoris Brezillon #include "physmap-gemini.h"
1956ff337eSLinus Walleij 
2056ff337eSLinus Walleij /*
2156ff337eSLinus Walleij  * The Flash-relevant parts of the global status register
2256ff337eSLinus Walleij  * These would also be relevant for a NAND driver.
2356ff337eSLinus Walleij  */
2456ff337eSLinus Walleij #define GLOBAL_STATUS			0x04
2556ff337eSLinus Walleij #define FLASH_TYPE_MASK			(0x3 << 24)
2656ff337eSLinus Walleij #define FLASH_TYPE_NAND_2K		(0x3 << 24)
2756ff337eSLinus Walleij #define FLASH_TYPE_NAND_512		(0x2 << 24)
2856ff337eSLinus Walleij #define FLASH_TYPE_PARALLEL		(0x1 << 24)
2956ff337eSLinus Walleij #define FLASH_TYPE_SERIAL		(0x0 << 24)
3056ff337eSLinus Walleij /* if parallel */
3156ff337eSLinus Walleij #define FLASH_WIDTH_16BIT		(1 << 23)	/* else 8 bit */
3256ff337eSLinus Walleij /* if serial */
3356ff337eSLinus Walleij #define FLASH_ATMEL			(1 << 23)	/* else STM */
3456ff337eSLinus Walleij 
3556ff337eSLinus Walleij #define FLASH_SIZE_MASK			(0x3 << 21)
3656ff337eSLinus Walleij #define NAND_256M			(0x3 << 21)	/* and more */
3756ff337eSLinus Walleij #define NAND_128M			(0x2 << 21)
3856ff337eSLinus Walleij #define NAND_64M			(0x1 << 21)
3956ff337eSLinus Walleij #define NAND_32M			(0x0 << 21)
4056ff337eSLinus Walleij #define ATMEL_16M			(0x3 << 21)	/* and more */
4156ff337eSLinus Walleij #define ATMEL_8M			(0x2 << 21)
4256ff337eSLinus Walleij #define ATMEL_4M_2M			(0x1 << 21)
4356ff337eSLinus Walleij #define ATMEL_1M			(0x0 << 21)	/* and less */
4456ff337eSLinus Walleij #define STM_32M				(1 << 22)	/* and more */
4556ff337eSLinus Walleij #define STM_16M				(0 << 22)	/* and less */
4656ff337eSLinus Walleij 
4756ff337eSLinus Walleij #define FLASH_PARALLEL_HIGH_PIN_CNT	(1 << 20)	/* else low pin cnt */
4856ff337eSLinus Walleij 
499d3b5086SLinus Walleij struct gemini_flash {
509d3b5086SLinus Walleij 	struct device *dev;
519d3b5086SLinus Walleij 	struct pinctrl *p;
529d3b5086SLinus Walleij 	struct pinctrl_state *enabled_state;
539d3b5086SLinus Walleij 	struct pinctrl_state *disabled_state;
549d3b5086SLinus Walleij };
559d3b5086SLinus Walleij 
569d3b5086SLinus Walleij /* Static local state */
579d3b5086SLinus Walleij static struct gemini_flash *gf;
589d3b5086SLinus Walleij 
599d3b5086SLinus Walleij static void gemini_flash_enable_pins(void)
609d3b5086SLinus Walleij {
619d3b5086SLinus Walleij 	int ret;
629d3b5086SLinus Walleij 
639d3b5086SLinus Walleij 	if (IS_ERR(gf->enabled_state))
649d3b5086SLinus Walleij 		return;
659d3b5086SLinus Walleij 	ret = pinctrl_select_state(gf->p, gf->enabled_state);
669d3b5086SLinus Walleij 	if (ret)
679d3b5086SLinus Walleij 		dev_err(gf->dev, "failed to enable pins\n");
689d3b5086SLinus Walleij }
699d3b5086SLinus Walleij 
709d3b5086SLinus Walleij static void gemini_flash_disable_pins(void)
719d3b5086SLinus Walleij {
729d3b5086SLinus Walleij 	int ret;
739d3b5086SLinus Walleij 
749d3b5086SLinus Walleij 	if (IS_ERR(gf->disabled_state))
759d3b5086SLinus Walleij 		return;
769d3b5086SLinus Walleij 	ret = pinctrl_select_state(gf->p, gf->disabled_state);
779d3b5086SLinus Walleij 	if (ret)
789d3b5086SLinus Walleij 		dev_err(gf->dev, "failed to disable pins\n");
799d3b5086SLinus Walleij }
809d3b5086SLinus Walleij 
819d3b5086SLinus Walleij static map_word __xipram gemini_flash_map_read(struct map_info *map,
829d3b5086SLinus Walleij 					       unsigned long ofs)
839d3b5086SLinus Walleij {
84*c58b1ff2SArnd Bergmann 	map_word ret;
859d3b5086SLinus Walleij 
869d3b5086SLinus Walleij 	gemini_flash_enable_pins();
879d3b5086SLinus Walleij 	ret = inline_map_read(map, ofs);
889d3b5086SLinus Walleij 	gemini_flash_disable_pins();
899d3b5086SLinus Walleij 
909d3b5086SLinus Walleij 	return ret;
919d3b5086SLinus Walleij }
929d3b5086SLinus Walleij 
939d3b5086SLinus Walleij static void __xipram gemini_flash_map_write(struct map_info *map,
949d3b5086SLinus Walleij 					    const map_word datum,
959d3b5086SLinus Walleij 					    unsigned long ofs)
969d3b5086SLinus Walleij {
979d3b5086SLinus Walleij 	gemini_flash_enable_pins();
989d3b5086SLinus Walleij 	inline_map_write(map, datum, ofs);
999d3b5086SLinus Walleij 	gemini_flash_disable_pins();
1009d3b5086SLinus Walleij }
1019d3b5086SLinus Walleij 
1029d3b5086SLinus Walleij static void __xipram gemini_flash_map_copy_from(struct map_info *map,
1039d3b5086SLinus Walleij 						void *to, unsigned long from,
1049d3b5086SLinus Walleij 						ssize_t len)
1059d3b5086SLinus Walleij {
1069d3b5086SLinus Walleij 	gemini_flash_enable_pins();
1079d3b5086SLinus Walleij 	inline_map_copy_from(map, to, from, len);
1089d3b5086SLinus Walleij 	gemini_flash_disable_pins();
1099d3b5086SLinus Walleij }
1109d3b5086SLinus Walleij 
1119d3b5086SLinus Walleij static void __xipram gemini_flash_map_copy_to(struct map_info *map,
1129d3b5086SLinus Walleij 					      unsigned long to,
1139d3b5086SLinus Walleij 					      const void *from, ssize_t len)
1149d3b5086SLinus Walleij {
1159d3b5086SLinus Walleij 	gemini_flash_enable_pins();
1169d3b5086SLinus Walleij 	inline_map_copy_to(map, to, from, len);
1179d3b5086SLinus Walleij 	gemini_flash_disable_pins();
1189d3b5086SLinus Walleij }
1199d3b5086SLinus Walleij 
12056ff337eSLinus Walleij int of_flash_probe_gemini(struct platform_device *pdev,
12156ff337eSLinus Walleij 			  struct device_node *np,
12256ff337eSLinus Walleij 			  struct map_info *map)
12356ff337eSLinus Walleij {
1246c51a52eSJulia Lawall 	struct regmap *rmap;
12556ff337eSLinus Walleij 	struct device *dev = &pdev->dev;
12656ff337eSLinus Walleij 	u32 val;
12756ff337eSLinus Walleij 	int ret;
12856ff337eSLinus Walleij 
12956ff337eSLinus Walleij 	/* Multiplatform guard */
13056ff337eSLinus Walleij 	if (!of_device_is_compatible(np, "cortina,gemini-flash"))
13156ff337eSLinus Walleij 		return 0;
13256ff337eSLinus Walleij 
1339d3b5086SLinus Walleij 	gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);
1349d3b5086SLinus Walleij 	if (!gf)
1359d3b5086SLinus Walleij 		return -ENOMEM;
1369d3b5086SLinus Walleij 	gf->dev = dev;
1379d3b5086SLinus Walleij 
13856ff337eSLinus Walleij 	rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
13956ff337eSLinus Walleij 	if (IS_ERR(rmap)) {
14056ff337eSLinus Walleij 		dev_err(dev, "no syscon\n");
14156ff337eSLinus Walleij 		return PTR_ERR(rmap);
14256ff337eSLinus Walleij 	}
14356ff337eSLinus Walleij 
14456ff337eSLinus Walleij 	ret = regmap_read(rmap, GLOBAL_STATUS, &val);
14556ff337eSLinus Walleij 	if (ret) {
14656ff337eSLinus Walleij 		dev_err(dev, "failed to read global status register\n");
14756ff337eSLinus Walleij 		return -ENODEV;
14856ff337eSLinus Walleij 	}
14956ff337eSLinus Walleij 	dev_dbg(dev, "global status reg: %08x\n", val);
15056ff337eSLinus Walleij 
15156ff337eSLinus Walleij 	/*
15256ff337eSLinus Walleij 	 * It would be contradictory if a physmap flash was NOT parallel.
15356ff337eSLinus Walleij 	 */
15456ff337eSLinus Walleij 	if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {
15556ff337eSLinus Walleij 		dev_err(dev, "flash is not parallel\n");
15656ff337eSLinus Walleij 		return -ENODEV;
15756ff337eSLinus Walleij 	}
15856ff337eSLinus Walleij 
15956ff337eSLinus Walleij 	/*
16056ff337eSLinus Walleij 	 * Complain if DT data and hardware definition is different.
16156ff337eSLinus Walleij 	 */
16256ff337eSLinus Walleij 	if (val & FLASH_WIDTH_16BIT) {
16356ff337eSLinus Walleij 		if (map->bankwidth != 2)
16456ff337eSLinus Walleij 			dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",
16556ff337eSLinus Walleij 				 map->bankwidth * 8);
16656ff337eSLinus Walleij 	} else {
16756ff337eSLinus Walleij 		if (map->bankwidth != 1)
16856ff337eSLinus Walleij 			dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",
16956ff337eSLinus Walleij 				 map->bankwidth * 8);
17056ff337eSLinus Walleij 	}
17156ff337eSLinus Walleij 
1729d3b5086SLinus Walleij 	gf->p = devm_pinctrl_get(dev);
1739d3b5086SLinus Walleij 	if (IS_ERR(gf->p)) {
1749d3b5086SLinus Walleij 		dev_err(dev, "no pinctrl handle\n");
1759d3b5086SLinus Walleij 		ret = PTR_ERR(gf->p);
1769d3b5086SLinus Walleij 		return ret;
1779d3b5086SLinus Walleij 	}
1789d3b5086SLinus Walleij 
1799d3b5086SLinus Walleij 	gf->enabled_state = pinctrl_lookup_state(gf->p, "enabled");
1809d3b5086SLinus Walleij 	if (IS_ERR(gf->enabled_state))
1819d3b5086SLinus Walleij 		dev_err(dev, "no enabled pin control state\n");
1829d3b5086SLinus Walleij 
1839d3b5086SLinus Walleij 	gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");
1849d3b5086SLinus Walleij 	if (IS_ERR(gf->enabled_state)) {
1859d3b5086SLinus Walleij 		dev_err(dev, "no disabled pin control state\n");
1869d3b5086SLinus Walleij 	} else {
1879d3b5086SLinus Walleij 		ret = pinctrl_select_state(gf->p, gf->disabled_state);
1889d3b5086SLinus Walleij 		if (ret)
1899d3b5086SLinus Walleij 			dev_err(gf->dev, "failed to disable pins\n");
1909d3b5086SLinus Walleij 	}
1919d3b5086SLinus Walleij 
1929d3b5086SLinus Walleij 	map->read = gemini_flash_map_read;
1939d3b5086SLinus Walleij 	map->write = gemini_flash_map_write;
1949d3b5086SLinus Walleij 	map->copy_from = gemini_flash_map_copy_from;
1959d3b5086SLinus Walleij 	map->copy_to = gemini_flash_map_copy_to;
1969d3b5086SLinus Walleij 
1979d3b5086SLinus Walleij 	dev_info(dev, "initialized Gemini-specific physmap control\n");
19856ff337eSLinus Walleij 
19956ff337eSLinus Walleij 	return 0;
20056ff337eSLinus Walleij }
201