diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 12:02:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 12:02:26 -0500 |
commit | 37969581301e50872a1ae84dc73962b5f7ee6b76 (patch) | |
tree | 35bbd6a07f903f248f4bd209b8d194a922415fe0 /drivers | |
parent | 80ff8a805113850a3ffafcc8e6eaa1fdd51b02f3 (diff) | |
parent | 24f1a849614ba1805e26a05da7cc8c6bd67490ea (diff) |
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (69 commits)
[POWERPC] Add SPE registers to core dumps
[POWERPC] Use regset code for compat PTRACE_*REGS* calls
[POWERPC] Use generic compat_sys_ptrace
[POWERPC] Use generic compat_ptrace_request
[POWERPC] Use generic ptrace peekdata/pokedata
[POWERPC] Use regset code for PTRACE_*REGS* requests
[POWERPC] Switch to generic compat_binfmt_elf code
[POWERPC] Switch to using user_regset-based core dumps
[POWERPC] Add user_regset compat support
[POWERPC] Add user_regset_view definitions
[POWERPC] Use user_regset accessors for GPRs
[POWERPC] ptrace accessors for special regs MSR and TRAP
[POWERPC] Use user_regset accessors for SPE regs
[POWERPC] Use user_regset accessors for altivec regs
[POWERPC] Use user_regset accessors for FP regs
[POWERPC] mpc52xx: fix compile error introduce when rebasing patch
[POWERPC] 4xx: PCIe indirect DCR spinlock fix.
[POWERPC] Add missing native dcr dcr_ind_lock spinlock
[POWERPC] 4xx: Fix offset value on Warp board
[POWERPC] 4xx: Add 440EPx Sequoia ehci dts entry
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/xsysace.c | 6 | ||||
-rw-r--r-- | drivers/cdrom/viocd.c | 2 | ||||
-rw-r--r-- | drivers/char/Kconfig | 10 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/Makefile | 7 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/buffer_icap.c | 380 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/buffer_icap.h | 57 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/fifo_icap.c | 381 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/fifo_icap.h | 62 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/xilinx_hwicap.c | 904 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/xilinx_hwicap.h | 193 | ||||
-rw-r--r-- | drivers/net/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/cpmac.c | 55 | ||||
-rw-r--r-- | drivers/of/base.c | 25 | ||||
-rw-r--r-- | drivers/of/platform.c | 10 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 12 | ||||
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 424 | ||||
-rw-r--r-- | drivers/serial/uartlite.c | 53 | ||||
-rw-r--r-- | drivers/video/xilinxfb.c | 4 |
19 files changed, 2430 insertions, 160 deletions
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 78ebfffc77e3..4a7a059ebaf7 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c | |||
@@ -1202,8 +1202,10 @@ static int __devexit ace_of_remove(struct of_device *op) | |||
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | /* Match table for of_platform binding */ | 1204 | /* Match table for of_platform binding */ |
1205 | static struct of_device_id __devinit ace_of_match[] = { | 1205 | static struct of_device_id ace_of_match[] __devinitdata = { |
1206 | { .compatible = "xilinx,xsysace", }, | 1206 | { .compatible = "xlnx,opb-sysace-1.00.b", }, |
1207 | { .compatible = "xlnx,opb-sysace-1.00.c", }, | ||
1208 | { .compatible = "xlnx,xps-sysace-1.00.a", }, | ||
1207 | {}, | 1209 | {}, |
1208 | }; | 1210 | }; |
1209 | MODULE_DEVICE_TABLE(of, ace_of_match); | 1211 | MODULE_DEVICE_TABLE(of, ace_of_match); |
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 8473b9f1da96..cac06bc1754b 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c | |||
@@ -558,7 +558,7 @@ static struct cdrom_device_ops viocd_dops = { | |||
558 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM | 558 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM |
559 | }; | 559 | }; |
560 | 560 | ||
561 | static int __init find_capability(const char *type) | 561 | static int find_capability(const char *type) |
562 | { | 562 | { |
563 | struct capability_entry *entry; | 563 | struct capability_entry *entry; |
564 | 564 | ||
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7927fd0faca3..f01ac9a07bf5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -830,6 +830,16 @@ config DTLK | |||
830 | To compile this driver as a module, choose M here: the | 830 | To compile this driver as a module, choose M here: the |
831 | module will be called dtlk. | 831 | module will be called dtlk. |
832 | 832 | ||
833 | config XILINX_HWICAP | ||
834 | tristate "Xilinx HWICAP Support" | ||
835 | depends on XILINX_VIRTEX | ||
836 | help | ||
837 | This option enables support for Xilinx Internal Configuration | ||
838 | Access Port (ICAP) driver. The ICAP is used on Xilinx Virtex | ||
839 | FPGA platforms to partially reconfigure the FPGA at runtime. | ||
840 | |||
841 | If unsure, say N. | ||
842 | |||
833 | config R3964 | 843 | config R3964 |
834 | tristate "Siemens R3964 line discipline" | 844 | tristate "Siemens R3964 line discipline" |
835 | ---help--- | 845 | ---help--- |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4396e37b3d0f..5407b7615614 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o | |||
76 | obj-$(CONFIG_SGI_DS1286) += ds1286.o | 76 | obj-$(CONFIG_SGI_DS1286) += ds1286.o |
77 | obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o | 77 | obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o |
78 | obj-$(CONFIG_DS1302) += ds1302.o | 78 | obj-$(CONFIG_DS1302) += ds1302.o |
79 | obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/ | ||
79 | ifeq ($(CONFIG_GENERIC_NVRAM),y) | 80 | ifeq ($(CONFIG_GENERIC_NVRAM),y) |
80 | obj-$(CONFIG_NVRAM) += generic_nvram.o | 81 | obj-$(CONFIG_NVRAM) += generic_nvram.o |
81 | else | 82 | else |
diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile new file mode 100644 index 000000000000..5491cbc42f43 --- /dev/null +++ b/drivers/char/xilinx_hwicap/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the Xilinx OPB hwicap driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o | ||
6 | |||
7 | xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o | ||
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c new file mode 100644 index 000000000000..dfea2bde162b --- /dev/null +++ b/drivers/char/xilinx_hwicap/buffer_icap.c | |||
@@ -0,0 +1,380 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2003-2008 Xilinx Inc. | ||
28 | * All rights reserved. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | #include "buffer_icap.h" | ||
37 | |||
38 | /* Indicates how many bytes will fit in a buffer. (1 BRAM) */ | ||
39 | #define XHI_MAX_BUFFER_BYTES 2048 | ||
40 | #define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2) | ||
41 | |||
42 | /* File access and error constants */ | ||
43 | #define XHI_DEVICE_READ_ERROR -1 | ||
44 | #define XHI_DEVICE_WRITE_ERROR -2 | ||
45 | #define XHI_BUFFER_OVERFLOW_ERROR -3 | ||
46 | |||
47 | #define XHI_DEVICE_READ 0x1 | ||
48 | #define XHI_DEVICE_WRITE 0x0 | ||
49 | |||
50 | /* Constants for checking transfer status */ | ||
51 | #define XHI_CYCLE_DONE 0 | ||
52 | #define XHI_CYCLE_EXECUTING 1 | ||
53 | |||
54 | /* buffer_icap register offsets */ | ||
55 | |||
56 | /* Size of transfer, read & write */ | ||
57 | #define XHI_SIZE_REG_OFFSET 0x800L | ||
58 | /* offset into bram, read & write */ | ||
59 | #define XHI_BRAM_OFFSET_REG_OFFSET 0x804L | ||
60 | /* Read not Configure, direction of transfer. Write only */ | ||
61 | #define XHI_RNC_REG_OFFSET 0x808L | ||
62 | /* Indicates transfer complete. Read only */ | ||
63 | #define XHI_STATUS_REG_OFFSET 0x80CL | ||
64 | |||
65 | /* Constants for setting the RNC register */ | ||
66 | #define XHI_CONFIGURE 0x0UL | ||
67 | #define XHI_READBACK 0x1UL | ||
68 | |||
69 | /* Constants for the Done register */ | ||
70 | #define XHI_NOT_FINISHED 0x0UL | ||
71 | #define XHI_FINISHED 0x1UL | ||
72 | |||
73 | #define XHI_BUFFER_START 0 | ||
74 | |||
75 | /** | ||
76 | * buffer_icap_get_status: Get the contents of the status register. | ||
77 | * @parameter base_address: is the base address of the device | ||
78 | * | ||
79 | * The status register contains the ICAP status and the done bit. | ||
80 | * | ||
81 | * D8 - cfgerr | ||
82 | * D7 - dalign | ||
83 | * D6 - rip | ||
84 | * D5 - in_abort_l | ||
85 | * D4 - Always 1 | ||
86 | * D3 - Always 1 | ||
87 | * D2 - Always 1 | ||
88 | * D1 - Always 1 | ||
89 | * D0 - Done bit | ||
90 | **/ | ||
91 | static inline u32 buffer_icap_get_status(void __iomem *base_address) | ||
92 | { | ||
93 | return in_be32(base_address + XHI_STATUS_REG_OFFSET); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * buffer_icap_get_bram: Reads data from the storage buffer bram. | ||
98 | * @parameter base_address: contains the base address of the component. | ||
99 | * @parameter offset: The word offset from which the data should be read. | ||
100 | * | ||
101 | * A bram is used as a configuration memory cache. One frame of data can | ||
102 | * be stored in this "storage buffer". | ||
103 | **/ | ||
104 | static inline u32 buffer_icap_get_bram(void __iomem *base_address, | ||
105 | u32 offset) | ||
106 | { | ||
107 | return in_be32(base_address + (offset << 2)); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * buffer_icap_busy: Return true if the icap device is busy | ||
112 | * @parameter base_address: is the base address of the device | ||
113 | * | ||
114 | * The queries the low order bit of the status register, which | ||
115 | * indicates whether the current configuration or readback operation | ||
116 | * has completed. | ||
117 | **/ | ||
118 | static inline bool buffer_icap_busy(void __iomem *base_address) | ||
119 | { | ||
120 | return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * buffer_icap_busy: Return true if the icap device is not busy | ||
125 | * @parameter base_address: is the base address of the device | ||
126 | * | ||
127 | * The queries the low order bit of the status register, which | ||
128 | * indicates whether the current configuration or readback operation | ||
129 | * has completed. | ||
130 | **/ | ||
131 | static inline bool buffer_icap_done(void __iomem *base_address) | ||
132 | { | ||
133 | return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * buffer_icap_set_size: Set the size register. | ||
138 | * @parameter base_address: is the base address of the device | ||
139 | * @parameter data: The size in bytes. | ||
140 | * | ||
141 | * The size register holds the number of 8 bit bytes to transfer between | ||
142 | * bram and the icap (or icap to bram). | ||
143 | **/ | ||
144 | static inline void buffer_icap_set_size(void __iomem *base_address, | ||
145 | u32 data) | ||
146 | { | ||
147 | out_be32(base_address + XHI_SIZE_REG_OFFSET, data); | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * buffer_icap_mSetoffsetReg: Set the bram offset register. | ||
152 | * @parameter base_address: contains the base address of the device. | ||
153 | * @parameter data: is the value to be written to the data register. | ||
154 | * | ||
155 | * The bram offset register holds the starting bram address to transfer | ||
156 | * data from during configuration or write data to during readback. | ||
157 | **/ | ||
158 | static inline void buffer_icap_set_offset(void __iomem *base_address, | ||
159 | u32 data) | ||
160 | { | ||
161 | out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register. | ||
166 | * @parameter base_address: contains the base address of the device. | ||
167 | * @parameter data: is the value to be written to the data register. | ||
168 | * | ||
169 | * The RNC register determines the direction of the data transfer. It | ||
170 | * controls whether a configuration or readback take place. Writing to | ||
171 | * this register initiates the transfer. A value of 1 initiates a | ||
172 | * readback while writing a value of 0 initiates a configuration. | ||
173 | **/ | ||
174 | static inline void buffer_icap_set_rnc(void __iomem *base_address, | ||
175 | u32 data) | ||
176 | { | ||
177 | out_be32(base_address + XHI_RNC_REG_OFFSET, data); | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * buffer_icap_set_bram: Write data to the storage buffer bram. | ||
182 | * @parameter base_address: contains the base address of the component. | ||
183 | * @parameter offset: The word offset at which the data should be written. | ||
184 | * @parameter data: The value to be written to the bram offset. | ||
185 | * | ||
186 | * A bram is used as a configuration memory cache. One frame of data can | ||
187 | * be stored in this "storage buffer". | ||
188 | **/ | ||
189 | static inline void buffer_icap_set_bram(void __iomem *base_address, | ||
190 | u32 offset, u32 data) | ||
191 | { | ||
192 | out_be32(base_address + (offset << 2), data); | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer. | ||
197 | * @parameter drvdata: a pointer to the drvdata. | ||
198 | * @parameter offset: The storage buffer start address. | ||
199 | * @parameter count: The number of words (32 bit) to read from the | ||
200 | * device (ICAP). | ||
201 | **/ | ||
202 | static int buffer_icap_device_read(struct hwicap_drvdata *drvdata, | ||
203 | u32 offset, u32 count) | ||
204 | { | ||
205 | |||
206 | s32 retries = 0; | ||
207 | void __iomem *base_address = drvdata->base_address; | ||
208 | |||
209 | if (buffer_icap_busy(base_address)) | ||
210 | return -EBUSY; | ||
211 | |||
212 | if ((offset + count) > XHI_MAX_BUFFER_INTS) | ||
213 | return -EINVAL; | ||
214 | |||
215 | /* setSize count*4 to get bytes. */ | ||
216 | buffer_icap_set_size(base_address, (count << 2)); | ||
217 | buffer_icap_set_offset(base_address, offset); | ||
218 | buffer_icap_set_rnc(base_address, XHI_READBACK); | ||
219 | |||
220 | while (buffer_icap_busy(base_address)) { | ||
221 | retries++; | ||
222 | if (retries > XHI_MAX_RETRIES) | ||
223 | return -EBUSY; | ||
224 | } | ||
225 | return 0; | ||
226 | |||
227 | }; | ||
228 | |||
229 | /** | ||
230 | * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer. | ||
231 | * @parameter drvdata: a pointer to the drvdata. | ||
232 | * @parameter offset: The storage buffer start address. | ||
233 | * @parameter count: The number of words (32 bit) to read from the | ||
234 | * device (ICAP). | ||
235 | **/ | ||
236 | static int buffer_icap_device_write(struct hwicap_drvdata *drvdata, | ||
237 | u32 offset, u32 count) | ||
238 | { | ||
239 | |||
240 | s32 retries = 0; | ||
241 | void __iomem *base_address = drvdata->base_address; | ||
242 | |||
243 | if (buffer_icap_busy(base_address)) | ||
244 | return -EBUSY; | ||
245 | |||
246 | if ((offset + count) > XHI_MAX_BUFFER_INTS) | ||
247 | return -EINVAL; | ||
248 | |||
249 | /* setSize count*4 to get bytes. */ | ||
250 | buffer_icap_set_size(base_address, count << 2); | ||
251 | buffer_icap_set_offset(base_address, offset); | ||
252 | buffer_icap_set_rnc(base_address, XHI_CONFIGURE); | ||
253 | |||
254 | while (buffer_icap_busy(base_address)) { | ||
255 | retries++; | ||
256 | if (retries > XHI_MAX_RETRIES) | ||
257 | return -EBUSY; | ||
258 | } | ||
259 | return 0; | ||
260 | |||
261 | }; | ||
262 | |||
263 | /** | ||
264 | * buffer_icap_reset: Reset the logic of the icap device. | ||
265 | * @parameter drvdata: a pointer to the drvdata. | ||
266 | * | ||
267 | * Writing to the status register resets the ICAP logic in an internal | ||
268 | * version of the core. For the version of the core published in EDK, | ||
269 | * this is a noop. | ||
270 | **/ | ||
271 | void buffer_icap_reset(struct hwicap_drvdata *drvdata) | ||
272 | { | ||
273 | out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE); | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * buffer_icap_set_configuration: Load a partial bitstream from system memory. | ||
278 | * @parameter drvdata: a pointer to the drvdata. | ||
279 | * @parameter data: Kernel address of the partial bitstream. | ||
280 | * @parameter size: the size of the partial bitstream in 32 bit words. | ||
281 | **/ | ||
282 | int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, | ||
283 | u32 size) | ||
284 | { | ||
285 | int status; | ||
286 | s32 buffer_count = 0; | ||
287 | s32 num_writes = 0; | ||
288 | bool dirty = 0; | ||
289 | u32 i; | ||
290 | void __iomem *base_address = drvdata->base_address; | ||
291 | |||
292 | /* Loop through all the data */ | ||
293 | for (i = 0, buffer_count = 0; i < size; i++) { | ||
294 | |||
295 | /* Copy data to bram */ | ||
296 | buffer_icap_set_bram(base_address, buffer_count, data[i]); | ||
297 | dirty = 1; | ||
298 | |||
299 | if (buffer_count < XHI_MAX_BUFFER_INTS - 1) { | ||
300 | buffer_count++; | ||
301 | continue; | ||
302 | } | ||
303 | |||
304 | /* Write data to ICAP */ | ||
305 | status = buffer_icap_device_write( | ||
306 | drvdata, | ||
307 | XHI_BUFFER_START, | ||
308 | XHI_MAX_BUFFER_INTS); | ||
309 | if (status != 0) { | ||
310 | /* abort. */ | ||
311 | buffer_icap_reset(drvdata); | ||
312 | return status; | ||
313 | } | ||
314 | |||
315 | buffer_count = 0; | ||
316 | num_writes++; | ||
317 | dirty = 0; | ||
318 | } | ||
319 | |||
320 | /* Write unwritten data to ICAP */ | ||
321 | if (dirty) { | ||
322 | /* Write data to ICAP */ | ||
323 | status = buffer_icap_device_write(drvdata, XHI_BUFFER_START, | ||
324 | buffer_count); | ||
325 | if (status != 0) { | ||
326 | /* abort. */ | ||
327 | buffer_icap_reset(drvdata); | ||
328 | } | ||
329 | return status; | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | }; | ||
334 | |||
335 | /** | ||
336 | * buffer_icap_get_configuration: Read configuration data from the device. | ||
337 | * @parameter drvdata: a pointer to the drvdata. | ||
338 | * @parameter data: Address of the data representing the partial bitstream | ||
339 | * @parameter size: the size of the partial bitstream in 32 bit words. | ||
340 | **/ | ||
341 | int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, | ||
342 | u32 size) | ||
343 | { | ||
344 | int status; | ||
345 | s32 buffer_count = 0; | ||
346 | s32 read_count = 0; | ||
347 | u32 i; | ||
348 | void __iomem *base_address = drvdata->base_address; | ||
349 | |||
350 | /* Loop through all the data */ | ||
351 | for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) { | ||
352 | if (buffer_count == XHI_MAX_BUFFER_INTS) { | ||
353 | u32 words_remaining = size - i; | ||
354 | u32 words_to_read = | ||
355 | words_remaining < | ||
356 | XHI_MAX_BUFFER_INTS ? words_remaining : | ||
357 | XHI_MAX_BUFFER_INTS; | ||
358 | |||
359 | /* Read data from ICAP */ | ||
360 | status = buffer_icap_device_read( | ||
361 | drvdata, | ||
362 | XHI_BUFFER_START, | ||
363 | words_to_read); | ||
364 | if (status != 0) { | ||
365 | /* abort. */ | ||
366 | buffer_icap_reset(drvdata); | ||
367 | return status; | ||
368 | } | ||
369 | |||
370 | buffer_count = 0; | ||
371 | read_count++; | ||
372 | } | ||
373 | |||
374 | /* Copy data from bram */ | ||
375 | data[i] = buffer_icap_get_bram(base_address, buffer_count); | ||
376 | buffer_count++; | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | }; | ||
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h new file mode 100644 index 000000000000..03184959fa00 --- /dev/null +++ b/drivers/char/xilinx_hwicap/buffer_icap.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2003-2008 Xilinx Inc. | ||
28 | * All rights reserved. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | #ifndef XILINX_BUFFER_ICAP_H_ /* prevent circular inclusions */ | ||
37 | #define XILINX_BUFFER_ICAP_H_ /* by using protection macros */ | ||
38 | |||
39 | #include <linux/types.h> | ||
40 | #include <linux/cdev.h> | ||
41 | #include <linux/version.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | #include "xilinx_hwicap.h" | ||
46 | |||
47 | void buffer_icap_reset(struct hwicap_drvdata *drvdata); | ||
48 | |||
49 | /* Loads a partial bitstream from system memory. */ | ||
50 | int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, | ||
51 | u32 Size); | ||
52 | |||
53 | /* Loads a partial bitstream from system memory. */ | ||
54 | int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, | ||
55 | u32 Size); | ||
56 | |||
57 | #endif | ||
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c new file mode 100644 index 000000000000..0988314694a6 --- /dev/null +++ b/drivers/char/xilinx_hwicap/fifo_icap.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2007-2008 Xilinx Inc. | ||
28 | * All rights reserved. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | #include "fifo_icap.h" | ||
37 | |||
38 | /* Register offsets for the XHwIcap device. */ | ||
39 | #define XHI_GIER_OFFSET 0x1C /* Device Global Interrupt Enable Reg */ | ||
40 | #define XHI_IPISR_OFFSET 0x20 /* Interrupt Status Register */ | ||
41 | #define XHI_IPIER_OFFSET 0x28 /* Interrupt Enable Register */ | ||
42 | #define XHI_WF_OFFSET 0x100 /* Write FIFO */ | ||
43 | #define XHI_RF_OFFSET 0x104 /* Read FIFO */ | ||
44 | #define XHI_SZ_OFFSET 0x108 /* Size Register */ | ||
45 | #define XHI_CR_OFFSET 0x10C /* Control Register */ | ||
46 | #define XHI_SR_OFFSET 0x110 /* Status Register */ | ||
47 | #define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */ | ||
48 | #define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */ | ||
49 | |||
50 | /* Device Global Interrupt Enable Register (GIER) bit definitions */ | ||
51 | |||
52 | #define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */ | ||
53 | |||
54 | /** | ||
55 | * HwIcap Device Interrupt Status/Enable Registers | ||
56 | * | ||
57 | * Interrupt Status Register (IPISR) : This register holds the | ||
58 | * interrupt status flags for the device. These bits are toggle on | ||
59 | * write. | ||
60 | * | ||
61 | * Interrupt Enable Register (IPIER) : This register is used to enable | ||
62 | * interrupt sources for the device. | ||
63 | * Writing a '1' to a bit enables the corresponding interrupt. | ||
64 | * Writing a '0' to a bit disables the corresponding interrupt. | ||
65 | * | ||
66 | * IPISR/IPIER registers have the same bit definitions and are only defined | ||
67 | * once. | ||
68 | */ | ||
69 | #define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */ | ||
70 | #define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */ | ||
71 | #define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */ | ||
72 | #define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */ | ||
73 | #define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */ | ||
74 | |||
75 | /* Control Register (CR) */ | ||
76 | #define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */ | ||
77 | #define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */ | ||
78 | #define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */ | ||
79 | #define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */ | ||
80 | |||
81 | /* Status Register (SR) */ | ||
82 | #define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */ | ||
83 | #define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */ | ||
84 | #define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */ | ||
85 | #define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */ | ||
86 | #define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask */ | ||
87 | |||
88 | |||
89 | #define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */ | ||
90 | #define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */ | ||
91 | /* The maximum amount we can request from fifo_icap_get_configuration | ||
92 | at once, in bytes. */ | ||
93 | #define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF | ||
94 | |||
95 | |||
96 | /** | ||
97 | * fifo_icap_fifo_write: Write data to the write FIFO. | ||
98 | * @parameter drvdata: a pointer to the drvdata. | ||
99 | * @parameter data: the 32-bit value to be written to the FIFO. | ||
100 | * | ||
101 | * This function will silently fail if the fifo is full. | ||
102 | **/ | ||
103 | static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata, | ||
104 | u32 data) | ||
105 | { | ||
106 | dev_dbg(drvdata->dev, "fifo_write: %x\n", data); | ||
107 | out_be32(drvdata->base_address + XHI_WF_OFFSET, data); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * fifo_icap_fifo_read: Read data from the Read FIFO. | ||
112 | * @parameter drvdata: a pointer to the drvdata. | ||
113 | * | ||
114 | * This function will silently fail if the fifo is empty. | ||
115 | **/ | ||
116 | static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata) | ||
117 | { | ||
118 | u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET); | ||
119 | dev_dbg(drvdata->dev, "fifo_read: %x\n", data); | ||
120 | return data; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * fifo_icap_set_read_size: Set the the size register. | ||
125 | * @parameter drvdata: a pointer to the drvdata. | ||
126 | * @parameter data: the size of the following read transaction, in words. | ||
127 | **/ | ||
128 | static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata, | ||
129 | u32 data) | ||
130 | { | ||
131 | out_be32(drvdata->base_address + XHI_SZ_OFFSET, data); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * fifo_icap_start_config: Initiate a configuration (write) to the device. | ||
136 | * @parameter drvdata: a pointer to the drvdata. | ||
137 | **/ | ||
138 | static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata) | ||
139 | { | ||
140 | out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK); | ||
141 | dev_dbg(drvdata->dev, "configuration started\n"); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * fifo_icap_start_readback: Initiate a readback from the device. | ||
146 | * @parameter drvdata: a pointer to the drvdata. | ||
147 | **/ | ||
148 | static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata) | ||
149 | { | ||
150 | out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK); | ||
151 | dev_dbg(drvdata->dev, "readback started\n"); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * fifo_icap_busy: Return true if the ICAP is still processing a transaction. | ||
156 | * @parameter drvdata: a pointer to the drvdata. | ||
157 | **/ | ||
158 | static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata) | ||
159 | { | ||
160 | u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET); | ||
161 | dev_dbg(drvdata->dev, "Getting status = %x\n", status); | ||
162 | return (status & XHI_SR_DONE_MASK) ? 0 : 1; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * fifo_icap_write_fifo_vacancy: Query the write fifo available space. | ||
167 | * @parameter drvdata: a pointer to the drvdata. | ||
168 | * | ||
169 | * Return the number of words that can be safely pushed into the write fifo. | ||
170 | **/ | ||
171 | static inline u32 fifo_icap_write_fifo_vacancy( | ||
172 | struct hwicap_drvdata *drvdata) | ||
173 | { | ||
174 | return in_be32(drvdata->base_address + XHI_WFV_OFFSET); | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * fifo_icap_read_fifo_occupancy: Query the read fifo available data. | ||
179 | * @parameter drvdata: a pointer to the drvdata. | ||
180 | * | ||
181 | * Return the number of words that can be safely read from the read fifo. | ||
182 | **/ | ||
183 | static inline u32 fifo_icap_read_fifo_occupancy( | ||
184 | struct hwicap_drvdata *drvdata) | ||
185 | { | ||
186 | return in_be32(drvdata->base_address + XHI_RFO_OFFSET); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * fifo_icap_set_configuration: Send configuration data to the ICAP. | ||
191 | * @parameter drvdata: a pointer to the drvdata. | ||
192 | * @parameter frame_buffer: a pointer to the data to be written to the | ||
193 | * ICAP device. | ||
194 | * @parameter num_words: the number of words (32 bit) to write to the ICAP | ||
195 | * device. | ||
196 | |||
197 | * This function writes the given user data to the Write FIFO in | ||
198 | * polled mode and starts the transfer of the data to | ||
199 | * the ICAP device. | ||
200 | **/ | ||
201 | int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata, | ||
202 | u32 *frame_buffer, u32 num_words) | ||
203 | { | ||
204 | |||
205 | u32 write_fifo_vacancy = 0; | ||
206 | u32 retries = 0; | ||
207 | u32 remaining_words; | ||
208 | |||
209 | dev_dbg(drvdata->dev, "fifo_set_configuration\n"); | ||
210 | |||
211 | /* | ||
212 | * Check if the ICAP device is Busy with the last Read/Write | ||
213 | */ | ||
214 | if (fifo_icap_busy(drvdata)) | ||
215 | return -EBUSY; | ||
216 | |||
217 | /* | ||
218 | * Set up the buffer pointer and the words to be transferred. | ||
219 | */ | ||
220 | remaining_words = num_words; | ||
221 | |||
222 | while (remaining_words > 0) { | ||
223 | /* | ||
224 | * Wait until we have some data in the fifo. | ||
225 | */ | ||
226 | while (write_fifo_vacancy == 0) { | ||
227 | write_fifo_vacancy = | ||
228 | fifo_icap_write_fifo_vacancy(drvdata); | ||
229 | retries++; | ||
230 | if (retries > XHI_MAX_RETRIES) | ||
231 | return -EIO; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Write data into the Write FIFO. | ||
236 | */ | ||
237 | while ((write_fifo_vacancy != 0) && | ||
238 | (remaining_words > 0)) { | ||
239 | fifo_icap_fifo_write(drvdata, *frame_buffer); | ||
240 | |||
241 | remaining_words--; | ||
242 | write_fifo_vacancy--; | ||
243 | frame_buffer++; | ||
244 | } | ||
245 | /* Start pushing whatever is in the FIFO into the ICAP. */ | ||
246 | fifo_icap_start_config(drvdata); | ||
247 | } | ||
248 | |||
249 | /* Wait until the write has finished. */ | ||
250 | while (fifo_icap_busy(drvdata)) { | ||
251 | retries++; | ||
252 | if (retries > XHI_MAX_RETRIES) | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | dev_dbg(drvdata->dev, "done fifo_set_configuration\n"); | ||
257 | |||
258 | /* | ||
259 | * If the requested number of words have not been read from | ||
260 | * the device then indicate failure. | ||
261 | */ | ||
262 | if (remaining_words != 0) | ||
263 | return -EIO; | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * fifo_icap_get_configuration: Read configuration data from the device. | ||
270 | * @parameter drvdata: a pointer to the drvdata. | ||
271 | * @parameter data: Address of the data representing the partial bitstream | ||
272 | * @parameter size: the size of the partial bitstream in 32 bit words. | ||
273 | * | ||
274 | * This function reads the specified number of words from the ICAP device in | ||
275 | * the polled mode. | ||
276 | */ | ||
277 | int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata, | ||
278 | u32 *frame_buffer, u32 num_words) | ||
279 | { | ||
280 | |||
281 | u32 read_fifo_occupancy = 0; | ||
282 | u32 retries = 0; | ||
283 | u32 *data = frame_buffer; | ||
284 | u32 remaining_words; | ||
285 | u32 words_to_read; | ||
286 | |||
287 | dev_dbg(drvdata->dev, "fifo_get_configuration\n"); | ||
288 | |||
289 | /* | ||
290 | * Check if the ICAP device is Busy with the last Write/Read | ||
291 | */ | ||
292 | if (fifo_icap_busy(drvdata)) | ||
293 | return -EBUSY; | ||
294 | |||
295 | remaining_words = num_words; | ||
296 | |||
297 | while (remaining_words > 0) { | ||
298 | words_to_read = remaining_words; | ||
299 | /* The hardware has a limit on the number of words | ||
300 | that can be read at one time. */ | ||
301 | if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS) | ||
302 | words_to_read = XHI_MAX_READ_TRANSACTION_WORDS; | ||
303 | |||
304 | remaining_words -= words_to_read; | ||
305 | |||
306 | fifo_icap_set_read_size(drvdata, words_to_read); | ||
307 | fifo_icap_start_readback(drvdata); | ||
308 | |||
309 | while (words_to_read > 0) { | ||
310 | /* Wait until we have some data in the fifo. */ | ||
311 | while (read_fifo_occupancy == 0) { | ||
312 | read_fifo_occupancy = | ||
313 | fifo_icap_read_fifo_occupancy(drvdata); | ||
314 | retries++; | ||
315 | if (retries > XHI_MAX_RETRIES) | ||
316 | return -EIO; | ||
317 | } | ||
318 | |||
319 | if (read_fifo_occupancy > words_to_read) | ||
320 | read_fifo_occupancy = words_to_read; | ||
321 | |||
322 | words_to_read -= read_fifo_occupancy; | ||
323 | |||
324 | /* Read the data from the Read FIFO. */ | ||
325 | while (read_fifo_occupancy != 0) { | ||
326 | *data++ = fifo_icap_fifo_read(drvdata); | ||
327 | read_fifo_occupancy--; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | |||
332 | dev_dbg(drvdata->dev, "done fifo_get_configuration\n"); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * buffer_icap_reset: Reset the logic of the icap device. | ||
339 | * @parameter drvdata: a pointer to the drvdata. | ||
340 | * | ||
341 | * This function forces the software reset of the complete HWICAP device. | ||
342 | * All the registers will return to the default value and the FIFO is also | ||
343 | * flushed as a part of this software reset. | ||
344 | */ | ||
345 | void fifo_icap_reset(struct hwicap_drvdata *drvdata) | ||
346 | { | ||
347 | u32 reg_data; | ||
348 | /* | ||
349 | * Reset the device by setting/clearing the RESET bit in the | ||
350 | * Control Register. | ||
351 | */ | ||
352 | reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET); | ||
353 | |||
354 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
355 | reg_data | XHI_CR_SW_RESET_MASK); | ||
356 | |||
357 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
358 | reg_data & (~XHI_CR_SW_RESET_MASK)); | ||
359 | |||
360 | } | ||
361 | |||
362 | /** | ||
363 | * fifo_icap_flush_fifo: This function flushes the FIFOs in the device. | ||
364 | * @parameter drvdata: a pointer to the drvdata. | ||
365 | */ | ||
366 | void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata) | ||
367 | { | ||
368 | u32 reg_data; | ||
369 | /* | ||
370 | * Flush the FIFO by setting/clearing the FIFO Clear bit in the | ||
371 | * Control Register. | ||
372 | */ | ||
373 | reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET); | ||
374 | |||
375 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
376 | reg_data | XHI_CR_FIFO_CLR_MASK); | ||
377 | |||
378 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
379 | reg_data & (~XHI_CR_FIFO_CLR_MASK)); | ||
380 | } | ||
381 | |||
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h new file mode 100644 index 000000000000..4d3068dd0405 --- /dev/null +++ b/drivers/char/xilinx_hwicap/fifo_icap.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2007-2008 Xilinx Inc. | ||
28 | * All rights reserved. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | #ifndef XILINX_FIFO_ICAP_H_ /* prevent circular inclusions */ | ||
37 | #define XILINX_FIFO_ICAP_H_ /* by using protection macros */ | ||
38 | |||
39 | #include <linux/types.h> | ||
40 | #include <linux/cdev.h> | ||
41 | #include <linux/version.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | #include "xilinx_hwicap.h" | ||
46 | |||
47 | /* Reads integers from the device into the storage buffer. */ | ||
48 | int fifo_icap_get_configuration( | ||
49 | struct hwicap_drvdata *drvdata, | ||
50 | u32 *FrameBuffer, | ||
51 | u32 NumWords); | ||
52 | |||
53 | /* Writes integers to the device from the storage buffer. */ | ||
54 | int fifo_icap_set_configuration( | ||
55 | struct hwicap_drvdata *drvdata, | ||
56 | u32 *FrameBuffer, | ||
57 | u32 NumWords); | ||
58 | |||
59 | void fifo_icap_reset(struct hwicap_drvdata *drvdata); | ||
60 | void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata); | ||
61 | |||
62 | #endif | ||
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c new file mode 100644 index 000000000000..24f6aef0fd3c --- /dev/null +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c | |||
@@ -0,0 +1,904 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2002 Xilinx Inc., Systems Engineering Group | ||
28 | * (c) Copyright 2004 Xilinx Inc., Systems Engineering Group | ||
29 | * (c) Copyright 2007-2008 Xilinx Inc. | ||
30 | * All rights reserved. | ||
31 | * | ||
32 | * You should have received a copy of the GNU General Public License along | ||
33 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
34 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
35 | * | ||
36 | *****************************************************************************/ | ||
37 | |||
38 | /* | ||
39 | * This is the code behind /dev/xilinx_icap -- it allows a user-space | ||
40 | * application to use the Xilinx ICAP subsystem. | ||
41 | * | ||
42 | * The following operations are possible: | ||
43 | * | ||
44 | * open open the port and initialize for access. | ||
45 | * release release port | ||
46 | * write Write a bitstream to the configuration processor. | ||
47 | * read Read a data stream from the configuration processor. | ||
48 | * | ||
49 | * After being opened, the port is initialized and accessed to avoid a | ||
50 | * corrupted first read which may occur with some hardware. The port | ||
51 | * is left in a desynched state, requiring that a synch sequence be | ||
52 | * transmitted before any valid configuration data. A user will have | ||
53 | * exclusive access to the device while it remains open, and the state | ||
54 | * of the ICAP cannot be guaranteed after the device is closed. Note | ||
55 | * that a complete reset of the core and the state of the ICAP cannot | ||
56 | * be performed on many versions of the cores, hence users of this | ||
57 | * device should avoid making inconsistent accesses to the device. In | ||
58 | * particular, accessing the read interface, without first generating | ||
59 | * a write containing a readback packet can leave the ICAP in an | ||
60 | * inaccessible state. | ||
61 | * | ||
62 | * Note that in order to use the read interface, it is first necessary | ||
63 | * to write a request packet to the write interface. i.e., it is not | ||
64 | * possible to simply readback the bitstream (or any configuration | ||
65 | * bits) from a device without specifically requesting them first. | ||
66 | * The code to craft such packets is intended to be part of the | ||
67 | * user-space application code that uses this device. The simplest | ||
68 | * way to use this interface is simply: | ||
69 | * | ||
70 | * cp foo.bit /dev/xilinx_icap | ||
71 | * | ||
72 | * Note that unless foo.bit is an appropriately constructed partial | ||
73 | * bitstream, this has a high likelyhood of overwriting the design | ||
74 | * currently programmed in the FPGA. | ||
75 | */ | ||
76 | |||
77 | #include <linux/version.h> | ||
78 | #include <linux/module.h> | ||
79 | #include <linux/kernel.h> | ||
80 | #include <linux/types.h> | ||
81 | #include <linux/ioport.h> | ||
82 | #include <linux/interrupt.h> | ||
83 | #include <linux/fcntl.h> | ||
84 | #include <linux/init.h> | ||
85 | #include <linux/poll.h> | ||
86 | #include <linux/proc_fs.h> | ||
87 | #include <asm/semaphore.h> | ||
88 | #include <linux/sysctl.h> | ||
89 | #include <linux/version.h> | ||
90 | #include <linux/fs.h> | ||
91 | #include <linux/cdev.h> | ||
92 | #include <linux/platform_device.h> | ||
93 | |||
94 | #include <asm/io.h> | ||
95 | #include <asm/uaccess.h> | ||
96 | #include <asm/system.h> | ||
97 | |||
98 | #ifdef CONFIG_OF | ||
99 | /* For open firmware. */ | ||
100 | #include <linux/of_device.h> | ||
101 | #include <linux/of_platform.h> | ||
102 | #endif | ||
103 | |||
104 | #include "xilinx_hwicap.h" | ||
105 | #include "buffer_icap.h" | ||
106 | #include "fifo_icap.h" | ||
107 | |||
108 | #define DRIVER_NAME "xilinx_icap" | ||
109 | |||
110 | #define HWICAP_REGS (0x10000) | ||
111 | |||
112 | /* dynamically allocate device number */ | ||
113 | static int xhwicap_major; | ||
114 | static int xhwicap_minor; | ||
115 | #define HWICAP_DEVICES 1 | ||
116 | |||
117 | module_param(xhwicap_major, int, S_IRUGO); | ||
118 | module_param(xhwicap_minor, int, S_IRUGO); | ||
119 | |||
120 | /* An array, which is set to true when the device is registered. */ | ||
121 | static bool probed_devices[HWICAP_DEVICES]; | ||
122 | |||
123 | static struct class *icap_class; | ||
124 | |||
125 | #define UNIMPLEMENTED 0xFFFF | ||
126 | |||
127 | static const struct config_registers v2_config_registers = { | ||
128 | .CRC = 0, | ||
129 | .FAR = 1, | ||
130 | .FDRI = 2, | ||
131 | .FDRO = 3, | ||
132 | .CMD = 4, | ||
133 | .CTL = 5, | ||
134 | .MASK = 6, | ||
135 | .STAT = 7, | ||
136 | .LOUT = 8, | ||
137 | .COR = 9, | ||
138 | .MFWR = 10, | ||
139 | .FLR = 11, | ||
140 | .KEY = 12, | ||
141 | .CBC = 13, | ||
142 | .IDCODE = 14, | ||
143 | .AXSS = UNIMPLEMENTED, | ||
144 | .C0R_1 = UNIMPLEMENTED, | ||
145 | .CSOB = UNIMPLEMENTED, | ||
146 | .WBSTAR = UNIMPLEMENTED, | ||
147 | .TIMER = UNIMPLEMENTED, | ||
148 | .BOOTSTS = UNIMPLEMENTED, | ||
149 | .CTL_1 = UNIMPLEMENTED, | ||
150 | }; | ||
151 | |||
152 | static const struct config_registers v4_config_registers = { | ||
153 | .CRC = 0, | ||
154 | .FAR = 1, | ||
155 | .FDRI = 2, | ||
156 | .FDRO = 3, | ||
157 | .CMD = 4, | ||
158 | .CTL = 5, | ||
159 | .MASK = 6, | ||
160 | .STAT = 7, | ||
161 | .LOUT = 8, | ||
162 | .COR = 9, | ||
163 | .MFWR = 10, | ||
164 | .FLR = UNIMPLEMENTED, | ||
165 | .KEY = UNIMPLEMENTED, | ||
166 | .CBC = 11, | ||
167 | .IDCODE = 12, | ||
168 | .AXSS = 13, | ||
169 | .C0R_1 = UNIMPLEMENTED, | ||
170 | .CSOB = UNIMPLEMENTED, | ||
171 | .WBSTAR = UNIMPLEMENTED, | ||
172 | .TIMER = UNIMPLEMENTED, | ||
173 | .BOOTSTS = UNIMPLEMENTED, | ||
174 | .CTL_1 = UNIMPLEMENTED, | ||
175 | }; | ||
176 | static const struct config_registers v5_config_registers = { | ||
177 | .CRC = 0, | ||
178 | .FAR = 1, | ||
179 | .FDRI = 2, | ||
180 | .FDRO = 3, | ||
181 | .CMD = 4, | ||
182 | .CTL = 5, | ||
183 | .MASK = 6, | ||
184 | .STAT = 7, | ||
185 | .LOUT = 8, | ||
186 | .COR = 9, | ||
187 | .MFWR = 10, | ||
188 | .FLR = UNIMPLEMENTED, | ||
189 | .KEY = UNIMPLEMENTED, | ||
190 | .CBC = 11, | ||
191 | .IDCODE = 12, | ||
192 | .AXSS = 13, | ||
193 | .C0R_1 = 14, | ||
194 | .CSOB = 15, | ||
195 | .WBSTAR = 16, | ||
196 | .TIMER = 17, | ||
197 | .BOOTSTS = 18, | ||
198 | .CTL_1 = 19, | ||
199 | }; | ||
200 | |||
201 | /** | ||
202 | * hwicap_command_desync: Send a DESYNC command to the ICAP port. | ||
203 | * @parameter drvdata: a pointer to the drvdata. | ||
204 | * | ||
205 | * This command desynchronizes the ICAP After this command, a | ||
206 | * bitstream containing a NULL packet, followed by a SYNCH packet is | ||
207 | * required before the ICAP will recognize commands. | ||
208 | */ | ||
209 | int hwicap_command_desync(struct hwicap_drvdata *drvdata) | ||
210 | { | ||
211 | u32 buffer[4]; | ||
212 | u32 index = 0; | ||
213 | |||
214 | /* | ||
215 | * Create the data to be written to the ICAP. | ||
216 | */ | ||
217 | buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1; | ||
218 | buffer[index++] = XHI_CMD_DESYNCH; | ||
219 | buffer[index++] = XHI_NOOP_PACKET; | ||
220 | buffer[index++] = XHI_NOOP_PACKET; | ||
221 | |||
222 | /* | ||
223 | * Write the data to the FIFO and intiate the transfer of data present | ||
224 | * in the FIFO to the ICAP device. | ||
225 | */ | ||
226 | return drvdata->config->set_configuration(drvdata, | ||
227 | &buffer[0], index); | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * hwicap_command_capture: Send a CAPTURE command to the ICAP port. | ||
232 | * @parameter drvdata: a pointer to the drvdata. | ||
233 | * | ||
234 | * This command captures all of the flip flop states so they will be | ||
235 | * available during readback. One can use this command instead of | ||
236 | * enabling the CAPTURE block in the design. | ||
237 | */ | ||
238 | int hwicap_command_capture(struct hwicap_drvdata *drvdata) | ||
239 | { | ||
240 | u32 buffer[7]; | ||
241 | u32 index = 0; | ||
242 | |||
243 | /* | ||
244 | * Create the data to be written to the ICAP. | ||
245 | */ | ||
246 | buffer[index++] = XHI_DUMMY_PACKET; | ||
247 | buffer[index++] = XHI_SYNC_PACKET; | ||
248 | buffer[index++] = XHI_NOOP_PACKET; | ||
249 | buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1; | ||
250 | buffer[index++] = XHI_CMD_GCAPTURE; | ||
251 | buffer[index++] = XHI_DUMMY_PACKET; | ||
252 | buffer[index++] = XHI_DUMMY_PACKET; | ||
253 | |||
254 | /* | ||
255 | * Write the data to the FIFO and intiate the transfer of data | ||
256 | * present in the FIFO to the ICAP device. | ||
257 | */ | ||
258 | return drvdata->config->set_configuration(drvdata, | ||
259 | &buffer[0], index); | ||
260 | |||
261 | } | ||
262 | |||
263 | /** | ||
264 | * hwicap_get_configuration_register: Query a configuration register. | ||
265 | * @parameter drvdata: a pointer to the drvdata. | ||
266 | * @parameter reg: a constant which represents the configuration | ||
267 | * register value to be returned. | ||
268 | * Examples: XHI_IDCODE, XHI_FLR. | ||
269 | * @parameter RegData: returns the value of the register. | ||
270 | * | ||
271 | * Sends a query packet to the ICAP and then receives the response. | ||
272 | * The icap is left in Synched state. | ||
273 | */ | ||
274 | int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata, | ||
275 | u32 reg, u32 *RegData) | ||
276 | { | ||
277 | int status; | ||
278 | u32 buffer[6]; | ||
279 | u32 index = 0; | ||
280 | |||
281 | /* | ||
282 | * Create the data to be written to the ICAP. | ||
283 | */ | ||
284 | buffer[index++] = XHI_DUMMY_PACKET; | ||
285 | buffer[index++] = XHI_SYNC_PACKET; | ||
286 | buffer[index++] = XHI_NOOP_PACKET; | ||
287 | buffer[index++] = hwicap_type_1_read(reg) | 1; | ||
288 | buffer[index++] = XHI_NOOP_PACKET; | ||
289 | buffer[index++] = XHI_NOOP_PACKET; | ||
290 | |||
291 | /* | ||
292 | * Write the data to the FIFO and intiate the transfer of data present | ||
293 | * in the FIFO to the ICAP device. | ||
294 | */ | ||
295 | status = drvdata->config->set_configuration(drvdata, | ||
296 | &buffer[0], index); | ||
297 | if (status) | ||
298 | return status; | ||
299 | |||
300 | /* | ||
301 | * Read the configuration register | ||
302 | */ | ||
303 | status = drvdata->config->get_configuration(drvdata, RegData, 1); | ||
304 | if (status) | ||
305 | return status; | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata) | ||
311 | { | ||
312 | int status; | ||
313 | u32 idcode; | ||
314 | |||
315 | dev_dbg(drvdata->dev, "initializing\n"); | ||
316 | |||
317 | /* Abort any current transaction, to make sure we have the | ||
318 | * ICAP in a good state. */ | ||
319 | dev_dbg(drvdata->dev, "Reset...\n"); | ||
320 | drvdata->config->reset(drvdata); | ||
321 | |||
322 | dev_dbg(drvdata->dev, "Desync...\n"); | ||
323 | status = hwicap_command_desync(drvdata); | ||
324 | if (status) | ||
325 | return status; | ||
326 | |||
327 | /* Attempt to read the IDCODE from ICAP. This | ||
328 | * may not be returned correctly, due to the design of the | ||
329 | * hardware. | ||
330 | */ | ||
331 | dev_dbg(drvdata->dev, "Reading IDCODE...\n"); | ||
332 | status = hwicap_get_configuration_register( | ||
333 | drvdata, drvdata->config_regs->IDCODE, &idcode); | ||
334 | dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode); | ||
335 | if (status) | ||
336 | return status; | ||
337 | |||
338 | dev_dbg(drvdata->dev, "Desync...\n"); | ||
339 | status = hwicap_command_desync(drvdata); | ||
340 | if (status) | ||
341 | return status; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static ssize_t | ||
347 | hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos) | ||
348 | { | ||
349 | struct hwicap_drvdata *drvdata = file->private_data; | ||
350 | ssize_t bytes_to_read = 0; | ||
351 | u32 *kbuf; | ||
352 | u32 words; | ||
353 | u32 bytes_remaining; | ||
354 | int status; | ||
355 | |||
356 | if (down_interruptible(&drvdata->sem)) | ||
357 | return -ERESTARTSYS; | ||
358 | |||
359 | if (drvdata->read_buffer_in_use) { | ||
360 | /* If there are leftover bytes in the buffer, just */ | ||
361 | /* return them and don't try to read more from the */ | ||
362 | /* ICAP device. */ | ||
363 | bytes_to_read = | ||
364 | (count < drvdata->read_buffer_in_use) ? count : | ||
365 | drvdata->read_buffer_in_use; | ||
366 | |||
367 | /* Return the data currently in the read buffer. */ | ||
368 | if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) { | ||
369 | status = -EFAULT; | ||
370 | goto error; | ||
371 | } | ||
372 | drvdata->read_buffer_in_use -= bytes_to_read; | ||
373 | memcpy(drvdata->read_buffer + bytes_to_read, | ||
374 | drvdata->read_buffer, 4 - bytes_to_read); | ||
375 | } else { | ||
376 | /* Get new data from the ICAP, and return was was requested. */ | ||
377 | kbuf = (u32 *) get_zeroed_page(GFP_KERNEL); | ||
378 | if (!kbuf) { | ||
379 | status = -ENOMEM; | ||
380 | goto error; | ||
381 | } | ||
382 | |||
383 | /* The ICAP device is only able to read complete */ | ||
384 | /* words. If a number of bytes that do not correspond */ | ||
385 | /* to complete words is requested, then we read enough */ | ||
386 | /* words to get the required number of bytes, and then */ | ||
387 | /* save the remaining bytes for the next read. */ | ||
388 | |||
389 | /* Determine the number of words to read, rounding up */ | ||
390 | /* if necessary. */ | ||
391 | words = ((count + 3) >> 2); | ||
392 | bytes_to_read = words << 2; | ||
393 | |||
394 | if (bytes_to_read > PAGE_SIZE) | ||
395 | bytes_to_read = PAGE_SIZE; | ||
396 | |||
397 | /* Ensure we only read a complete number of words. */ | ||
398 | bytes_remaining = bytes_to_read & 3; | ||
399 | bytes_to_read &= ~3; | ||
400 | words = bytes_to_read >> 2; | ||
401 | |||
402 | status = drvdata->config->get_configuration(drvdata, | ||
403 | kbuf, words); | ||
404 | |||
405 | /* If we didn't read correctly, then bail out. */ | ||
406 | if (status) { | ||
407 | free_page((unsigned long)kbuf); | ||
408 | goto error; | ||
409 | } | ||
410 | |||
411 | /* If we fail to return the data to the user, then bail out. */ | ||
412 | if (copy_to_user(buf, kbuf, bytes_to_read)) { | ||
413 | free_page((unsigned long)kbuf); | ||
414 | status = -EFAULT; | ||
415 | goto error; | ||
416 | } | ||
417 | memcpy(kbuf, drvdata->read_buffer, bytes_remaining); | ||
418 | drvdata->read_buffer_in_use = bytes_remaining; | ||
419 | free_page((unsigned long)kbuf); | ||
420 | } | ||
421 | status = bytes_to_read; | ||
422 | error: | ||
423 | up(&drvdata->sem); | ||
424 | return status; | ||
425 | } | ||
426 | |||
427 | static ssize_t | ||
428 | hwicap_write(struct file *file, const char *buf, | ||
429 | size_t count, loff_t *ppos) | ||
430 | { | ||
431 | struct hwicap_drvdata *drvdata = file->private_data; | ||
432 | ssize_t written = 0; | ||
433 | ssize_t left = count; | ||
434 | u32 *kbuf; | ||
435 | ssize_t len; | ||
436 | ssize_t status; | ||
437 | |||
438 | if (down_interruptible(&drvdata->sem)) | ||
439 | return -ERESTARTSYS; | ||
440 | |||
441 | left += drvdata->write_buffer_in_use; | ||
442 | |||
443 | /* Only write multiples of 4 bytes. */ | ||
444 | if (left < 4) { | ||
445 | status = 0; | ||
446 | goto error; | ||
447 | } | ||
448 | |||
449 | kbuf = (u32 *) __get_free_page(GFP_KERNEL); | ||
450 | if (!kbuf) { | ||
451 | status = -ENOMEM; | ||
452 | goto error; | ||
453 | } | ||
454 | |||
455 | while (left > 3) { | ||
456 | /* only write multiples of 4 bytes, so there might */ | ||
457 | /* be as many as 3 bytes left (at the end). */ | ||
458 | len = left; | ||
459 | |||
460 | if (len > PAGE_SIZE) | ||
461 | len = PAGE_SIZE; | ||
462 | len &= ~3; | ||
463 | |||
464 | if (drvdata->write_buffer_in_use) { | ||
465 | memcpy(kbuf, drvdata->write_buffer, | ||
466 | drvdata->write_buffer_in_use); | ||
467 | if (copy_from_user( | ||
468 | (((char *)kbuf) + (drvdata->write_buffer_in_use)), | ||
469 | buf + written, | ||
470 | len - (drvdata->write_buffer_in_use))) { | ||
471 | free_page((unsigned long)kbuf); | ||
472 | status = -EFAULT; | ||
473 | goto error; | ||
474 | } | ||
475 | } else { | ||
476 | if (copy_from_user(kbuf, buf + written, len)) { | ||
477 | free_page((unsigned long)kbuf); | ||
478 | status = -EFAULT; | ||
479 | goto error; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | status = drvdata->config->set_configuration(drvdata, | ||
484 | kbuf, len >> 2); | ||
485 | |||
486 | if (status) { | ||
487 | free_page((unsigned long)kbuf); | ||
488 | status = -EFAULT; | ||
489 | goto error; | ||
490 | } | ||
491 | if (drvdata->write_buffer_in_use) { | ||
492 | len -= drvdata->write_buffer_in_use; | ||
493 | left -= drvdata->write_buffer_in_use; | ||
494 | drvdata->write_buffer_in_use = 0; | ||
495 | } | ||
496 | written += len; | ||
497 | left -= len; | ||
498 | } | ||
499 | if ((left > 0) && (left < 4)) { | ||
500 | if (!copy_from_user(drvdata->write_buffer, | ||
501 | buf + written, left)) { | ||
502 | drvdata->write_buffer_in_use = left; | ||
503 | written += left; | ||
504 | left = 0; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | free_page((unsigned long)kbuf); | ||
509 | status = written; | ||
510 | error: | ||
511 | up(&drvdata->sem); | ||
512 | return status; | ||
513 | } | ||
514 | |||
515 | static int hwicap_open(struct inode *inode, struct file *file) | ||
516 | { | ||
517 | struct hwicap_drvdata *drvdata; | ||
518 | int status; | ||
519 | |||
520 | drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev); | ||
521 | |||
522 | if (down_interruptible(&drvdata->sem)) | ||
523 | return -ERESTARTSYS; | ||
524 | |||
525 | if (drvdata->is_open) { | ||
526 | status = -EBUSY; | ||
527 | goto error; | ||
528 | } | ||
529 | |||
530 | status = hwicap_initialize_hwicap(drvdata); | ||
531 | if (status) { | ||
532 | dev_err(drvdata->dev, "Failed to open file"); | ||
533 | goto error; | ||
534 | } | ||
535 | |||
536 | file->private_data = drvdata; | ||
537 | drvdata->write_buffer_in_use = 0; | ||
538 | drvdata->read_buffer_in_use = 0; | ||
539 | drvdata->is_open = 1; | ||
540 | |||
541 | error: | ||
542 | up(&drvdata->sem); | ||
543 | return status; | ||
544 | } | ||
545 | |||
546 | static int hwicap_release(struct inode *inode, struct file *file) | ||
547 | { | ||
548 | struct hwicap_drvdata *drvdata = file->private_data; | ||
549 | int i; | ||
550 | int status = 0; | ||
551 | |||
552 | if (down_interruptible(&drvdata->sem)) | ||
553 | return -ERESTARTSYS; | ||
554 | |||
555 | if (drvdata->write_buffer_in_use) { | ||
556 | /* Flush write buffer. */ | ||
557 | for (i = drvdata->write_buffer_in_use; i < 4; i++) | ||
558 | drvdata->write_buffer[i] = 0; | ||
559 | |||
560 | status = drvdata->config->set_configuration(drvdata, | ||
561 | (u32 *) drvdata->write_buffer, 1); | ||
562 | if (status) | ||
563 | goto error; | ||
564 | } | ||
565 | |||
566 | status = hwicap_command_desync(drvdata); | ||
567 | if (status) | ||
568 | goto error; | ||
569 | |||
570 | error: | ||
571 | drvdata->is_open = 0; | ||
572 | up(&drvdata->sem); | ||
573 | return status; | ||
574 | } | ||
575 | |||
576 | static struct file_operations hwicap_fops = { | ||
577 | .owner = THIS_MODULE, | ||
578 | .write = hwicap_write, | ||
579 | .read = hwicap_read, | ||
580 | .open = hwicap_open, | ||
581 | .release = hwicap_release, | ||
582 | }; | ||
583 | |||
584 | static int __devinit hwicap_setup(struct device *dev, int id, | ||
585 | const struct resource *regs_res, | ||
586 | const struct hwicap_driver_config *config, | ||
587 | const struct config_registers *config_regs) | ||
588 | { | ||
589 | dev_t devt; | ||
590 | struct hwicap_drvdata *drvdata = NULL; | ||
591 | int retval = 0; | ||
592 | |||
593 | dev_info(dev, "Xilinx icap port driver\n"); | ||
594 | |||
595 | if (id < 0) { | ||
596 | for (id = 0; id < HWICAP_DEVICES; id++) | ||
597 | if (!probed_devices[id]) | ||
598 | break; | ||
599 | } | ||
600 | if (id < 0 || id >= HWICAP_DEVICES) { | ||
601 | dev_err(dev, "%s%i too large\n", DRIVER_NAME, id); | ||
602 | return -EINVAL; | ||
603 | } | ||
604 | if (probed_devices[id]) { | ||
605 | dev_err(dev, "cannot assign to %s%i; it is already in use\n", | ||
606 | DRIVER_NAME, id); | ||
607 | return -EBUSY; | ||
608 | } | ||
609 | |||
610 | probed_devices[id] = 1; | ||
611 | |||
612 | devt = MKDEV(xhwicap_major, xhwicap_minor + id); | ||
613 | |||
614 | drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); | ||
615 | if (!drvdata) { | ||
616 | dev_err(dev, "Couldn't allocate device private record\n"); | ||
617 | return -ENOMEM; | ||
618 | } | ||
619 | memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata)); | ||
620 | dev_set_drvdata(dev, (void *)drvdata); | ||
621 | |||
622 | if (!regs_res) { | ||
623 | dev_err(dev, "Couldn't get registers resource\n"); | ||
624 | retval = -EFAULT; | ||
625 | goto failed1; | ||
626 | } | ||
627 | |||
628 | drvdata->mem_start = regs_res->start; | ||
629 | drvdata->mem_end = regs_res->end; | ||
630 | drvdata->mem_size = regs_res->end - regs_res->start + 1; | ||
631 | |||
632 | if (!request_mem_region(drvdata->mem_start, | ||
633 | drvdata->mem_size, DRIVER_NAME)) { | ||
634 | dev_err(dev, "Couldn't lock memory region at %p\n", | ||
635 | (void *)regs_res->start); | ||
636 | retval = -EBUSY; | ||
637 | goto failed1; | ||
638 | } | ||
639 | |||
640 | drvdata->devt = devt; | ||
641 | drvdata->dev = dev; | ||
642 | drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size); | ||
643 | if (!drvdata->base_address) { | ||
644 | dev_err(dev, "ioremap() failed\n"); | ||
645 | goto failed2; | ||
646 | } | ||
647 | |||
648 | drvdata->config = config; | ||
649 | drvdata->config_regs = config_regs; | ||
650 | |||
651 | init_MUTEX(&drvdata->sem); | ||
652 | drvdata->is_open = 0; | ||
653 | |||
654 | dev_info(dev, "ioremap %lx to %p with size %x\n", | ||
655 | (unsigned long int)drvdata->mem_start, | ||
656 | drvdata->base_address, drvdata->mem_size); | ||
657 | |||
658 | cdev_init(&drvdata->cdev, &hwicap_fops); | ||
659 | drvdata->cdev.owner = THIS_MODULE; | ||
660 | retval = cdev_add(&drvdata->cdev, devt, 1); | ||
661 | if (retval) { | ||
662 | dev_err(dev, "cdev_add() failed\n"); | ||
663 | goto failed3; | ||
664 | } | ||
665 | /* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */ | ||
666 | class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME); | ||
667 | return 0; /* success */ | ||
668 | |||
669 | failed3: | ||
670 | iounmap(drvdata->base_address); | ||
671 | |||
672 | failed2: | ||
673 | release_mem_region(regs_res->start, drvdata->mem_size); | ||
674 | |||
675 | failed1: | ||
676 | kfree(drvdata); | ||
677 | |||
678 | return retval; | ||
679 | } | ||
680 | |||
681 | static struct hwicap_driver_config buffer_icap_config = { | ||
682 | .get_configuration = buffer_icap_get_configuration, | ||
683 | .set_configuration = buffer_icap_set_configuration, | ||
684 | .reset = buffer_icap_reset, | ||
685 | }; | ||
686 | |||
687 | static struct hwicap_driver_config fifo_icap_config = { | ||
688 | .get_configuration = fifo_icap_get_configuration, | ||
689 | .set_configuration = fifo_icap_set_configuration, | ||
690 | .reset = fifo_icap_reset, | ||
691 | }; | ||
692 | |||
693 | static int __devexit hwicap_remove(struct device *dev) | ||
694 | { | ||
695 | struct hwicap_drvdata *drvdata; | ||
696 | |||
697 | drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev); | ||
698 | |||
699 | if (!drvdata) | ||
700 | return 0; | ||
701 | |||
702 | class_device_destroy(icap_class, drvdata->devt); | ||
703 | cdev_del(&drvdata->cdev); | ||
704 | iounmap(drvdata->base_address); | ||
705 | release_mem_region(drvdata->mem_start, drvdata->mem_size); | ||
706 | kfree(drvdata); | ||
707 | dev_set_drvdata(dev, NULL); | ||
708 | probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0; | ||
709 | |||
710 | return 0; /* success */ | ||
711 | } | ||
712 | |||
713 | static int __devinit hwicap_drv_probe(struct platform_device *pdev) | ||
714 | { | ||
715 | struct resource *res; | ||
716 | const struct config_registers *regs; | ||
717 | const char *family; | ||
718 | |||
719 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
720 | if (!res) | ||
721 | return -ENODEV; | ||
722 | |||
723 | /* It's most likely that we're using V4, if the family is not | ||
724 | specified */ | ||
725 | regs = &v4_config_registers; | ||
726 | family = pdev->dev.platform_data; | ||
727 | |||
728 | if (family) { | ||
729 | if (!strcmp(family, "virtex2p")) { | ||
730 | regs = &v2_config_registers; | ||
731 | } else if (!strcmp(family, "virtex4")) { | ||
732 | regs = &v4_config_registers; | ||
733 | } else if (!strcmp(family, "virtex5")) { | ||
734 | regs = &v5_config_registers; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | return hwicap_setup(&pdev->dev, pdev->id, res, | ||
739 | &buffer_icap_config, regs); | ||
740 | } | ||
741 | |||
742 | static int __devexit hwicap_drv_remove(struct platform_device *pdev) | ||
743 | { | ||
744 | return hwicap_remove(&pdev->dev); | ||
745 | } | ||
746 | |||
747 | static struct platform_driver hwicap_platform_driver = { | ||
748 | .probe = hwicap_drv_probe, | ||
749 | .remove = hwicap_drv_remove, | ||
750 | .driver = { | ||
751 | .owner = THIS_MODULE, | ||
752 | .name = DRIVER_NAME, | ||
753 | }, | ||
754 | }; | ||
755 | |||
756 | /* --------------------------------------------------------------------- | ||
757 | * OF bus binding | ||
758 | */ | ||
759 | |||
760 | #if defined(CONFIG_OF) | ||
761 | static int __devinit | ||
762 | hwicap_of_probe(struct of_device *op, const struct of_device_id *match) | ||
763 | { | ||
764 | struct resource res; | ||
765 | const unsigned int *id; | ||
766 | const char *family; | ||
767 | int rc; | ||
768 | const struct hwicap_driver_config *config = match->data; | ||
769 | const struct config_registers *regs; | ||
770 | |||
771 | dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match); | ||
772 | |||
773 | rc = of_address_to_resource(op->node, 0, &res); | ||
774 | if (rc) { | ||
775 | dev_err(&op->dev, "invalid address\n"); | ||
776 | return rc; | ||
777 | } | ||
778 | |||
779 | id = of_get_property(op->node, "port-number", NULL); | ||
780 | |||
781 | /* It's most likely that we're using V4, if the family is not | ||
782 | specified */ | ||
783 | regs = &v4_config_registers; | ||
784 | family = of_get_property(op->node, "xlnx,family", NULL); | ||
785 | |||
786 | if (family) { | ||
787 | if (!strcmp(family, "virtex2p")) { | ||
788 | regs = &v2_config_registers; | ||
789 | } else if (!strcmp(family, "virtex4")) { | ||
790 | regs = &v4_config_registers; | ||
791 | } else if (!strcmp(family, "virtex5")) { | ||
792 | regs = &v5_config_registers; | ||
793 | } | ||
794 | } | ||
795 | return hwicap_setup(&op->dev, id ? *id : -1, &res, config, | ||
796 | regs); | ||
797 | } | ||
798 | |||
799 | static int __devexit hwicap_of_remove(struct of_device *op) | ||
800 | { | ||
801 | return hwicap_remove(&op->dev); | ||
802 | } | ||
803 | |||
804 | /* Match table for of_platform binding */ | ||
805 | static const struct of_device_id __devinit hwicap_of_match[] = { | ||
806 | { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, | ||
807 | { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config}, | ||
808 | {}, | ||
809 | }; | ||
810 | MODULE_DEVICE_TABLE(of, hwicap_of_match); | ||
811 | |||
812 | static struct of_platform_driver hwicap_of_driver = { | ||
813 | .owner = THIS_MODULE, | ||
814 | .name = DRIVER_NAME, | ||
815 | .match_table = hwicap_of_match, | ||
816 | .probe = hwicap_of_probe, | ||
817 | .remove = __devexit_p(hwicap_of_remove), | ||
818 | .driver = { | ||
819 | .name = DRIVER_NAME, | ||
820 | }, | ||
821 | }; | ||
822 | |||
823 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
824 | static inline int __devinit hwicap_of_register(void) | ||
825 | { | ||
826 | pr_debug("hwicap: calling of_register_platform_driver()\n"); | ||
827 | return of_register_platform_driver(&hwicap_of_driver); | ||
828 | } | ||
829 | |||
830 | static inline void __devexit hwicap_of_unregister(void) | ||
831 | { | ||
832 | of_unregister_platform_driver(&hwicap_of_driver); | ||
833 | } | ||
834 | #else /* CONFIG_OF */ | ||
835 | /* CONFIG_OF not enabled; do nothing helpers */ | ||
836 | static inline int __devinit hwicap_of_register(void) { return 0; } | ||
837 | static inline void __devexit hwicap_of_unregister(void) { } | ||
838 | #endif /* CONFIG_OF */ | ||
839 | |||
840 | static int __devinit hwicap_module_init(void) | ||
841 | { | ||
842 | dev_t devt; | ||
843 | int retval; | ||
844 | |||
845 | icap_class = class_create(THIS_MODULE, "xilinx_config"); | ||
846 | |||
847 | if (xhwicap_major) { | ||
848 | devt = MKDEV(xhwicap_major, xhwicap_minor); | ||
849 | retval = register_chrdev_region( | ||
850 | devt, | ||
851 | HWICAP_DEVICES, | ||
852 | DRIVER_NAME); | ||
853 | if (retval < 0) | ||
854 | return retval; | ||
855 | } else { | ||
856 | retval = alloc_chrdev_region(&devt, | ||
857 | xhwicap_minor, | ||
858 | HWICAP_DEVICES, | ||
859 | DRIVER_NAME); | ||
860 | if (retval < 0) | ||
861 | return retval; | ||
862 | xhwicap_major = MAJOR(devt); | ||
863 | } | ||
864 | |||
865 | retval = platform_driver_register(&hwicap_platform_driver); | ||
866 | |||
867 | if (retval) | ||
868 | goto failed1; | ||
869 | |||
870 | retval = hwicap_of_register(); | ||
871 | |||
872 | if (retval) | ||
873 | goto failed2; | ||
874 | |||
875 | return retval; | ||
876 | |||
877 | failed2: | ||
878 | platform_driver_unregister(&hwicap_platform_driver); | ||
879 | |||
880 | failed1: | ||
881 | unregister_chrdev_region(devt, HWICAP_DEVICES); | ||
882 | |||
883 | return retval; | ||
884 | } | ||
885 | |||
886 | static void __devexit hwicap_module_cleanup(void) | ||
887 | { | ||
888 | dev_t devt = MKDEV(xhwicap_major, xhwicap_minor); | ||
889 | |||
890 | class_destroy(icap_class); | ||
891 | |||
892 | platform_driver_unregister(&hwicap_platform_driver); | ||
893 | |||
894 | hwicap_of_unregister(); | ||
895 | |||
896 | unregister_chrdev_region(devt, HWICAP_DEVICES); | ||
897 | } | ||
898 | |||
899 | module_init(hwicap_module_init); | ||
900 | module_exit(hwicap_module_cleanup); | ||
901 | |||
902 | MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group"); | ||
903 | MODULE_DESCRIPTION("Xilinx ICAP Port Driver"); | ||
904 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h new file mode 100644 index 000000000000..ae771cac1629 --- /dev/null +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h | |||
@@ -0,0 +1,193 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Author: Xilinx, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" | ||
11 | * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND | ||
12 | * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, | ||
13 | * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, | ||
14 | * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION | ||
15 | * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, | ||
16 | * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE | ||
17 | * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY | ||
18 | * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE | ||
19 | * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR | ||
20 | * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF | ||
21 | * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
22 | * FOR A PARTICULAR PURPOSE. | ||
23 | * | ||
24 | * Xilinx products are not intended for use in life support appliances, | ||
25 | * devices, or systems. Use in such applications is expressly prohibited. | ||
26 | * | ||
27 | * (c) Copyright 2003-2007 Xilinx Inc. | ||
28 | * All rights reserved. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License along | ||
31 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | *****************************************************************************/ | ||
35 | |||
36 | #ifndef XILINX_HWICAP_H_ /* prevent circular inclusions */ | ||
37 | #define XILINX_HWICAP_H_ /* by using protection macros */ | ||
38 | |||
39 | #include <linux/types.h> | ||
40 | #include <linux/cdev.h> | ||
41 | #include <linux/version.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | |||
46 | struct hwicap_drvdata { | ||
47 | u32 write_buffer_in_use; /* Always in [0,3] */ | ||
48 | u8 write_buffer[4]; | ||
49 | u32 read_buffer_in_use; /* Always in [0,3] */ | ||
50 | u8 read_buffer[4]; | ||
51 | u32 mem_start; /* phys. address of the control registers */ | ||
52 | u32 mem_end; /* phys. address of the control registers */ | ||
53 | u32 mem_size; | ||
54 | void __iomem *base_address;/* virt. address of the control registers */ | ||
55 | |||
56 | struct device *dev; | ||
57 | struct cdev cdev; /* Char device structure */ | ||
58 | dev_t devt; | ||
59 | |||
60 | const struct hwicap_driver_config *config; | ||
61 | const struct config_registers *config_regs; | ||
62 | void *private_data; | ||
63 | bool is_open; | ||
64 | struct semaphore sem; | ||
65 | }; | ||
66 | |||
67 | struct hwicap_driver_config { | ||
68 | int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data, | ||
69 | u32 size); | ||
70 | int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data, | ||
71 | u32 size); | ||
72 | void (*reset)(struct hwicap_drvdata *drvdata); | ||
73 | }; | ||
74 | |||
75 | /* Number of times to poll the done regsiter */ | ||
76 | #define XHI_MAX_RETRIES 10 | ||
77 | |||
78 | /************ Constant Definitions *************/ | ||
79 | |||
80 | #define XHI_PAD_FRAMES 0x1 | ||
81 | |||
82 | /* Mask for calculating configuration packet headers */ | ||
83 | #define XHI_WORD_COUNT_MASK_TYPE_1 0x7FFUL | ||
84 | #define XHI_WORD_COUNT_MASK_TYPE_2 0x1FFFFFUL | ||
85 | #define XHI_TYPE_MASK 0x7 | ||
86 | #define XHI_REGISTER_MASK 0xF | ||
87 | #define XHI_OP_MASK 0x3 | ||
88 | |||
89 | #define XHI_TYPE_SHIFT 29 | ||
90 | #define XHI_REGISTER_SHIFT 13 | ||
91 | #define XHI_OP_SHIFT 27 | ||
92 | |||
93 | #define XHI_TYPE_1 1 | ||
94 | #define XHI_TYPE_2 2 | ||
95 | #define XHI_OP_WRITE 2 | ||
96 | #define XHI_OP_READ 1 | ||
97 | |||
98 | /* Address Block Types */ | ||
99 | #define XHI_FAR_CLB_BLOCK 0 | ||
100 | #define XHI_FAR_BRAM_BLOCK 1 | ||
101 | #define XHI_FAR_BRAM_INT_BLOCK 2 | ||
102 | |||
103 | struct config_registers { | ||
104 | u32 CRC; | ||
105 | u32 FAR; | ||
106 | u32 FDRI; | ||
107 | u32 FDRO; | ||
108 | u32 CMD; | ||
109 | u32 CTL; | ||
110 | u32 MASK; | ||
111 | u32 STAT; | ||
112 | u32 LOUT; | ||
113 | u32 COR; | ||
114 | u32 MFWR; | ||
115 | u32 FLR; | ||
116 | u32 KEY; | ||
117 | u32 CBC; | ||
118 | u32 IDCODE; | ||
119 | u32 AXSS; | ||
120 | u32 C0R_1; | ||
121 | u32 CSOB; | ||
122 | u32 WBSTAR; | ||
123 | u32 TIMER; | ||
124 | u32 BOOTSTS; | ||
125 | u32 CTL_1; | ||
126 | }; | ||
127 | |||
128 | /* Configuration Commands */ | ||
129 | #define XHI_CMD_NULL 0 | ||
130 | #define XHI_CMD_WCFG 1 | ||
131 | #define XHI_CMD_MFW 2 | ||
132 | #define XHI_CMD_DGHIGH 3 | ||
133 | #define XHI_CMD_RCFG 4 | ||
134 | #define XHI_CMD_START 5 | ||
135 | #define XHI_CMD_RCAP 6 | ||
136 | #define XHI_CMD_RCRC 7 | ||
137 | #define XHI_CMD_AGHIGH 8 | ||
138 | #define XHI_CMD_SWITCH 9 | ||
139 | #define XHI_CMD_GRESTORE 10 | ||
140 | #define XHI_CMD_SHUTDOWN 11 | ||
141 | #define XHI_CMD_GCAPTURE 12 | ||
142 | #define XHI_CMD_DESYNCH 13 | ||
143 | #define XHI_CMD_IPROG 15 /* Only in Virtex5 */ | ||
144 | #define XHI_CMD_CRCC 16 /* Only in Virtex5 */ | ||
145 | #define XHI_CMD_LTIMER 17 /* Only in Virtex5 */ | ||
146 | |||
147 | /* Packet constants */ | ||
148 | #define XHI_SYNC_PACKET 0xAA995566UL | ||
149 | #define XHI_DUMMY_PACKET 0xFFFFFFFFUL | ||
150 | #define XHI_NOOP_PACKET (XHI_TYPE_1 << XHI_TYPE_SHIFT) | ||
151 | #define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \ | ||
152 | (XHI_OP_READ << XHI_OP_SHIFT)) | ||
153 | |||
154 | #define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \ | ||
155 | (XHI_OP_WRITE << XHI_OP_SHIFT)) | ||
156 | |||
157 | #define XHI_TYPE2_CNT_MASK 0x07FFFFFF | ||
158 | |||
159 | #define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL | ||
160 | #define XHI_TYPE_1_HEADER_BYTES 4 | ||
161 | #define XHI_TYPE_2_HEADER_BYTES 8 | ||
162 | |||
163 | /* Constant to use for CRC check when CRC has been disabled */ | ||
164 | #define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL | ||
165 | |||
166 | /** | ||
167 | * hwicap_type_1_read: Generates a Type 1 read packet header. | ||
168 | * @parameter: Register is the address of the register to be read back. | ||
169 | * | ||
170 | * Generates a Type 1 read packet header, which is used to indirectly | ||
171 | * read registers in the configuration logic. This packet must then | ||
172 | * be sent through the icap device, and a return packet received with | ||
173 | * the information. | ||
174 | **/ | ||
175 | static inline u32 hwicap_type_1_read(u32 Register) | ||
176 | { | ||
177 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | | ||
178 | (Register << XHI_REGISTER_SHIFT) | | ||
179 | (XHI_OP_READ << XHI_OP_SHIFT); | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * hwicap_type_1_write: Generates a Type 1 write packet header | ||
184 | * @parameter: Register is the address of the register to be read back. | ||
185 | **/ | ||
186 | static inline u32 hwicap_type_1_write(u32 Register) | ||
187 | { | ||
188 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | | ||
189 | (Register << XHI_REGISTER_SHIFT) | | ||
190 | (XHI_OP_WRITE << XHI_OP_SHIFT); | ||
191 | } | ||
192 | |||
193 | #endif | ||
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7d170cd381c3..9cc25fd80b60 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -1737,10 +1737,8 @@ config SC92031 | |||
1737 | 1737 | ||
1738 | config CPMAC | 1738 | config CPMAC |
1739 | tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" | 1739 | tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" |
1740 | depends on NET_ETHERNET && EXPERIMENTAL && AR7 | 1740 | depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN |
1741 | select PHYLIB | 1741 | select PHYLIB |
1742 | select FIXED_PHY | ||
1743 | select FIXED_MII_100_FDX | ||
1744 | help | 1742 | help |
1745 | TI AR7 CPMAC Ethernet support | 1743 | TI AR7 CPMAC Ethernet support |
1746 | 1744 | ||
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 6ccebb830ff9..c85194f2cd2d 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c | |||
@@ -845,15 +845,6 @@ static void cpmac_adjust_link(struct net_device *dev) | |||
845 | spin_unlock(&priv->lock); | 845 | spin_unlock(&priv->lock); |
846 | } | 846 | } |
847 | 847 | ||
848 | static int cpmac_link_update(struct net_device *dev, | ||
849 | struct fixed_phy_status *status) | ||
850 | { | ||
851 | status->link = 1; | ||
852 | status->speed = 100; | ||
853 | status->duplex = 1; | ||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int cpmac_open(struct net_device *dev) | 848 | static int cpmac_open(struct net_device *dev) |
858 | { | 849 | { |
859 | int i, size, res; | 850 | int i, size, res; |
@@ -996,11 +987,11 @@ static int external_switch; | |||
996 | static int __devinit cpmac_probe(struct platform_device *pdev) | 987 | static int __devinit cpmac_probe(struct platform_device *pdev) |
997 | { | 988 | { |
998 | int rc, phy_id, i; | 989 | int rc, phy_id, i; |
990 | int mdio_bus_id = cpmac_mii.id; | ||
999 | struct resource *mem; | 991 | struct resource *mem; |
1000 | struct cpmac_priv *priv; | 992 | struct cpmac_priv *priv; |
1001 | struct net_device *dev; | 993 | struct net_device *dev; |
1002 | struct plat_cpmac_data *pdata; | 994 | struct plat_cpmac_data *pdata; |
1003 | struct fixed_info *fixed_phy; | ||
1004 | DECLARE_MAC_BUF(mac); | 995 | DECLARE_MAC_BUF(mac); |
1005 | 996 | ||
1006 | pdata = pdev->dev.platform_data; | 997 | pdata = pdev->dev.platform_data; |
@@ -1014,9 +1005,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev) | |||
1014 | } | 1005 | } |
1015 | 1006 | ||
1016 | if (phy_id == PHY_MAX_ADDR) { | 1007 | if (phy_id == PHY_MAX_ADDR) { |
1017 | if (external_switch || dumb_switch) | 1008 | if (external_switch || dumb_switch) { |
1009 | struct fixed_phy_status status = {}; | ||
1010 | |||
1011 | mdio_bus_id = 0; | ||
1012 | |||
1013 | /* | ||
1014 | * FIXME: this should be in the platform code! | ||
1015 | * Since there is not platform code at all (that is, | ||
1016 | * no mainline users of that driver), place it here | ||
1017 | * for now. | ||
1018 | */ | ||
1018 | phy_id = 0; | 1019 | phy_id = 0; |
1019 | else { | 1020 | status.link = 1; |
1021 | status.duplex = 1; | ||
1022 | status.speed = 100; | ||
1023 | fixed_phy_add(PHY_POLL, phy_id, &status); | ||
1024 | } else { | ||
1020 | printk(KERN_ERR "cpmac: no PHY present\n"); | 1025 | printk(KERN_ERR "cpmac: no PHY present\n"); |
1021 | return -ENODEV; | 1026 | return -ENODEV; |
1022 | } | 1027 | } |
@@ -1060,32 +1065,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) | |||
1060 | priv->msg_enable = netif_msg_init(debug_level, 0xff); | 1065 | priv->msg_enable = netif_msg_init(debug_level, 0xff); |
1061 | memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); | 1066 | memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); |
1062 | 1067 | ||
1063 | if (phy_id == 31) { | 1068 | snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); |
1064 | snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id, | ||
1065 | phy_id); | ||
1066 | } else { | ||
1067 | /* Let's try to get a free fixed phy... */ | ||
1068 | for (i = 0; i < MAX_PHY_AMNT; i++) { | ||
1069 | fixed_phy = fixed_mdio_get_phydev(i); | ||
1070 | if (!fixed_phy) | ||
1071 | continue; | ||
1072 | if (!fixed_phy->phydev->attached_dev) { | ||
1073 | strncpy(priv->phy_name, | ||
1074 | fixed_phy->phydev->dev.bus_id, | ||
1075 | BUS_ID_SIZE); | ||
1076 | fixed_mdio_set_link_update(fixed_phy->phydev, | ||
1077 | &cpmac_link_update); | ||
1078 | goto phy_found; | ||
1079 | } | ||
1080 | } | ||
1081 | if (netif_msg_drv(priv)) | ||
1082 | printk(KERN_ERR "%s: Could not find fixed PHY\n", | ||
1083 | dev->name); | ||
1084 | rc = -ENODEV; | ||
1085 | goto fail; | ||
1086 | } | ||
1087 | 1069 | ||
1088 | phy_found: | ||
1089 | priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0, | 1070 | priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0, |
1090 | PHY_INTERFACE_MODE_MII); | 1071 | PHY_INTERFACE_MODE_MII); |
1091 | if (IS_ERR(priv->phy)) { | 1072 | if (IS_ERR(priv->phy)) { |
diff --git a/drivers/of/base.c b/drivers/of/base.c index b306fef1ac41..80c9deca5f35 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -138,6 +138,31 @@ struct device_node *of_get_parent(const struct device_node *node) | |||
138 | EXPORT_SYMBOL(of_get_parent); | 138 | EXPORT_SYMBOL(of_get_parent); |
139 | 139 | ||
140 | /** | 140 | /** |
141 | * of_get_next_parent - Iterate to a node's parent | ||
142 | * @node: Node to get parent of | ||
143 | * | ||
144 | * This is like of_get_parent() except that it drops the | ||
145 | * refcount on the passed node, making it suitable for iterating | ||
146 | * through a node's parents. | ||
147 | * | ||
148 | * Returns a node pointer with refcount incremented, use | ||
149 | * of_node_put() on it when done. | ||
150 | */ | ||
151 | struct device_node *of_get_next_parent(struct device_node *node) | ||
152 | { | ||
153 | struct device_node *parent; | ||
154 | |||
155 | if (!node) | ||
156 | return NULL; | ||
157 | |||
158 | read_lock(&devtree_lock); | ||
159 | parent = of_node_get(node->parent); | ||
160 | of_node_put(node); | ||
161 | read_unlock(&devtree_lock); | ||
162 | return parent; | ||
163 | } | ||
164 | |||
165 | /** | ||
141 | * of_get_next_child - Iterate a node childs | 166 | * of_get_next_child - Iterate a node childs |
142 | * @node: parent node | 167 | * @node: parent node |
143 | * @prev: previous child of the parent node, or NULL to get first | 168 | * @prev: previous child of the parent node, or NULL to get first |
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index b47bb2d7476a..ca09a63a64db 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev) | |||
85 | return error; | 85 | return error; |
86 | } | 86 | } |
87 | 87 | ||
88 | static void of_platform_device_shutdown(struct device *dev) | ||
89 | { | ||
90 | struct of_device *of_dev = to_of_device(dev); | ||
91 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
92 | |||
93 | if (dev->driver && drv->shutdown) | ||
94 | drv->shutdown(of_dev); | ||
95 | } | ||
96 | |||
88 | int of_bus_type_init(struct bus_type *bus, const char *name) | 97 | int of_bus_type_init(struct bus_type *bus, const char *name) |
89 | { | 98 | { |
90 | bus->name = name; | 99 | bus->name = name; |
@@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name) | |||
93 | bus->remove = of_platform_device_remove; | 102 | bus->remove = of_platform_device_remove; |
94 | bus->suspend = of_platform_device_suspend; | 103 | bus->suspend = of_platform_device_suspend; |
95 | bus->resume = of_platform_device_resume; | 104 | bus->resume = of_platform_device_resume; |
105 | bus->shutdown = of_platform_device_shutdown; | ||
96 | return bus_register(bus); | 106 | return bus_register(bus); |
97 | } | 107 | } |
98 | 108 | ||
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 50d6e2214ddf..84a054d7e986 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -1142,17 +1142,17 @@ config SERIAL_SGI_L1_CONSOLE | |||
1142 | say Y. Otherwise, say N. | 1142 | say Y. Otherwise, say N. |
1143 | 1143 | ||
1144 | config SERIAL_MPC52xx | 1144 | config SERIAL_MPC52xx |
1145 | tristate "Freescale MPC52xx family PSC serial support" | 1145 | tristate "Freescale MPC52xx/MPC512x family PSC serial support" |
1146 | depends on PPC_MPC52xx | 1146 | depends on PPC_MPC52xx || PPC_MPC512x |
1147 | select SERIAL_CORE | 1147 | select SERIAL_CORE |
1148 | help | 1148 | help |
1149 | This drivers support the MPC52xx PSC serial ports. If you would | 1149 | This driver supports MPC52xx and MPC512x PSC serial ports. If you would |
1150 | like to use them, you must answer Y or M to this option. Not that | 1150 | like to use them, you must answer Y or M to this option. Note that |
1151 | for use as console, it must be included in kernel and not as a | 1151 | for use as console, it must be included in kernel and not as a |
1152 | module. | 1152 | module. |
1153 | 1153 | ||
1154 | config SERIAL_MPC52xx_CONSOLE | 1154 | config SERIAL_MPC52xx_CONSOLE |
1155 | bool "Console on a Freescale MPC52xx family PSC serial port" | 1155 | bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port" |
1156 | depends on SERIAL_MPC52xx=y | 1156 | depends on SERIAL_MPC52xx=y |
1157 | select SERIAL_CORE_CONSOLE | 1157 | select SERIAL_CORE_CONSOLE |
1158 | help | 1158 | help |
@@ -1160,7 +1160,7 @@ config SERIAL_MPC52xx_CONSOLE | |||
1160 | of the Freescale MPC52xx family as a console. | 1160 | of the Freescale MPC52xx family as a console. |
1161 | 1161 | ||
1162 | config SERIAL_MPC52xx_CONSOLE_BAUD | 1162 | config SERIAL_MPC52xx_CONSOLE_BAUD |
1163 | int "Freescale MPC52xx family PSC serial port baud" | 1163 | int "Freescale MPC52xx/MPC512x family PSC serial port baud" |
1164 | depends on SERIAL_MPC52xx_CONSOLE=y | 1164 | depends on SERIAL_MPC52xx_CONSOLE=y |
1165 | default "9600" | 1165 | default "9600" |
1166 | help | 1166 | help |
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 3c4d29e59b2c..a638f23c6c61 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c | |||
@@ -16,6 +16,9 @@ | |||
16 | * Some of the code has been inspired/copied from the 2.4 code written | 16 | * Some of the code has been inspired/copied from the 2.4 code written |
17 | * by Dale Farnsworth <dfarnsworth@mvista.com>. | 17 | * by Dale Farnsworth <dfarnsworth@mvista.com>. |
18 | * | 18 | * |
19 | * Copyright (C) 2008 Freescale Semiconductor Inc. | ||
20 | * John Rigby <jrigby@gmail.com> | ||
21 | * Added support for MPC5121 | ||
19 | * Copyright (C) 2006 Secret Lab Technologies Ltd. | 22 | * Copyright (C) 2006 Secret Lab Technologies Ltd. |
20 | * Grant Likely <grant.likely@secretlab.ca> | 23 | * Grant Likely <grant.likely@secretlab.ca> |
21 | * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> | 24 | * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> |
@@ -67,7 +70,6 @@ | |||
67 | #include <linux/serial.h> | 70 | #include <linux/serial.h> |
68 | #include <linux/sysrq.h> | 71 | #include <linux/sysrq.h> |
69 | #include <linux/console.h> | 72 | #include <linux/console.h> |
70 | |||
71 | #include <linux/delay.h> | 73 | #include <linux/delay.h> |
72 | #include <linux/io.h> | 74 | #include <linux/io.h> |
73 | 75 | ||
@@ -79,6 +81,7 @@ | |||
79 | #endif | 81 | #endif |
80 | 82 | ||
81 | #include <asm/mpc52xx.h> | 83 | #include <asm/mpc52xx.h> |
84 | #include <asm/mpc512x.h> | ||
82 | #include <asm/mpc52xx_psc.h> | 85 | #include <asm/mpc52xx_psc.h> |
83 | 86 | ||
84 | #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 87 | #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
@@ -111,8 +114,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; | |||
111 | static void mpc52xx_uart_of_enumerate(void); | 114 | static void mpc52xx_uart_of_enumerate(void); |
112 | #endif | 115 | #endif |
113 | 116 | ||
117 | |||
114 | #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) | 118 | #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) |
115 | #define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) | ||
116 | 119 | ||
117 | 120 | ||
118 | /* Forward declaration of the interruption handling routine */ | 121 | /* Forward declaration of the interruption handling routine */ |
@@ -128,15 +131,301 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); | |||
128 | #define uart_console(port) (0) | 131 | #define uart_console(port) (0) |
129 | #endif | 132 | #endif |
130 | 133 | ||
134 | /* ======================================================================== */ | ||
135 | /* PSC fifo operations for isolating differences between 52xx and 512x */ | ||
136 | /* ======================================================================== */ | ||
137 | |||
138 | struct psc_ops { | ||
139 | void (*fifo_init)(struct uart_port *port); | ||
140 | int (*raw_rx_rdy)(struct uart_port *port); | ||
141 | int (*raw_tx_rdy)(struct uart_port *port); | ||
142 | int (*rx_rdy)(struct uart_port *port); | ||
143 | int (*tx_rdy)(struct uart_port *port); | ||
144 | int (*tx_empty)(struct uart_port *port); | ||
145 | void (*stop_rx)(struct uart_port *port); | ||
146 | void (*start_tx)(struct uart_port *port); | ||
147 | void (*stop_tx)(struct uart_port *port); | ||
148 | void (*rx_clr_irq)(struct uart_port *port); | ||
149 | void (*tx_clr_irq)(struct uart_port *port); | ||
150 | void (*write_char)(struct uart_port *port, unsigned char c); | ||
151 | unsigned char (*read_char)(struct uart_port *port); | ||
152 | void (*cw_disable_ints)(struct uart_port *port); | ||
153 | void (*cw_restore_ints)(struct uart_port *port); | ||
154 | unsigned long (*getuartclk)(void *p); | ||
155 | }; | ||
156 | |||
157 | #ifdef CONFIG_PPC_MPC52xx | ||
158 | #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) | ||
159 | static void mpc52xx_psc_fifo_init(struct uart_port *port) | ||
160 | { | ||
161 | struct mpc52xx_psc __iomem *psc = PSC(port); | ||
162 | struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); | ||
163 | |||
164 | /* /32 prescaler */ | ||
165 | out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); | ||
166 | |||
167 | out_8(&fifo->rfcntl, 0x00); | ||
168 | out_be16(&fifo->rfalarm, 0x1ff); | ||
169 | out_8(&fifo->tfcntl, 0x07); | ||
170 | out_be16(&fifo->tfalarm, 0x80); | ||
171 | |||
172 | port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; | ||
173 | out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); | ||
174 | } | ||
175 | |||
176 | static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) | ||
177 | { | ||
178 | return in_be16(&PSC(port)->mpc52xx_psc_status) | ||
179 | & MPC52xx_PSC_SR_RXRDY; | ||
180 | } | ||
181 | |||
182 | static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) | ||
183 | { | ||
184 | return in_be16(&PSC(port)->mpc52xx_psc_status) | ||
185 | & MPC52xx_PSC_SR_TXRDY; | ||
186 | } | ||
187 | |||
188 | |||
189 | static int mpc52xx_psc_rx_rdy(struct uart_port *port) | ||
190 | { | ||
191 | return in_be16(&PSC(port)->mpc52xx_psc_isr) | ||
192 | & port->read_status_mask | ||
193 | & MPC52xx_PSC_IMR_RXRDY; | ||
194 | } | ||
195 | |||
196 | static int mpc52xx_psc_tx_rdy(struct uart_port *port) | ||
197 | { | ||
198 | return in_be16(&PSC(port)->mpc52xx_psc_isr) | ||
199 | & port->read_status_mask | ||
200 | & MPC52xx_PSC_IMR_TXRDY; | ||
201 | } | ||
202 | |||
203 | static int mpc52xx_psc_tx_empty(struct uart_port *port) | ||
204 | { | ||
205 | return in_be16(&PSC(port)->mpc52xx_psc_status) | ||
206 | & MPC52xx_PSC_SR_TXEMP; | ||
207 | } | ||
208 | |||
209 | static void mpc52xx_psc_start_tx(struct uart_port *port) | ||
210 | { | ||
211 | port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; | ||
212 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
213 | } | ||
214 | |||
215 | static void mpc52xx_psc_stop_tx(struct uart_port *port) | ||
216 | { | ||
217 | port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; | ||
218 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
219 | } | ||
220 | |||
221 | static void mpc52xx_psc_stop_rx(struct uart_port *port) | ||
222 | { | ||
223 | port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; | ||
224 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
225 | } | ||
226 | |||
227 | static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) | ||
228 | { | ||
229 | } | ||
230 | |||
231 | static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) | ||
232 | { | ||
233 | } | ||
234 | |||
235 | static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) | ||
236 | { | ||
237 | out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); | ||
238 | } | ||
239 | |||
240 | static unsigned char mpc52xx_psc_read_char(struct uart_port *port) | ||
241 | { | ||
242 | return in_8(&PSC(port)->mpc52xx_psc_buffer_8); | ||
243 | } | ||
244 | |||
245 | static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) | ||
246 | { | ||
247 | out_be16(&PSC(port)->mpc52xx_psc_imr, 0); | ||
248 | } | ||
249 | |||
250 | static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) | ||
251 | { | ||
252 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
253 | } | ||
254 | |||
255 | /* Search for bus-frequency property in this node or a parent */ | ||
256 | static unsigned long mpc52xx_getuartclk(void *p) | ||
257 | { | ||
131 | #if defined(CONFIG_PPC_MERGE) | 258 | #if defined(CONFIG_PPC_MERGE) |
132 | static struct of_device_id mpc52xx_uart_of_match[] = { | 259 | /* |
133 | { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", }, | 260 | * 5200 UARTs have a / 32 prescaler |
134 | { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */ | 261 | * but the generic serial code assumes 16 |
135 | { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */ | 262 | * so return ipb freq / 2 |
136 | {}, | 263 | */ |
264 | return mpc52xx_find_ipb_freq(p) / 2; | ||
265 | #else | ||
266 | pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n"); | ||
267 | return NULL; | ||
268 | #endif | ||
269 | } | ||
270 | |||
271 | static struct psc_ops mpc52xx_psc_ops = { | ||
272 | .fifo_init = mpc52xx_psc_fifo_init, | ||
273 | .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, | ||
274 | .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, | ||
275 | .rx_rdy = mpc52xx_psc_rx_rdy, | ||
276 | .tx_rdy = mpc52xx_psc_tx_rdy, | ||
277 | .tx_empty = mpc52xx_psc_tx_empty, | ||
278 | .stop_rx = mpc52xx_psc_stop_rx, | ||
279 | .start_tx = mpc52xx_psc_start_tx, | ||
280 | .stop_tx = mpc52xx_psc_stop_tx, | ||
281 | .rx_clr_irq = mpc52xx_psc_rx_clr_irq, | ||
282 | .tx_clr_irq = mpc52xx_psc_tx_clr_irq, | ||
283 | .write_char = mpc52xx_psc_write_char, | ||
284 | .read_char = mpc52xx_psc_read_char, | ||
285 | .cw_disable_ints = mpc52xx_psc_cw_disable_ints, | ||
286 | .cw_restore_ints = mpc52xx_psc_cw_restore_ints, | ||
287 | .getuartclk = mpc52xx_getuartclk, | ||
288 | }; | ||
289 | |||
290 | #endif /* CONFIG_MPC52xx */ | ||
291 | |||
292 | #ifdef CONFIG_PPC_MPC512x | ||
293 | #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) | ||
294 | static void mpc512x_psc_fifo_init(struct uart_port *port) | ||
295 | { | ||
296 | out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); | ||
297 | out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); | ||
298 | out_be32(&FIFO_512x(port)->txalarm, 1); | ||
299 | out_be32(&FIFO_512x(port)->tximr, 0); | ||
300 | |||
301 | out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); | ||
302 | out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); | ||
303 | out_be32(&FIFO_512x(port)->rxalarm, 1); | ||
304 | out_be32(&FIFO_512x(port)->rximr, 0); | ||
305 | |||
306 | out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); | ||
307 | out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); | ||
308 | } | ||
309 | |||
310 | static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) | ||
311 | { | ||
312 | return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); | ||
313 | } | ||
314 | |||
315 | static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) | ||
316 | { | ||
317 | return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); | ||
318 | } | ||
319 | |||
320 | static int mpc512x_psc_rx_rdy(struct uart_port *port) | ||
321 | { | ||
322 | return in_be32(&FIFO_512x(port)->rxsr) | ||
323 | & in_be32(&FIFO_512x(port)->rximr) | ||
324 | & MPC512x_PSC_FIFO_ALARM; | ||
325 | } | ||
326 | |||
327 | static int mpc512x_psc_tx_rdy(struct uart_port *port) | ||
328 | { | ||
329 | return in_be32(&FIFO_512x(port)->txsr) | ||
330 | & in_be32(&FIFO_512x(port)->tximr) | ||
331 | & MPC512x_PSC_FIFO_ALARM; | ||
332 | } | ||
333 | |||
334 | static int mpc512x_psc_tx_empty(struct uart_port *port) | ||
335 | { | ||
336 | return in_be32(&FIFO_512x(port)->txsr) | ||
337 | & MPC512x_PSC_FIFO_EMPTY; | ||
338 | } | ||
339 | |||
340 | static void mpc512x_psc_stop_rx(struct uart_port *port) | ||
341 | { | ||
342 | unsigned long rx_fifo_imr; | ||
343 | |||
344 | rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); | ||
345 | rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; | ||
346 | out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); | ||
347 | } | ||
348 | |||
349 | static void mpc512x_psc_start_tx(struct uart_port *port) | ||
350 | { | ||
351 | unsigned long tx_fifo_imr; | ||
352 | |||
353 | tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); | ||
354 | tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; | ||
355 | out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); | ||
356 | } | ||
357 | |||
358 | static void mpc512x_psc_stop_tx(struct uart_port *port) | ||
359 | { | ||
360 | unsigned long tx_fifo_imr; | ||
361 | |||
362 | tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); | ||
363 | tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; | ||
364 | out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); | ||
365 | } | ||
366 | |||
367 | static void mpc512x_psc_rx_clr_irq(struct uart_port *port) | ||
368 | { | ||
369 | out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); | ||
370 | } | ||
371 | |||
372 | static void mpc512x_psc_tx_clr_irq(struct uart_port *port) | ||
373 | { | ||
374 | out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); | ||
375 | } | ||
376 | |||
377 | static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) | ||
378 | { | ||
379 | out_8(&FIFO_512x(port)->txdata_8, c); | ||
380 | } | ||
381 | |||
382 | static unsigned char mpc512x_psc_read_char(struct uart_port *port) | ||
383 | { | ||
384 | return in_8(&FIFO_512x(port)->rxdata_8); | ||
385 | } | ||
386 | |||
387 | static void mpc512x_psc_cw_disable_ints(struct uart_port *port) | ||
388 | { | ||
389 | port->read_status_mask = | ||
390 | in_be32(&FIFO_512x(port)->tximr) << 16 | | ||
391 | in_be32(&FIFO_512x(port)->rximr); | ||
392 | out_be32(&FIFO_512x(port)->tximr, 0); | ||
393 | out_be32(&FIFO_512x(port)->rximr, 0); | ||
394 | } | ||
395 | |||
396 | static void mpc512x_psc_cw_restore_ints(struct uart_port *port) | ||
397 | { | ||
398 | out_be32(&FIFO_512x(port)->tximr, | ||
399 | (port->read_status_mask >> 16) & 0x7f); | ||
400 | out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); | ||
401 | } | ||
402 | |||
403 | static unsigned long mpc512x_getuartclk(void *p) | ||
404 | { | ||
405 | return mpc512x_find_ips_freq(p); | ||
406 | } | ||
407 | |||
408 | static struct psc_ops mpc512x_psc_ops = { | ||
409 | .fifo_init = mpc512x_psc_fifo_init, | ||
410 | .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, | ||
411 | .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, | ||
412 | .rx_rdy = mpc512x_psc_rx_rdy, | ||
413 | .tx_rdy = mpc512x_psc_tx_rdy, | ||
414 | .tx_empty = mpc512x_psc_tx_empty, | ||
415 | .stop_rx = mpc512x_psc_stop_rx, | ||
416 | .start_tx = mpc512x_psc_start_tx, | ||
417 | .stop_tx = mpc512x_psc_stop_tx, | ||
418 | .rx_clr_irq = mpc512x_psc_rx_clr_irq, | ||
419 | .tx_clr_irq = mpc512x_psc_tx_clr_irq, | ||
420 | .write_char = mpc512x_psc_write_char, | ||
421 | .read_char = mpc512x_psc_read_char, | ||
422 | .cw_disable_ints = mpc512x_psc_cw_disable_ints, | ||
423 | .cw_restore_ints = mpc512x_psc_cw_restore_ints, | ||
424 | .getuartclk = mpc512x_getuartclk, | ||
137 | }; | 425 | }; |
138 | #endif | 426 | #endif |
139 | 427 | ||
428 | static struct psc_ops *psc_ops; | ||
140 | 429 | ||
141 | /* ======================================================================== */ | 430 | /* ======================================================================== */ |
142 | /* UART operations */ | 431 | /* UART operations */ |
@@ -145,8 +434,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { | |||
145 | static unsigned int | 434 | static unsigned int |
146 | mpc52xx_uart_tx_empty(struct uart_port *port) | 435 | mpc52xx_uart_tx_empty(struct uart_port *port) |
147 | { | 436 | { |
148 | int status = in_be16(&PSC(port)->mpc52xx_psc_status); | 437 | return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; |
149 | return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; | ||
150 | } | 438 | } |
151 | 439 | ||
152 | static void | 440 | static void |
@@ -166,16 +454,14 @@ static void | |||
166 | mpc52xx_uart_stop_tx(struct uart_port *port) | 454 | mpc52xx_uart_stop_tx(struct uart_port *port) |
167 | { | 455 | { |
168 | /* port->lock taken by caller */ | 456 | /* port->lock taken by caller */ |
169 | port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; | 457 | psc_ops->stop_tx(port); |
170 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
171 | } | 458 | } |
172 | 459 | ||
173 | static void | 460 | static void |
174 | mpc52xx_uart_start_tx(struct uart_port *port) | 461 | mpc52xx_uart_start_tx(struct uart_port *port) |
175 | { | 462 | { |
176 | /* port->lock taken by caller */ | 463 | /* port->lock taken by caller */ |
177 | port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; | 464 | psc_ops->start_tx(port); |
178 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
179 | } | 465 | } |
180 | 466 | ||
181 | static void | 467 | static void |
@@ -188,8 +474,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch) | |||
188 | if (ch) { | 474 | if (ch) { |
189 | /* Make sure tx interrupts are on */ | 475 | /* Make sure tx interrupts are on */ |
190 | /* Truly necessary ??? They should be anyway */ | 476 | /* Truly necessary ??? They should be anyway */ |
191 | port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; | 477 | psc_ops->start_tx(port); |
192 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
193 | } | 478 | } |
194 | 479 | ||
195 | spin_unlock_irqrestore(&port->lock, flags); | 480 | spin_unlock_irqrestore(&port->lock, flags); |
@@ -199,8 +484,7 @@ static void | |||
199 | mpc52xx_uart_stop_rx(struct uart_port *port) | 484 | mpc52xx_uart_stop_rx(struct uart_port *port) |
200 | { | 485 | { |
201 | /* port->lock taken by caller */ | 486 | /* port->lock taken by caller */ |
202 | port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; | 487 | psc_ops->stop_rx(port); |
203 | out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); | ||
204 | } | 488 | } |
205 | 489 | ||
206 | static void | 490 | static void |
@@ -227,12 +511,12 @@ static int | |||
227 | mpc52xx_uart_startup(struct uart_port *port) | 511 | mpc52xx_uart_startup(struct uart_port *port) |
228 | { | 512 | { |
229 | struct mpc52xx_psc __iomem *psc = PSC(port); | 513 | struct mpc52xx_psc __iomem *psc = PSC(port); |
230 | struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port); | ||
231 | int ret; | 514 | int ret; |
232 | 515 | ||
233 | /* Request IRQ */ | 516 | /* Request IRQ */ |
234 | ret = request_irq(port->irq, mpc52xx_uart_int, | 517 | ret = request_irq(port->irq, mpc52xx_uart_int, |
235 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port); | 518 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED, |
519 | "mpc52xx_psc_uart", port); | ||
236 | if (ret) | 520 | if (ret) |
237 | return ret; | 521 | return ret; |
238 | 522 | ||
@@ -242,15 +526,7 @@ mpc52xx_uart_startup(struct uart_port *port) | |||
242 | 526 | ||
243 | out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ | 527 | out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ |
244 | 528 | ||
245 | out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ | 529 | psc_ops->fifo_init(port); |
246 | |||
247 | out_8(&fifo->rfcntl, 0x00); | ||
248 | out_be16(&fifo->rfalarm, 0x1ff); | ||
249 | out_8(&fifo->tfcntl, 0x07); | ||
250 | out_be16(&fifo->tfalarm, 0x80); | ||
251 | |||
252 | port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; | ||
253 | out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); | ||
254 | 530 | ||
255 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); | 531 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); |
256 | out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); | 532 | out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); |
@@ -333,8 +609,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, | |||
333 | * boot for the console, all stuff is not yet ready to receive at that | 609 | * boot for the console, all stuff is not yet ready to receive at that |
334 | * time and that just makes the kernel oops */ | 610 | * time and that just makes the kernel oops */ |
335 | /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ | 611 | /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ |
336 | while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && | 612 | while (!mpc52xx_uart_tx_empty(port) && --j) |
337 | --j) | ||
338 | udelay(1); | 613 | udelay(1); |
339 | 614 | ||
340 | if (!j) | 615 | if (!j) |
@@ -462,11 +737,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) | |||
462 | unsigned short status; | 737 | unsigned short status; |
463 | 738 | ||
464 | /* While we can read, do so ! */ | 739 | /* While we can read, do so ! */ |
465 | while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) & | 740 | while (psc_ops->raw_rx_rdy(port)) { |
466 | MPC52xx_PSC_SR_RXRDY) { | ||
467 | |||
468 | /* Get the char */ | 741 | /* Get the char */ |
469 | ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8); | 742 | ch = psc_ops->read_char(port); |
470 | 743 | ||
471 | /* Handle sysreq char */ | 744 | /* Handle sysreq char */ |
472 | #ifdef SUPPORT_SYSRQ | 745 | #ifdef SUPPORT_SYSRQ |
@@ -481,6 +754,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) | |||
481 | flag = TTY_NORMAL; | 754 | flag = TTY_NORMAL; |
482 | port->icount.rx++; | 755 | port->icount.rx++; |
483 | 756 | ||
757 | status = in_be16(&PSC(port)->mpc52xx_psc_status); | ||
758 | |||
484 | if (status & (MPC52xx_PSC_SR_PE | | 759 | if (status & (MPC52xx_PSC_SR_PE | |
485 | MPC52xx_PSC_SR_FE | | 760 | MPC52xx_PSC_SR_FE | |
486 | MPC52xx_PSC_SR_RB)) { | 761 | MPC52xx_PSC_SR_RB)) { |
@@ -510,7 +785,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) | |||
510 | 785 | ||
511 | tty_flip_buffer_push(tty); | 786 | tty_flip_buffer_push(tty); |
512 | 787 | ||
513 | return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; | 788 | return psc_ops->raw_rx_rdy(port); |
514 | } | 789 | } |
515 | 790 | ||
516 | static inline int | 791 | static inline int |
@@ -520,7 +795,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) | |||
520 | 795 | ||
521 | /* Process out of band chars */ | 796 | /* Process out of band chars */ |
522 | if (port->x_char) { | 797 | if (port->x_char) { |
523 | out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char); | 798 | psc_ops->write_char(port, port->x_char); |
524 | port->icount.tx++; | 799 | port->icount.tx++; |
525 | port->x_char = 0; | 800 | port->x_char = 0; |
526 | return 1; | 801 | return 1; |
@@ -533,8 +808,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) | |||
533 | } | 808 | } |
534 | 809 | ||
535 | /* Send chars */ | 810 | /* Send chars */ |
536 | while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) { | 811 | while (psc_ops->raw_tx_rdy(port)) { |
537 | out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]); | 812 | psc_ops->write_char(port, xmit->buf[xmit->tail]); |
538 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 813 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
539 | port->icount.tx++; | 814 | port->icount.tx++; |
540 | if (uart_circ_empty(xmit)) | 815 | if (uart_circ_empty(xmit)) |
@@ -560,7 +835,6 @@ mpc52xx_uart_int(int irq, void *dev_id) | |||
560 | struct uart_port *port = dev_id; | 835 | struct uart_port *port = dev_id; |
561 | unsigned long pass = ISR_PASS_LIMIT; | 836 | unsigned long pass = ISR_PASS_LIMIT; |
562 | unsigned int keepgoing; | 837 | unsigned int keepgoing; |
563 | unsigned short status; | ||
564 | 838 | ||
565 | spin_lock(&port->lock); | 839 | spin_lock(&port->lock); |
566 | 840 | ||
@@ -569,18 +843,12 @@ mpc52xx_uart_int(int irq, void *dev_id) | |||
569 | /* If we don't find anything to do, we stop */ | 843 | /* If we don't find anything to do, we stop */ |
570 | keepgoing = 0; | 844 | keepgoing = 0; |
571 | 845 | ||
572 | /* Read status */ | 846 | psc_ops->rx_clr_irq(port); |
573 | status = in_be16(&PSC(port)->mpc52xx_psc_isr); | 847 | if (psc_ops->rx_rdy(port)) |
574 | status &= port->read_status_mask; | ||
575 | |||
576 | /* Do we need to receive chars ? */ | ||
577 | /* For this RX interrupts must be on and some chars waiting */ | ||
578 | if (status & MPC52xx_PSC_IMR_RXRDY) | ||
579 | keepgoing |= mpc52xx_uart_int_rx_chars(port); | 848 | keepgoing |= mpc52xx_uart_int_rx_chars(port); |
580 | 849 | ||
581 | /* Do we need to send chars ? */ | 850 | psc_ops->tx_clr_irq(port); |
582 | /* For this, TX must be ready and TX interrupt enabled */ | 851 | if (psc_ops->tx_rdy(port)) |
583 | if (status & MPC52xx_PSC_IMR_TXRDY) | ||
584 | keepgoing |= mpc52xx_uart_int_tx_chars(port); | 852 | keepgoing |= mpc52xx_uart_int_tx_chars(port); |
585 | 853 | ||
586 | /* Limit number of iteration */ | 854 | /* Limit number of iteration */ |
@@ -647,36 +915,33 @@ static void | |||
647 | mpc52xx_console_write(struct console *co, const char *s, unsigned int count) | 915 | mpc52xx_console_write(struct console *co, const char *s, unsigned int count) |
648 | { | 916 | { |
649 | struct uart_port *port = &mpc52xx_uart_ports[co->index]; | 917 | struct uart_port *port = &mpc52xx_uart_ports[co->index]; |
650 | struct mpc52xx_psc __iomem *psc = PSC(port); | ||
651 | unsigned int i, j; | 918 | unsigned int i, j; |
652 | 919 | ||
653 | /* Disable interrupts */ | 920 | /* Disable interrupts */ |
654 | out_be16(&psc->mpc52xx_psc_imr, 0); | 921 | psc_ops->cw_disable_ints(port); |
655 | 922 | ||
656 | /* Wait the TX buffer to be empty */ | 923 | /* Wait the TX buffer to be empty */ |
657 | j = 5000000; /* Maximum wait */ | 924 | j = 5000000; /* Maximum wait */ |
658 | while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && | 925 | while (!mpc52xx_uart_tx_empty(port) && --j) |
659 | --j) | ||
660 | udelay(1); | 926 | udelay(1); |
661 | 927 | ||
662 | /* Write all the chars */ | 928 | /* Write all the chars */ |
663 | for (i = 0; i < count; i++, s++) { | 929 | for (i = 0; i < count; i++, s++) { |
664 | /* Line return handling */ | 930 | /* Line return handling */ |
665 | if (*s == '\n') | 931 | if (*s == '\n') |
666 | out_8(&psc->mpc52xx_psc_buffer_8, '\r'); | 932 | psc_ops->write_char(port, '\r'); |
667 | 933 | ||
668 | /* Send the char */ | 934 | /* Send the char */ |
669 | out_8(&psc->mpc52xx_psc_buffer_8, *s); | 935 | psc_ops->write_char(port, *s); |
670 | 936 | ||
671 | /* Wait the TX buffer to be empty */ | 937 | /* Wait the TX buffer to be empty */ |
672 | j = 20000; /* Maximum wait */ | 938 | j = 20000; /* Maximum wait */ |
673 | while (!(in_be16(&psc->mpc52xx_psc_status) & | 939 | while (!mpc52xx_uart_tx_empty(port) && --j) |
674 | MPC52xx_PSC_SR_TXEMP) && --j) | ||
675 | udelay(1); | 940 | udelay(1); |
676 | } | 941 | } |
677 | 942 | ||
678 | /* Restore interrupt state */ | 943 | /* Restore interrupt state */ |
679 | out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); | 944 | psc_ops->cw_restore_ints(port); |
680 | } | 945 | } |
681 | 946 | ||
682 | #if !defined(CONFIG_PPC_MERGE) | 947 | #if !defined(CONFIG_PPC_MERGE) |
@@ -721,7 +986,7 @@ mpc52xx_console_setup(struct console *co, char *options) | |||
721 | { | 986 | { |
722 | struct uart_port *port = &mpc52xx_uart_ports[co->index]; | 987 | struct uart_port *port = &mpc52xx_uart_ports[co->index]; |
723 | struct device_node *np = mpc52xx_uart_nodes[co->index]; | 988 | struct device_node *np = mpc52xx_uart_nodes[co->index]; |
724 | unsigned int ipb_freq; | 989 | unsigned int uartclk; |
725 | struct resource res; | 990 | struct resource res; |
726 | int ret; | 991 | int ret; |
727 | 992 | ||
@@ -753,17 +1018,16 @@ mpc52xx_console_setup(struct console *co, char *options) | |||
753 | return ret; | 1018 | return ret; |
754 | } | 1019 | } |
755 | 1020 | ||
756 | /* Search for bus-frequency property in this node or a parent */ | 1021 | uartclk = psc_ops->getuartclk(np); |
757 | ipb_freq = mpc52xx_find_ipb_freq(np); | 1022 | if (uartclk == 0) { |
758 | if (ipb_freq == 0) { | 1023 | pr_debug("Could not find uart clock frequency!\n"); |
759 | pr_debug("Could not find IPB bus frequency!\n"); | ||
760 | return -EINVAL; | 1024 | return -EINVAL; |
761 | } | 1025 | } |
762 | 1026 | ||
763 | /* Basic port init. Needed since we use some uart_??? func before | 1027 | /* Basic port init. Needed since we use some uart_??? func before |
764 | * real init for early access */ | 1028 | * real init for early access */ |
765 | spin_lock_init(&port->lock); | 1029 | spin_lock_init(&port->lock); |
766 | port->uartclk = ipb_freq / 2; | 1030 | port->uartclk = uartclk; |
767 | port->ops = &mpc52xx_uart_ops; | 1031 | port->ops = &mpc52xx_uart_ops; |
768 | port->mapbase = res.start; | 1032 | port->mapbase = res.start; |
769 | port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); | 1033 | port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); |
@@ -945,11 +1209,25 @@ static struct platform_driver mpc52xx_uart_platform_driver = { | |||
945 | /* OF Platform Driver */ | 1209 | /* OF Platform Driver */ |
946 | /* ======================================================================== */ | 1210 | /* ======================================================================== */ |
947 | 1211 | ||
1212 | static struct of_device_id mpc52xx_uart_of_match[] = { | ||
1213 | #ifdef CONFIG_PPC_MPC52xx | ||
1214 | { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, | ||
1215 | /* binding used by old lite5200 device trees: */ | ||
1216 | { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, | ||
1217 | /* binding used by efika: */ | ||
1218 | { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, | ||
1219 | #endif | ||
1220 | #ifdef CONFIG_PPC_MPC512x | ||
1221 | { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, | ||
1222 | {}, | ||
1223 | #endif | ||
1224 | }; | ||
1225 | |||
948 | static int __devinit | 1226 | static int __devinit |
949 | mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) | 1227 | mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) |
950 | { | 1228 | { |
951 | int idx = -1; | 1229 | int idx = -1; |
952 | unsigned int ipb_freq; | 1230 | unsigned int uartclk; |
953 | struct uart_port *port = NULL; | 1231 | struct uart_port *port = NULL; |
954 | struct resource res; | 1232 | struct resource res; |
955 | int ret; | 1233 | int ret; |
@@ -965,10 +1243,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) | |||
965 | pr_debug("Found %s assigned to ttyPSC%x\n", | 1243 | pr_debug("Found %s assigned to ttyPSC%x\n", |
966 | mpc52xx_uart_nodes[idx]->full_name, idx); | 1244 | mpc52xx_uart_nodes[idx]->full_name, idx); |
967 | 1245 | ||
968 | /* Search for bus-frequency property in this node or a parent */ | 1246 | uartclk = psc_ops->getuartclk(op->node); |
969 | ipb_freq = mpc52xx_find_ipb_freq(op->node); | 1247 | if (uartclk == 0) { |
970 | if (ipb_freq == 0) { | 1248 | dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); |
971 | dev_dbg(&op->dev, "Could not find IPB bus frequency!\n"); | ||
972 | return -EINVAL; | 1249 | return -EINVAL; |
973 | } | 1250 | } |
974 | 1251 | ||
@@ -976,7 +1253,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) | |||
976 | port = &mpc52xx_uart_ports[idx]; | 1253 | port = &mpc52xx_uart_ports[idx]; |
977 | 1254 | ||
978 | spin_lock_init(&port->lock); | 1255 | spin_lock_init(&port->lock); |
979 | port->uartclk = ipb_freq / 2; | 1256 | port->uartclk = uartclk; |
980 | port->fifosize = 512; | 1257 | port->fifosize = 512; |
981 | port->iotype = UPIO_MEM; | 1258 | port->iotype = UPIO_MEM; |
982 | port->flags = UPF_BOOT_AUTOCONF | | 1259 | port->flags = UPF_BOOT_AUTOCONF | |
@@ -1080,15 +1357,19 @@ mpc52xx_uart_of_enumerate(void) | |||
1080 | static int enum_done; | 1357 | static int enum_done; |
1081 | struct device_node *np; | 1358 | struct device_node *np; |
1082 | const unsigned int *devno; | 1359 | const unsigned int *devno; |
1360 | const struct of_device_id *match; | ||
1083 | int i; | 1361 | int i; |
1084 | 1362 | ||
1085 | if (enum_done) | 1363 | if (enum_done) |
1086 | return; | 1364 | return; |
1087 | 1365 | ||
1088 | for_each_node_by_type(np, "serial") { | 1366 | for_each_node_by_type(np, "serial") { |
1089 | if (!of_match_node(mpc52xx_uart_of_match, np)) | 1367 | match = of_match_node(mpc52xx_uart_of_match, np); |
1368 | if (!match) | ||
1090 | continue; | 1369 | continue; |
1091 | 1370 | ||
1371 | psc_ops = match->data; | ||
1372 | |||
1092 | /* Is a particular device number requested? */ | 1373 | /* Is a particular device number requested? */ |
1093 | devno = of_get_property(np, "port-number", NULL); | 1374 | devno = of_get_property(np, "port-number", NULL); |
1094 | mpc52xx_uart_of_assign(np, devno ? *devno : -1); | 1375 | mpc52xx_uart_of_assign(np, devno ? *devno : -1); |
@@ -1149,6 +1430,7 @@ mpc52xx_uart_init(void) | |||
1149 | return ret; | 1430 | return ret; |
1150 | } | 1431 | } |
1151 | #else | 1432 | #else |
1433 | psc_ops = &mpc52xx_psc_ops; | ||
1152 | ret = platform_driver_register(&mpc52xx_uart_platform_driver); | 1434 | ret = platform_driver_register(&mpc52xx_uart_platform_driver); |
1153 | if (ret) { | 1435 | if (ret) { |
1154 | printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", | 1436 | printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", |
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index bacf68dca01a..4e06ab6bcb6e 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c | |||
@@ -17,10 +17,21 @@ | |||
17 | #include <linux/tty.h> | 17 | #include <linux/tty.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/init.h> | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | #if defined(CONFIG_OF) | 22 | #if defined(CONFIG_OF) |
23 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
23 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
26 | |||
27 | /* Match table for of_platform binding */ | ||
28 | static struct of_device_id ulite_of_match[] __devinitdata = { | ||
29 | { .compatible = "xlnx,opb-uartlite-1.00.b", }, | ||
30 | { .compatible = "xlnx,xps-uartlite-1.00.a", }, | ||
31 | {} | ||
32 | }; | ||
33 | MODULE_DEVICE_TABLE(of, ulite_of_match); | ||
34 | |||
24 | #endif | 35 | #endif |
25 | 36 | ||
26 | #define ULITE_NAME "ttyUL" | 37 | #define ULITE_NAME "ttyUL" |
@@ -275,6 +286,9 @@ static void ulite_release_port(struct uart_port *port) | |||
275 | 286 | ||
276 | static int ulite_request_port(struct uart_port *port) | 287 | static int ulite_request_port(struct uart_port *port) |
277 | { | 288 | { |
289 | pr_debug("ulite console: port=%p; port->mapbase=%x\n", | ||
290 | port, port->mapbase); | ||
291 | |||
278 | if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) { | 292 | if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) { |
279 | dev_err(port->dev, "Memory region busy\n"); | 293 | dev_err(port->dev, "Memory region busy\n"); |
280 | return -EBUSY; | 294 | return -EBUSY; |
@@ -375,32 +389,6 @@ static void ulite_console_write(struct console *co, const char *s, | |||
375 | spin_unlock_irqrestore(&port->lock, flags); | 389 | spin_unlock_irqrestore(&port->lock, flags); |
376 | } | 390 | } |
377 | 391 | ||
378 | #if defined(CONFIG_OF) | ||
379 | static inline void __init ulite_console_of_find_device(int id) | ||
380 | { | ||
381 | struct device_node *np; | ||
382 | struct resource res; | ||
383 | const unsigned int *of_id; | ||
384 | int rc; | ||
385 | |||
386 | for_each_compatible_node(np, NULL, "xilinx,uartlite") { | ||
387 | of_id = of_get_property(np, "port-number", NULL); | ||
388 | if ((!of_id) || (*of_id != id)) | ||
389 | continue; | ||
390 | |||
391 | rc = of_address_to_resource(np, 0, &res); | ||
392 | if (rc) | ||
393 | continue; | ||
394 | |||
395 | ulite_ports[id].mapbase = res.start; | ||
396 | of_node_put(np); | ||
397 | return; | ||
398 | } | ||
399 | } | ||
400 | #else /* CONFIG_OF */ | ||
401 | static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ } | ||
402 | #endif /* CONFIG_OF */ | ||
403 | |||
404 | static int __init ulite_console_setup(struct console *co, char *options) | 392 | static int __init ulite_console_setup(struct console *co, char *options) |
405 | { | 393 | { |
406 | struct uart_port *port; | 394 | struct uart_port *port; |
@@ -414,11 +402,7 @@ static int __init ulite_console_setup(struct console *co, char *options) | |||
414 | 402 | ||
415 | port = &ulite_ports[co->index]; | 403 | port = &ulite_ports[co->index]; |
416 | 404 | ||
417 | /* Check if it is an OF device */ | 405 | /* Has the device been initialized yet? */ |
418 | if (!port->mapbase) | ||
419 | ulite_console_of_find_device(co->index); | ||
420 | |||
421 | /* Do we have a device now? */ | ||
422 | if (!port->mapbase) { | 406 | if (!port->mapbase) { |
423 | pr_debug("console on ttyUL%i not present\n", co->index); | 407 | pr_debug("console on ttyUL%i not present\n", co->index); |
424 | return -ENODEV; | 408 | return -ENODEV; |
@@ -617,13 +601,6 @@ static int __devexit ulite_of_remove(struct of_device *op) | |||
617 | return ulite_release(&op->dev); | 601 | return ulite_release(&op->dev); |
618 | } | 602 | } |
619 | 603 | ||
620 | /* Match table for of_platform binding */ | ||
621 | static struct of_device_id __devinit ulite_of_match[] = { | ||
622 | { .type = "serial", .compatible = "xilinx,uartlite", }, | ||
623 | {}, | ||
624 | }; | ||
625 | MODULE_DEVICE_TABLE(of, ulite_of_match); | ||
626 | |||
627 | static struct of_platform_driver ulite_of_driver = { | 604 | static struct of_platform_driver ulite_of_driver = { |
628 | .owner = THIS_MODULE, | 605 | .owner = THIS_MODULE, |
629 | .name = "uartlite", | 606 | .name = "uartlite", |
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e38d3b7c3ad7..7b3a8423f485 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c | |||
@@ -459,8 +459,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op) | |||
459 | } | 459 | } |
460 | 460 | ||
461 | /* Match table for of_platform binding */ | 461 | /* Match table for of_platform binding */ |
462 | static struct of_device_id __devinit xilinxfb_of_match[] = { | 462 | static struct of_device_id xilinxfb_of_match[] __devinitdata = { |
463 | { .compatible = "xilinx,ml300-fb", }, | 463 | { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", }, |
464 | {}, | 464 | {}, |
465 | }; | 465 | }; |
466 | MODULE_DEVICE_TABLE(of, xilinxfb_of_match); | 466 | MODULE_DEVICE_TABLE(of, xilinxfb_of_match); |