Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
221bfb31
Commit
221bfb31
authored
Jun 17, 2004
by
David Woodhouse
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
UART driver for Motorola CPM/CPM2 I/O core on 8xx/8xxx chips.
parent
b0e99957
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2033 additions
and
0 deletions
+2033
-0
drivers/serial/Kconfig
drivers/serial/Kconfig
+60
-0
drivers/serial/Makefile
drivers/serial/Makefile
+1
-0
drivers/serial/cpm_uart/Makefile
drivers/serial/cpm_uart/Makefile
+11
-0
drivers/serial/cpm_uart/cpm_uart.h
drivers/serial/cpm_uart/cpm_uart.h
+89
-0
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_core.c
+1177
-0
drivers/serial/cpm_uart/cpm_uart_cpm1.c
drivers/serial/cpm_uart/cpm_uart_cpm1.c
+275
-0
drivers/serial/cpm_uart/cpm_uart_cpm1.h
drivers/serial/cpm_uart/cpm_uart_cpm1.h
+45
-0
drivers/serial/cpm_uart/cpm_uart_cpm2.c
drivers/serial/cpm_uart/cpm_uart_cpm2.c
+327
-0
drivers/serial/cpm_uart/cpm_uart_cpm2.h
drivers/serial/cpm_uart/cpm_uart_cpm2.h
+45
-0
include/linux/serial_core.h
include/linux/serial_core.h
+3
-0
No files found.
drivers/serial/Kconfig
View file @
221bfb31
...
...
@@ -616,5 +616,65 @@ config SERIAL_PMACZILOG_CONSOLE
on your PowerMac as the console, you can do so by answering
Y to this option.
config SERIAL_CPM
tristate "CPM2 SCC/SMC serial port support"
depends on CPM2 || 8xx
select SERIAL_CORE
help
This driver supports the SCC and SMC serial ports on Motorola
embedded PowerPC that contain a CPM2 (8xxx) or a CPM1 (8xx)
config SERIAL_CPM_CONSOLE
bool "Support for console on CPM2 SCC/SMC serial port"
depends on SERIAL_CPM=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use a SCC or SMC CPM UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyCPM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_CPM_SCC1
bool "Support for SCC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC1 as a serial port
config SERIAL_CPM_SCC2
bool "Support for SCC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC2 as a serial port
config SERIAL_CPM_SCC3
bool "Support for SCC3 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC3 as a serial port
config SERIAL_CPM_SCC4
bool "Support for SCC4 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC4 as a serial port
config SERIAL_CPM_SMC1
bool "Support for SMC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC1 as a serial port
config SERIAL_CPM_SMC2
bool "Support for SMC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC2 as a serial port
endmenu
drivers/serial/Makefile
View file @
221bfb31
...
...
@@ -39,3 +39,4 @@ obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ)
+=
dz.o
obj-$(CONFIG_SERIAL_SH_SCI)
+=
sh-sci.o
obj-$(CONFIG_SERIAL_BAST_SIO)
+=
bast_sio.o
obj-$(CONFIG_SERIAL_CPM)
+=
cpm_uart/
drivers/serial/cpm_uart/Makefile
0 → 100644
View file @
221bfb31
#
# Makefile for the Motorola 8xx FEC ethernet controller
#
obj-$(CONFIG_SERIAL_CPM)
+=
cpm_uart.o
# Select the correct platform objects.
cpm_uart-objs-$(CONFIG_CPM2)
+=
cpm_uart_cpm2.o
cpm_uart-objs-$(CONFIG_8xx)
+=
cpm_uart_cpm1.o
cpm_uart-objs
:=
cpm_uart_core.o
$
(
cpm_uart-objs-y
)
drivers/serial/cpm_uart/cpm_uart.h
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* Copyright (C) 2004 Motorola, Inc
*
*/
#ifndef CPM_UART_H
#define CPM_UART_H
#include <linux/config.h>
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
#elif defined(CONFIG_8xx)
#include "cpm_uart_cpm1.h"
#endif
#ifndef CONFIG_SERIAL_8250
#define SERIAL_CPM_MAJOR TTY_MAJOR
#define SERIAL_CPM_MINOR 64
#else
#define SERIAL_CPM_MAJOR 204
#define SERIAL_CPM_MINOR 42
#endif
#define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC)
#define FLAG_SMC 0x00000002
#define FLAG_CONSOLE 0x00000001
#define UART_SMC1 0
#define UART_SMC2 1
#define UART_SCC1 2
#define UART_SCC2 3
#define UART_SCC3 4
#define UART_SCC4 5
#define UART_NR 6
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
#define TX_NUM_FIFO 4
#define TX_BUF_SIZE 32
struct
uart_cpm_port
{
struct
uart_port
port
;
u16
rx_nrfifos
;
u16
rx_fifosize
;
u16
tx_nrfifos
;
u16
tx_fifosize
;
smc_t
*
smcp
;
volatile
smc_uart_t
*
smcup
;
scc_t
*
sccp
;
scc_uart_t
*
sccup
;
volatile
cbd_t
*
rx_bd_base
;
volatile
cbd_t
*
rx_cur
;
volatile
cbd_t
*
tx_bd_base
;
volatile
cbd_t
*
tx_cur
;
unsigned
char
*
tx_buf
;
unsigned
char
*
rx_buf
;
u32
flags
;
void
(
*
set_lineif
)
(
struct
uart_cpm_port
*
);
u8
brg
;
uint
dp_addr
;
void
*
mem_addr
;
dma_addr_t
dma_addr
;
int
baud
;
int
bits
;
};
extern
int
cpm_uart_port_map
[
UART_NR
];
extern
int
cpm_uart_nr
;
extern
struct
uart_cpm_port
cpm_uart_ports
[
UART_NR
];
/* these are located in their respective files */
extern
void
cpm_line_cr_cmd
(
int
line
,
int
cmd
);
extern
int
cpm_uart_init_portdesc
(
void
);
extern
int
cpm_uart_allocbuf
(
struct
uart_cpm_port
*
pinfo
,
unsigned
int
is_con
);
extern
void
cpm_uart_freebuf
(
struct
uart_cpm_port
*
pinfo
);
extern
void
smc1_lineif
(
struct
uart_cpm_port
*
pinfo
);
extern
void
smc2_lineif
(
struct
uart_cpm_port
*
pinfo
);
extern
void
scc1_lineif
(
struct
uart_cpm_port
*
pinfo
);
extern
void
scc2_lineif
(
struct
uart_cpm_port
*
pinfo
);
extern
void
scc3_lineif
(
struct
uart_cpm_port
*
pinfo
);
extern
void
scc4_lineif
(
struct
uart_cpm_port
*
pinfo
);
#endif
/* CPM_UART_H */
drivers/serial/cpm_uart/cpm_uart_core.c
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart.c
*
* Driver for CPM (SCC/SMC) serial ports; core driver
*
* Based on arch/ppc/cpm2_io/uart.c by Dan Malek
* Based on ppc8xx.c by Thomas Gleixner
* Based on drivers/serial/amba.c by Russell King
*
* Maintainer: Kumar Gala (kumar.gala@motorola.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Motorola, Inc
* (C) 2004 Intracom, S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#include "cpm_uart.h"
/***********************************************************************/
/* Track which ports are configured as uarts */
int
cpm_uart_port_map
[
UART_NR
];
/* How many ports did we config as uarts */
int
cpm_uart_nr
;
/*
* Check, if transmit buffers are processed
*/
static
unsigned
int
cpm_uart_tx_empty
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
cbd_t
*
bdp
=
pinfo
->
tx_bd_base
;
int
ret
=
0
;
while
(
1
)
{
if
(
bdp
->
cbd_sc
&
BD_SC_READY
)
break
;
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
{
ret
=
TIOCSER_TEMT
;
break
;
}
bdp
++
;
}
pr_debug
(
"CPM uart[%d]:tx_empty: %d
\n
"
,
port
->
line
,
ret
);
return
ret
;
}
static
void
cpm_uart_set_mctrl
(
struct
uart_port
*
port
,
unsigned
int
mctrl
)
{
/* Whee. Do nothing. */
}
static
unsigned
int
cpm_uart_get_mctrl
(
struct
uart_port
*
port
)
{
/* Whee. Do nothing. */
return
TIOCM_CAR
|
TIOCM_DSR
|
TIOCM_CTS
;
}
/*
* Stop transmitter
*/
static
void
cpm_uart_stop_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_stop
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
smc_t
*
smcp
=
pinfo
->
smcp
;
volatile
scc_t
*
sccp
=
pinfo
->
sccp
;
pr_debug
(
"CPM uart[%d]:stop tx
\n
"
,
port
->
line
);
if
(
IS_SMC
(
pinfo
))
smcp
->
smc_smcm
&=
~
SMCM_TX
;
else
sccp
->
scc_sccm
&=
~
UART_SCCM_TX
;
}
/*
* Transmit characters, refill buffer descriptor, if possible
*/
static
int
cpm_uart_tx_pump
(
struct
uart_port
*
port
)
{
volatile
cbd_t
*
bdp
;
unsigned
char
*
p
;
int
count
;
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
struct
circ_buf
*
xmit
=
&
port
->
info
->
xmit
;
/* Handle xon/xoff */
if
(
port
->
x_char
)
{
/* Pick next descriptor and fill from buffer */
bdp
=
pinfo
->
tx_cur
;
p
=
bus_to_virt
(
bdp
->
cbd_bufaddr
);
*
p
++
=
xmit
->
buf
[
xmit
->
tail
];
bdp
->
cbd_datlen
=
1
;
bdp
->
cbd_sc
|=
BD_SC_READY
;
/* Get next BD. */
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
bdp
=
pinfo
->
tx_bd_base
;
else
bdp
++
;
pinfo
->
tx_cur
=
bdp
;
port
->
icount
.
tx
++
;
port
->
x_char
=
0
;
return
1
;
}
if
(
uart_circ_empty
(
xmit
)
||
uart_tx_stopped
(
port
))
{
cpm_uart_stop_tx
(
port
,
0
);
return
0
;
}
/* Pick next descriptor and fill from buffer */
bdp
=
pinfo
->
tx_cur
;
while
(
!
(
bdp
->
cbd_sc
&
BD_SC_READY
)
&&
(
xmit
->
tail
!=
xmit
->
head
))
{
count
=
0
;
p
=
bus_to_virt
(
bdp
->
cbd_bufaddr
);
while
(
count
<
pinfo
->
tx_fifosize
)
{
*
p
++
=
xmit
->
buf
[
xmit
->
tail
];
xmit
->
tail
=
(
xmit
->
tail
+
1
)
&
(
UART_XMIT_SIZE
-
1
);
port
->
icount
.
tx
++
;
count
++
;
if
(
xmit
->
head
==
xmit
->
tail
)
break
;
}
bdp
->
cbd_datlen
=
count
;
bdp
->
cbd_sc
|=
BD_SC_READY
;
/* Get next BD. */
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
bdp
=
pinfo
->
tx_bd_base
;
else
bdp
++
;
}
pinfo
->
tx_cur
=
bdp
;
if
(
uart_circ_chars_pending
(
xmit
)
<
WAKEUP_CHARS
)
uart_write_wakeup
(
port
);
if
(
uart_circ_empty
(
xmit
))
{
cpm_uart_stop_tx
(
port
,
0
);
return
0
;
}
return
1
;
}
/*
* Start transmitter
*/
static
void
cpm_uart_start_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_start
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
smc_t
*
smcp
=
pinfo
->
smcp
;
volatile
scc_t
*
sccp
=
pinfo
->
sccp
;
pr_debug
(
"CPM uart[%d]:start tx
\n
"
,
port
->
line
);
if
(
IS_SMC
(
pinfo
))
{
if
(
smcp
->
smc_smcm
&
SMCM_TX
)
return
;
}
else
{
if
(
sccp
->
scc_sccm
&
UART_SCCM_TX
)
return
;
}
if
(
cpm_uart_tx_pump
(
port
)
!=
0
)
{
if
(
IS_SMC
(
pinfo
))
smcp
->
smc_smcm
|=
SMCM_TX
;
else
sccp
->
scc_sccm
|=
UART_SCCM_TX
;
}
}
/*
* Stop receiver
*/
static
void
cpm_uart_stop_rx
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
smc_t
*
smcp
=
pinfo
->
smcp
;
volatile
scc_t
*
sccp
=
pinfo
->
sccp
;
pr_debug
(
"CPM uart[%d]:stop rx
\n
"
,
port
->
line
);
if
(
IS_SMC
(
pinfo
))
smcp
->
smc_smcm
&=
~
SMCM_RX
;
else
sccp
->
scc_sccm
&=
~
UART_SCCM_RX
;
}
/*
* Enable Modem status interrupts
*/
static
void
cpm_uart_enable_ms
(
struct
uart_port
*
port
)
{
pr_debug
(
"CPM uart[%d]:enable ms
\n
"
,
port
->
line
);
}
/*
* Generate a break.
*/
static
void
cpm_uart_break_ctl
(
struct
uart_port
*
port
,
int
break_state
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
pr_debug
(
"CPM uart[%d]:break ctrl, break_state: %d
\n
"
,
port
->
line
,
break_state
);
if
(
break_state
)
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_STOP_TX
);
else
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_RESTART_TX
);
}
/*
* Transmit characters, refill buffer descriptor, if possible
*/
static
void
cpm_uart_int_tx
(
struct
uart_port
*
port
,
struct
pt_regs
*
regs
)
{
pr_debug
(
"CPM uart[%d]:TX INT
\n
"
,
port
->
line
);
cpm_uart_tx_pump
(
port
);
}
/*
* Receive characters
*/
static
void
cpm_uart_int_rx
(
struct
uart_port
*
port
,
struct
pt_regs
*
regs
)
{
int
i
;
unsigned
char
ch
,
*
cp
;
struct
tty_struct
*
tty
=
port
->
info
->
tty
;
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
cbd_t
*
bdp
;
u16
status
;
unsigned
int
flg
;
pr_debug
(
"CPM uart[%d]:RX INT
\n
"
,
port
->
line
);
/* Just loop through the closed BDs and copy the characters into
* the buffer.
*/
bdp
=
pinfo
->
rx_cur
;
for
(;;)
{
/* get status */
status
=
bdp
->
cbd_sc
;
/* If this one is empty, return happy */
if
(
status
&
BD_SC_EMPTY
)
break
;
/* get number of characters, and check spce in flip-buffer */
i
=
bdp
->
cbd_datlen
;
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
*/
if
((
tty
->
flip
.
count
+
i
)
>=
TTY_FLIPBUF_SIZE
)
{
tty
->
flip
.
work
.
func
((
void
*
)
tty
);
if
((
tty
->
flip
.
count
+
i
)
>=
TTY_FLIPBUF_SIZE
)
{
printk
(
KERN_WARNING
"TTY_DONT_FLIP set
\n
"
);
return
;
}
}
/* get pointer */
cp
=
(
unsigned
char
*
)
bus_to_virt
(
bdp
->
cbd_bufaddr
);
/* loop through the buffer */
while
(
i
--
>
0
)
{
ch
=
*
cp
++
;
port
->
icount
.
rx
++
;
flg
=
TTY_NORMAL
;
if
(
status
&
(
BD_SC_BR
|
BD_SC_FR
|
BD_SC_PR
|
BD_SC_OV
))
goto
handle_error
;
if
(
uart_handle_sysrq_char
(
port
,
ch
,
regs
))
continue
;
error_return:
*
tty
->
flip
.
char_buf_ptr
++
=
ch
;
*
tty
->
flip
.
flag_buf_ptr
++
=
flg
;
tty
->
flip
.
count
++
;
}
/* End while (i--) */
/* This BD is ready to be used again. Clear status. get next */
bdp
->
cbd_sc
&=
~
(
BD_SC_BR
|
BD_SC_FR
|
BD_SC_PR
|
BD_SC_OV
);
bdp
->
cbd_sc
|=
BD_SC_EMPTY
;
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
bdp
=
pinfo
->
rx_bd_base
;
else
bdp
++
;
}
/* End for (;;) */
/* Write back buffer pointer */
pinfo
->
rx_cur
=
(
volatile
cbd_t
*
)
bdp
;
/* activate BH processing */
tty_flip_buffer_push
(
tty
);
return
;
/* Error processing */
handle_error:
/* Statistics */
if
(
status
&
BD_SC_BR
)
port
->
icount
.
brk
++
;
if
(
status
&
BD_SC_PR
)
port
->
icount
.
parity
++
;
if
(
status
&
BD_SC_FR
)
port
->
icount
.
frame
++
;
if
(
status
&
BD_SC_OV
)
port
->
icount
.
overrun
++
;
/* Mask out ignored conditions */
status
&=
port
->
read_status_mask
;
/* Handle the remaining ones */
if
(
status
&
BD_SC_BR
)
flg
=
TTY_BREAK
;
else
if
(
status
&
BD_SC_PR
)
flg
=
TTY_PARITY
;
else
if
(
status
&
BD_SC_FR
)
flg
=
TTY_FRAME
;
/* overrun does not affect the current character ! */
if
(
status
&
BD_SC_OV
)
{
ch
=
0
;
flg
=
TTY_OVERRUN
;
/* We skip this buffer */
/* CHECK: Is really nothing senseful there */
/* ASSUMPTION: it contains nothing valid */
i
=
0
;
}
#ifdef SUPPORT_SYSRQ
port
->
sysrq
=
0
;
#endif
goto
error_return
;
}
/*
* Asynchron mode interrupt handler
*/
static
irqreturn_t
cpm_uart_int
(
int
irq
,
void
*
data
,
struct
pt_regs
*
regs
)
{
u8
events
;
struct
uart_port
*
port
=
(
struct
uart_port
*
)
data
;
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
volatile
smc_t
*
smcp
=
pinfo
->
smcp
;
volatile
scc_t
*
sccp
=
pinfo
->
sccp
;
pr_debug
(
"CPM uart[%d]:IRQ
\n
"
,
port
->
line
);
if
(
IS_SMC
(
pinfo
))
{
events
=
smcp
->
smc_smce
;
if
(
events
&
SMCM_BRKE
)
uart_handle_break
(
port
);
if
(
events
&
SMCM_RX
)
cpm_uart_int_rx
(
port
,
regs
);
if
(
events
&
SMCM_TX
)
cpm_uart_int_tx
(
port
,
regs
);
smcp
->
smc_smce
=
events
;
}
else
{
events
=
sccp
->
scc_scce
;
if
(
events
&
UART_SCCM_BRKE
)
uart_handle_break
(
port
);
if
(
events
&
UART_SCCM_RX
)
cpm_uart_int_rx
(
port
,
regs
);
if
(
events
&
UART_SCCM_TX
)
cpm_uart_int_tx
(
port
,
regs
);
sccp
->
scc_scce
=
events
;
}
return
(
events
)
?
IRQ_HANDLED
:
IRQ_NONE
;
}
static
int
cpm_uart_startup
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
int
retval
;
pr_debug
(
"CPM uart[%d]:startup
\n
"
,
port
->
line
);
/* Install interrupt handler. */
retval
=
request_irq
(
port
->
irq
,
cpm_uart_int
,
0
,
"cpm_uart"
,
port
);
if
(
retval
)
return
retval
;
/* Startup rx-int */
if
(
IS_SMC
(
pinfo
))
{
pinfo
->
smcp
->
smc_smcm
|=
SMCM_RX
;
pinfo
->
smcp
->
smc_smcmr
|=
SMCMR_REN
;
}
else
{
pinfo
->
sccp
->
scc_sccm
|=
UART_SCCM_RX
;
}
return
0
;
}
/*
* Reinit buffer descriptors
*/
static
void
cpm_uart_initbd
(
struct
uart_cpm_port
*
pinfo
)
{
int
i
;
volatile
cbd_t
*
bdp
;
pr_debug
(
"CPM uart[%d]:initbd
\n
"
,
pinfo
->
port
.
line
);
for
(
bdp
=
pinfo
->
rx_cur
=
pinfo
->
rx_bd_base
,
i
=
0
;
i
<
pinfo
->
rx_nrfifos
;
i
++
,
bdp
++
)
bdp
->
cbd_sc
=
BD_SC_EMPTY
|
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
rx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
for
(
bdp
=
pinfo
->
tx_cur
=
pinfo
->
tx_bd_base
,
i
=
0
;
i
<
pinfo
->
tx_nrfifos
;
i
++
,
bdp
++
)
bdp
->
cbd_sc
=
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
rx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
}
/*
* Shutdown the uart
*/
static
void
cpm_uart_shutdown
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
pr_debug
(
"CPM uart[%d]:shutdown
\n
"
,
port
->
line
);
/* free interrupt handler */
free_irq
(
port
->
irq
,
port
);
/* If the port is not the console, disable Rx and Tx. */
if
(
!
(
pinfo
->
flags
&
FLAG_CONSOLE
))
{
/* Stop uarts */
if
(
IS_SMC
(
pinfo
))
{
volatile
smc_t
*
smcp
=
pinfo
->
smcp
;
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
smcp
->
smc_smcm
&=
~
(
SMCM_RX
|
SMCM_TX
);
}
else
{
volatile
scc_t
*
sccp
=
pinfo
->
sccp
;
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
}
/* Shut them really down and reinit buffer descriptors */
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_STOP_TX
);
cpm_uart_initbd
(
pinfo
);
}
}
static
void
cpm_uart_init_scc
(
struct
uart_cpm_port
*
pinfo
,
int
bits
,
u16
scval
)
{
volatile
scc_t
*
scp
;
volatile
scc_uart_t
*
sup
;
u8
*
mem_addr
;
volatile
cbd_t
*
bdp
;
int
i
;
pr_debug
(
"CPM uart[%d]:init_scc
\n
"
,
pinfo
->
port
.
line
);
scp
=
pinfo
->
sccp
;
sup
=
pinfo
->
sccup
;
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
pinfo
->
rx_cur
=
pinfo
->
rx_bd_base
;
mem_addr
=
pinfo
->
mem_addr
;
for
(
bdp
=
pinfo
->
rx_bd_base
,
i
=
0
;
i
<
pinfo
->
rx_nrfifos
;
i
++
,
bdp
++
)
{
bdp
->
cbd_bufaddr
=
virt_to_bus
(
mem_addr
);
bdp
->
cbd_sc
=
BD_SC_EMPTY
|
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
rx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
mem_addr
+=
pinfo
->
rx_fifosize
;
}
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr
=
pinfo
->
mem_addr
+
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
);
pinfo
->
tx_cur
=
pinfo
->
tx_bd_base
;
for
(
bdp
=
pinfo
->
tx_bd_base
,
i
=
0
;
i
<
pinfo
->
tx_nrfifos
;
i
++
,
bdp
++
)
{
bdp
->
cbd_bufaddr
=
virt_to_bus
(
mem_addr
);
bdp
->
cbd_sc
=
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
tx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
mem_addr
+=
pinfo
->
tx_fifosize
;
bdp
++
;
}
/* Store address */
pinfo
->
sccup
->
scc_genscc
.
scc_rbase
=
(
unsigned
char
*
)
pinfo
->
rx_bd_base
-
DPRAM_BASE
;
pinfo
->
sccup
->
scc_genscc
.
scc_tbase
=
(
unsigned
char
*
)
pinfo
->
tx_bd_base
-
DPRAM_BASE
;
/* Set up the uart parameters in the
* parameter ram.
*/
cpm_set_scc_fcr
(
sup
);
sup
->
scc_genscc
.
scc_mrblr
=
pinfo
->
rx_fifosize
;
sup
->
scc_maxidl
=
pinfo
->
rx_fifosize
;
sup
->
scc_brkcr
=
1
;
sup
->
scc_parec
=
0
;
sup
->
scc_frmec
=
0
;
sup
->
scc_nosec
=
0
;
sup
->
scc_brkec
=
0
;
sup
->
scc_uaddr1
=
0
;
sup
->
scc_uaddr2
=
0
;
sup
->
scc_toseq
=
0
;
sup
->
scc_char1
=
0x8000
;
sup
->
scc_char2
=
0x8000
;
sup
->
scc_char3
=
0x8000
;
sup
->
scc_char4
=
0x8000
;
sup
->
scc_char5
=
0x8000
;
sup
->
scc_char6
=
0x8000
;
sup
->
scc_char7
=
0x8000
;
sup
->
scc_char8
=
0x8000
;
sup
->
scc_rccm
=
0xc0ff
;
/* Send the CPM an initialize command.
*/
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_INIT_TRX
);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
scp
->
scc_gsmrh
=
0
;
scp
->
scc_gsmrl
=
(
SCC_GSMRL_MODE_UART
|
SCC_GSMRL_TDCR_16
|
SCC_GSMRL_RDCR_16
);
/* Enable rx interrupts and clear all pending events. */
scp
->
scc_sccm
=
UART_SCCM_RX
;
scp
->
scc_scce
=
0xffff
;
scp
->
scc_dsr
=
0x7e7e
;
scp
->
scc_psmr
=
(
bits
<<
12
)
|
scval
;
scp
->
scc_gsmrl
|=
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
}
static
void
cpm_uart_init_smc
(
struct
uart_cpm_port
*
pinfo
,
int
bits
,
u16
cval
)
{
volatile
smc_t
*
sp
;
volatile
smc_uart_t
*
up
;
volatile
u8
*
mem_addr
;
volatile
cbd_t
*
bdp
;
int
i
;
pr_debug
(
"CPM uart[%d]:init_smc
\n
"
,
pinfo
->
port
.
line
);
sp
=
pinfo
->
smcp
;
up
=
pinfo
->
smcup
;
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr
=
pinfo
->
mem_addr
;
pinfo
->
rx_cur
=
pinfo
->
rx_bd_base
;
for
(
bdp
=
pinfo
->
rx_bd_base
,
i
=
0
;
i
<
pinfo
->
rx_nrfifos
;
i
++
,
bdp
++
)
{
bdp
->
cbd_bufaddr
=
virt_to_bus
(
mem_addr
);
bdp
->
cbd_sc
=
BD_SC_EMPTY
|
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
rx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
mem_addr
+=
pinfo
->
rx_fifosize
;
}
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr
=
pinfo
->
mem_addr
+
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
);
pinfo
->
tx_cur
=
pinfo
->
tx_bd_base
;
for
(
bdp
=
pinfo
->
tx_bd_base
,
i
=
0
;
i
<
pinfo
->
tx_nrfifos
;
i
++
,
bdp
++
)
{
bdp
->
cbd_bufaddr
=
virt_to_bus
(
mem_addr
);
bdp
->
cbd_sc
=
BD_SC_INTRPT
|
(
i
<
(
pinfo
->
tx_nrfifos
-
1
)
?
0
:
BD_SC_WRAP
);
mem_addr
+=
pinfo
->
tx_fifosize
;
}
/* Store address */
pinfo
->
smcup
->
smc_rbase
=
(
u_char
*
)
pinfo
->
rx_bd_base
-
DPRAM_BASE
;
pinfo
->
smcup
->
smc_tbase
=
(
u_char
*
)
pinfo
->
tx_bd_base
-
DPRAM_BASE
;
/* Set up the uart parameters in the
* parameter ram.
*/
cpm_set_smc_fcr
(
up
);
/* Using idle charater time requires some additional tuning. */
up
->
smc_mrblr
=
pinfo
->
rx_fifosize
;
up
->
smc_maxidl
=
pinfo
->
rx_fifosize
;
up
->
smc_brkcr
=
1
;
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_INIT_TRX
);
/* Set UART mode, according to the parameters */
sp
->
smc_smcmr
=
smcr_mk_clen
(
bits
)
|
cval
|
SMCMR_SM_UART
;
/* Enable only rx interrupts clear all pending events. */
sp
->
smc_smcm
=
SMCM_RX
;
sp
->
smc_smce
=
0xff
;
sp
->
smc_smcmr
|=
(
SMCMR_REN
|
SMCMR_TEN
);
}
static
void
cpm_uart_set_termios
(
struct
uart_port
*
port
,
struct
termios
*
termios
,
struct
termios
*
old
)
{
int
baud
;
unsigned
long
flags
;
u16
cval
,
scval
;
int
bits
,
sbits
;
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
pr_debug
(
"CPM uart[%d]:set_termios
\n
"
,
port
->
line
);
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
/* Disable UART interrupts */
if
(
IS_SMC
(
pinfo
))
pinfo
->
smcp
->
smc_smcm
&=
~
(
SMCM_RX
|
SMCM_TX
);
else
pinfo
->
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
/*
* If a previous configuration exists wait 2+1 character times
* for tx to finish
*/
if
(
pinfo
->
baud
!=
0
&&
pinfo
->
bits
!=
0
)
udelay
((
3
*
1000000
*
pinfo
->
bits
)
/
pinfo
->
baud
);
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
/* Send the CPM an initialize command. */
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_STOP_TX
);
/* Stop uart */
if
(
IS_SMC
(
pinfo
))
pinfo
->
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
else
pinfo
->
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
/* Send the CPM an initialize command. */
cpm_line_cr_cmd
(
pinfo
->
port
.
line
,
CPM_CR_INIT_TRX
);
/* init bds */
cpm_uart_initbd
(
pinfo
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
baud
=
uart_get_baud_rate
(
port
,
termios
,
old
,
0
,
port
->
uartclk
/
16
);
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
* 1 or 2 stop bits, minus 1.
* The value 'bits' counts this for us.
*/
cval
=
0
;
scval
=
0
;
/* byte size */
switch
(
termios
->
c_cflag
&
CSIZE
)
{
case
CS5
:
bits
=
5
;
break
;
case
CS6
:
bits
=
6
;
break
;
case
CS7
:
bits
=
7
;
break
;
case
CS8
:
bits
=
8
;
break
;
/* Never happens, but GCC is too dumb to figure it out */
default:
bits
=
8
;
break
;
}
sbits
=
bits
-
5
;
if
(
termios
->
c_cflag
&
CSTOPB
)
{
cval
|=
SMCMR_SL
;
/* Two stops */
scval
|=
SCU_PSMR_SL
;
bits
++
;
}
if
(
termios
->
c_cflag
&
PARENB
)
{
cval
|=
SMCMR_PEN
;
scval
|=
SCU_PSMR_PEN
;
bits
++
;
if
(
!
(
termios
->
c_cflag
&
PARODD
))
{
cval
|=
SMCMR_PM_EVEN
;
scval
|=
(
SCU_PSMR_REVP
|
SCU_PSMR_TEVP
);
}
}
/*
* Set up parity check flag
*/
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
port
->
read_status_mask
=
(
BD_SC_EMPTY
|
BD_SC_OV
);
if
(
termios
->
c_iflag
&
INPCK
)
port
->
read_status_mask
|=
BD_SC_FR
|
BD_SC_PR
;
if
((
termios
->
c_iflag
&
BRKINT
)
||
(
termios
->
c_iflag
&
PARMRK
))
port
->
read_status_mask
|=
BD_SC_BR
;
/*
* Characters to ignore
*/
port
->
ignore_status_mask
=
0
;
if
(
termios
->
c_iflag
&
IGNPAR
)
port
->
ignore_status_mask
|=
BD_SC_PR
|
BD_SC_FR
;
if
(
termios
->
c_iflag
&
IGNBRK
)
{
port
->
ignore_status_mask
|=
BD_SC_BR
;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if
(
termios
->
c_iflag
&
IGNPAR
)
port
->
ignore_status_mask
|=
BD_SC_OV
;
}
/*
* !!! ignore all characters if CREAD is not set
*/
if
((
termios
->
c_cflag
&
CREAD
)
==
0
)
port
->
read_status_mask
&=
~
BD_SC_EMPTY
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
cpm_set_brg
(
pinfo
->
brg
-
1
,
baud
);
/* Start bit has not been added (so don't, because we would just
* subtract it later), and we need to add one for the number of
* stops bits (there is always at least one).
*/
bits
++
;
/* re-init */
if
(
IS_SMC
(
pinfo
))
cpm_uart_init_smc
(
pinfo
,
bits
,
cval
);
else
cpm_uart_init_scc
(
pinfo
,
sbits
,
scval
);
pinfo
->
baud
=
baud
;
pinfo
->
bits
=
bits
;
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
const
char
*
cpm_uart_type
(
struct
uart_port
*
port
)
{
pr_debug
(
"CPM uart[%d]:uart_type
\n
"
,
port
->
line
);
return
port
->
type
==
PORT_CPM
?
"CPM UART"
:
NULL
;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static
int
cpm_uart_verify_port
(
struct
uart_port
*
port
,
struct
serial_struct
*
ser
)
{
int
ret
=
0
;
pr_debug
(
"CPM uart[%d]:verify_port
\n
"
,
port
->
line
);
if
(
ser
->
type
!=
PORT_UNKNOWN
&&
ser
->
type
!=
PORT_CPM
)
ret
=
-
EINVAL
;
if
(
ser
->
irq
<
0
||
ser
->
irq
>=
NR_IRQS
)
ret
=
-
EINVAL
;
if
(
ser
->
baud_base
<
9600
)
ret
=
-
EINVAL
;
return
ret
;
}
/*
* Initialize port. This is called from early_console stuff
* so we have to be careful here !
*/
static
int
cpm_uart_request_port
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
int
ret
;
pr_debug
(
"CPM uart[%d]:request port
\n
"
,
port
->
line
);
if
(
pinfo
->
flags
&
FLAG_CONSOLE
)
return
0
;
/*
* Setup any port IO, connect any baud rate generators,
* etc. This is expected to be handled by board
* dependant code
*/
if
(
pinfo
->
set_lineif
)
pinfo
->
set_lineif
(
pinfo
);
ret
=
cpm_uart_allocbuf
(
pinfo
,
0
);
if
(
ret
)
return
ret
;
return
0
;
}
static
void
cpm_uart_release_port
(
struct
uart_port
*
port
)
{
struct
uart_cpm_port
*
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
if
(
!
(
pinfo
->
flags
&
FLAG_CONSOLE
))
cpm_uart_freebuf
(
pinfo
);
}
/*
* Configure/autoconfigure the port.
*/
static
void
cpm_uart_config_port
(
struct
uart_port
*
port
,
int
flags
)
{
pr_debug
(
"CPM uart[%d]:config_port
\n
"
,
port
->
line
);
if
(
flags
&
UART_CONFIG_TYPE
)
{
port
->
type
=
PORT_CPM
;
cpm_uart_request_port
(
port
);
}
}
static
struct
uart_ops
cpm_uart_pops
=
{
.
tx_empty
=
cpm_uart_tx_empty
,
.
set_mctrl
=
cpm_uart_set_mctrl
,
.
get_mctrl
=
cpm_uart_get_mctrl
,
.
stop_tx
=
cpm_uart_stop_tx
,
.
start_tx
=
cpm_uart_start_tx
,
.
stop_rx
=
cpm_uart_stop_rx
,
.
enable_ms
=
cpm_uart_enable_ms
,
.
break_ctl
=
cpm_uart_break_ctl
,
.
startup
=
cpm_uart_startup
,
.
shutdown
=
cpm_uart_shutdown
,
.
set_termios
=
cpm_uart_set_termios
,
.
type
=
cpm_uart_type
,
.
release_port
=
cpm_uart_release_port
,
.
request_port
=
cpm_uart_request_port
,
.
config_port
=
cpm_uart_config_port
,
.
verify_port
=
cpm_uart_verify_port
,
};
struct
uart_cpm_port
cpm_uart_ports
[
UART_NR
]
=
{
[
UART_SMC1
]
=
{
.
port
=
{
.
irq
=
SMC1_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
.
line
=
UART_SMC1
,
},
.
flags
=
FLAG_SMC
,
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
smc1_lineif
,
},
[
UART_SMC2
]
=
{
.
port
=
{
.
irq
=
SMC2_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
},
.
flags
=
FLAG_SMC
,
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
smc2_lineif
,
},
[
UART_SCC1
]
=
{
.
port
=
{
.
irq
=
SCC1_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
.
line
=
UART_SCC1
,
},
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
scc1_lineif
,
},
[
UART_SCC2
]
=
{
.
port
=
{
.
irq
=
SCC2_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
},
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
scc2_lineif
,
},
[
UART_SCC3
]
=
{
.
port
=
{
.
irq
=
SCC3_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
},
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
scc3_lineif
,
},
[
UART_SCC4
]
=
{
.
port
=
{
.
irq
=
SCC4_IRQ
,
.
ops
=
&
cpm_uart_pops
,
.
iotype
=
SERIAL_IO_MEM
,
.
line
=
UART_SCC4
,
},
.
tx_nrfifos
=
TX_NUM_FIFO
,
.
tx_fifosize
=
TX_BUF_SIZE
,
.
rx_nrfifos
=
RX_NUM_FIFO
,
.
rx_fifosize
=
RX_BUF_SIZE
,
.
set_lineif
=
scc4_lineif
,
},
};
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* Note that this is called with interrupts already disabled
*/
static
void
cpm_uart_console_write
(
struct
console
*
co
,
const
char
*
s
,
u_int
count
)
{
struct
uart_cpm_port
*
pinfo
=
&
cpm_uart_ports
[
cpm_uart_port_map
[
co
->
index
]];
unsigned
int
i
;
volatile
cbd_t
*
bdp
,
*
bdbase
;
volatile
unsigned
char
*
cp
;
/* Get the address of the host memory buffer.
*/
bdp
=
pinfo
->
tx_cur
;
bdbase
=
pinfo
->
tx_bd_base
;
/*
* Now, do each character. This is not as bad as it looks
* since this is a holding FIFO and not a transmitting FIFO.
* We could add the complexity of filling the entire transmit
* buffer, but we would just wait longer between accesses......
*/
for
(
i
=
0
;
i
<
count
;
i
++
,
s
++
)
{
/* Wait for transmitter fifo to empty.
* Ready indicates output is ready, and xmt is doing
* that, not that it is ready for us to send.
*/
while
((
bdp
->
cbd_sc
&
BD_SC_READY
)
!=
0
)
;
/* Send the character out.
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
if
((
uint
)
(
bdp
->
cbd_bufaddr
)
>
(
uint
)
CPM_ADDR
)
cp
=
(
unsigned
char
*
)
(
bdp
->
cbd_bufaddr
);
else
cp
=
bus_to_virt
(
bdp
->
cbd_bufaddr
);
*
cp
=
*
s
;
bdp
->
cbd_datlen
=
1
;
bdp
->
cbd_sc
|=
BD_SC_READY
;
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
bdp
=
bdbase
;
else
bdp
++
;
/* if a LF, also do CR... */
if
(
*
s
==
10
)
{
while
((
bdp
->
cbd_sc
&
BD_SC_READY
)
!=
0
)
;
if
((
uint
)
(
bdp
->
cbd_bufaddr
)
>
(
uint
)
CPM_ADDR
)
cp
=
(
unsigned
char
*
)
(
bdp
->
cbd_bufaddr
);
else
cp
=
bus_to_virt
(
bdp
->
cbd_bufaddr
);
*
cp
=
13
;
bdp
->
cbd_datlen
=
1
;
bdp
->
cbd_sc
|=
BD_SC_READY
;
if
(
bdp
->
cbd_sc
&
BD_SC_WRAP
)
bdp
=
bdbase
;
else
bdp
++
;
}
}
/*
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
while
((
bdp
->
cbd_sc
&
BD_SC_READY
)
!=
0
)
;
pinfo
->
tx_cur
=
(
volatile
cbd_t
*
)
bdp
;
}
/*
* Setup console. Be careful is called early !
*/
static
int
__init
cpm_uart_console_setup
(
struct
console
*
co
,
char
*
options
)
{
struct
uart_port
*
port
;
struct
uart_cpm_port
*
pinfo
;
int
baud
=
38400
;
int
bits
=
8
;
int
parity
=
'n'
;
int
flow
=
'n'
;
int
ret
;
port
=
(
struct
uart_port
*
)
&
cpm_uart_ports
[
cpm_uart_port_map
[
co
->
index
]];
pinfo
=
(
struct
uart_cpm_port
*
)
port
;
pinfo
->
flags
|=
FLAG_CONSOLE
;
if
(
options
)
{
uart_parse_options
(
options
,
&
baud
,
&
parity
,
&
bits
,
&
flow
);
}
else
{
bd_t
*
bd
=
(
bd_t
*
)
__res
;
if
(
bd
->
bi_baudrate
)
baud
=
bd
->
bi_baudrate
;
else
baud
=
9600
;
}
/*
* Setup any port IO, connect any baud rate generators,
* etc. This is expected to be handled by board
* dependant code
*/
if
(
pinfo
->
set_lineif
)
pinfo
->
set_lineif
(
pinfo
);
ret
=
cpm_uart_allocbuf
(
pinfo
,
1
);
if
(
ret
)
return
ret
;
uart_set_options
(
port
,
co
,
baud
,
parity
,
bits
,
flow
);
return
0
;
}
extern
struct
uart_driver
cpm_reg
;
static
struct
console
cpm_scc_uart_console
=
{
.
name
"ttyCPM"
,
.
write
cpm_uart_console_write
,
.
device
uart_console_device
,
.
setup
cpm_uart_console_setup
,
.
flags
CON_PRINTBUFFER
,
.
index
-
1
,
.
data
=
&
cpm_reg
,
};
int
__init
cpm_uart_console_init
(
void
)
{
int
ret
=
cpm_uart_init_portdesc
();
if
(
!
ret
)
register_console
(
&
cpm_scc_uart_console
);
return
ret
;
}
console_initcall
(
cpm_uart_console_init
);
#define CPM_UART_CONSOLE &cpm_scc_uart_console
#else
#define CPM_UART_CONSOLE NULL
#endif
static
struct
uart_driver
cpm_reg
=
{
.
owner
=
THIS_MODULE
,
.
driver_name
=
"ttyCPM"
,
.
dev_name
=
"ttyCPM"
,
.
major
=
SERIAL_CPM_MAJOR
,
.
minor
=
SERIAL_CPM_MINOR
,
.
cons
=
CPM_UART_CONSOLE
,
};
static
int
__init
cpm_uart_init
(
void
)
{
int
ret
,
i
;
printk
(
KERN_INFO
"Serial: CPM driver $Revision: 0.01 $
\n
"
);
#ifndef CONFIG_SERIAL_CPM_CONSOLE
ret
=
cpm_uart_init_portdesc
();
if
(
ret
)
return
ret
;
#endif
cpm_reg
.
nr
=
cpm_uart_nr
;
ret
=
uart_register_driver
(
&
cpm_reg
);
if
(
ret
)
return
ret
;
for
(
i
=
0
;
i
<
cpm_uart_nr
;
i
++
)
{
int
con
=
cpm_uart_port_map
[
i
];
cpm_uart_ports
[
con
].
port
.
line
=
i
;
cpm_uart_ports
[
con
].
port
.
flags
=
UPF_BOOT_AUTOCONF
;
uart_add_one_port
(
&
cpm_reg
,
&
cpm_uart_ports
[
con
].
port
);
}
return
ret
;
}
static
void
__exit
cpm_uart_exit
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
cpm_uart_nr
;
i
++
)
{
int
con
=
cpm_uart_port_map
[
i
];
uart_remove_one_port
(
&
cpm_reg
,
&
cpm_uart_ports
[
con
].
port
);
}
uart_unregister_driver
(
&
cpm_reg
);
}
module_init
(
cpm_uart_init
);
module_exit
(
cpm_uart_exit
);
MODULE_AUTHOR
(
"Kumar Gala/Antoniou Pantelis"
);
MODULE_DESCRIPTION
(
"CPM SCC/SMC port driver $Revision: 0.01 $"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_CHARDEV
(
SERIAL_CPM_MAJOR
,
SERIAL_CPM_MINOR
);
drivers/serial/cpm_uart/cpm_uart_cpm1.c
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
*
* Maintainer: Kumar Gala (kumar.gala@motorola.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Motorola, Inc
* (C) 2004 Intracom, S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void
cpm_line_cr_cmd
(
int
line
,
int
cmd
)
{
ushort
val
;
volatile
cpm8xx_t
*
cp
=
cpmp
;
switch
(
line
)
{
case
UART_SMC1
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SMC1
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SMC2
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SMC2
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC1
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SCC1
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC2
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SCC2
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC3
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SCC3
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC4
:
val
=
mk_cr_cmd
(
CPM_CR_CH_SCC4
,
cmd
)
|
CPM_CR_FLG
;
break
;
default:
return
;
}
cp
->
cp_cpcr
=
val
;
while
(
cp
->
cp_cpcr
&
CPM_CR_FLG
)
;
}
void
smc1_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
cpm8xx_t
*
cp
=
cpmp
;
cp
->
cp_pbpar
|=
0x000000c0
;
cp
->
cp_pbdir
&=
~
0x000000c0
;
cp
->
cp_pbodr
&=
~
0x000000c0
;
pinfo
->
brg
=
1
;
}
void
smc2_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
/* XXX SMC2: insert port configuration here */
pinfo
->
brg
=
2
;
}
void
scc1_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
/* XXX SCC1: insert port configuration here */
pinfo
->
brg
=
1
;
}
void
scc2_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
/* XXX SCC2: insert port configuration here */
pinfo
->
brg
=
2
;
}
void
scc3_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
/* XXX SCC3: insert port configuration here */
pinfo
->
brg
=
3
;
}
void
scc4_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
/* XXX SCC4: insert port configuration here */
pinfo
->
brg
=
4
;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int
cpm_uart_allocbuf
(
struct
uart_cpm_port
*
pinfo
,
unsigned
int
is_con
)
{
int
dpmemsz
,
memsz
;
uint
dp_addr
;
u8
*
mem_addr
;
dma_addr_t
dma_addr
;
pr_debug
(
"CPM uart[%d]:allocbuf
\n
"
,
pinfo
->
port
.
line
);
dpmemsz
=
sizeof
(
cbd_t
)
*
(
pinfo
->
rx_nrfifos
+
pinfo
->
tx_nrfifos
);
dp_addr
=
m8xx_cpm_dpalloc
(
dpmemsz
);
if
(
dp_addr
==
CPM_DP_NOSPACE
)
{
printk
(
KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors
\n
"
);
return
-
ENOMEM
;
}
memsz
=
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
)
+
L1_CACHE_ALIGN
(
pinfo
->
tx_nrfifos
*
pinfo
->
tx_fifosize
);
if
(
is_con
)
{
mem_addr
=
(
u8
*
)
m8xx_cpm_hostalloc
(
memsz
);
dma_addr
=
0
;
}
else
mem_addr
=
dma_alloc_coherent
(
NULL
,
memsz
,
&
dma_addr
,
GFP_KERNEL
);
/* We cant really from memory allocated via cpm2_dpalloc,
* fix this if in the future we can */
if
(
mem_addr
==
NULL
)
{
/* XXX cpm_dpalloc does not yet free */
printk
(
KERN_ERR
"cpm_uart_cpm1.c: could not allocate coherent memory
\n
"
);
return
-
ENOMEM
;
}
pinfo
->
dp_addr
=
dp_addr
;
pinfo
->
mem_addr
=
mem_addr
;
pinfo
->
dma_addr
=
dma_addr
;
pinfo
->
rx_buf
=
mem_addr
;
pinfo
->
tx_buf
=
pinfo
->
rx_buf
+
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
);
pinfo
->
rx_bd_base
=
(
volatile
cbd_t
*
)(
DPRAM_BASE
+
dp_addr
);
pinfo
->
tx_bd_base
=
pinfo
->
rx_bd_base
+
pinfo
->
rx_nrfifos
;
return
0
;
}
void
cpm_uart_freebuf
(
struct
uart_cpm_port
*
pinfo
)
{
dma_free_coherent
(
NULL
,
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
)
+
L1_CACHE_ALIGN
(
pinfo
->
tx_nrfifos
*
pinfo
->
tx_fifosize
),
pinfo
->
mem_addr
,
pinfo
->
dma_addr
);
/* XXX cannot free dpmem yet */
}
/* Setup any dynamic params in the uart desc */
int
cpm_uart_init_portdesc
(
void
)
{
pr_debug
(
"CPM uart[-]:init portdesc
\n
"
);
cpm_uart_nr
=
0
;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports
[
UART_SMC1
].
smcp
=
&
cpmp
->
cp_smc
[
0
];
cpm_uart_ports
[
UART_SMC1
].
smcup
=
(
smc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SMC1
];
cpm_uart_ports
[
UART_SMC1
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_smc
[
0
];
cpm_uart_ports
[
UART_SMC1
].
smcp
->
smc_smcm
|=
(
SMCM_RX
|
SMCM_TX
);
cpm_uart_ports
[
UART_SMC1
].
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
cpm_uart_ports
[
UART_SMC1
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SMC1
;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports
[
UART_SMC2
].
smcp
=
&
cpmp
->
cp_smc
[
1
];
cpm_uart_ports
[
UART_SMC2
].
smcup
=
(
smc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SMC2
];
cpm_uart_ports
[
UART_SMC2
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_smc
[
1
];
cpm_uart_ports
[
UART_SMC2
].
smcp
->
smc_smcm
|=
(
SMCM_RX
|
SMCM_TX
);
cpm_uart_ports
[
UART_SMC2
].
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
cpm_uart_ports
[
UART_SMC2
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SMC2
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports
[
UART_SCC1
].
sccp
=
&
cpmp
->
cp_scc
[
0
];
cpm_uart_ports
[
UART_SCC1
].
sccup
=
(
scc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SCC1
];
cpm_uart_ports
[
UART_SCC1
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_scc
[
0
];
cpm_uart_ports
[
UART_SCC1
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC1
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC1
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC1
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports
[
UART_SCC2
].
sccp
=
&
cpmp
->
cp_scc
[
1
];
cpm_uart_ports
[
UART_SCC2
].
sccup
=
(
scc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SCC2
];
cpm_uart_ports
[
UART_SCC2
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_scc
[
1
];
cpm_uart_ports
[
UART_SCC2
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC2
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC2
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC2
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports
[
UART_SCC3
].
sccp
=
&
cpmp
->
cp_scc
[
2
];
cpm_uart_ports
[
UART_SCC3
].
sccup
=
(
scc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SCC3
];
cpm_uart_ports
[
UART_SCC3
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_scc
[
2
];
cpm_uart_ports
[
UART_SCC3
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC3
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC3
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC3
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports
[
UART_SCC4
].
sccp
=
&
cpmp
->
cp_scc
[
3
];
cpm_uart_ports
[
UART_SCC4
].
sccup
=
(
scc_uart_t
*
)
&
cpmp
->
cp_dparam
[
PROFF_SCC4
];
cpm_uart_ports
[
UART_SCC4
].
port
.
mapbase
=
(
unsigned
long
)
&
cpmp
->
cp_scc
[
3
];
cpm_uart_ports
[
UART_SCC4
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC4
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC4
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC4
;
#endif
return
0
;
}
drivers/serial/cpm_uart/cpm_uart_cpm1.h
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart_cpm1.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm1
*
*/
#ifndef CPM_UART_CPM1_H
#define CPM_UART_CPM1_H
#include <asm/commproc.h>
/* defines for IRQs */
#define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1)
#define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2)
#define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1)
#define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2)
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
/* the CPM address */
#define CPM_ADDR IMAP_ADDR
static
inline
void
cpm_set_brg
(
int
brg
,
int
baud
)
{
m8xx_cpm_setbrg
(
brg
,
baud
);
}
static
inline
void
cpm_set_scc_fcr
(
volatile
scc_uart_t
*
sup
)
{
sup
->
scc_genscc
.
scc_rfcr
=
SMC_EB
;
sup
->
scc_genscc
.
scc_tfcr
=
SMC_EB
;
}
static
inline
void
cpm_set_smc_fcr
(
volatile
smc_uart_t
*
up
)
{
up
->
smc_rfcr
=
SMC_EB
;
up
->
smc_tfcr
=
SMC_EB
;
}
#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0])
#endif
drivers/serial/cpm_uart/cpm_uart_cpm2.c
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart_cpm2.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
*
* Maintainer: Kumar Gala (kumar.gala@motorola.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Motorola, Inc
* (C) 2004 Intracom, S.A.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void
cpm_line_cr_cmd
(
int
line
,
int
cmd
)
{
volatile
cpm_cpm2_t
*
cp
=
cpmp
;
ulong
val
;
switch
(
line
)
{
case
UART_SMC1
:
val
=
mk_cr_cmd
(
CPM_CR_SMC1_PAGE
,
CPM_CR_SMC1_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SMC2
:
val
=
mk_cr_cmd
(
CPM_CR_SMC2_PAGE
,
CPM_CR_SMC2_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC1
:
val
=
mk_cr_cmd
(
CPM_CR_SCC1_PAGE
,
CPM_CR_SCC1_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC2
:
val
=
mk_cr_cmd
(
CPM_CR_SCC2_PAGE
,
CPM_CR_SCC2_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC3
:
val
=
mk_cr_cmd
(
CPM_CR_SCC3_PAGE
,
CPM_CR_SCC3_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
case
UART_SCC4
:
val
=
mk_cr_cmd
(
CPM_CR_SCC4_PAGE
,
CPM_CR_SCC4_SBLOCK
,
0
,
cmd
)
|
CPM_CR_FLG
;
break
;
default:
return
;
}
cp
->
cp_cpcr
=
val
;
while
(
cp
->
cp_cpcr
&
CPM_CR_FLG
)
;
}
void
smc1_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
/* SMC1 is only on port D */
io
->
iop_ppard
|=
0x00c00000
;
io
->
iop_pdird
|=
0x00400000
;
io
->
iop_pdird
&=
~
0x00800000
;
io
->
iop_psord
&=
~
0x00c00000
;
/* Wire BRG1 to SMC1 */
cpm2_immr
->
im_cpmux
.
cmx_smr
&=
0x0f
;
pinfo
->
brg
=
1
;
}
void
smc2_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
/* SMC2 is only on port A */
io
->
iop_ppara
|=
0x00c00000
;
io
->
iop_pdira
|=
0x00400000
;
io
->
iop_pdira
&=
~
0x00800000
;
io
->
iop_psora
&=
~
0x00c00000
;
/* Wire BRG2 to SMC2 */
cpm2_immr
->
im_cpmux
.
cmx_smr
&=
0xf0
;
pinfo
->
brg
=
2
;
}
void
scc1_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
/* Use Port D for SCC1 instead of other functions. */
io
->
iop_ppard
|=
0x00000003
;
io
->
iop_psord
&=
~
0x00000001
;
/* Rx */
io
->
iop_psord
|=
0x00000002
;
/* Tx */
io
->
iop_pdird
&=
~
0x00000001
;
/* Rx */
io
->
iop_pdird
|=
0x00000002
;
/* Tx */
/* Wire BRG1 to SCC1 */
cpm2_immr
->
im_cpmux
.
cmx_scr
&=
~
0x00ffffff
;
cpm2_immr
->
im_cpmux
.
cmx_scr
|=
0x00000000
;
pinfo
->
brg
=
1
;
}
void
scc2_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
io
->
iop_pparb
|=
0x008b0000
;
io
->
iop_pdirb
|=
0x00880000
;
io
->
iop_psorb
|=
0x00880000
;
io
->
iop_pdirb
&=
~
0x00030000
;
io
->
iop_psorb
&=
~
0x00030000
;
cpm2_immr
->
im_cpmux
.
cmx_scr
&=
~
0xff00ffff
;
cpm2_immr
->
im_cpmux
.
cmx_scr
|=
0x00090000
;
pinfo
->
brg
=
2
;
}
void
scc3_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
io
->
iop_pparb
|=
0x008b0000
;
io
->
iop_pdirb
|=
0x00880000
;
io
->
iop_psorb
|=
0x00880000
;
io
->
iop_pdirb
&=
~
0x00030000
;
io
->
iop_psorb
&=
~
0x00030000
;
cpm2_immr
->
im_cpmux
.
cmx_scr
&=
~
0xffff00ff
;
cpm2_immr
->
im_cpmux
.
cmx_scr
|=
0x00001200
;
pinfo
->
brg
=
3
;
}
void
scc4_lineif
(
struct
uart_cpm_port
*
pinfo
)
{
volatile
iop_cpm2_t
*
io
=
&
cpm2_immr
->
im_ioport
;
io
->
iop_ppard
|=
0x00000600
;
io
->
iop_psord
&=
~
0x00000600
;
/* Tx/Rx */
io
->
iop_pdird
&=
~
0x00000200
;
/* Rx */
io
->
iop_pdird
|=
0x00000400
;
/* Tx */
cpm2_immr
->
im_cpmux
.
cmx_scr
&=
~
0xffffff00
;
cpm2_immr
->
im_cpmux
.
cmx_scr
|=
0x0000001b
;
pinfo
->
brg
=
4
;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int
cpm_uart_allocbuf
(
struct
uart_cpm_port
*
pinfo
,
unsigned
int
is_con
)
{
int
dpmemsz
,
memsz
;
uint
dp_addr
;
u8
*
mem_addr
;
dma_addr_t
dma_addr
=
0
;
pr_debug
(
"CPM uart[%d]:allocbuf
\n
"
,
pinfo
->
port
.
line
);
dpmemsz
=
sizeof
(
cbd_t
)
*
(
pinfo
->
rx_nrfifos
+
pinfo
->
tx_nrfifos
);
dp_addr
=
cpm2_dpalloc
(
dpmemsz
,
8
);
if
(
dp_addr
==
CPM_DP_NOSPACE
)
{
printk
(
KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors
\n
"
);
return
-
ENOMEM
;
}
memsz
=
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
)
+
L1_CACHE_ALIGN
(
pinfo
->
tx_nrfifos
*
pinfo
->
tx_fifosize
);
if
(
is_con
)
mem_addr
=
alloc_bootmem
(
memsz
);
else
mem_addr
=
dma_alloc_coherent
(
NULL
,
memsz
,
&
dma_addr
,
GFP_KERNEL
);
/* We cant really from memory allocated via cpm2_dpalloc,
* fix this if in the future we can */
if
(
mem_addr
==
NULL
)
{
/* XXX cpm_dpalloc does not yet free */
printk
(
KERN_ERR
"cpm_uart_cpm1.c: could not allocate coherent memory
\n
"
);
return
-
ENOMEM
;
}
pinfo
->
dp_addr
=
dp_addr
;
pinfo
->
mem_addr
=
mem_addr
;
pinfo
->
dma_addr
=
dma_addr
;
pinfo
->
rx_buf
=
mem_addr
;
pinfo
->
tx_buf
=
pinfo
->
rx_buf
+
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
);
pinfo
->
rx_bd_base
=
(
volatile
cbd_t
*
)(
DPRAM_BASE
+
dp_addr
);
pinfo
->
tx_bd_base
=
pinfo
->
rx_bd_base
+
pinfo
->
rx_nrfifos
;
return
0
;
}
void
cpm_uart_freebuf
(
struct
uart_cpm_port
*
pinfo
)
{
dma_free_coherent
(
NULL
,
L1_CACHE_ALIGN
(
pinfo
->
rx_nrfifos
*
pinfo
->
rx_fifosize
)
+
L1_CACHE_ALIGN
(
pinfo
->
tx_nrfifos
*
pinfo
->
tx_fifosize
),
pinfo
->
mem_addr
,
pinfo
->
dma_addr
);
/* XXX cannot free dpmem yet */
}
/* Setup any dynamic params in the uart desc */
int
cpm_uart_init_portdesc
(
void
)
{
pr_debug
(
"CPM uart[-]:init portdesc
\n
"
);
cpm_uart_nr
=
0
;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports
[
UART_SMC1
].
smcp
=
(
smc_t
*
)
&
cpm2_immr
->
im_smc
[
0
];
cpm_uart_ports
[
UART_SMC1
].
smcup
=
(
smc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SMC1
];
cpm_uart_ports
[
UART_SMC1
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_smc
[
0
];
cpm_uart_ports
[
UART_SMC1
].
smcp
->
smc_smcm
|=
(
SMCM_RX
|
SMCM_TX
);
cpm_uart_ports
[
UART_SMC1
].
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
cpm_uart_ports
[
UART_SMC1
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SMC1
;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports
[
UART_SMC2
].
smcp
=
(
smc_t
*
)
&
cpm2_immr
->
im_smc
[
1
];
cpm_uart_ports
[
UART_SMC2
].
smcup
=
(
smc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SMC2
];
cpm_uart_ports
[
UART_SMC2
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_smc
[
1
];
cpm_uart_ports
[
UART_SMC2
].
smcp
->
smc_smcm
|=
(
SMCM_RX
|
SMCM_TX
);
cpm_uart_ports
[
UART_SMC2
].
smcp
->
smc_smcmr
&=
~
(
SMCMR_REN
|
SMCMR_TEN
);
cpm_uart_ports
[
UART_SMC2
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SMC2
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports
[
UART_SCC1
].
sccp
=
(
scc_t
*
)
&
cpm2_immr
->
im_scc
[
0
];
cpm_uart_ports
[
UART_SCC1
].
sccup
=
(
scc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SCC1
];
cpm_uart_ports
[
UART_SCC1
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_scc
[
0
];
cpm_uart_ports
[
UART_SCC1
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC1
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC1
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC1
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports
[
UART_SCC2
].
sccp
=
(
scc_t
*
)
&
cpm2_immr
->
im_scc
[
1
];
cpm_uart_ports
[
UART_SCC2
].
sccup
=
(
scc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SCC2
];
cpm_uart_ports
[
UART_SCC2
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_scc
[
1
];
cpm_uart_ports
[
UART_SCC2
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC2
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC2
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC2
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports
[
UART_SCC3
].
sccp
=
(
scc_t
*
)
&
cpm2_immr
->
im_scc
[
2
];
cpm_uart_ports
[
UART_SCC3
].
sccup
=
(
scc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SCC3
];
cpm_uart_ports
[
UART_SCC3
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_scc
[
2
];
cpm_uart_ports
[
UART_SCC3
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC3
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC3
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC3
;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports
[
UART_SCC4
].
sccp
=
(
scc_t
*
)
&
cpm2_immr
->
im_scc
[
3
];
cpm_uart_ports
[
UART_SCC4
].
sccup
=
(
scc_uart_t
*
)
&
cpm2_immr
->
im_dprambase
[
PROFF_SCC4
];
cpm_uart_ports
[
UART_SCC4
].
port
.
mapbase
=
(
unsigned
long
)
&
cpm2_immr
->
im_scc
[
3
];
cpm_uart_ports
[
UART_SCC4
].
sccp
->
scc_sccm
&=
~
(
UART_SCCM_TX
|
UART_SCCM_RX
);
cpm_uart_ports
[
UART_SCC4
].
sccp
->
scc_gsmrl
&=
~
(
SCC_GSMRL_ENR
|
SCC_GSMRL_ENT
);
cpm_uart_ports
[
UART_SCC4
].
port
.
uartclk
=
(((
bd_t
*
)
__res
)
->
bi_intfreq
);
cpm_uart_port_map
[
cpm_uart_nr
++
]
=
UART_SCC4
;
#endif
return
0
;
}
drivers/serial/cpm_uart/cpm_uart_cpm2.h
0 → 100644
View file @
221bfb31
/*
* linux/drivers/serial/cpm_uart_cpm2.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm2
*
*/
#ifndef CPM_UART_CPM2_H
#define CPM_UART_CPM2_H
#include <asm/cpm2.h>
/* defines for IRQs */
#define SMC1_IRQ SIU_INT_SMC1
#define SMC2_IRQ SIU_INT_SMC2
#define SCC1_IRQ SIU_INT_SCC1
#define SCC2_IRQ SIU_INT_SCC2
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
/* the CPM address */
#define CPM_ADDR CPM_MAP_ADDR
static
inline
void
cpm_set_brg
(
int
brg
,
int
baud
)
{
cpm2_setbrg
(
brg
,
baud
);
}
static
inline
void
cpm_set_scc_fcr
(
volatile
scc_uart_t
*
sup
)
{
sup
->
scc_genscc
.
scc_rfcr
=
CPMFCR_GBL
|
CPMFCR_EB
;
sup
->
scc_genscc
.
scc_tfcr
=
CPMFCR_GBL
|
CPMFCR_EB
;
}
static
inline
void
cpm_set_smc_fcr
(
volatile
smc_uart_t
*
up
)
{
up
->
smc_rfcr
=
CPMFCR_GBL
|
CPMFCR_EB
;
up
->
smc_tfcr
=
CPMFCR_GBL
|
CPMFCR_EB
;
}
#define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0])
#endif
include/linux/serial_core.h
View file @
221bfb31
...
...
@@ -88,6 +88,9 @@
/* SGI IP22 aka Indy / Challenge S / Indigo 2 */
#define PORT_IP22ZILOG 56
/* PPC CPM type number */
#define PORT_CPM 57
#ifdef __KERNEL__
#include <linux/config.h>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment