aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/mn10300-serial-low.S
blob: 2244853882283a1070e844e8a8ddc088af19e632 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
###############################################################################
#
# Virtual DMA driver for MN10300 serial ports
#
# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
# Written by David Howells (dhowells@redhat.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public Licence
# as published by the Free Software Foundation; either version
# 2 of the Licence, or (at your option) any later version.
#
###############################################################################
#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/smp.h>
#include <asm/cpu-regs.h>
#include <asm/frame.inc>
#include <asm/timer-regs.h>
#include <proc/cache.h>
#include <unit/timex.h>
#include "mn10300-serial.h"

#define	SCxCTR	0x00
#define	SCxICR	0x04
#define	SCxTXB	0x08
#define	SCxRXB	0x09
#define	SCxSTR	0x0c
#define	SCxTIM	0x0d

	.text

###############################################################################
#
# serial port interrupt virtual DMA entry point
# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
#
###############################################################################
	.balign	L1_CACHE_BYTES
ENTRY(mn10300_serial_vdma_interrupt)
	or	EPSW_IE,psw			# permit overriding by
						# debugging interrupts
	movm	[d2,d3,a2,a3,exreg0],(sp)

	movhu	(IAGR),a2			# see if which interrupt is
						# pending
	and	IAGR_GN,a2
	add	a2,a2
	add	mn10300_serial_int_tbl,a2

	mov	(a2+),a3
	mov	(__iobase,a3),e2
	mov	(a2),a2
	jmp	(a2)

###############################################################################
#
# serial port receive interrupt virtual DMA entry point
# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
# - stores data/status byte pairs in the ring buffer
# - induces a scheduler tick timer interrupt when done, which we then subvert
# on entry:
#	A3	struct mn10300_serial_port *
#	E2	I/O port base
#
###############################################################################
ENTRY(mn10300_serial_vdma_rx_handler)
	mov	(__rx_icr,a3),e3
	mov	GxICR_DETECT,d2
	movbu	d2,(e3)				# ACK the interrupt
	movhu	(e3),d2				# flush

	mov	(__rx_inp,a3),d3
	mov	d3,a2
	add	2,d3
	and	MNSC_BUFFER_SIZE-1,d3
	mov	(__rx_outp,a3),d2
	cmp	d3,d2
	beq	mnsc_vdma_rx_overflow

	mov	(__rx_buffer,a3),d2
	add	d2,a2
	movhu	(SCxSTR,e2),d2
	movbu	d2,(1,a2)
	movbu	(SCxRXB,e2),d2
	movbu	d2,(a2)
	mov	d3,(__rx_inp,a3)
	bset	MNSCx_RX_AVAIL,(__intr_flags,a3)

mnsc_vdma_rx_done:
	mov	(__tm_icr,a3),a2
	mov	GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
	movhu	d2,(a2)				# request a slow interrupt
	movhu	(a2),d2				# flush

	movm	(sp),[d2,d3,a2,a3,exreg0]
	rti

mnsc_vdma_rx_overflow:
	bset	MNSCx_RX_OVERF,(__intr_flags,a3)
	bra	mnsc_vdma_rx_done

###############################################################################
#
# serial port transmit interrupt virtual DMA entry point
# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
# - retrieves data bytes from the ring buffer and passes them to the serial port
# - induces a scheduler tick timer interrupt when done, which we then subvert
#	A3	struct mn10300_serial_port *
#	E2	I/O port base
#
###############################################################################
	.balign	L1_CACHE_BYTES
ENTRY(mn10300_serial_vdma_tx_handler)
	mov	(__tx_icr,a3),e3
	mov	GxICR_DETECT,d2
	movbu	d2,(e3)			# ACK the interrupt
	movhu	(e3),d2			# flush

	btst	0x01,(__tx_break,a3)	# handle transmit break request
	bne	mnsc_vdma_tx_break

	movbu	(SCxSTR,e2),d2		# don't try and transmit a char if the
					# buffer is not empty
	btst	SC01STR_TBF,d2		# (may have tried to jumpstart)
	bne	mnsc_vdma_tx_noint

	movbu	(__tx_xchar,a3),d2	# handle hi-pri XON/XOFF
	or	d2,d2
	bne	mnsc_vdma_tx_xchar

	mov	(__tx_info_buffer,a3),a2 # get the uart_info struct for Tx
	mov	(__xmit_tail,a2),d3
	mov	(__xmit_head,a2),d2
	cmp	d3,d2
	beq	mnsc_vdma_tx_empty

	mov	(__xmit_buffer,a2),d2	# get a char from the buffer and
					# transmit it
	movbu	(d3,d2),d2
	movbu	d2,(SCxTXB,e2)		# Tx

	inc	d3			# advance the buffer pointer
	and	__UART_XMIT_SIZE-1,d3
	mov	(__xmit_head,a2),d2
	mov	d3,(__xmit_tail,a2)

	sub	d3,d2			# see if we've written everything
	beq	mnsc_vdma_tx_empty

	and	__UART_XMIT_SIZE-1,d2	# see if we just made a hole
	cmp	__UART_XMIT_SIZE-2,d2
	beq	mnsc_vdma_tx_made_hole

mnsc_vdma_tx_done:
	mov	(__tm_icr,a3),a2
	mov	GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
	movhu	d2,(a2)			# request a slow interrupt
	movhu	(a2),d2			# flush

mnsc_vdma_tx_noint:
	movm	(sp),[d2,d3,a2,a3,exreg0]
	rti

mnsc_vdma_tx_empty:
	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2
	movhu	d2,(e3)			# disable the interrupt
	movhu	(e3),d2			# flush

	bset	MNSCx_TX_EMPTY,(__intr_flags,a3)
	bra	mnsc_vdma_tx_done

mnsc_vdma_tx_break:
	movhu	(SCxCTR,e2),d2		# turn on break mode
	or	SC01CTR_BKE,d2
	movhu	d2,(SCxCTR,e2)
	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2
	movhu	d2,(e3)			# disable transmit interrupts on this
					# channel
	movhu	(e3),d2			# flush
	bra	mnsc_vdma_tx_noint

mnsc_vdma_tx_xchar:
	bclr	0xff,(__tx_xchar,a3)
	movbu	d2,(SCxTXB,e2)
	bra	mnsc_vdma_tx_done

mnsc_vdma_tx_made_hole:
	bset	MNSCx_TX_SPACE,(__intr_flags,a3)
	bra	mnsc_vdma_tx_done