123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /*
- * Versatile OF physmap driver add-on
- *
- * Copyright (c) 2016, Linaro Limited
- * Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
- #include <linux/export.h>
- #include <linux/io.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/of_device.h>
- #include <linux/mtd/map.h>
- #include <linux/mfd/syscon.h>
- #include <linux/regmap.h>
- #include <linux/bitops.h>
- #include "physmap_of_versatile.h"
- static struct regmap *syscon_regmap;
- enum versatile_flashprot {
- INTEGRATOR_AP_FLASHPROT,
- INTEGRATOR_CP_FLASHPROT,
- VERSATILE_FLASHPROT,
- REALVIEW_FLASHPROT,
- };
- static const struct of_device_id syscon_match[] = {
- {
- .compatible = "arm,integrator-ap-syscon",
- .data = (void *)INTEGRATOR_AP_FLASHPROT,
- },
- {
- .compatible = "arm,integrator-cp-syscon",
- .data = (void *)INTEGRATOR_CP_FLASHPROT,
- },
- {
- .compatible = "arm,core-module-versatile",
- .data = (void *)VERSATILE_FLASHPROT,
- },
- {
- .compatible = "arm,realview-eb-syscon",
- .data = (void *)REALVIEW_FLASHPROT,
- },
- {
- .compatible = "arm,realview-pb1176-syscon",
- .data = (void *)REALVIEW_FLASHPROT,
- },
- {
- .compatible = "arm,realview-pb11mp-syscon",
- .data = (void *)REALVIEW_FLASHPROT,
- },
- {
- .compatible = "arm,realview-pba8-syscon",
- .data = (void *)REALVIEW_FLASHPROT,
- },
- {
- .compatible = "arm,realview-pbx-syscon",
- .data = (void *)REALVIEW_FLASHPROT,
- },
- {},
- };
- /*
- * Flash protection handling for the Integrator/AP
- */
- #define INTEGRATOR_SC_CTRLS_OFFSET 0x08
- #define INTEGRATOR_SC_CTRLC_OFFSET 0x0C
- #define INTEGRATOR_SC_CTRL_FLVPPEN BIT(1)
- #define INTEGRATOR_SC_CTRL_FLWP BIT(2)
- #define INTEGRATOR_EBI_CSR1_OFFSET 0x04
- /* The manual says bit 2, the code says bit 3, trust the code */
- #define INTEGRATOR_EBI_WRITE_ENABLE BIT(3)
- #define INTEGRATOR_EBI_LOCK_OFFSET 0x20
- #define INTEGRATOR_EBI_LOCK_VAL 0xA05F
- static const struct of_device_id ebi_match[] = {
- { .compatible = "arm,external-bus-interface"},
- { },
- };
- static int ap_flash_init(struct platform_device *pdev)
- {
- struct device_node *ebi;
- void __iomem *ebi_base;
- u32 val;
- int ret;
- /* Look up the EBI */
- ebi = of_find_matching_node(NULL, ebi_match);
- if (!ebi) {
- return -ENODEV;
- }
- ebi_base = of_iomap(ebi, 0);
- if (!ebi_base)
- return -ENODEV;
- /* Clear VPP and write protection bits */
- ret = regmap_write(syscon_regmap,
- INTEGRATOR_SC_CTRLC_OFFSET,
- INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
- if (ret)
- dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
- /* Unlock the EBI */
- writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
- /* Enable write cycles on the EBI, CSR1 (flash) */
- val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
- val |= INTEGRATOR_EBI_WRITE_ENABLE;
- writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
- /* Lock the EBI again */
- writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
- iounmap(ebi_base);
- return 0;
- }
- static void ap_flash_set_vpp(struct map_info *map, int on)
- {
- int ret;
- if (on) {
- ret = regmap_write(syscon_regmap,
- INTEGRATOR_SC_CTRLS_OFFSET,
- INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
- if (ret)
- pr_err("error enabling AP VPP\n");
- } else {
- ret = regmap_write(syscon_regmap,
- INTEGRATOR_SC_CTRLC_OFFSET,
- INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
- if (ret)
- pr_err("error disabling AP VPP\n");
- }
- }
- /*
- * Flash protection handling for the Integrator/CP
- */
- #define INTCP_FLASHPROG_OFFSET 0x04
- #define CINTEGRATOR_FLVPPEN BIT(0)
- #define CINTEGRATOR_FLWREN BIT(1)
- #define CINTEGRATOR_FLMASK BIT(0)|BIT(1)
- static void cp_flash_set_vpp(struct map_info *map, int on)
- {
- int ret;
- if (on) {
- ret = regmap_update_bits(syscon_regmap,
- INTCP_FLASHPROG_OFFSET,
- CINTEGRATOR_FLMASK,
- CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
- if (ret)
- pr_err("error setting CP VPP\n");
- } else {
- ret = regmap_update_bits(syscon_regmap,
- INTCP_FLASHPROG_OFFSET,
- CINTEGRATOR_FLMASK,
- 0);
- if (ret)
- pr_err("error setting CP VPP\n");
- }
- }
- /*
- * Flash protection handling for the Versatiles and RealViews
- */
- #define VERSATILE_SYS_FLASH_OFFSET 0x4C
- static void versatile_flash_set_vpp(struct map_info *map, int on)
- {
- int ret;
- ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
- 0x01, !!on);
- if (ret)
- pr_err("error setting Versatile VPP\n");
- }
- int of_flash_probe_versatile(struct platform_device *pdev,
- struct device_node *np,
- struct map_info *map)
- {
- struct device_node *sysnp;
- const struct of_device_id *devid;
- struct regmap *rmap;
- static enum versatile_flashprot versatile_flashprot;
- int ret;
- /* Not all flash chips use this protection line */
- if (!of_device_is_compatible(np, "arm,versatile-flash"))
- return 0;
- /* For first chip probed, look up the syscon regmap */
- if (!syscon_regmap) {
- sysnp = of_find_matching_node_and_match(NULL,
- syscon_match,
- &devid);
- if (!sysnp)
- return -ENODEV;
- versatile_flashprot = (enum versatile_flashprot)devid->data;
- rmap = syscon_node_to_regmap(sysnp);
- if (IS_ERR(rmap))
- return PTR_ERR(rmap);
- syscon_regmap = rmap;
- }
- switch (versatile_flashprot) {
- case INTEGRATOR_AP_FLASHPROT:
- ret = ap_flash_init(pdev);
- if (ret)
- return ret;
- map->set_vpp = ap_flash_set_vpp;
- dev_info(&pdev->dev, "Integrator/AP flash protection\n");
- break;
- case INTEGRATOR_CP_FLASHPROT:
- map->set_vpp = cp_flash_set_vpp;
- dev_info(&pdev->dev, "Integrator/CP flash protection\n");
- break;
- case VERSATILE_FLASHPROT:
- case REALVIEW_FLASHPROT:
- map->set_vpp = versatile_flash_set_vpp;
- dev_info(&pdev->dev, "versatile/realview flash protection\n");
- break;
- default:
- dev_info(&pdev->dev, "device marked as Versatile flash "
- "but no system controller was found\n");
- break;
- }
- return 0;
- }
|