243 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Versatile OF physmap driver add-on4 *5 * Copyright (c) 2016, Linaro Limited6 * Author: Linus Walleij <linus.walleij@linaro.org>7 */8#include <linux/export.h>9#include <linux/io.h>10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/mtd/map.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 "physmap-versatile.h"18 19static struct regmap *syscon_regmap;20 21enum versatile_flashprot {22 INTEGRATOR_AP_FLASHPROT,23 INTEGRATOR_CP_FLASHPROT,24 VERSATILE_FLASHPROT,25 REALVIEW_FLASHPROT,26};27 28static const struct of_device_id syscon_match[] = {29 {30 .compatible = "arm,integrator-ap-syscon",31 .data = (void *)INTEGRATOR_AP_FLASHPROT,32 },33 {34 .compatible = "arm,integrator-cp-syscon",35 .data = (void *)INTEGRATOR_CP_FLASHPROT,36 },37 {38 .compatible = "arm,core-module-versatile",39 .data = (void *)VERSATILE_FLASHPROT,40 },41 {42 .compatible = "arm,realview-eb-syscon",43 .data = (void *)REALVIEW_FLASHPROT,44 },45 {46 .compatible = "arm,realview-pb1176-syscon",47 .data = (void *)REALVIEW_FLASHPROT,48 },49 {50 .compatible = "arm,realview-pb11mp-syscon",51 .data = (void *)REALVIEW_FLASHPROT,52 },53 {54 .compatible = "arm,realview-pba8-syscon",55 .data = (void *)REALVIEW_FLASHPROT,56 },57 {58 .compatible = "arm,realview-pbx-syscon",59 .data = (void *)REALVIEW_FLASHPROT,60 },61 {},62};63 64/*65 * Flash protection handling for the Integrator/AP66 */67#define INTEGRATOR_SC_CTRLS_OFFSET 0x0868#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C69#define INTEGRATOR_SC_CTRL_FLVPPEN BIT(1)70#define INTEGRATOR_SC_CTRL_FLWP BIT(2)71 72#define INTEGRATOR_EBI_CSR1_OFFSET 0x0473/* The manual says bit 2, the code says bit 3, trust the code */74#define INTEGRATOR_EBI_WRITE_ENABLE BIT(3)75#define INTEGRATOR_EBI_LOCK_OFFSET 0x2076#define INTEGRATOR_EBI_LOCK_VAL 0xA05F77 78static const struct of_device_id ebi_match[] = {79 { .compatible = "arm,external-bus-interface"},80 { },81};82 83static int ap_flash_init(struct platform_device *pdev)84{85 struct device_node *ebi;86 void __iomem *ebi_base;87 u32 val;88 int ret;89 90 /* Look up the EBI */91 ebi = of_find_matching_node(NULL, ebi_match);92 if (!ebi) {93 return -ENODEV;94 }95 ebi_base = of_iomap(ebi, 0);96 of_node_put(ebi);97 if (!ebi_base)98 return -ENODEV;99 100 /* Clear VPP and write protection bits */101 ret = regmap_write(syscon_regmap,102 INTEGRATOR_SC_CTRLC_OFFSET,103 INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);104 if (ret)105 dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");106 107 /* Unlock the EBI */108 writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);109 110 /* Enable write cycles on the EBI, CSR1 (flash) */111 val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);112 val |= INTEGRATOR_EBI_WRITE_ENABLE;113 writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);114 115 /* Lock the EBI again */116 writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);117 iounmap(ebi_base);118 119 return 0;120}121 122static void ap_flash_set_vpp(struct map_info *map, int on)123{124 int ret;125 126 if (on) {127 ret = regmap_write(syscon_regmap,128 INTEGRATOR_SC_CTRLS_OFFSET,129 INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);130 if (ret)131 pr_err("error enabling AP VPP\n");132 } else {133 ret = regmap_write(syscon_regmap,134 INTEGRATOR_SC_CTRLC_OFFSET,135 INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);136 if (ret)137 pr_err("error disabling AP VPP\n");138 }139}140 141/*142 * Flash protection handling for the Integrator/CP143 */144 145#define INTCP_FLASHPROG_OFFSET 0x04146#define CINTEGRATOR_FLVPPEN BIT(0)147#define CINTEGRATOR_FLWREN BIT(1)148#define CINTEGRATOR_FLMASK BIT(0)|BIT(1)149 150static void cp_flash_set_vpp(struct map_info *map, int on)151{152 int ret;153 154 if (on) {155 ret = regmap_update_bits(syscon_regmap,156 INTCP_FLASHPROG_OFFSET,157 CINTEGRATOR_FLMASK,158 CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);159 if (ret)160 pr_err("error setting CP VPP\n");161 } else {162 ret = regmap_update_bits(syscon_regmap,163 INTCP_FLASHPROG_OFFSET,164 CINTEGRATOR_FLMASK,165 0);166 if (ret)167 pr_err("error setting CP VPP\n");168 }169}170 171/*172 * Flash protection handling for the Versatiles and RealViews173 */174 175#define VERSATILE_SYS_FLASH_OFFSET 0x4C176 177static void versatile_flash_set_vpp(struct map_info *map, int on)178{179 int ret;180 181 ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,182 0x01, !!on);183 if (ret)184 pr_err("error setting Versatile VPP\n");185}186 187int of_flash_probe_versatile(struct platform_device *pdev,188 struct device_node *np,189 struct map_info *map)190{191 struct device_node *sysnp;192 const struct of_device_id *devid;193 struct regmap *rmap;194 static enum versatile_flashprot versatile_flashprot;195 int ret;196 197 /* Not all flash chips use this protection line */198 if (!of_device_is_compatible(np, "arm,versatile-flash"))199 return 0;200 201 /* For first chip probed, look up the syscon regmap */202 if (!syscon_regmap) {203 sysnp = of_find_matching_node_and_match(NULL,204 syscon_match,205 &devid);206 if (!sysnp)207 return -ENODEV;208 209 versatile_flashprot = (uintptr_t)devid->data;210 rmap = syscon_node_to_regmap(sysnp);211 of_node_put(sysnp);212 if (IS_ERR(rmap))213 return PTR_ERR(rmap);214 215 syscon_regmap = rmap;216 }217 218 switch (versatile_flashprot) {219 case INTEGRATOR_AP_FLASHPROT:220 ret = ap_flash_init(pdev);221 if (ret)222 return ret;223 map->set_vpp = ap_flash_set_vpp;224 dev_info(&pdev->dev, "Integrator/AP flash protection\n");225 break;226 case INTEGRATOR_CP_FLASHPROT:227 map->set_vpp = cp_flash_set_vpp;228 dev_info(&pdev->dev, "Integrator/CP flash protection\n");229 break;230 case VERSATILE_FLASHPROT:231 case REALVIEW_FLASHPROT:232 map->set_vpp = versatile_flash_set_vpp;233 dev_info(&pdev->dev, "versatile/realview flash protection\n");234 break;235 default:236 dev_info(&pdev->dev, "device marked as Versatile flash "237 "but no system controller was found\n");238 break;239 }240 241 return 0;242}243