linux/drivers/mtd/maps/physmap_of_versatile.c
<<
>>
Prefs
   1/*
   2 * Versatile OF physmap driver add-on
   3 *
   4 * Copyright (c) 2016, Linaro Limited
   5 * Author: Linus Walleij <linus.walleij@linaro.org>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 * MA 02111-1307 USA
  21 */
  22#include <linux/export.h>
  23#include <linux/io.h>
  24#include <linux/of.h>
  25#include <linux/of_address.h>
  26#include <linux/of_device.h>
  27#include <linux/mtd/map.h>
  28#include <linux/mfd/syscon.h>
  29#include <linux/regmap.h>
  30#include <linux/bitops.h>
  31#include "physmap_of_versatile.h"
  32
  33static struct regmap *syscon_regmap;
  34
  35enum versatile_flashprot {
  36        INTEGRATOR_AP_FLASHPROT,
  37        INTEGRATOR_CP_FLASHPROT,
  38        VERSATILE_FLASHPROT,
  39        REALVIEW_FLASHPROT,
  40};
  41
  42static const struct of_device_id syscon_match[] = {
  43        {
  44                .compatible = "arm,integrator-ap-syscon",
  45                .data = (void *)INTEGRATOR_AP_FLASHPROT,
  46        },
  47        {
  48                .compatible = "arm,integrator-cp-syscon",
  49                .data = (void *)INTEGRATOR_CP_FLASHPROT,
  50        },
  51        {
  52                .compatible = "arm,core-module-versatile",
  53                .data = (void *)VERSATILE_FLASHPROT,
  54        },
  55        {
  56                .compatible = "arm,realview-eb-syscon",
  57                .data = (void *)REALVIEW_FLASHPROT,
  58        },
  59        {
  60                .compatible = "arm,realview-pb1176-syscon",
  61                .data = (void *)REALVIEW_FLASHPROT,
  62        },
  63        {
  64                .compatible = "arm,realview-pb11mp-syscon",
  65                .data = (void *)REALVIEW_FLASHPROT,
  66        },
  67        {
  68                .compatible = "arm,realview-pba8-syscon",
  69                .data = (void *)REALVIEW_FLASHPROT,
  70        },
  71        {
  72                .compatible = "arm,realview-pbx-syscon",
  73                .data = (void *)REALVIEW_FLASHPROT,
  74        },
  75        {},
  76};
  77
  78/*
  79 * Flash protection handling for the Integrator/AP
  80 */
  81#define INTEGRATOR_SC_CTRLS_OFFSET      0x08
  82#define INTEGRATOR_SC_CTRLC_OFFSET      0x0C
  83#define INTEGRATOR_SC_CTRL_FLVPPEN      BIT(1)
  84#define INTEGRATOR_SC_CTRL_FLWP         BIT(2)
  85
  86#define INTEGRATOR_EBI_CSR1_OFFSET      0x04
  87/* The manual says bit 2, the code says bit 3, trust the code */
  88#define INTEGRATOR_EBI_WRITE_ENABLE     BIT(3)
  89#define INTEGRATOR_EBI_LOCK_OFFSET      0x20
  90#define INTEGRATOR_EBI_LOCK_VAL         0xA05F
  91
  92static const struct of_device_id ebi_match[] = {
  93        { .compatible = "arm,external-bus-interface"},
  94        { },
  95};
  96
  97static int ap_flash_init(struct platform_device *pdev)
  98{
  99        struct device_node *ebi;
 100        static void __iomem *ebi_base;
 101        u32 val;
 102        int ret;
 103
 104        /* Look up the EBI */
 105        ebi = of_find_matching_node(NULL, ebi_match);
 106        if (!ebi) {
 107                return -ENODEV;
 108        }
 109        ebi_base = of_iomap(ebi, 0);
 110        if (!ebi_base)
 111                return -ENODEV;
 112
 113        /* Clear VPP and write protection bits */
 114        ret = regmap_write(syscon_regmap,
 115                INTEGRATOR_SC_CTRLC_OFFSET,
 116                INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 117        if (ret)
 118                dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
 119
 120        /* Unlock the EBI */
 121        writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
 122
 123        /* Enable write cycles on the EBI, CSR1 (flash) */
 124        val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
 125        val |= INTEGRATOR_EBI_WRITE_ENABLE;
 126        writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
 127
 128        /* Lock the EBI again */
 129        writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
 130        iounmap(ebi_base);
 131
 132        return 0;
 133}
 134
 135static void ap_flash_set_vpp(struct map_info *map, int on)
 136{
 137        int ret;
 138
 139        if (on) {
 140                ret = regmap_write(syscon_regmap,
 141                        INTEGRATOR_SC_CTRLS_OFFSET,
 142                        INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 143                if (ret)
 144                        pr_err("error enabling AP VPP\n");
 145        } else {
 146                ret = regmap_write(syscon_regmap,
 147                        INTEGRATOR_SC_CTRLC_OFFSET,
 148                        INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
 149                if (ret)
 150                        pr_err("error disabling AP VPP\n");
 151        }
 152}
 153
 154/*
 155 * Flash protection handling for the Integrator/CP
 156 */
 157
 158#define INTCP_FLASHPROG_OFFSET          0x04
 159#define CINTEGRATOR_FLVPPEN             BIT(0)
 160#define CINTEGRATOR_FLWREN              BIT(1)
 161#define CINTEGRATOR_FLMASK              BIT(0)|BIT(1)
 162
 163static void cp_flash_set_vpp(struct map_info *map, int on)
 164{
 165        int ret;
 166
 167        if (on) {
 168                ret = regmap_update_bits(syscon_regmap,
 169                                INTCP_FLASHPROG_OFFSET,
 170                                CINTEGRATOR_FLMASK,
 171                                CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
 172                if (ret)
 173                        pr_err("error setting CP VPP\n");
 174        } else {
 175                ret = regmap_update_bits(syscon_regmap,
 176                                INTCP_FLASHPROG_OFFSET,
 177                                CINTEGRATOR_FLMASK,
 178                                0);
 179                if (ret)
 180                        pr_err("error setting CP VPP\n");
 181        }
 182}
 183
 184/*
 185 * Flash protection handling for the Versatiles and RealViews
 186 */
 187
 188#define VERSATILE_SYS_FLASH_OFFSET            0x4C
 189
 190static void versatile_flash_set_vpp(struct map_info *map, int on)
 191{
 192        int ret;
 193
 194        ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
 195                                 0x01, !!on);
 196        if (ret)
 197                pr_err("error setting Versatile VPP\n");
 198}
 199
 200int of_flash_probe_versatile(struct platform_device *pdev,
 201                             struct device_node *np,
 202                             struct map_info *map)
 203{
 204        struct device_node *sysnp;
 205        const struct of_device_id *devid;
 206        struct regmap *rmap;
 207        static enum versatile_flashprot versatile_flashprot;
 208        int ret;
 209
 210        /* Not all flash chips use this protection line */
 211        if (!of_device_is_compatible(np, "arm,versatile-flash"))
 212                return 0;
 213
 214        /* For first chip probed, look up the syscon regmap */
 215        if (!syscon_regmap) {
 216                sysnp = of_find_matching_node_and_match(NULL,
 217                                                        syscon_match,
 218                                                        &devid);
 219                if (!sysnp)
 220                        return -ENODEV;
 221
 222                versatile_flashprot = (enum versatile_flashprot)devid->data;
 223                rmap = syscon_node_to_regmap(sysnp);
 224                if (IS_ERR(rmap))
 225                        return PTR_ERR(rmap);
 226
 227                syscon_regmap = rmap;
 228        }
 229
 230        switch (versatile_flashprot) {
 231        case INTEGRATOR_AP_FLASHPROT:
 232                ret = ap_flash_init(pdev);
 233                if (ret)
 234                        return ret;
 235                map->set_vpp = ap_flash_set_vpp;
 236                dev_info(&pdev->dev, "Integrator/AP flash protection\n");
 237                break;
 238        case INTEGRATOR_CP_FLASHPROT:
 239                map->set_vpp = cp_flash_set_vpp;
 240                dev_info(&pdev->dev, "Integrator/CP flash protection\n");
 241                break;
 242        case VERSATILE_FLASHPROT:
 243        case REALVIEW_FLASHPROT:
 244                map->set_vpp = versatile_flash_set_vpp;
 245                dev_info(&pdev->dev, "versatile/realview flash protection\n");
 246                break;
 247        default:
 248                dev_info(&pdev->dev, "device marked as Versatile flash "
 249                         "but no system controller was found\n");
 250                break;
 251        }
 252
 253        return 0;
 254}
 255EXPORT_SYMBOL_GPL(of_flash_probe_versatile);
 256