summaryrefslogtreecommitdiffstats
path: root/drivers/char/sh-sci.h
blob: ddf5712a5ddee7acd2cda24e6f00d2f18ce37f5c (plain)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/* $Id: sh-sci.h,v 1.8 2000/03/08 15:19:39 gniibe Exp $
 *
 *  linux/drivers/char/sh-sci.h
 *
 *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
 *  Copyright (C) 1999, 2000  Niibe Yutaka
 *  Copyright (C) 2000  Greg Banks
 *  Modified to support multiple serial ports. Stuart Menefy (May 2000).
 *
 */
#include <linux/config.h>

/* Values for sci_port->type */
#define PORT_SCI  0
#define PORT_SCIF 1

/* Offsets into the sci_port->irqs array */
#define SCIx_ERI_IRQ 0
#define SCIx_RXI_IRQ 1
#define SCIx_TXI_IRQ 2

/*                     ERI, RXI, TXI,   INTC reg, INTC pos */
#define SCI_IRQS      { 23,  24,  25 }, INTC_IPRB, 1
#define SH3_SCIF_IRQS { 56,  57,  59 }, INTC_IPRE, 1
#define SH4_SCIF_IRQS { 40,  41,  43 }, INTC_IPRC, 1

#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCI_NPORTS 1
# define SCI_INIT { \
  { {}, PORT_SCI,  0xfffffe80, SCI_IRQS,      sci_init_pins_sci  } \
}
# define SCSPTR 0xffffff7c /* 8 bit */
# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
# define SCI_NPORTS 2
# define SCI_INIT { \
  { {}, PORT_SCI,  0xfffffe80, SCI_IRQS,      sci_init_pins_sci  }, \
  { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif }  \
}
# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_AND_SCIF
#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
# define SCI_NPORTS 2
# define SCI_INIT { \
  { {}, PORT_SCI,  0xffe00000, SCI_IRQS,      sci_init_pins_sci  }, \
  { {}, PORT_SCIF, 0xFFE80000, SH4_SCIF_IRQS, sci_init_pins_scif }  \
}
# define SCSPTR1 0xffe0001c /* 8  bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCLSR2  0xFFE80024 /* 16 bit SCIF */
# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
	0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
	0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
# define SCI_AND_SCIF
#else
# error CPU subtype not defined
#endif

/* SCSCR */
#define SCI_CTRL_FLAGS_TIE  0x80 /* all */
#define SCI_CTRL_FLAGS_RIE  0x40 /* all */
#define SCI_CTRL_FLAGS_TE   0x20 /* all */
#define SCI_CTRL_FLAGS_RE   0x10 /* all */
/*      SCI_CTRL_FLAGS_REIE 0x08  * 7750 SCIF */
/*      SCI_CTRL_FLAGS_MPIE 0x08  * 7708 SCI, 7709 SCI, 7750 SCI */
/*      SCI_CTRL_FLAGS_TEIE 0x04  * 7708 SCI, 7709 SCI, 7750 SCI */
/*      SCI_CTRL_FLAGS_CKE1 0x02  * all */
/*      SCI_CTRL_FLAGS_CKE0 0x01  * 7708 SCI, 7709 SCI/SCIF, 7750 SCI */

/* SCxSR SCI */
#define SCI_TDRE  0x80 /* 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_RDRF  0x40 /* 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_ORER  0x20 /* 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_FER   0x10 /* 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_PER   0x08 /* 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_TEND  0x04 /* 7708 SCI, 7709 SCI, 7750 SCI */
/*      SCI_MPB   0x02  * 7708 SCI, 7709 SCI, 7750 SCI */
/*      SCI_MPBT  0x01  * 7708 SCI, 7709 SCI, 7750 SCI */

#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)

/* SCxSR SCIF */
#define SCIF_ER    0x0080 /* 7709 SCIF, 7750 SCIF */
#define SCIF_TEND  0x0040 /* 7709 SCIF, 7750 SCIF */
#define SCIF_TDFE  0x0020 /* 7709 SCIF, 7750 SCIF */
#define SCIF_BRK   0x0010 /* 7709 SCIF, 7750 SCIF */
#define SCIF_FER   0x0008 /* 7709 SCIF, 7750 SCIF */
#define SCIF_PER   0x0004 /* 7709 SCIF, 7750 SCIF */
#define SCIF_RDF   0x0002 /* 7709 SCIF, 7750 SCIF */
#define SCIF_DR    0x0001 /* 7709 SCIF, 7750 SCIF */

