This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
PPC40x serial_init fix
- From: Markus Schade <marks at peppercon dot de>
- To: ecos-patches at sourceware dot org
- Date: Fri, 2 Sep 2005 16:34:00 +0200
- Subject: PPC40x serial_init fix
serial initialization failed to set UART Divisor in DCR register
when calculation baud clock.
added calculation for PPC405EP
diff -Nbaur ecos-cvs/packages/hal/powerpc/ppc40x/current/ChangeLog ecos/packages/hal/powerpc/ppc40x/current/ChangeLog
--- ecos-cvs/packages/hal/powerpc/ppc40x/current/ChangeLog 2005-08-25 16:06:08.000000000 +0200
+++ ecos/packages/hal/powerpc/ppc40x/current/ChangeLog 2005-09-02 14:49:50.000000000 +0200
@@ -1,3 +1,9 @@
+2005-09-02 Markus Schade <marks@peppercon.de>
+
+ * src/hal_diag.c: Correct and _complete_ serial initialization
+ for 405EP and GP. Fixed calculation of baud clock and
+ actually _setting_ UART Divisor
+
2005-08-25 Markus Schade <marks@peppercon.de>
* src/var_misc.c:
diff -Nbaur ecos-cvs/packages/hal/powerpc/ppc40x/current/src/hal_diag.c ecos/packages/hal/powerpc/ppc40x/current/src/hal_diag.c
--- ecos-cvs/packages/hal/powerpc/ppc40x/current/src/hal_diag.c 2005-08-25 16:06:08.000000000 +0200
+++ ecos/packages/hal/powerpc/ppc40x/current/src/hal_diag.c 2005-09-02 15:19:49.000000000 +0200
@@ -75,13 +75,22 @@
//-----------------------------------------------------------------------------
// There are two serial ports.
-#if defined(CYGHWR_HAL_POWERPC_PPC4XX_405) || defined(CYGHWR_HAL_POWERPC_PPC4XX_405GP)
-#define CYG_DEV_SERIAL_BASE_A _PPC405GP_UART0
-#define CYG_DEV_SERIAL_BASE_B _PPC405GP_UART1
-#endif
+// baseBaud = cpuClock/(uartDivisor*16)
+#define CFG_BASE_BAUD 691200
#if defined(CYGHWR_HAL_POWERPC_PPC4XX_405EP)
#define CYG_DEV_SERIAL_BASE_A _PPC405EP_UART0
#define CYG_DEV_SERIAL_BASE_B _PPC405EP_UART1
+#define UCR0_MASK 0x0000007f
+#define UCR1_MASK 0x00007f00
+#define UCR0_UDIV_POS 0
+#define UCR1_UDIV_POS 8
+#define UDIV_MAX 127
+#else /* defined(CYGHWR_HAL_POWERPC_PPC4XX_405) || defined(CYGHWR_HAL_POWERPC_PPC4XX_405GP) */
+#define CYG_DEV_SERIAL_BASE_A _PPC405GP_UART0
+#define CYG_DEV_SERIAL_BASE_B _PPC405GP_UART1
+#define CR0_MASK 0x00001fff
+#define CR0_UDIV_POS 1
+#define UDIV_MAX 32
#endif
//-----------------------------------------------------------------------------
// Define the serial registers. The PPC405GP has 16552 UART(s) builtin.
@@ -164,14 +173,54 @@
int
cyg_var_baud_generator(int baud)
{
- int clock_rate, baud_clock, clock_divisor;
- unsigned int cr0;
+ cyg_uint32 reg;
+ cyg_uint32 tmp;
+ cyg_uint32 clk;
+ cyg_uint32 clock_divisor;
+ cyg_uint8 baud_clock;
+
+ /* Calculate baud rate clock divisor */
+#if defined(CYGHWR_HAL_POWERPC_PPC4XX_405EP)
+ /* CPC0_UCR_BASE 25:31 (7Bit) U0DIV 17:23 (7bit) U1DIV */
+ CYGARC_MFDCR(DCR_CPC0_UCR_BASE, reg);
+ reg &= ~(UCR0_MASK | UCR1_MASK);
+
+ // baseBaud = cpuClock/(uartDivisor*16)
+ clk = (CYGHWR_HAL_POWERPC_CPU_SPEED*1000000);
+ tmp = CFG_BASE_BAUD * 16;
+ clock_divisor = (clk + tmp / 2) / tmp;
+ if (clock_divisor > UDIV_MAX)
+ clock_divisor = UDIV_MAX; /* Max == 128 */
+ reg |= (clock_divisor) << UCR0_UDIV_POS; /* set the UART divisor */
+ reg |= (clock_divisor) << UCR1_UDIV_POS; /* set the UART divisor */
+
+ /* write back both UART Divisors */
+ CYGARC_MTDCR(DCR_CPC0_UCR_BASE, reg);
+
+#else /* defined(CYGHWR_HAL_POWERPC_PPC4XX_405) || defined(CYGHWR_HAL_POWERPC_PPC4XX_405GP) */
+ /* CPC0_CR0 26:30 (5Bit) generic UART divisor */
+ CYGARC_MFDCR(DCR_CPC0_CR0, reg);
+ reg &= & ~CR0_MASK;
+ /* 405GP could also be clocked externally TODO */
+ clk = (CYGHWR_HAL_POWERPC_CPU_SPEED*1000000);
+#ifdef CYGHWR_HAL_POWERPC_PPC4XX_405_UART_ERRATA_59
+ /* PPC405 Errata 59 (UART Div stuck at 31)
+ * phew, that is way too long for my taste :-) */
+ clock_divisor = 31;
+#else
+ tmp = CFG_BASE_BAUD * 16;
+ clock_divisor = (clk + tmp / 2) / tmp;
+ if (clock_divisor > UDIV_MAX)
+ clock_divisor = UDIV_MAX;
+#endif
+ reg |= (clock_divisor - 1) << CR0_UDIV_POS; /* set the UART divisor */
+
+ /* write back both UART Divisor */
+ CYGARC_MTDCR(DCR_CPC0_CR0, reg);
+#endif
- // Calculate baud rate clock divisor
- CYGARC_MFDCR(DCR_CPC0_CR0, cr0);
- clock_divisor = ((cr0 & 0x3E) >> 1) + 1;
- clock_rate = ((CYGHWR_HAL_POWERPC_CPU_SPEED*1000000)/clock_divisor);
- baud_clock = ((clock_rate)/16)/baud;
+ tmp = baud * 16 * clock_divisor;
+ baud_clock = (clk + tmp / 2) /tmp;
return baud_clock;
}
@@ -182,34 +231,40 @@
{
cyg_uint8* base = __ch_data->base;
cyg_uint8 lcr;
- int baud_clock = cyg_var_baud_generator(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
+ cyg_uint8 baud_clock = cyg_var_baud_generator(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_IER, 0);
- // Disable and clear FIFOs (need to enable to clear).
+ /* Disable and clear FIFOs (need to enable to clear). */
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_FCR,
(SIO_FCR_FCR0 | SIO_FCR_FCR1 | SIO_FCR_FCR2));
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_FCR, 0);
- // 8-1-no parity.
+ /* 8-1-no parity. */
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR, SIO_LCR_WLS0 | SIO_LCR_WLS1);
- // Set speed to the default baud rate
+ /* Set DLAB Bit */
HAL_READ_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
lcr |= SIO_LCR_DLAB;
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
- HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLL, baud_clock & 0xFF);
- HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLM, (baud_clock >> 8) & 0xFF);
+ /* Set speed to the default baud rate */
+ HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLL, baud_clock);
+ HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLM, baud_clock >> 8);
+
+ /* Clear DLAB Bit */
lcr &= ~SIO_LCR_DLAB;
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
- // Enable FIFOs (and clear them).
+ /* Enable FIFOs (and clear them). */
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_FCR,
(SIO_FCR_FCR0 | SIO_FCR_FCR1 | SIO_FCR_FCR2));
- // Assert handshake signals
+ /* Assert handshake signals */
HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_MCR, (SIO_MCR_DTR|SIO_MCR_RTS));
+
+ /* Clear scratchpad */
+ HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_SCR, 0);
}
static cyg_bool