Skip to content
Snippets Groups Projects
Commit 121cb96d authored by Wolfgang Denk's avatar Wolfgang Denk
Browse files

Initial revision

parent 82e299bf
No related branches found
No related tags found
No related merge requests found
/*
* This file is based on "arch/ppc/8260_io/commproc.c" - here is it's
* copyright notice:
*
* General Purpose functions for the global management of the
* 8260 Communication Processor Module.
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
* Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
* 2.3.99 Updates
*
* In addition to the individual control of the communication
* channels, there are a few functions that globally affect the
* communication processor.
*
* Buffer descriptors must be allocated from the dual ported memory
* space. The allocator for that is here. When the communication
* process is reset, we reclaim the memory available. There is
* currently no deallocator for this memory.
*/
#include <common.h>
#include <asm/cpm_8260.h>
/*
* because we have stack and init data in dual port ram
* we must reduce the size
*/
#undef CPM_DATAONLY_SIZE
#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE)
void
m8260_cpm_reset(void)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile ulong count;
/* Reclaim the DP memory for our use.
*/
gd->dp_alloc_base = CPM_DATAONLY_BASE;
gd->dp_alloc_top = gd->dp_alloc_base + CPM_DATAONLY_SIZE;
/*
* Reset CPM
*/
immr->im_cpm.cp_cpcr = CPM_CR_RST;
count = 0;
do { /* Spin until command processed */
__asm__ __volatile__ ("eieio");
} while ((immr->im_cpm.cp_cpcr & CPM_CR_FLG) && ++count < 1000000);
#ifdef CONFIG_HARD_I2C
*((unsigned short*)(&immr->im_dprambase[PROFF_I2C_BASE])) = 0;
#endif
}
/* Allocate some memory from the dual ported ram.
* To help protocols with object alignment restrictions, we do that
* if they ask.
*/
uint
m8260_cpm_dpalloc(uint size, uint align)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
uint retloc;
uint align_mask, off;
uint savebase;
align_mask = align - 1;
savebase = gd->dp_alloc_base;
if ((off = (gd->dp_alloc_base & align_mask)) != 0)
gd->dp_alloc_base += (align - off);
if ((off = size & align_mask) != 0)
size += align - off;
if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top) {
gd->dp_alloc_base = savebase;
panic("m8260_cpm_dpalloc: ran out of dual port ram!");
}
retloc = gd->dp_alloc_base;
gd->dp_alloc_base += size;
memset((void *)&immr->im_dprambase[retloc], 0, size);
return(retloc);
}
/* We also own one page of host buffer space for the allocation of
* UART "fifos" and the like.
*/
uint
m8260_cpm_hostalloc(uint size, uint align)
{
/* the host might not even have RAM yet - just use dual port RAM */
return (m8260_cpm_dpalloc(size, align));
}
/* Set a baud rate generator. This needs lots of work. There are
* eight BRGs, which can be connected to the CPM channels or output
* as clocks. The BRGs are in two different block of internal
* memory mapped space.
* The baud rate clock is the system clock divided by something.
* It was set up long ago during the initial boot phase and is
* is given to us.
* Baud rate clocks are zero-based in the driver code (as that maps
* to port numbers). Documentation uses 1-based numbering.
*/
#define BRG_INT_CLK gd->brg_clk
#define BRG_UART_CLK ((BRG_INT_CLK + 15) / 16)
/* This function is used by UARTS, or anything else that uses a 16x
* oversampled clock.
*/
void
m8260_cpm_setbrg(uint brg, uint rate)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile uint *bp;
/* This is good enough to get SMCs running.....
*/
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = (((((BRG_UART_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
}
/* This function is used to set high speed synchronous baud rate
* clocks.
*/
void
m8260_cpm_fastbrg(uint brg, uint rate, int div16)
{
DECLARE_GLOBAL_DATA_PTR;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile uint *bp;
/* This is good enough to get SMCs running.....
*/
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
if (div16)
*bp |= CPM_BRG_DIV16;
}
/* This function is used to set baud rate generators using an external
* clock source and 16x oversampling.
*/
void
m8260_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile uint *bp;
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
brg -= 4;
}
bp += brg;
*bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
if (pinsel == 0)
*bp |= CPM_BRG_EXTC_CLK3_9;
else
*bp |= CPM_BRG_EXTC_CLK5_15;
}
#ifdef CONFIG_POST
void post_word_store (ulong a)
{
volatile ulong *save_addr =
(volatile ulong *)(CFG_IMMR + CPM_POST_WORD_ADDR);
*save_addr = a;
}
ulong post_word_load (void)
{
volatile ulong *save_addr =
(volatile ulong *)(CFG_IMMR + CPM_POST_WORD_ADDR);
return *save_addr;
}
#endif /* CONFIG_POST */
This diff is collapsed.
/*
* (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 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 <net.h>
#if CONFIG_POST & CFG_POST_UART
#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 (*putc) (int index, const char c);
int (*getc) (int index);
} ctlr_proc[2];
static char *ctlr_name[2] = { "SMC", "SCC" };
static int used_by_uart[2] = { -1, -1 };
static int used_by_ether[2] = { -1, -1 };
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)
{
DECLARE_GLOBAL_DATA_PTR;
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_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)
{
DECLARE_GLOBAL_DATA_PTR;
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_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;
#if !defined(CONFIG_8xx_CONS_NONE)
if (used_by_uart[ctlr] == index) {
while (ctlr_proc[ctlr].getc (index) != -1);
}
#endif
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:
#if !defined(CONFIG_8xx_CONS_NONE)
if (used_by_uart[ctlr] == index) {
serial_init ();
}
#endif
#if defined(SCC_ENET)
if (used_by_ether[ctlr] == index) {
DECLARE_GLOBAL_DATA_PTR;
eth_init (gd->bd);
}
#endif
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;
#if defined(CONFIG_8xx_CONS_SMC1)
used_by_uart[CTLR_SMC] = 0;
#elif defined(CONFIG_8xx_CONS_SMC2)
used_by_uart[CTLR_SMC] = 1;
#elif defined(CONFIG_8xx_CONS_SCC1)
used_by_uart[CTLR_SCC] = 0;
#elif defined(CONFIG_8xx_CONS_SCC2)
used_by_uart[CTLR_SCC] = 1;
#elif defined(CONFIG_8xx_CONS_SCC3)
used_by_uart[CTLR_SCC] = 2;
#elif defined(CONFIG_8xx_CONS_SCC4)
used_by_uart[CTLR_SCC] = 3;
#endif
#if defined(SCC_ENET)
used_by_ether[CTLR_SCC] = SCC_ENET;
#endif
ctlr_proc[CTLR_SMC].init = smc_init;
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].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;
}
}
return res;
}
#endif /* CONFIG_POST & CFG_POST_UART */
#endif /* CONFIG_POST */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment