| 
									
										
										
										
											2012-05-30 21:02:49 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This file is subject to the terms and conditions of the GNU General Public | 
					
						
							|  |  |  |  * License.  See the file "COPYING" in the main directory of this archive | 
					
						
							|  |  |  |  * for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/spinlock.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PIC32_NULL	0x00
 | 
					
						
							|  |  |  | #define PIC32_RD	0x01
 | 
					
						
							|  |  |  | #define PIC32_SYSRD	0x02
 | 
					
						
							|  |  |  | #define PIC32_WR	0x10
 | 
					
						
							|  |  |  | #define PIC32_SYSWR	0x20
 | 
					
						
							| 
									
										
										
										
											2013-01-22 12:59:30 +01:00
										 |  |  | #define PIC32_IRQ_CLR	0x40
 | 
					
						
							| 
									
										
										
										
											2012-05-30 21:02:49 +00:00
										 |  |  | #define PIC32_STATUS	0x80
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-22 12:59:30 +01:00
										 |  |  | #define DELAY() udelay(100)	/* FIXME: needed? */
 | 
					
						
							| 
									
										
										
										
											2012-05-30 21:02:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* spinlock to ensure atomic access to PIC32 */ | 
					
						
							|  |  |  | static DEFINE_SPINLOCK(pic32_bus_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* FIXME: io_remap these */ | 
					
						
							| 
									
										
										
										
											2013-01-22 12:59:30 +01:00
										 |  |  | static void __iomem *bus_xfer	= (void __iomem *)0xbf000600; | 
					
						
							| 
									
										
										
										
											2012-05-30 21:02:49 +00:00
										 |  |  | static void __iomem *bus_status = (void __iomem *)0xbf000060; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned int ioready(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return readl(bus_status) & 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void wait_ioready(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	do { } while (!ioready()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void wait_ioclear(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	do { } while (ioready()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void check_ioclear(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ioready()) { | 
					
						
							|  |  |  | 		pr_debug("ioclear: initially busy\n"); | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			(void) readl(bus_xfer); | 
					
						
							|  |  |  | 			DELAY(); | 
					
						
							|  |  |  | 		} while (ioready()); | 
					
						
							|  |  |  | 		pr_debug("ioclear: cleared busy\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 pic32_bus_readl(u32 reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 status, val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&pic32_bus_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	check_ioclear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel((PIC32_RD << 24) | (reg & 0x00ffffff), bus_xfer); | 
					
						
							|  |  |  | 	DELAY(); | 
					
						
							|  |  |  | 	wait_ioready(); | 
					
						
							|  |  |  | 	status = readl(bus_xfer); | 
					
						
							|  |  |  | 	DELAY(); | 
					
						
							|  |  |  | 	val = readl(bus_xfer); | 
					
						
							|  |  |  | 	wait_ioclear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug("pic32_bus_readl: *%x -> %x (status=%x)\n", reg, val, status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&pic32_bus_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void pic32_bus_writel(u32 val, u32 reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u32 status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&pic32_bus_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	check_ioclear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel((PIC32_WR << 24) | (reg & 0x00ffffff), bus_xfer); | 
					
						
							|  |  |  | 	DELAY(); | 
					
						
							|  |  |  | 	writel(val, bus_xfer); | 
					
						
							|  |  |  | 	DELAY(); | 
					
						
							|  |  |  | 	wait_ioready(); | 
					
						
							|  |  |  | 	status = readl(bus_xfer); | 
					
						
							|  |  |  | 	wait_ioclear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug("pic32_bus_writel: *%x <- %x (status=%x)\n", reg, val, status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&pic32_bus_lock, flags); | 
					
						
							|  |  |  | } |