0001
0002
0003
0004
0005
0006
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
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
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
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
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
0108 writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
0109
0110
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
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
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
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
0198 if (!of_device_is_compatible(np, "arm,versatile-flash"))
0199 return 0;
0200
0201
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 }