Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Versatile OF physmap driver add-on
0004  *
0005  * Copyright (c) 2016, Linaro Limited
0006  * Author: Linus Walleij <linus.walleij@linaro.org>
0007  */
0008 #include <linux/export.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_device.h>
0013 #include <linux/mtd/map.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/regmap.h>
0016 #include <linux/bitops.h>
0017 #include "physmap-versatile.h"
0018 
0019 static struct regmap *syscon_regmap;
0020 
0021 enum versatile_flashprot {
0022     INTEGRATOR_AP_FLASHPROT,
0023     INTEGRATOR_CP_FLASHPROT,
0024     VERSATILE_FLASHPROT,
0025     REALVIEW_FLASHPROT,
0026 };
0027 
0028 static const struct of_device_id syscon_match[] = {
0029     {
0030         .compatible = "arm,integrator-ap-syscon",
0031         .data = (void *)INTEGRATOR_AP_FLASHPROT,
0032     },
0033     {
0034         .compatible = "arm,integrator-cp-syscon",
0035         .data = (void *)INTEGRATOR_CP_FLASHPROT,
0036     },
0037     {
0038         .compatible = "arm,core-module-versatile",
0039         .data = (void *)VERSATILE_FLASHPROT,
0040     },
0041     {
0042         .compatible = "arm,realview-eb-syscon",
0043         .data = (void *)REALVIEW_FLASHPROT,
0044     },
0045     {
0046         .compatible = "arm,realview-pb1176-syscon",
0047         .data = (void *)REALVIEW_FLASHPROT,
0048     },
0049     {
0050         .compatible = "arm,realview-pb11mp-syscon",
0051         .data = (void *)REALVIEW_FLASHPROT,
0052     },
0053     {
0054         .compatible = "arm,realview-pba8-syscon",
0055         .data = (void *)REALVIEW_FLASHPROT,
0056     },
0057     {
0058         .compatible = "arm,realview-pbx-syscon",
0059         .data = (void *)REALVIEW_FLASHPROT,
0060     },
0061     {},
0062 };
0063 
0064 /*
0065  * Flash protection handling for the Integrator/AP
0066  */
0067 #define INTEGRATOR_SC_CTRLS_OFFSET  0x08
0068 #define INTEGRATOR_SC_CTRLC_OFFSET  0x0C
0069 #define INTEGRATOR_SC_CTRL_FLVPPEN  BIT(1)
0070 #define INTEGRATOR_SC_CTRL_FLWP     BIT(2)
0071 
0072 #define INTEGRATOR_EBI_CSR1_OFFSET  0x04
0073 /* The manual says bit 2, the code says bit 3, trust the code */
0074 #define INTEGRATOR_EBI_WRITE_ENABLE BIT(3)
0075 #define INTEGRATOR_EBI_LOCK_OFFSET  0x20
0076 #define INTEGRATOR_EBI_LOCK_VAL     0xA05F
0077 
0078 static const struct of_device_id ebi_match[] = {
0079     { .compatible = "arm,external-bus-interface"},
0080     { },
0081 };
0082 
0083 static int ap_flash_init(struct platform_device *pdev)
0084 {
0085     struct device_node *ebi;
0086     void __iomem *ebi_base;
0087     u32 val;
0088     int ret;
0089 
0090     /* Look up the EBI */
0091     ebi = of_find_matching_node(NULL, ebi_match);
0092     if (!ebi) {
0093         return -ENODEV;
0094     }
0095     ebi_base = of_iomap(ebi, 0);
0096     of_node_put(ebi);
0097     if (!ebi_base)
0098         return -ENODEV;
0099 
0100     /* Clear VPP and write protection bits */
0101     ret = regmap_write(syscon_regmap,
0102         INTEGRATOR_SC_CTRLC_OFFSET,
0103         INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
0104     if (ret)
0105         dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
0106 
0107     /* Unlock the EBI */
0108     writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
0109 
0110     /* Enable write cycles on the EBI, CSR1 (flash) */
0111     val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
0112     val |= INTEGRATOR_EBI_WRITE_ENABLE;
0113     writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
0114 
0115     /* Lock the EBI again */
0116     writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
0117     iounmap(ebi_base);
0118 
0119     return 0;
0120 }
0121 
0122 static void ap_flash_set_vpp(struct map_info *map, int on)
0123 {
0124     int ret;
0125 
0126     if (on) {
0127         ret = regmap_write(syscon_regmap,
0128             INTEGRATOR_SC_CTRLS_OFFSET,
0129             INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
0130         if (ret)
0131             pr_err("error enabling AP VPP\n");
0132     } else {
0133         ret = regmap_write(syscon_regmap,
0134             INTEGRATOR_SC_CTRLC_OFFSET,
0135             INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
0136         if (ret)
0137             pr_err("error disabling AP VPP\n");
0138     }
0139 }
0140 
0141 /*
0142  * Flash protection handling for the Integrator/CP
0143  */
0144 
0145 #define INTCP_FLASHPROG_OFFSET      0x04
0146 #define CINTEGRATOR_FLVPPEN     BIT(0)
0147 #define CINTEGRATOR_FLWREN      BIT(1)
0148 #define CINTEGRATOR_FLMASK      BIT(0)|BIT(1)
0149 
0150 static void cp_flash_set_vpp(struct map_info *map, int on)
0151 {
0152     int ret;
0153 
0154     if (on) {
0155         ret = regmap_update_bits(syscon_regmap,
0156                 INTCP_FLASHPROG_OFFSET,
0157                 CINTEGRATOR_FLMASK,
0158                 CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
0159         if (ret)
0160             pr_err("error setting CP VPP\n");
0161     } else {
0162         ret = regmap_update_bits(syscon_regmap,
0163                 INTCP_FLASHPROG_OFFSET,
0164                 CINTEGRATOR_FLMASK,
0165                 0);
0166         if (ret)
0167             pr_err("error setting CP VPP\n");
0168     }
0169 }
0170 
0171 /*
0172  * Flash protection handling for the Versatiles and RealViews
0173  */
0174 
0175 #define VERSATILE_SYS_FLASH_OFFSET            0x4C
0176 
0177 static void versatile_flash_set_vpp(struct map_info *map, int on)
0178 {
0179     int ret;
0180 
0181     ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
0182                  0x01, !!on);
0183     if (ret)
0184         pr_err("error setting Versatile VPP\n");
0185 }
0186 
0187 int of_flash_probe_versatile(struct platform_device *pdev,
0188                  struct device_node *np,
0189                  struct map_info *map)
0190 {
0191     struct device_node *sysnp;
0192     const struct of_device_id *devid;
0193     struct regmap *rmap;
0194     static enum versatile_flashprot versatile_flashprot;
0195     int ret;
0196 
0197     /* Not all flash chips use this protection line */
0198     if (!of_device_is_compatible(np, "arm,versatile-flash"))
0199         return 0;
0200 
0201     /* For first chip probed, look up the syscon regmap */
0202     if (!syscon_regmap) {
0203         sysnp = of_find_matching_node_and_match(NULL,
0204                             syscon_match,
0205                             &devid);
0206         if (!sysnp)
0207             return -ENODEV;
0208 
0209         versatile_flashprot = (enum versatile_flashprot)devid->data;
0210         rmap = syscon_node_to_regmap(sysnp);
0211         of_node_put(sysnp);
0212         if (IS_ERR(rmap))
0213             return PTR_ERR(rmap);
0214 
0215         syscon_regmap = rmap;
0216     }
0217 
0218     switch (versatile_flashprot) {
0219     case INTEGRATOR_AP_FLASHPROT:
0220         ret = ap_flash_init(pdev);
0221         if (ret)
0222             return ret;
0223         map->set_vpp = ap_flash_set_vpp;
0224         dev_info(&pdev->dev, "Integrator/AP flash protection\n");
0225         break;
0226     case INTEGRATOR_CP_FLASHPROT:
0227         map->set_vpp = cp_flash_set_vpp;
0228         dev_info(&pdev->dev, "Integrator/CP flash protection\n");
0229         break;
0230     case VERSATILE_FLASHPROT:
0231     case REALVIEW_FLASHPROT:
0232         map->set_vpp = versatile_flash_set_vpp;
0233         dev_info(&pdev->dev, "versatile/realview flash protection\n");
0234         break;
0235     default:
0236         dev_info(&pdev->dev, "device marked as Versatile flash "
0237              "but no system controller was found\n");
0238         break;
0239     }
0240 
0241     return 0;
0242 }