11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 26ca15cfaSBoris Brezillon /* 36ca15cfaSBoris Brezillon * Versatile OF physmap driver add-on 46ca15cfaSBoris Brezillon * 56ca15cfaSBoris Brezillon * Copyright (c) 2016, Linaro Limited 66ca15cfaSBoris Brezillon * Author: Linus Walleij <linus.walleij@linaro.org> 76ca15cfaSBoris Brezillon */ 86ca15cfaSBoris Brezillon #include <linux/export.h> 96ca15cfaSBoris Brezillon #include <linux/io.h> 106ca15cfaSBoris Brezillon #include <linux/of.h> 116ca15cfaSBoris Brezillon #include <linux/of_address.h> 126ca15cfaSBoris Brezillon #include <linux/of_device.h> 136ca15cfaSBoris Brezillon #include <linux/mtd/map.h> 146ca15cfaSBoris Brezillon #include <linux/mfd/syscon.h> 156ca15cfaSBoris Brezillon #include <linux/regmap.h> 166ca15cfaSBoris Brezillon #include <linux/bitops.h> 176ca15cfaSBoris Brezillon #include "physmap-versatile.h" 186ca15cfaSBoris Brezillon 196ca15cfaSBoris Brezillon static struct regmap *syscon_regmap; 206ca15cfaSBoris Brezillon 216ca15cfaSBoris Brezillon enum versatile_flashprot { 226ca15cfaSBoris Brezillon INTEGRATOR_AP_FLASHPROT, 236ca15cfaSBoris Brezillon INTEGRATOR_CP_FLASHPROT, 246ca15cfaSBoris Brezillon VERSATILE_FLASHPROT, 256ca15cfaSBoris Brezillon REALVIEW_FLASHPROT, 266ca15cfaSBoris Brezillon }; 276ca15cfaSBoris Brezillon 286ca15cfaSBoris Brezillon static const struct of_device_id syscon_match[] = { 296ca15cfaSBoris Brezillon { 306ca15cfaSBoris Brezillon .compatible = "arm,integrator-ap-syscon", 316ca15cfaSBoris Brezillon .data = (void *)INTEGRATOR_AP_FLASHPROT, 326ca15cfaSBoris Brezillon }, 336ca15cfaSBoris Brezillon { 346ca15cfaSBoris Brezillon .compatible = "arm,integrator-cp-syscon", 356ca15cfaSBoris Brezillon .data = (void *)INTEGRATOR_CP_FLASHPROT, 366ca15cfaSBoris Brezillon }, 376ca15cfaSBoris Brezillon { 386ca15cfaSBoris Brezillon .compatible = "arm,core-module-versatile", 396ca15cfaSBoris Brezillon .data = (void *)VERSATILE_FLASHPROT, 406ca15cfaSBoris Brezillon }, 416ca15cfaSBoris Brezillon { 426ca15cfaSBoris Brezillon .compatible = "arm,realview-eb-syscon", 436ca15cfaSBoris Brezillon .data = (void *)REALVIEW_FLASHPROT, 446ca15cfaSBoris Brezillon }, 456ca15cfaSBoris Brezillon { 466ca15cfaSBoris Brezillon .compatible = "arm,realview-pb1176-syscon", 476ca15cfaSBoris Brezillon .data = (void *)REALVIEW_FLASHPROT, 486ca15cfaSBoris Brezillon }, 496ca15cfaSBoris Brezillon { 506ca15cfaSBoris Brezillon .compatible = "arm,realview-pb11mp-syscon", 516ca15cfaSBoris Brezillon .data = (void *)REALVIEW_FLASHPROT, 526ca15cfaSBoris Brezillon }, 536ca15cfaSBoris Brezillon { 546ca15cfaSBoris Brezillon .compatible = "arm,realview-pba8-syscon", 556ca15cfaSBoris Brezillon .data = (void *)REALVIEW_FLASHPROT, 566ca15cfaSBoris Brezillon }, 576ca15cfaSBoris Brezillon { 586ca15cfaSBoris Brezillon .compatible = "arm,realview-pbx-syscon", 596ca15cfaSBoris Brezillon .data = (void *)REALVIEW_FLASHPROT, 606ca15cfaSBoris Brezillon }, 616ca15cfaSBoris Brezillon {}, 626ca15cfaSBoris Brezillon }; 636ca15cfaSBoris Brezillon 646ca15cfaSBoris Brezillon /* 656ca15cfaSBoris Brezillon * Flash protection handling for the Integrator/AP 666ca15cfaSBoris Brezillon */ 676ca15cfaSBoris Brezillon #define INTEGRATOR_SC_CTRLS_OFFSET 0x08 686ca15cfaSBoris Brezillon #define INTEGRATOR_SC_CTRLC_OFFSET 0x0C 696ca15cfaSBoris Brezillon #define INTEGRATOR_SC_CTRL_FLVPPEN BIT(1) 706ca15cfaSBoris Brezillon #define INTEGRATOR_SC_CTRL_FLWP BIT(2) 716ca15cfaSBoris Brezillon 726ca15cfaSBoris Brezillon #define INTEGRATOR_EBI_CSR1_OFFSET 0x04 736ca15cfaSBoris Brezillon /* The manual says bit 2, the code says bit 3, trust the code */ 746ca15cfaSBoris Brezillon #define INTEGRATOR_EBI_WRITE_ENABLE BIT(3) 756ca15cfaSBoris Brezillon #define INTEGRATOR_EBI_LOCK_OFFSET 0x20 766ca15cfaSBoris Brezillon #define INTEGRATOR_EBI_LOCK_VAL 0xA05F 776ca15cfaSBoris Brezillon 786ca15cfaSBoris Brezillon static const struct of_device_id ebi_match[] = { 796ca15cfaSBoris Brezillon { .compatible = "arm,external-bus-interface"}, 806ca15cfaSBoris Brezillon { }, 816ca15cfaSBoris Brezillon }; 826ca15cfaSBoris Brezillon 836ca15cfaSBoris Brezillon static int ap_flash_init(struct platform_device *pdev) 846ca15cfaSBoris Brezillon { 856ca15cfaSBoris Brezillon struct device_node *ebi; 866ca15cfaSBoris Brezillon void __iomem *ebi_base; 876ca15cfaSBoris Brezillon u32 val; 886ca15cfaSBoris Brezillon int ret; 896ca15cfaSBoris Brezillon 906ca15cfaSBoris Brezillon /* Look up the EBI */ 916ca15cfaSBoris Brezillon ebi = of_find_matching_node(NULL, ebi_match); 926ca15cfaSBoris Brezillon if (!ebi) { 936ca15cfaSBoris Brezillon return -ENODEV; 946ca15cfaSBoris Brezillon } 956ca15cfaSBoris Brezillon ebi_base = of_iomap(ebi, 0); 966ca15cfaSBoris Brezillon if (!ebi_base) 976ca15cfaSBoris Brezillon return -ENODEV; 986ca15cfaSBoris Brezillon 996ca15cfaSBoris Brezillon /* Clear VPP and write protection bits */ 1006ca15cfaSBoris Brezillon ret = regmap_write(syscon_regmap, 1016ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRLC_OFFSET, 1026ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); 1036ca15cfaSBoris Brezillon if (ret) 1046ca15cfaSBoris Brezillon dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n"); 1056ca15cfaSBoris Brezillon 1066ca15cfaSBoris Brezillon /* Unlock the EBI */ 1076ca15cfaSBoris Brezillon writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); 1086ca15cfaSBoris Brezillon 1096ca15cfaSBoris Brezillon /* Enable write cycles on the EBI, CSR1 (flash) */ 1106ca15cfaSBoris Brezillon val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); 1116ca15cfaSBoris Brezillon val |= INTEGRATOR_EBI_WRITE_ENABLE; 1126ca15cfaSBoris Brezillon writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); 1136ca15cfaSBoris Brezillon 1146ca15cfaSBoris Brezillon /* Lock the EBI again */ 1156ca15cfaSBoris Brezillon writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); 1166ca15cfaSBoris Brezillon iounmap(ebi_base); 1176ca15cfaSBoris Brezillon 1186ca15cfaSBoris Brezillon return 0; 1196ca15cfaSBoris Brezillon } 1206ca15cfaSBoris Brezillon 1216ca15cfaSBoris Brezillon static void ap_flash_set_vpp(struct map_info *map, int on) 1226ca15cfaSBoris Brezillon { 1236ca15cfaSBoris Brezillon int ret; 1246ca15cfaSBoris Brezillon 1256ca15cfaSBoris Brezillon if (on) { 1266ca15cfaSBoris Brezillon ret = regmap_write(syscon_regmap, 1276ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRLS_OFFSET, 1286ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); 1296ca15cfaSBoris Brezillon if (ret) 1306ca15cfaSBoris Brezillon pr_err("error enabling AP VPP\n"); 1316ca15cfaSBoris Brezillon } else { 1326ca15cfaSBoris Brezillon ret = regmap_write(syscon_regmap, 1336ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRLC_OFFSET, 1346ca15cfaSBoris Brezillon INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); 1356ca15cfaSBoris Brezillon if (ret) 1366ca15cfaSBoris Brezillon pr_err("error disabling AP VPP\n"); 1376ca15cfaSBoris Brezillon } 1386ca15cfaSBoris Brezillon } 1396ca15cfaSBoris Brezillon 1406ca15cfaSBoris Brezillon /* 1416ca15cfaSBoris Brezillon * Flash protection handling for the Integrator/CP 1426ca15cfaSBoris Brezillon */ 1436ca15cfaSBoris Brezillon 1446ca15cfaSBoris Brezillon #define INTCP_FLASHPROG_OFFSET 0x04 1456ca15cfaSBoris Brezillon #define CINTEGRATOR_FLVPPEN BIT(0) 1466ca15cfaSBoris Brezillon #define CINTEGRATOR_FLWREN BIT(1) 1476ca15cfaSBoris Brezillon #define CINTEGRATOR_FLMASK BIT(0)|BIT(1) 1486ca15cfaSBoris Brezillon 1496ca15cfaSBoris Brezillon static void cp_flash_set_vpp(struct map_info *map, int on) 1506ca15cfaSBoris Brezillon { 1516ca15cfaSBoris Brezillon int ret; 1526ca15cfaSBoris Brezillon 1536ca15cfaSBoris Brezillon if (on) { 1546ca15cfaSBoris Brezillon ret = regmap_update_bits(syscon_regmap, 1556ca15cfaSBoris Brezillon INTCP_FLASHPROG_OFFSET, 1566ca15cfaSBoris Brezillon CINTEGRATOR_FLMASK, 1576ca15cfaSBoris Brezillon CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN); 1586ca15cfaSBoris Brezillon if (ret) 1596ca15cfaSBoris Brezillon pr_err("error setting CP VPP\n"); 1606ca15cfaSBoris Brezillon } else { 1616ca15cfaSBoris Brezillon ret = regmap_update_bits(syscon_regmap, 1626ca15cfaSBoris Brezillon INTCP_FLASHPROG_OFFSET, 1636ca15cfaSBoris Brezillon CINTEGRATOR_FLMASK, 1646ca15cfaSBoris Brezillon 0); 1656ca15cfaSBoris Brezillon if (ret) 1666ca15cfaSBoris Brezillon pr_err("error setting CP VPP\n"); 1676ca15cfaSBoris Brezillon } 1686ca15cfaSBoris Brezillon } 1696ca15cfaSBoris Brezillon 1706ca15cfaSBoris Brezillon /* 1716ca15cfaSBoris Brezillon * Flash protection handling for the Versatiles and RealViews 1726ca15cfaSBoris Brezillon */ 1736ca15cfaSBoris Brezillon 1746ca15cfaSBoris Brezillon #define VERSATILE_SYS_FLASH_OFFSET 0x4C 1756ca15cfaSBoris Brezillon 1766ca15cfaSBoris Brezillon static void versatile_flash_set_vpp(struct map_info *map, int on) 1776ca15cfaSBoris Brezillon { 1786ca15cfaSBoris Brezillon int ret; 1796ca15cfaSBoris Brezillon 1806ca15cfaSBoris Brezillon ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET, 1816ca15cfaSBoris Brezillon 0x01, !!on); 1826ca15cfaSBoris Brezillon if (ret) 1836ca15cfaSBoris Brezillon pr_err("error setting Versatile VPP\n"); 1846ca15cfaSBoris Brezillon } 1856ca15cfaSBoris Brezillon 1866ca15cfaSBoris Brezillon int of_flash_probe_versatile(struct platform_device *pdev, 1876ca15cfaSBoris Brezillon struct device_node *np, 1886ca15cfaSBoris Brezillon struct map_info *map) 1896ca15cfaSBoris Brezillon { 1906ca15cfaSBoris Brezillon struct device_node *sysnp; 1916ca15cfaSBoris Brezillon const struct of_device_id *devid; 1926ca15cfaSBoris Brezillon struct regmap *rmap; 1936ca15cfaSBoris Brezillon static enum versatile_flashprot versatile_flashprot; 1946ca15cfaSBoris Brezillon int ret; 1956ca15cfaSBoris Brezillon 1966ca15cfaSBoris Brezillon /* Not all flash chips use this protection line */ 1976ca15cfaSBoris Brezillon if (!of_device_is_compatible(np, "arm,versatile-flash")) 1986ca15cfaSBoris Brezillon return 0; 1996ca15cfaSBoris Brezillon 2006ca15cfaSBoris Brezillon /* For first chip probed, look up the syscon regmap */ 2016ca15cfaSBoris Brezillon if (!syscon_regmap) { 2026ca15cfaSBoris Brezillon sysnp = of_find_matching_node_and_match(NULL, 2036ca15cfaSBoris Brezillon syscon_match, 2046ca15cfaSBoris Brezillon &devid); 2056ca15cfaSBoris Brezillon if (!sysnp) 2066ca15cfaSBoris Brezillon return -ENODEV; 2076ca15cfaSBoris Brezillon 2086ca15cfaSBoris Brezillon versatile_flashprot = (enum versatile_flashprot)devid->data; 2096ca15cfaSBoris Brezillon rmap = syscon_node_to_regmap(sysnp); 2106ca15cfaSBoris Brezillon if (IS_ERR(rmap)) 2116ca15cfaSBoris Brezillon return PTR_ERR(rmap); 2126ca15cfaSBoris Brezillon 2136ca15cfaSBoris Brezillon syscon_regmap = rmap; 2146ca15cfaSBoris Brezillon } 2156ca15cfaSBoris Brezillon 2166ca15cfaSBoris Brezillon switch (versatile_flashprot) { 2176ca15cfaSBoris Brezillon case INTEGRATOR_AP_FLASHPROT: 2186ca15cfaSBoris Brezillon ret = ap_flash_init(pdev); 2196ca15cfaSBoris Brezillon if (ret) 2206ca15cfaSBoris Brezillon return ret; 2216ca15cfaSBoris Brezillon map->set_vpp = ap_flash_set_vpp; 2226ca15cfaSBoris Brezillon dev_info(&pdev->dev, "Integrator/AP flash protection\n"); 2236ca15cfaSBoris Brezillon break; 2246ca15cfaSBoris Brezillon case INTEGRATOR_CP_FLASHPROT: 2256ca15cfaSBoris Brezillon map->set_vpp = cp_flash_set_vpp; 2266ca15cfaSBoris Brezillon dev_info(&pdev->dev, "Integrator/CP flash protection\n"); 2276ca15cfaSBoris Brezillon break; 2286ca15cfaSBoris Brezillon case VERSATILE_FLASHPROT: 2296ca15cfaSBoris Brezillon case REALVIEW_FLASHPROT: 2306ca15cfaSBoris Brezillon map->set_vpp = versatile_flash_set_vpp; 2316ca15cfaSBoris Brezillon dev_info(&pdev->dev, "versatile/realview flash protection\n"); 2326ca15cfaSBoris Brezillon break; 2336ca15cfaSBoris Brezillon default: 2346ca15cfaSBoris Brezillon dev_info(&pdev->dev, "device marked as Versatile flash " 2356ca15cfaSBoris Brezillon "but no system controller was found\n"); 2366ca15cfaSBoris Brezillon break; 2376ca15cfaSBoris Brezillon } 2386ca15cfaSBoris Brezillon 2396ca15cfaSBoris Brezillon return 0; 2406ca15cfaSBoris Brezillon } 241