201 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Cortina Systems Gemini OF physmap add-on4 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>5 *6 * This SoC has an elaborate flash control register, so we need to7 * detect and set it up when booting on this platform.8 */9#include <linux/export.h>10#include <linux/of.h>11#include <linux/mtd/map.h>12#include <linux/mtd/xip.h>13#include <linux/mfd/syscon.h>14#include <linux/platform_device.h>15#include <linux/regmap.h>16#include <linux/bitops.h>17#include <linux/pinctrl/consumer.h>18#include "physmap-gemini.h"19 20/*21 * The Flash-relevant parts of the global status register22 * These would also be relevant for a NAND driver.23 */24#define GLOBAL_STATUS 0x0425#define FLASH_TYPE_MASK (0x3 << 24)26#define FLASH_TYPE_NAND_2K (0x3 << 24)27#define FLASH_TYPE_NAND_512 (0x2 << 24)28#define FLASH_TYPE_PARALLEL (0x1 << 24)29#define FLASH_TYPE_SERIAL (0x0 << 24)30/* if parallel */31#define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */32/* if serial */33#define FLASH_ATMEL (1 << 23) /* else STM */34 35#define FLASH_SIZE_MASK (0x3 << 21)36#define NAND_256M (0x3 << 21) /* and more */37#define NAND_128M (0x2 << 21)38#define NAND_64M (0x1 << 21)39#define NAND_32M (0x0 << 21)40#define ATMEL_16M (0x3 << 21) /* and more */41#define ATMEL_8M (0x2 << 21)42#define ATMEL_4M_2M (0x1 << 21)43#define ATMEL_1M (0x0 << 21) /* and less */44#define STM_32M (1 << 22) /* and more */45#define STM_16M (0 << 22) /* and less */46 47#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */48 49struct gemini_flash {50 struct device *dev;51 struct pinctrl *p;52 struct pinctrl_state *enabled_state;53 struct pinctrl_state *disabled_state;54};55 56/* Static local state */57static struct gemini_flash *gf;58 59static void gemini_flash_enable_pins(void)60{61 int ret;62 63 if (IS_ERR(gf->enabled_state))64 return;65 ret = pinctrl_select_state(gf->p, gf->enabled_state);66 if (ret)67 dev_err(gf->dev, "failed to enable pins\n");68}69 70static void gemini_flash_disable_pins(void)71{72 int ret;73 74 if (IS_ERR(gf->disabled_state))75 return;76 ret = pinctrl_select_state(gf->p, gf->disabled_state);77 if (ret)78 dev_err(gf->dev, "failed to disable pins\n");79}80 81static map_word __xipram gemini_flash_map_read(struct map_info *map,82 unsigned long ofs)83{84 map_word ret;85 86 gemini_flash_enable_pins();87 ret = inline_map_read(map, ofs);88 gemini_flash_disable_pins();89 90 return ret;91}92 93static void __xipram gemini_flash_map_write(struct map_info *map,94 const map_word datum,95 unsigned long ofs)96{97 gemini_flash_enable_pins();98 inline_map_write(map, datum, ofs);99 gemini_flash_disable_pins();100}101 102static void __xipram gemini_flash_map_copy_from(struct map_info *map,103 void *to, unsigned long from,104 ssize_t len)105{106 gemini_flash_enable_pins();107 inline_map_copy_from(map, to, from, len);108 gemini_flash_disable_pins();109}110 111static void __xipram gemini_flash_map_copy_to(struct map_info *map,112 unsigned long to,113 const void *from, ssize_t len)114{115 gemini_flash_enable_pins();116 inline_map_copy_to(map, to, from, len);117 gemini_flash_disable_pins();118}119 120int of_flash_probe_gemini(struct platform_device *pdev,121 struct device_node *np,122 struct map_info *map)123{124 struct regmap *rmap;125 struct device *dev = &pdev->dev;126 u32 val;127 int ret;128 129 /* Multiplatform guard */130 if (!of_device_is_compatible(np, "cortina,gemini-flash"))131 return 0;132 133 gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);134 if (!gf)135 return -ENOMEM;136 gf->dev = dev;137 138 rmap = syscon_regmap_lookup_by_phandle(np, "syscon");139 if (IS_ERR(rmap)) {140 dev_err(dev, "no syscon\n");141 return PTR_ERR(rmap);142 }143 144 ret = regmap_read(rmap, GLOBAL_STATUS, &val);145 if (ret) {146 dev_err(dev, "failed to read global status register\n");147 return -ENODEV;148 }149 dev_dbg(dev, "global status reg: %08x\n", val);150 151 /*152 * It would be contradictory if a physmap flash was NOT parallel.153 */154 if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {155 dev_err(dev, "flash is not parallel\n");156 return -ENODEV;157 }158 159 /*160 * Complain if DT data and hardware definition is different.161 */162 if (val & FLASH_WIDTH_16BIT) {163 if (map->bankwidth != 2)164 dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",165 map->bankwidth * 8);166 } else {167 if (map->bankwidth != 1)168 dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",169 map->bankwidth * 8);170 }171 172 gf->p = devm_pinctrl_get(dev);173 if (IS_ERR(gf->p)) {174 dev_err(dev, "no pinctrl handle\n");175 ret = PTR_ERR(gf->p);176 return ret;177 }178 179 gf->enabled_state = pinctrl_lookup_state(gf->p, "enabled");180 if (IS_ERR(gf->enabled_state))181 dev_err(dev, "no enabled pin control state\n");182 183 gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");184 if (IS_ERR(gf->enabled_state)) {185 dev_err(dev, "no disabled pin control state\n");186 } else {187 ret = pinctrl_select_state(gf->p, gf->disabled_state);188 if (ret)189 dev_err(gf->dev, "failed to disable pins\n");190 }191 192 map->read = gemini_flash_map_read;193 map->write = gemini_flash_map_write;194 map->copy_from = gemini_flash_map_copy_from;195 map->copy_to = gemini_flash_map_copy_to;196 197 dev_info(dev, "initialized Gemini-specific physmap control\n");198 199 return 0;200}201