diff options
| author | Wolfgang Denk <wd@pollux.denx.de> | 2007-03-06 18:08:43 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2007-03-06 18:08:43 +0100 | 
| commit | ad5bb451ade552c44bef9119d907929ebc2c126f (patch) | |
| tree | df979d3c6385a161cd6df6b6f903ed7eaad31948 /post/cpu/mpc8xx/uart.c | |
| parent | a5284efd125967675b2e9c6ef7b95832268ad360 (diff) | |
| download | olio-uboot-2014.01-ad5bb451ade552c44bef9119d907929ebc2c126f.tar.xz olio-uboot-2014.01-ad5bb451ade552c44bef9119d907929ebc2c126f.zip | |
Restructure POST directory to support of other CPUs, boards, etc.
Diffstat (limited to 'post/cpu/mpc8xx/uart.c')
| -rw-r--r-- | post/cpu/mpc8xx/uart.c | 560 | 
1 files changed, 560 insertions, 0 deletions
| diff --git a/post/cpu/mpc8xx/uart.c b/post/cpu/mpc8xx/uart.c new file mode 100644 index 000000000..fd97e3899 --- /dev/null +++ b/post/cpu/mpc8xx/uart.c @@ -0,0 +1,560 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> + +/* + * UART test + * + * The Serial Management Controllers (SMC) and the Serial Communication + * Controllers (SCC) listed in ctlr_list array below are tested in + * the loopback UART mode. + * The controllers are configured accordingly and several characters + * are transmitted. The configurable test parameters are: + *   MIN_PACKET_LENGTH - minimum size of packet to transmit + *   MAX_PACKET_LENGTH - maximum size of packet to transmit + *   TEST_NUM - number of tests + */ + +#ifdef CONFIG_POST + +#include <post.h> +#if CONFIG_POST & CFG_POST_UART +#if defined(CONFIG_8xx) +#include <commproc.h> +#elif defined(CONFIG_MPC8260) +#include <asm/cpm_8260.h> +#else +#error "Apparently a bad configuration, please fix." +#endif +#include <command.h> +#include <serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define CTLR_SMC 0 +#define CTLR_SCC 1 + +/* The list of controllers to test */ +#if defined(CONFIG_MPC823) +static int ctlr_list[][2] = +		{ {CTLR_SMC, 0}, {CTLR_SMC, 1}, {CTLR_SCC, 1} }; +#else +static int ctlr_list[][2] = { }; +#endif + +#define CTRL_LIST_SIZE (sizeof(ctlr_list) / sizeof(ctlr_list[0])) + +static struct { +	void (*init) (int index); +	void (*halt) (int index); +	void (*putc) (int index, const char c); +	int (*getc) (int index); +} ctlr_proc[2]; + +static char *ctlr_name[2] = { "SMC", "SCC" }; + +static int proff_smc[] = { PROFF_SMC1, PROFF_SMC2 }; +static int proff_scc[] = +		{ PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 }; + +/* + * SMC callbacks + */ + +static void smc_init (int smc_index) +{ +	static int cpm_cr_ch[] = { CPM_CR_CH_SMC1, CPM_CR_CH_SMC2 }; + +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile smc_t *sp; +	volatile smc_uart_t *up; +	volatile cbd_t *tbdf, *rbdf; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	uint dpaddr; + +	/* initialize pointers to SMC */ + +	sp = (smc_t *) & (cp->cp_smc[smc_index]); +	up = (smc_uart_t *) & cp->cp_dparam[proff_smc[smc_index]]; + +	/* Disable transmitter/receiver. +	 */ +	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +	/* Enable SDMA. +	 */ +	im->im_siu_conf.sc_sdcr = 1; + +	/* clear error conditions */ +#ifdef	CFG_SDSR +	im->im_sdma.sdma_sdsr = CFG_SDSR; +#else +	im->im_sdma.sdma_sdsr = 0x83; +#endif + +	/* clear SDMA interrupt mask */ +#ifdef	CFG_SDMR +	im->im_sdma.sdma_sdmr = CFG_SDMR; +#else +	im->im_sdma.sdma_sdmr = 0x00; +#endif + +#if defined(CONFIG_FADS) +	/* Enable RS232 */ +	*((uint *) BCSR1) &= +			~(smc_index == 1 ? BCSR1_RS232EN_1 : BCSR1_RS232EN_2); +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) +	/* Enable Monitor Port Transceiver */ +	*((uchar *) BCSR0) |= BCSR0_ENMONXCVR; +#endif + +	/* Set the physical address of the host memory buffers in +	 * the buffer descriptors. +	 */ + +#ifdef CFG_ALLOC_DPRAM +	dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8); +#else +	dpaddr = CPM_POST_BASE; +#endif + +	/* Allocate space for two buffer descriptors in the DP ram. +	 * For now, this address seems OK, but it may have to +	 * change with newer versions of the firmware. +	 * damm: allocating space after the two buffers for rx/tx data +	 */ + +	rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr]; +	rbdf->cbd_bufaddr = (uint) (rbdf + 2); +	rbdf->cbd_sc = 0; +	tbdf = rbdf + 1; +	tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1; +	tbdf->cbd_sc = 0; + +	/* Set up the uart parameters in the parameter ram. +	 */ +	up->smc_rbase = dpaddr; +	up->smc_tbase = dpaddr + sizeof (cbd_t); +	up->smc_rfcr = SMC_EB; +	up->smc_tfcr = SMC_EB; + +#if defined(CONFIG_MBX) +	board_serial_init (); +#endif + +	/* Set UART mode, 8 bit, no parity, one stop. +	 * Enable receive and transmit. +	 * Set local loopback mode. +	 */ +	sp->smc_smcmr = smcr_mk_clen (9) | SMCMR_SM_UART | (ushort) 0x0004; + +	/* Mask all interrupts and remove anything pending. +	 */ +	sp->smc_smcm = 0; +	sp->smc_smce = 0xff; + +	/* Set up the baud rate generator. +	 */ +	cp->cp_simode = 0x00000000; + +	cp->cp_brgc1 = +			(((gd->cpu_clk / 16 / gd->baudrate) - +			  1) << 1) | CPM_BRG_EN; + +	/* Make the first buffer the only buffer. +	 */ +	tbdf->cbd_sc |= BD_SC_WRAP; +	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + +	/* Single character receive. +	 */ +	up->smc_mrblr = 1; +	up->smc_maxidl = 0; + +	/* Initialize Tx/Rx parameters. +	 */ + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	cp->cp_cpcr = +			mk_cr_cmd (cpm_cr_ch[smc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG; + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	/* Enable transmitter/receiver. +	 */ +	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +static void smc_halt(int smc_index) +{ +} + +static void smc_putc (int smc_index, const char c) +{ +	volatile cbd_t *tbdf; +	volatile char *buf; +	volatile smc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); + +	up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]]; + +	tbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_tbase]; + +	/* Wait for last character to go. +	 */ + +	buf = (char *) tbdf->cbd_bufaddr; +#if 0 +	__asm__ ("eieio"); +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif + +	*buf = c; +	tbdf->cbd_datlen = 1; +	tbdf->cbd_sc |= BD_SC_READY; +	__asm__ ("eieio"); +#if 1 +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif +} + +static int smc_getc (int smc_index) +{ +	volatile cbd_t *rbdf; +	volatile unsigned char *buf; +	volatile smc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); +	unsigned char c; +	int i; + +	up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]]; + +	rbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_rbase]; + +	/* Wait for character to show up. +	 */ +	buf = (unsigned char *) rbdf->cbd_bufaddr; +#if 0 +	while (rbdf->cbd_sc & BD_SC_EMPTY); +#else +	for (i = 100; i > 0; i--) { +		if (!(rbdf->cbd_sc & BD_SC_EMPTY)) +			break; +		udelay (1000); +	} + +	if (i == 0) +		return -1; +#endif +	c = *buf; +	rbdf->cbd_sc |= BD_SC_EMPTY; + +	return (c); +} + +  /* +   * SCC callbacks +   */ + +static void scc_init (int scc_index) +{ +	static int cpm_cr_ch[] = { +		CPM_CR_CH_SCC1, +		CPM_CR_CH_SCC2, +		CPM_CR_CH_SCC3, +		CPM_CR_CH_SCC4, +	}; + +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile scc_t *sp; +	volatile scc_uart_t *up; +	volatile cbd_t *tbdf, *rbdf; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	uint dpaddr; + +	/* initialize pointers to SCC */ + +	sp = (scc_t *) & (cp->cp_scc[scc_index]); +	up = (scc_uart_t *) & cp->cp_dparam[proff_scc[scc_index]]; + +	/* Disable transmitter/receiver. +	 */ +	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + +	/* Allocate space for two buffer descriptors in the DP ram. +	 */ + +#ifdef CFG_ALLOC_DPRAM +	dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8); +#else +	dpaddr = CPM_POST_BASE; +#endif + +	/* Enable SDMA. +	 */ +	im->im_siu_conf.sc_sdcr = 0x0001; + +	/* Set the physical address of the host memory buffers in +	 * the buffer descriptors. +	 */ + +	rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr]; +	rbdf->cbd_bufaddr = (uint) (rbdf + 2); +	rbdf->cbd_sc = 0; +	tbdf = rbdf + 1; +	tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1; +	tbdf->cbd_sc = 0; + +	/* Set up the baud rate generator. +	 */ +	cp->cp_sicr &= ~(0x000000FF << (8 * scc_index)); +	/* no |= needed, since BRG1 is 000 */ + +	cp->cp_brgc1 = +			(((gd->cpu_clk / 16 / gd->baudrate) - +			  1) << 1) | CPM_BRG_EN; + +	/* Set up the uart parameters in the parameter ram. +	 */ +	up->scc_genscc.scc_rbase = dpaddr; +	up->scc_genscc.scc_tbase = dpaddr + sizeof (cbd_t); + +	/* Initialize Tx/Rx parameters. +	 */ +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; +	cp->cp_cpcr = +			mk_cr_cmd (cpm_cr_ch[scc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG; + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	up->scc_genscc.scc_rfcr = SCC_EB | 0x05; +	up->scc_genscc.scc_tfcr = SCC_EB | 0x05; + +	up->scc_genscc.scc_mrblr = 1;	/* Single character receive */ +	up->scc_maxidl = 0;		/* disable max idle */ +	up->scc_brkcr = 1;		/* send one break character on stop TX */ +	up->scc_parec = 0; +	up->scc_frmec = 0; +	up->scc_nosec = 0; +	up->scc_brkec = 0; +	up->scc_uaddr1 = 0; +	up->scc_uaddr2 = 0; +	up->scc_toseq = 0; +	up->scc_char1 = 0x8000; +	up->scc_char2 = 0x8000; +	up->scc_char3 = 0x8000; +	up->scc_char4 = 0x8000; +	up->scc_char5 = 0x8000; +	up->scc_char6 = 0x8000; +	up->scc_char7 = 0x8000; +	up->scc_char8 = 0x8000; +	up->scc_rccm = 0xc0ff; + +	/* Set low latency / small fifo. +	 */ +	sp->scc_gsmrh = SCC_GSMRH_RFW; + +	/* Set UART mode +	 */ +	sp->scc_gsmrl &= ~0xF; +	sp->scc_gsmrl |= SCC_GSMRL_MODE_UART; + +	/* Set local loopback mode. +	 */ +	sp->scc_gsmrl &= ~SCC_GSMRL_DIAG_LE; +	sp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP; + +	/* Set clock divider 16 on Tx and Rx +	 */ +	sp->scc_gsmrl |= (SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + +	sp->scc_psmr |= SCU_PSMR_CL; + +	/* Mask all interrupts and remove anything pending. +	 */ +	sp->scc_sccm = 0; +	sp->scc_scce = 0xffff; +	sp->scc_dsr = 0x7e7e; +	sp->scc_psmr = 0x3000; + +	/* Make the first buffer the only buffer. +	 */ +	tbdf->cbd_sc |= BD_SC_WRAP; +	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + +	/* Enable transmitter/receiver. +	 */ +	sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +} + +static void scc_halt(int scc_index) +{ +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	volatile scc_t *sp = (scc_t *) & (cp->cp_scc[scc_index]); + +	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT | SCC_GSMRL_DIAG_LE); +} + +static void scc_putc (int scc_index, const char c) +{ +	volatile cbd_t *tbdf; +	volatile char *buf; +	volatile scc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); + +	up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]]; + +	tbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_tbase]; + +	/* Wait for last character to go. +	 */ + +	buf = (char *) tbdf->cbd_bufaddr; +#if 0 +	__asm__ ("eieio"); +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif + +	*buf = c; +	tbdf->cbd_datlen = 1; +	tbdf->cbd_sc |= BD_SC_READY; +	__asm__ ("eieio"); +#if 1 +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif +} + +static int scc_getc (int scc_index) +{ +	volatile cbd_t *rbdf; +	volatile unsigned char *buf; +	volatile scc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); +	unsigned char c; +	int i; + +	up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]]; + +	rbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; + +	/* Wait for character to show up. +	 */ +	buf = (unsigned char *) rbdf->cbd_bufaddr; +#if 0 +	while (rbdf->cbd_sc & BD_SC_EMPTY); +#else +	for (i = 100; i > 0; i--) { +		if (!(rbdf->cbd_sc & BD_SC_EMPTY)) +			break; +		udelay (1000); +	} + +	if (i == 0) +		return -1; +#endif +	c = *buf; +	rbdf->cbd_sc |= BD_SC_EMPTY; + +	return (c); +} + +  /* +   * Test routines +   */ + +static int test_ctlr (int ctlr, int index) +{ +	int res = -1; +	char test_str[] = "*** UART Test String ***\r\n"; +	int i; + +	ctlr_proc[ctlr].init (index); + +	for (i = 0; i < sizeof (test_str) - 1; i++) { +		ctlr_proc[ctlr].putc (index, test_str[i]); +		if (ctlr_proc[ctlr].getc (index) != test_str[i]) +			goto Done; +	} + +	res = 0; + +Done: +	ctlr_proc[ctlr].halt (index); + +	if (res != 0) { +		post_log ("uart %s%d test failed\n", +				ctlr_name[ctlr], index + 1); +	} + +	return res; +} + +int uart_post_test (int flags) +{ +	int res = 0; +	int i; + +	ctlr_proc[CTLR_SMC].init = smc_init; +	ctlr_proc[CTLR_SMC].halt = smc_halt; +	ctlr_proc[CTLR_SMC].putc = smc_putc; +	ctlr_proc[CTLR_SMC].getc = smc_getc; + +	ctlr_proc[CTLR_SCC].init = scc_init; +	ctlr_proc[CTLR_SCC].halt = scc_halt; +	ctlr_proc[CTLR_SCC].putc = scc_putc; +	ctlr_proc[CTLR_SCC].getc = scc_getc; + +	for (i = 0; i < CTRL_LIST_SIZE; i++) { +		if (test_ctlr (ctlr_list[i][0], ctlr_list[i][1]) != 0) { +			res = -1; +		} +	} + +#if !defined(CONFIG_8xx_CONS_NONE) +	serial_reinit_all (); +#endif + +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_UART */ + +#endif /* CONFIG_POST */ |