linux/drivers/mtd/maps/physmap-versatile.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Versatile OF physmap driver add-on
   4 *
   5 * Copyright (c) 2016, Linaro Limited
   6 * 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/of_device.h>
  13#include <linux/mtd/map.h>
  14#include <linux/mfd/syscon.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/AP
  66 */
  67#define INTEGRATOR_SC_CTRLS_OFFSET      0x08
  68#define INTEGRATOR_SC_CTRLC_OFFSET      0x0C
  69#define INTEGRATOR_SC_CTRL_FLVPPEN      BIT(1)
  70#define INTEGRATOR_SC_CTRL_FLWP         BIT(2)
  71
  72#define INTEGRATOR_EBI_CSR1_OFFSET      0x04
  73/* 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      0x20
  76#define INTEGRATOR_EBI_LOCK_VAL         0xA05F
  77
  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        if (!ebi_base)
  97                return -ENODEV;
  98
  99        /* Clear VPP and write protection bits */
 100        ret = regmap_write(syscon_regmap,
 101                INTEGRATOR_SC_CTRLC_OFFSET,
 102                INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 103        if (ret)
 104                dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
 105
 106        /* Unlock the EBI */
 107        writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
 108
 109        /* Enable write cycles on the EBI, CSR1 (flash) */
 110        val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
 111        val |= INTEGRATOR_EBI_WRITE_ENABLE;
 112        writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
 113
 114        /* Lock the EBI again */
 115        writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
 116        iounmap(ebi_base);
 117
 118        return 0;
 119}
 120
 121static void ap_flash_set_vpp(struct map_info *map, int on)
 122{
 123        int ret;
 124
 125        if (on) {
 126                ret = regmap_write(syscon_regmap,
 127                        INTEGRATOR_SC_CTRLS_OFFSET,
 128                        INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 129                if (ret)
 130                        pr_err("error enabling AP VPP\n");
 131        } else {
 132                ret = regmap_write(syscon_regmap,
 133                        INTEGRATOR_SC_CTRLC_OFFSET,
 134                        INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 135                if (ret)
 136                        pr_err("error disabling AP VPP\n");
 137        }
 138}
 139
 140/*
 141 * Flash protection handling for the Integrator/CP
 142 */
 143
 144#define INTCP_FLASHPROG_OFFSET          0x04
 145#define CINTEGRATOR_FLVPPEN             BIT(0)
 146#define CINTEGRATOR_FLWREN              BIT(1)
 147#define CINTEGRATOR_FLMASK              BIT(0)|BIT(1)
 148
 149static void cp_flash_set_vpp(struct map_info *map, int on)
 150{
 151        int ret;
 152
 153        if (on) {
 154                ret = regmap_update_bits(syscon_regmap,
 155                                INTCP_FLASHPROG_OFFSET,
 156                                CINTEGRATOR_FLMASK,
 157                                CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
 158                if (ret)
 159                        pr_err("error setting CP VPP\n");
 160        } else {
 161                ret = regmap_update_bits(syscon_regmap,
 162                                INTCP_FLASHPROG_OFFSET,
 163                                CINTEGRATOR_FLMASK,
 164                                0);
 165                if (ret)
 166                        pr_err("error setting CP VPP\n");
 167        }
 168}
 169
 170/*
 171 * Flash protection handling for the Versatiles and RealViews
 172 */
 173
 174#define VERSATILE_SYS_FLASH_OFFSET            0x4C
 175
 176static void versatile_flash_set_vpp(struct map_info *map, int on)
 177{
 178        int ret;
 179
 180        ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
 181                                 0x01, !!on);
 182        if (ret)
 183                pr_err("error setting Versatile VPP\n");
 184}
 185
 186int of_flash_probe_versatile(struct platform_device *pdev,
 187                             struct device_node *np,
 188                             struct map_info *map)
 189{
 190        struct device_node *sysnp;
 191        const struct of_device_id *devid;
 192        struct regmap *rmap;
 193        static enum versatile_flashprot versatile_flashprot;
 194        int ret;
 195
 196        /* Not all flash chips use this protection line */
 197        if (!of_device_is_compatible(np, "arm,versatile-flash"))
 198                return 0;
 199
 200        /* For first chip probed, look up the syscon regmap */
 201        if (!syscon_regmap) {
 202                sysnp = of_find_matching_node_and_match(NULL,
 203                                                        syscon_match,
 204                                                        &devid);
 205                if (!sysnp)
 206                        return -ENODEV;
 207
 208                versatile_flashprot = (enum versatile_flashprot)devid->data;
 209                rmap = syscon_node_to_regmap(sysnp);
 210                if (IS_ERR(rmap))
 211                        return PTR_ERR(rmap);
 212
 213                syscon_regmap = rmap;
 214        }
 215
 216        switch (versatile_flashprot) {
 217        case INTEGRATOR_AP_FLASHPROT:
 218                ret = ap_flash_init(pdev);
 219                if (ret)
 220                        return ret;
 221                map->set_vpp = ap_flash_set_vpp;
 222                dev_info(&pdev->dev, "Integrator/AP flash protection\n");
 223                break;
 224        case INTEGRATOR_CP_FLASHPROT:
 225                map->set_vpp = cp_flash_set_vpp;
 226                dev_info(&pdev->dev, "Integrator/CP flash protection\n");
 227                break;
 228        case VERSATILE_FLASHPROT:
 229        case REALVIEW_FLASHPROT:
 230                map->set_vpp = versatile_flash_set_vpp;
 231                dev_info(&pdev->dev, "versatile/realview flash protection\n");
 232                break;
 233        default:
 234                dev_info(&pdev->dev, "device marked as Versatile flash "
 235                         "but no system controller was found\n");
 236                break;
 237        }
 238
 239        return 0;
 240}
 241