Commit 599f030c authored by John Rigby's avatar John Rigby Committed by Grant Likely

[POWERPC] mpc512x: Factor out 5200 dependencies from 52xx psc driver

PSC devices are different between the mpc5200 and the mpc5121
this patch localizes the differences in preparation for adding mpc5121
support to the psc uart driver.
Signed-off-by: default avatarJohn Rigby <jrigby@freescale.com>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent bd05f91f
...@@ -67,7 +67,6 @@ ...@@ -67,7 +67,6 @@
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -111,8 +110,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; ...@@ -111,8 +110,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
static void mpc52xx_uart_of_enumerate(void); static void mpc52xx_uart_of_enumerate(void);
#endif #endif
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
/* Forward declaration of the interruption handling routine */ /* Forward declaration of the interruption handling routine */
...@@ -137,6 +136,162 @@ static struct of_device_id mpc52xx_uart_of_match[] = { ...@@ -137,6 +136,162 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
}; };
#endif #endif
/* ======================================================================== */
/* PSC fifo operations for isolating differences between 52xx and 512x */
/* ======================================================================== */
struct psc_ops {
void (*fifo_init)(struct uart_port *port);
int (*raw_rx_rdy)(struct uart_port *port);
int (*raw_tx_rdy)(struct uart_port *port);
int (*rx_rdy)(struct uart_port *port);
int (*tx_rdy)(struct uart_port *port);
int (*tx_empty)(struct uart_port *port);
void (*stop_rx)(struct uart_port *port);
void (*start_tx)(struct uart_port *port);
void (*stop_tx)(struct uart_port *port);
void (*rx_clr_irq)(struct uart_port *port);
void (*tx_clr_irq)(struct uart_port *port);
void (*write_char)(struct uart_port *port, unsigned char c);
unsigned char (*read_char)(struct uart_port *port);
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
unsigned long (*getuartclk)(void *p);
};
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
/* /32 prescaler */
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
out_8(&fifo->rfcntl, 0x00);
out_be16(&fifo->rfalarm, 0x1ff);
out_8(&fifo->tfcntl, 0x07);
out_be16(&fifo->tfalarm, 0x80);
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_status)
& MPC52xx_PSC_SR_RXRDY;
}
static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_status)
& MPC52xx_PSC_SR_TXRDY;
}
static int mpc52xx_psc_rx_rdy(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_isr)
& port->read_status_mask
& MPC52xx_PSC_IMR_RXRDY;
}
static int mpc52xx_psc_tx_rdy(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_isr)
& port->read_status_mask
& MPC52xx_PSC_IMR_TXRDY;
}
static int mpc52xx_psc_tx_empty(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_status)
& MPC52xx_PSC_SR_TXEMP;
}
static void mpc52xx_psc_start_tx(struct uart_port *port)
{
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void mpc52xx_psc_stop_tx(struct uart_port *port)
{
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void mpc52xx_psc_stop_rx(struct uart_port *port)
{
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
{
}
static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
{
}
static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
{
out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
}
static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
{
return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
}
static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
{
out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
}
static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
{
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
/* Search for bus-frequency property in this node or a parent */
static unsigned long mpc52xx_getuartclk(void *p)
{
#if defined(CONFIG_PPC_MERGE)
/*
* 5200 UARTs have a / 32 prescaler
* but the generic serial code assumes 16
* so return ipb freq / 2
*/
return mpc52xx_find_ipb_freq(p) / 2;
#else
pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
return NULL;
#endif
}
static struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
.rx_rdy = mpc52xx_psc_rx_rdy,
.tx_rdy = mpc52xx_psc_tx_rdy,
.tx_empty = mpc52xx_psc_tx_empty,
.stop_rx = mpc52xx_psc_stop_rx,
.start_tx = mpc52xx_psc_start_tx,
.stop_tx = mpc52xx_psc_stop_tx,
.rx_clr_irq = mpc52xx_psc_rx_clr_irq,
.tx_clr_irq = mpc52xx_psc_tx_clr_irq,
.write_char = mpc52xx_psc_write_char,
.read_char = mpc52xx_psc_read_char,
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
.getuartclk = mpc52xx_getuartclk,
};
static struct psc_ops *psc_ops = &mpc52xx_psc_ops;
/* ======================================================================== */ /* ======================================================================== */
/* UART operations */ /* UART operations */
...@@ -145,8 +300,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { ...@@ -145,8 +300,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
static unsigned int static unsigned int
mpc52xx_uart_tx_empty(struct uart_port *port) mpc52xx_uart_tx_empty(struct uart_port *port)
{ {
int status = in_be16(&PSC(port)->mpc52xx_psc_status); return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
} }
static void static void
...@@ -166,16 +320,14 @@ static void ...@@ -166,16 +320,14 @@ static void
mpc52xx_uart_stop_tx(struct uart_port *port) mpc52xx_uart_stop_tx(struct uart_port *port)
{ {
/* port->lock taken by caller */ /* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; psc_ops->stop_tx(port);
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
} }
static void static void
mpc52xx_uart_start_tx(struct uart_port *port) mpc52xx_uart_start_tx(struct uart_port *port)
{ {
/* port->lock taken by caller */ /* port->lock taken by caller */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; psc_ops->start_tx(port);
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
} }
static void static void
...@@ -188,8 +340,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch) ...@@ -188,8 +340,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
if (ch) { if (ch) {
/* Make sure tx interrupts are on */ /* Make sure tx interrupts are on */
/* Truly necessary ??? They should be anyway */ /* Truly necessary ??? They should be anyway */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; psc_ops->start_tx(port);
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
} }
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
...@@ -199,8 +350,7 @@ static void ...@@ -199,8 +350,7 @@ static void
mpc52xx_uart_stop_rx(struct uart_port *port) mpc52xx_uart_stop_rx(struct uart_port *port)
{ {
/* port->lock taken by caller */ /* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; psc_ops->stop_rx(port);
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
} }
static void static void
...@@ -227,7 +377,6 @@ static int ...@@ -227,7 +377,6 @@ static int
mpc52xx_uart_startup(struct uart_port *port) mpc52xx_uart_startup(struct uart_port *port)
{ {
struct mpc52xx_psc __iomem *psc = PSC(port); struct mpc52xx_psc __iomem *psc = PSC(port);
struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
int ret; int ret;
/* Request IRQ */ /* Request IRQ */
...@@ -242,15 +391,7 @@ mpc52xx_uart_startup(struct uart_port *port) ...@@ -242,15 +391,7 @@ mpc52xx_uart_startup(struct uart_port *port)
out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ psc_ops->fifo_init(port);
out_8(&fifo->rfcntl, 0x00);
out_be16(&fifo->rfalarm, 0x1ff);
out_8(&fifo->tfcntl, 0x07);
out_be16(&fifo->tfalarm, 0x80);
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
...@@ -333,8 +474,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, ...@@ -333,8 +474,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
* boot for the console, all stuff is not yet ready to receive at that * boot for the console, all stuff is not yet ready to receive at that
* time and that just makes the kernel oops */ * time and that just makes the kernel oops */
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && while (!mpc52xx_uart_tx_empty(port) && --j)
--j)
udelay(1); udelay(1);
if (!j) if (!j)
...@@ -462,11 +602,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) ...@@ -462,11 +602,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
unsigned short status; unsigned short status;
/* While we can read, do so ! */ /* While we can read, do so ! */
while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) & while (psc_ops->raw_rx_rdy(port)) {
MPC52xx_PSC_SR_RXRDY) {
/* Get the char */ /* Get the char */
ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8); ch = psc_ops->read_char(port);
/* Handle sysreq char */ /* Handle sysreq char */
#ifdef SUPPORT_SYSRQ #ifdef SUPPORT_SYSRQ
...@@ -481,6 +619,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) ...@@ -481,6 +619,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
flag = TTY_NORMAL; flag = TTY_NORMAL;
port->icount.rx++; port->icount.rx++;
status = in_be16(&PSC(port)->mpc52xx_psc_status);
if (status & (MPC52xx_PSC_SR_PE | if (status & (MPC52xx_PSC_SR_PE |
MPC52xx_PSC_SR_FE | MPC52xx_PSC_SR_FE |
MPC52xx_PSC_SR_RB)) { MPC52xx_PSC_SR_RB)) {
...@@ -510,7 +650,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) ...@@ -510,7 +650,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; return psc_ops->raw_rx_rdy(port);
} }
static inline int static inline int
...@@ -520,7 +660,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) ...@@ -520,7 +660,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
/* Process out of band chars */ /* Process out of band chars */
if (port->x_char) { if (port->x_char) {
out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char); psc_ops->write_char(port, port->x_char);
port->icount.tx++; port->icount.tx++;
port->x_char = 0; port->x_char = 0;
return 1; return 1;
...@@ -533,8 +673,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) ...@@ -533,8 +673,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
} }
/* Send chars */ /* Send chars */
while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) { while (psc_ops->raw_tx_rdy(port)) {
out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]); psc_ops->write_char(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++; port->icount.tx++;
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
...@@ -560,7 +700,6 @@ mpc52xx_uart_int(int irq, void *dev_id) ...@@ -560,7 +700,6 @@ mpc52xx_uart_int(int irq, void *dev_id)
struct uart_port *port = dev_id; struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT; unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing; unsigned int keepgoing;
unsigned short status;
spin_lock(&port->lock); spin_lock(&port->lock);
...@@ -569,18 +708,12 @@ mpc52xx_uart_int(int irq, void *dev_id) ...@@ -569,18 +708,12 @@ mpc52xx_uart_int(int irq, void *dev_id)
/* If we don't find anything to do, we stop */ /* If we don't find anything to do, we stop */
keepgoing = 0; keepgoing = 0;
/* Read status */ psc_ops->rx_clr_irq(port);
status = in_be16(&PSC(port)->mpc52xx_psc_isr); if (psc_ops->rx_rdy(port))
status &= port->read_status_mask;
/* Do we need to receive chars ? */
/* For this RX interrupts must be on and some chars waiting */
if (status & MPC52xx_PSC_IMR_RXRDY)
keepgoing |= mpc52xx_uart_int_rx_chars(port); keepgoing |= mpc52xx_uart_int_rx_chars(port);
/* Do we need to send chars ? */ psc_ops->tx_clr_irq(port);
/* For this, TX must be ready and TX interrupt enabled */ if (psc_ops->tx_rdy(port))
if (status & MPC52xx_PSC_IMR_TXRDY)
keepgoing |= mpc52xx_uart_int_tx_chars(port); keepgoing |= mpc52xx_uart_int_tx_chars(port);
/* Limit number of iteration */ /* Limit number of iteration */
...@@ -647,36 +780,33 @@ static void ...@@ -647,36 +780,33 @@ static void
mpc52xx_console_write(struct console *co, const char *s, unsigned int count) mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct uart_port *port = &mpc52xx_uart_ports[co->index]; struct uart_port *port = &mpc52xx_uart_ports[co->index];
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned int i, j; unsigned int i, j;
/* Disable interrupts */ /* Disable interrupts */
out_be16(&psc->mpc52xx_psc_imr, 0); psc_ops->cw_disable_ints(port);
/* Wait the TX buffer to be empty */ /* Wait the TX buffer to be empty */
j = 5000000; /* Maximum wait */ j = 5000000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && while (!mpc52xx_uart_tx_empty(port) && --j)
--j)
udelay(1); udelay(1);
/* Write all the chars */ /* Write all the chars */
for (i = 0; i < count; i++, s++) { for (i = 0; i < count; i++, s++) {
/* Line return handling */ /* Line return handling */
if (*s == '\n') if (*s == '\n')
out_8(&psc->mpc52xx_psc_buffer_8, '\r'); psc_ops->write_char(port, '\r');
/* Send the char */ /* Send the char */
out_8(&psc->mpc52xx_psc_buffer_8, *s); psc_ops->write_char(port, *s);
/* Wait the TX buffer to be empty */ /* Wait the TX buffer to be empty */
j = 20000; /* Maximum wait */ j = 20000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) & while (!mpc52xx_uart_tx_empty(port) && --j)
MPC52xx_PSC_SR_TXEMP) && --j)
udelay(1); udelay(1);
} }
/* Restore interrupt state */ /* Restore interrupt state */
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); psc_ops->cw_restore_ints(port);
} }
#if !defined(CONFIG_PPC_MERGE) #if !defined(CONFIG_PPC_MERGE)
...@@ -721,7 +851,7 @@ mpc52xx_console_setup(struct console *co, char *options) ...@@ -721,7 +851,7 @@ mpc52xx_console_setup(struct console *co, char *options)
{ {
struct uart_port *port = &mpc52xx_uart_ports[co->index]; struct uart_port *port = &mpc52xx_uart_ports[co->index];
struct device_node *np = mpc52xx_uart_nodes[co->index]; struct device_node *np = mpc52xx_uart_nodes[co->index];
unsigned int ipb_freq; unsigned int uartclk;
struct resource res; struct resource res;
int ret; int ret;
...@@ -753,17 +883,16 @@ mpc52xx_console_setup(struct console *co, char *options) ...@@ -753,17 +883,16 @@ mpc52xx_console_setup(struct console *co, char *options)
return ret; return ret;
} }
/* Search for bus-frequency property in this node or a parent */ uartclk = psc_ops->getuartclk(np);
ipb_freq = mpc52xx_find_ipb_freq(np); if (uartclk == 0) {
if (ipb_freq == 0) { pr_debug("Could not find uart clock frequency!\n");
pr_debug("Could not find IPB bus frequency!\n");
return -EINVAL; return -EINVAL;
} }
/* Basic port init. Needed since we use some uart_??? func before /* Basic port init. Needed since we use some uart_??? func before
* real init for early access */ * real init for early access */
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->uartclk = ipb_freq / 2; port->uartclk = uartclk;
port->ops = &mpc52xx_uart_ops; port->ops = &mpc52xx_uart_ops;
port->mapbase = res.start; port->mapbase = res.start;
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
...@@ -949,7 +1078,7 @@ static int __devinit ...@@ -949,7 +1078,7 @@ static int __devinit
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
{ {
int idx = -1; int idx = -1;
unsigned int ipb_freq; unsigned int uartclk;
struct uart_port *port = NULL; struct uart_port *port = NULL;
struct resource res; struct resource res;
int ret; int ret;
...@@ -965,10 +1094,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) ...@@ -965,10 +1094,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
pr_debug("Found %s assigned to ttyPSC%x\n", pr_debug("Found %s assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[idx]->full_name, idx); mpc52xx_uart_nodes[idx]->full_name, idx);
/* Search for bus-frequency property in this node or a parent */ uartclk = psc_ops->getuartclk(op->node);
ipb_freq = mpc52xx_find_ipb_freq(op->node); if (uartclk == 0) {
if (ipb_freq == 0) { dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
return -EINVAL; return -EINVAL;
} }
...@@ -976,7 +1104,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) ...@@ -976,7 +1104,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
port = &mpc52xx_uart_ports[idx]; port = &mpc52xx_uart_ports[idx];
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->uartclk = ipb_freq / 2; port->uartclk = uartclk;
port->fifosize = 512; port->fifosize = 512;
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF | port->flags = UPF_BOOT_AUTOCONF |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment