mirror of https://gitee.com/openkylin/linux.git
326 lines
7.4 KiB
C
326 lines
7.4 KiB
C
/* Minimal serial functions needed to send messages out the serial
|
|
* port on SMC1.
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <asm/mpc8260.h>
|
|
#include <asm/cpm2.h>
|
|
#include <asm/immap_cpm2.h>
|
|
|
|
uint no_print;
|
|
extern char *params[];
|
|
extern int nparams;
|
|
static u_char cons_hold[128], *sgptr;
|
|
static int cons_hold_cnt;
|
|
|
|
/* If defined, enables serial console. The value (1 through 4)
|
|
* should designate which SCC is used, but this isn't complete. Only
|
|
* SCC1 is known to work at this time.
|
|
* We're only linked if SERIAL_CPM_CONSOLE=y, so we only need to test
|
|
* SERIAL_CPM_SCC1.
|
|
*/
|
|
#ifdef CONFIG_SERIAL_CPM_SCC1
|
|
#define SCC_CONSOLE 1
|
|
#endif
|
|
|
|
unsigned long
|
|
serial_init(int ignored, bd_t *bd)
|
|
{
|
|
#ifdef SCC_CONSOLE
|
|
volatile scc_t *sccp;
|
|
volatile scc_uart_t *sup;
|
|
#else
|
|
volatile smc_t *sp;
|
|
volatile smc_uart_t *up;
|
|
#endif
|
|
volatile cbd_t *tbdf, *rbdf;
|
|
volatile cpm2_map_t *ip;
|
|
volatile iop_cpm2_t *io;
|
|
volatile cpm_cpm2_t *cp;
|
|
uint dpaddr, memaddr;
|
|
|
|
ip = (cpm2_map_t *)CPM_MAP_ADDR;
|
|
cp = &ip->im_cpm;
|
|
io = &ip->im_ioport;
|
|
|
|
/* Perform a reset.
|
|
*/
|
|
cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
|
|
|
|
/* Wait for it.
|
|
*/
|
|
while (cp->cp_cpcr & CPM_CR_FLG);
|
|
|
|
#ifdef CONFIG_ADS8260
|
|
/* Enable the RS-232 transceivers.
|
|
*/
|
|
*(volatile uint *)(BCSR_ADDR + 4) &=
|
|
~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2);
|
|
#endif
|
|
|
|
#ifdef SCC_CONSOLE
|
|
sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]);
|
|
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
|
|
sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
|
|
sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
|
|
|
|
/* Use Port D for SCC1 instead of other functions.
|
|
*/
|
|
io->iop_ppard |= 0x00000003;
|
|
io->iop_psord &= ~0x00000001; /* Rx */
|
|
io->iop_psord |= 0x00000002; /* Tx */
|
|
io->iop_pdird &= ~0x00000001; /* Rx */
|
|
io->iop_pdird |= 0x00000002; /* Tx */
|
|
|
|
#else
|
|
sp = (smc_t*)&(ip->im_smc[0]);
|
|
*(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
|
|
up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1];
|
|
|
|
/* Disable transmitter/receiver.
|
|
*/
|
|
sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
|
|
|
|
/* Use Port D for SMC1 instead of other functions.
|
|
*/
|
|
io->iop_ppard |= 0x00c00000;
|
|
io->iop_pdird |= 0x00400000;
|
|
io->iop_pdird &= ~0x00800000;
|
|
io->iop_psord &= ~0x00c00000;
|
|
#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.
|
|
*/
|
|
dpaddr = 0x0800;
|
|
|
|
/* Grab a few bytes from the top of memory.
|
|
*/
|
|
memaddr = (bd->bi_memsize - 256) & ~15;
|
|
|
|
/* Set the physical address of the host memory buffers in
|
|
* the buffer descriptors.
|
|
*/
|
|
rbdf = (cbd_t *)&ip->im_dprambase[dpaddr];
|
|
rbdf->cbd_bufaddr = memaddr;
|
|
rbdf->cbd_sc = 0;
|
|
tbdf = rbdf + 1;
|
|
tbdf->cbd_bufaddr = memaddr+128;
|
|
tbdf->cbd_sc = 0;
|
|
|
|
/* Set up the uart parameters in the parameter ram.
|
|
*/
|
|
#ifdef SCC_CONSOLE
|
|
sup->scc_genscc.scc_rbase = dpaddr;
|
|
sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t);
|
|
|
|
/* Set up the uart parameters in the
|
|
* parameter ram.
|
|
*/
|
|
sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
|
|
sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
|
|
|
|
sup->scc_genscc.scc_mrblr = 128;
|
|
sup->scc_maxidl = 8;
|
|
sup->scc_brkcr = 1;
|
|
sup->scc_parec = 0;
|
|
sup->scc_frmec = 0;
|
|
sup->scc_nosec = 0;
|
|
sup->scc_brkec = 0;
|
|
sup->scc_uaddr1 = 0;
|
|
sup->scc_uaddr2 = 0;
|
|
sup->scc_toseq = 0;
|
|
sup->scc_char1 = 0x8000;
|
|
sup->scc_char2 = 0x8000;
|
|
sup->scc_char3 = 0x8000;
|
|
sup->scc_char4 = 0x8000;
|
|
sup->scc_char5 = 0x8000;
|
|
sup->scc_char6 = 0x8000;
|
|
sup->scc_char7 = 0x8000;
|
|
sup->scc_char8 = 0x8000;
|
|
sup->scc_rccm = 0xc0ff;
|
|
|
|
/* Send the CPM an initialize command.
|
|
*/
|
|
cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
|
|
CPM_CR_INIT_TRX) | CPM_CR_FLG;
|
|
while (cp->cp_cpcr & CPM_CR_FLG);
|
|
|
|
/* Set UART mode, 8 bit, no parity, one stop.
|
|
* Enable receive and transmit.
|
|
*/
|
|
sccp->scc_gsmrh = 0;
|
|
sccp->scc_gsmrl =
|
|
(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
|
|
|
|
/* Disable all interrupts and clear all pending
|
|
* events.
|
|
*/
|
|
sccp->scc_sccm = 0;
|
|
sccp->scc_scce = 0xffff;
|
|
sccp->scc_dsr = 0x7e7e;
|
|
sccp->scc_psmr = 0x3000;
|
|
|
|
/* Wire BRG1 to SCC1. The console driver will take care of
|
|
* others.
|
|
*/
|
|
ip->im_cpmux.cmx_scr = 0;
|
|
#else
|
|
up->smc_rbase = dpaddr;
|
|
up->smc_tbase = dpaddr+sizeof(cbd_t);
|
|
up->smc_rfcr = CPMFCR_EB;
|
|
up->smc_tfcr = CPMFCR_EB;
|
|
up->smc_brklen = 0;
|
|
up->smc_brkec = 0;
|
|
up->smc_brkcr = 0;
|
|
up->smc_mrblr = 128;
|
|
up->smc_maxidl = 8;
|
|
|
|
/* Set UART mode, 8 bit, no parity, one stop.
|
|
* Enable receive and transmit.
|
|
*/
|
|
sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
|
|
|
|
/* Mask all interrupts and remove anything pending.
|
|
*/
|
|
sp->smc_smcm = 0;
|
|
sp->smc_smce = 0xff;
|
|
|
|
/* Set up the baud rate generator.
|
|
*/
|
|
ip->im_cpmux.cmx_smr = 0;
|
|
#endif
|
|
|
|
/* The baud rate divisor needs to be coordinated with clk_8260().
|
|
*/
|
|
ip->im_brgc1 =
|
|
(((bd->bi_brgfreq/16) / bd->bi_baudrate) << 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;
|
|
|
|
/* Initialize Tx/Rx parameters.
|
|
*/
|
|
#ifdef SCC_CONSOLE
|
|
sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
|
|
#else
|
|
cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
|
|
while (cp->cp_cpcr & CPM_CR_FLG);
|
|
|
|
/* Enable transmitter/receiver.
|
|
*/
|
|
sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
|
|
#endif
|
|
|
|
/* This is ignored.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
serial_readbuf(u_char *cbuf)
|
|
{
|
|
volatile cbd_t *rbdf;
|
|
volatile char *buf;
|
|
#ifdef SCC_CONSOLE
|
|
volatile scc_uart_t *sup;
|
|
#else
|
|
volatile smc_uart_t *up;
|
|
#endif
|
|
volatile cpm2_map_t *ip;
|
|
int i, nc;
|
|
|
|
ip = (cpm2_map_t *)CPM_MAP_ADDR;
|
|
|
|
#ifdef SCC_CONSOLE
|
|
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
|
|
rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase];
|
|
#else
|
|
up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
|
|
rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
|
|
#endif
|
|
|
|
/* Wait for character to show up.
|
|
*/
|
|
buf = (char *)rbdf->cbd_bufaddr;
|
|
while (rbdf->cbd_sc & BD_SC_EMPTY);
|
|
nc = rbdf->cbd_datlen;
|
|
for (i=0; i<nc; i++)
|
|
*cbuf++ = *buf++;
|
|
rbdf->cbd_sc |= BD_SC_EMPTY;
|
|
|
|
return(nc);
|
|
}
|
|
|
|
void
|
|
serial_putc(void *ignored, const char c)
|
|
{
|
|
volatile cbd_t *tbdf;
|
|
volatile char *buf;
|
|
#ifdef SCC_CONSOLE
|
|
volatile scc_uart_t *sup;
|
|
#else
|
|
volatile smc_uart_t *up;
|
|
#endif
|
|
volatile cpm2_map_t *ip;
|
|
|
|
ip = (cpm2_map_t *)CPM_MAP_ADDR;
|
|
#ifdef SCC_CONSOLE
|
|
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
|
|
tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase];
|
|
#else
|
|
up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
|
|
tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase];
|
|
#endif
|
|
|
|
/* Wait for last character to go.
|
|
*/
|
|
buf = (char *)tbdf->cbd_bufaddr;
|
|
while (tbdf->cbd_sc & BD_SC_READY);
|
|
|
|
*buf = c;
|
|
tbdf->cbd_datlen = 1;
|
|
tbdf->cbd_sc |= BD_SC_READY;
|
|
}
|
|
|
|
char
|
|
serial_getc(void *ignored)
|
|
{
|
|
char c;
|
|
|
|
if (cons_hold_cnt <= 0) {
|
|
cons_hold_cnt = serial_readbuf(cons_hold);
|
|
sgptr = cons_hold;
|
|
}
|
|
c = *sgptr++;
|
|
cons_hold_cnt--;
|
|
|
|
return(c);
|
|
}
|
|
|
|
int
|
|
serial_tstc(void *ignored)
|
|
{
|
|
volatile cbd_t *rbdf;
|
|
#ifdef SCC_CONSOLE
|
|
volatile scc_uart_t *sup;
|
|
#else
|
|
volatile smc_uart_t *up;
|
|
#endif
|
|
volatile cpm2_map_t *ip;
|
|
|
|
ip = (cpm2_map_t *)CPM_MAP_ADDR;
|
|
#ifdef SCC_CONSOLE
|
|
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
|
|
rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase];
|
|
#else
|
|
up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
|
|
rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
|
|
#endif
|
|
|
|
return(!(rbdf->cbd_sc & BD_SC_EMPTY));
|
|
}
|