]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
56ff337e LW |
2 | /* |
3 | * Cortina Systems Gemini OF physmap add-on | |
4 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | |
5 | * | |
6 | * This SoC has an elaborate flash control register, so we need to | |
7 | * detect and set it up when booting on this platform. | |
8 | */ | |
9 | #include <linux/export.h> | |
10 | #include <linux/of.h> | |
11 | #include <linux/of_device.h> | |
12 | #include <linux/mtd/map.h> | |
13 | #include <linux/mfd/syscon.h> | |
14 | #include <linux/regmap.h> | |
15 | #include <linux/bitops.h> | |
16 | #include "physmap_of_gemini.h" | |
17 | ||
18 | /* | |
19 | * The Flash-relevant parts of the global status register | |
20 | * These would also be relevant for a NAND driver. | |
21 | */ | |
22 | #define GLOBAL_STATUS 0x04 | |
23 | #define FLASH_TYPE_MASK (0x3 << 24) | |
24 | #define FLASH_TYPE_NAND_2K (0x3 << 24) | |
25 | #define FLASH_TYPE_NAND_512 (0x2 << 24) | |
26 | #define FLASH_TYPE_PARALLEL (0x1 << 24) | |
27 | #define FLASH_TYPE_SERIAL (0x0 << 24) | |
28 | /* if parallel */ | |
29 | #define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */ | |
30 | /* if serial */ | |
31 | #define FLASH_ATMEL (1 << 23) /* else STM */ | |
32 | ||
33 | #define FLASH_SIZE_MASK (0x3 << 21) | |
34 | #define NAND_256M (0x3 << 21) /* and more */ | |
35 | #define NAND_128M (0x2 << 21) | |
36 | #define NAND_64M (0x1 << 21) | |
37 | #define NAND_32M (0x0 << 21) | |
38 | #define ATMEL_16M (0x3 << 21) /* and more */ | |
39 | #define ATMEL_8M (0x2 << 21) | |
40 | #define ATMEL_4M_2M (0x1 << 21) | |
41 | #define ATMEL_1M (0x0 << 21) /* and less */ | |
42 | #define STM_32M (1 << 22) /* and more */ | |
43 | #define STM_16M (0 << 22) /* and less */ | |
44 | ||
45 | #define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */ | |
46 | ||
56ff337e LW |
47 | static const struct of_device_id syscon_match[] = { |
48 | { .compatible = "cortina,gemini-syscon" }, | |
49 | { }, | |
50 | }; | |
51 | ||
52 | int of_flash_probe_gemini(struct platform_device *pdev, | |
53 | struct device_node *np, | |
54 | struct map_info *map) | |
55 | { | |
6c51a52e | 56 | struct regmap *rmap; |
56ff337e LW |
57 | struct device *dev = &pdev->dev; |
58 | u32 val; | |
59 | int ret; | |
60 | ||
61 | /* Multiplatform guard */ | |
62 | if (!of_device_is_compatible(np, "cortina,gemini-flash")) | |
63 | return 0; | |
64 | ||
65 | rmap = syscon_regmap_lookup_by_phandle(np, "syscon"); | |
66 | if (IS_ERR(rmap)) { | |
67 | dev_err(dev, "no syscon\n"); | |
68 | return PTR_ERR(rmap); | |
69 | } | |
70 | ||
71 | ret = regmap_read(rmap, GLOBAL_STATUS, &val); | |
72 | if (ret) { | |
73 | dev_err(dev, "failed to read global status register\n"); | |
74 | return -ENODEV; | |
75 | } | |
76 | dev_dbg(dev, "global status reg: %08x\n", val); | |
77 | ||
78 | /* | |
79 | * It would be contradictory if a physmap flash was NOT parallel. | |
80 | */ | |
81 | if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) { | |
82 | dev_err(dev, "flash is not parallel\n"); | |
83 | return -ENODEV; | |
84 | } | |
85 | ||
86 | /* | |
87 | * Complain if DT data and hardware definition is different. | |
88 | */ | |
89 | if (val & FLASH_WIDTH_16BIT) { | |
90 | if (map->bankwidth != 2) | |
91 | dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n", | |
92 | map->bankwidth * 8); | |
93 | } else { | |
94 | if (map->bankwidth != 1) | |
95 | dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n", | |
96 | map->bankwidth * 8); | |
97 | } | |
98 | ||
56ff337e LW |
99 | dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n"); |
100 | ||
101 | return 0; | |
102 | } |