#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)

#if defined(SCI_ONLY)
# define SCxSR_TEND(port)		SCI_TEND
# define SCxSR_ERRORS(port)		SCI_ERRORS
# define SCxSR_RDxF(port)               SCI_RDRF
# define SCxSR_TDxE(port)               SCI_TDRE
# define SCxSR_RDxF_CLEAR(port)		0xbc
# define SCxSR_ERROR_CLEAR(port)	0xc4
# define SCxSR_TDxE_CLEAR(port)		0x78
#elif defined(SCIF_ONLY) 
# define SCxSR_TEND(port)		SCIF_TEND
# define SCxSR_ERRORS(port)		SCIF_ERRORS
# define SCxSR_RDxF(port)               SCIF_RDF
# define SCxSR_TDxE(port)               SCIF_TDFE
# define SCxSR_RDxF_CLEAR(port)		0x00fc
# define SCxSR_ERROR_CLEAR(port)	0x0063
# define SCxSR_TDxE_CLEAR(port)		0x00df
#else
# define SCxSR_TEND(port)	 (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
# define SCxSR_ERRORS(port)	 (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
# define SCxSR_RDxF(port)        (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
# define SCxSR_TDxE(port)        (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
# define SCxSR_RDxF_CLEAR(port)	 (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063)
# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
#endif

/* SCFCR */
#define SCFCR_RFRST 0x0002
#define SCFCR_TFRST 0x0004
#define SCFCR_MCE   0x0008

#define SCI_PRIORITY	3

#define SCI_MAJOR	      204
#define SCI_MINOR_START		8

/* Generic serial flags */
#define SCI_RX_THROTTLE		0x0000001

/* generic serial tty */
#define O_OTHER(tty)    \
      ((O_OLCUC(tty))  ||\
      (O_ONLCR(tty))   ||\
      (O_OCRNL(tty))   ||\
      (O_ONOCR(tty))   ||\
      (O_ONLRET(tty))  ||\
      (O_OFILL(tty))   ||\
      (O_OFDEL(tty))   ||\
      (O_NLDLY(tty))   ||\
      (O_CRDLY(tty))   ||\
      (O_TABDLY(tty))  ||\
      (O_BSDLY(tty))   ||\
      (O_VTDLY(tty))   ||\
      (O_FFDLY(tty)))

#define I_OTHER(tty)    \
      ((I_INLCR(tty))  ||\
      (I_IGNCR(tty))   ||\
      (I_ICRNL(tty))   ||\
      (I_IUCLC(tty))   ||\
      (L_ISIG(tty)))

#define SCI_MAGIC 0xbabeface

struct sci_port {
	struct gs_port gs;
	int type;
	unsigned int base;
	unsigned char irqs[3]; /* ERI, RXI, TXI */
	unsigned int intc_addr, intc_pos;
	void (*init_pins)(struct sci_port* port, unsigned int cflag);
	unsigned int old_cflag;
};

#define SCI_IN(size, offset)					\
  unsigned int addr = port->base + (offset);			\
  if ((size) == 8) { 						\
    return ctrl_inb(addr);					\
  } else {					 		\
    return ctrl_inw(addr);					\
  }
#define SCI_OUT(size, offset, value)				\
  unsigned int addr = port->base + (offset);			\
  if ((size) == 8) { 						\
    ctrl_outb(value, addr);					\
  } else {							\
    ctrl_outw(value, addr);					\
  }

#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
  static inline unsigned int sci_##name##_in(struct sci_port* port)	\
  {									\
    if (port->type == PORT_SCI) { 					\
      SCI_IN(sci_size, sci_offset)					\
    } else {								\
      SCI_IN(scif_size, scif_offset);		 			\
    }									\
  }									\
  static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
  {									\
    if (port->type == PORT_SCI) {					\
      SCI_OUT(sci_size, sci_offset, value)				\
    } else {								\
      SCI_OUT(scif_size, scif_offset, value);				\
    }									\
  }

