aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-08-26 18:51:22 +0100
committerJeff Garzik <jeff@garzik.org>2007-08-31 06:52:57 -0400
commit0491d1f3fd93f838d8bfb75b12acfba39d06a4da (patch)
tree2e53bd38d7fc41357a936d052ef018e287c3fdd6
parent2d8348b429b4ae5cc47449c787881221fe43af4b (diff)
IOC3: Program UART predividers.
The IOC3 driver's UART detection bits used to rely on the the firmware setting the UART pre-divider in a way that's apropriate for the 8250 driver which doesn't currently program this register. This happens to work for the console but not rarely for additional ports. While at it, also program the UART to RS-232 PIO mode; it the UART might have been in mac-serial and/or DMA mode though that hasn't actually been observed in practice. Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/ioc3-eth.c80
1 files changed, 60 insertions, 20 deletions
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 3ca1e8ece54..0834ef0eddb 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -48,6 +48,7 @@
#ifdef CONFIG_SERIAL_8250
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
#endif
#include <linux/netdevice.h>
@@ -1151,13 +1152,41 @@ static int ioc3_is_menet(struct pci_dev *pdev)
* Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
* around ioc3 oddities in this respect.
*
- * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
+ * The IOC3 serials use a 22MHz clock rate with an additional divider which
+ * can be programmed in the SCR register if the DLAB bit is set.
+ *
+ * Register to interrupt zero because we share the interrupt with
+ * the serial driver which we don't properly support yet.
+ *
+ * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
+ * registered.
*/
+static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
+{
+#define COSMISC_CONSTANT 6
+
+ struct uart_port port = {
+ .irq = 0,
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
+
+ .membase = (unsigned char __iomem *) uart,
+ .mapbase = (unsigned long) uart,
+ };
+ unsigned char lcr;
+
+ lcr = uart->iu_lcr;
+ uart->iu_lcr = lcr | UART_LCR_DLAB;
+ uart->iu_scr = COSMISC_CONSTANT,
+ uart->iu_lcr = lcr;
+ uart->iu_lcr;
+ serial8250_register_port(&port);
+}
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
{
- struct uart_port port;
-
/*
* We need to recognice and treat the fourth MENET serial as it
* does not have an SuperIO chip attached to it, therefore attempting
@@ -1171,24 +1200,35 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
return;
/*
- * Register to interrupt zero because we share the interrupt with
- * the serial driver which we don't properly support yet.
- *
- * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
- * been registered.
+ * Switch IOC3 to PIO mode. It probably already was but let's be
+ * paranoid
*/
- memset(&port, 0, sizeof(port));
- port.irq = 0;
- port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- port.iotype = UPIO_MEM;
- port.regshift = 0;
- port.uartclk = 22000000 / 3;
-
- port.membase = (unsigned char *) &ioc3->sregs.uarta;
- serial8250_register_port(&port);
-
- port.membase = (unsigned char *) &ioc3->sregs.uartb;
- serial8250_register_port(&port);
+ ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL;
+ ioc3->gpcr_s;
+ ioc3->gppr_6 = 0;
+ ioc3->gppr_6;
+ ioc3->gppr_7 = 0;
+ ioc3->gppr_7;
+ ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN;
+ ioc3->sscr_a;
+ ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN;
+ ioc3->sscr_b;
+ /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */
+ ioc3->sio_iec &= ~ (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL |
+ SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER |
+ SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS |
+ SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR);
+ ioc3->sio_iec |= SIO_IR_SA_INT;
+ ioc3->sscr_a = 0;
+ ioc3->sio_iec &= ~ (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL |
+ SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER |
+ SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS |
+ SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR);
+ ioc3->sio_iec |= SIO_IR_SB_INT;
+ ioc3->sscr_b = 0;
+
+ ioc3_8250_register(&ioc3->sregs.uarta);
+ ioc3_8250_register(&ioc3->sregs.uartb);
}
#endif