diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:02:15 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:02:15 +0200 |
commit | f59546b79bcad4d65b84208817ab740214e78340 (patch) | |
tree | 142f4c2e3749509cd9be24da63b210fb553d2b47 /drivers | |
parent | 4f69d7aa1a4ff6f871ff0f95b76c1b6b4d03d87c (diff) | |
download | barebox-f59546b79bcad4d65b84208817ab740214e78340.tar.gz barebox-f59546b79bcad4d65b84208817ab740214e78340.tar.xz |
svn_rev_675
move serial and network drivers from cpu/ to drivers/
Diffstat (limited to 'drivers')
26 files changed, 7171 insertions, 0 deletions
diff --git a/drivers/net/fec_mpc8xx.c b/drivers/net/fec_mpc8xx.c new file mode 100644 index 0000000000..18464ba80f --- /dev/null +++ b/drivers/net/fec_mpc8xx.c @@ -0,0 +1,1016 @@ +/* + * (C) Copyright 2000 + * 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> +#include <malloc.h> +#include <commproc.h> +#include <net.h> +#include <command.h> + +DECLARE_GLOBAL_DATA_PTR; + +#undef ET_DEBUG + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && \ + (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2)) + +/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */ +#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2) +#define CONFIG_ETHER_ON_FEC1 1 +#endif + +/* define WANT_MII when MII support is required */ +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY) +#define WANT_MII +#else +#undef WANT_MII +#endif + +#if defined(WANT_MII) +#include <miiphy.h> + +#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) +#error "CONFIG_MII has to be defined!" +#endif + +#endif + +#if defined(CONFIG_RMII) && !defined(WANT_MII) +#error RMII support is unusable without a working PHY. +#endif + +#ifdef CFG_DISCOVER_PHY +static int mii_discover_phy(struct eth_device *dev); +#endif + +int fec8xx_miiphy_read(char *devname, unsigned char addr, + unsigned char reg, unsigned short *value); +int fec8xx_miiphy_write(char *devname, unsigned char addr, + unsigned char reg, unsigned short value); + +static struct ether_fcc_info_s +{ + int ether_index; + int fecp_offset; + int phy_addr; + int actual_phy_addr; + int initialized; +} + ether_fcc_info[] = { +#if defined(CONFIG_ETHER_ON_FEC1) + { + 0, + offsetof(immap_t, im_cpm.cp_fec1), +#if defined(CONFIG_FEC1_PHY) + CONFIG_FEC1_PHY, +#else + -1, /* discover */ +#endif + -1, + 0, + + }, +#endif +#if defined(CONFIG_ETHER_ON_FEC2) + { + 1, + offsetof(immap_t, im_cpm.cp_fec2), +#if defined(CONFIG_FEC2_PHY) + CONFIG_FEC2_PHY, +#else + -1, +#endif + -1, + 0, + }, +#endif +}; + +/* Ethernet Transmit and Receive Buffers */ +#define DBUF_LENGTH 1520 + +#define TX_BUF_CNT 2 + +#define TOUT_LOOP 100 + +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +#ifdef __GNUC__ +static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8))); +#else +#error txbuf must be aligned. +#endif + +static uint rxIdx; /* index of the current RX buffer */ +static uint txIdx; /* index of the current TX buffer */ + +/* + * FEC Ethernet Tx and Rx buffer descriptors allocated at the + * immr->udata_bd address on Dual-Port RAM + * Provide for Double Buffering + */ + +typedef volatile struct CommonBufferDescriptor { + cbd_t rxbd[PKTBUFSRX]; /* Rx BD */ + cbd_t txbd[TX_BUF_CNT]; /* Tx BD */ +} RTXBD; + +static RTXBD *rtx = NULL; + +static int fec_send(struct eth_device* dev, volatile void *packet, int length); +static int fec_recv(struct eth_device* dev); +static int fec_init(struct eth_device* dev, bd_t * bd); +static void fec_halt(struct eth_device* dev); + +int fec_initialize(bd_t *bis) +{ + struct eth_device* dev; + struct ether_fcc_info_s *efis; + int i; + + for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) { + + dev = malloc(sizeof(*dev)); + if (dev == NULL) + hang(); + + memset(dev, 0, sizeof(*dev)); + + /* for FEC1 make sure that the name of the interface is the same + as the old one for compatibility reasons */ + if (i == 0) { + sprintf (dev->name, "FEC ETHERNET"); + } else { + sprintf (dev->name, "FEC%d ETHERNET", + ether_fcc_info[i].ether_index + 1); + } + + efis = ðer_fcc_info[i]; + + /* + * reset actual phy addr + */ + efis->actual_phy_addr = -1; + + dev->priv = efis; + dev->init = fec_init; + dev->halt = fec_halt; + dev->send = fec_send; + dev->recv = fec_recv; + + eth_register(dev); + +#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) + miiphy_register(dev->name, + fec8xx_miiphy_read, fec8xx_miiphy_write); +#endif + } + return 1; +} + +static int fec_send(struct eth_device* dev, volatile void *packet, int length) +{ + int j, rc; + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + + /* section 16.9.23.3 + * Wait for ready + */ + j = 0; + while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) { + udelay(1); + j++; + } + if (j>=TOUT_LOOP) { + printf("TX not ready\n"); + } + + rtx->txbd[txIdx].cbd_bufaddr = (uint)packet; + rtx->txbd[txIdx].cbd_datlen = length; + rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST; + __asm__ ("eieio"); + + /* Activate transmit Buffer Descriptor polling */ + fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */ + + j = 0; + while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) { +#if defined(CONFIG_ICU862) + udelay(10); +#else + udelay(1); +#endif + j++; + } + if (j>=TOUT_LOOP) { + printf("TX timeout\n"); + } +#ifdef ET_DEBUG + printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", + __FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc, + (rtx->txbd[txIdx].cbd_sc & 0x003C)>>2); +#endif + /* return only status bits */; + rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS); + + txIdx = (txIdx + 1) % TX_BUF_CNT; + + return rc; +} + +static int fec_recv (struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = + (volatile fec_t *) (CFG_IMMR + efis->fecp_offset); + int length; + + for (;;) { + /* section 16.9.23.2 */ + if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { + length = -1; + break; /* nothing received - leave for() loop */ + } + + length = rtx->rxbd[rxIdx].cbd_datlen; + + if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) { +#ifdef ET_DEBUG + printf ("%s[%d] err: %x\n", + __FUNCTION__, __LINE__, + rtx->rxbd[rxIdx].cbd_sc); +#endif + } else { + volatile uchar *rx = NetRxPackets[rxIdx]; + + length -= 4; + +#if (CONFIG_COMMANDS & CFG_CMD_CDP) + if ((rx[0] & 1) != 0 + && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0 + && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0) + rx = NULL; +#endif + /* + * Pass the packet up to the protocol layers. + */ + if (rx != NULL) + NetReceive (rx, length); + } + + /* Give the buffer back to the FEC. */ + rtx->rxbd[rxIdx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if ((rxIdx + 1) >= PKTBUFSRX) { + rtx->rxbd[PKTBUFSRX - 1].cbd_sc = + (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + rxIdx = 0; + } else { + rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; + rxIdx++; + } + + __asm__ ("eieio"); + + /* Try to fill Buffer Descriptors */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + } + + return length; +} + +/************************************************************** + * + * FEC Ethernet Initialization Routine + * + *************************************************************/ + +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + +#define FEC_RESET_DELAY 50 + +#if defined(CONFIG_RMII) + +static inline void fec_10Mbps(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; + + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr |= mask; +} + +static inline void fec_100Mbps(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; + + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr &= ~mask; +} + +#endif + +static inline void fec_full_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT; + fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */ +} + +static inline void fec_half_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl |= FEC_RCNTRL_DRT; + fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */ +} + +static void fec_pin_init(int fecidx) +{ + bd_t *bd = gd->bd; + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile fec_t *fecp; + + /* + * only two FECs please + */ + if ((unsigned int)fecidx >= 2) + hang(); + + if (fecidx == 0) + fecp = &immr->im_cpm.cp_fec1; + else + fecp = &immr->im_cpm.cp_fec2; + + /* + * Set MII speed to 2.5 MHz or slightly below. + * * According to the MPC860T (Rev. D) Fast ethernet controller user + * * manual (6.2.14), + * * the MII management interface clock must be less than or equal + * * to 2.5 MHz. + * * This MDC frequency is equal to system clock / (2 * MII_SPEED). + * * Then MII_SPEED = system_clock / 2 * 2,5 Mhz. + * + * All MII configuration is done via FEC1 registers: + */ + immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1; + +#if defined(CONFIG_NETTA) || defined(CONFIG_NETPHONE) || defined(CONFIG_NETTA2) + /* our PHYs are the limit at 2.5 MHz */ + fecp->fec_mii_speed <<= 1; +#endif + +#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII) + /* use MDC for MII */ + immr->im_ioport.iop_pdpar |= 0x0080; + immr->im_ioport.iop_pddir &= ~0x0080; +#endif + + if (fecidx == 0) { +#if defined(CONFIG_ETHER_ON_FEC1) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + + immr->im_ioport.iop_papar |= 0xf830; + immr->im_ioport.iop_padir |= 0x0830; + immr->im_ioport.iop_padir &= ~0xf000; + + immr->im_cpm.cp_pbpar |= 0x00001001; + immr->im_cpm.cp_pbdir &= ~0x00001001; + + immr->im_ioport.iop_pcpar |= 0x000c; + immr->im_ioport.iop_pcdir &= ~0x000c; + + immr->im_cpm.cp_pepar |= 0x00000003; + immr->im_cpm.cp_pedir |= 0x00000003; + immr->im_cpm.cp_peso &= ~0x00000003; + + immr->im_cpm.cp_cptr &= ~0x00000100; + +#else + +#if !defined(CONFIG_FEC1_PHY_NORXERR) + immr->im_ioport.iop_papar |= 0x1000; + immr->im_ioport.iop_padir &= ~0x1000; +#endif + immr->im_ioport.iop_papar |= 0xe810; + immr->im_ioport.iop_padir |= 0x0810; + immr->im_ioport.iop_padir &= ~0xe000; + + immr->im_cpm.cp_pbpar |= 0x00000001; + immr->im_cpm.cp_pbdir &= ~0x00000001; + + immr->im_cpm.cp_cptr |= 0x00000100; + immr->im_cpm.cp_cptr &= ~0x00000050; + +#endif /* !CONFIG_RMII */ + +#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210) + /* + * Configure all of port D for MII. + */ + immr->im_ioport.iop_pdpar = 0x1fff; + + /* + * Bits moved from Rev. D onward + */ + if ((get_immr(0) & 0xffff) < 0x0501) + immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ + else + immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ +#else + /* + * Configure port A for MII. + */ + +#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY) + + /* + * On the ICU862 board the MII-MDC pin is routed to PD8 pin + * * of CPU, so for this board we need to configure Utopia and + * * enable PD8 to MII-MDC function + */ + immr->im_ioport.iop_pdpar |= 0x4080; +#endif + + /* + * Has Utopia been configured? + */ + if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) { + /* + * YES - Use MUXED mode for UTOPIA bus. + * This frees Port A for use by MII (see 862UM table 41-6). + */ + immr->im_ioport.utmode &= ~0x80; + } else { + /* + * NO - set SPLIT mode for UTOPIA bus. + * + * This doesn't really effect UTOPIA (which isn't + * enabled anyway) but just tells the 862 + * to use port A for MII (see 862UM table 41-6). + */ + immr->im_ioport.utmode |= 0x80; + } +#endif /* !defined(CONFIG_ICU862) */ + +#endif /* CONFIG_ETHER_ON_FEC1 */ + } else if (fecidx == 1) { + +#if defined(CONFIG_ETHER_ON_FEC2) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + immr->im_cpm.cp_pepar |= 0x0003fffc; + immr->im_cpm.cp_pedir |= 0x0003fffc; + immr->im_cpm.cp_peso &= ~0x000087fc; + immr->im_cpm.cp_peso |= 0x00037800; + + immr->im_cpm.cp_cptr &= ~0x00000080; +#else + +#if !defined(CONFIG_FEC2_PHY_NORXERR) + immr->im_cpm.cp_pepar |= 0x00000010; + immr->im_cpm.cp_pedir |= 0x00000010; + immr->im_cpm.cp_peso &= ~0x00000010; +#endif + immr->im_cpm.cp_pepar |= 0x00039620; + immr->im_cpm.cp_pedir |= 0x00039620; + immr->im_cpm.cp_peso |= 0x00031000; + immr->im_cpm.cp_peso &= ~0x00008620; + + immr->im_cpm.cp_cptr |= 0x00000080; + immr->im_cpm.cp_cptr &= ~0x00000028; +#endif /* CONFIG_RMII */ + +#endif /* CONFIG_MPC885_FAMILY */ + +#endif /* CONFIG_ETHER_ON_FEC2 */ + + } +} + +static int fec_init (struct eth_device *dev, bd_t * bd) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile fec_t *fecp = + (volatile fec_t *) (CFG_IMMR + efis->fecp_offset); + int i; + + if (efis->ether_index == 0) { +#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */ +#if defined(CONFIG_MPC885ADS) + *(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST); +#else + /* configure FADS for fast (FEC) ethernet, half-duplex */ + /* The LXT970 needs about 50ms to recover from reset, so + * wait for it by discovering the PHY before leaving eth_init(). + */ + { + volatile uint *bcsr4 = (volatile uint *) BCSR4; + + *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1)) + | (BCSR4_FETHCFG0 | BCSR4_FETHFDE | + BCSR4_FETHRST); + + /* reset the LXT970 PHY */ + *bcsr4 &= ~BCSR4_FETHRST; + udelay (10); + *bcsr4 |= BCSR4_FETHRST; + udelay (10); + } +#endif /* CONFIG_MPC885ADS */ +#endif /* CONFIG_FADS */ + } + + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) { + printf ("FEC_RESET_DELAY timeout\n"); + return 0; + } + + /* We use strictly polling mode only + */ + fecp->fec_imask = 0; + + /* Clear any pending interrupt + */ + fecp->fec_ievent = 0xffc0; + + /* No need to set the IVEC register */ + + /* Set station address + */ +#define ea eth_get_dev()->enetaddr + fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); + fecp->fec_addr_high = (ea[4] << 8) | (ea[5]); +#undef ea + +#if (CONFIG_COMMANDS & CFG_CMD_CDP) + /* + * Turn on multicast address hash table + */ + fecp->fec_hash_table_high = 0xffffffff; + fecp->fec_hash_table_low = 0xffffffff; +#else + /* Clear multicast address hash table + */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; +#endif + + /* Set maximum receive buffer size. + */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + + /* Set maximum frame length + */ + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + + /* + * Setup Buffers and Buffer Desriptors + */ + rxIdx = 0; + txIdx = 0; + + if (!rtx) { +#ifdef CFG_ALLOC_DPRAM + rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + + dpram_alloc_align (sizeof (RTXBD), 8)); +#else + rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE); +#endif + } + /* + * Setup Receiver Buffer Descriptors (13.14.24.18) + * Settings: + * Empty, Wrap + */ + for (i = 0; i < PKTBUFSRX; i++) { + rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; + rtx->rxbd[i].cbd_datlen = 0; /* Reset */ + rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i]; + } + rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; + + /* + * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19) + * Settings: + * Last, Tx CRC + */ + for (i = 0; i < TX_BUF_CNT; i++) { + rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; + rtx->txbd[i].cbd_datlen = 0; /* Reset */ + rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]); + } + rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; + + /* Set receive and transmit descriptor base + */ + fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]); + fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]); + + /* Enable MII mode + */ + fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT; + fecp->fec_x_cntrl = 0; + + /* Enable big endian and don't care about SDMA FC. + */ + fecp->fec_fun_code = 0x78000000; + + /* + * Setup the pin configuration of the FEC + */ + fec_pin_init (efis->ether_index); + + rxIdx = 0; + txIdx = 0; + + /* + * Now enable the transmit and receive processing + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; + + if (efis->phy_addr == -1) { +#ifdef CFG_DISCOVER_PHY + /* + * wait for the PHY to wake up after reset + */ + efis->actual_phy_addr = mii_discover_phy (dev); + + if (efis->actual_phy_addr == -1) { + printf ("Unable to discover phy!\n"); + return 0; + } +#else + efis->actual_phy_addr = -1; +#endif + } else { + efis->actual_phy_addr = efis->phy_addr; + } +#if defined(CONFIG_MII) && defined(CONFIG_RMII) + + /* the MII interface is connected to FEC1 + * so for the miiphy_xxx function to work we must + * call mii_init since fec_halt messes the thing up + */ + if (efis->ether_index != 0) + mii_init(); + + /* + * adapt the RMII speed to the speed of the phy + */ + if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) { + fec_100Mbps (dev); + } else { + fec_10Mbps (dev); + } +#endif + +#if defined(CONFIG_MII) + /* + * adapt to the half/full speed settings + */ + if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) { + fec_full_duplex (dev); + } else { + fec_half_duplex (dev); + } +#endif + + /* And last, try to fill Rx Buffer Descriptors */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + + efis->initialized = 1; + + return 1; +} + + +static void fec_halt(struct eth_device* dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + int i; + + /* avoid halt if initialized; mii gets stuck otherwise */ + if (!efis->initialized) + return; + + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ + + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) { + printf ("FEC_RESET_DELAY timeout\n"); + return; + } + + efis->initialized = 0; +} + +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) + +/* Make MII read/write commands for the FEC. +*/ + +#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \ + (REG & 0x1f) << 18)) + +#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \ + (REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ +#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ +#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ +#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ +#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */ +#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ +#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */ +#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ +#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ +#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ + +/* PHY identification + */ +#define PHY_ID_LXT970 0x78100000 /* LXT970 */ +#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */ +#define PHY_ID_82555 0x02a80150 /* Intel 82555 */ +#define PHY_ID_QS6612 0x01814400 /* QS6612 */ +#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */ +#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */ +#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */ +#define PHY_ID_DM9161 0x0181B880 /* Davicom DM9161 */ +#define PHY_ID_KSM8995M 0x00221450 /* MICREL KS8995MA */ + +/* send command to phy using mii, wait for result */ +static uint +mii_send(uint mii_cmd) +{ + uint mii_reply; + volatile fec_t *ep; + int cnt; + + ep = &(((immap_t *)CFG_IMMR)->im_cpm.cp_fec); + + ep->fec_mii_data = mii_cmd; /* command to phy */ + + /* wait for mii complete */ + cnt = 0; + while (!(ep->fec_ievent & FEC_ENET_MII)) { + if (++cnt > 1000) { + printf("mii_send STUCK!\n"); + break; + } + } + mii_reply = ep->fec_mii_data; /* result from phy */ + ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */ + return (mii_reply & 0xffff); /* data read from phy */ +} +#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */ + +#if defined(CFG_DISCOVER_PHY) +static int mii_discover_phy(struct eth_device *dev) +{ +#define MAX_PHY_PASSES 11 + uint phyno; + int pass; + uint phytype; + int phyaddr; + + phyaddr = -1; /* didn't find a PHY yet */ + for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) { + if (pass > 1) { + /* PHY may need more time to recover from reset. + * The LXT970 needs 50ms typical, no maximum is + * specified, so wait 10ms before try again. + * With 11 passes this gives it 100ms to wake up. + */ + udelay(10000); /* wait 10ms */ + } + for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) { + phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1)); +#ifdef ET_DEBUG + printf("PHY type 0x%x pass %d type ", phytype, pass); +#endif + if (phytype != 0xffff) { + phyaddr = phyno; + phytype <<= 16; + phytype |= mii_send(mk_mii_read(phyno, + PHY_PHYIDR2)); + +#ifdef ET_DEBUG + printf("PHY @ 0x%x pass %d type ",phyno,pass); + switch (phytype & 0xfffffff0) { + case PHY_ID_LXT970: + printf("LXT970\n"); + break; + case PHY_ID_LXT971: + printf("LXT971\n"); + break; + case PHY_ID_82555: + printf("82555\n"); + break; + case PHY_ID_QS6612: + printf("QS6612\n"); + break; + case PHY_ID_AMD79C784: + printf("AMD79C784\n"); + break; + case PHY_ID_LSI80225B: + printf("LSI L80225/B\n"); + break; + case PHY_ID_DM9161: + printf("Davicom DM9161\n"); + break; + case PHY_ID_KSM8995M: + printf("MICREL KS8995M\n"); + break; + default: + printf("0x%08x\n", phytype); + break; + } +#endif + } + } + } + if (phyaddr < 0) { + printf("No PHY device found.\n"); + } + return phyaddr; +} +#endif /* CFG_DISCOVER_PHY */ + +#if (defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) && !defined(CONFIG_BITBANGMII) + +/**************************************************************************** + * mii_init -- Initialize the MII for MII command without ethernet + * This function is a subset of eth_init + **************************************************************************** + */ +void mii_init (void) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile fec_t *fecp = &(immr->im_cpm.cp_fec); + int i, j; + + for (j = 0; j < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); j++) { + + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ + + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) { + printf ("FEC_RESET_DELAY timeout\n"); + return; + } + + /* We use strictly polling mode only + */ + fecp->fec_imask = 0; + + /* Clear any pending interrupt + */ + fecp->fec_ievent = 0xffc0; + + /* Setup the pin configuration of the FEC(s) + */ + fec_pin_init(ether_fcc_info[i].ether_index); + + /* Now enable the transmit and receive processing + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; + } +} + +/***************************************************************************** + * Read and write a MII PHY register, routines used by MII Utilities + * + * FIXME: These routines are expected to return 0 on success, but mii_send + * does _not_ return an error code. Maybe 0xFFFF means error, i.e. + * no PHY connected... + * For now always return 0. + * FIXME: These routines only work after calling eth_init() at least once! + * Otherwise they hang in mii_send() !!! Sorry! + *****************************************************************************/ + +int fec8xx_miiphy_read(char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + short rdreg; /* register working value */ + +#ifdef MII_DEBUG + printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr); +#endif + rdreg = mii_send(mk_mii_read(addr, reg)); + + *value = rdreg; +#ifdef MII_DEBUG + printf ("0x%04x\n", *value); +#endif + return 0; +} + +int fec8xx_miiphy_write(char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + short rdreg; /* register working value */ +#ifdef MII_DEBUG + printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr); +#endif + rdreg = mii_send(mk_mii_write(addr, reg, value)); + +#ifdef MII_DEBUG + printf ("0x%04x\n", value); +#endif + return 0; +} +#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/ + +#endif /* CFG_CMD_NET, FEC_ENET */ diff --git a/drivers/net/fec_mpc8xx.h b/drivers/net/fec_mpc8xx.h new file mode 100644 index 0000000000..a49417c666 --- /dev/null +++ b/drivers/net/fec_mpc8xx.h @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2000 + * 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 + */ + +#ifndef _FEC_H_ +#define _FEC_H_ + + +#endif /* _FEC_H_ */ diff --git a/drivers/serial/asc_serial.c b/drivers/serial/asc_serial.c new file mode 100644 index 0000000000..d95ec3fd2f --- /dev/null +++ b/drivers/serial/asc_serial.c @@ -0,0 +1,371 @@ +/* + * (INCA) ASC UART support + */ + +#include <config.h> + +#if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP) + +#ifdef CONFIG_PURPLE +#define serial_init asc_serial_init +#define serial_putc asc_serial_putc +#define serial_puts asc_serial_puts +#define serial_getc asc_serial_getc +#define serial_tstc asc_serial_tstc +#define serial_setbrg asc_serial_setbrg +#endif + +#include <common.h> +#include <asm/inca-ip.h> +#include "asc_serial.h" + +#ifdef CONFIG_PURPLE + +#undef ASC_FIFO_PRESENT +#define TOUT_LOOP 100000 + +/* Set base address for second FPI interrupt control register bank */ +#define SFPI_INTCON_BASEADDR 0xBF0F0000 + +/* Register offset from base address */ +#define FBS_ISR 0x00000000 /* Interrupt status register */ +#define FBS_IMR 0x00000008 /* Interrupt mask register */ +#define FBS_IDIS 0x00000010 /* Interrupt disable register */ + +/* Interrupt status register bits */ +#define FBS_ISR_AT 0x00000040 /* ASC transmit interrupt */ +#define FBS_ISR_AR 0x00000020 /* ASC receive interrupt */ +#define FBS_ISR_AE 0x00000010 /* ASC error interrupt */ +#define FBS_ISR_AB 0x00000008 /* ASC transmit buffer interrupt */ +#define FBS_ISR_AS 0x00000004 /* ASC start of autobaud detection interrupt */ +#define FBS_ISR_AF 0x00000002 /* ASC end of autobaud detection interrupt */ + +#else + +#define ASC_FIFO_PRESENT + +#endif + + +#define SET_BIT(reg, mask) reg |= (mask) +#define CLEAR_BIT(reg, mask) reg &= (~mask) +#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask) +#define SET_BITS(reg, mask) SET_BIT(reg, mask) +#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);} + +extern uint incaip_get_fpiclk(void); + +static int serial_setopt (void); + +/* pointer to ASC register base address */ +static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC; + +/****************************************************************************** +* +* serial_init - initialize a INCAASC channel +* +* This routine initializes the number of data bits, parity +* and set the selected baud rate. Interrupts are disabled. +* Set the modem control signals if the option is selected. +* +* RETURNS: N/A +*/ + +int serial_init (void) +{ +#ifdef CONFIG_INCA_IP + /* we have to set PMU.EN13 bit to enable an ASC device*/ + INCAASC_PMU_ENABLE(13); +#endif + + /* and we have to set CLC register*/ + CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS); + SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001); + + /* initialy we are in async mode */ + pAsc->asc_con = ASCCON_M_8ASYNC; + + /* select input port */ + pAsc->asc_pisel = (CONSOLE_TTY & 0x1); + +#ifdef ASC_FIFO_PRESENT + /* TXFIFO's filling level */ + SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK, + ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL); + /* enable TXFIFO */ + SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN); + + /* RXFIFO's filling level */ + SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK, + ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL); + /* enable RXFIFO */ + SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN); +#endif + + /* enable error signals */ + SET_BIT(pAsc->asc_con, ASCCON_FEN); + SET_BIT(pAsc->asc_con, ASCCON_OEN); + +#ifdef CONFIG_INCA_IP + /* acknowledge ASC interrupts */ + ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL); + + /* disable ASC interrupts */ + ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL); +#endif + +#ifdef ASC_FIFO_PRESENT + /* set FIFOs into the transparent mode */ + SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN); + SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN); +#endif + + /* set baud rate */ + serial_setbrg(); + + /* set the options */ + serial_setopt(); + + return 0; +} + +void serial_setbrg (void) +{ + ulong uiReloadValue, fdv; + ulong f_ASC; + +#ifdef CONFIG_INCA_IP + f_ASC = incaip_get_fpiclk(); +#else + f_ASC = ASC_CLOCK_RATE; +#endif + +#ifndef INCAASC_USE_FDV + fdv = 2; + uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1; +#else + fdv = INCAASC_FDV_HIGH_BAUDRATE; + uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1; +#endif /* INCAASC_USE_FDV */ + + if ( (uiReloadValue < 0) || (uiReloadValue > 8191) ) + { +#ifndef INCAASC_USE_FDV + fdv = 3; + uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1; +#else + fdv = INCAASC_FDV_LOW_BAUDRATE; + uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1; +#endif /* INCAASC_USE_FDV */ + + if ( (uiReloadValue < 0) || (uiReloadValue > 8191) ) + { + return; /* can't impossibly generate that baud rate */ + } + } + + /* Disable Baud Rate Generator; BG should only be written when R=0 */ + CLEAR_BIT(pAsc->asc_con, ASCCON_R); + +#ifndef INCAASC_USE_FDV + /* + * Disable Fractional Divider (FDE) + * Divide clock by reload-value + constant (BRS) + */ + /* FDE = 0 */ + CLEAR_BIT(pAsc->asc_con, ASCCON_FDE); + + if ( fdv == 2 ) + CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */ + else + SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */ + +#else /* INCAASC_USE_FDV */ + + /* Enable Fractional Divider */ + SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */ + + /* Set fractional divider value */ + pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK; + +#endif /* INCAASC_USE_FDV */ + + /* Set reload value in BG */ + pAsc->asc_bg = uiReloadValue; + + /* Enable Baud Rate Generator */ + SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */ +} + +/******************************************************************************* +* +* serial_setopt - set the serial options +* +* Set the channel operating mode to that specified. Following options +* are supported: CREAD, CSIZE, PARENB, and PARODD. +* +* Note, this routine disables the transmitter. The calling routine +* may have to re-enable it. +* +* RETURNS: +* Returns 0 to indicate success, otherwise -1 is returned +*/ + +static int serial_setopt (void) +{ + ulong con; + + switch ( ASC_OPTIONS & ASCOPT_CSIZE ) + { + /* 7-bit-data */ + case ASCOPT_CS7: + con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */ + break; + + /* 8-bit-data */ + case ASCOPT_CS8: + if ( ASC_OPTIONS & ASCOPT_PARENB ) + con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */ + else + con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */ + break; + + /* + * only 7 and 8-bit frames are supported + * if we don't use IOCTL extensions + */ + default: + return -1; + } + + if ( ASC_OPTIONS & ASCOPT_STOPB ) + SET_BIT(con, ASCCON_STP); /* 2 stop bits */ + else + CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */ + + if ( ASC_OPTIONS & ASCOPT_PARENB ) + SET_BIT(con, ASCCON_PEN); /* enable parity checking */ + else + CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */ + + if ( ASC_OPTIONS & ASCOPT_PARODD ) + SET_BIT(con, ASCCON_ODD); /* odd parity */ + else + CLEAR_BIT(con, ASCCON_ODD); /* even parity */ + + if ( ASC_OPTIONS & ASCOPT_CREAD ) + SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */ + + pAsc->asc_con |= con; + + return 0; +} + +void serial_putc (const char c) +{ +#ifdef ASC_FIFO_PRESENT + uint txFl = 0; +#else + uint timeout = 0; +#endif + + if (c == '\n') serial_putc ('\r'); + +#ifdef ASC_FIFO_PRESENT + /* check do we have a free space in the TX FIFO */ + /* get current filling level */ + do + { + txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF; + } + while ( txFl == INCAASC_TXFIFO_FULL ); +#else + + while(!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) & + FBS_ISR_AB)) + { + if (timeout++ > TOUT_LOOP) + { + break; + } + } +#endif + + pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */ + +#ifndef ASC_FIFO_PRESENT + *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB | + FBS_ISR_AT; +#endif + + /* check for errors */ + if ( pAsc->asc_con & ASCCON_OE ) + { + SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE); + return; + } +} + +void serial_puts (const char *s) +{ + while (*s) + { + serial_putc (*s++); + } +} + +int serial_getc (void) +{ + ulong symbol_mask; + char c; + + while (!serial_tstc()); + + symbol_mask = + ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff); + + c = (char)(pAsc->asc_rbuf & symbol_mask); + +#ifndef ASC_FIFO_PRESENT + *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR; +#endif + + return c; +} + +int serial_tstc (void) +{ + int res = 1; + +#ifdef ASC_FIFO_PRESENT + if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 ) + { + res = 0; + } +#else + if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) & + FBS_ISR_AR)) + + { + res = 0; + } +#endif + else if ( pAsc->asc_con & ASCCON_FE ) + { + SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE); + res = 0; + } + else if ( pAsc->asc_con & ASCCON_PE ) + { + SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE); + res = 0; + } + else if ( pAsc->asc_con & ASCCON_OE ) + { + SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE); + res = 0; + } + + return res; +} +#endif /* CONFIG_PURPLE || CONFIG_INCA_IP */ diff --git a/drivers/serial/asc_serial.h b/drivers/serial/asc_serial.h new file mode 100644 index 0000000000..7ffdcfaf8b --- /dev/null +++ b/drivers/serial/asc_serial.h @@ -0,0 +1,177 @@ +/* incaAscSio.h - (INCA) ASC UART tty driver header */ + +#ifndef __INCincaAscSioh +#define __INCincaAscSioh + +#include <asm/inca-ip.h> + +/* channel operating modes */ +#define ASCOPT_CSIZE 0x00000003 +#define ASCOPT_CS7 0x00000001 +#define ASCOPT_CS8 0x00000002 +#define ASCOPT_PARENB 0x00000004 +#define ASCOPT_STOPB 0x00000008 +#define ASCOPT_PARODD 0x00000010 +#define ASCOPT_CREAD 0x00000020 + +#define ASC_OPTIONS (ASCOPT_CREAD | ASCOPT_CS8) + +/* ASC input select (0 or 1) */ +#define CONSOLE_TTY 0 + +/* use fractional divider for baudrate settings */ +#define INCAASC_USE_FDV + +#ifdef INCAASC_USE_FDV + #define INCAASC_FDV_LOW_BAUDRATE 71 + #define INCAASC_FDV_HIGH_BAUDRATE 453 +#endif /*INCAASC_USE_FDV*/ + + +#define INCAASC_TXFIFO_FL 1 +#define INCAASC_RXFIFO_FL 1 +#define INCAASC_TXFIFO_FULL 16 + +/* interrupt lines masks for the ASC device interrupts*/ +/* change these macroses if it's necessary */ +#define INCAASC_IRQ_LINE_ALL 0x000F0000 /* all IRQs */ + +#define INCAASC_IRQ_LINE_TIR 0x00010000 /* TIR - Tx */ +#define INCAASC_IRQ_LINE_RIR 0x00020000 /* RIR - Rx */ +#define INCAASC_IRQ_LINE_EIR 0x00040000 /* EIR - Err */ +#define INCAASC_IRQ_LINE_TBIR 0x00080000 /* TBIR - Tx Buf*/ + +/* interrupt controller access macros */ +#define ASC_INTERRUPTS_ENABLE(X) \ + *((volatile unsigned int*) INCA_IP_ICU_IM2_IER) |= X; +#define ASC_INTERRUPTS_DISABLE(X) \ + *((volatile unsigned int*) INCA_IP_ICU_IM2_IER) &= ~X; +#define ASC_INTERRUPTS_CLEAR(X) \ + *((volatile unsigned int*) INCA_IP_ICU_IM2_ISR) = X; + +/* CLC register's bits and bitfields */ +#define ASCCLC_DISR 0x00000001 +#define ASCCLC_DISS 0x00000002 +#define ASCCLC_RMCMASK 0x0000FF00 +#define ASCCLC_RMCOFFSET 8 + +/* CON register's bits and bitfields */ +#define ASCCON_MODEMASK 0x0007 + #define ASCCON_M_8SYNC 0x0 + #define ASCCON_M_8ASYNC 0x1 + #define ASCCON_M_8IRDAASYNC 0x2 + #define ASCCON_M_7ASYNCPAR 0x3 + #define ASCCON_M_9ASYNC 0x4 + #define ASCCON_M_8WAKEUPASYNC 0x5 + #define ASCCON_M_8ASYNCPAR 0x7 +#define ASCCON_STP 0x0008 +#define ASCCON_REN 0x0010 +#define ASCCON_PEN 0x0020 +#define ASCCON_FEN 0x0040 +#define ASCCON_OEN 0x0080 +#define ASCCON_PE 0x0100 +#define ASCCON_FE 0x0200 +#define ASCCON_OE 0x0400 +#define ASCCON_FDE 0x0800 +#define ASCCON_ODD 0x1000 +#define ASCCON_BRS 0x2000 +#define ASCCON_LB 0x4000 +#define ASCCON_R 0x8000 + +/* WHBCON register's bits and bitfields */ +#define ASCWHBCON_CLRREN 0x0010 +#define ASCWHBCON_SETREN 0x0020 +#define ASCWHBCON_CLRPE 0x0100 +#define ASCWHBCON_CLRFE 0x0200 +#define ASCWHBCON_CLROE 0x0400 +#define ASCWHBCON_SETPE 0x0800 +#define ASCWHBCON_SETFE 0x1000 +#define ASCWHBCON_SETOE 0x2000 + +/* ABCON register's bits and bitfields */ +#define ASCABCON_ABEN 0x0001 +#define ASCABCON_AUREN 0x0002 +#define ASCABCON_ABSTEN 0x0004 +#define ASCABCON_ABDETEN 0x0008 +#define ASCABCON_FCDETEN 0x0010 +#define ASCABCON_EMMASK 0x0300 + #define ASCABCON_EMOFF 8 + #define ASCABCON_EM_DISAB 0x0 + #define ASCABCON_EM_DURAB 0x1 + #define ASCABCON_EM_ALWAYS 0x2 +#define ASCABCON_TXINV 0x0400 +#define ASCABCON_RXINV 0x0800 + +/* FDV register mask, offset and bitfields*/ +#define ASCFDV_VALUE_MASK 0x000001FF + +/* WHBABCON register's bits and bitfields */ +#define ASCWHBABCON_SETABEN 0x0001 +#define ASCWHBABCON_CLRABEN 0x0002 + +/* ABSTAT register's bits and bitfields */ +#define ASCABSTAT_FCSDET 0x0001 +#define ASCABSTAT_FCCDET 0x0002 +#define ASCABSTAT_SCSDET 0x0004 +#define ASCABSTAT_SCCDET 0x0008 +#define ASCABSTAT_DETWAIT 0x0010 + +/* WHBABSTAT register's bits and bitfields */ +#define ASCWHBABSTAT_CLRFCSDET 0x0001 +#define ASCWHBABSTAT_SETFCSDET 0x0002 +#define ASCWHBABSTAT_CLRFCCDET 0x0004 +#define ASCWHBABSTAT_SETFCCDET 0x0008 +#define ASCWHBABSTAT_CLRSCSDET 0x0010 +#define ASCWHBABSTAT_SETSCSDET 0x0020 +#define ASCWHBABSTAT_SETSCCDET 0x0040 +#define ASCWHBABSTAT_CLRSCCDET 0x0080 +#define ASCWHBABSTAT_CLRDETWAIT 0x0100 +#define ASCWHBABSTAT_SETDETWAIT 0x0200 + +/* TXFCON register's bits and bitfields */ +#define ASCTXFCON_TXFEN 0x0001 +#define ASCTXFCON_TXFFLU 0x0002 +#define ASCTXFCON_TXTMEN 0x0004 +#define ASCTXFCON_TXFITLMASK 0x3F00 +#define ASCTXFCON_TXFITLOFF 8 + +/* RXFCON register's bits and bitfields */ +#define ASCRXFCON_RXFEN 0x0001 +#define ASCRXFCON_RXFFLU 0x0002 +#define ASCRXFCON_RXTMEN 0x0004 +#define ASCRXFCON_RXFITLMASK 0x3F00 +#define ASCRXFCON_RXFITLOFF 8 + +/* FSTAT register's bits and bitfields */ +#define ASCFSTAT_RXFFLMASK 0x003F +#define ASCFSTAT_TXFFLMASK 0x3F00 +#define ASCFSTAT_TXFFLOFF 8 + +#define INCAASC_PMU_ENABLE(BIT) *((volatile ulong*)0xBF102000) |= (0x1 << BIT); + +typedef struct /* incaAsc_t */ +{ + volatile unsigned long asc_clc; /*0x0000*/ + volatile unsigned long asc_pisel; /*0x0004*/ + volatile unsigned long asc_rsvd1[2]; /* for mapping */ /*0x0008*/ + volatile unsigned long asc_con; /*0x0010*/ + volatile unsigned long asc_bg; /*0x0014*/ + volatile unsigned long asc_fdv; /*0x0018*/ + volatile unsigned long asc_pmw; /* not used */ /*0x001C*/ + volatile unsigned long asc_tbuf; /*0x0020*/ + volatile unsigned long asc_rbuf; /*0x0024*/ + volatile unsigned long asc_rsvd2[2]; /* for mapping */ /*0x0028*/ + volatile unsigned long asc_abcon; /*0x0030*/ + volatile unsigned long asc_abstat; /* not used */ /*0x0034*/ + volatile unsigned long asc_rsvd3[2]; /* for mapping */ /*0x0038*/ + volatile unsigned long asc_rxfcon; /*0x0040*/ + volatile unsigned long asc_txfcon; /*0x0044*/ + volatile unsigned long asc_fstat; /*0x0048*/ + volatile unsigned long asc_rsvd4; /* for mapping */ /*0x004C*/ + volatile unsigned long asc_whbcon; /*0x0050*/ + volatile unsigned long asc_whbabcon; /*0x0054*/ + volatile unsigned long asc_whbabstat; /* not used */ /*0x0058*/ + +} incaAsc_t; + +#endif /* __INCincaAscSioh */ diff --git a/drivers/serial/serial_at91rm9200.c b/drivers/serial/serial_at91rm9200.c new file mode 100644 index 0000000000..7f00b30ad6 --- /dev/null +++ b/drivers/serial/serial_at91rm9200.c @@ -0,0 +1,110 @@ +/* + * (C) Copyright 2002 + * Lineo, Inc <www.lineo.com> + * Bernhard Kuhn <bkuhn@lineo.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +#if !defined(CONFIG_DBGU) && !defined(CONFIG_USART0) && !defined(CONFIG_USART1) +#error must define one of CONFIG_DBGU or CONFIG_USART0 or CONFIG_USART1 +#endif + +/* ggi thunder */ +#ifdef CONFIG_DBGU +AT91PS_USART us = (AT91PS_USART) AT91C_BASE_DBGU; +#endif +#ifdef CONFIG_USART0 +AT91PS_USART us = (AT91PS_USART) AT91C_BASE_US0; +#endif +#ifdef CONFIG_USART1 +AT91PS_USART us = (AT91PS_USART) AT91C_BASE_US1; +#endif + +void serial_setbrg (void) +{ + int baudrate; + + baudrate = CONFIG_BAUDRATE; + /* MASTER_CLOCK/(16 * baudrate) */ + us->US_BRGR = (AT91C_MASTER_CLOCK >> 4) / (unsigned)baudrate; +} + +int serial_init (void) +{ + /* make any port initializations specific to this port */ +#ifdef CONFIG_DBGU + *AT91C_PIOA_PDR = AT91C_PA31_DTXD | AT91C_PA30_DRXD; /* PA 31 & 30 */ + *AT91C_PMC_PCER = 1 << AT91C_ID_SYS; /* enable clock */ +#endif +#ifdef CONFIG_USART0 + *AT91C_PIOA_PDR = AT91C_PA17_TXD0 | AT91C_PA18_RXD0; + *AT91C_PMC_PCER |= 1 << AT91C_ID_USART0; /* enable clock */ +#endif +#ifdef CONFIG_USART1 + *AT91C_PIOB_PDR = AT91C_PB21_TXD1 | AT91C_PB20_RXD1; + *AT91C_PMC_PCER |= 1 << AT91C_ID_USART1; /* enable clock */ +#endif + serial_setbrg (); + + us->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX; + us->US_CR = AT91C_US_RXEN | AT91C_US_TXEN; + us->US_MR = + (AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS | + AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT); + us->US_IMR = ~0ul; + return (0); +} + +void serial_putc (const char c) +{ + if (c == '\n') + serial_putc ('\r'); + while ((us->US_CSR & AT91C_US_TXRDY) == 0); + us->US_THR = c; +} + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int serial_getc (void) +{ + while ((us->US_CSR & AT91C_US_RXRDY) == 0); + return us->US_RHR; +} + +int serial_tstc (void) +{ + return ((us->US_CSR & AT91C_US_RXRDY) == AT91C_US_RXRDY); +} diff --git a/drivers/serial/serial_au1x00.c b/drivers/serial/serial_au1x00.c new file mode 100644 index 0000000000..42c668ee3d --- /dev/null +++ b/drivers/serial/serial_au1x00.c @@ -0,0 +1,135 @@ +/* + * AU1X00 UART support + * + * Hardcoded to UART 0 for now + * Speed and options also hardcoded to 115200 8N1 + * + * Copyright (c) 2003 Thomas.Lange@corelatus.se + * + * 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 <config.h> + +#ifdef CONFIG_AU1X00 + +#include <common.h> +#include <asm/au1x00.h> + +/****************************************************************************** +* +* serial_init - initialize a channel +* +* This routine initializes the number of data bits, parity +* and set the selected baud rate. Interrupts are disabled. +* Set the modem control signals if the option is selected. +* +* RETURNS: N/A +*/ + +int serial_init (void) +{ + volatile u32 *uart_fifoctl = (volatile u32*)(UART0_ADDR+UART_FCR); + volatile u32 *uart_enable = (volatile u32*)(UART0_ADDR+UART_ENABLE); + + /* Enable clocks first */ + *uart_enable = UART_EN_CE; + + /* Then release reset */ + /* Must release reset before setting other regs */ + *uart_enable = UART_EN_CE|UART_EN_E; + + /* Activate fifos, reset tx and rx */ + /* Set tx trigger level to 12 */ + *uart_fifoctl = UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR| + UART_FCR_CLEAR_XMIT|UART_FCR_T_TRIGGER_12; + + serial_setbrg(); + + return 0; +} + + +void serial_setbrg (void) +{ + volatile u32 *uart_clk = (volatile u32*)(UART0_ADDR+UART_CLK); + volatile u32 *uart_lcr = (volatile u32*)(UART0_ADDR+UART_LCR); + volatile u32 *sys_powerctrl = (u32 *)SYS_POWERCTRL; + int sd; + int divisorx2; + + /* sd is system clock divisor */ + /* see section 10.4.5 in au1550 datasheet */ + sd = (*sys_powerctrl & 0x03) + 2; + + /* calulate 2x baudrate and round */ + divisorx2 = ((CFG_HZ/(sd * 16 * CONFIG_BAUDRATE))); + + if (divisorx2 & 0x01) + divisorx2 = divisorx2 + 1; + + *uart_clk = divisorx2 / 2; + + /* Set parity, stop bits and word length to 8N1 */ + *uart_lcr = UART_LCR_WLEN8; +} + +void serial_putc (const char c) +{ + volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR); + volatile u32 *uart_tx = (volatile u32*)(UART0_ADDR+UART_TX); + + if (c == '\n') serial_putc ('\r'); + + /* Wait for fifo to shift out some bytes */ + while((*uart_lsr&UART_LSR_THRE)==0); + + *uart_tx = (u32)c; +} + +void serial_puts (const char *s) +{ + while (*s) + { + serial_putc (*s++); + } +} + +int serial_getc (void) +{ + volatile u32 *uart_rx = (volatile u32*)(UART0_ADDR+UART_RX); + char c; + + while (!serial_tstc()); + + c = (*uart_rx&0xFF); + return c; +} + +int serial_tstc (void) +{ + volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR); + + if(*uart_lsr&UART_LSR_DR){ + /* Data in rfifo */ + return(1); + } + return 0; +} +#endif /* CONFIG_SERIAL_AU1X00 */ diff --git a/drivers/serial/serial_bf533.c b/drivers/serial/serial_bf533.c new file mode 100644 index 0000000000..7b43ffd188 --- /dev/null +++ b/drivers/serial/serial_bf533.c @@ -0,0 +1,195 @@ +/* + * U-boot - serial.c Serial driver for BF533 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.c: Serial driver for BlackFin BF533 DSP internal UART. + * Copyright (c) 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on blkfinserial.c + * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs. + * Copyright(c) 2003 Metrowerks <mwaddel@metrowerks.com> + * Copyright(c) 2001 Tony Z. Kou <tonyko@arcturusnetworks.com> + * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328 version serial driver imlpementation which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * 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> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/segment.h> +#include <asm/bitops.h> +#include <asm/delay.h> +#include <asm/uaccess.h> +#include "bf533_serial.h" + +DECLARE_GLOBAL_DATA_PTR; + +unsigned long pll_div_fact; + +void calc_baud(void) +{ + unsigned char i; + int temp; + + for(i = 0; i < sizeof(baud_table)/sizeof(int); i++) { + temp = CONFIG_SCLK_HZ/(baud_table[i]*8); + if ( temp && 0x1 == 1 ) { + temp++; + } + temp = temp/2; + hw_baud_table[i].dl_high = (temp >> 8)& 0xFF; + hw_baud_table[i].dl_low = (temp) & 0xFF; + } +} + +void serial_setbrg(void) +{ + int i; + + calc_baud(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + if (gd->baudrate == baud_table[i]) + break; + } + + /* Enable UART */ + *pUART_GCTL |= UART_GCTL_UCEN; + asm("ssync;"); + + /* Set DLAB in LCR to Access DLL and DLH */ + ACCESS_LATCH; + asm("ssync;"); + + *pUART_DLL = hw_baud_table[i].dl_low; + asm("ssync;"); + *pUART_DLH = hw_baud_table[i].dl_high; + asm("ssync;"); + + /* Clear DLAB in LCR to Access THR RBR IER */ + ACCESS_PORT_IER; + asm("ssync;"); + + /* Enable ERBFI and ELSI interrupts + * to poll SIC_ISR register*/ + *pUART_IER = UART_IER_ELSI | UART_IER_ERBFI | UART_IER_ETBEI; + asm("ssync;"); + + /* Set LCR to Word Lengh 8-bit word select */ + *pUART_LCR = UART_LCR_WLS8; + asm("ssync;"); + + return; +} + +int serial_init(void) +{ + serial_setbrg(); + return (0); +} + +void serial_putc(const char c) +{ + if ((*pUART_LSR) & UART_LSR_TEMT) + { + if (c == '\n') + serial_putc('\r'); + + local_put_char(c); + } + + while (!((*pUART_LSR) & UART_LSR_TEMT)) + SYNC_ALL; + + return; +} + +int serial_tstc(void) +{ + if (*pUART_LSR & UART_LSR_DR) + return 1; + else + return 0; +} + +int serial_getc(void) +{ + unsigned short uart_lsr_val, uart_rbr_val; + unsigned long isr_val; + int ret; + + /* Poll for RX Interrupt */ + while (!((isr_val = *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)); + asm("csync;"); + + uart_lsr_val = *pUART_LSR; /* Clear status bit */ + uart_rbr_val = *pUART_RBR; /* getc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + ret = -1; + } + else + { + ret = uart_rbr_val & 0xff; + } + + return ret; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +static void local_put_char(char ch) +{ + int flags = 0; + unsigned long isr_val; + + save_and_cli(flags); + + /* Poll for TX Interruput */ + while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)); + asm("csync;"); + + *pUART_THR = ch; /* putc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + printf("?"); + } + + restore_flags(flags); + + return ; +} diff --git a/drivers/serial/serial_bf533.h b/drivers/serial/serial_bf533.h new file mode 100644 index 0000000000..d430e6cabd --- /dev/null +++ b/drivers/serial/serial_bf533.h @@ -0,0 +1,78 @@ +/* + * U-boot - bf533_serial.h Serial Driver defines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.h: Definitions for the BlackFin BF533 DSP serial driver. + * Copyright (C) 2003 Bas Vermeulen <bas@buyways.nl> + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on: + * blkfinserial.h: Definitions for the BlackFin DSP serial driver. + * + * Copyright (C) 2001 Tony Z. Kou tonyko@arcturusnetworks.com + * Copyright (C) 2001 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328serial.c which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * 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 + */ + +#ifndef _Bf533_SERIAL_H +#define _Bf533_SERIAL_H + +#include <linux/config.h> +#include <asm/blackfin.h> + +#define SYNC_ALL __asm__ __volatile__ ("ssync;\n") +#define ACCESS_LATCH *pUART_LCR |= UART_LCR_DLAB; +#define ACCESS_PORT_IER *pUART_LCR &= (~UART_LCR_DLAB); + +void serial_setbrg(void); +static void local_put_char(char ch); +void calc_baud(void); +void serial_setbrg(void); +int serial_init(void); +void serial_putc(const char c); +int serial_tstc(void); +int serial_getc(void); +void serial_puts(const char *s); +static void local_put_char(char ch); + +extern int get_clock(void); +int baud_table[5] = {9600, 19200, 38400, 57600, 115200}; + +struct { + unsigned char dl_high; + unsigned char dl_low; +} hw_baud_table[5]; + +#ifdef CONFIG_STAMP +extern unsigned long pll_div_fact; +#endif + +#endif diff --git a/drivers/serial/serial_clps7111.c b/drivers/serial/serial_clps7111.c new file mode 100644 index 0000000000..054bab9811 --- /dev/null +++ b/drivers/serial/serial_clps7111.c @@ -0,0 +1,126 @@ +/* + * (C) Copyright 2002-2004 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> + +#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) + +#include <clps7111.h> + +DECLARE_GLOBAL_DATA_PTR; + +void serial_setbrg (void) +{ + unsigned int reg = 0; + + switch (gd->baudrate) { + case 1200: reg = 191; break; + case 9600: reg = 23; break; + case 19200: reg = 11; break; + case 38400: reg = 5; break; + case 57600: reg = 3; break; + case 115200: reg = 1; break; + default: hang (); break; + } + + /* init serial serial 1,2 */ + IO_SYSCON1 = SYSCON1_UART1EN; + IO_SYSCON2 = SYSCON2_UART2EN; + + reg |= UBRLCR_WRDLEN8; + + IO_UBRLCR1 = reg; + IO_UBRLCR2 = reg; +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + int tmo; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); + + tmo = get_timer (0) + 1 * CFG_HZ; + while (IO_SYSFLG1 & SYSFLG1_UTXFF) + if (get_timer (0) > tmo) + break; + + IO_UARTDR1 = c; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_tstc (void) +{ + return !(IO_SYSFLG1 & SYSFLG1_URXFE); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ + while (IO_SYSFLG1 & SYSFLG1_URXFE); + + return IO_UARTDR1 & 0xff; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +#endif /* defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) */ diff --git a/drivers/serial/serial_ixp.c b/drivers/serial/serial_ixp.c new file mode 100644 index 0000000000..2015958571 --- /dev/null +++ b/drivers/serial/serial_ixp.c @@ -0,0 +1,125 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> +#include <asm/arch/ixp425.h> + +DECLARE_GLOBAL_DATA_PTR; + +void serial_setbrg (void) +{ + unsigned int quot = 0; + int uart = CFG_IXP425_CONSOLE; + + if (gd->baudrate == 1200) + quot = 192; + else if (gd->baudrate == 9600) + quot = 96; + else if (gd->baudrate == 19200) + quot = 48; + else if (gd->baudrate == 38400) + quot = 24; + else if (gd->baudrate == 57600) + quot = 16; + else if (gd->baudrate == 115200) + quot = 8; + else + hang (); + + IER(uart) = 0; /* Disable for now */ + FCR(uart) = 0; /* No fifos enabled */ + + /* set baud rate */ + LCR(uart) = LCR_WLS0 | LCR_WLS1 | LCR_DLAB; + DLL(uart) = quot & 0xff; + DLH(uart) = quot >> 8; + LCR(uart) = LCR_WLS0 | LCR_WLS1; + + IER(uart) = IER_UUE; +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + /* wait for room in the tx FIFO on UART */ + while ((LSR(CFG_IXP425_CONSOLE) & LSR_TEMT) == 0); + + THR(CFG_IXP425_CONSOLE) = c; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_tstc (void) +{ + return LSR(CFG_IXP425_CONSOLE) & LSR_DR; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ + while (!(LSR(CFG_IXP425_CONSOLE) & LSR_DR)); + + return (char) RBR(CFG_IXP425_CONSOLE) & 0xff; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c new file mode 100644 index 0000000000..aacd1be630 --- /dev/null +++ b/drivers/serial/serial_ks8695.c @@ -0,0 +1,117 @@ +/* + * serial.c -- KS8695 serial driver + * + * (C) Copyright 2004, Greg Ungerer <greg.ungerer@opengear.com> + * + * 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> +#include <asm/arch/platform.h> + +#ifndef CONFIG_SERIAL1 +#error "Bad: you didn't configure serial ..." +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Define the UART hardware register access structure. + */ +struct ks8695uart { + unsigned int RX; /* 0x00 - Receive data (r) */ + unsigned int TX; /* 0x04 - Transmit data (w) */ + unsigned int FCR; /* 0x08 - Fifo Control (r/w) */ + unsigned int LCR; /* 0x0c - Line Control (r/w) */ + unsigned int MCR; /* 0x10 - Modem Control (r/w) */ + unsigned int LSR; /* 0x14 - Line Status (r/w) */ + unsigned int MSR; /* 0x18 - Modem Status (r/w) */ + unsigned int BD; /* 0x1c - Baud Rate (r/w) */ + unsigned int SR; /* 0x20 - Status (r/w) */ +}; + +#define KS8695_UART_ADDR ((void *) (KS8695_IO_BASE + KS8695_UART_RX_BUFFER)) +#define KS8695_UART_CLK 25000000 + + +/* + * Under some circumstances we want to be "quiet" and not issue any + * serial output - though we want u-boot to otherwise work and behave + * the same. By default be noisy. + */ +int serial_console = 1; + + +void serial_setbrg(void) +{ + volatile struct ks8695uart *uartp = KS8695_UART_ADDR; + + /* Set to global baud rate and 8 data bits, no parity, 1 stop bit*/ + uartp->BD = KS8695_UART_CLK / gd->baudrate; + uartp->LCR = KS8695_UART_LINEC_WLEN8; +} + +int serial_init(void) +{ + serial_console = 1; + serial_setbrg(); + return 0; +} + +void serial_raw_putc(const char c) +{ + volatile struct ks8695uart *uartp = KS8695_UART_ADDR; + int i; + + for (i = 0; (i < 0x100000); i++) { + if (uartp->LSR & KS8695_UART_LINES_TXFE) + break; + } + + uartp->TX = c; +} + +void serial_putc(const char c) +{ + if (serial_console) { + serial_raw_putc(c); + if (c == '\n') + serial_raw_putc('\r'); + } +} + +int serial_tstc(void) +{ + volatile struct ks8695uart *uartp = KS8695_UART_ADDR; + if (serial_console) + return ((uartp->LSR & KS8695_UART_LINES_RXFE) ? 1 : 0); + return 0; +} + +void serial_puts(const char *s) +{ + char c; + while ((c = *s++) != 0) + serial_putc(c); +} + +int serial_getc(void) +{ + volatile struct ks8695uart *uartp = KS8695_UART_ADDR; + + while ((uartp->LSR & KS8695_UART_LINES_RXFE) == 0) + ; + return (uartp->RX); +} diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c new file mode 100644 index 0000000000..d727ccaa4f --- /dev/null +++ b/drivers/serial/serial_lh7a40x.c @@ -0,0 +1,166 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * 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> +#include <lh7a40x.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CONSOLE_UART1) +# define UART_CONSOLE 1 +#elif defined(CONFIG_CONSOLE_UART2) +# define UART_CONSOLE 2 +#elif defined(CONFIG_CONSOLE_UART3) +# define UART_CONSOLE 3 +#else +# error "No console configured ... " +#endif + +void serial_setbrg (void) +{ + lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); + int i; + unsigned int reg = 0; + + /* + * userguide 15.1.2.4 + * + * BAUDDIV is (UART_REF_FREQ/(16 X BAUD))-1 + * + * UART_REF_FREQ = external system clock input / 2 (Hz) + * BAUD is desired baudrate (bits/s) + * + * NOTE: we add (divisor/2) to numerator to round for + * more precision + */ + reg = (((get_PLLCLK()/2) + ((16*gd->baudrate)/2)) / (16 * gd->baudrate)) - 1; + uart->brcon = reg; + + for (i = 0; i < 100; i++); +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); + + /* UART must be enabled before writing to any config registers */ + uart->con |= (UART_EN); + +#ifdef CONFIG_CONSOLE_UART1 + /* infrared disabled */ + uart->con |= UART_SIRD; +#endif + /* loopback disabled */ + uart->con &= ~(UART_LBE); + + /* modem lines and tx/rx polarities */ + uart->con &= ~(UART_MXP | UART_TXP | UART_RXP); + + /* FIFO enable, N81 */ + uart->fcon = (UART_WLEN_8 | UART_FEN | UART_STP2_1); + + /* set baudrate */ + serial_setbrg (); + + /* enable rx interrupt */ + uart->inten |= UART_RI; + + return (0); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ + lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); + + /* wait for character to arrive */ + while (uart->status & UART_RXFE); + + return(uart->data & 0xff); +} + +#ifdef CONFIG_HWFLOW +static int hwflow = 0; /* turned off by default */ +int hwflow_onoff(int on) +{ + switch(on) { + case 0: + default: + break; /* return current */ + case 1: + hwflow = 1; /* turn on */ + break; + case -1: + hwflow = 0; /* turn off */ + break; + } + return hwflow; +} +#endif + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); + + /* wait for room in the tx FIFO */ + while (!(uart->status & UART_TXFE)); + +#ifdef CONFIG_HWFLOW + /* Wait for CTS up */ + while(hwflow && !(uart->status & UART_CTS)); +#endif + + uart->data = c; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); +} + +/* + * Test whether a character is in the RX buffer + */ +int serial_tstc (void) +{ + lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); + + return(!(uart->status & UART_RXFE)); +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} diff --git a/drivers/serial/serial_mcf52x2.c b/drivers/serial/serial_mcf52x2.c new file mode 100644 index 0000000000..8be09e34fe --- /dev/null +++ b/drivers/serial/serial_mcf52x2.c @@ -0,0 +1,215 @@ +/* + * (C) Copyright 2000-2004 + * 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> +#include <command.h> +#include <watchdog.h> + +#include <asm/mcfuart.h> + +#ifdef CONFIG_M5271 +#include <asm/m5271.h> +#endif + +#ifdef CONFIG_M5272 +#include <asm/m5272.h> +#endif + +#ifdef CONFIG_M5282 +#include <asm/m5282.h> +#endif + +#ifdef CONFIG_M5249 +#include <asm/m5249.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_M5249) || defined(CONFIG_M5271) +#define DoubleClock(a) ((double)(CFG_CLK/2) / 32.0 / (double)(a)) +#else +#define DoubleClock(a) ((double)(CFG_CLK) / 32.0 / (double)(a)) +#endif + +void rs_serial_setbaudrate(int port,int baudrate) +{ +#if defined(CONFIG_M5272) || defined(CONFIG_M5249) || defined(CONFIG_M5271) + volatile unsigned char *uartp; +# ifndef CONFIG_M5271 + double fraction; +# endif + double clock; + + if (port == 0) + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + else + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE2); + + clock = DoubleClock(baudrate); /* Set baud above */ + + uartp[MCFUART_UBG1] = (((int)clock >> 8) & 0xff); /* set msb baud */ + uartp[MCFUART_UBG2] = ((int)clock & 0xff); /* set lsb baud */ + +# ifndef CONFIG_M5271 + fraction = ((clock - (int)clock) * 16.0) + 0.5; + uartp[MCFUART_UFPD] = ((int)fraction & 0xf); /* set baud fraction adjust */ +# endif +#endif + +#if defined(CONFIG_M5282) + volatile unsigned char *uartp; + long clock; + + switch (port) { + case 1: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE2); + break; + case 2: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE3); + break; + default: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + } + + clock = (long) CFG_CLK / ((long) 32 * baudrate); /* Set baud above */ + + uartp[MCFUART_UBG1] = (((int)clock >> 8) & 0xff); /* set msb baud */ + uartp[MCFUART_UBG2] = ((int) clock & 0xff); /* set lsb baud */ + +#endif +}; + +void rs_serial_init (int port, int baudrate) +{ + volatile unsigned char *uartp; + + /* + * Reset UART, get it into known state... + */ + switch (port) { + case 1: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE2); + break; +#if defined(CONFIG_M5282) + case 2: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE3); + break; +#endif + default: + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + } + + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR; /* reset Error pointer */ + + /* + * Set port for CONSOLE_BAUD_RATE, 8 data bits, 1 stop bit, no parity. + */ + uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; + uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; + + /* Mask UART interrupts */ + uartp[MCFUART_UIMR] = 0; + + /* Set clock Select Register: Tx/Rx clock is timer */ + uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; + + rs_serial_setbaudrate (port, baudrate); + + /* Enable Tx/Rx */ + uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; + + return; +} + +/****************************************************************************/ +/* + * Output a single character, using UART polled mode. + * This is used for console output. + */ + +void rs_put_char(char ch) +{ + volatile unsigned char *uartp; + int i; + + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + + for (i = 0; (i < 0x10000); i++) { + if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) + break; + } + uartp[MCFUART_UTB] = ch; + return; +} + +int rs_is_char(void) +{ + volatile unsigned char *uartp; + + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + return((uartp[MCFUART_USR] & MCFUART_USR_RXREADY) ? 1 : 0); +} + +int rs_get_char(void) +{ + volatile unsigned char *uartp; + + uartp = (volatile unsigned char *) (CFG_MBAR + MCFUART_BASE1); + return(uartp[MCFUART_URB]); +} + +void serial_setbrg(void) { + rs_serial_setbaudrate(0,gd->bd->bi_baudrate); +} + +int serial_init(void) { + rs_serial_init(0,gd->baudrate); + return 0; +} + + +void serial_putc(const char c) { + if (c == '\n') + serial_putc ('\r'); + rs_put_char(c); +} + +void serial_puts (const char *s) { + while (*s) + serial_putc(*s++); +} + +int serial_getc(void) { + while(!rs_is_char()) + WATCHDOG_RESET(); + + return rs_get_char(); +} + +int serial_tstc() { + return rs_is_char(); +} diff --git a/drivers/serial/serial_mpc5xx.c b/drivers/serial/serial_mpc5xx.c new file mode 100644 index 0000000000..ac5556f05c --- /dev/null +++ b/drivers/serial/serial_mpc5xx.c @@ -0,0 +1,170 @@ +/* + * (C) Copyright 2003 + * Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * 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, + */ + +/* + * File: serial.c + * + * Discription: Serial interface driver for SCI1 and SCI2. + * Since this code will be called from ROM use + * only non-static local variables. + * + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <mpc5xx.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Local function prototypes + */ + +static int ready_to_send(void); + +/* + * Minimal global serial functions needed to use one of the SCI modules. + */ + +int serial_init (void) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + + serial_setbrg(); + +#if defined(CONFIG_5xx_CONS_SCI1) + /* 10-Bit, 1 start bit, 8 data bit, no parity, 1 stop bit */ + immr->im_qsmcm.qsmcm_scc1r1 = SCI_M_10; + immr->im_qsmcm.qsmcm_scc1r1 = SCI_TE | SCI_RE; +#else + immr->im_qsmcm.qsmcm_scc2r1 = SCI_M_10; + immr->im_qsmcm.qsmcm_scc2r1 = SCI_TE | SCI_RE; +#endif + return 0; +} + +void serial_putc(const char c) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + + /* Test for completition */ + if(ready_to_send()) { +#if defined(CONFIG_5xx_CONS_SCI1) + immr->im_qsmcm.qsmcm_sc1dr = (short)c; +#else + immr->im_qsmcm.qsmcm_sc2dr = (short)c; +#endif + if(c == '\n') { + if(ready_to_send()); +#if defined(CONFIG_5xx_CONS_SCI1) + immr->im_qsmcm.qsmcm_sc1dr = (short)'\r'; +#else + immr->im_qsmcm.qsmcm_sc2dr = (short)'\r'; +#endif + } + } +} + +int serial_getc(void) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile short status; + unsigned char tmp; + + /* New data ? */ + do { +#if defined(CONFIG_5xx_CONS_SCI1) + status = immr->im_qsmcm.qsmcm_sc1sr; +#else + status = immr->im_qsmcm.qsmcm_sc2sr; +#endif + +#if defined(CONFIG_WATCHDOG) + reset_5xx_watchdog (immr); +#endif + } while ((status & SCI_RDRF) == 0); + + /* Read data */ +#if defined(CONFIG_5xx_CONS_SCI1) + tmp = (unsigned char)(immr->im_qsmcm.qsmcm_sc1dr & SCI_SCXDR_MK); +#else + tmp = (unsigned char)( immr->im_qsmcm.qsmcm_sc2dr & SCI_SCXDR_MK); +#endif + return tmp; +} + +int serial_tstc() +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + short status; + + /* New data character ? */ +#if defined(CONFIG_5xx_CONS_SCI1) + status = immr->im_qsmcm.qsmcm_sc1sr; +#else + status = immr->im_qsmcm.qsmcm_sc2sr; +#endif + return (status & SCI_RDRF); +} + +void serial_setbrg (void) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + short scxbr; + + /* Set baudrate */ + scxbr = (gd->cpu_clk / (32 * gd->baudrate)); +#if defined(CONFIG_5xx_CONS_SCI1) + immr->im_qsmcm.qsmcm_scc1r0 = (scxbr & SCI_SCXBR_MK); +#else + immr->im_qsmcm.qsmcm_scc2r0 = (scxbr & SCI_SCXBR_MK); +#endif +} + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc(*s); + ++s; + } +} + +int ready_to_send(void) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile short status; + + do { +#if defined(CONFIG_5xx_CONS_SCI1) + status = immr->im_qsmcm.qsmcm_sc1sr; +#else + status = immr->im_qsmcm.qsmcm_sc2sr; +#endif + +#if defined(CONFIG_WATCHDOG) + reset_5xx_watchdog (immr); +#endif + } while ((status & SCI_TDRE) == 0); + return 1; + +} diff --git a/drivers/serial/serial_mpc8260_scc.c b/drivers/serial/serial_mpc8260_scc.c new file mode 100644 index 0000000000..3a6eaf0a67 --- /dev/null +++ b/drivers/serial/serial_mpc8260_scc.c @@ -0,0 +1,498 @@ +/* + * (C) Copyright 2000 + * 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 + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00. + */ + +/* + * Minimal serial functions needed to use one of the SCC ports + * as serial console interface. + */ + +#include <common.h> +#include <mpc8260.h> +#include <asm/cpm_8260.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CONS_ON_SCC) + +#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */ + +#define SCC_INDEX 0 +#define PROFF_SCC PROFF_SCC1 +#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) +#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK + +#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */ + +#define SCC_INDEX 1 +#define PROFF_SCC PROFF_SCC2 +#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) +#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK + +#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */ + +#define SCC_INDEX 2 +#define PROFF_SCC PROFF_SCC3 +#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) +#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK + +#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */ + +#define SCC_INDEX 3 +#define PROFF_SCC PROFF_SCC4 +#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) +#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK + +#else + +#error "console not correctly defined" + +#endif + +int serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile scc_t *sp; + volatile scc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8260_t *cp = &(im->im_cpm); + uint dpaddr; + + /* initialize pointers to SCC */ + + sp = (scc_t *) &(im->im_scc[SCC_INDEX]); + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; + + /* Disable transmitter/receiver. + */ + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* put the SCC channel into NMSI (non multiplexd serial interface) + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). + */ + im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr&~CMXSCR_MASK)|CMXSCR_VALUE; + + /* Set up the baud rate generator. + */ + serial_setbrg (); + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; + rbdf->cbd_bufaddr = (uint) (rbdf+2); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; + tbdf->cbd_sc = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ + up->scc_genscc.scc_rbase = dpaddr; + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); + up->scc_genscc.scc_rfcr = CPMFCR_EB; + up->scc_genscc.scc_tfcr = CPMFCR_EB; + up->scc_genscc.scc_mrblr = 1; + up->scc_maxidl = 0; + up->scc_brkcr = 1; + 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 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; + up->scc_rccm = 0xc0ff; + + /* Mask all interrupts and remove anything pending. + */ + sp->scc_sccm = 0; + sp->scc_scce = 0xffff; + + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. + */ + sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ + sp->scc_gsmrl = \ + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; + + /* Set CTS flow control, 1 stop bit, 8 bit character length, + * normal async UART mode, no parity + */ + sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL; + + /* execute the "Init Rx and Tx params" CP command. + */ + + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + /* Enable transmitter/receiver. + */ + sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; + + return (0); +} + +void +serial_setbrg (void) +{ +#if defined(CONFIG_CONS_USE_EXTC) + m8260_cpm_extcbrg(SCC_INDEX, gd->baudrate, + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); +#else + m8260_cpm_setbrg(SCC_INDEX, gd->baudrate); +#endif +} + +void +serial_putc(const char c) +{ + volatile scc_uart_t *up; + volatile cbd_t *tbdf; + volatile immap_t *im; + + if (c == '\n') + serial_putc ('\r'); + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; + tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase]; + + /* Wait for last character to go. + */ + while (tbdf->cbd_sc & BD_SC_READY) + ; + + /* Load the character into the transmit buffer. + */ + *(volatile char *)tbdf->cbd_bufaddr = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int +serial_getc(void) +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + unsigned char c; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; + + /* Wait for character to show up. + */ + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + + /* Grab the char and clear the buffer again. + */ + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return (c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; + + return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0); +} + +#endif /* CONFIG_CONS_ON_SCC */ + +#if defined(CONFIG_KGDB_ON_SCC) + +#if defined(CONFIG_CONS_ON_SCC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX +#error Whoops! serial console and kgdb are on the same scc serial port +#endif + +#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SCC1 */ + +#define KGDB_SCC_INDEX 0 +#define KGDB_PROFF_SCC PROFF_SCC1 +#define KGDB_CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define KGDB_CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK + +#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SCC2 */ + +#define KGDB_SCC_INDEX 1 +#define KGDB_PROFF_SCC PROFF_SCC2 +#define KGDB_CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) +#define KGDB_CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK + +#elif CONFIG_KGDB_INDEX == 3 /* KGDB Port on SCC3 */ + +#define KGDB_SCC_INDEX 2 +#define KGDB_PROFF_SCC PROFF_SCC3 +#define KGDB_CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) +#define KGDB_CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK + +#elif CONFIG_KGDB_INDEX == 4 /* KGDB Port on SCC4 */ + +#define KGDB_SCC_INDEX 3 +#define KGDB_PROFF_SCC PROFF_SCC4 +#define KGDB_CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) +#define KGDB_CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK + +#else + +#error "kgdb serial port not correctly defined" + +#endif + +void +kgdb_serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile scc_t *sp; + volatile scc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8260_t *cp = &(im->im_cpm); + uint dpaddr, speed = CONFIG_KGDB_BAUDRATE; + char *s, *e; + + if ((s = getenv("kgdbrate")) != NULL && *s != '\0') { + ulong rate = simple_strtoul(s, &e, 10); + if (e > s && *e == '\0') + speed = rate; + } + + /* initialize pointers to SCC */ + + sp = (scc_t *) &(im->im_scc[KGDB_SCC_INDEX]); + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; + + /* Disable transmitter/receiver. + */ + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* put the SCC channel into NMSI (non multiplexd serial interface) + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). + */ + im->im_cpmux.cmx_scr = \ + (im->im_cpmux.cmx_scr & ~KGDB_CMXSCR_MASK) | KGDB_CMXSCR_VALUE; + + /* Set up the baud rate generator. + */ +#if defined(CONFIG_KGDB_USE_EXTC) + m8260_cpm_extcbrg(KGDB_SCC_INDEX, speed, + CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL); +#else + m8260_cpm_setbrg(KGDB_SCC_INDEX, speed); +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; + rbdf->cbd_bufaddr = (uint) (rbdf+2); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; + tbdf->cbd_sc = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ + up->scc_genscc.scc_rbase = dpaddr; + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); + up->scc_genscc.scc_rfcr = CPMFCR_EB; + up->scc_genscc.scc_tfcr = CPMFCR_EB; + up->scc_genscc.scc_mrblr = 1; + up->scc_maxidl = 0; + up->scc_brkcr = 1; + 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 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; + up->scc_rccm = 0xc0ff; + + /* Mask all interrupts and remove anything pending. + */ + sp->scc_sccm = 0; + sp->scc_scce = 0xffff; + + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. + */ + sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ + sp->scc_gsmrl = \ + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; + + /* Set CTS flow control, 1 stop bit, 8 bit character length, + * normal async UART mode, no parity + */ + sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL; + + /* execute the "Init Rx and Tx params" CP command. + */ + + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SCC_PAGE, KGDB_CPM_CR_SCC_SBLOCK, + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + /* Enable transmitter/receiver. + */ + sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; + + printf("SCC%d at %dbps ", CONFIG_KGDB_INDEX, speed); +} + +void +putDebugChar(const char c) +{ + volatile scc_uart_t *up; + volatile cbd_t *tbdf; + volatile immap_t *im; + + if (c == '\n') + putDebugChar ('\r'); + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; + tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase]; + + /* Wait for last character to go. + */ + while (tbdf->cbd_sc & BD_SC_READY) + ; + + /* Load the character into the transmit buffer. + */ + *(volatile char *)tbdf->cbd_bufaddr = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +void +putDebugStr (const char *s) +{ + while (*s) { + putDebugChar (*s++); + } +} + +int +getDebugChar(void) +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + unsigned char c; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; + + /* Wait for character to show up. + */ + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + + /* Grab the char and clear the buffer again. + */ + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return (c); +} + +void +kgdb_interruptible(int yes) +{ + return; +} + +#endif /* CONFIG_KGDB_ON_SCC */ diff --git a/drivers/serial/serial_mpc8260_smc.c b/drivers/serial/serial_mpc8260_smc.c new file mode 100644 index 0000000000..f3dffeb119 --- /dev/null +++ b/drivers/serial/serial_mpc8260_smc.c @@ -0,0 +1,462 @@ +/* + * (C) Copyright 2000, 2001, 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 + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with + * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the + * Linux/PPC sources (m8260_tty.c had no copyright info in it). + */ + +/* + * Minimal serial functions needed to use one of the SMC ports + * as serial console interface. + */ + +#include <common.h> +#include <mpc8260.h> +#include <asm/cpm_8260.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CONS_ON_SMC) + +#if CONFIG_CONS_INDEX == 1 /* Console on SMC1 */ + +#define SMC_INDEX 0 +#define PROFF_SMC_BASE PROFF_SMC1_BASE +#define PROFF_SMC PROFF_SMC1 +#define CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE +#define CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK +#define CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) +#define CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 + +#elif CONFIG_CONS_INDEX == 2 /* Console on SMC2 */ + +#define SMC_INDEX 1 +#define PROFF_SMC_BASE PROFF_SMC2_BASE +#define PROFF_SMC PROFF_SMC2 +#define CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE +#define CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK +#define CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) +#define CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 + +#else + +#error "console not correctly defined" + +#endif + +/* map rs_table index to baud rate generator index */ +static unsigned char brg_map[] = { + 6, /* BRG7 for SMC1 */ + 7, /* BRG8 for SMC2 */ + 0, /* BRG1 for SCC1 */ + 1, /* BRG1 for SCC2 */ + 2, /* BRG1 for SCC3 */ + 3, /* BRG1 for SCC4 */ +}; + +int serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8260_t *cp = &(im->im_cpm); + uint dpaddr; + + /* initialize pointers to SMC */ + + sp = (smc_t *) &(im->im_smc[SMC_INDEX]); + *(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC; + up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&im->im_dprambase[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 = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; + up->smc_brklen = 0; + up->smc_brkec = 0; + up->smc_brkcr = 0; + + /* 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; + + /* put the SMC channel into NMSI (non multiplexd serial interface) + * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). + */ + im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE; + + /* Set up the baud rate generator. + */ + serial_setbrg (); + + /* 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_SMC_PAGE, CPM_CR_SMC_SBLOCK, + 0, 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; + + return (0); +} + +void +serial_setbrg (void) +{ +#if defined(CONFIG_CONS_USE_EXTC) + m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate, + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); +#else + m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate); +#endif +} + +void +serial_putc(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CFG_IMMR; + + if (c == '\n') + serial_putc ('\r'); + + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); + + tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; + + /* 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; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int +serial_getc(void) +{ + volatile cbd_t *rbdf; + volatile unsigned char *buf; + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CFG_IMMR; + unsigned char c; + + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); + + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (unsigned char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CFG_IMMR; + + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); + + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} + +#endif /* CONFIG_CONS_ON_SMC */ + +#if defined(CONFIG_KGDB_ON_SMC) + +#if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX +#error Whoops! serial console and kgdb are on the same smc serial port +#endif + +#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SMC1 */ + +#define KGDB_SMC_INDEX 0 +#define KGDB_PROFF_SMC_BASE PROFF_SMC1_BASE +#define KGDB_PROFF_SMC PROFF_SMC1 +#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE +#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK +#define KGDB_CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) +#define KGDB_CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 + +#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SMC2 */ + +#define KGDB_SMC_INDEX 1 +#define KGDB_PROFF_SMC_BASE PROFF_SMC2_BASE +#define KGDB_PROFF_SMC PROFF_SMC2 +#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE +#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK +#define KGDB_CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) +#define KGDB_CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 + +#else + +#error "console not correctly defined" + +#endif + +void +kgdb_serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8260_t *cp = &(im->im_cpm); + uint dpaddr, speed = CONFIG_KGDB_BAUDRATE; + char *s, *e; + + if ((s = getenv("kgdbrate")) != NULL && *s != '\0') { + ulong rate = simple_strtoul(s, &e, 10); + if (e > s && *e == '\0') + speed = rate; + } + + /* initialize pointers to SMC */ + + sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]); + *(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC; + up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&im->im_dprambase[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 = CPMFCR_EB; + up->smc_tfcr = CPMFCR_EB; + up->smc_brklen = 0; + up->smc_brkec = 0; + up->smc_brkcr = 0; + + /* 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; + + /* put the SMC channel into NMSI (non multiplexd serial interface) + * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). + */ + im->im_cpmux.cmx_smr = + (im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE; + + /* Set up the baud rate generator. + */ +#if defined(CONFIG_KGDB_USE_EXTC) + m8260_cpm_extcbrg(brg_map[KGDB_SMC_INDEX], speed, + CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL); +#else + m8260_cpm_setbrg(brg_map[KGDB_SMC_INDEX], speed); +#endif + + /* 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(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK, + 0, 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; + + printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed); +} + +void +putDebugChar(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CFG_IMMR; + + if (c == '\n') + putDebugChar ('\r'); + + up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); + + tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; + + /* 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; +} + +void +putDebugStr (const char *s) +{ + while (*s) { + putDebugChar (*s++); + } +} + +int +getDebugChar(void) +{ + volatile cbd_t *rbdf; + volatile unsigned char *buf; + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CFG_IMMR; + unsigned char c; + + up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); + + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (unsigned char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +void +kgdb_interruptible(int yes) +{ + return; +} + +#endif /* CONFIG_KGDB_ON_SMC */ diff --git a/drivers/serial/serial_mpc85xx_scc.c b/drivers/serial/serial_mpc85xx_scc.c new file mode 100644 index 0000000000..4e925f8bea --- /dev/null +++ b/drivers/serial/serial_mpc85xx_scc.c @@ -0,0 +1,274 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * Modified based on 8260 for 8560. + * + * (C) Copyright 2000 + * 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 + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00. + */ + +/* + * Minimal serial functions needed to use one of the SCC ports + * as serial console interface. + */ + +#include <common.h> +#include <asm/cpm_85xx.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CPM2) +#if defined(CONFIG_CONS_ON_SCC) + +#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */ + +#define SCC_INDEX 0 +#define PROFF_SCC PROFF_SCC1 +#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) +#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK + +#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */ + +#define SCC_INDEX 1 +#define PROFF_SCC PROFF_SCC2 +#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) +#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK + +#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */ + +#define SCC_INDEX 2 +#define PROFF_SCC PROFF_SCC3 +#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) +#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK + +#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */ + +#define SCC_INDEX 3 +#define PROFF_SCC PROFF_SCC4 +#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) +#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK + +#else + +#error "console not correctly defined" + +#endif + +int serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile ccsr_cpm_scc_t *sp; + volatile scc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile ccsr_cpm_cp_t *cp = &(im->im_cpm.im_cpm_cp); + uint dpaddr; + + /* initialize pointers to SCC */ + + sp = (ccsr_cpm_scc_t *) &(im->im_cpm.im_cpm_scc[SCC_INDEX]); + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + + /* Disable transmitter/receiver. + */ + sp->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* put the SCC channel into NMSI (non multiplexd serial interface) + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). + */ + im->im_cpm.im_cpm_mux.cmxscr = \ + (im->im_cpm.im_cpm_mux.cmxscr&~CMXSCR_MASK)|CMXSCR_VALUE; + + /* Set up the baud rate generator. + */ + serial_setbrg (); + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8560_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[dpaddr]); + rbdf->cbd_bufaddr = (uint) (rbdf+2); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; + tbdf->cbd_sc = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ + up->scc_genscc.scc_rbase = dpaddr; + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); + up->scc_genscc.scc_rfcr = CPMFCR_EB; + up->scc_genscc.scc_tfcr = CPMFCR_EB; + up->scc_genscc.scc_mrblr = 1; + up->scc_maxidl = 0; + up->scc_brkcr = 1; + 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 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; + up->scc_rccm = 0xc0ff; + + /* Mask all interrupts and remove anything pending. + */ + sp->sccm = 0; + sp->scce = 0xffff; + + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. + */ + sp->gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ + sp->gsmrl = \ + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; + + /* Set CTS no flow control, 1 stop bit, 8 bit character length, + * normal async UART mode, no parity + */ + sp->psmr = SCU_PSMR_CL; + + /* execute the "Init Rx and Tx params" CP command. + */ + + while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + cp->cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + + while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + /* Enable transmitter/receiver. + */ + sp->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; + + return (0); +} + +void +serial_setbrg (void) +{ +#if defined(CONFIG_CONS_USE_EXTC) + m8560_cpm_extcbrg(SCC_INDEX, gd->baudrate, + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); +#else + m8560_cpm_setbrg(SCC_INDEX, gd->baudrate); +#endif +} + +void +serial_putc(const char c) +{ + volatile scc_uart_t *up; + volatile cbd_t *tbdf; + volatile immap_t *im; + + if (c == '\n') + serial_putc ('\r'); + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + tbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_tbase]); + + /* Wait for last character to go. + */ + while (tbdf->cbd_sc & BD_SC_READY) + ; + + /* Load the character into the transmit buffer. + */ + *(volatile char *)tbdf->cbd_bufaddr = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int +serial_getc(void) +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + unsigned char c; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_rbase]); + + /* Wait for character to show up. + */ + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + + /* Grab the char and clear the buffer again. + */ + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return (c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_rbase]); + + return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0); +} + +#endif /* CONFIG_CONS_ON_SCC */ + +#endif /* CONFIG_CPM2 */ diff --git a/drivers/serial/serial_mpc8xx.c b/drivers/serial/serial_mpc8xx.c new file mode 100644 index 0000000000..af5f4cf201 --- /dev/null +++ b/drivers/serial/serial_mpc8xx.c @@ -0,0 +1,704 @@ +/* + * (C) Copyright 2000 + * 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> +#include <commproc.h> +#include <command.h> +#include <serial.h> +#include <watchdog.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */ + +#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */ +#define SMC_INDEX 0 +#define PROFF_SMC PROFF_SMC1 +#define CPM_CR_CH_SMC CPM_CR_CH_SMC1 + +#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */ +#define SMC_INDEX 1 +#define PROFF_SMC PROFF_SMC2 +#define CPM_CR_CH_SMC CPM_CR_CH_SMC2 + +#endif /* CONFIG_8xx_CONS_SMCx */ + +#if defined(CONFIG_8xx_CONS_SCC1) /* Console on SCC1 */ +#define SCC_INDEX 0 +#define PROFF_SCC PROFF_SCC1 +#define CPM_CR_CH_SCC CPM_CR_CH_SCC1 + +#elif defined(CONFIG_8xx_CONS_SCC2) /* Console on SCC2 */ +#define SCC_INDEX 1 +#define PROFF_SCC PROFF_SCC2 +#define CPM_CR_CH_SCC CPM_CR_CH_SCC2 + +#elif defined(CONFIG_8xx_CONS_SCC3) /* Console on SCC3 */ +#define SCC_INDEX 2 +#define PROFF_SCC PROFF_SCC3 +#define CPM_CR_CH_SCC CPM_CR_CH_SCC3 + +#elif defined(CONFIG_8xx_CONS_SCC4) /* Console on SCC4 */ +#define SCC_INDEX 3 +#define PROFF_SCC PROFF_SCC4 +#define CPM_CR_CH_SCC CPM_CR_CH_SCC4 + +#endif /* CONFIG_8xx_CONS_SCCx */ + +static void serial_setdivisor(volatile cpm8xx_t *cp) +{ + int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate; + + if(divisor/16>0x1000) { + /* bad divisor, assume 50Mhz clock and 9600 baud */ + divisor=(50*1000*1000 + 8*9600)/16/9600; + } + +#ifdef CFG_BRGCLK_PRESCALE + divisor /= CFG_BRGCLK_PRESCALE; +#endif + + if(divisor<=0x1000) { + cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN; + } else { + cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16; + } +} + +#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2)) + +/* + * Minimal serial functions needed to use one of the SMC ports + * as serial console interface. + */ + +static void smc_setbrg (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile cpm8xx_t *cp = &(im->im_cpm); + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * + * Wire BRG1 to SMCx + */ + + cp->cp_simode = 0x00000000; + + serial_setdivisor(cp); +} + +static int smc_init (void) +{ + 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); +#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850)) + volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport); +#endif + uint dpaddr; + + /* initialize pointers to SMC */ + + sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]); + up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC]; + + /* 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_8xx_CONS_SMC1) + /* Use Port B for SMC1 instead of other functions. + */ + cp->cp_pbpar |= 0x000000c0; + cp->cp_pbdir &= ~0x000000c0; + cp->cp_pbodr &= ~0x000000c0; +#else /* CONFIG_8xx_CONS_SMC2 */ +# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850) + /* Use Port A for SMC2 instead of other functions. + */ + ip->iop_papar |= 0x00c0; + ip->iop_padir &= ~0x00c0; + ip->iop_paodr &= ~0x00c0; +# else /* must be a 860 then */ + /* Use Port B for SMC2 instead of other functions. + */ + cp->cp_pbpar |= 0x00000c00; + cp->cp_pbdir &= ~0x00000c00; + cp->cp_pbodr &= ~0x00000c00; +# endif +#endif + +#if defined(CONFIG_FADS) || defined(CONFIG_ADS) + /* Enable RS232 */ +#if defined(CONFIG_8xx_CONS_SMC1) + *((uint *) BCSR1) &= ~BCSR1_RS232EN_1; +#else + *((uint *) BCSR1) &= ~BCSR1_RS232EN_2; +#endif +#endif /* CONFIG_FADS */ + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + /* Enable Monitor Port Transceiver */ + *((uchar *) BCSR0) |= BCSR0_ENMONXCVR ; +#endif /* CONFIG_RPXLITE */ + + /* 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_SERIAL_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 /* CONFIG_MBX */ + + /* 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; + +#ifdef CFG_SPC1920_SMC1_CLK4 /* clock source is PLD */ + *((volatile uchar *) CFG_SPC1920_PLD_BASE+6) = 0xff; +#else + /* Set up the baud rate generator */ + smc_setbrg (); +#endif + + /* 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, 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; + + return (0); +} + +static void +smc_putc(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); + + if (c == '\n') + smc_putc ('\r'); + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; + + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + + buf = (char *)tbdf->cbd_bufaddr; + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; + __asm__("eieio"); + + while (tbdf->cbd_sc & BD_SC_READY) { + WATCHDOG_RESET (); + __asm__("eieio"); + } +} + +static void +smc_puts (const char *s) +{ + while (*s) { + smc_putc (*s++); + } +} + +static int +smc_getc(void) +{ + 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; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; + + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (unsigned char *)rbdf->cbd_bufaddr; + + while (rbdf->cbd_sc & BD_SC_EMPTY) + WATCHDOG_RESET (); + + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +static int +smc_tstc(void) +{ + volatile cbd_t *rbdf; + 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]; + + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} + +struct serial_device serial_smc_device = +{ + "serial_smc", + "SMC", + smc_init, + smc_setbrg, + smc_getc, + smc_tstc, + smc_putc, + smc_puts, +}; + +#endif /* CONFIG_8xx_CONS_SMC1 || CONFIG_8xx_CONS_SMC2 */ + +#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \ + defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4) + +static void +scc_setbrg (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile cpm8xx_t *cp = &(im->im_cpm); + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * + * Wire BRG1 to SCCx + */ + + cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX)); + + serial_setdivisor(cp); +} + +static int scc_init (void) +{ + 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; +#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850) + volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport); +#endif + + /* initialize pointers to SCC */ + + sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]); + up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC]; + +#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2) + { /* Disable Ethernet, enable Serial */ + uchar c; + + c = pic_read (0x61); + c &= ~0x40; /* enable COM3 */ + c |= 0x80; /* disable Ethernet */ + pic_write (0x61, c); + + /* enable RTS2 */ + cp->cp_pbpar |= 0x2000; + cp->cp_pbdat |= 0x2000; + cp->cp_pbdir |= 0x2000; + } +#endif /* CONFIG_LWMON */ + + /* Disable transmitter/receiver. + */ + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + +#if (SCC_INDEX == 2) && defined(CONFIG_MPC850) + /* + * The MPC850 has SCC3 on Port B + */ + cp->cp_pbpar |= 0x06; + cp->cp_pbdir &= ~0x06; + cp->cp_pbodr &= ~0x06; + +#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860) + /* + * Standard configuration for SCC's is on Part A + */ + ip->iop_papar |= ((3 << (2 * SCC_INDEX))); + ip->iop_padir &= ~((3 << (2 * SCC_INDEX))); + ip->iop_paodr &= ~((3 << (2 * SCC_INDEX))); +#else + /* + * The IP860 has SCC3 and SCC4 on Port D + */ + ip->iop_pdpar |= ((3 << (2 * SCC_INDEX))); +#endif + + /* 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_SERIAL2_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. + */ + scc_setbrg (); + + /* 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, 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 SCC(x) clock mode to 16x + * See 8xx_io/commproc.c for details. + * + * Wire BRG1 to SCCn + */ + + /* Set UART mode, clock divider 16 on Tx and Rx + */ + sp->scc_gsmrl &= ~0xF; + sp->scc_gsmrl |= + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + sp->scc_psmr = 0; + 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); + + return (0); +} + +static void +scc_putc(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); + + if (c == '\n') + scc_putc ('\r'); + + up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC]; + + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase]; + + /* Wait for last character to go. + */ + + buf = (char *)tbdf->cbd_bufaddr; + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; + __asm__("eieio"); + + while (tbdf->cbd_sc & BD_SC_READY) { + __asm__("eieio"); + WATCHDOG_RESET (); + } +} + +static void +scc_puts (const char *s) +{ + while (*s) { + scc_putc (*s++); + } +} + +static int +scc_getc(void) +{ + 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; + + up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC]; + + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; + + /* Wait for character to show up. + */ + buf = (unsigned char *)rbdf->cbd_bufaddr; + + while (rbdf->cbd_sc & BD_SC_EMPTY) + WATCHDOG_RESET (); + + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +static int +scc_tstc(void) +{ + volatile cbd_t *rbdf; + 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]; + + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} + +struct serial_device serial_scc_device = +{ + "serial_scc", + "SCC", + scc_init, + scc_setbrg, + scc_getc, + scc_tstc, + scc_putc, + scc_puts, +}; + +#endif /* CONFIG_8xx_CONS_SCCx */ + +void enable_putc(void) +{ + gd->be_quiet = 0; +} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + +void +kgdb_serial_init(void) +{ + int i = -1; + + if (strcmp(default_serial_console()->ctlr, "SMC") == 0) + { +#if defined(CONFIG_8xx_CONS_SMC1) + i = 1; +#elif defined(CONFIG_8xx_CONS_SMC2) + i = 2; +#endif + } + else if (strcmp(default_serial_console()->ctlr, "SMC") == 0) + { +#if defined(CONFIG_8xx_CONS_SCC1) + i = 1; +#elif defined(CONFIG_8xx_CONS_SCC2) + i = 2; +#elif defined(CONFIG_8xx_CONS_SCC3) + i = 3; +#elif defined(CONFIG_8xx_CONS_SCC4) + i = 4; +#endif + } + + if (i >= 0) + { + serial_printf("[on %s%d] ", default_serial_console()->ctlr, i); + } +} + +void +putDebugChar (int c) +{ + serial_putc (c); +} + +void +putDebugStr (const char *str) +{ + serial_puts (str); +} + +int +getDebugChar (void) +{ + return serial_getc(); +} + +void +kgdb_interruptible (int yes) +{ + return; +} +#endif /* CFG_CMD_KGDB */ + +#endif /* CONFIG_8xx_CONS_NONE */ diff --git a/drivers/serial/serial_netarm.c b/drivers/serial/serial_netarm.c new file mode 100644 index 0000000000..bc6bf30b69 --- /dev/null +++ b/drivers/serial/serial_netarm.c @@ -0,0 +1,200 @@ +/* + * Serial Port stuff - taken from Linux + * + * (C) Copyright 2002 + * MAZeT GmbH <www.mazet.de> + * Stephan Linz <linz@mazet.de>, <linz@li-pro.net> + * + * (c) 2004 + * IMMS gGmbH <www.imms.de> + * Thomas Elste <info@elste.org> + * + * 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> + +#ifdef CONFIG_NETARM + +#include <asm/hardware.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define PORTA (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_PORTA)) +#if !defined(CONFIG_NETARM_NS7520) +#define PORTB (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_PORTB)) +#else +#define PORTC (*(volatile unsigned int *)(NETARM_GEN_MODULE_BASE + NETARM_GEN_PORTC)) +#endif + +/* wait until transmitter is ready for another character */ +#define TXWAITRDY(registers) \ +{ \ + ulong tmo = get_timer(0) + 1 * CFG_HZ; \ + while (((registers)->status_a & NETARM_SER_STATA_TX_RDY) == 0 ) { \ + if (get_timer(0) > tmo) \ + break; \ + } \ +} + + +#ifndef CONFIG_UART1_CONSOLE +volatile netarm_serial_channel_t *serial_reg_ch1 = get_serial_channel(0); +volatile netarm_serial_channel_t *serial_reg_ch2 = get_serial_channel(1); +#else +volatile netarm_serial_channel_t *serial_reg_ch1 = get_serial_channel(1); +volatile netarm_serial_channel_t *serial_reg_ch2 = get_serial_channel(0); +#endif + +extern void _netarm_led_FAIL1(void); + +/* + * Setup both serial i/f with given baudrate + */ +void serial_setbrg (void) +{ + /* set 0 ... make sure pins are configured for serial */ +#if !defined(CONFIG_NETARM_NS7520) + PORTA = PORTB = + NETARM_GEN_PORT_MODE (0xef) | NETARM_GEN_PORT_DIR (0xe0); +#else + PORTA = NETARM_GEN_PORT_MODE (0xef) | NETARM_GEN_PORT_DIR (0xe0); + PORTC = NETARM_GEN_PORT_CSF (0xef) | NETARM_GEN_PORT_MODE (0xef) | NETARM_GEN_PORT_DIR (0xe0); +#endif + + /* first turn em off */ + serial_reg_ch1->ctrl_a = serial_reg_ch2->ctrl_a = 0; + + /* clear match register, we don't need it */ + serial_reg_ch1->rx_match = serial_reg_ch2->rx_match = 0; + + /* setup bit rate generator and rx buffer gap timer (1 byte only) */ + if ((gd->baudrate >= MIN_BAUD_RATE) + && (gd->baudrate <= MAX_BAUD_RATE)) { + serial_reg_ch1->bitrate = serial_reg_ch2->bitrate = + NETARM_SER_BR_X16 (gd->baudrate); + serial_reg_ch1->rx_buf_timer = serial_reg_ch2->rx_buf_timer = + 0; + serial_reg_ch1->rx_char_timer = serial_reg_ch2->rx_char_timer = + NETARM_SER_RXGAP (gd->baudrate); + } else { + hang (); + } + + /* setup port mode */ + serial_reg_ch1->ctrl_b = serial_reg_ch2->ctrl_b = + ( NETARM_SER_CTLB_RCGT_EN | + NETARM_SER_CTLB_UART_MODE); + serial_reg_ch1->ctrl_a = serial_reg_ch2->ctrl_a = + ( NETARM_SER_CTLA_ENABLE | + NETARM_SER_CTLA_P_NONE | + /* see errata */ + NETARM_SER_CTLA_2STOP | + NETARM_SER_CTLA_8BITS | + NETARM_SER_CTLA_DTR_EN | + NETARM_SER_CTLA_RTS_EN); +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + */ +int serial_init (void) +{ + serial_setbrg (); + return 0; +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + volatile unsigned char *fifo; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); + + fifo = (volatile unsigned char *) &(serial_reg_ch1->fifo); + TXWAITRDY (serial_reg_ch1); + *fifo = c; +} + +/* + * Test of a single byte from the serial port. Returns 1 on success, 0 + * otherwise. + */ +int serial_tstc(void) +{ + return serial_reg_ch1->status_a & NETARM_SER_STATA_RX_RDY; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. + */ +int serial_getc (void) +{ + unsigned int ch_uint; + volatile unsigned int *fifo; + volatile unsigned char *fifo_char = NULL; + int buf_count = 0; + + while (!(serial_reg_ch1->status_a & NETARM_SER_STATA_RX_RDY)) + /* NOP */ ; + + fifo = (volatile unsigned int *) &(serial_reg_ch1->fifo); + fifo_char = (unsigned char *) &ch_uint; + ch_uint = *fifo; + + buf_count = NETARM_SER_STATA_RXFDB (serial_reg_ch1->status_a); + switch (buf_count) { + case NETARM_SER_STATA_RXFDB_4BYTES: + buf_count = 4; + break; + case NETARM_SER_STATA_RXFDB_3BYTES: + buf_count = 3; + break; + case NETARM_SER_STATA_RXFDB_2BYTES: + buf_count = 2; + break; + case NETARM_SER_STATA_RXFDB_1BYTES: + buf_count = 1; + break; + default: + /* panic, be never here */ + break; + } + + serial_reg_ch1->status_a |= NETARM_SER_STATA_RX_CLOSED; + + return ch_uint & 0xff; +} + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +#endif /* CONFIG_NETARM */ diff --git a/drivers/serial/serial_nios.c b/drivers/serial/serial_nios.c new file mode 100644 index 0000000000..5ecdc6d7ea --- /dev/null +++ b/drivers/serial/serial_nios.c @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2003, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * 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> +#include <watchdog.h> +#include <nios-io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/*------------------------------------------------------------------ + * JTAG acts as the serial port + *-----------------------------------------------------------------*/ +#if defined(CONFIG_CONSOLE_JTAG) + +static nios_jtag_t *jtag = (nios_jtag_t *)CFG_NIOS_CONSOLE; + +void serial_setbrg( void ){ return; } +int serial_init( void ) { return(0);} + +void serial_putc (char c) +{ + while ((jtag->txcntl & NIOS_JTAG_TRDY) != 0) + WATCHDOG_RESET (); + jtag->txcntl = NIOS_JTAG_TRDY | (unsigned char)c; +} + +void serial_puts (const char *s) +{ + while (*s != 0) + serial_putc (*s++); +} + +int serial_tstc (void) +{ + return (jtag->rxcntl & NIOS_JTAG_RRDY); +} + +int serial_getc (void) +{ + int c; + while (serial_tstc() == 0) + WATCHDOG_RESET (); + c = jtag->rxcntl & 0x0ff; + jtag->rxcntl = 0; + return (c); +} + +/*------------------------------------------------------------------ + * UART the serial port + *-----------------------------------------------------------------*/ +#else + +static nios_uart_t *uart = (nios_uart_t *)CFG_NIOS_CONSOLE; + +#if defined(CFG_NIOS_FIXEDBAUD) + +/* Everything's already setup for fixed-baud PTF + * assignment + */ +void serial_setbrg (void){ return; } +int serial_init (void) { return (0);} + +#else + +void serial_setbrg (void) +{ + unsigned div; + + div = (CONFIG_SYS_CLK_FREQ/gd->baudrate)-1; + uart->divisor = div; + return; +} + +int serial_init (void) +{ + serial_setbrg (); + return (0); +} + +#endif /* CFG_NIOS_FIXEDBAUD */ + + +/*----------------------------------------------------------------------- + * UART CONSOLE + *---------------------------------------------------------------------*/ +void serial_putc (char c) +{ + if (c == '\n') + serial_putc ('\r'); + while ((uart->status & NIOS_UART_TRDY) == 0) + WATCHDOG_RESET (); + uart->txdata = (unsigned char)c; +} + +void serial_puts (const char *s) +{ + while (*s != 0) { + serial_putc (*s++); + } +} + +int serial_tstc (void) +{ + return (uart->status & NIOS_UART_RRDY); +} + +int serial_getc (void) +{ + while (serial_tstc () == 0) + WATCHDOG_RESET (); + return( uart->rxdata & 0x00ff ); +} + +#endif /* CONFIG_JTAG_CONSOLE */ diff --git a/drivers/serial/serial_nios2.c b/drivers/serial/serial_nios2.c new file mode 100644 index 0000000000..0bd3821e39 --- /dev/null +++ b/drivers/serial/serial_nios2.c @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2004, Psyent Corporation <www.psyent.com> + * Scott McNutt <smcnutt@psyent.com> + * + * 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> +#include <watchdog.h> +#include <asm/io.h> +#include <nios2-io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/*------------------------------------------------------------------ + * JTAG acts as the serial port + *-----------------------------------------------------------------*/ +#if defined(CONFIG_CONSOLE_JTAG) + +static nios_jtag_t *jtag = (nios_jtag_t *)CFG_NIOS_CONSOLE; + +void serial_setbrg( void ){ return; } +int serial_init( void ) { return(0);} + +void serial_putc (char c) +{ + unsigned val; + + while (NIOS_JTAG_WSPACE ( readl (&jtag->control)) == 0) + WATCHDOG_RESET (); + writel (&jtag->data, (unsigned char)c); +} + +void serial_puts (const char *s) +{ + while (*s != 0) + serial_putc (*s++); +} + +int serial_tstc (void) +{ + return ( readl (&jtag->control) & NIOS_JTAG_RRDY); +} + +int serial_getc (void) +{ + int c; + unsigned val; + + while (1) { + WATCHDOG_RESET (); + val = readl (&jtag->data); + if (val & NIOS_JTAG_RVALID) + break; + } + c = val & 0x0ff; + return (c); +} + +/*------------------------------------------------------------------ + * UART the serial port + *-----------------------------------------------------------------*/ +#else + +static nios_uart_t *uart = (nios_uart_t *) CFG_NIOS_CONSOLE; + +#if defined(CFG_NIOS_FIXEDBAUD) + +/* Everything's already setup for fixed-baud PTF + * assignment + */ +void serial_setbrg (void){ return; } +int serial_init (void) { return (0);} + +#else + +void serial_setbrg (void) +{ + unsigned div; + + div = (CONFIG_SYS_CLK_FREQ/gd->baudrate)-1; + writel (&uart->divisor,div); + return; +} + +int serial_init (void) +{ + serial_setbrg (); + return (0); +} + +#endif /* CFG_NIOS_FIXEDBAUD */ + + +/*----------------------------------------------------------------------- + * UART CONSOLE + *---------------------------------------------------------------------*/ +void serial_putc (char c) +{ + if (c == '\n') + serial_putc ('\r'); + while ((readl (&uart->status) & NIOS_UART_TRDY) == 0) + WATCHDOG_RESET (); + writel (&uart->txdata,(unsigned char)c); +} + +void serial_puts (const char *s) +{ + while (*s != 0) { + serial_putc (*s++); + } +} + +int serial_tstc (void) +{ + return (readl (&uart->status) & NIOS_UART_RRDY); +} + +int serial_getc (void) +{ + while (serial_tstc () == 0) + WATCHDOG_RESET (); + return (readl (&uart->rxdata) & 0x00ff ); +} + +#endif /* CONFIG_JTAG_CONSOLE */ diff --git a/drivers/serial/serial_ppc4xx.c b/drivers/serial/serial_ppc4xx.c new file mode 100644 index 0000000000..fab0d95006 --- /dev/null +++ b/drivers/serial/serial_ppc4xx.c @@ -0,0 +1,984 @@ +/* + * (C) Copyright 2000-2006 + * 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 + */ +/*------------------------------------------------------------------------------+ */ +/* + * This source code has been made available to you by IBM on an AS-IS + * basis. Anyone receiving this source is licensed under IBM + * copyrights to use it in any way he or she deems fit, including + * copying it, modifying it, compiling it, and redistributing it either + * with or without modifications. No license under IBM patents or + * patent applications is to be implied by the copyright license. + * + * Any user of this software should understand that IBM cannot provide + * technical support for this software and will not be responsible for + * any consequences resulting from the use of this software. + * + * Any person who transfers this source code or any derivative work + * must include the IBM copyright notice, this paragraph, and the + * preceding two paragraphs in the transferred software. + * + * COPYRIGHT I B M CORPORATION 1995 + * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M + */ +/*------------------------------------------------------------------------------- */ +/* + * Travis Sawyer 15 September 2004 + * Added CONFIG_SERIAL_MULTI support + */ +#include <common.h> +#include <commproc.h> +#include <asm/processor.h> +#include <watchdog.h> +#include "vecnum.h" + +#ifdef CONFIG_SERIAL_MULTI +#include <serial.h> +#endif + +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO +#include <malloc.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/*****************************************************************************/ +#ifdef CONFIG_IOP480 + +#define SPU_BASE 0x40000000 + +#define spu_LineStat_rc 0x00 /* Line Status Register (Read/Clear) */ +#define spu_LineStat_w 0x04 /* Line Status Register (Set) */ +#define spu_Handshk_rc 0x08 /* Handshake Status Register (Read/Clear) */ +#define spu_Handshk_w 0x0c /* Handshake Status Register (Set) */ +#define spu_BRateDivh 0x10 /* Baud rate divisor high */ +#define spu_BRateDivl 0x14 /* Baud rate divisor low */ +#define spu_CtlReg 0x18 /* Control Register */ +#define spu_RxCmd 0x1c /* Rx Command Register */ +#define spu_TxCmd 0x20 /* Tx Command Register */ +#define spu_RxBuff 0x24 /* Rx data buffer */ +#define spu_TxBuff 0x24 /* Tx data buffer */ + +/*-----------------------------------------------------------------------------+ + | Line Status Register. + +-----------------------------------------------------------------------------*/ +#define asyncLSRport1 0x40000000 +#define asyncLSRport1set 0x40000004 +#define asyncLSRDataReady 0x80 +#define asyncLSRFramingError 0x40 +#define asyncLSROverrunError 0x20 +#define asyncLSRParityError 0x10 +#define asyncLSRBreakInterrupt 0x08 +#define asyncLSRTxHoldEmpty 0x04 +#define asyncLSRTxShiftEmpty 0x02 + +/*-----------------------------------------------------------------------------+ + | Handshake Status Register. + +-----------------------------------------------------------------------------*/ +#define asyncHSRport1 0x40000008 +#define asyncHSRport1set 0x4000000c +#define asyncHSRDsr 0x80 +#define asyncLSRCts 0x40 + +/*-----------------------------------------------------------------------------+ + | Control Register. + +-----------------------------------------------------------------------------*/ +#define asyncCRport1 0x40000018 +#define asyncCRNormal 0x00 +#define asyncCRLoopback 0x40 +#define asyncCRAutoEcho 0x80 +#define asyncCRDtr 0x20 +#define asyncCRRts 0x10 +#define asyncCRWordLength7 0x00 +#define asyncCRWordLength8 0x08 +#define asyncCRParityDisable 0x00 +#define asyncCRParityEnable 0x04 +#define asyncCREvenParity 0x00 +#define asyncCROddParity 0x02 +#define asyncCRStopBitsOne 0x00 +#define asyncCRStopBitsTwo 0x01 +#define asyncCRDisableDtrRts 0x00 + +/*-----------------------------------------------------------------------------+ + | Receiver Command Register. + +-----------------------------------------------------------------------------*/ +#define asyncRCRport1 0x4000001c +#define asyncRCRDisable 0x00 +#define asyncRCREnable 0x80 +#define asyncRCRIntDisable 0x00 +#define asyncRCRIntEnabled 0x20 +#define asyncRCRDMACh2 0x40 +#define asyncRCRDMACh3 0x60 +#define asyncRCRErrorInt 0x10 +#define asyncRCRPauseEnable 0x08 + +/*-----------------------------------------------------------------------------+ + | Transmitter Command Register. + +-----------------------------------------------------------------------------*/ +#define asyncTCRport1 0x40000020 +#define asyncTCRDisable 0x00 +#define asyncTCREnable 0x80 +#define asyncTCRIntDisable 0x00 +#define asyncTCRIntEnabled 0x20 +#define asyncTCRDMACh2 0x40 +#define asyncTCRDMACh3 0x60 +#define asyncTCRTxEmpty 0x10 +#define asyncTCRErrorInt 0x08 +#define asyncTCRStopPause 0x04 +#define asyncTCRBreakGen 0x02 + +/*-----------------------------------------------------------------------------+ + | Miscellanies defines. + +-----------------------------------------------------------------------------*/ +#define asyncTxBufferport1 0x40000024 +#define asyncRxBufferport1 0x40000024 +#define asyncDLABLsbport1 0x40000014 +#define asyncDLABMsbport1 0x40000010 +#define asyncXOFFchar 0x13 +#define asyncXONchar 0x11 + +/* + * Minimal serial functions needed to use one of the SMC ports + * as serial console interface. + */ + +int serial_init (void) +{ + volatile char val; + unsigned short br_reg; + + br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1); + + /* + * Init onboard UART + */ + out8 (SPU_BASE + spu_LineStat_rc, 0x78); /* Clear all bits in Line Status Reg */ + out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */ + out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */ + out8 (SPU_BASE + spu_CtlReg, 0x08); /* Set 8 bits, no parity and 1 stop bit */ + out8 (SPU_BASE + spu_RxCmd, 0xb0); /* Enable Rx */ + out8 (SPU_BASE + spu_TxCmd, 0x9c); /* Enable Tx */ + out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */ + val = in8 (SPU_BASE + spu_RxBuff); /* Dummy read, to clear receiver */ + + return (0); +} + +void serial_setbrg (void) +{ + unsigned short br_reg; + + br_reg = ((((CONFIG_CPUCLOCK * 1000000) / 16) / gd->baudrate) - 1); + + out8 (SPU_BASE + spu_BRateDivl, (br_reg & 0x00ff)); /* Set baud rate divisor... */ + out8 (SPU_BASE + spu_BRateDivh, ((br_reg & 0xff00) >> 8)); /* ... */ +} + +void serial_putc (const char c) +{ + if (c == '\n') + serial_putc ('\r'); + + /* load status from handshake register */ + if (in8 (SPU_BASE + spu_Handshk_rc) != 00) + out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */ + + out8 (SPU_BASE + spu_TxBuff, c); /* Put char */ + + while ((in8 (SPU_BASE + spu_LineStat_rc) & 04) != 04) { + if (in8 (SPU_BASE + spu_Handshk_rc) != 00) + out8 (SPU_BASE + spu_Handshk_rc, 0xff); /* Clear Handshake */ + } +} + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int serial_getc () +{ + unsigned char status = 0; + + while (1) { + status = in8 (asyncLSRport1); + if ((status & asyncLSRDataReady) != 0x0) { + break; + } + if ((status & ( asyncLSRFramingError | + asyncLSROverrunError | + asyncLSRParityError | + asyncLSRBreakInterrupt )) != 0) { + (void) out8 (asyncLSRport1, + asyncLSRFramingError | + asyncLSROverrunError | + asyncLSRParityError | + asyncLSRBreakInterrupt ); + } + } + return (0x000000ff & (int) in8 (asyncRxBufferport1)); +} + +int serial_tstc () +{ + unsigned char status; + + status = in8 (asyncLSRport1); + if ((status & asyncLSRDataReady) != 0x0) { + return (1); + } + if ((status & ( asyncLSRFramingError | + asyncLSROverrunError | + asyncLSRParityError | + asyncLSRBreakInterrupt )) != 0) { + (void) out8 (asyncLSRport1, + asyncLSRFramingError | + asyncLSROverrunError | + asyncLSRParityError | + asyncLSRBreakInterrupt); + } + return 0; +} + +#endif /* CONFIG_IOP480 */ + +/*****************************************************************************/ +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP) || \ + defined(CONFIG_440) + +#if defined(CONFIG_440) +#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ + defined(CONFIG_440EPX) || defined(CONFIG_440GRX) +#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300 +#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400 +#else +#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200 +#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300 +#endif + +#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) +#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000600 +#endif + +#if defined(CONFIG_440GP) +#define CR0_MASK 0x3fff0000 +#define CR0_EXTCLK_ENA 0x00600000 +#define CR0_UDIV_POS 16 +#define UDIV_SUBTRACT 1 +#define UART0_SDR cntrl0 +#define MFREG(a, d) d = mfdcr(a) +#define MTREG(a, d) mtdcr(a, d) +#else /* #if defined(CONFIG_440GP) */ +/* all other 440 PPC's access clock divider via sdr register */ +#define CR0_MASK 0xdfffffff +#define CR0_EXTCLK_ENA 0x00800000 +#define CR0_UDIV_POS 0 +#define UDIV_SUBTRACT 0 +#define UART0_SDR sdr_uart0 +#define UART1_SDR sdr_uart1 +#if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \ + defined(CONFIG_440GR) || defined(CONFIG_440GRx) || \ + defined(CONFIG_440SP) || defined(CONFIG_440SPe) +#define UART2_SDR sdr_uart2 +#endif +#if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \ + defined(CONFIG_440GR) || defined(CONFIG_440GRx) +#define UART3_SDR sdr_uart3 +#endif +#define MFREG(a, d) mfsdr(a, d) +#define MTREG(a, d) mtsdr(a, d) +#endif /* #if defined(CONFIG_440GP) */ +#elif defined(CONFIG_405EP) +#define UART0_BASE 0xef600300 +#define UART1_BASE 0xef600400 +#define UCR0_MASK 0x0000007f +#define UCR1_MASK 0x00007f00 +#define UCR0_UDIV_POS 0 +#define UCR1_UDIV_POS 8 +#define UDIV_MAX 127 +#else /* CONFIG_405GP || CONFIG_405CR */ +#define UART0_BASE 0xef600300 +#define UART1_BASE 0xef600400 +#define CR0_MASK 0x00001fff +#define CR0_EXTCLK_ENA 0x000000c0 +#define CR0_UDIV_POS 1 +#define UDIV_MAX 32 +#endif + +/* using serial port 0 or 1 as U-Boot console ? */ +#if defined(CONFIG_UART1_CONSOLE) +#define ACTING_UART0_BASE UART1_BASE +#define ACTING_UART1_BASE UART0_BASE +#else +#define ACTING_UART0_BASE UART0_BASE +#define ACTING_UART1_BASE UART1_BASE +#endif + +#if defined(CONFIG_SERIAL_MULTI) +#define UART_BASE dev_base +#else +#define UART_BASE ACTING_UART0_BASE +#endif + +#if defined(CONFIG_405EP) && defined(CFG_EXT_SERIAL_CLOCK) +#error "External serial clock not supported on AMCC PPC405EP!" +#endif + +#define UART_RBR 0x00 +#define UART_THR 0x00 +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/*-----------------------------------------------------------------------------+ + | Line Status Register. + +-----------------------------------------------------------------------------*/ +/*#define asyncLSRport1 ACTING_UART0_BASE+0x05 */ +#define asyncLSRDataReady1 0x01 +#define asyncLSROverrunError1 0x02 +#define asyncLSRParityError1 0x04 +#define asyncLSRFramingError1 0x08 +#define asyncLSRBreakInterrupt1 0x10 +#define asyncLSRTxHoldEmpty1 0x20 +#define asyncLSRTxShiftEmpty1 0x40 +#define asyncLSRRxFifoError1 0x80 + +/*-----------------------------------------------------------------------------+ + | Miscellanies defines. + +-----------------------------------------------------------------------------*/ +/*#define asyncTxBufferport1 ACTING_UART0_BASE+0x00 */ +/*#define asyncRxBufferport1 ACTING_UART0_BASE+0x00 */ + +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO +/*-----------------------------------------------------------------------------+ + | Fifo + +-----------------------------------------------------------------------------*/ +typedef struct { + char *rx_buffer; + ulong rx_put; + ulong rx_get; +} serial_buffer_t; + +volatile static serial_buffer_t buf_info; +#endif + +#if defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLOCK) +static void serial_divs (int baudrate, unsigned long *pudiv, + unsigned short *pbdiv ) +{ + sys_info_t sysinfo; + unsigned long div; /* total divisor udiv * bdiv */ + unsigned long umin; /* minimum udiv */ + unsigned short diff; /* smallest diff */ + unsigned long udiv; /* best udiv */ + + unsigned short idiff; /* current diff */ + unsigned short ibdiv; /* current bdiv */ + unsigned long i; + unsigned long est; /* current estimate */ + + get_sys_info( &sysinfo ); + + udiv = 32; /* Assume lowest possible serial clk */ + div = sysinfo.freqPLB/(16*baudrate); /* total divisor */ + umin = sysinfo.pllOpbDiv<<1; /* 2 x OPB divisor */ + diff = 32; /* highest possible */ + + /* i is the test udiv value -- start with the largest + * possible (32) to minimize serial clock and constrain + * search to umin. + */ + for( i = 32; i > umin; i-- ){ + ibdiv = div/i; + est = i * ibdiv; + idiff = (est > div) ? (est-div) : (div-est); + if( idiff == 0 ){ + udiv = i; + break; /* can't do better */ + } + else if( idiff < diff ){ + udiv = i; /* best so far */ + diff = idiff; /* update lowest diff*/ + } + } + + *pudiv = udiv; + *pbdiv = div/udiv; + +} +#endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */ + +/* + * Minimal serial functions needed to use one of the SMC ports + * as serial console interface. + */ + +#if defined(CONFIG_440) +#if defined(CONFIG_SERIAL_MULTI) +int serial_init_dev (unsigned long dev_base) +#else +int serial_init(void) +#endif +{ + unsigned long reg; + unsigned long udiv; + unsigned short bdiv; + volatile char val; +#ifdef CFG_EXT_SERIAL_CLOCK + unsigned long tmp; +#endif + + MFREG(UART0_SDR, reg); + reg &= ~CR0_MASK; + +#ifdef CFG_EXT_SERIAL_CLOCK + reg |= CR0_EXTCLK_ENA; + udiv = 1; + tmp = gd->baudrate * 16; + bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp; +#else + /* For 440, the cpu clock is on divider chain A, UART on divider + * chain B ... so cpu clock is irrelevant. Get the "optimized" + * values that are subject to the 1/2 opb clock constraint + */ + serial_divs (gd->baudrate, &udiv, &bdiv); +#endif + + reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS; /* set the UART divisor */ + + /* + * Configure input clock to baudrate generator for all + * available serial ports here + */ + MTREG(UART0_SDR, reg); +#if defined(UART1_SDR) + MTREG(UART1_SDR, reg); +#endif +#if defined(UART2_SDR) + MTREG(UART2_SDR, reg); +#endif +#if defined(UART3_SDR) + MTREG(UART3_SDR, reg); +#endif + + out8(UART_BASE + UART_LCR, 0x80); /* set DLAB bit */ + out8(UART_BASE + UART_DLL, bdiv); /* set baudrate divisor */ + out8(UART_BASE + UART_DLM, bdiv >> 8); /* set baudrate divisor */ + out8(UART_BASE + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */ + out8(UART_BASE + UART_FCR, 0x00); /* disable FIFO */ + out8(UART_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */ + val = in8(UART_BASE + UART_LSR); /* clear line status */ + val = in8(UART_BASE + UART_RBR); /* read receive buffer */ + out8(UART_BASE + UART_SCR, 0x00); /* set scratchpad */ + out8(UART_BASE + UART_IER, 0x00); /* set interrupt enable reg */ + + return (0); +} + +#else /* !defined(CONFIG_440) */ + +#if defined(CONFIG_SERIAL_MULTI) +int serial_init_dev (unsigned long dev_base) +#else +int serial_init (void) +#endif +{ + unsigned long reg; + unsigned long tmp; + unsigned long clk; + unsigned long udiv; + unsigned short bdiv; + volatile char val; + +#ifdef CONFIG_405EP + reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK); + clk = gd->cpu_clk; + tmp = CFG_BASE_BAUD * 16; + udiv = (clk + tmp / 2) / tmp; + if (udiv > UDIV_MAX) /* max. n bits for udiv */ + udiv = UDIV_MAX; + reg |= (udiv) << UCR0_UDIV_POS; /* set the UART divisor */ + reg |= (udiv) << UCR1_UDIV_POS; /* set the UART divisor */ + mtdcr (cpc0_ucr, reg); +#else /* CONFIG_405EP */ + reg = mfdcr(cntrl0) & ~CR0_MASK; +#ifdef CFG_EXT_SERIAL_CLOCK + clk = CFG_EXT_SERIAL_CLOCK; + udiv = 1; + reg |= CR0_EXTCLK_ENA; +#else + clk = gd->cpu_clk; +#ifdef CFG_405_UART_ERRATA_59 + udiv = 31; /* Errata 59: stuck at 31 */ +#else + tmp = CFG_BASE_BAUD * 16; + udiv = (clk + tmp / 2) / tmp; + if (udiv > UDIV_MAX) /* max. n bits for udiv */ + udiv = UDIV_MAX; +#endif +#endif + reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */ + mtdcr (cntrl0, reg); +#endif /* CONFIG_405EP */ + + tmp = gd->baudrate * udiv * 16; + bdiv = (clk + tmp / 2) / tmp; + + out8(UART_BASE + UART_LCR, 0x80); /* set DLAB bit */ + out8(UART_BASE + UART_DLL, bdiv); /* set baudrate divisor */ + out8(UART_BASE + UART_DLM, bdiv >> 8); /* set baudrate divisor */ + out8(UART_BASE + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */ + out8(UART_BASE + UART_FCR, 0x00); /* disable FIFO */ + out8(UART_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */ + val = in8(UART_BASE + UART_LSR); /* clear line status */ + val = in8(UART_BASE + UART_RBR); /* read receive buffer */ + out8(UART_BASE + UART_SCR, 0x00); /* set scratchpad */ + out8(UART_BASE + UART_IER, 0x00); /* set interrupt enable reg */ + + return (0); +} + +#endif /* if defined(CONFIG_440) */ + +#if defined(CONFIG_SERIAL_MULTI) +void serial_setbrg_dev (unsigned long dev_base) +#else +void serial_setbrg (void) +#endif +{ +#if defined(CONFIG_SERIAL_MULTI) + serial_init_dev(dev_base); +#else + serial_init(); +#endif +} + +#if defined(CONFIG_SERIAL_MULTI) +void serial_putc_dev (unsigned long dev_base, const char c) +#else +void serial_putc (const char c) +#endif +{ + int i; + + if (c == '\n') +#if defined(CONFIG_SERIAL_MULTI) + serial_putc_dev (dev_base, '\r'); +#else + serial_putc ('\r'); +#endif + + /* check THRE bit, wait for transmiter available */ + for (i = 1; i < 3500; i++) { + if ((in8 (UART_BASE + UART_LSR) & 0x20) == 0x20) + break; + udelay (100); + } + out8 (UART_BASE + UART_THR, c); /* put character out */ +} + +#if defined(CONFIG_SERIAL_MULTI) +void serial_puts_dev (unsigned long dev_base, const char *s) +#else +void serial_puts (const char *s) +#endif +{ + while (*s) { +#if defined(CONFIG_SERIAL_MULTI) + serial_putc_dev (dev_base, *s++); +#else + serial_putc (*s++); +#endif + } +} + +#if defined(CONFIG_SERIAL_MULTI) +int serial_getc_dev (unsigned long dev_base) +#else +int serial_getc (void) +#endif +{ + unsigned char status = 0; + + while (1) { +#if defined(CONFIG_HW_WATCHDOG) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ +#endif /* CONFIG_HW_WATCHDOG */ + status = in8 (UART_BASE + UART_LSR); + if ((status & asyncLSRDataReady1) != 0x0) { + break; + } + if ((status & ( asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1 )) != 0) { + out8 (UART_BASE + UART_LSR, + asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1); + } + } + return (0x000000ff & (int) in8 (UART_BASE)); +} + +#if defined(CONFIG_SERIAL_MULTI) +int serial_tstc_dev (unsigned long dev_base) +#else +int serial_tstc (void) +#endif +{ + unsigned char status; + + status = in8 (UART_BASE + UART_LSR); + if ((status & asyncLSRDataReady1) != 0x0) { + return (1); + } + if ((status & ( asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1 )) != 0) { + out8 (UART_BASE + UART_LSR, + asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1); + } + return 0; +} + +#ifdef CONFIG_SERIAL_SOFTWARE_FIFO + +void serial_isr (void *arg) +{ + int space; + int c; + const int rx_get = buf_info.rx_get; + int rx_put = buf_info.rx_put; + + if (rx_get <= rx_put) { + space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get); + } else { + space = rx_get - rx_put; + } + while (serial_tstc_dev (ACTING_UART0_BASE)) { + c = serial_getc_dev (ACTING_UART0_BASE); + if (space) { + buf_info.rx_buffer[rx_put++] = c; + space--; + } + if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) + rx_put = 0; + if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) { + /* Stop flow by setting RTS inactive */ + out8 (ACTING_UART0_BASE + UART_MCR, + in8 (ACTING_UART0_BASE + UART_MCR) & (0xFF ^ 0x02)); + } + } + buf_info.rx_put = rx_put; +} + +void serial_buffered_init (void) +{ + serial_puts ("Switching to interrupt driven serial input mode.\n"); + buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO); + buf_info.rx_put = 0; + buf_info.rx_get = 0; + + if (in8 (ACTING_UART0_BASE + UART_MSR) & 0x10) { + serial_puts ("Check CTS signal present on serial port: OK.\n"); + } else { + serial_puts ("WARNING: CTS signal not present on serial port.\n"); + } + + irq_install_handler ( VECNUM_U0 /*UART0 */ /*int vec */ , + serial_isr /*interrupt_handler_t *handler */ , + (void *) &buf_info /*void *arg */ ); + + /* Enable "RX Data Available" Interrupt on UART */ + /* out8(ACTING_UART0_BASE + UART_IER, in8(ACTING_UART0_BASE + UART_IER) |0x01); */ + out8 (ACTING_UART0_BASE + UART_IER, 0x01); + /* Set DTR active */ + out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x01); + /* Start flow by setting RTS active */ + out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02); + /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */ + out8 (ACTING_UART0_BASE + UART_FCR, (1 << 6) | 1); +} + +void serial_buffered_putc (const char c) +{ + /* Wait for CTS */ +#if defined(CONFIG_HW_WATCHDOG) + while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10)) + WATCHDOG_RESET (); +#else + while (!(in8 (ACTING_UART0_BASE + UART_MSR) & 0x10)); +#endif + serial_putc (c); +} + +void serial_buffered_puts (const char *s) +{ + serial_puts (s); +} + +int serial_buffered_getc (void) +{ + int space; + int c; + int rx_get = buf_info.rx_get; + int rx_put; + +#if defined(CONFIG_HW_WATCHDOG) + while (rx_get == buf_info.rx_put) + WATCHDOG_RESET (); +#else + while (rx_get == buf_info.rx_put); +#endif + c = buf_info.rx_buffer[rx_get++]; + if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO) + rx_get = 0; + buf_info.rx_get = rx_get; + + rx_put = buf_info.rx_put; + if (rx_get <= rx_put) { + space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get); + } else { + space = rx_get - rx_put; + } + if (space > CONFIG_SERIAL_SOFTWARE_FIFO / 2) { + /* Start flow by setting RTS active */ + out8 (ACTING_UART0_BASE + UART_MCR, in8 (ACTING_UART0_BASE + UART_MCR) | 0x02); + } + + return c; +} + +int serial_buffered_tstc (void) +{ + return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0; +} + +#endif /* CONFIG_SERIAL_SOFTWARE_FIFO */ + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +/* + AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port + number 0 or number 1 + - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 : + configuration has been already done + - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 : + configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE +*/ +#if (CONFIG_KGDB_SER_INDEX & 2) +void kgdb_serial_init (void) +{ + volatile char val; + unsigned short br_reg; + + get_clocks (); + br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) + + 5) / 10; + /* + * Init onboard 16550 UART + */ + out8 (ACTING_UART1_BASE + UART_LCR, 0x80); /* set DLAB bit */ + out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set divisor for 9600 baud */ + out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8)); /* set divisor for 9600 baud */ + out8 (ACTING_UART1_BASE + UART_LCR, 0x03); /* line control 8 bits no parity */ + out8 (ACTING_UART1_BASE + UART_FCR, 0x00); /* disable FIFO */ + out8 (ACTING_UART1_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */ + val = in8 (ACTING_UART1_BASE + UART_LSR); /* clear line status */ + val = in8 (ACTING_UART1_BASE + UART_RBR); /* read receive buffer */ + out8 (ACTING_UART1_BASE + UART_SCR, 0x00); /* set scratchpad */ + out8 (ACTING_UART1_BASE + UART_IER, 0x00); /* set interrupt enable reg */ +} + +void putDebugChar (const char c) +{ + if (c == '\n') + serial_putc ('\r'); + + out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */ + + /* check THRE bit, wait for transfer done */ + while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20); +} + +void putDebugStr (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int getDebugChar (void) +{ + unsigned char status = 0; + + while (1) { + status = in8 (ACTING_UART1_BASE + UART_LSR); + if ((status & asyncLSRDataReady1) != 0x0) { + break; + } + if ((status & ( asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1 )) != 0) { + out8 (ACTING_UART1_BASE + UART_LSR, + asyncLSRFramingError1 | + asyncLSROverrunError1 | + asyncLSRParityError1 | + asyncLSRBreakInterrupt1); + } + } + return (0x000000ff & (int) in8 (ACTING_UART1_BASE)); +} + +void kgdb_interruptible (int yes) +{ + return; +} + +#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */ + +void kgdb_serial_init (void) +{ + serial_printf ("[on serial] "); +} + +void putDebugChar (int c) +{ + serial_putc (c); +} + +void putDebugStr (const char *str) +{ + serial_puts (str); +} + +int getDebugChar (void) +{ + return serial_getc (); +} + +void kgdb_interruptible (int yes) +{ + return; +} +#endif /* (CONFIG_KGDB_SER_INDEX & 2) */ +#endif /* CFG_CMD_KGDB */ + + +#if defined(CONFIG_SERIAL_MULTI) +int serial0_init(void) +{ + return (serial_init_dev(UART0_BASE)); +} + +int serial1_init(void) +{ + return (serial_init_dev(UART1_BASE)); +} +void serial0_setbrg (void) +{ + serial_setbrg_dev(UART0_BASE); +} +void serial1_setbrg (void) +{ + serial_setbrg_dev(UART1_BASE); +} + +void serial0_putc(const char c) +{ + serial_putc_dev(UART0_BASE,c); +} + +void serial1_putc(const char c) +{ + serial_putc_dev(UART1_BASE, c); +} +void serial0_puts(const char *s) +{ + serial_puts_dev(UART0_BASE, s); +} + +void serial1_puts(const char *s) +{ + serial_puts_dev(UART1_BASE, s); +} + +int serial0_getc(void) +{ + return(serial_getc_dev(UART0_BASE)); +} + +int serial1_getc(void) +{ + return(serial_getc_dev(UART1_BASE)); +} +int serial0_tstc(void) +{ + return (serial_tstc_dev(UART0_BASE)); +} + +int serial1_tstc(void) +{ + return (serial_tstc_dev(UART1_BASE)); +} + +struct serial_device serial0_device = +{ + "serial0", + "UART0", + serial0_init, + serial0_setbrg, + serial0_getc, + serial0_tstc, + serial0_putc, + serial0_puts, +}; + +struct serial_device serial1_device = +{ + "serial1", + "UART1", + serial1_init, + serial1_setbrg, + serial1_getc, + serial1_tstc, + serial1_putc, + serial1_puts, +}; +#endif /* CONFIG_SERIAL_MULTI */ + +#endif /* CONFIG_405GP || CONFIG_405CR */ diff --git a/drivers/serial/serial_pxa.c b/drivers/serial/serial_pxa.c new file mode 100644 index 0000000000..09e036db40 --- /dev/null +++ b/drivers/serial/serial_pxa.c @@ -0,0 +1,198 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> +#include <watchdog.h> +#include <asm/arch/pxa-regs.h> + +DECLARE_GLOBAL_DATA_PTR; + +void serial_setbrg (void) +{ + unsigned int quot = 0; + + if (gd->baudrate == 1200) + quot = 768; + else if (gd->baudrate == 9600) + quot = 96; + else if (gd->baudrate == 19200) + quot = 48; + else if (gd->baudrate == 38400) + quot = 24; + else if (gd->baudrate == 57600) + quot = 16; + else if (gd->baudrate == 115200) + quot = 8; + else + hang (); + +#ifdef CONFIG_FFUART +#ifdef CONFIG_CPU_MONAHANS + CKENA |= CKENA_22_FFUART; +#else + CKEN |= CKEN6_FFUART; +#endif /* CONFIG_CPU_MONAHANS */ + + FFIER = 0; /* Disable for now */ + FFFCR = FCR_TRFIFOE; /* Fifos enabled */ + + /* set baud rate */ + FFLCR = LCR_WLS0 | LCR_WLS1 | LCR_DLAB; + FFDLL = quot & 0xff; + FFDLH = quot >> 8; + FFLCR = LCR_WLS0 | LCR_WLS1; + + FFIER = IER_UUE; /* Enable FFUART */ + +#elif defined(CONFIG_BTUART) +#ifdef CONFIG_CPU_MONAHANS + CKENA |= CKENA_21_BTUART; +#else + CKEN |= CKEN7_BTUART; +#endif /* CONFIG_CPU_MONAHANS */ + + BTIER = 0; + BTFCR = FCR_TRFIFOE; /* Fifos enabled */ + + /* set baud rate */ + BTLCR = LCR_DLAB; + BTDLL = quot & 0xff; + BTDLH = quot >> 8; + BTLCR = LCR_WLS0 | LCR_WLS1; + + BTIER = IER_UUE; /* Enable BFUART */ + +#elif defined(CONFIG_STUART) +#ifdef CONFIG_CPU_MONAHANS + CKENA |= CKENA_23_STUART; +#else + CKEN |= CKEN5_STUART; +#endif /* CONFIG_CPU_MONAHANS */ + + STIER = 0; + STFCR = 0; + + /* set baud rate */ + STLCR = LCR_DLAB; + STDLL = quot & 0xff; + STDLH = quot >> 8; + STLCR = LCR_WLS0 | LCR_WLS1; + + STIER = IER_UUE; /* Enable STUART */ + +#else +#error "Bad: you didn't configure serial ..." +#endif +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ +#ifdef CONFIG_FFUART + /* wait for room in the tx FIFO on FFUART */ + while ((FFLSR & LSR_TEMT) == 0) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + FFTHR = c; +#elif defined(CONFIG_BTUART) + while ((BTLSR & LSR_TEMT ) == 0 ) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + BTTHR = c; +#elif defined(CONFIG_STUART) + while ((STLSR & LSR_TEMT ) == 0 ) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + STTHR = c; +#endif + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_tstc (void) +{ +#ifdef CONFIG_FFUART + return FFLSR & LSR_DR; +#elif defined(CONFIG_BTUART) + return BTLSR & LSR_DR; +#elif defined(CONFIG_STUART) + return STLSR & LSR_DR; +#endif +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ +#ifdef CONFIG_FFUART + while (!(FFLSR & LSR_DR)) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + return (char) FFRBR & 0xff; +#elif defined(CONFIG_BTUART) + while (!(BTLSR & LSR_DR)) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + return (char) BTRBR & 0xff; +#elif defined(CONFIG_STUART) + while (!(STLSR & LSR_DR)) + WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + return (char) STRBR & 0xff; +#endif +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c new file mode 100644 index 0000000000..52b07ad286 --- /dev/null +++ b/drivers/serial/serial_s3c24x0.c @@ -0,0 +1,166 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * 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> +#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) + +#if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB) +#include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +#include <s3c2410.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SERIAL1 +#define UART_NR S3C24X0_UART0 + +#elif defined(CONFIG_SERIAL2) +# if defined(CONFIG_TRAB) +# error "TRAB supports only CONFIG_SERIAL1" +# endif +#define UART_NR S3C24X0_UART1 + +#elif defined(CONFIG_SERIAL3) +# if defined(CONFIG_TRAB) +# #error "TRAB supports only CONFIG_SERIAL1" +# endif +#define UART_NR S3C24X0_UART2 + +#else +#error "Bad: you didn't configure serial ..." +#endif + +void serial_setbrg (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + int i; + unsigned int reg = 0; + + /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ + reg = get_PCLK() / (16 * gd->baudrate) - 1; + + /* FIFO enable, Tx/Rx FIFO clear */ + uart->UFCON = 0x07; + uart->UMCON = 0x0; + /* Normal,No parity,1 stop,8 bit */ + uart->ULCON = 0x3; + /* + * tx=level,rx=edge,disable timeout int.,enable rx error int., + * normal,interrupt or polling + */ + uart->UCON = 0x245; + uart->UBRDIV = reg; + +#ifdef CONFIG_HWFLOW + uart->UMCON = 0x1; /* RTS up */ +#endif + for (i = 0; i < 100; i++); +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + /* wait for character to arrive */ + while (!(uart->UTRSTAT & 0x1)); + + return uart->URXH & 0xff; +} + +#ifdef CONFIG_HWFLOW +static int hwflow = 0; /* turned off by default */ +int hwflow_onoff(int on) +{ + switch(on) { + case 0: + default: + break; /* return current */ + case 1: + hwflow = 1; /* turn on */ + break; + case -1: + hwflow = 0; /* turn off */ + break; + } + return hwflow; +} +#endif + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + /* wait for room in the tx FIFO */ + while (!(uart->UTRSTAT & 0x2)); + +#ifdef CONFIG_HWFLOW + /* Wait for CTS up */ + while(hwflow && !(uart->UMSTAT & 0x1)) + ; +#endif + + uart->UTXH = c; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); +} + +/* + * Test whether a character is in the RX buffer + */ +int serial_tstc (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + return uart->UTRSTAT & 0x1; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +#endif /* defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) */ diff --git a/drivers/serial/serial_s3c44b0.c b/drivers/serial/serial_s3c44b0.c new file mode 100644 index 0000000000..95d0266c6c --- /dev/null +++ b/drivers/serial/serial_s3c44b0.c @@ -0,0 +1,218 @@ +/* + * (C) Copyright 2004 + * DAVE Srl + * http://www.dave-tech.it + * http://www.wawnet.biz + * mailto:info@wawnet.biz + * + * (C) Copyright 2002-2004 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> +#include <asm/hardware.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* flush serial input queue. returns 0 on success or negative error + * number otherwise + */ +static int serial_flush_input(void) +{ + volatile u32 tmp; + + /* keep on reading as long as the receiver is not empty */ + while(UTRSTAT0&0x01) { + tmp = REGB(URXH0); + } + + return 0; +} + + +/* flush output queue. returns 0 on success or negative error number + * otherwise + */ +static int serial_flush_output(void) +{ + /* wait until the transmitter is no longer busy */ + while(!(UTRSTAT0 & 0x02)) { + } + + return 0; +} + + +void serial_setbrg (void) +{ + u32 divisor = 0; + + /* get correct divisor */ + switch(gd->baudrate) { + + case 1200: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 3124; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 3905; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif + break; + + case 9600: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 390; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 487; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif + break; + + case 19200: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 194; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 243; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif + break; + + case 38400: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 97; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 121; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif /* break; */ + + case 57600: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 64; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 80; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif /* break; */ + + case 115200: +#if CONFIG_S3C44B0_CLOCK_SPEED==66 + divisor = 32; +#elif CONFIG_S3C44B0_CLOCK_SPEED==75 + divisor = 40; +#else +# error CONFIG_S3C44B0_CLOCK_SPEED undefined +#endif /* break; */ + } + + serial_flush_output(); + serial_flush_input(); + UFCON0 = 0x0; + ULCON0 = 0x03; + UCON0 = 0x05; + UBRDIV0 = divisor; + + UFCON1 = 0x0; + ULCON1 = 0x03; + UCON1 = 0x05; + UBRDIV1 = divisor; + + for(divisor=0; divisor<100; divisor++) { + /* NOP */ + } +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ + /* wait for room in the transmit FIFO */ + while(!(UTRSTAT0 & 0x02)); + + UTXH0 = (unsigned char)c; + + /* + to be polite with serial console add a line feed + to the carriage return character + */ + if (c=='\n') + serial_putc('\r'); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_tstc (void) +{ + return (UTRSTAT0 & 0x01); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ + int rv; + + for(;;) { + rv = serial_tstc(); + + if(rv > 0) + return URXH0; + } +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} diff --git a/drivers/serial/serial_sa1100.c b/drivers/serial/serial_sa1100.c new file mode 100644 index 0000000000..5d1887580d --- /dev/null +++ b/drivers/serial/serial_sa1100.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * 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> +#include <SA-1100.h> + +DECLARE_GLOBAL_DATA_PTR; + +void serial_setbrg (void) +{ + unsigned int reg = 0; + + if (gd->baudrate == 1200) + reg = 191; + else if (gd->baudrate == 9600) + reg = 23; + else if (gd->baudrate == 19200) + reg = 11; + else if (gd->baudrate == 38400) + reg = 5; + else if (gd->baudrate == 57600) + reg = 3; + else if (gd->baudrate == 115200) + reg = 1; + else + hang (); + +#ifdef CONFIG_SERIAL1 + /* SA1110 uart function */ + Ser1SDCR0 |= SDCR0_SUS; + + /* Wait until port is ready ... */ + while(Ser1UTSR1 & UTSR1_TBY) {} + + /* init serial serial 1 */ + Ser1UTCR3 = 0x00; + Ser1UTSR0 = 0xff; + Ser1UTCR0 = ( UTCR0_1StpBit | UTCR0_8BitData ); + Ser1UTCR1 = 0; + Ser1UTCR2 = (u32)reg; + Ser1UTCR3 = ( UTCR3_RXE | UTCR3_TXE ); +#elif defined(CONFIG_SERIAL3) + /* Wait until port is ready ... */ + while (Ser3UTSR1 & UTSR1_TBY) { + } + + /* init serial serial 3 */ + Ser3UTCR3 = 0x00; + Ser3UTSR0 = 0xff; + Ser3UTCR0 = (UTCR0_1StpBit | UTCR0_8BitData); + Ser3UTCR1 = 0; + Ser3UTCR2 = (u32) reg; + Ser3UTCR3 = (UTCR3_RXE | UTCR3_TXE); +#else +#error "Bad: you didn't configured serial ..." +#endif +} + + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int serial_init (void) +{ + serial_setbrg (); + + return (0); +} + + +/* + * Output a single byte to the serial port. + */ +void serial_putc (const char c) +{ +#ifdef CONFIG_SERIAL1 + /* wait for room in the tx FIFO on SERIAL1 */ + while ((Ser1UTSR0 & UTSR0_TFS) == 0); + + Ser1UTDR = c; +#elif defined(CONFIG_SERIAL3) + /* wait for room in the tx FIFO on SERIAL3 */ + while ((Ser3UTSR0 & UTSR0_TFS) == 0); + + Ser3UTDR = c; +#endif + + /* If \n, also do \r */ + if (c == '\n') + serial_putc ('\r'); +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_tstc (void) +{ +#ifdef CONFIG_SERIAL1 + return Ser1UTSR1 & UTSR1_RNE; +#elif defined(CONFIG_SERIAL3) + return Ser3UTSR1 & UTSR1_RNE; +#endif +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc (void) +{ +#ifdef CONFIG_SERIAL1 + while (!(Ser1UTSR1 & UTSR1_RNE)); + + return (char) Ser1UTDR & 0xff; +#elif defined(CONFIG_SERIAL3) + while (!(Ser3UTSR1 & UTSR1_RNE)); + + return (char) Ser3UTDR & 0xff; +#endif +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} |