Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
36764631
Commit
36764631
authored
Jun 29, 2006
by
David S. Miller
Committed by
David S. Miller
Jun 29, 2006
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SERIAL] sunzilog: Convert to of_driver.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
8f96cd1a
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
258 additions
and
527 deletions
+258
-527
drivers/serial/sunzilog.c
drivers/serial/sunzilog.c
+258
-527
No files found.
drivers/serial/sunzilog.c
View file @
36764631
/*
* sunzilog.c
/* sunzilog.c: Zilog serial driver for Sparc systems.
*
* Driver for Zilog serial chips found on Sun workstations and
* servers. This driver could actually be made more generic.
...
...
@@ -10,7 +9,7 @@
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there.
*
* Copyright (C) 2002
David S. Miller (davem@redhat.com
)
* Copyright (C) 2002
, 2006 David S. Miller (davem@davemloft.net
)
*/
#include <linux/config.h>
...
...
@@ -38,10 +37,8 @@
#include <asm/io.h>
#include <asm/irq.h>
#ifdef CONFIG_SPARC64
#include <asm/fhc.h>
#endif
#include <asm/sbus.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
...
...
@@ -65,7 +62,7 @@
#define ZSDELAY()
#define ZSDELAY_LONG()
#define ZS_WSYNC(__channel) \
sbus_
readb(&((__channel)->control))
readb(&((__channel)->control))
#endif
static
int
num_sunzilog
;
...
...
@@ -107,7 +104,7 @@ struct uart_sunzilog_port {
unsigned
char
prev_status
;
#ifdef CONFIG_SERIO
struct
serio
*
serio
;
struct
serio
serio
;
int
serio_open
;
#endif
};
...
...
@@ -138,9 +135,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
{
unsigned
char
retval
;
sbus_
writeb
(
reg
,
&
channel
->
control
);
writeb
(
reg
,
&
channel
->
control
);
ZSDELAY
();
retval
=
sbus_
readb
(
&
channel
->
control
);
retval
=
readb
(
&
channel
->
control
);
ZSDELAY
();
return
retval
;
...
...
@@ -149,9 +146,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
static
void
write_zsreg
(
struct
zilog_channel
__iomem
*
channel
,
unsigned
char
reg
,
unsigned
char
value
)
{
sbus_
writeb
(
reg
,
&
channel
->
control
);
writeb
(
reg
,
&
channel
->
control
);
ZSDELAY
();
sbus_
writeb
(
value
,
&
channel
->
control
);
writeb
(
value
,
&
channel
->
control
);
ZSDELAY
();
}
...
...
@@ -162,17 +159,17 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
for
(
i
=
0
;
i
<
32
;
i
++
)
{
unsigned
char
regval
;
regval
=
sbus_
readb
(
&
channel
->
control
);
regval
=
readb
(
&
channel
->
control
);
ZSDELAY
();
if
(
regval
&
Rx_CH_AV
)
break
;
regval
=
read_zsreg
(
channel
,
R1
);
sbus_
readb
(
&
channel
->
data
);
readb
(
&
channel
->
data
);
ZSDELAY
();
if
(
regval
&
(
PAR_ERR
|
Rx_OVR
|
CRC_ERR
))
{
sbus_
writeb
(
ERR_RES
,
&
channel
->
control
);
writeb
(
ERR_RES
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
}
...
...
@@ -194,7 +191,7 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
udelay
(
100
);
}
sbus_
writeb
(
ERR_RES
,
&
channel
->
control
);
writeb
(
ERR_RES
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -291,7 +288,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
/* Stop-A is handled by drivers/char/keyboard.c now. */
#ifdef CONFIG_SERIO
if
(
up
->
serio_open
)
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
#endif
}
else
if
(
ZS_IS_MOUSE
(
up
))
{
int
ret
=
suncore_mouse_baud_detection
(
ch
,
is_break
);
...
...
@@ -306,7 +303,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
case
0
:
#ifdef CONFIG_SERIO
if
(
up
->
serio_open
)
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
#endif
break
;
};
...
...
@@ -330,12 +327,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
r1
=
read_zsreg
(
channel
,
R1
);
if
(
r1
&
(
PAR_ERR
|
Rx_OVR
|
CRC_ERR
))
{
sbus_
writeb
(
ERR_RES
,
&
channel
->
control
);
writeb
(
ERR_RES
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
}
ch
=
sbus_
readb
(
&
channel
->
control
);
ch
=
readb
(
&
channel
->
control
);
ZSDELAY
();
/* This funny hack depends upon BRK_ABRT not interfering
...
...
@@ -347,7 +344,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
if
(
!
(
ch
&
Rx_CH_AV
))
break
;
ch
=
sbus_
readb
(
&
channel
->
data
);
ch
=
readb
(
&
channel
->
data
);
ZSDELAY
();
ch
&=
up
->
parity_mask
;
...
...
@@ -406,10 +403,10 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
{
unsigned
char
status
;
status
=
sbus_
readb
(
&
channel
->
control
);
status
=
readb
(
&
channel
->
control
);
ZSDELAY
();
sbus_
writeb
(
RES_EXT_INT
,
&
channel
->
control
);
writeb
(
RES_EXT_INT
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -421,7 +418,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
* confusing the PROM.
*/
while
(
1
)
{
status
=
sbus_
readb
(
&
channel
->
control
);
status
=
readb
(
&
channel
->
control
);
ZSDELAY
();
if
(
!
(
status
&
BRK_ABRT
))
break
;
...
...
@@ -458,7 +455,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
struct
circ_buf
*
xmit
;
if
(
ZS_IS_CONS
(
up
))
{
unsigned
char
status
=
sbus_
readb
(
&
channel
->
control
);
unsigned
char
status
=
readb
(
&
channel
->
control
);
ZSDELAY
();
/* TX still busy? Just wait for the next TX done interrupt.
...
...
@@ -487,7 +484,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
if
(
up
->
port
.
x_char
)
{
up
->
flags
|=
SUNZILOG_FLAG_TX_ACTIVE
;
sbus_
writeb
(
up
->
port
.
x_char
,
&
channel
->
data
);
writeb
(
up
->
port
.
x_char
,
&
channel
->
data
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -506,7 +503,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
goto
ack_tx_int
;
up
->
flags
|=
SUNZILOG_FLAG_TX_ACTIVE
;
sbus_
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
channel
->
data
);
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
channel
->
data
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -519,7 +516,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
return
;
ack_tx_int:
sbus_
writeb
(
RES_Tx_P
,
&
channel
->
control
);
writeb
(
RES_Tx_P
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
}
...
...
@@ -540,7 +537,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
/* Channel A */
tty
=
NULL
;
if
(
r3
&
(
CHAEXT
|
CHATxIP
|
CHARxIP
))
{
sbus_
writeb
(
RES_H_IUS
,
&
channel
->
control
);
writeb
(
RES_H_IUS
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -563,7 +560,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
spin_lock
(
&
up
->
port
.
lock
);
tty
=
NULL
;
if
(
r3
&
(
CHBEXT
|
CHBTxIP
|
CHBRxIP
))
{
sbus_
writeb
(
RES_H_IUS
,
&
channel
->
control
);
writeb
(
RES_H_IUS
,
&
channel
->
control
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -594,7 +591,7 @@ static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *p
unsigned
char
status
;
channel
=
ZILOG_CHANNEL_FROM_PORT
(
port
);
status
=
sbus_
readb
(
&
channel
->
control
);
status
=
readb
(
&
channel
->
control
);
ZSDELAY
();
return
status
;
...
...
@@ -682,7 +679,7 @@ static void sunzilog_start_tx(struct uart_port *port)
up
->
flags
|=
SUNZILOG_FLAG_TX_ACTIVE
;
up
->
flags
&=
~
SUNZILOG_FLAG_TX_STOPPED
;
status
=
sbus_
readb
(
&
channel
->
control
);
status
=
readb
(
&
channel
->
control
);
ZSDELAY
();
/* TX busy? Just wait for the TX done interrupt. */
...
...
@@ -693,7 +690,7 @@ static void sunzilog_start_tx(struct uart_port *port)
* IRQ sending engine.
*/
if
(
port
->
x_char
)
{
sbus_
writeb
(
port
->
x_char
,
&
channel
->
data
);
writeb
(
port
->
x_char
,
&
channel
->
data
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -702,7 +699,7 @@ static void sunzilog_start_tx(struct uart_port *port)
}
else
{
struct
circ_buf
*
xmit
=
&
port
->
info
->
xmit
;
sbus_
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
channel
->
data
);
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
channel
->
data
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
...
...
@@ -779,7 +776,7 @@ static void __sunzilog_startup(struct uart_sunzilog_port *up)
struct
zilog_channel
__iomem
*
channel
;
channel
=
ZILOG_CHANNEL_FROM_PORT
(
&
up
->
port
);
up
->
prev_status
=
sbus_
readb
(
&
channel
->
control
);
up
->
prev_status
=
readb
(
&
channel
->
control
);
/* Enable receiver and transmitter. */
up
->
curregs
[
R3
]
|=
RxENAB
;
...
...
@@ -963,7 +960,7 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios,
static
const
char
*
sunzilog_type
(
struct
uart_port
*
port
)
{
return
"
SunZilog
"
;
return
"
zs
"
;
}
/* We do not request/release mappings of the registers here, this
...
...
@@ -1012,7 +1009,6 @@ static struct uart_sunzilog_port *sunzilog_port_table;
static
struct
zilog_layout
__iomem
**
sunzilog_chip_regs
;
static
struct
uart_sunzilog_port
*
sunzilog_irq_chain
;
static
int
zilog_irq
=
-
1
;
static
struct
uart_driver
sunzilog_reg
=
{
.
owner
=
THIS_MODULE
,
...
...
@@ -1021,232 +1017,47 @@ static struct uart_driver sunzilog_reg = {
.
major
=
TTY_MAJOR
,
};
static
void
*
__init
alloc_one_table
(
unsigned
long
size
)
{
void
*
ret
;
ret
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
ret
!=
NULL
)
memset
(
ret
,
0
,
size
);
return
ret
;
}
static
void
__init
sunzilog_alloc_tables
(
void
)
{
sunzilog_port_table
=
alloc_one_table
(
NUM_CHANNELS
*
sizeof
(
struct
uart_sunzilog_port
));
sunzilog_chip_regs
=
alloc_one_table
(
NUM_SUNZILOG
*
sizeof
(
struct
zilog_layout
__iomem
*
));
if
(
sunzilog_port_table
==
NULL
||
sunzilog_chip_regs
==
NULL
)
{
prom_printf
(
"SunZilog: Cannot allocate tables.
\n
"
);
prom_halt
();
}
}
#ifdef CONFIG_SPARC64
/* We used to attempt to use the address property of the Zilog device node
* but that totally is not necessary on sparc64.
*/
static
struct
zilog_layout
__iomem
*
__init
get_zs_sun4u
(
int
chip
,
int
zsnode
)
static
int
__init
sunzilog_alloc_tables
(
void
)
{
void
__iomem
*
mapped_addr
;
unsigned
int
sun4u_ino
;
struct
sbus_bus
*
sbus
=
NULL
;
struct
sbus_dev
*
sdev
=
NULL
;
int
err
;
if
(
central_bus
==
NULL
)
{
for_each_sbus
(
sbus
)
{
for_each_sbusdev
(
sdev
,
sbus
)
{
if
(
sdev
->
prom_node
==
zsnode
)
goto
found
;
}
}
}
found:
if
(
sdev
==
NULL
&&
central_bus
==
NULL
)
{
prom_printf
(
"SunZilog: sdev&¢ral == NULL for "
"Zilog %d in get_zs_sun4u.
\n
"
,
chip
);
prom_halt
();
}
if
(
central_bus
==
NULL
)
{
mapped_addr
=
sbus_ioremap
(
&
sdev
->
resource
[
0
],
0
,
PAGE_SIZE
,
"Zilog Registers"
);
}
else
{
struct
linux_prom_registers
zsregs
[
1
];
err
=
prom_getproperty
(
zsnode
,
"reg"
,
(
char
*
)
&
zsregs
[
0
],
sizeof
(
zsregs
));
if
(
err
==
-
1
)
{
prom_printf
(
"SunZilog: Cannot map "
"Zilog %d regs on "
"central bus.
\n
"
,
chip
);
prom_halt
();
}
apply_fhc_ranges
(
central_bus
->
child
,
&
zsregs
[
0
],
1
);
apply_central_ranges
(
central_bus
,
&
zsregs
[
0
],
1
);
mapped_addr
=
(
void
__iomem
*
)
((((
u64
)
zsregs
[
0
].
which_io
)
<<
32UL
)
|
((
u64
)
zsregs
[
0
].
phys_addr
));
}
if
(
zilog_irq
==
-
1
)
{
if
(
central_bus
)
{
unsigned
long
iclr
,
imap
;
iclr
=
central_bus
->
child
->
fhc_regs
.
uregs
+
FHC_UREGS_ICLR
;
imap
=
central_bus
->
child
->
fhc_regs
.
uregs
+
FHC_UREGS_IMAP
;
zilog_irq
=
build_irq
(
0
,
iclr
,
imap
);
}
else
{
err
=
prom_getproperty
(
zsnode
,
"interrupts"
,
(
char
*
)
&
sun4u_ino
,
sizeof
(
sun4u_ino
));
zilog_irq
=
sbus_build_irq
(
sbus_root
,
sun4u_ino
);
}
}
return
(
struct
zilog_layout
__iomem
*
)
mapped_addr
;
}
#else
/* CONFIG_SPARC64 */
/*
* XXX The sun4d case is utterly screwed: it tries to re-walk the tree
* (for the 3rd time) in order to find bootbus and cpu. Streamline it.
*/
static
struct
zilog_layout
__iomem
*
__init
get_zs_sun4cmd
(
int
chip
,
int
node
)
{
struct
linux_prom_irqs
irq_info
[
2
];
void
__iomem
*
mapped_addr
=
NULL
;
int
zsnode
,
cpunode
,
bbnode
;
struct
linux_prom_registers
zsreg
[
4
];
struct
resource
res
;
if
(
sparc_cpu_model
==
sun4d
)
{
int
walk
;
zsnode
=
0
;
bbnode
=
0
;
cpunode
=
0
;
for
(
walk
=
prom_getchild
(
prom_root_node
);
(
walk
=
prom_searchsiblings
(
walk
,
"cpu-unit"
))
!=
0
;
walk
=
prom_getsibling
(
walk
))
{
bbnode
=
prom_getchild
(
walk
);
if
(
bbnode
&&
(
bbnode
=
prom_searchsiblings
(
bbnode
,
"bootbus"
)))
{
if
((
zsnode
=
prom_getchild
(
bbnode
))
==
node
)
{
cpunode
=
walk
;
break
;
}
}
}
if
(
!
walk
)
{
prom_printf
(
"SunZilog: Cannot find the %d'th bootbus on sun4d.
\n
"
,
(
chip
/
2
));
prom_halt
();
}
struct
uart_sunzilog_port
*
up
;
unsigned
long
size
;
int
i
;
if
(
prom_getproperty
(
zsnode
,
"reg"
,
(
char
*
)
zsreg
,
sizeof
(
zsreg
))
==
-
1
)
{
prom_printf
(
"SunZilog: Cannot map Zilog %d
\n
"
,
chip
);
prom_halt
();
}
/* XXX Looks like an off by one? */
prom_apply_generic_ranges
(
bbnode
,
cpunode
,
zsreg
,
1
);
res
.
start
=
zsreg
[
0
].
phys_addr
;
res
.
end
=
res
.
start
+
(
8
-
1
);
res
.
flags
=
zsreg
[
0
].
which_io
|
IORESOURCE_IO
;
mapped_addr
=
sbus_ioremap
(
&
res
,
0
,
8
,
"Zilog Serial"
);
size
=
NUM_CHANNELS
*
sizeof
(
struct
uart_sunzilog_port
);
sunzilog_port_table
=
kzalloc
(
size
,
GFP_KERNEL
);
if
(
!
sunzilog_port_table
)
return
-
ENOMEM
;
}
else
{
zsnode
=
node
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
up
=
&
sunzilog_port_table
[
i
]
;
#if 0 /* XXX When was this used? */
if (prom_getintdefault(zsnode, "slave", -1) != chipid) {
zsnode = prom_getsibling(zsnode);
continue;
}
#endif
spin_lock_init
(
&
up
->
port
.
lock
);
/*
* "address" is only present on ports that OBP opened
* (from Mitch Bradley's "Hitchhiker's Guide to OBP").
* We do not use it.
*/
if
(
i
==
0
)
sunzilog_irq_chain
=
up
;
if
(
prom_getproperty
(
zsnode
,
"reg"
,
(
char
*
)
zsreg
,
sizeof
(
zsreg
))
==
-
1
)
{
prom_printf
(
"SunZilog: Cannot map Zilog %d
\n
"
,
chip
);
prom_halt
();
}
if
(
sparc_cpu_model
==
sun4m
)
/* Crude. Pass parent. XXX */
prom_apply_obio_ranges
(
zsreg
,
1
);
res
.
start
=
zsreg
[
0
].
phys_addr
;
res
.
end
=
res
.
start
+
(
8
-
1
);
res
.
flags
=
zsreg
[
0
].
which_io
|
IORESOURCE_IO
;
mapped_addr
=
sbus_ioremap
(
&
res
,
0
,
8
,
"Zilog Serial"
);
if
(
i
<
NUM_CHANNELS
-
1
)
up
->
next
=
up
+
1
;
else
up
->
next
=
NULL
;
}
if
(
prom_getproperty
(
zsnode
,
"intr"
,
(
char
*
)
irq_info
,
sizeof
(
irq_info
))
%
sizeof
(
struct
linux_prom_irqs
))
{
prom_printf
(
"SunZilog: Cannot get IRQ property for Zilog %d.
\n
"
,
chip
);
prom_halt
();
}
if
(
zilog_irq
==
-
1
)
{
zilog_irq
=
irq_info
[
0
].
pri
;
}
else
if
(
zilog_irq
!=
irq_info
[
0
].
pri
)
{
/* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */
prom_printf
(
"SunZilog: Inconsistent IRQ layout for Zilog %d.
\n
"
,
chip
);
prom_halt
();
size
=
NUM_SUNZILOG
*
sizeof
(
struct
zilog_layout
__iomem
*
);
sunzilog_chip_regs
=
kzalloc
(
size
,
GFP_KERNEL
);
if
(
!
sunzilog_chip_regs
)
{
kfree
(
sunzilog_port_table
);
sunzilog_irq_chain
=
NULL
;
return
-
ENOMEM
;
}
return
(
struct
zilog_layout
__iomem
*
)
mapped_addr
;
return
0
;
}
#endif
/* !(CONFIG_SPARC64) */
/* Get the address of the registers for SunZilog instance CHIP. */
static
struct
zilog_layout
__iomem
*
__init
get_zs
(
int
chip
,
int
node
)
static
void
sunzilog_free_tables
(
void
)
{
if
(
chip
<
0
||
chip
>=
NUM_SUNZILOG
)
{
prom_printf
(
"SunZilog: Illegal chip number %d in get_zs.
\n
"
,
chip
);
prom_halt
();
}
#ifdef CONFIG_SPARC64
return
get_zs_sun4u
(
chip
,
node
);
#else
if
(
sparc_cpu_model
==
sun4
)
{
struct
resource
res
;
/* Not probe-able, hard code it. */
switch
(
chip
)
{
case
0
:
res
.
start
=
0xf1000000
;
break
;
case
1
:
res
.
start
=
0xf0000000
;
break
;
};
zilog_irq
=
12
;
res
.
end
=
(
res
.
start
+
(
8
-
1
));
res
.
flags
=
IORESOURCE_IO
;
return
sbus_ioremap
(
&
res
,
0
,
8
,
"SunZilog"
);
}
return
get_zs_sun4cmd
(
chip
,
node
);
#endif
kfree
(
sunzilog_port_table
);
sunzilog_irq_chain
=
NULL
;
kfree
(
sunzilog_chip_regs
);
}
#define ZS_PUT_CHAR_MAX_DELAY 2000
/* 10 ms */
...
...
@@ -1260,7 +1071,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch)
* udelay with ZSDELAY as that is a NOP on some platforms. -DaveM
*/
do
{
unsigned
char
val
=
sbus_
readb
(
&
channel
->
control
);
unsigned
char
val
=
readb
(
&
channel
->
control
);
if
(
val
&
Tx_BUF_EMP
)
{
ZSDELAY
();
break
;
...
...
@@ -1268,7 +1079,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch)
udelay
(
5
);
}
while
(
--
loops
);
sbus_
writeb
(
ch
,
&
channel
->
data
);
writeb
(
ch
,
&
channel
->
data
);
ZSDELAY
();
ZS_WSYNC
(
channel
);
}
...
...
@@ -1385,28 +1196,6 @@ static struct console sunzilog_console = {
.
data
=
&
sunzilog_reg
,
};
static
int
__init
sunzilog_console_init
(
void
)
{
int
i
;
if
(
con_is_present
())
return
0
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
int
this_minor
=
sunzilog_reg
.
minor
+
i
;
if
((
this_minor
-
64
)
==
(
serial_console
-
1
))
break
;
}
if
(
i
==
NUM_CHANNELS
)
return
0
;
sunzilog_console
.
index
=
i
;
sunzilog_port_table
[
i
].
flags
|=
SUNZILOG_FLAG_IS_CONS
;
register_console
(
&
sunzilog_console
);
return
0
;
}
static
inline
struct
console
*
SUNZILOG_CONSOLE
(
void
)
{
int
i
;
...
...
@@ -1431,101 +1220,8 @@ static inline struct console *SUNZILOG_CONSOLE(void)
#else
#define SUNZILOG_CONSOLE() (NULL)
#define sunzilog_console_init() do { } while (0)
#endif
/*
* We scan the PROM tree recursively. This is the most reliable way
* to find Zilog nodes on various platforms. However, we face an extreme
* shortage of kernel stack, so we must be very careful. To that end,
* we scan only to a certain depth, and we use a common property buffer
* in the scan structure.
*/
#define ZS_PROPSIZE 128
#define ZS_SCAN_DEPTH 5
struct
zs_probe_scan
{
int
depth
;
void
(
*
scanner
)(
struct
zs_probe_scan
*
t
,
int
node
);
int
devices
;
char
prop
[
ZS_PROPSIZE
];
};
static
int
__inline__
sunzilog_node_ok
(
int
node
,
const
char
*
name
,
int
len
)
{
if
(
strncmp
(
name
,
"zs"
,
len
)
==
0
)
return
1
;
/* Don't fold this procedure just yet. Compare to su_node_ok(). */
return
0
;
}
static
void
__init
sunzilog_scan
(
struct
zs_probe_scan
*
t
,
int
node
)
{
int
len
;
for
(;
node
!=
0
;
node
=
prom_getsibling
(
node
))
{
len
=
prom_getproperty
(
node
,
"name"
,
t
->
prop
,
ZS_PROPSIZE
);
if
(
len
<=
1
)
continue
;
/* Broken PROM node */
if
(
sunzilog_node_ok
(
node
,
t
->
prop
,
len
))
{
(
*
t
->
scanner
)(
t
,
node
);
}
else
{
if
(
t
->
depth
<
ZS_SCAN_DEPTH
)
{
t
->
depth
++
;
sunzilog_scan
(
t
,
prom_getchild
(
node
));
--
t
->
depth
;
}
}
}
}
static
void
__init
sunzilog_prepare
(
void
)
{
struct
uart_sunzilog_port
*
up
;
struct
zilog_layout
__iomem
*
rp
;
int
channel
,
chip
;
/*
* Temporary fix.
*/
for
(
channel
=
0
;
channel
<
NUM_CHANNELS
;
channel
++
)
spin_lock_init
(
&
sunzilog_port_table
[
channel
].
port
.
lock
);
sunzilog_irq_chain
=
up
=
&
sunzilog_port_table
[
0
];
for
(
channel
=
0
;
channel
<
NUM_CHANNELS
-
1
;
channel
++
)
up
[
channel
].
next
=
&
up
[
channel
+
1
];
up
[
channel
].
next
=
NULL
;
for
(
chip
=
0
;
chip
<
NUM_SUNZILOG
;
chip
++
)
{
rp
=
sunzilog_chip_regs
[
chip
];
up
[(
chip
*
2
)
+
0
].
port
.
membase
=
(
void
__iomem
*
)
&
rp
->
channelA
;
up
[(
chip
*
2
)
+
1
].
port
.
membase
=
(
void
__iomem
*
)
&
rp
->
channelB
;
/* Channel A */
up
[(
chip
*
2
)
+
0
].
port
.
iotype
=
UPIO_MEM
;
up
[(
chip
*
2
)
+
0
].
port
.
irq
=
zilog_irq
;
up
[(
chip
*
2
)
+
0
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
0
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
0
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
0
].
port
.
type
=
PORT_SUNZILOG
;
up
[(
chip
*
2
)
+
0
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
0
].
port
.
line
=
(
chip
*
2
)
+
0
;
up
[(
chip
*
2
)
+
0
].
flags
|=
SUNZILOG_FLAG_IS_CHANNEL_A
;
/* Channel B */
up
[(
chip
*
2
)
+
1
].
port
.
iotype
=
UPIO_MEM
;
up
[(
chip
*
2
)
+
1
].
port
.
irq
=
zilog_irq
;
up
[(
chip
*
2
)
+
1
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
1
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
1
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
1
].
port
.
type
=
PORT_SUNZILOG
;
up
[(
chip
*
2
)
+
1
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
1
].
port
.
line
=
(
chip
*
2
)
+
1
;
up
[(
chip
*
2
)
+
1
].
flags
|=
0
;
}
}
static
void
__init
sunzilog_init_kbdms
(
struct
uart_sunzilog_port
*
up
,
int
channel
)
{
int
baud
,
brg
;
...
...
@@ -1539,8 +1235,6 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
up
->
cflag
=
B4800
|
CS8
|
CLOCAL
|
CREAD
;
baud
=
4800
;
}
printk
(
KERN_INFO
"zs%d at 0x%p (irq = %d) is a SunZilog
\n
"
,
channel
,
up
->
port
.
membase
,
zilog_irq
);
up
->
curregs
[
R15
]
=
BRKIE
;
brg
=
BPS_TO_BRG
(
baud
,
ZS_CLOCK
/
ZS_CLOCK_DIVISOR
);
...
...
@@ -1552,11 +1246,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
#ifdef CONFIG_SERIO
static
void
__init
sunzilog_register_serio
(
struct
uart_sunzilog_port
*
up
,
int
channel
)
{
struct
serio
*
serio
;
up
->
serio
=
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
*
serio
));
struct
serio
*
serio
=
&
up
->
serio
;
serio
->
port_data
=
up
;
...
...
@@ -1576,35 +1266,30 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int ch
serio
->
write
=
sunzilog_serio_write
;
serio
->
open
=
sunzilog_serio_open
;
serio
->
close
=
sunzilog_serio_close
;
serio
->
dev
.
parent
=
up
->
port
.
dev
;
serio_register_port
(
serio
);
}
else
{
printk
(
KERN_WARNING
"zs%d: not enough memory for serio port
\n
"
,
channel
);
}
}
#endif
static
void
__init
sunzilog_init_hw
(
void
)
static
void
__init
sunzilog_init_hw
(
struct
uart_sunzilog_port
*
up
)
{
int
i
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
struct
uart_sunzilog_port
*
up
=
&
sunzilog_port_table
[
i
];
struct
zilog_channel
__iomem
*
channel
=
ZILOG_CHANNEL_FROM_PORT
(
&
up
->
port
);
struct
zilog_channel
__iomem
*
channel
;
unsigned
long
flags
;
int
baud
,
brg
;
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
channel
=
ZILOG_CHANNEL_FROM_PORT
(
&
up
->
port
);
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
if
(
ZS_IS_CHANNEL_A
(
up
))
{
write_zsreg
(
channel
,
R9
,
FHWRES
);
ZSDELAY_LONG
();
(
void
)
read_zsreg
(
channel
,
R0
);
}
if
(
i
==
KEYBOARD_LINE
||
i
==
MOUSE_LINE
)
{
sunzilog_init_kbdms
(
up
,
i
);
if
(
up
->
port
.
line
==
KEYBOARD_LINE
||
up
->
port
.
line
==
MOUSE_LINE
)
{
sunzilog_init_kbdms
(
up
,
up
->
port
.
line
);
up
->
curregs
[
R9
]
|=
(
NV
|
MIE
);
write_zsreg
(
channel
,
R9
,
up
->
curregs
[
R9
]);
}
else
{
...
...
@@ -1629,139 +1314,185 @@ static void __init sunzilog_init_hw(void)
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
#ifdef CONFIG_SERIO
if
(
i
==
KEYBOARD_LINE
||
i
==
MOUSE_LINE
)
sunzilog_register_serio
(
up
,
i
);
if
(
up
->
port
.
line
==
KEYBOARD_LINE
||
up
->
port
.
line
==
MOUSE_LINE
)
sunzilog_register_serio
(
up
,
up
->
port
.
line
);
#endif
}
}
static
struct
zilog_layout
__iomem
*
__init
get_zs
(
int
chip
,
int
node
);
static
void
__init
sunzilog_scan_probe
(
struct
zs_probe_scan
*
t
,
int
node
)
{
sunzilog_chip_regs
[
t
->
devices
]
=
get_zs
(
t
->
devices
,
node
);
t
->
devices
++
;
}
static
int
__init
sunzilog_ports_init
(
void
)
static
int
__devinit
zs_get_instance
(
struct
device_node
*
dp
)
{
struct
zs_probe_scan
scan
;
int
ret
;
int
uart_count
;
int
i
;
printk
(
KERN_DEBUG
"SunZilog: %d chips.
\n
"
,
NUM_SUNZILOG
);
ret
=
of_getintprop_default
(
dp
,
"slave"
,
-
1
);
if
(
ret
!=
-
1
)
return
ret
;
scan
.
scanner
=
sunzilog_scan_probe
;
scan
.
depth
=
0
;
scan
.
devices
=
0
;
sunzilog_scan
(
&
scan
,
prom_getchild
(
prom_root_node
))
;
if
(
of_find_property
(
dp
,
"keyboard"
,
NULL
))
ret
=
1
;
else
ret
=
0
;
sunzilog_prepare
();
return
ret
;
}
if
(
request_irq
(
zilog_irq
,
sunzilog_interrupt
,
SA_SHIRQ
,
"SunZilog"
,
sunzilog_irq_chain
))
{
prom_printf
(
"SunZilog: Unable to register zs interrupt handler.
\n
"
);
prom_halt
();
}
static
int
__devinit
zs_probe
(
struct
of_device
*
dev
,
const
struct
of_device_id
*
match
)
{
static
int
zilog_irq
=
-
1
;
struct
of_device
*
op
=
to_of_device
(
&
dev
->
dev
);
struct
uart_sunzilog_port
*
up
;
struct
zilog_layout
__iomem
*
rp
;
int
inst
=
zs_get_instance
(
dev
->
node
);
int
err
;
sunzilog_init_hw
();
sunzilog_chip_regs
[
inst
]
=
of_ioremap
(
&
op
->
resource
[
0
],
0
,
sizeof
(
struct
zilog_layout
),
"zs"
);
if
(
!
sunzilog_chip_regs
[
inst
])
return
-
ENOMEM
;
/* We can only init this once we have probed the Zilogs
* in the system. Do not count channels assigned to keyboards
* or mice when we are deciding how many ports to register.
*/
uart_count
=
0
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
struct
uart_sunzilog_port
*
up
=
&
sunzilog_port_table
[
i
];
rp
=
sunzilog_chip_regs
[
inst
];
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
continue
;
if
(
zilog_irq
==
-
1
)
{
zilog_irq
=
op
->
irqs
[
0
];
err
=
request_irq
(
zilog_irq
,
sunzilog_interrupt
,
SA_SHIRQ
,
"zs"
,
sunzilog_irq_chain
);
if
(
err
)
{
of_iounmap
(
rp
,
sizeof
(
struct
zilog_layout
));
uart_count
++
;
return
err
;
}
}
sunzilog_reg
.
nr
=
uart_count
;
sunzilog_reg
.
minor
=
sunserial_current_minor
;
ret
=
uart_register_driver
(
&
sunzilog_reg
);
if
(
ret
==
0
)
{
sunzilog_reg
.
tty_driver
->
name_base
=
sunzilog_reg
.
minor
-
64
;
sunzilog_reg
.
cons
=
SUNZILOG_CONSOLE
();
sunserial_current_minor
+=
uart_count
;
up
=
&
sunzilog_port_table
[
inst
*
2
];
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
struct
uart_sunzilog_port
*
up
=
&
sunzilog_port_table
[
i
];
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
continue
;
/* Channel A */
up
[
0
].
port
.
mapbase
=
op
->
resource
[
0
].
start
+
0x00
;
up
[
0
].
port
.
membase
=
(
void
__iomem
*
)
&
rp
->
channelA
;
up
[
0
].
port
.
iotype
=
UPIO_MEM
;
up
[
0
].
port
.
irq
=
op
->
irqs
[
0
];
up
[
0
].
port
.
uartclk
=
ZS_CLOCK
;
up
[
0
].
port
.
fifosize
=
1
;
up
[
0
].
port
.
ops
=
&
sunzilog_pops
;
up
[
0
].
port
.
type
=
PORT_SUNZILOG
;
up
[
0
].
port
.
flags
=
0
;
up
[
0
].
port
.
line
=
(
inst
*
2
)
+
0
;
up
[
0
].
port
.
dev
=
&
op
->
dev
;
up
[
0
].
flags
|=
SUNZILOG_FLAG_IS_CHANNEL_A
;
if
(
inst
==
1
)
up
[
0
].
flags
|=
SUNZILOG_FLAG_CONS_KEYB
;
sunzilog_init_hw
(
&
up
[
0
]);
if
(
uart_add_one_port
(
&
sunzilog_reg
,
&
up
->
port
))
{
printk
(
KERN_ERR
"SunZilog: failed to add port zs%d
\n
"
,
i
);
}
/* Channel B */
up
[
1
].
port
.
mapbase
=
op
->
resource
[
0
].
start
+
0x04
;
up
[
1
].
port
.
membase
=
(
void
__iomem
*
)
&
rp
->
channelB
;
up
[
1
].
port
.
iotype
=
UPIO_MEM
;
up
[
1
].
port
.
irq
=
op
->
irqs
[
0
];
up
[
1
].
port
.
uartclk
=
ZS_CLOCK
;
up
[
1
].
port
.
fifosize
=
1
;
up
[
1
].
port
.
ops
=
&
sunzilog_pops
;
up
[
1
].
port
.
type
=
PORT_SUNZILOG
;
up
[
1
].
port
.
flags
=
0
;
up
[
1
].
port
.
line
=
(
inst
*
2
)
+
1
;
up
[
1
].
port
.
dev
=
&
op
->
dev
;
up
[
1
].
flags
|=
0
;
if
(
inst
==
1
)
up
[
1
].
flags
|=
SUNZILOG_FLAG_CONS_MOUSE
;
sunzilog_init_hw
(
&
up
[
1
]);
if
(
inst
!=
1
)
{
err
=
uart_add_one_port
(
&
sunzilog_reg
,
&
up
[
0
].
port
);
if
(
err
)
{
of_iounmap
(
rp
,
sizeof
(
struct
zilog_layout
));
return
err
;
}
err
=
uart_add_one_port
(
&
sunzilog_reg
,
&
up
[
1
].
port
);
if
(
err
)
{
uart_remove_one_port
(
&
sunzilog_reg
,
&
up
[
0
].
port
);
of_iounmap
(
rp
,
sizeof
(
struct
zilog_layout
));
return
err
;
}
}
return
ret
;
}
static
void
__init
sunzilog_scan_count
(
struct
zs_probe_scan
*
t
,
int
node
)
{
t
->
devices
++
;
return
0
;
}
static
int
__
init
sunzilog_ports_count
(
void
)
static
int
__
devexit
zs_remove
(
struct
of_device
*
dev
)
{
struct
zs_probe_scan
scan
;
struct
uart_sunzilog_port
*
up
=
dev_get_drvdata
(
&
dev
->
dev
);
struct
zilog_channel
__iomem
*
channel
;
/* Sun4 Zilog setup is hard coded, no probing to do. */
if
(
sparc_cpu_model
==
sun4
)
return
2
;
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
{
#ifdef CONFIG_SERIO
serio_unregister_port
(
&
up
->
serio
);
#endif
}
else
uart_remove_one_port
(
&
sunzilog_reg
,
&
up
->
port
);
scan
.
scanner
=
sunzilog_scan_count
;
scan
.
depth
=
0
;
scan
.
devices
=
0
;
channel
=
ZILOG_CHANNEL_FROM_PORT
(
&
up
->
port
);
sunzilog_scan
(
&
scan
,
prom_getchild
(
prom_root_node
));
of_iounmap
(
channel
,
sizeof
(
struct
zilog_channel
));
return
scan
.
devices
;
return
0
;
}
static
struct
of_device_id
zs_match
[]
=
{
{
.
name
=
"zs"
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
zs_match
);
static
struct
of_platform_driver
zs_driver
=
{
.
name
=
"zs"
,
.
match_table
=
zs_match
,
.
probe
=
zs_probe
,
.
remove
=
__devexit_p
(
zs_remove
),
};
static
int
__init
sunzilog_init
(
void
)
{
struct
device_node
*
dp
;
int
err
;
NUM_SUNZILOG
=
0
;
for_each_node_by_name
(
dp
,
"zs"
)
NUM_SUNZILOG
++
;
NUM_SUNZILOG
=
sunzilog_ports_count
();
if
(
NUM_SUNZILOG
==
0
)
return
-
ENODEV
;
if
(
NUM_SUNZILOG
)
{
int
uart_count
;
sunzilog_alloc_tables
();
err
=
sunzilog_alloc_tables
();
if
(
err
)
return
err
;
sunzilog_ports_init
();
/* Subtract 1 for keyboard, 1 for mouse. */
uart_count
=
(
NUM_SUNZILOG
*
2
)
-
2
;
return
0
;
sunzilog_reg
.
nr
=
uart_count
;
sunzilog_reg
.
minor
=
sunserial_current_minor
;
err
=
uart_register_driver
(
&
sunzilog_reg
);
if
(
err
)
{
sunzilog_free_tables
();
return
err
;
}
sunzilog_reg
.
tty_driver
->
name_base
=
sunzilog_reg
.
minor
-
64
;
sunzilog_reg
.
cons
=
SUNZILOG_CONSOLE
();
sunserial_current_minor
+=
uart_count
;
}
return
of_register_driver
(
&
zs_driver
,
&
of_bus_type
);
}
static
void
__exit
sunzilog_exit
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
struct
uart_sunzilog_port
*
up
=
&
sunzilog_port_table
[
i
];
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
{
#ifdef CONFIG_SERIO
if
(
up
->
serio
)
{
serio_unregister_port
(
up
->
serio
);
up
->
serio
=
NULL
;
}
#endif
}
else
uart_remove_one_port
(
&
sunzilog_reg
,
&
up
->
port
);
}
of_unregister_driver
(
&
zs_driver
);
if
(
NUM_SUNZILOG
)
{
uart_unregister_driver
(
&
sunzilog_reg
);
sunzilog_free_tables
();
}
}
module_init
(
sunzilog_init
);
...
...
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