#define CPU_SCIF_FNS(name, scif_offset, scif_size)				\
  static inline unsigned int sci_##name##_in(struct sci_port* port)	\
  {									\
    SCI_IN(scif_size, scif_offset);		 			\
  }									\
  static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
  {									\
    SCI_OUT(scif_size, scif_offset, value);				\
  }

#ifdef __sh3__
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
		 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
		 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif

/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  */
/*      name     off  sz   off  sz   off  sz   off  sz   */
SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16)
SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8)
SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16)
SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8)
SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16)
SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8)
SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)

#define sci_in(port, reg) sci_##reg##_in(port)
#define sci_out(port, reg, value) sci_##reg##_out(port, value)


/*
 * Values for the BitRate Register (SCBRR)
 *
 * The values are actually divisors for a frequency which can
 * be internal to the SH3 (14.7456MHz) or derived from an external
 * clock source.  This driver assumes the internal clock is used;
 * to support using an external clock source, config options or
 * possibly command-line options would need to be added.
 *
 * Also, to support speeds below 2400 (why?) the lower 2 bits of
 * the SCSMR register would also need to be set to non-zero values.
 *
 * -- Greg Banks 27Feb2000
 *
 * Answer: The SCBRR register is only eight bits, and the value in
 * it gets larger with lower baud rates. At around 2400 (depending on
 * the peripherial module clock) you run out of bits. However the
 * lower two bits of SCSMR allow the module clock to be divided down,
 * scaling the value which is needed in SCBRR.
 *
 * -- Stuart Menefy - 23 May 2000
 */

#define PCLK           (current_cpu_data.module_clock)

#define SCBRR_VALUE(bps) (PCLK/(32*bps)-1)
#define BPS_2400       SCBRR_VALUE(2400)
#define BPS_4800       SCBRR_VALUE(4800)
#define BPS_9600       SCBRR_VALUE(9600)
#define BPS_19200      SCBRR_VALUE(19200)
#define BPS_38400      SCBRR_VALUE(38400)
#define BPS_115200     SCBRR_VALUE(115200)

#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
/* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef";

static __inline__ char highhex(int  x)
{
	return hexchars[(x >> 4) & 0xf];
}

static __inline__ char lowhex(int  x)
{
	return hexchars[x & 0xf];
}
#endif

static __inline__ void put_char(struct sci_port *port, char c)
{
	unsigned long flags;
	unsigned short status;

	save_and_cli(flags);

	do
		status = sci_in(port, SCxSR);
	while (!(status & SCxSR_TDxE(port)));

	sci_out(port, SCxTDR, c);
	sci_in(port, SCxSR);            /* Dummy read */
	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));

	restore_flags(flags);
}

static __inline__ void handle_error(struct sci_port *port)
{				/* Clear error flags */
	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
}

static __inline__ int get_char(struct sci_port *port)
{
	unsigned long flags;
	unsigned short status;
	int c;

	save_and_cli(flags);
        do {
		status = sci_in(port, SCxSR);
		if (status & SCxSR_ERRORS(port)) {
			handle_error(port);
			continue;
		}
	} while (!(status & SCxSR_RDxF(port)));
	c = sci_in(port, SCxRDR);
	sci_in(port, SCxSR);            /* Dummy read */
	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
	restore_flags(flags);

	return c;
}

/*
 * Send the packet in buffer.  The host get's one chance to read it.
 * This routine does not wait for a positive acknowledge.
 */

static __inline__ void put_string(struct sci_port *port,
				  const char *buffer, int count)
{
	int i;
	const unsigned char *p = buffer;
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
	int checksum;

if (IN_GDB) {
	/*  $<packet info>#<checksum>. */
	do {
		unsigned char c;
		put_char(port, '$');
		put_char(port, 'O'); /* 'O'utput to console */
		checksum = 'O';

		for (i=0; i<count; i++) { /* Don't use run length encoding */
			int h, l;

			c = *p++;
			h = highhex(c);
			l = lowhex(c);
			put_char(port, h);
			put_char(port, l);
			checksum += h + l;
		}
		put_char(port, '#');
		put_char(port, highhex(checksum));
		put_char(port, lowhex(checksum));
	} while  (get_char(port) != '+');
} else
#endif
	for (i=0; i<count; i++) {
		if (*p == 10)
			put_char(port, '\r');
		put_char(port, *p++);
	}
}