2 * drivers/serial/mpsc/mpsc.h
4 * Author: Mark A. Greer <mgreer@mvista.com>
6 * 2004 (c) MontaVista, Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
15 #include <linux/config.h>
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 #include <linux/tty.h>
19 #include <linux/ioport.h>
20 #include <linux/init.h>
21 #include <linux/console.h>
22 #include <linux/sysrq.h>
23 #include <linux/serial.h>
24 #include <linux/delay.h>
25 #include <linux/device.h>
26 #include <linux/dma-mapping.h>
31 #if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
35 #include <linux/serial_core.h>
36 #include "mpsc_defs.h"
40 * Descriptors and buffers must be cache line aligned.
41 * Buffers lengths must be multiple of cache line size.
42 * Number of Tx & Rx descriptors must be power of 2.
44 #define MPSC_DESC_ALIGN dma_get_cache_alignment()
45 #define MPSC_BUF_ALIGN dma_get_cache_alignment()
47 #define MPSC_RXR_ENTRIES 32
48 #define MPSC_RXRE_SIZE sizeof(mpsc_rx_desc_t)
49 #define MPSC_RXR_SIZE (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
50 #define MPSC_RXBE_SIZE dma_get_cache_alignment()
51 #define MPSC_RXB_SIZE (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
53 #define MPSC_TXR_ENTRIES 32
54 #define MPSC_TXRE_SIZE sizeof(mpsc_tx_desc_t)
55 #define MPSC_TXR_SIZE (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
56 #define MPSC_TXBE_SIZE dma_get_cache_alignment()
57 #define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
65 } mpsc_rx_desc_t __attribute((packed));
67 /* Tx and Rx Ring entry descriptors */
74 } mpsc_tx_desc_t __attribute((packed));
76 /* The main driver data structure */
78 struct uart_port port; /* Overlay uart_port structure */
80 /* Internal driver state for this ctlr */
83 tcflag_t c_iflag; /* save termios->c_iflag */
84 tcflag_t c_cflag; /* save termios->c_cflag */
86 /* Info passed in from platform */
87 u8 mirror_regs; /* Need to mirror regs? */
88 u8 cache_mgmt; /* Need manual cache mgmt? */
89 u8 brg_can_tune; /* BRG has baud tuning? */
97 /* Physical addresses of various blocks of registers (from platform) */
99 u32 mpsc_routing_base_p;
101 u32 sdma_intr_base_p;
104 /* Virtual addresses of various blocks of registers (from platform) */
106 u32 mpsc_routing_base;
111 /* Descriptor ring and buffer allocations */
112 void *desc_region; /* Region for desc rings */
113 dma_addr_t desc_region_p;
114 u32 desc_region_size;
116 void *buf_region; /* kmalloc region for bufs */
119 mpsc_rx_desc_t *rxr; /* Rx descriptor ring */
120 mpsc_rx_desc_t *rxr_p; /* Phys addr of rxr */
121 u32 rxr_posn; /* First desc w/ Rx data */
122 u8 *rxb; /* Rx Ring I/O buf */
123 dma_addr_t rxb_p; /* Phys addr of rxb */
125 mpsc_tx_desc_t *txr; /* Tx descriptor ring */
126 mpsc_tx_desc_t *txr_p; /* Phys addr of txr */
127 u32 txr_posn; /* First unused desc */
128 u8 *txb; /* Tx Ring I/O buf */
129 dma_addr_t txb_p; /* Phys addr of txb */
131 /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
139 u32 SDMA_INTR_MASK_m;
144 * Some MPSC ctlrs have an erratum where they aren't supposed to access
145 * cache coherent memory regions. From practical experience, the erratum
146 * is not triggered as long as there isn't a snoop hit. Therefore, if
147 * the MPSC in used has this erratum and coherency is enabled on the platform,
148 * we must manually manage the cache for ring descriptors and the I/O buffers.
150 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
151 #define MPSC_CACHE_FLUSH(pi, s, e) { \
152 if (pi->cache_mgmt) { \
153 /* 64x60 erratum: can't use dcbst/clean_dcache_range() */ \
154 flush_dcache_range((ulong)s, (ulong)e); \
159 #define MPSC_CACHE_INVALIDATE(pi, s, e) { \
160 if (pi->cache_mgmt) { \
161 invalidate_dcache_range((ulong)s, (ulong)e); \
166 #define MPSC_CACHE_FLUSH_INVALIDATE(pi, s, e) { \
167 if (pi->cache_mgmt) { \
168 flush_dcache_range((ulong)s, (ulong)e); \
173 #define MPSC_CACHE_FLUSH(pi, s, e)
174 #define MPSC_CACHE_INVALIDATE(pi, s, e)
175 #define MPSC_CACHE_FLUSH_INVALIDATE(pi, s, e)
179 * 'MASK_INSERT' takes the low-order 'n' bits of 'i', shifts it 'b' bits to
180 * the left, and inserts it into the target 't'. The corresponding bits in
181 * 't' will have been cleared before the bits in 'i' are inserted.
184 #define MASK_INSERT(t, i, n, b) ({ \
186 __asm__ __volatile__( \
187 "rlwimi %0,%2,%4,32-(%3+%4),31-%4\n" \
189 : "0" (rval), "r" (i), "i" (n), "i" (b)); \
193 /* These macros are really just examples. Feel free to change them --MAG */
194 #define GEN_MASK(n, b) \
199 m = (0xffffffff << sl) >> sr; \
202 #define MASK_INSERT(t, i, n, b) \
205 m = GEN_MASK((n), (b)); \
207 rval |= (((i) << (b)) & m); \
211 /* I/O macros for regs that you can read */
212 #define MPSC_READ(pi, unit, offset) readl((pi)->unit##_base + (offset))
213 #define MPSC_WRITE(pi, unit, offset, v) writel(v, (pi)->unit##_base + (offset))
214 #define MPSC_MOD_FIELD(pi, unit, offset, num_bits, shift, val) \
217 v = readl((pi)->unit##_base + (offset)); \
218 writel(MASK_INSERT(v,val,num_bits,shift), (pi)->unit##_base+(offset));\
221 #define MPSC_READ_M(pi, unit, offset) \
224 if ((pi)->mirror_regs) v = (pi)->offset##_m; \
225 else v = readl((pi)->unit##_base + (offset)); \
229 #define MPSC_WRITE_M(pi, unit, offset, v) \
231 if ((pi)->mirror_regs) (pi)->offset##_m = v; \
232 writel(v, (pi)->unit##_base + (offset)); \
235 #define MPSC_MOD_FIELD_M(pi, unit, offset, num_bits, shift, val) \
238 if ((pi)->mirror_regs) v = (pi)->offset##_m; \
239 else v = readl((pi)->unit##_base + (offset)); \
240 v = MASK_INSERT(v, val, num_bits, shift); \
241 if ((pi)->mirror_regs) (pi)->offset##_m = v; \
242 writel(v, (pi)->unit##_base + (offset)); \
246 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
249 /* Hooks to platform-specific code */
250 int mpsc_platform_register_driver(void);
251 void mpsc_platform_unregister_driver(void);
253 /* Hooks back in to mpsc common to be called by platform-specific code */
254 mpsc_port_info_t *mpsc_device_probe(int index);
255 mpsc_port_info_t *mpsc_device_remove(int index);
257 #endif /* __MPSC_H__ */