1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Intel IXP4xx OF physmap add-on |
4 | * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org> |
5 | * |
6 | * Based on the ixp4xx.c map driver, originally written by: |
7 | * Intel Corporation |
8 | * Deepak Saxena <dsaxena@mvista.com> |
9 | * Copyright (C) 2002 Intel Corporation |
10 | * Copyright (C) 2003-2004 MontaVista Software, Inc. |
11 | */ |
12 | #include <linux/export.h> |
13 | #include <linux/of.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/mtd/map.h> |
16 | #include <linux/mtd/xip.h> |
17 | #include "physmap-ixp4xx.h" |
18 | |
19 | /* |
20 | * Read/write a 16 bit word from flash address 'addr'. |
21 | * |
22 | * When the cpu is in little-endian mode it swizzles the address lines |
23 | * ('address coherency') so we need to undo the swizzling to ensure commands |
24 | * and the like end up on the correct flash address. |
25 | * |
26 | * To further complicate matters, due to the way the expansion bus controller |
27 | * handles 32 bit reads, the byte stream ABCD is stored on the flash as: |
28 | * D15 D0 |
29 | * +---+---+ |
30 | * | A | B | 0 |
31 | * +---+---+ |
32 | * | C | D | 2 |
33 | * +---+---+ |
34 | * This means that on LE systems each 16 bit word must be swapped. Note that |
35 | * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI |
36 | * data and other flash commands which are always in D7-D0. |
37 | */ |
38 | #ifndef CONFIG_CPU_BIG_ENDIAN |
39 | |
40 | static inline u16 flash_read16(void __iomem *addr) |
41 | { |
42 | return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2))); |
43 | } |
44 | |
45 | static inline void flash_write16(u16 d, void __iomem *addr) |
46 | { |
47 | __raw_writew(cpu_to_be16(d), addr: (void __iomem *)((unsigned long)addr ^ 0x2)); |
48 | } |
49 | |
50 | #define BYTE0(h) ((h) & 0xFF) |
51 | #define BYTE1(h) (((h) >> 8) & 0xFF) |
52 | |
53 | #else |
54 | |
55 | static inline u16 flash_read16(const void __iomem *addr) |
56 | { |
57 | return __raw_readw(addr); |
58 | } |
59 | |
60 | static inline void flash_write16(u16 d, void __iomem *addr) |
61 | { |
62 | __raw_writew(d, addr); |
63 | } |
64 | |
65 | #define BYTE0(h) (((h) >> 8) & 0xFF) |
66 | #define BYTE1(h) ((h) & 0xFF) |
67 | #endif |
68 | |
69 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) |
70 | { |
71 | map_word val; |
72 | |
73 | val.x[0] = flash_read16(addr: map->virt + ofs); |
74 | return val; |
75 | } |
76 | |
77 | /* |
78 | * The IXP4xx expansion bus only allows 16-bit wide acceses |
79 | * when attached to a 16-bit wide device (such as the 28F128J3A), |
80 | * so we can't just memcpy_fromio(). |
81 | */ |
82 | static void ixp4xx_copy_from(struct map_info *map, void *to, |
83 | unsigned long from, ssize_t len) |
84 | { |
85 | u8 *dest = (u8 *) to; |
86 | void __iomem *src = map->virt + from; |
87 | |
88 | if (len <= 0) |
89 | return; |
90 | |
91 | if (from & 1) { |
92 | *dest++ = BYTE1(flash_read16(src-1)); |
93 | src++; |
94 | --len; |
95 | } |
96 | |
97 | while (len >= 2) { |
98 | u16 data = flash_read16(addr: src); |
99 | *dest++ = BYTE0(data); |
100 | *dest++ = BYTE1(data); |
101 | src += 2; |
102 | len -= 2; |
103 | } |
104 | |
105 | if (len > 0) |
106 | *dest++ = BYTE0(flash_read16(src)); |
107 | } |
108 | |
109 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) |
110 | { |
111 | flash_write16(d: d.x[0], addr: map->virt + adr); |
112 | } |
113 | |
114 | int of_flash_probe_ixp4xx(struct platform_device *pdev, |
115 | struct device_node *np, |
116 | struct map_info *map) |
117 | { |
118 | struct device *dev = &pdev->dev; |
119 | |
120 | /* Multiplatform guard */ |
121 | if (!of_device_is_compatible(device: np, "intel,ixp4xx-flash" )) |
122 | return 0; |
123 | |
124 | map->read = ixp4xx_read16; |
125 | map->write = ixp4xx_write16; |
126 | map->copy_from = ixp4xx_copy_from; |
127 | map->copy_to = NULL; |
128 | |
129 | dev_info(dev, "initialized Intel IXP4xx-specific physmap control\n" ); |
130 | |
131 | return 0; |
132 | } |
133 | |