Commit 0cf0c2cc authored by David Woodhouse's avatar David Woodhouse

Merge

parents 9a85e04e 912c5dae
#
# MPC8260 Communication options
# CPM2 Communication options
#
menu "MPC8260 CPM Options"
depends on 8260
config SCC_CONSOLE
bool "Enable SCC Console"
menu "CPM2 Options"
depends on CPM2
config SCC_ENET
bool "CPM SCC Ethernet"
......@@ -24,19 +21,19 @@ config FCC1_ENET
bool "Ethernet on FCC1"
depends on FEC_ENET
help
Use MPC8260 fast Ethernet controller 1 to drive Ethernet (default).
Use CPM2 fast Ethernet controller 1 to drive Ethernet (default).
config FCC2_ENET
bool "Ethernet on FCC2"
depends on FEC_ENET
help
Use MPC8260 fast Ethernet controller 2 to drive Ethernet.
Use CPM2 fast Ethernet controller 2 to drive Ethernet.
config FCC3_ENET
bool "Ethernet on FCC3"
depends on FEC_ENET
help
Use MPC8260 fast Ethernet controller 3 to drive Ethernet.
Use CPM2 fast Ethernet controller 3 to drive Ethernet.
config USE_MDIO
bool "Use MDIO for PHY configuration"
......
#
# Makefile for the linux MPC8xx ppc-specific parts of comm processor
# Makefile for the linux ppc-specific parts of comm processor (v2)
#
obj-y := commproc.o uart.o
obj-$(CONFIG_FEC_ENET) += fcc_enet.o
obj-$(CONFIG_SCC_ENET) += enet.o
......@@ -40,12 +40,12 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/pgtable.h>
#include <asm/mpc8260.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/cpm_8260.h>
#include <asm/cpm2.h>
#include <asm/irq.h>
/*
......@@ -376,7 +376,7 @@ scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
}
if (must_restart) {
volatile cpm8260_t *cp;
volatile cpm_cpm2_t *cp;
/* Some transmit errors cause the transmitter to shut
* down. We now issue a restart transmit. Since the
......@@ -552,10 +552,10 @@ static void set_multicast_list(struct net_device *dev)
/* Log any net taps. */
printk("%s: Promiscuous mode enabled.\n", dev->name);
cep->sccp->scc_pmsr |= SCC_PSMR_PRO;
cep->sccp->scc_psmr |= SCC_PSMR_PRO;
} else {
cep->sccp->scc_pmsr &= ~SCC_PSMR_PRO;
cep->sccp->scc_psmr &= ~SCC_PSMR_PRO;
if (dev->flags & IFF_ALLMULTI) {
/* Catch all multicast addresses, so set the
......@@ -617,15 +617,15 @@ static int __init scc_enet_init(void)
unsigned long mem_addr;
bd_t *bd;
volatile cbd_t *bdp;
volatile cpm8260_t *cp;
volatile cpm_cpm2_t *cp;
volatile scc_t *sccp;
volatile scc_enet_t *ep;
volatile immap_t *immap;
volatile iop8260_t *io;
volatile cpm2_map_t *immap;
volatile iop_cpm2_t *io;
cp = cpmp; /* Get pointer to Communication Processor */
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */
io = &immap->im_ioport;
bd = (bd_t *)__res;
......@@ -680,11 +680,11 @@ static int __init scc_enet_init(void)
* These are relative offsets in the DP ram address space.
* Initialize base addresses for the buffer descriptors.
*/
i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
i = cpm2_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
ep->sen_genscc.scc_rbase = i;
cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i];
i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
i = cpm2_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
ep->sen_genscc.scc_tbase = i;
cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i];
......@@ -820,7 +820,7 @@ static int __init scc_enet_init(void)
/* Set processing mode. Use Ethernet CRC, catch broadcast, and
* start frame search 22 bit times after RENA.
*/
sccp->scc_pmsr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
sccp->scc_psmr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
/* It is now OK to enable the Ethernet transmitter.
* Unfortunately, there are board implementation differences here.
......
......@@ -35,13 +35,13 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/pgtable.h>
#include <asm/mpc8260.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/cpm_8260.h>
#include <asm/cpm2.h>
/* The transmitter timeout
*/
......@@ -159,20 +159,23 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER)
#ifdef CONFIG_SBC82xx
/* rx is clk9, tx is clk10
*/
/* rx is clk9, tx is clk10 */
#define PC_F1RXCLK ((uint)0x00000100)
#define PC_F1TXCLK ((uint)0x00000200)
#define CMX1_CLK_ROUTE ((uint)0x25000000)
#define CMX1_CLK_MASK ((uint)0xff000000)
#else
/* CLK12 is receive, CLK11 is transmit. These are board specific.
*/
#elif defined(CONFIG_ADS8272)
#define PC_F1RXCLK ((uint)0x00000400)
#define PC_F1TXCLK ((uint)0x00000200)
#define CMX1_CLK_ROUTE ((uint)0x36000000)
#define CMX1_CLK_MASK ((uint)0xff000000)
#else /* other boards */
/* CLK12 is receive, CLK11 is transmit. These are board specific. */
#define PC_F1RXCLK ((uint)0x00000800)
#define PC_F1TXCLK ((uint)0x00000400)
#define CMX1_CLK_ROUTE ((uint)0x3e000000)
#define CMX1_CLK_MASK ((uint)0xff000000)
#endif /* !CONFIG_SBC82xx */
#endif
/* I/O Pin assignment for FCC2. I don't yet know the best way to do this,
* but there is little variation among the choices.
......@@ -193,10 +196,17 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
/* CLK13 is receive, CLK14 is transmit. These are board dependent.
*/
#ifdef CONFIG_ADS8272
#define PC_F2RXCLK ((uint)0x00004000)
#define PC_F2TXCLK ((uint)0x00008000)
#define CMX2_CLK_ROUTE ((uint)0x00370000)
#define CMX2_CLK_MASK ((uint)0x00ff0000)
#else
#define PC_F2RXCLK ((uint)0x00001000)
#define PC_F2TXCLK ((uint)0x00002000)
#define CMX2_CLK_ROUTE ((uint)0x00250000)
#define CMX2_CLK_MASK ((uint)0x00ff0000)
#endif
/* I/O Pin assignment for FCC3. I don't yet know the best way to do this,
* but there is little variation among the choices.
......@@ -228,6 +238,9 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
/* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */
#define PC_MDIO ((uint)0x00000002)
#define PC_MDCK ((uint)0x00000001)
#elif defined(CONFIG_ADS8272)
#define PC_MDIO ((uint)0x00002000)
#define PC_MDCK ((uint)0x00001000)
#else
#define PC_MDIO ((uint)0x00000004)
#define PC_MDCK ((uint)0x00000020)
......@@ -255,7 +268,7 @@ static fcc_info_t fcc_ports[] = {
#ifdef CONFIG_FCC1_ENET
{ 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,
(PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK,
# if defined(CONFIG_TQM8260)
# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
PC_MDIO, PC_MDCK },
# else
0x00000004, 0x00000100 },
......@@ -264,7 +277,7 @@ static fcc_info_t fcc_ports[] = {
#ifdef CONFIG_FCC2_ENET
{ 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,
(PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK,
# if defined(CONFIG_TQM8260)
# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
PC_MDIO, PC_MDCK },
# elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260)
0x00400000, 0x00200000 },
......@@ -275,7 +288,7 @@ static fcc_info_t fcc_ports[] = {
#ifdef CONFIG_FCC3_ENET
{ 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,
(PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK,
# if defined(CONFIG_TQM8260)
# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
PC_MDIO, PC_MDCK },
# else
0x00000001, 0x00000040 },
......@@ -331,12 +344,12 @@ struct fcc_enet_private {
};
static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
volatile immap_t *immap);
volatile cpm2_map_t *immap);
static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev);
static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
volatile immap_t *immap);
static void init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,
volatile cpm2_map_t *immap);
static void init_fcc_param(fcc_info_t *fip, struct net_device *dev,
volatile immap_t *immap);
volatile cpm2_map_t *immap);
#ifdef CONFIG_USE_MDIO
static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *));
......@@ -586,7 +599,7 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
}
if (must_restart) {
volatile cpm8260_t *cp;
volatile cpm_cpm2_t *cp;
/* Some transmit errors cause the transmitter to shut
* down. We now issue a restart transmit. Since the
......@@ -1052,6 +1065,75 @@ static phy_info_t phy_info_qs6612 = {
#endif /* CONFIG_FEC_QS6612 */
/* ------------------------------------------------------------------------- */
/* The Davicom DM9131 is used on the HYMOD board */
#ifdef CONFIG_FCC_DM9131
/* register definitions */
#define MII_DM9131_ACR 16 /* Aux. Config Register */
#define MII_DM9131_ACSR 17 /* Aux. Config/Status Register */
#define MII_DM9131_10TCSR 18 /* 10BaseT Config/Status Reg. */
#define MII_DM9131_INTR 21 /* Interrupt Register */
#define MII_DM9131_RECR 22 /* Receive Error Counter Reg. */
#define MII_DM9131_DISCR 23 /* Disconnect Counter Register */
static void mii_parse_dm9131_acsr(uint mii_reg, struct net_device *dev)
{
volatile struct fcc_enet_private *fep = dev->priv;
uint s = fep->phy_status;
s &= ~(PHY_STAT_SPMASK);
switch ((mii_reg >> 12) & 0xf) {
case 1: s |= PHY_STAT_10HDX; break;
case 2: s |= PHY_STAT_10FDX; break;
case 4: s |= PHY_STAT_100HDX; break;
case 8: s |= PHY_STAT_100FDX; break;
}
fep->phy_status = s;
}
static phy_info_t phy_info_dm9131 = {
0x00181b80,
"DM9131",
(const phy_cmd_t []) { /* config */
/* parse cr and anar to get some info */
{ mk_mii_read(MII_REG_CR), mii_parse_cr },
{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
{ mk_mii_end, }
},
(const phy_cmd_t []) { /* startup - enable interrupts */
{ mk_mii_write(MII_DM9131_INTR, 0x0002), NULL },
{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
{ mk_mii_end, }
},
(const phy_cmd_t []) { /* ack_int */
/* we need to read INTR, SR and ANER to acknowledge */
{ mk_mii_read(MII_DM9131_INTR), NULL },
{ mk_mii_read(MII_REG_SR), mii_parse_sr },
{ mk_mii_read(MII_REG_ANER), NULL },
/* read acsr to get info */
{ mk_mii_read(MII_DM9131_ACSR), mii_parse_dm9131_acsr },
{ mk_mii_end, }
},
(const phy_cmd_t []) { /* shutdown - disable interrupts */
{ mk_mii_write(MII_DM9131_INTR, 0x0f00), NULL },
{ mk_mii_end, }
},
};
#endif /* CONFIG_FEC_DM9131 */
static phy_info_t *phy_info[] = {
#ifdef CONFIG_FCC_LXT970
......@@ -1064,7 +1146,11 @@ static phy_info_t *phy_info[] = {
#ifdef CONFIG_FCC_QS6612
&phy_info_qs6612,
#endif /* CONFIG_FEC_LXT971 */
#endif /* CONFIG_FEC_QS6612 */
#ifdef CONFIG_FCC_DM9131
&phy_info_dm9131,
#endif /* CONFIG_FEC_DM9131 */
NULL
};
......@@ -1361,10 +1447,10 @@ static int __init fec_enet_init(void)
struct fcc_enet_private *cep;
fcc_info_t *fip;
int i, np, err;
volatile immap_t *immap;
volatile iop8260_t *io;
volatile cpm2_map_t *immap;
volatile iop_cpm2_t *io;
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */
io = &immap->im_ioport;
np = sizeof(fcc_ports) / sizeof(fcc_info_t);
......@@ -1431,7 +1517,7 @@ module_init(fec_enet_init);
*/
static void __init
init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
volatile immap_t *immap)
volatile cpm2_map_t *immap)
{
volatile fcc_enet_t *ep;
volatile fcc_t *fccp;
......@@ -1454,8 +1540,8 @@ init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
/* Initialize the I/O pins for the FCC Ethernet.
*/
static void __init
init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
volatile immap_t *immap)
init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,
volatile cpm2_map_t *immap)
{
/* FCC1 pins are on port A/C. FCC2/3 are port B/C.
......@@ -1513,7 +1599,7 @@ init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
static void __init
init_fcc_param(fcc_info_t *fip, struct net_device *dev,
volatile immap_t *immap)
volatile cpm2_map_t *immap)
{
unsigned char *eap;
unsigned long mem_addr;
......@@ -1522,7 +1608,7 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
struct fcc_enet_private *cep;
volatile fcc_enet_t *ep;
volatile cbd_t *bdp;
volatile cpm8260_t *cp;
volatile cpm_cpm2_t *cp;
cep = (struct fcc_enet_private *)(dev->priv);
ep = cep->ep;
......@@ -1544,17 +1630,17 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
* work with the data cache enabled, so I allocate from the
* main memory instead.
*/
i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
i = cpm2_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i];
cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i];
i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
i = cpm2_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i];
cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i];
#else
cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
cep->rx_bd_base = (cbd_t *)cpm2_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base);
cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
cep->tx_bd_base = (cbd_t *)cpm2_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base);
#endif
......@@ -1773,11 +1859,11 @@ init_fcc_startup(fcc_info_t *fip, struct net_device *dev)
*/
fccp->fcc_fpsmr = FCC_PSMR_ENCRC;
#ifdef CONFIG_ADS8260
#ifdef CONFIG_PQ2ADS
/* Enable the PHY.
*/
ads_csr_addr[1] |= BCSR1_FETH_RST; /* Remove reset */
ads_csr_addr[1] &= ~BCSR1_FETHIEN; /* Enable */
*(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN;
*(volatile uint *)(BCSR_ADDR + 4) |= BCSR1_FETH_RST;
#endif
#if defined(CONFIG_USE_MDIO) || defined(CONFIG_TQM8260)
......@@ -1817,10 +1903,10 @@ mii_send_receive(fcc_info_t *fip, uint cmd)
{
uint retval;
int read_op, i, off;
volatile immap_t *immap;
volatile iop8260_t *io;
volatile cpm2_map_t *immap;
volatile iop_cpm2_t *io;
immap = (immap_t *)IMAP_ADDR;
immap = (cpm2_map_t *)CPM_MAP_ADDR;
io = &immap->im_ioport;
io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);
......
/*
* UART driver for MPC8260 CPM SCC or SMC
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
* Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com)
* 2.3.99 updates
* Copyright (c) 2002 Allen Curtis, Ones and Zeros, Inc. (acurtis@onz.com)
* 2.5.50 updates
* Fix the console driver to be registered with initcalls and some minor fixup
* for 2.6.2, by Petter Larsen, moreCom as (petter.larsen@morecom.no) and
* Miguel Valero, AxxessIT ASA (miguel.valero@axxessit.no)
*
* I used the 8xx uart.c driver as the framework for this driver.
* The original code was written for the EST8260 board. I tried to make
* it generic, but there may be some assumptions in the structures that
* have to be fixed later.
*
* The 8xx and 8260 are similar, but not identical. Over time we
* could probably merge these two drivers.
* To save porting time, I did not bother to change any object names
* that are not accessed outside of this file.
* It still needs lots of work........When it was easy, I included code
* to support the SCCs.
* Only the SCCs support modem control, so that is not complete either.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/immap_8260.h>
#include <asm/mpc8260.h>
#include <asm/cpm_8260.h>
#include <asm/irq.h>
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#endif
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
/* SCC Console configuration. Not quite finished. The SCC_CONSOLE
* should be the number of the SCC to use, but only SCC1 will
* work at this time.
*/
#ifdef CONFIG_SCC_CONSOLE
#define SCC_CONSOLE 1
#endif
/* this defines the index into rs_table for the port to use
*/
#ifndef CONFIG_SERIAL_CONSOLE_PORT
#define CONFIG_SERIAL_CONSOLE_PORT 0
#endif
#endif
#define CONFIG_SERIAL_CONSOLE_PORT 0
#define TX_WAKEUP ASYNC_SHARE_IRQ
static char *serial_name = "CPM UART driver";
static char *serial_version = "0.02";
static struct tty_driver *serial_driver;
static int __init serial_console_setup( struct console *co, char *options);
static void serial_console_write(struct console *c, const char *s,
unsigned count);
static struct tty_driver *serial_console_device(struct console *c, int *index);
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
static unsigned long break_pressed; /* break, really ... */
#endif
/*
* Serial driver configuration section. Here are the various options:
*/
#define SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
#define _INLINE_ inline
#define DBG_CNT(s)
/* We overload some of the items in the data structure to meet our
* needs. For example, the port address is the CPM parameter ram
* offset for the SCC or SMC. The maximum number of ports is 4 SCCs and
* 2 SMCs. The "hub6" field is used to indicate the channel number, with
* 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs.
* Since these ports are so versatile, I don't yet have a strategy for
* their management. For example, SCC1 is used for Ethernet. Right
* now, just don't put them in the table. Of course, right now I just
* want the SMC to work as a uart :-)..
* The "type" field is currently set to 0, for PORT_UNKNOWN. It is
* not currently used. I should probably use it to indicate the port
* type of CMS or SCC.
* The SMCs do not support any modem control signals.
*/
#define smc_scc_num hub6
/* The choice of serial port to use for KGDB. If the system has
* two ports, you can use one for console and one for KGDB (which
* doesn't make sense to me, but people asked for it).
*/
#ifdef CONFIG_KGDB_TTYS1
#define KGDB_SER_IDX 1 /* SCC2/SMC2 */
#else
#define KGDB_SER_IDX 0 /* SCC1/SMC1 */
#endif
#ifndef SCC_CONSOLE
/* SMC2 is sometimes used for low performance TDM interfaces. Define
* this as 1 if you want SMC2 as a serial port UART managed by this driver.
* Define this as 0 if you wish to use SMC2 for something else.
*/
#define USE_SMC2 1
/* Define SCC to ttySx mapping.
*/
#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */
/* Define which SCC is the first one to use for a serial port. These
* are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
* for Ethernet, and the first available SCC for serial UART is SCC2.
* NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and
* interrupt vectors in the table below to match.
*/
#define SCC_IDX_BASE 1 /* table index */
static struct serial_state rs_table[] = {
/* UART CLK PORT IRQ FLAGS NUM */
{ 0, 0, PROFF_SMC1, SIU_INT_SMC1, 0, 0 }, /* SMC1 ttyS0 */
#ifdef USE_SMC2
{ 0, 0, PROFF_SMC2, SIU_INT_SMC2, 0, 1 }, /* SMC2 ttyS1 */
#endif
#ifndef CONFIG_SCC1_ENET
{ 0, 0, PROFF_SCC1, SIU_INT_SCC1, 0, SCC_NUM_BASE}, /* SCC1 ttyS2 */
#endif
#ifndef CONFIG_SCC2_ENET
{ 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE + 1}, /* SCC2 ttyS3 */
#endif
};
#else /* SCC_CONSOLE */
#define SCC_NUM_BASE 0 /* SCC base tty "number" */
#define SCC_IDX_BASE 0 /* table index */
static struct serial_state rs_table[] = {
/* UART CLK PORT IRQ FLAGS NUM */
{ 0, 0, PROFF_SCC1, SIU_INT_SCC1, 0, SCC_NUM_BASE}, /* SCC1 ttyS2 */
{ 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE + 1}, /* SCC2 ttyS3 */
};
#endif /* SCC_CONSOLE */
#define PORT_NUM(P) (((P) < (SCC_NUM_BASE)) ? (P) : (P)-(SCC_NUM_BASE))
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
/* The number of buffer descriptors and their sizes.
*/
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
#define TX_NUM_FIFO 4
#define TX_BUF_SIZE 32
/* The async_struct in serial.h does not really give us what we
* need, so define our own here.
*/
typedef struct serial_info {
int magic;
int flags;
struct serial_state *state;
struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int timeout;
int line;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int blocked_open; /* # of blocked opens */
struct work_struct tqueue;
struct work_struct tqueue_hangup;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
/* CPM Buffer Descriptor pointers.
*/
cbd_t *rx_bd_base;
cbd_t *rx_cur;
cbd_t *tx_bd_base;
cbd_t *tx_cur;
} ser_info_t;
static struct console sercons = {
.name = "ttyS",
.write = serial_console_write,
.device = serial_console_device,
.setup = serial_console_setup,
.flags = CON_PRINTBUFFER,
.index = CONFIG_SERIAL_CONSOLE_PORT,
};
static void change_speed(ser_info_t *info);
static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout);
static inline int serial_paranoia_check(ser_info_t *info,
char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
"Warning: bad magic number for serial struct (%s) in %s\n";
static const char *badinfo =
"Warning: null async_struct for (%s) in %s\n";
if (!info) {
printk(badinfo, name, routine);
return 1;
}
if (info->magic != SERIAL_MAGIC) {
printk(badmagic, name, routine);
return 1;
}
#endif
return 0;
}
/*
* This is used to figure out the divisor speeds and the timeouts,
* indexed by the termio value. The generic CPM functions are responsible
* for setting and assigning baud rate generators for us.
*/
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
* This routines are called before setting or resetting tty->stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
static void rs_8xx_stop(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
int idx;
unsigned long flags;
volatile scc_t *sccp;
volatile smc_t *smcp;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
save_flags(flags); cli();
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
smcp->smc_smcm &= ~SMCM_TX;
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
sccp->scc_sccm &= ~UART_SCCM_TX;
}
restore_flags(flags);
}
static void rs_8xx_start(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
int idx;
unsigned long flags;
volatile scc_t *sccp;
volatile smc_t *smcp;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
save_flags(flags); cli();
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
smcp->smc_smcm |= SMCM_TX;
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
sccp->scc_sccm |= UART_SCCM_TX;
}
restore_flags(flags);
}
/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
* subroutines are declared as inline and are folded into
* rs_interrupt(). They were separated out for readability's sake.
*
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
*
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
*
* - Ted Ts'o (tytso@mit.edu), 7-Mar-93
* -----------------------------------------------------------------------
*/
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
static _INLINE_ void rs_sched_event(ser_info_t *info,
int event)
{
info->event |= 1 << event;
schedule_work(&info->tqueue);
}
static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs)
{
struct tty_struct *tty = info->tty;
unsigned char ch, *cp;
/*int ignored = 0;*/
int i;
ushort status;
struct async_icount *icount;
volatile cbd_t *bdp;
icount = &info->state->icount;
/* Just loop through the closed BDs and copy the characters into
* the buffer.
*/
bdp = info->rx_cur;
for (;;) {
if (bdp->cbd_sc & BD_SC_EMPTY) /* If this one is empty */
break; /* we are all done */
/* The read status mask tell us what we should do with
* incoming characters, especially if errors occur.
* One special case is the use of BD_SC_EMPTY. If
* this is not set, we are supposed to be ignoring
* inputs. In this case, just mark the buffer empty and
* continue.
if (!(info->read_status_mask & BD_SC_EMPTY)) {
bdp->cbd_sc |= BD_SC_EMPTY;
bdp->cbd_sc &=
~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = info->rx_bd_base;
else
bdp++;
continue;
}
*/
/* Get the number of characters and the buffer pointer.
*/
i = bdp->cbd_datlen;
cp = (unsigned char *)__va(bdp->cbd_bufaddr);
status = bdp->cbd_sc;
#ifdef CONFIG_KGDB
if (info->state->smc_scc_num == KGDB_SER_IDX) {
if (*cp == 0x03 || *cp == '$')
breakpoint();
return;
}
#endif
/* Check to see if there is room in the tty buffer for
* the characters in our BD buffer. If not, we exit
* now, leaving the BD with the characters. We'll pick
* them up again on the next receive interrupt (which could
* be a timeout).
*/
if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE)
break;
while (i-- > 0) {
ch = *cp++;
*tty->flip.char_buf_ptr = ch;
icount->rx++;
#ifdef SERIAL_DEBUG_INTR
printk("DR%02x:%02x...", ch, *status);
#endif
*tty->flip.flag_buf_ptr = 0;
if (status & (BD_SC_BR | BD_SC_FR |
BD_SC_PR | BD_SC_OV)) {
/*
* For statistics only
*/
if (status & BD_SC_BR)
icount->brk++;
else if (status & BD_SC_PR)
icount->parity++;
else if (status & BD_SC_FR)
icount->frame++;
if (status & BD_SC_OV)
icount->overrun++;
/*
* Now check to see if character should be
* ignored, and mask off conditions which
* should be ignored.
if (status & info->ignore_status_mask) {
if (++ignored > 100)
break;
continue;
}
*/
status &= info->read_status_mask;
if (status & (BD_SC_BR)) {
#ifdef SERIAL_DEBUG_INTR
printk("handling break....");
#endif
*tty->flip.flag_buf_ptr = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (status & BD_SC_PR)
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (status & BD_SC_FR)
*tty->flip.flag_buf_ptr = TTY_FRAME;
if (status & BD_SC_OV) {
/*
* Overrun is special, since it's
* reported immediately, and doesn't
* affect the current character
*/
if (tty->flip.count < TTY_FLIPBUF_SIZE) {
tty->flip.count++;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
*tty->flip.flag_buf_ptr =
TTY_OVERRUN;
}
}
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
if (ch != 0 && time_before(jiffies,
break_pressed + HZ*5)) {
handle_sysrq(ch, regs, NULL);
break_pressed = 0;
goto ignore_char;
} else
break_pressed = 0;
}
#endif
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
ignore_char:
#endif
/* This BD is ready to be used again. Clear status.
* Get next BD.
*/
bdp->cbd_sc |= BD_SC_EMPTY;
bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = info->rx_bd_base;
else
bdp++;
}
info->rx_cur = (cbd_t *)bdp;
schedule_delayed_work(&tty->flip.work, 1);
}
static _INLINE_ void receive_break(ser_info_t *info, struct pt_regs *regs)
{
struct tty_struct *tty = info->tty;
info->state->icount.brk++;
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (info->line == sercons.index) {
if (!break_pressed) {
break_pressed = jiffies;
return;
} else
break_pressed = 0;
}
#endif
/* Check to see if there is room in the tty buffer for
* the break. If not, we exit now, losing the break. FIXME
*/
if ((tty->flip.count + 1) >= TTY_FLIPBUF_SIZE)
return;
*(tty->flip.flag_buf_ptr++) = TTY_BREAK;
*(tty->flip.char_buf_ptr++) = 0;
tty->flip.count++;
}
static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs)
{
if (info->flags & TX_WAKEUP) {
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
}
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
#endif
}
#ifdef notdef
/* I need to do this for the SCCs, so it is left as a reminder.
*/
static _INLINE_ void check_modem_status(struct async_struct *info)
{
int status;
struct async_icount *icount;
status = serial_in(info, UART_MSR);
if (status & UART_MSR_ANY_DELTA) {
icount = &info->state->icount;
/* update input line counters */
if (status & UART_MSR_TERI)
icount->rng++;
if (status & UART_MSR_DDSR)
icount->dsr++;
if (status & UART_MSR_DDCD) {
icount->dcd++;
#ifdef CONFIG_HARD_PPS
if ((info->flags & ASYNC_HARDPPS_CD) &&
(status & UART_MSR_DCD))
hardpps();
#endif
}
if (status & UART_MSR_DCTS)
icount->cts++;
wake_up_interruptible(&info->delta_msr_wait);
}
if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
#endif
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
else {
#ifdef SERIAL_DEBUG_OPEN
printk("scheduling hangup...");
#endif
schedule_work(&info->tqueue_hangup);
}
}
if (info->flags & ASYNC_CTS_FLOW) {
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx start...");
#endif
info->tty->hw_stopped = 0;
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
return;
}
} else {
if (!(status & UART_MSR_CTS)) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx stop...");
#endif
info->tty->hw_stopped = 1;
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
}
}
}
#endif
/*
* This is the serial driver's interrupt routine for a single port
*/
static irqreturn_t rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
u_char events;
int idx;
ser_info_t *info;
volatile smc_t *smcp;
volatile scc_t *sccp;
info = (ser_info_t *)dev_id;
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
events = smcp->smc_smce;
if (events & SMCM_BRKE)
receive_break(info, regs);
if (events & SMCM_RX)
receive_chars(info, regs);
if (events & SMCM_TX)
transmit_chars(info, regs);
smcp->smc_smce = events;
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
events = sccp->scc_scce;
if (events & SMCM_BRKE)
receive_break(info, regs);
if (events & SCCM_RX)
receive_chars(info, regs);
if (events & SCCM_TX)
transmit_chars(info, regs);
sccp->scc_scce = events;
}
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d, %x)...",
info->state->smc_scc_num, events);
#endif
#ifdef modem_control
check_modem_status(info);
#endif
info->last_active = jiffies;
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
return IRQ_HANDLED;
}
/*
* -------------------------------------------------------------------
* Here ends the serial interrupt routines.
* -------------------------------------------------------------------
*/
/*
* This routine is used to handle the "bottom half" processing for the
* serial driver, known also the "software interrupt" processing.
* This processing is done at the kernel interrupt level, after the
* rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
* them using rs_sched_event(), and they get done here.
*/
static void do_softint(void *private_)
{
ser_info_t *info = (ser_info_t *) private_;
struct tty_struct *tty;
tty = info->tty;
if (!tty)
return;
if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
}
}
/*
* This routine is called from the scheduler work queue when the interrupt
* routine has signalled that a hangup has occurred. The path of
* hangup processing is:
*
* serial interrupt routine -> (scheduler tqueue) ->
* do_serial_hangup() -> tty->hangup() -> rs_hangup()
*
*/
static void do_serial_hangup(void *private_)
{
struct async_struct *info = (struct async_struct *) private_;
struct tty_struct *tty;
tty = info->tty;
if (tty)
tty_hangup(tty);
}
/*static void rs_8xx_timer(void)
{
printk("rs_8xx_timer\n");
}*/
static int startup(ser_info_t *info)
{
unsigned long flags;
int retval=0;
int idx;
struct serial_state *state= info->state;
volatile smc_t *smcp;
volatile scc_t *sccp;
volatile smc_uart_t *up;
volatile scc_uart_t *scup;
save_flags(flags); cli();
if (info->flags & ASYNC_INITIALIZED) {
goto errout;
}
#ifdef maybe
if (!state->port || !state->type) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
goto errout;
}
#endif
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
#endif
#ifdef modem_control
info->MCR = 0;
if (info->tty->termios->c_cflag & CBAUD)
info->MCR = UART_MCR_DTR | UART_MCR_RTS;
#endif
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
/*
* and set the speed of the serial port
*/
change_speed(info);
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
/* Enable interrupts and I/O.
*/
smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
/* We can tune the buffer length and idle characters
* to take advantage of the entire incoming buffer size.
* If mrblr is something other than 1, maxidl has to be
* non-zero or we never get an interrupt. The maxidl
* is the number of character times we wait after reception
* of the last character before we decide no more characters
* are coming.
*/
up = (smc_uart_t *)&immr->im_dprambase[state->port];
#if 0
up->smc_mrblr = 1; /* receive buffer length */
up->smc_maxidl = 0; /* wait forever for next char */
#else
up->smc_mrblr = RX_BUF_SIZE;
up->smc_maxidl = RX_BUF_SIZE;
#endif
up->smc_brkcr = 1; /* number of break chars */
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
scup = (scc_uart_t *)&immr->im_dprambase[state->port];
#if 0
scup->scc_genscc.scc_mrblr = 1; /* receive buffer length */
scup->scc_maxidl = 0; /* wait forever for next char */
#else
scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
scup->scc_maxidl = RX_BUF_SIZE;
#endif
sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
return 0;
errout:
restore_flags(flags);
return retval;
}
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
static void shutdown(ser_info_t * info)
{
unsigned long flags;
struct serial_state *state;
int idx;
volatile smc_t *smcp;
volatile scc_t *sccp;
if (!(info->flags & ASYNC_INITIALIZED))
return;
state = info->state;
#ifdef SERIAL_DEBUG_OPEN
printk("Shutting down serial port %d (irq %d)....", info->line,
state->irq);
#endif
save_flags(flags); cli(); /* Disable interrupts */
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
/* Disable interrupts and I/O.
*/
smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
#ifdef CONFIG_SERIAL_CONSOLE
/* We can't disable the transmitter if this is the
* system console.
*/
if (idx != CONFIG_SERIAL_CONSOLE_PORT)
#endif
smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
#ifdef CONFIG_SERIAL_CONSOLE
if (idx != CONFIG_SERIAL_CONSOLE_PORT)
sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
#endif
}
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
restore_flags(flags);
}
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
static void change_speed(ser_info_t *info)
{
int baud_rate;
unsigned cflag, cval, scval, prev_mode;
int i, bits, sbits, idx;
unsigned long flags;
volatile smc_t *smcp;
volatile scc_t *sccp;
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
* 1 or 2 stop bits, minus 1.
* The value 'bits' counts this for us.
*/
cval = 0;
scval = 0;
/* byte size and parity */
switch (cflag & CSIZE) {
case CS5: bits = 5; break;
case CS6: bits = 6; break;
case CS7: bits = 7; break;
case CS8: bits = 8; break;
/* Never happens, but GCC is too dumb to figure it out */
default: bits = 8; break;
}
sbits = bits - 5;
if (cflag & CSTOPB) {
cval |= SMCMR_SL; /* Two stops */
scval |= SCU_PMSR_SL;
bits++;
}
if (cflag & PARENB) {
cval |= SMCMR_PEN;
scval |= SCU_PMSR_PEN;
bits++;
}
if (!(cflag & PARODD)) {
cval |= SMCMR_PM_EVEN;
scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
}
/* Determine divisor based on baud rate */
i = cflag & CBAUD;
if (i >= (sizeof(baud_table)/sizeof(int)))
baud_rate = 9600;
else
baud_rate = baud_table[i];
info->timeout = (TX_BUF_SIZE*HZ*bits);
info->timeout += HZ/50; /* Add .02 seconds of slop */
#ifdef modem_control
/* CTS flow control flag and modem status interrupts */
info->IER &= ~UART_IER_MSI;
if (info->flags & ASYNC_HARDPPS_CD)
info->IER |= UART_IER_MSI;
if (cflag & CRTSCTS) {
info->flags |= ASYNC_CTS_FLOW;
info->IER |= UART_IER_MSI;
} else
info->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
else {
info->flags |= ASYNC_CHECK_CD;
info->IER |= UART_IER_MSI;
}
serial_out(info, UART_IER, info->IER);
#endif
/*
* Set up parity check flag
*/
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
if (I_INPCK(info->tty))
info->read_status_mask |= BD_SC_FR | BD_SC_PR;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= BD_SC_BR;
/*
* Characters to ignore
*/
info->ignore_status_mask = 0;
if (I_IGNPAR(info->tty))
info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
if (I_IGNBRK(info->tty)) {
info->ignore_status_mask |= BD_SC_BR;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty))
info->ignore_status_mask |= BD_SC_OV;
}
/*
* !!! ignore all characters if CREAD is not set
*/
if ((cflag & CREAD) == 0)
info->read_status_mask &= ~BD_SC_EMPTY;
save_flags(flags); cli();
/* Start bit has not been added (so don't, because we would just
* subtract it later), and we need to add one for the number of
* stops bits (there is always at least one).
*/
bits++;
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
/* Set the mode register. We want to keep a copy of the
* enables, because we want to put them back if they were
* present.
*/
prev_mode = smcp->smc_smcmr;
smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
sccp->scc_pmsr = (sbits << 12) | scval;
}
m8260_cpm_setbrg(info->state->smc_scc_num, baud_rate);
restore_flags(flags);
}
static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
volatile cbd_t *bdp;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
return;
if (!tty)
return;
bdp = info->tx_cur;
while (bdp->cbd_sc & BD_SC_READY);
*((char *)__va(bdp->cbd_bufaddr)) = ch;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
/* Get next BD.
*/
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = info->tx_bd_base;
else
bdp++;
info->tx_cur = (cbd_t *)bdp;
}
static int rs_8xx_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
int c, ret = 0;
ser_info_t *info = (ser_info_t *)tty->driver_data;
volatile cbd_t *bdp;
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
if (!tty)
return 0;
bdp = info->tx_cur;
while (1) {
c = min(count, TX_BUF_SIZE);
if (c <= 0)
break;
if (bdp->cbd_sc & BD_SC_READY) {
info->flags |= TX_WAKEUP;
break;
}
if (from_user) {
if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
if (!ret)
ret = -EFAULT;
break;
}
} else {
memcpy(__va(bdp->cbd_bufaddr), buf, c);
}
bdp->cbd_datlen = c;
bdp->cbd_sc |= BD_SC_READY;
buf += c;
count -= c;
ret += c;
/* Get next BD.
*/
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = info->tx_bd_base;
else
bdp++;
info->tx_cur = (cbd_t *)bdp;
}
return ret;
}
static int rs_8xx_write_room(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
int ret;
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) {
info->flags &= ~TX_WAKEUP;
ret = TX_BUF_SIZE;
}
else {
info->flags |= TX_WAKEUP;
ret = 0;
}
return ret;
}
/* I could track this with transmit counters....maybe later.
*/
static int rs_8xx_chars_in_buffer(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
return 0;
}
static void rs_8xx_flush_buffer(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
/* There is nothing to "flush", whatever we gave the CPM
* is on its way out.
*/
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
info->flags &= ~TX_WAKEUP;
}
/*
* This function is used to send a high-priority XON/XOFF character to
* the device
*/
static void rs_8xx_send_xchar(struct tty_struct *tty, char ch)
{
volatile cbd_t *bdp;
ser_info_t *info = (ser_info_t *)tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_send_char"))
return;
bdp = info->tx_cur;
while (bdp->cbd_sc & BD_SC_READY);
*((char *)__va(bdp->cbd_bufaddr)) = ch;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
/* Get next BD.
*/
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = info->tx_bd_base;
else
bdp++;
info->tx_cur = (cbd_t *)bdp;
}
/*
* ------------------------------------------------------------
* rs_throttle()
*
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
static void rs_8xx_throttle(struct tty_struct * tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
printk("throttle %s: %d....\n", _tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
return;
if (I_IXOFF(tty))
rs_8xx_send_xchar(tty, STOP_CHAR(tty));
#ifdef modem_control
if (tty->termios->c_cflag & CRTSCTS)
info->MCR &= ~UART_MCR_RTS;
cli();
serial_out(info, UART_MCR, info->MCR);
sti();
#endif
}
static void rs_8xx_unthrottle(struct tty_struct * tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else
rs_8xx_send_xchar(tty, START_CHAR(tty));
}
#ifdef modem_control
if (tty->termios->c_cflag & CRTSCTS)
info->MCR |= UART_MCR_RTS;
cli();
serial_out(info, UART_MCR, info->MCR);
sti();
#endif
}
/*
* ------------------------------------------------------------
* rs_ioctl() and friends
* ------------------------------------------------------------
*/
#ifdef maybe
/*
* get_lsr_info - get line status register info
*
* Purpose: Let user call ioctl() to get info when the UART physically
* is emptied. On bus types like RS485, the transmitter must
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
static int get_lsr_info(struct async_struct * info, unsigned int *value)
{
unsigned char status;
unsigned int result;
cli();
status = serial_in(info, UART_LSR);
sti();
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
return put_user(result,value);
}
#endif
static int get_modem_info(ser_info_t *info, unsigned int *value)
{
unsigned int result = 0;
#ifdef modem_control
unsigned char control, status;
control = info->MCR;
cli();
status = serial_in(info, UART_MSR);
sti();
result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
#ifdef TIOCM_OUT1
| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
#endif
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
#endif
return put_user(result,value);
}
static int set_modem_info(ser_info_t *info, unsigned int cmd,
unsigned int *value)
{
int error;
unsigned int arg;
error = get_user(arg, value);
if (error)
return error;
#ifdef modem_control
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
info->MCR |= UART_MCR_RTS;
if (arg & TIOCM_DTR)
info->MCR |= UART_MCR_DTR;
#ifdef TIOCM_OUT1
if (arg & TIOCM_OUT1)
info->MCR |= UART_MCR_OUT1;
if (arg & TIOCM_OUT2)
info->MCR |= UART_MCR_OUT2;
#endif
break;
case TIOCMBIC:
if (arg & TIOCM_RTS)
info->MCR &= ~UART_MCR_RTS;
if (arg & TIOCM_DTR)
info->MCR &= ~UART_MCR_DTR;
#ifdef TIOCM_OUT1
if (arg & TIOCM_OUT1)
info->MCR &= ~UART_MCR_OUT1;
if (arg & TIOCM_OUT2)
info->MCR &= ~UART_MCR_OUT2;
#endif
break;
case TIOCMSET:
info->MCR = ((info->MCR & ~(UART_MCR_RTS |
#ifdef TIOCM_OUT1
UART_MCR_OUT1 |
UART_MCR_OUT2 |
#endif
UART_MCR_DTR))
| ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
#ifdef TIOCM_OUT1
| ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
| ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
#endif
| ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
break;
default:
return -EINVAL;
}
cli();
serial_out(info, UART_MCR, info->MCR);
sti();
#endif
return 0;
}
/* Sending a break is a two step process on the SMC/SCC. It is accomplished
* by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
* command. We take advantage of the begin/end functions to make this
* happen.
*/
static void begin_break(ser_info_t *info)
{
volatile cpm8260_t *cp;
uint page, sblock;
int num;
cp = cpmp;
if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
if (num == 0) {
page = CPM_CR_SMC1_PAGE;
sblock = CPM_CR_SMC1_SBLOCK;
}
else {
page = CPM_CR_SMC2_PAGE;
sblock = CPM_CR_SMC2_SBLOCK;
}
}
else {
num -= SCC_NUM_BASE;
switch (num) {
case 0:
page = CPM_CR_SCC1_PAGE;
sblock = CPM_CR_SCC1_SBLOCK;
break;
case 1:
page = CPM_CR_SCC2_PAGE;
sblock = CPM_CR_SCC2_SBLOCK;
break;
case 2:
page = CPM_CR_SCC3_PAGE;
sblock = CPM_CR_SCC3_SBLOCK;
break;
case 3:
page = CPM_CR_SCC4_PAGE;
sblock = CPM_CR_SCC4_SBLOCK;
break;
default: return;
}
}
cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_STOP_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
static void end_break(ser_info_t *info)
{
volatile cpm8260_t *cp;
uint page, sblock;
int num;
cp = cpmp;
if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
if (num == 0) {
page = CPM_CR_SMC1_PAGE;
sblock = CPM_CR_SMC1_SBLOCK;
}
else {
page = CPM_CR_SMC2_PAGE;
sblock = CPM_CR_SMC2_SBLOCK;
}
}
else {
num -= SCC_NUM_BASE;
switch (num) {
case 0:
page = CPM_CR_SCC1_PAGE;
sblock = CPM_CR_SCC1_SBLOCK;
break;
case 1:
page = CPM_CR_SCC2_PAGE;
sblock = CPM_CR_SCC2_SBLOCK;
break;
case 2:
page = CPM_CR_SCC3_PAGE;
sblock = CPM_CR_SCC3_SBLOCK;
break;
case 3:
page = CPM_CR_SCC4_PAGE;
sblock = CPM_CR_SCC4_SBLOCK;
break;
default: return;
}
}
cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_RESTART_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
/*
* This routine sends a break character out the serial port.
*/
static void send_break(ser_info_t *info, int duration)
{
current->state = TASK_INTERRUPTIBLE;
#ifdef SERIAL_DEBUG_SEND_BREAK
printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
#endif
begin_break(info);
schedule_timeout(duration);
end_break(info);
#ifdef SERIAL_DEBUG_SEND_BREAK
printk("done jiffies=%lu\n", jiffies);
#endif
}
static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
int error;
ser_info_t *info = (ser_info_t *)tty->driver_data;
int retval;
struct async_icount cnow; /* kernel counter temps */
struct serial_icounter_struct *p_cuser; /* user space */
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
if (signal_pending(current))
return -EINTR;
if (!arg) {
send_break(info, HZ/4); /* 1/4 second */
if (signal_pending(current))
return -EINTR;
}
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
if (signal_pending(current))
return -EINTR;
send_break(info, arg ? arg*(HZ/10) : HZ/4);
if (signal_pending(current))
return -EINTR;
return 0;
case TIOCSBRK:
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
begin_break(info);
return 0;
case TIOCCBRK:
retval = tty_check_change(tty);
if (retval)
return retval;
end_break(info);
return 0;
case TIOCGSOFTCAR:
return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
case TIOCSSOFTCAR:
error = get_user(arg, (unsigned int *) arg);
if (error)
return error;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
return 0;
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
return set_modem_info(info, cmd, (unsigned int *) arg);
#ifdef maybe
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
#endif
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
#ifdef modem_control
cli();
/* note the counters on entry */
cprev = info->state->icount;
sti();
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
cli();
cnow = info->state->icount; /* atomic copy */
sti();
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
return 0;
}
cprev = cnow;
}
/* NOTREACHED */
#else
return 0;
#endif
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
* Return: write counters to the user passed counter struct
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
cli();
cnow = info->state->icount;
sti();
p_cuser = (struct serial_icounter_struct *) arg;
error = put_user(cnow.cts, &p_cuser->cts);
if (error) return error;
error = put_user(cnow.dsr, &p_cuser->dsr);
if (error) return error;
error = put_user(cnow.rng, &p_cuser->rng);
if (error) return error;
error = put_user(cnow.dcd, &p_cuser->dcd);
if (error) return error;
return 0;
default:
return -ENOIOCTLCMD;
}
return 0;
}
/* FIX UP modem control here someday......
*/
static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
if ( (tty->termios->c_cflag == old_termios->c_cflag)
&& ( RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
change_speed(info);
#ifdef modem_control
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
!(tty->termios->c_cflag & CBAUD)) {
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
cli();
serial_out(info, UART_MCR, info->MCR);
sti();
}
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
(tty->termios->c_cflag & CBAUD)) {
info->MCR |= UART_MCR_DTR;
if (!tty->hw_stopped ||
!(tty->termios->c_cflag & CRTSCTS)) {
info->MCR |= UART_MCR_RTS;
}
cli();
serial_out(info, UART_MCR, info->MCR);
sti();
}
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_8xx_start(tty);
}
#endif
#if 0
/*
* No need to wake up processes in open wait, since they
* sample the CLOCAL flag once, and don't recheck it.
* XXX It's not clear whether the current behavior is correct
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
#endif
}
/*
* ------------------------------------------------------------
* rs_close()
*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
static void rs_8xx_close(struct tty_struct *tty, struct file * filp)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
struct serial_state *state;
unsigned long flags;
int idx;
volatile smc_t *smcp;
volatile scc_t *sccp;
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
state = info->state;
save_flags(flags); cli();
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
restore_flags(flags);
return;
}
#ifdef SERIAL_DEBUG_OPEN
printk("rs_close ttys%d, count = %d\n", info->line, state->count);
#endif
if ((tty->count == 1) && (state->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. state->count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk("rs_close: bad serial port count; tty->count is 1, "
"state->count is %d\n", state->count);
state->count = 1;
}
if (--state->count < 0) {
printk("rs_close: bad serial port count for ttys%d: %d\n",
info->line, state->count);
state->count = 0;
}
if (state->count) {
DBG_CNT("before DEC-2");
restore_flags(flags);
return;
}
info->flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
* interrupt driver to stop checking the data ready bit in the
* line status register.
*/
info->read_status_mask &= ~BD_SC_EMPTY;
if (info->flags & ASYNC_INITIALIZED) {
if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
smcp = &immr->im_smc[idx];
smcp->smc_smcm &= ~SMCM_RX;
smcp->smc_smcmr &= ~SMCMR_REN;
}
else {
sccp = &immr->im_scc[idx - SCC_IDX_BASE];
sccp->scc_sccm &= ~UART_SCCM_RX;
sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
}
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
rs_8xx_wait_until_sent(tty, info->timeout);
}
shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
tty->closing = 0;
info->event = 0;
info->tty = 0;
if (info->blocked_open) {
if (info->close_delay) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(info->close_delay);
}
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
restore_flags(flags);
}
/*
* rs_wait_until_sent() --- wait until the transmitter is empty
*/
static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
unsigned long orig_jiffies, char_time;
/*int lsr;*/
volatile cbd_t *bdp;
if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
return;
#ifdef maybe
if (info->state->type == PORT_UNKNOWN)
return;
#endif
orig_jiffies = jiffies;
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
* interval should also be less than the timeout.
*
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
char_time = 1;
if (timeout)
char_time = min(char_time, (unsigned long)timeout);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
/* We go through the loop at least once because we can't tell
* exactly when the last character exits the shifter. There can
* be at least two characters waiting to be sent after the buffers
* are empty.
*/
do {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
#endif
current->state = TASK_INTERRUPTIBLE;
/* current->dyn_prio = 0; make us low-priority */
schedule_timeout(char_time);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
bdp = info->tx_cur;
} while (bdp->cbd_sc & BD_SC_READY);
current->state = TASK_RUNNING;
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
}
/*
* rs_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
static void rs_8xx_hangup(struct tty_struct *tty)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
struct serial_state *state = info->state;
if (serial_paranoia_check(info, tty->name, "rs_hangup"))
return;
state = info->state;
rs_8xx_flush_buffer(tty);
shutdown(info);
info->event = 0;
state->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = 0;
wake_up_interruptible(&info->open_wait);
}
/*
* ------------------------------------------------------------
* rs_open() and friends
* ------------------------------------------------------------
*/
static int block_til_ready(struct tty_struct *tty, struct file * filp,
ser_info_t *info)
{
#ifdef DO_THIS_LATER
DECLARE_WAITQUEUE(wait, current);
struct serial_state *state = info->state;
#endif
int retval;
int do_clocal = 0;
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
#else
return -EAGAIN;
#endif
}
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
* If this is an SMC port, we don't have modem control to wait
* for, so just get out here.
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR)) ||
(info->state->smc_scc_num < SCC_NUM_BASE)) {
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
* this loop, state->count is dropped by one, so that
* rs_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
#ifdef DO_THIS_LATER
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready before block: ttys%d, count = %d\n",
state->line, state->count);
#endif
cli();
if (!tty_hung_up_p(filp))
state->count--;
sti();
info->blocked_open++;
while (1) {
cli();
if (tty->termios->c_cflag & CBAUD)
serial_out(info, UART_MCR,
serial_inp(info, UART_MCR) |
(UART_MCR_DTR | UART_MCR_RTS));
sti();
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
break;
}
if (!(info->flags & ASYNC_CLOSING) &&
(do_clocal || (serial_in(info, UART_MSR) &
UART_MSR_DCD)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, state->count);
#endif
schedule();
}
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp))
state->count++;
info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttys%d, count = %d\n",
info->line, state->count);
#endif
#endif /* DO_THIS_LATER */
if (retval)
return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
static int get_async_struct(int line, ser_info_t **ret_info)
{
struct serial_state *sstate;
sstate = rs_table + line;
if (sstate->info) {
sstate->count++;
*ret_info = (ser_info_t *)sstate->info;
return 0;
}
else {
return -ENOMEM;
}
}
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
static int rs_8xx_open(struct tty_struct *tty, struct file * filp)
{
ser_info_t *info;
int retval, line;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
retval = get_async_struct(line, &info);
if (retval)
return retval;
if (serial_paranoia_check(info, tty->name, "rs_open"))
return -ENODEV;
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s, count = %d\n", tty->name, info->state->count);
#endif
tty->driver_data = info;
info->tty = tty;
/*
* Start up serial port
*/
retval = startup(info);
if (retval)
return retval;
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s successful...", line);
#endif
return 0;
}
/*
* /proc fs routines....
*/
static inline int line_info(char *buf, struct serial_state *state)
{
#ifdef notdef
struct async_struct *info = state->info, scr_info;
char stat_buf[30], control, status;
#endif
int ret;
ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
state->line,
(state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
(unsigned int)(state->port), state->irq);
if (!state->port || (state->type == PORT_UNKNOWN)) {
ret += sprintf(buf+ret, "\n");
return ret;
}
#ifdef notdef
/*
* Figure out the current RS-232 lines
*/
if (!info) {
info = &scr_info; /* This is just for serial_{in,out} */
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
info->quot = 0;
info->tty = 0;
}
cli();
status = serial_in(info, UART_MSR);
control = info ? info->MCR : serial_in(info, UART_MCR);
sti();
stat_buf[0] = 0;
stat_buf[1] = 0;
if (control & UART_MCR_RTS)
strcat(stat_buf, "|RTS");
if (status & UART_MSR_CTS)
strcat(stat_buf, "|CTS");
if (control & UART_MCR_DTR)
strcat(stat_buf, "|DTR");
if (status & UART_MSR_DSR)
strcat(stat_buf, "|DSR");
if (status & UART_MSR_DCD)
strcat(stat_buf, "|CD");
if (status & UART_MSR_RI)
strcat(stat_buf, "|RI");
if (info->quot) {
ret += sprintf(buf+ret, " baud:%d",
state->baud_base / info->quot);
}
ret += sprintf(buf+ret, " tx:%d rx:%d",
state->icount.tx, state->icount.rx);
if (state->icount.frame)
ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
if (state->icount.parity)
ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
if (state->icount.brk)
ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
if (state->icount.overrun)
ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
/*
* Last thing is the RS-232 status lines
*/
ret += sprintf(buf+ret, " %s\n", stat_buf+1);
#endif
return ret;
}
int rs_8xx_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
int i, len = 0;
off_t begin = 0;
len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
for (i = 0; i < NR_PORTS && len < 4000; i++) {
len += line_info(page + len, &rs_table[i]);
if (len+begin > off+count)
goto done;
if (len+begin < off) {
begin += len;
len = 0;
}
}
*eof = 1;
done:
if (off >= len+begin)
return 0;
*start = page + (begin-off);
return ((count < begin+len-off) ? count : begin+len-off);
}
/*
* ---------------------------------------------------------------------
* rs_init() and friends
*
* rs_init() is called at boot-time to initialize the serial driver.
* ---------------------------------------------------------------------
*/
/*
* This routine prints out the appropriate serial driver version
* number, and identifies which options were configured into this
* driver.
*/
static _INLINE_ void show_serial_version(void)
{
printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
}
/*
* The serial console driver used during boot. Note that these names
* clash with those found in "serial.c", so we currently can't support
* the 16xxx uarts and these at the same time. I will fix this to become
* an indirect function call from tty_io.c (or something).
*/
#ifdef CONFIG_SERIAL_CONSOLE
/*
* Print a string to the serial port trying not to disturb any possible
* real use of the port...
* These funcitons work equally well for SCC, even though they are
* designed for SMC. Our only interests are the transmit/receive
* buffers, which are identically mapped for either the SCC or SMC.
*/
static void my_console_write(int idx, const char *s,
unsigned count)
{
struct serial_state *ser;
ser_info_t *info;
unsigned i;
volatile cbd_t *bdp, *bdbase;
volatile smc_uart_t *up;
volatile u_char *cp;
ser = rs_table + idx;
/* If the port has been initialized for general use, we have
* to use the buffer descriptors allocated there. Otherwise,
* we simply use the single buffer allocated.
*/
if ((info = (ser_info_t *)ser->info) != NULL) {
bdp = info->tx_cur;
bdbase = info->tx_bd_base;
}
else {
/* Pointer to UART in parameter ram.
*/
up = (smc_uart_t *)&immr->im_dprambase[ser->port];
/* Get the address of the host memory buffer.
*/
bdp = bdbase = (cbd_t *)&immr->im_dprambase[up->smc_tbase];
}
/*
* We need to gracefully shut down the transmitter, disable
* interrupts, then send our bytes out.
*/
/*
* Now, do each character. This is not as bad as it looks
* since this is a holding FIFO and not a transmitting FIFO.
* We could add the complexity of filling the entire transmit
* buffer, but we would just wait longer between accesses......
*/
for (i = 0; i < count; i++, s++) {
/* Wait for transmitter fifo to empty.
* Ready indicates output is ready, and xmt is doing
* that, not that it is ready for us to send.
*/
while (bdp->cbd_sc & BD_SC_READY);
/* Send the character out.
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)
cp = (u_char *)(bdp->cbd_bufaddr);
else
cp = __va(bdp->cbd_bufaddr);
*cp = *s;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
/* if a LF, also do CR... */
if (*s == 10) {
while (bdp->cbd_sc & BD_SC_READY);
cp = __va(bdp->cbd_bufaddr);
*cp = 13;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
if (bdp->cbd_sc & BD_SC_WRAP) {
bdp = bdbase;
}
else {
bdp++;
}
}
}
/*
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
while (bdp->cbd_sc & BD_SC_READY);
if (info)
info->tx_cur = (cbd_t *)bdp;
}
static void serial_console_write(struct console *c, const char *s,
unsigned count)
{
#if defined(CONFIG_KGDB_CONSOLE) && !defined(CONFIG_USE_SERIAL2_KGDB)
/* Try to let stub handle output. Returns true if it did. */
if (kgdb_output_string(s, count))
return;
#endif
my_console_write(c->index, s, count);
}
#ifdef CONFIG_XMON
int
xmon_8xx_write(const char *s, unsigned count)
{
my_console_write(KGDB_SER_IDX, s, count);
return(count);
}
#endif
#ifdef CONFIG_KGDB
void
putDebugChar(char ch)
{
my_console_write(KGDB_SER_IDX, &ch, 1);
}
#endif
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
/*
* Receive character from the serial port. This only works well
* before the port is initialize for real use.
*/
static int my_console_wait_key(int idx, int xmon, char *obuf)
{
struct serial_state *ser;
u_char c, *cp;
ser_info_t *info;
volatile cbd_t *bdp;
volatile smc_uart_t *up;
int i;
ser = rs_table + idx;
/* Pointer to UART in parameter ram.
*/
up = (smc_uart_t *)&immr->im_dprambase[ser->port];
/* Get the address of the host memory buffer.
* If the port has been initialized for general use, we must
* use information from the port structure.
*/
if ((info = (ser_info_t *)ser->info))
bdp = info->rx_cur;
else
bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase];
/*
* We need to gracefully shut down the receiver, disable
* interrupts, then read the input.
* XMON just wants a poll. If no character, return -1, else
* return the character.
*/
if (!xmon) {
while (bdp->cbd_sc & BD_SC_EMPTY);
}
else {
if (bdp->cbd_sc & BD_SC_EMPTY)
return -1;
}
/* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)
cp = (u_char *)(bdp->cbd_bufaddr);
else
cp = __va(bdp->cbd_bufaddr);
if (obuf) {
i = c = bdp->cbd_datlen;
while (i-- > 0)
*obuf++ = *cp++;
}
else {
c = *cp;
}
bdp->cbd_sc |= BD_SC_EMPTY;
if (info) {
if (bdp->cbd_sc & BD_SC_WRAP) {
bdp = info->rx_bd_base;
}
else {
bdp++;
}
info->rx_cur = (cbd_t *)bdp;
}
return((int)c);
}
#endif /* CONFIG_XMON || CONFIG_KGDB */
#ifdef CONFIG_XMON
int
xmon_8xx_read_poll(void)
{
return(my_console_wait_key(KGDB_SER_IDX, 1, NULL));
}
int
xmon_8xx_read_char(void)
{
return(my_console_wait_key(KGDB_SER_IDX, 0, NULL));
}
#endif
#ifdef CONFIG_KGDB
static char kgdb_buf[RX_BUF_SIZE], *kgdp;
static int kgdb_chars;
char
getDebugChar(void)
{
if (kgdb_chars <= 0) {
kgdb_chars = my_console_wait_key(KGDB_SER_IDX, 0, kgdb_buf);
kgdp = kgdb_buf;
}
kgdb_chars--;
return(*kgdp++);
}
void kgdb_interruptible(int yes)
{
volatile smc_t *smcp;
smcp = &immr->im_smc[KGDB_SER_IDX];
if (yes == 1)
smcp->smc_smcm |= SMCM_RX;
else
smcp->smc_smcm &= ~SMCM_RX;
}
void kgdb_map_scc(void)
{
ushort serbase;
uint mem_addr;
volatile cbd_t *bdp;
volatile smc_uart_t *up;
/* The serial port has already been initialized before
* we get here. We have to assign some pointers needed by
* the kernel, and grab a memory location in the CPM that will
* work until the driver is really initialized.
*/
immr = (immap_t *)IMAP_ADDR;
/* Right now, assume we are using SMCs.
*/
#ifdef USE_KGDB_SMC2
*(ushort *)(&immr->im_dprambase[PROFF_SMC2_BASE]) = serbase = PROFF_SMC2;
#else
*(ushort *)(&immr->im_dprambase[PROFF_SMC1_BASE]) = serbase = PROFF_SMC1;
#endif
up = (smc_uart_t *)&immr->im_dprambase[serbase];
/* Allocate space for an input FIFO, plus a few bytes for output.
* Allocate bytes to maintain word alignment.
*/
mem_addr = (uint)(&immr->im_dprambase[0x1000]);
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase];
bdp->cbd_bufaddr = mem_addr;
bdp = (cbd_t *)&immr->im_dprambase[up->smc_tbase];
bdp->cbd_bufaddr = mem_addr+RX_BUF_SIZE;
up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */
up->smc_maxidl = RX_BUF_SIZE;
}
#endif
static struct tty_driver *serial_console_device(struct console *c, int *index)
{
*index = c->index;
return serial_driver;
}
/*
* Register console.
*/
static int __init console_8xx_init(void)
{
register_console(&sercons);
return 0;
}
console_initcall(console_8xx_init);
#endif
/* Default console baud rate as determined by the board information
* structure.
*/
static int baud_idx;
static struct tty_operations rs_8xx_ops = {
.open = rs_8xx_open,
.close = rs_8xx_close,
.write = rs_8xx_write,
.put_char = rs_8xx_put_char,
.write_room = rs_8xx_write_room,
.chars_in_buffer = rs_8xx_chars_in_buffer,
.flush_buffer = rs_8xx_flush_buffer,
.ioctl = rs_8xx_ioctl,
.throttle = rs_8xx_throttle,
.unthrottle = rs_8xx_unthrottle,
.send_xchar = rs_8xx_send_xchar,
.set_termios = rs_8xx_set_termios,
.stop = rs_8xx_stop,
.start = rs_8xx_start,
.hangup = rs_8xx_hangup,
.wait_until_sent = rs_8xx_wait_until_sent,
.read_proc = rs_8xx_read_proc,
};
/*
* The serial driver boot-time initialization code!
*/
static int __init rs_8xx_init(void)
{
struct serial_state * state;
ser_info_t *info;
uint mem_addr, dp_addr;
int i, j, idx;
uint page, sblock;
volatile cbd_t *bdp;
volatile cpm8260_t *cp;
volatile smc_t *sp;
volatile smc_uart_t *up;
volatile scc_t *scp;
volatile scc_uart_t *sup;
volatile immap_t *immap;
volatile iop8260_t *io;
serial_driver = alloc_tty_driver(NR_PORTS);
if (!serial_driver)
return -ENOMEM;
show_serial_version();
/* Initialize the tty_driver structure */
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "serial";
serial_driver->devfs_name = "tts/";
serial_driver->name = "ttyS";
serial_driver->major = TTY_MAJOR;
serial_driver->minor_start = 64;
serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
serial_driver->subtype = SERIAL_TYPE_NORMAL;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &rs_8xx_ops);
if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n");
immap = immr;
cp = &immap->im_cpm;
io = &immap->im_ioport;
/* This should have been done long ago by the early boot code,
* but do it again to make sure.
*/
*(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
*(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
/* Geeze, here we go....Picking I/O port bits....Lots of
* choices. If you don't like mine, pick your own.
* Configure SMCs Tx/Rx. SMC1 is only on Port D, SMC2 is
* only on Port A. You either pick 'em, or not.
*/
#ifndef SCC_CONSOLE
io->iop_ppard |= 0x00c00000;
io->iop_pdird |= 0x00400000;
io->iop_pdird &= ~0x00800000;
io->iop_psord &= ~0x00c00000;
#ifdef USE_SMC2
io->iop_ppara |= 0x00c00000;
io->iop_pdira |= 0x00400000;
io->iop_pdira &= ~0x00800000;
io->iop_psora &= ~0x00c00000;
#endif
/* Configure SCC2 and SCC3. Be careful about the fine print.
* Secondary options are only available when you take away
* the primary option. Unless the pins are used for something
* else, SCC2 and SCC3 are on Port B.
* Port B, 8 - SCC3 TxD
* Port B, 12 - SCC2 TxD
* Port B, 14 - SCC3 RxD
* Port B, 15 - SCC2 RxD
*/
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
/* Wire BRG1 to SMC1 and BRG2 to SMC2.
*/
immap->im_cpmux.cmx_smr = 0;
/* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and
* BRG4 to SCC3.
*/
immap->im_cpmux.cmx_scr &= ~0x00ffff00;
immap->im_cpmux.cmx_scr |= 0x00121b00;
#else
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
/* Use Port D for SCC1 instead of other functions.
*/
io->iop_ppard |= 0x00000003;
io->iop_psord &= ~0x00000001; /* Rx */
io->iop_psord |= 0x00000002; /* Tx */
io->iop_pdird &= ~0x00000001; /* Rx */
io->iop_pdird |= 0x00000002; /* Tx */
/* Connect SCC1, SCC2, SCC3 to NMSI. Connect BRG1 to SCC1,
* BRG2 to SCC2, BRG3 to SCC3.
*/
immap->im_cpmux.cmx_scr &= ~0xffffff00;
immap->im_cpmux.cmx_scr |= 0x00091200;
#endif
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
state->magic = SSTATE_MAGIC;
state->line = i;
state->type = PORT_UNKNOWN;
state->custom_divisor = 0;
state->close_delay = 5*HZ/10;
state->closing_wait = 30*HZ;
state->icount.cts = state->icount.dsr =
state->icount.rng = state->icount.dcd = 0;
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
printk (KERN_INFO "ttyS%d on %s%d at 0x%04x, BRG%d\n",
i,
(state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
PORT_NUM(state->smc_scc_num) + 1,
(unsigned int)(state->port),
state->smc_scc_num + 1);
#ifdef CONFIG_SERIAL_CONSOLE
/* If we just printed the message on the console port, and
* we are about to initialize it for general use, we have
* to wait a couple of character times for the CR/NL to
* make it out of the transmit buffer.
*/
if (i == CONFIG_SERIAL_CONSOLE_PORT)
mdelay(300);
#endif
info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
if (info) {
/*memset(info, 0, sizeof(ser_info_t));*/
__clear_user(info,sizeof(ser_info_t));
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->magic = SERIAL_MAGIC;
info->flags = state->flags;
INIT_WORK(&info->tqueue, do_softint, info);
INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
info->line = i;
info->state = state;
state->info = (struct async_struct *)info;
/* We need to allocate a transmit and receive buffer
* descriptors from dual port ram, and a character
* buffer area from host mem.
*/
dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8);
/* Allocate space for FIFOs in the host memory.
*/
mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1);
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;
for (j=0; j<(RX_NUM_FIFO-1); j++) {
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
mem_addr += RX_BUF_SIZE;
bdp++;
}
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
if ((idx = state->smc_scc_num) < SCC_NUM_BASE) {
sp = &immap->im_smc[idx];
up = (smc_uart_t *)&immap->im_dprambase[state->port];
up->smc_rbase = dp_addr;
}
else {
scp = &immap->im_scc[idx - SCC_IDX_BASE];
sup = (scc_uart_t *)&immap->im_dprambase[state->port];
scp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
sup->scc_genscc.scc_rbase = dp_addr;
}
dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8);
/* Allocate space for FIFOs in the host memory.
*/
mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1);
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;
for (j=0; j<(TX_NUM_FIFO-1); j++) {
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = BD_SC_INTRPT;
mem_addr += TX_BUF_SIZE;
bdp++;
}
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
if (idx < SCC_NUM_BASE) {
up->smc_tbase = dp_addr;
/* Set up the uart parameters in the
* parameter ram.
*/
up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
/* Set this to 1 for now, so we get single
* character interrupts. Using idle charater
* time requires some additional tuning.
*/
up->smc_mrblr = 1;
up->smc_maxidl = 0;
up->smc_brkcr = 1;
/* Send the CPM an initialize command.
*/
if (state->smc_scc_num == 0) {
page = CPM_CR_SMC1_PAGE;
sblock = CPM_CR_SMC1_SBLOCK;
}
else {
page = CPM_CR_SMC2_PAGE;
sblock = CPM_CR_SMC2_SBLOCK;
}
cp->cp_cpcr = mk_cr_cmd(page, sblock, 0,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
/* Disable all interrupts and clear all pending
* events.
*/
sp->smc_smcm = 0;
sp->smc_smce = 0xff;
}
else {
sup->scc_genscc.scc_tbase = dp_addr;
/* Set up the uart parameters in the
* parameter ram.
*/
sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
/* Set this to 1 for now, so we get single
* character interrupts. Using idle charater
* time requires some additional tuning.
*/
sup->scc_genscc.scc_mrblr = 1;
sup->scc_maxidl = 0;
sup->scc_brkcr = 1;
sup->scc_parec = 0;
sup->scc_frmec = 0;
sup->scc_nosec = 0;
sup->scc_brkec = 0;
sup->scc_uaddr1 = 0;
sup->scc_uaddr2 = 0;
sup->scc_toseq = 0;
sup->scc_char1 = 0x8000;
sup->scc_char2 = 0x8000;
sup->scc_char3 = 0x8000;
sup->scc_char4 = 0x8000;
sup->scc_char5 = 0x8000;
sup->scc_char6 = 0x8000;
sup->scc_char7 = 0x8000;
sup->scc_char8 = 0x8000;
sup->scc_rccm = 0xc0ff;
/* Send the CPM an initialize command.
*/
#ifdef SCC_CONSOLE
switch (state->smc_scc_num) {
case 0:
page = CPM_CR_SCC1_PAGE;
sblock = CPM_CR_SCC1_SBLOCK;
break;
case 1:
page = CPM_CR_SCC2_PAGE;
sblock = CPM_CR_SCC2_SBLOCK;
break;
case 2:
page = CPM_CR_SCC3_PAGE;
sblock = CPM_CR_SCC3_SBLOCK;
break;
}
#else
if (state->smc_scc_num == 2) {
page = CPM_CR_SCC2_PAGE;
sblock = CPM_CR_SCC2_SBLOCK;
}
else {
page = CPM_CR_SCC3_PAGE;
sblock = CPM_CR_SCC3_SBLOCK;
}
#endif
cp->cp_cpcr = mk_cr_cmd(page, sblock, 0,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
scp->scc_gsmrh = 0;
scp->scc_gsmrl =
(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
/* Disable all interrupts and clear all pending
* events.
*/
scp->scc_sccm = 0;
scp->scc_scce = 0xffff;
scp->scc_dsr = 0x7e7e;
scp->scc_pmsr = 0x3000;
}
/* Install interrupt handler.
*/
request_irq(state->irq, rs_8xx_interrupt, 0, "uart", info);
/* Set up the baud rate generator.
*/
m8260_cpm_setbrg(state->smc_scc_num,
baud_table[baud_idx]);
/* If the port is the console, enable Rx and Tx.
*/
#ifdef CONFIG_SERIAL_CONSOLE
if (i == CONFIG_SERIAL_CONSOLE_PORT) {
if (idx < SCC_NUM_BASE)
sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
else
scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
#endif
}
}
return 0;
}
module_init(rs_8xx_init);
/* This must always be called before the rs_8xx_init() function, otherwise
* it blows away the port control information.
*/
static int __init serial_console_setup(struct console *co, char *options)
{
struct serial_state *ser;
uint mem_addr, dp_addr, bidx;
volatile cbd_t *bdp;
volatile cpm8260_t *cp;
volatile immap_t *immap;
#ifndef SCC_CONSOLE
volatile smc_t *sp;
volatile smc_uart_t *up;
#endif
#ifdef SCC_CONSOLE
volatile scc_t *scp;
volatile scc_uart_t *sup;
#endif
volatile iop8260_t *io;
bd_t *bd;
bd = (bd_t *)__res;
for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
if (bd->bi_baudrate == baud_table[bidx])
break;
co->cflag = CREAD|CLOCAL|bidx|CS8;
baud_idx = bidx;
ser = rs_table + co->index;
immap = immr;
cp = &immap->im_cpm;
io = &immap->im_ioport;
#ifdef SCC_CONSOLE
scp = (scc_t *)&(immap->im_scc[SCC_CONSOLE-1]);
sup = (scc_uart_t *)&immap->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
scp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
scp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
/* Use Port D for SCC1 instead of other functions.
*/
io->iop_ppard |= 0x00000003;
io->iop_psord &= ~0x00000001; /* Rx */
io->iop_psord |= 0x00000002; /* Tx */
io->iop_pdird &= ~0x00000001; /* Rx */
io->iop_pdird |= 0x00000002; /* Tx */
#else
/* This should have been done long ago by the early boot code,
* but do it again to make sure.
*/
*(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
*(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
/* Right now, assume we are using SMCs.
*/
sp = &immap->im_smc[ser->smc_scc_num];
/* When we get here, the CPM has been reset, so we need
* to configure the port.
* We need to allocate a transmit and receive buffer descriptor
* from dual port ram, and a character buffer area from host mem.
*/
up = (smc_uart_t *)&immap->im_dprambase[ser->port];
/* Disable transmitter/receiver.
*/
sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
/* Use Port D for SMC1 instead of other functions.
*/
io->iop_ppard |= 0x00c00000;
io->iop_pdird |= 0x00400000;
io->iop_pdird &= ~0x00800000;
io->iop_psord &= ~0x00c00000;
#endif
/* Allocate space for two buffer descriptors in the DP ram.
*/
dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2, 8);
/* Allocate space for two 2 byte FIFOs in the host memory.
*/
mem_addr = m8260_cpm_hostalloc(4, 1);
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
bdp = (cbd_t *)&immap->im_dprambase[dp_addr];
bdp->cbd_bufaddr = __pa(mem_addr);
(bdp+1)->cbd_bufaddr = __pa(mem_addr+2);
/* For the receive, set empty and wrap.
* For transmit, set wrap.
*/
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
(bdp+1)->cbd_sc = BD_SC_WRAP;
/* Set up the uart parameters in the parameter ram.
*/
#ifdef SCC_CONSOLE
sup->scc_genscc.scc_rbase = dp_addr;
sup->scc_genscc.scc_tbase = dp_addr + sizeof(cbd_t);
/* Set up the uart parameters in the
* parameter ram.
*/
sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
sup->scc_genscc.scc_mrblr = 1;
sup->scc_maxidl = 0;
sup->scc_brkcr = 1;
sup->scc_parec = 0;
sup->scc_frmec = 0;
sup->scc_nosec = 0;
sup->scc_brkec = 0;
sup->scc_uaddr1 = 0;
sup->scc_uaddr2 = 0;
sup->scc_toseq = 0;
sup->scc_char1 = 0x8000;
sup->scc_char2 = 0x8000;
sup->scc_char3 = 0x8000;
sup->scc_char4 = 0x8000;
sup->scc_char5 = 0x8000;
sup->scc_char6 = 0x8000;
sup->scc_char7 = 0x8000;
sup->scc_char8 = 0x8000;
sup->scc_rccm = 0xc0ff;
/* Send the CPM an initialize command.
*/
cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
scp->scc_gsmrh = 0;
scp->scc_gsmrl =
(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
/* Disable all interrupts and clear all pending
* events.
*/
scp->scc_sccm = 0;
scp->scc_scce = 0xffff;
scp->scc_dsr = 0x7e7e;
scp->scc_pmsr = 0x3000;
/* Wire BRG1 to SCC1. The serial init will take care of
* others.
*/
immap->im_cpmux.cmx_scr = 0;
/* Set up the baud rate generator.
*/
m8260_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate);
scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
#else
up->smc_rbase = dp_addr; /* Base of receive buffer desc. */
up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */
up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
/* Set this to 1 for now, so we get single character interrupts.
*/
up->smc_mrblr = 1; /* receive buffer length */
up->smc_maxidl = 0; /* wait forever for next char */
/* Send the CPM an initialize command.
*/
cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
/* Set up the baud rate generator.
*/
m8260_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate);
/* And finally, enable Rx and Tx.
*/
sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
#endif
return 0;
}
......@@ -598,8 +598,16 @@ config TQM8260
End of Life: not yet :-)
URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
config ADS8272
bool "ADS8272"
endchoice
config PQ2ADS
bool
depends on ADS8272
default y
config TQM8xxL
bool
depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L || SM850)
......@@ -611,14 +619,32 @@ config EMBEDDEDBOOT
default y
config 8260
bool "MPC8260 CPM Support" if WILLOW
bool "CPM2 Support" if WILLOW
depends on 6xx
default y if TQM8260 || RPXSUPER || EST8260 || SBS8260 || SBC82xx
help
The MPC8260 CPM (Communications Processor Module) is a typical
embedded CPU made by Motorola. Selecting this option means that
you wish to build a kernel for a machine with specifically an 8260
for a CPU.
The MPC8260 is a typical embedded CPU made by Motorola. Selecting
this option means that you wish to build a kernel for a machine with
an 8260 class CPU.
config 8272
bool
depends on 6xx
default y if ADS8272
select 8260
help
The MPC8272 CPM has a different internal dpram setup than other CPM2
devices
config CPM2
bool
depends on 8260
default y
help
The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Motorola. Selecting this option means that
you wish to build a kernel for a machine with a CPM2 coprocessor
on it (826x, 827x, 8560).
config PPC_CHRP
bool
......@@ -701,11 +727,11 @@ config SPRUCE_BAUD_33M
config PC_KEYBOARD
bool "PC PS/2 style Keyboard"
depends on 4xx || 8260
depends on 4xx || CPM2
config SERIAL_CONSOLE
bool
depends on 8xx || 8260
depends on 8xx
default y
config SERIAL_CONSOLE_BAUD
......@@ -986,7 +1012,7 @@ config ISA
config GENERIC_ISA_DMA
bool
depends on POWER3 || POWER4 || 6xx && !8260
depends on POWER3 || POWER4 || 6xx && !CPM2
default y
config EISA
......@@ -1003,10 +1029,10 @@ config MCA
bool
config PCI
bool "PCI support" if 40x || 8260 || 85xx
default y if !40x && !8260 && !8xx && !APUS && !85xx
default PCI_PERMEDIA if !4xx && !8260 && !8xx && APUS
default PCI_QSPAN if !4xx && !8260 && 8xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
default PCI_QSPAN if !4xx && !CPM2 && 8xx
bool "PCI support" if 40x || CPM2 || 85xx
default y if !40x && !CPM2 && !8xx && !APUS && !85xx
help
Find out whether your system includes a PCI bus. PCI is the name of
a bus system, i.e. the way the CPU talks to the other stuff inside
......@@ -1019,11 +1045,39 @@ config PCI_DOMAINS
config PCI_QSPAN
bool "QSpan PCI"
depends on !4xx && !8260 && 8xx
depends on !4xx && !CPM2 && 8xx
help
Say Y here if you have a system based on a Motorola 8xx-series
embedded processor with a QSPAN PCI interface, otherwise say N.
config PCI_8260
bool
depends on PCI && 8260 && !8272
default y
config 8260_PCI9
bool " Enable workaround for MPC826x erratum PCI 9"
depends on PCI_8260
default y
choice
prompt " IDMA channel for PCI 9 workaround"
depends on 8260_PCI9
config 8260_PCI9_IDMA1
bool "IDMA1"
config 8260_PCI9_IDMA2
bool "IDMA2"
config 8260_PCI9_IDMA3
bool "IDMA3"
config 8260_PCI9_IDMA4
bool "IDMA4"
endchoice
config PCI_PERMEDIA
bool "PCI for Permedia2"
depends on !4xx && !8xx && APUS
......@@ -1258,7 +1312,7 @@ endchoice
config KGDB_CONSOLE
bool "Enable serial console thru kgdb port"
depends on KGDB && 8xx || 8260
depends on KGDB && 8xx || CPM2
help
If you enable this, all serial console messages will be sent
over the gdb stub.
......
......@@ -48,7 +48,7 @@ core-$(CONFIG_XMON) += arch/ppc/xmon/
core-$(CONFIG_APUS) += arch/ppc/amiga/
drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
drivers-$(CONFIG_8260) += arch/ppc/8260_io/
drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/
BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
......
......@@ -16,7 +16,7 @@
#endif
#ifdef CONFIG_8260
#include <asm/mpc8260.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#endif
#ifdef CONFIG_40x
#include <asm/io.h>
......@@ -415,9 +415,9 @@ clk_8260(bd_t *bd)
{
uint scmr, vco_out, clkin;
uint plldf, pllmf, corecnf;
volatile immap_t *ip;
volatile cpm2_map_t *ip;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
scmr = ip->im_clkrst.car_scmr;
/* The clkin is always bus frequency.
......@@ -457,9 +457,9 @@ clk_8280(bd_t *bd)
{
uint scmr, main_clk, clkin;
uint pllmf, corecnf;
volatile immap_t *ip;
volatile cpm2_map_t *ip;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
scmr = ip->im_clkrst.car_scmr;
/* The clkin is always bus frequency.
......
......@@ -3,7 +3,8 @@
*/
#include <linux/types.h>
#include <asm/mpc8260.h>
#include <asm/cpm_8260.h>
#include <asm/cpm2.h>
#include <asm/immap_cpm2.h>
uint no_print;
extern char *params[];
......@@ -29,12 +30,12 @@ serial_init(int ignored, bd_t *bd)
volatile scc_uart_t *sup;
#endif
volatile cbd_t *tbdf, *rbdf;
volatile immap_t *ip;
volatile iop8260_t *io;
volatile cpm8260_t *cp;
volatile cpm2_map_t *ip;
volatile iop_cpm2_t *io;
volatile cpm_cpm2_t *cp;
uint dpaddr, memaddr;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
cp = &ip->im_cpm;
io = &ip->im_ioport;
......@@ -223,10 +224,10 @@ serial_readbuf(u_char *cbuf)
volatile char *buf;
volatile smc_uart_t *up;
volatile scc_uart_t *sup;
volatile immap_t *ip;
volatile cpm2_map_t *ip;
int i, nc;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
#ifdef SCC_CONSOLE
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
......@@ -255,10 +256,10 @@ serial_putc(void *ignored, const char c)
volatile char *buf;
volatile smc_uart_t *up;
volatile scc_uart_t *sup;
volatile immap_t *ip;
volatile cpm2_map_t *ip;
extern bd_t *board_info;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
#ifdef SCC_CONSOLE
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase];
......@@ -298,9 +299,9 @@ serial_tstc(void *ignored)
volatile cbd_t *rbdf;
volatile smc_uart_t *up;
volatile scc_uart_t *sup;
volatile immap_t *ip;
volatile cpm2_map_t *ip;
ip = (immap_t *)IMAP_ADDR;
ip = (cpm2_map_t *)CPM_MAP_ADDR;
#ifdef SCC_CONSOLE
sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase];
......
#
# Automatically generated make config: don't edit
#
CONFIG_MMU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_STANDALONE=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
CONFIG_FUTEX=y
# CONFIG_EPOLL is not set
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
#
# CONFIG_MODULES is not set
#
# Processor
#
CONFIG_6xx=y
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
# CONFIG_CPU_FREQ is not set
CONFIG_EMBEDDEDBOOT=y
CONFIG_PPC_STD_MMU=y
#
# Platform options
#
# CONFIG_PPC_MULTIPLATFORM is not set
# CONFIG_APUS is not set
# CONFIG_WILLOW is not set
# CONFIG_PCORE is not set
# CONFIG_POWERPMC250 is not set
# CONFIG_EV64260 is not set
# CONFIG_SPRUCE is not set
# CONFIG_LOPEC is not set
# CONFIG_MCPN765 is not set
# CONFIG_MVME5100 is not set
# CONFIG_PPLUS is not set
# CONFIG_PRPMC750 is not set
# CONFIG_PRPMC800 is not set
# CONFIG_SANDPOINT is not set
# CONFIG_ADIR is not set
# CONFIG_K2 is not set
# CONFIG_PAL4 is not set
# CONFIG_GEMINI is not set
# CONFIG_EST8260 is not set
# CONFIG_SBC82xx is not set
# CONFIG_SBS8260 is not set
# CONFIG_RPX6 is not set
# CONFIG_TQM8260 is not set
CONFIG_ADS8272=y
CONFIG_PQ2ADS=y
CONFIG_8260=y
CONFIG_8272=y
CONFIG_CPM2=y
# CONFIG_PC_KEYBOARD is not set
CONFIG_SERIAL_CONSOLE=y
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
# CONFIG_HIGHMEM is not set
CONFIG_KERNEL_ELF=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Bus options
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_PCI_LEGACY_PROC is not set
# CONFIG_PCI_NAMES is not set
#
# Advanced setup
#
# CONFIG_ADVANCED_OPTIONS is not set
#
# Default settings for advanced configuration options are used
#
CONFIG_HIGHMEM_START=0xfe000000
CONFIG_LOWMEM_SIZE=0x30000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_TASK_SIZE=0x80000000
CONFIG_BOOT_LOAD=0x00400000
#
# Device Drivers
#
#
# Generic Driver Options
#
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_CARMEL is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=32768
CONFIG_BLK_DEV_INITRD=y
# CONFIG_LBD is not set
#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# Fusion MPT device support
#
#
# IEEE 1394 (FireWire) support
#
# CONFIG_IEEE1394 is not set
#
# I2O device support
#
# CONFIG_I2O is not set
#
# Macintosh device drivers
#
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
# CONFIG_OAKNET is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
#
# Tulip family network device support
#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_NET_PCI is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
#
# Token Ring devices
#
# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
#
# ISDN subsystem
#
# CONFIG_ISDN is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
# CONFIG_SERIO_I8042 is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_QIC02_TAPE is not set
#
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
# I2C support
#
# CONFIG_I2C is not set
#
# Misc devices
#
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
#
# Graphics support
#
# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB is not set
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
#
# Network File Systems
#
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
# CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_NEC98_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
# Native Language Support
#
# CONFIG_NLS is not set
# CONFIG_SCC_ENET is not set
CONFIG_FEC_ENET=y
# CONFIG_USE_MDIO is not set
#
# CPM2 Options
#
CONFIG_SCC_CONSOLE=y
CONFIG_FCC1_ENET=y
# CONFIG_FCC2_ENET is not set
# CONFIG_FCC3_ENET is not set
#
# Library routines
#
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_KGDB_CONSOLE is not set
#
# Security options
#
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
......@@ -30,6 +30,7 @@ obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o
obj-$(CONFIG_PREP_RESIDUAL) += residual.o
obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o
obj-$(CONFIG_EST8260) += est8260_setup.o
obj-$(CONFIG_PQ2ADS) += pq2ads_setup.o
obj-$(CONFIG_TQM8260) += tqm8260_setup.o
obj-$(CONFIG_EV64260) += ev64260_setup.o
obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
......
......@@ -6,7 +6,7 @@
#ifndef __EST8260_PLATFORM
#define __EST8260_PLATFORM
#define IMAP_ADDR ((uint)0xf0000000)
#define CPM_MAP_ADDR ((uint)0xf0000000)
#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
......
/*
* A collection of structures, addresses, and values associated with
* the Motorola MPC8260ADS/MPC8266ADS-PCI boards.
* Copied from the RPX-Classic and SBS8260 stuff.
*
* Copyright (c) 2001 Dan Malek (dan@mvista.com)
*/
#ifdef __KERNEL__
#ifndef __MACH_ADS8260_DEFS
#define __MACH_ADS8260_DEFS
#include <linux/config.h>
#include <asm/ppcboot.h>
/* Memory map is configured by the PROM startup.
* We just map a few things we need. The CSR is actually 4 byte-wide
* registers that can be accessed as 8-, 16-, or 32-bit values.
*/
#define CPM_MAP_ADDR ((uint)0xf0000000)
#define BCSR_ADDR ((uint)0xf4500000)
#define BCSR_SIZE ((uint)(32 * 1024))
#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
* only on word boundaries.
* Not all are used (yet), or are interesting to us (yet).
*/
/* Things of interest in the CSR.
*/
#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */
#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */
#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable */
#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */
#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 == enable */
#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 == enable */
#define PHY_INTERRUPT SIU_INT_IRQ7
#ifdef CONFIG_PCI
/* PCI interrupt controller */
#define PCI_INT_STAT_REG 0xF8200000
#define PCI_INT_MASK_REG 0xF8200004
#define PIRQA (NR_SIU_INTS + 0)
#define PIRQB (NR_SIU_INTS + 1)
#define PIRQC (NR_SIU_INTS + 2)
#define PIRQD (NR_SIU_INTS + 3)
/*
* PCI memory map definitions for MPC8266ADS-PCI.
*
* processor view
* local address PCI address target
* 0x80000000-0x9FFFFFFF 0x80000000-0x9FFFFFFF PCI mem with prefetch
* 0xA0000000-0xBFFFFFFF 0xA0000000-0xBFFFFFFF PCI mem w/o prefetch
* 0xF4000000-0xF7FFFFFF 0x00000000-0x03FFFFFF PCI IO
*
* PCI master view
* local address PCI address target
* 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory
*/
/* window for a PCI master to access MPC8266 memory */
#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */
#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */
/* window for the processor to access PCI memory with prefetching */
#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */
#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */
#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */
/* window for the processor to access PCI memory without prefetching */
#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */
#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */
#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */
/* window for the processor to access PCI I/O */
#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */
#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */
#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */
#define _IO_BASE PCI_MSTR_IO_LOCAL
#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL
#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS
#endif /* CONFIG_PCI */
#endif /* __MACH_ADS8260_DEFS */
#endif /* __KERNEL__ */
/*
* arch/ppc/platforms/pq2ads_setup.c
*
* PQ2ADS platform support
*
* Author: Kumar Gala <kumar.gala@freescale.com>
* Derived from: est8260_setup.c by Allen Curtis
*
* Copyright 2004 Freescale Semiconductor, Inc.
*
* 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.
*/
#include <linux/config.h>
#include <linux/seq_file.h>
#include <asm/mpc8260.h>
#include <asm/machdep.h>
static void (*callback_setup_arch)(void);
extern unsigned char __res[sizeof(bd_t)];
extern void m8260_init(unsigned long r3, unsigned long r4,
unsigned long r5, unsigned long r6, unsigned long r7);
static int
pq2ads_show_cpuinfo(struct seq_file *m)
{
bd_t *binfo = (bd_t *)__res;
seq_printf(m, "vendor\t\t: Motorola\n"
"machine\t\t: PQ2 ADS PowerPC\n"
"\n"
"mem size\t\t: 0x%08lx\n"
"console baud\t\t: %ld\n"
"\n",
binfo->bi_memsize,
binfo->bi_baudrate);
return 0;
}
static void __init
pq2ads_setup_arch(void)
{
printk("PQ2 ADS Port\n");
callback_setup_arch();
*(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2;
}
void __init
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
/* Generic 8260 platform initialization */
m8260_init(r3, r4, r5, r6, r7);
/* Anything special for this platform */
ppc_md.show_cpuinfo = pq2ads_show_cpuinfo;
callback_setup_arch = ppc_md.setup_arch;
ppc_md.setup_arch = pq2ads_setup_arch;
}
......@@ -32,7 +32,7 @@ extern bd_t m8xx_board_info;
* We just map a few things we need. The CSR is actually 4 byte-wide
* registers that can be accessed as 8-, 16-, or 32-bit values.
*/
#define IMAP_ADDR ((uint)0xf0000000)
#define CPM_MAP_ADDR ((uint)0xf0000000)
#define RPX_CSR_ADDR ((uint)0xfa000000)
#define RPX_CSR_SIZE ((uint)(512 * 1024))
#define RPX_NVRTC_ADDR ((uint)0xfa080000)
......
......@@ -18,14 +18,18 @@
#include <linux/config.h>
#include <linux/seq_file.h>
#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/mpc8260.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/todc.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/pci.h>
static void (*callback_setup_arch)(void);
static void (*callback_init_IRQ)(void);
extern unsigned char __res[sizeof(bd_t)];
......@@ -57,6 +61,7 @@ sbc82xx_setup_arch(void)
callback_setup_arch();
}
#ifdef CONFIG_GEN_RTC
TODC_ALLOC();
/*
......@@ -64,16 +69,17 @@ TODC_ALLOC();
* directly use ioremap() at that time.
* late_time_init() is call after paging init.
*/
#ifdef CONFIG_GEN_RTC
static void sbc82xx_time_init(void)
{
volatile memctl8260_t *mc = &immr->im_memctl;
TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0);
volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
/* Set up CS11 for RTC chip */
mc->memc_br11=0;
mc->memc_or11=0xffff0836;
mc->memc_br11=0x80000801;
mc->memc_br11=SBC82xx_TODC_NVRAM_ADDR | 0x0801;
TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0);
todc_info->nvram_data =
(unsigned int)ioremap(todc_info->nvram_data, 0x2000);
......@@ -86,6 +92,152 @@ static void sbc82xx_time_init(void)
}
#endif /* CONFIG_GEN_RTC */
static volatile char *sbc82xx_i8259_map;
static char sbc82xx_i8259_mask = 0xff;
static spinlock_t sbc82xx_i8259_lock = SPIN_LOCK_UNLOCKED;
static void sbc82xx_i8259_mask_and_ack_irq(unsigned int irq_nr)
{
unsigned long flags;
irq_nr -= NR_SIU_INTS;
spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
sbc82xx_i8259_mask |= 1 << irq_nr;
(void) sbc82xx_i8259_map[1]; /* Dummy read */
sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
sbc82xx_i8259_map[0] = 0x20; /* OCW2: Non-specific EOI */
spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
}
static void sbc82xx_i8259_mask_irq(unsigned int irq_nr)
{
unsigned long flags;
irq_nr -= NR_SIU_INTS;
spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
sbc82xx_i8259_mask |= 1 << irq_nr;
sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
}
static void sbc82xx_i8259_unmask_irq(unsigned int irq_nr)
{
unsigned long flags;
irq_nr -= NR_SIU_INTS;
spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
sbc82xx_i8259_mask &= ~(1 << irq_nr);
sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
}
static void sbc82xx_i8259_end_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
&& irq_desc[irq].action)
sbc82xx_i8259_unmask_irq(irq);
}
struct hw_interrupt_type sbc82xx_i8259_ic = {
.typename = " i8259 ",
.enable = sbc82xx_i8259_unmask_irq,
.disable = sbc82xx_i8259_mask_irq,
.ack = sbc82xx_i8259_mask_and_ack_irq,
.end = sbc82xx_i8259_end_irq,
};
static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs)
{
spin_lock(&sbc82xx_i8259_lock);
sbc82xx_i8259_map[0] = 0x0c; /* OCW3: Read IR register on RD# pulse */
irq = sbc82xx_i8259_map[0] & 7; /* Read IRR */
if (irq == 7) {
/* Possible spurious interrupt */
int isr;
sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */
isr = sbc82xx_i8259_map[0]; /* Read ISR */
if (!(isr & 0x80)) {
printk(KERN_INFO "Spurious i8259 interrupt\n");
return IRQ_HANDLED;
}
}
ppc_irq_dispatch_handler(regs, NR_SIU_INTS + irq);
return IRQ_HANDLED;
}
void __init sbc82xx_init_IRQ(void)
{
volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
volatile intctl_cpm2_t *ic = &cpm2_immr->im_intctl;
int i;
callback_init_IRQ();
/* u-boot doesn't always set the board up correctly */
mc->memc_br5 = 0;
mc->memc_or5 = 0xfff00856;
mc->memc_br5 = 0x22000801;
sbc82xx_i8259_map = ioremap(0x22008000, 2);
if (!sbc82xx_i8259_map) {
printk(KERN_CRIT "Mapping i8259 interrupt controller failed\n");
return;
}
/* Set up the interrupt handlers for the i8259 IRQs */
for (i = NR_SIU_INTS; i < NR_SIU_INTS + 8; i++) {
irq_desc[i].handler = &sbc82xx_i8259_ic;
irq_desc[i].status |= IRQ_LEVEL;
}
/* make IRQ6 level sensitive */
ic->ic_siexr &= ~(1 << (14 - (SIU_INT_IRQ6 - SIU_INT_IRQ1)));
irq_desc[SIU_INT_IRQ6].status |= IRQ_LEVEL;
/* Initialise the i8259 */
sbc82xx_i8259_map[0] = 0x1b; /* ICW1: Level, no cascade, ICW4 */
sbc82xx_i8259_map[1] = 0x00; /* ICW2: vector base */
/* No ICW3 (no cascade) */
sbc82xx_i8259_map[1] = 0x01; /* ICW4: 8086 mode, normal EOI */
sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */
sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; /* Set interrupt mask */
/* Request cascade IRQ */
if (request_irq(SIU_INT_IRQ6, sbc82xx_i8259_demux, SA_INTERRUPT,
"i8259 demux", 0)) {
printk("Installation of i8259 IRQ demultiplexer failed.\n");
}
}
static int sbc82xx_pci_map_irq(struct pci_dev *dev, unsigned char idsel,
unsigned char pin)
{
static char pci_irq_table[][4] = {
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{ SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 16 - PMC slot */
{ SBC82xx_PC_IRQA, SBC82xx_PC_IRQB, -1, -1 }, /* IDSEL 17 - CardBus */
{ SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 18 - PCI-X bridge */
};
const long min_idsel = 16, max_idsel = 18, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
void __init
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
......@@ -101,7 +253,11 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.show_cpuinfo = sbc82xx_show_cpuinfo;
callback_setup_arch = ppc_md.setup_arch;
callback_init_IRQ = ppc_md.init_IRQ;
ppc_md.setup_arch = sbc82xx_setup_arch;
ppc_md.init_IRQ = sbc82xx_init_IRQ;
ppc_md.pci_map_irq = sbc82xx_pci_map_irq;
#ifdef CONFIG_GEN_RTC
ppc_md.time_init = NULL;
ppc_md.get_rtc_time = NULL;
......
......@@ -9,10 +9,9 @@
#include <asm/ppcboot.h>
#define IMAP_ADDR 0xf0000000
#define CPM_MAP_ADDR 0xf0000000
#define SBC82xx_TODC_NVRAM_ADDR 0x80000000
#define SBC82xx_TODC_NVRAM_ADDR 0xd0000000
#define SBC82xx_MACADDR_NVRAM_FCC1 0x220000c9 /* JP6B */
#define SBC82xx_MACADDR_NVRAM_SCC1 0x220000cf /* JP6A */
......@@ -21,4 +20,13 @@
#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
#define SBC82xx_PC_IRQA (NR_SIU_INTS+0)
#define SBC82xx_PC_IRQB (NR_SIU_INTS+1)
#define SBC82xx_MPC185_IRQ (NR_SIU_INTS+2)
#define SBC82xx_ATM_IRQ (NR_SIU_INTS+3)
#define SBC82xx_PIRQA (NR_SIU_INTS+4)
#define SBC82xx_PIRQB (NR_SIU_INTS+5)
#define SBC82xx_PIRQC (NR_SIU_INTS+6)
#define SBC82xx_PIRQD (NR_SIU_INTS+7)
#endif /* __PPC_SBC82xx_H__ */
......@@ -5,7 +5,7 @@
* the configuration SCMR and the Power-On-Reset word.
*/
#define IMAP_ADDR ((uint)0xfe000000)
#define CPM_MAP_ADDR ((uint)0xfe000000)
/* A Board Information structure that is given to a program when
......
......@@ -11,7 +11,7 @@
#include <asm/ppcboot.h>
#define IMAP_ADDR ((uint)0xFFF00000)
#define CPM_MAP_ADDR ((uint)0xFFF00000)
#define PHY_INTERRUPT 25
#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
......
......@@ -17,7 +17,7 @@
#include <linux/config.h>
#include <linux/seq_file.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include <asm/machdep.h>
......@@ -44,8 +44,8 @@ tqm8260_show_cpuinfo(struct seq_file *m)
static int
tqm8260_set_rtc_time(unsigned long time)
{
((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt = time;
((immap_t *)IMAP_ADDR)->im_sit.sit_tmcntsc = 0x3;
((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt = time;
((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcntsc = 0x3;
return(0);
}
......@@ -53,7 +53,7 @@ tqm8260_set_rtc_time(unsigned long time)
static unsigned long
tqm8260_get_rtc_time(void)
{
return ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt;
return ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt;
}
static void __init
......
......@@ -69,7 +69,10 @@ obj-$(CONFIG_SANDPOINT) += i8259.o open_pic.o pci_auto.o todc_time.o
obj-$(CONFIG_SBC82xx) += todc_time.o
obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \
todc_time.o
obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o
obj-$(CONFIG_8260) += m8260_setup.o cpm2_pic.o
obj-$(CONFIG_PCI_8260) += m8260_pci.o indirect_pci.o
obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o
obj-$(CONFIG_CPM2) += cpm2_common.o
ifeq ($(CONFIG_PPC_GEN550),y)
obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o
obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o
......
......@@ -26,29 +26,26 @@
#include <asm/mpc8260.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/immap_8260.h>
#include <asm/cpm_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/cpm2.h>
static uint dp_alloc_base; /* Starting offset in DP ram */
static uint dp_alloc_top; /* Max offset + 1 */
static uint host_buffer; /* One page of host buffer */
static uint host_end; /* end + 1 */
cpm8260_t *cpmp; /* Pointer to comm processor space */
cpm_cpm2_t *cpmp; /* Pointer to comm processor space */
/* We allocate this here because it is used almost exclusively for
* the communication processor devices.
*/
immap_t *immr;
cpm2_map_t *cpm2_immr;
void
m8260_cpm_reset(void)
cpm2_reset(void)
{
volatile immap_t *imp;
volatile cpm8260_t *commproc;
uint vpgaddr;
uint vpgaddr;
immr = imp = (volatile immap_t *)IMAP_ADDR;
commproc = &imp->im_cpm;
cpm2_immr = (cpm2_map_t *)CPM_MAP_ADDR;
/* Reclaim the DP memory for our use.
*/
......@@ -65,7 +62,7 @@ m8260_cpm_reset(void)
/* Tell everyone where the comm processor resides.
*/
cpmp = (cpm8260_t *)commproc;
cpmp = &cpm2_immr->im_cpm;
}
/* Allocate some memory from the dual ported ram.
......@@ -73,7 +70,7 @@ m8260_cpm_reset(void)
* if they ask.
*/
uint
m8260_cpm_dpalloc(uint size, uint align)
cpm2_dpalloc(uint size, uint align)
{
uint retloc;
uint align_mask, off;
......@@ -100,7 +97,7 @@ m8260_cpm_dpalloc(uint size, uint align)
* UART "fifos" and the like.
*/
uint
m8260_cpm_hostalloc(uint size, uint align)
cpm2_hostalloc(uint size, uint align)
{
uint retloc;
uint align_mask, off;
......@@ -140,17 +137,17 @@ m8260_cpm_hostalloc(uint size, uint align)
* oversampled clock.
*/
void
m8260_cpm_setbrg(uint brg, uint rate)
cpm2_setbrg(uint brg, uint rate)
{
volatile uint *bp;
/* This is good enough to get SMCs running.....
*/
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
bp = (uint *)&cpm2_immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
bp = (uint *)&cpm2_immr->im_brgc5;
brg -= 4;
}
bp += brg;
......@@ -161,15 +158,15 @@ m8260_cpm_setbrg(uint brg, uint rate)
* clocks.
*/
void
m8260_cpm_fastbrg(uint brg, uint rate, int div16)
cpm2_fastbrg(uint brg, uint rate, int div16)
{
volatile uint *bp;
if (brg < 4) {
bp = (uint *)&immr->im_brgc1;
bp = (uint *)&cpm2_immr->im_brgc1;
}
else {
bp = (uint *)&immr->im_brgc5;
bp = (uint *)&cpm2_immr->im_brgc5;
brg -= 4;
}
bp += brg;
......
......@@ -3,11 +3,11 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <asm/irq.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include "ppc8260_pic.h"
#include "cpm2_pic.h"
/* The 8260 internal interrupt controller. It is usually
/* The CPM2 internal interrupt controller. It is usually
* the only interrupt controller.
* There are two 32-bit registers (high/low) for up to 64
* possible interrupts.
......@@ -40,7 +40,7 @@ static u_char irq_to_siubit[] = {
7, 6, 5, 4, 3, 2, 1, 0
};
static void m8260_mask_irq(unsigned int irq_nr)
static void cpm2_mask_irq(unsigned int irq_nr)
{
int bit, word;
volatile uint *simr;
......@@ -48,12 +48,12 @@ static void m8260_mask_irq(unsigned int irq_nr)
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
simr = &(immr->im_intctl.ic_simrh);
simr = &(cpm2_immr->im_intctl.ic_simrh);
ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
simr[word] = ppc_cached_irq_mask[word];
}
static void m8260_unmask_irq(unsigned int irq_nr)
static void cpm2_unmask_irq(unsigned int irq_nr)
{
int bit, word;
volatile uint *simr;
......@@ -61,12 +61,12 @@ static void m8260_unmask_irq(unsigned int irq_nr)
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
simr = &(immr->im_intctl.ic_simrh);
simr = &(cpm2_immr->im_intctl.ic_simrh);
ppc_cached_irq_mask[word] |= (1 << (31 - bit));
simr[word] = ppc_cached_irq_mask[word];
}
static void m8260_mask_and_ack(unsigned int irq_nr)
static void cpm2_mask_and_ack(unsigned int irq_nr)
{
int bit, word;
volatile uint *simr, *sipnr;
......@@ -74,14 +74,14 @@ static void m8260_mask_and_ack(unsigned int irq_nr)
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
simr = &(immr->im_intctl.ic_simrh);
sipnr = &(immr->im_intctl.ic_sipnrh);
simr = &(cpm2_immr->im_intctl.ic_simrh);
sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
simr[word] = ppc_cached_irq_mask[word];
sipnr[word] = 1 << (31 - bit);
}
static void m8260_end_irq(unsigned int irq_nr)
static void cpm2_end_irq(unsigned int irq_nr)
{
int bit, word;
volatile uint *simr;
......@@ -92,33 +92,33 @@ static void m8260_end_irq(unsigned int irq_nr)
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
simr = &(immr->im_intctl.ic_simrh);
simr = &(cpm2_immr->im_intctl.ic_simrh);
ppc_cached_irq_mask[word] |= (1 << (31 - bit));
simr[word] = ppc_cached_irq_mask[word];
}
}
struct hw_interrupt_type ppc8260_pic = {
" 8260 SIU ",
struct hw_interrupt_type cpm2_pic = {
" CPM2 SIU ",
NULL,
NULL,
m8260_unmask_irq,
m8260_mask_irq,
m8260_mask_and_ack,
m8260_end_irq,
cpm2_unmask_irq,
cpm2_mask_irq,
cpm2_mask_and_ack,
cpm2_end_irq,
0
};
int
m8260_get_irq(struct pt_regs *regs)
cpm2_get_irq(struct pt_regs *regs)
{
int irq;
unsigned long bits;
/* For MPC8260, read the SIVEC register and shift the bits down
/* For CPM2, read the SIVEC register and shift the bits down
* to get the irq number. */
bits = immr->im_intctl.ic_sivec;
bits = cpm2_immr->im_intctl.ic_sivec;
irq = bits >> 26;
if (irq == 0)
......
#ifndef _PPC_KERNEL_CPM2_H
#define _PPC_KERNEL_CPM2_H
#include <linux/irq.h>
extern struct hw_interrupt_type cpm2_pic;
void cpm2_pic_init(void);
void cpm2_do_IRQ(struct pt_regs *regs,
int cpu);
int cpm2_get_irq(struct pt_regs *regs);
#endif /* _PPC_KERNEL_CPM2_H */
/*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2004 Red Hat, Inc.
*
* 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 <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include "m8260_pci.h"
/* PCI bus configuration registers.
*/
static void __init m8260_setup_pci(struct pci_controller *hose)
{
volatile cpm2_map_t *immap = cpm2_immr;
unsigned long pocmr;
u16 tempShort;
#ifndef CONFIG_ATC /* already done in U-Boot */
/*
* Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
* and local bus for PCI (SIUMCR [LBPC]).
*/
immap->im_siu_conf.siu_82xx.sc_siumcr = 0x00640000;
#endif
/* Make PCI lowest priority */
/* Each 4 bits is a device bus request and the MS 4bits
is highest priority */
/* Bus 4bit value
--- ----------
CPM high 0b0000
CPM middle 0b0001
CPM low 0b0010
PCI reguest 0b0011
Reserved 0b0100
Reserved 0b0101
Internal Core 0b0110
External Master 1 0b0111
External Master 2 0b1000
External Master 3 0b1001
The rest are reserved */
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
/* Park bus on core while modifying PCI Bus accesses */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = 0x6;
/*
* Set up master window that allows the CPU to access PCI space. This
* window is set up using the first SIU PCIBR registers.
*/
immap->im_memctl.memc_pcimsk0 = MPC826x_PCI_MASK;
immap->im_memctl.memc_pcibr0 = MPC826x_PCI_BASE | PCIBR_ENABLE;
/* Disable machine check on no response or target abort */
immap->im_pci.pci_emr = cpu_to_le32(0x1fe7);
/* Release PCI RST (by default the PCI RST signal is held low) */
immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
/* give it some time */
mdelay(1);
/*
* Set up master window that allows the CPU to access PCI Memory (prefetch)
* space. This window is set up using the first set of Outbound ATU registers.
*/
immap->im_pci.pci_potar0 = cpu_to_le32(MPC826x_PCI_LOWER_MEM >> 12);
immap->im_pci.pci_pobar0 = cpu_to_le32((MPC826x_PCI_LOWER_MEM - MPC826x_PCI_MEM_OFFSET) >> 12);
pocmr = ((MPC826x_PCI_UPPER_MEM - MPC826x_PCI_LOWER_MEM) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr0 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PREFETCH_EN);
/*
* Set up master window that allows the CPU to access PCI Memory (non-prefetch)
* space. This window is set up using the second set of Outbound ATU registers.
*/
immap->im_pci.pci_potar1 = cpu_to_le32(MPC826x_PCI_LOWER_MMIO >> 12);
immap->im_pci.pci_pobar1 = cpu_to_le32((MPC826x_PCI_LOWER_MMIO - MPC826x_PCI_MMIO_OFFSET) >> 12);
pocmr = ((MPC826x_PCI_UPPER_MMIO - MPC826x_PCI_LOWER_MMIO) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr1 = cpu_to_le32(pocmr | POCMR_ENABLE);
/*
* Set up master window that allows the CPU to access PCI IO space. This window
* is set up using the third set of Outbound ATU registers.
*/
immap->im_pci.pci_potar2 = cpu_to_le32(MPC826x_PCI_IO_BASE >> 12);
immap->im_pci.pci_pobar2 = cpu_to_le32(MPC826x_PCI_LOWER_IO >> 12);
pocmr = ((MPC826x_PCI_UPPER_IO - MPC826x_PCI_LOWER_IO) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr2 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PCI_IO);
/*
* Set up slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
immap->im_pci.pci_pitar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_LOCAL >> 12);
immap->im_pci.pci_pibar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_BUS >> 12);
pocmr = ((MPC826x_PCI_SLAVE_MEM_SIZE-1) >> 12) ^ 0xfffff;
immap->im_pci.pci_picmr0 = cpu_to_le32(pocmr | PICMR_ENABLE | PICMR_PREFETCH_EN);
/* See above for description - puts PCI request as highest priority */
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
/* Park the bus on the PCI */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
/* Host mode - specify the bridge as a host-PCI bridge */
early_write_config_word(hose, 0, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_HOST);
/* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
early_read_config_word(hose, 0, 0, PCI_COMMAND, &tempShort);
early_write_config_word(hose, 0, 0, PCI_COMMAND,
tempShort | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
}
void __init m8260_find_bridges(void)
{
extern int pci_assign_all_busses;
struct pci_controller * hose;
pci_assign_all_busses = 1;
hose = pcibios_alloc_controller();
if (!hose)
return;
ppc_md.pci_swizzle = common_swizzle;
hose->first_busno = 0;
hose->bus_offset = 0;
hose->last_busno = 0xff;
setup_m8260_indirect_pci(hose,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
m8260_setup_pci(hose);
hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET;
isa_io_base =
(unsigned long) ioremap(MPC826x_PCI_IO_BASE,
MPC826x_PCI_IO_SIZE);
hose->io_base_virt = (void *) isa_io_base;
/* setup resources */
pci_init_resource(&hose->mem_resources[0],
MPC826x_PCI_LOWER_MEM,
MPC826x_PCI_UPPER_MEM,
IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
pci_init_resource(&hose->mem_resources[1],
MPC826x_PCI_LOWER_MMIO,
MPC826x_PCI_UPPER_MMIO,
IORESOURCE_MEM, "PCI memory");
pci_init_resource(&hose->io_resource,
MPC826x_PCI_LOWER_IO,
MPC826x_PCI_UPPER_IO,
IORESOURCE_IO, "PCI I/O");
}
#ifndef _PPC_KERNEL_M8260_PCI_H
#define _PPC_KERNEL_M8260_PCI_H
#include <asm/m8260_pci.h>
/*
* Local->PCI map (from CPU) controlled by
* MPC826x master window
*
* 0x80000000 - 0xBFFFFFFF Total CPU2PCI space PCIBR0
*
* 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1)
* 0xA0000000 - 0xAFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2)
* 0xB0000000 - 0xB0FFFFFF 32-bit PCI IO (Outbound ATU #3)
*
* PCI->Local map (from PCI)
* MPC826x slave window controlled by
*
* 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1)
*/
/*
* Slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
#ifndef MPC826x_PCI_SLAVE_MEM_LOCAL
#define MPC826x_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart)
#define MPC826x_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart)
#define MPC826x_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize)
#endif
/*
* This is the window that allows the CPU to access PCI address space.
* It will be setup with the SIU PCIBR0 register. All three PCI master
* windows, which allow the CPU to access PCI prefetch, non prefetch,
* and IO space (see below), must all fit within this window.
*/
#ifndef MPC826x_PCI_BASE
#define MPC826x_PCI_BASE 0x80000000
#define MPC826x_PCI_MASK 0xc0000000
#endif
#ifndef MPC826x_PCI_LOWER_MEM
#define MPC826x_PCI_LOWER_MEM 0x80000000
#define MPC826x_PCI_UPPER_MEM 0x9fffffff
#define MPC826x_PCI_MEM_OFFSET 0x00000000
#endif
#ifndef MPC826x_PCI_LOWER_MMIO
#define MPC826x_PCI_LOWER_MMIO 0xa0000000
#define MPC826x_PCI_UPPER_MMIO 0xafffffff
#define MPC826x_PCI_MMIO_OFFSET 0x00000000
#endif
#ifndef MPC826x_PCI_LOWER_IO
#define MPC826x_PCI_LOWER_IO 0x00000000
#define MPC826x_PCI_UPPER_IO 0x00ffffff
#define MPC826x_PCI_IO_BASE 0xb0000000
#define MPC826x_PCI_IO_SIZE 0x01000000
#endif
#ifndef _IO_BASE
#define _IO_BASE isa_io_base
#endif
#ifdef CONFIG_8260_PCI9
extern void setup_m8260_indirect_pci(struct pci_controller* hose,
u32 cfg_addr, u32 cfg_data);
#else
#define setup_m8260_indirect_pci setup_indirect_pci
#endif
#endif /* _PPC_KERNEL_M8260_PCI_H */
/*
* arch/ppc/platforms/mpc8260_pci9.c
*
* Workaround for device erratum PCI 9.
* See Motorola's "XPC826xA Family Device Errata Reference."
* The erratum applies to all 8260 family Hip4 processors. It is scheduled
* to be fixed in HiP4 Rev C. Erratum PCI 9 states that a simultaneous PCI
* inbound write transaction and PCI outbound read transaction can result in a
* bus deadlock. The suggested workaround is to use the IDMA controller to
* perform all reads from PCI configuration, memory, and I/O space.
*
* Author: andy_lowe@mvista.com
*
* 2003 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/byteorder.h>
#include <asm/mpc8260.h>
#include <asm/immap_cpm2.h>
#include <asm/cpm2.h>
#include "m8260_pci.h"
#ifdef CONFIG_8260_PCI9
/*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
#define IDMA_XFER_BUF_SIZE 64 /* size of the IDMA transfer buffer */
/* define a structure for the IDMA dpram usage */
typedef struct idma_dpram_s {
idma_t pram; /* IDMA parameter RAM */
u_char xfer_buf[IDMA_XFER_BUF_SIZE]; /* IDMA transfer buffer */
idma_bd_t bd; /* buffer descriptor */
} idma_dpram_t;
/* define offsets relative to start of IDMA dpram */
#define IDMA_XFER_BUF_OFFSET (sizeof(idma_t))
#define IDMA_BD_OFFSET (sizeof(idma_t) + IDMA_XFER_BUF_SIZE)
/* define globals */
static volatile idma_dpram_t *idma_dpram;
/* Exactly one of CONFIG_8260_PCI9_IDMAn must be defined,
* where n is 1, 2, 3, or 4. This selects the IDMA channel used for
* the PCI9 workaround.
*/
#ifdef CONFIG_8260_PCI9_IDMA1
#define IDMA_CHAN 0
#define PROFF_IDMA PROFF_IDMA1_BASE
#define IDMA_PAGE CPM_CR_IDMA1_PAGE
#define IDMA_SBLOCK CPM_CR_IDMA1_SBLOCK
#endif
#ifdef CONFIG_8260_PCI9_IDMA2
#define IDMA_CHAN 1
#define PROFF_IDMA PROFF_IDMA2_BASE
#define IDMA_PAGE CPM_CR_IDMA2_PAGE
#define IDMA_SBLOCK CPM_CR_IDMA2_SBLOCK
#endif
#ifdef CONFIG_8260_PCI9_IDMA3
#define IDMA_CHAN 2
#define PROFF_IDMA PROFF_IDMA3_BASE
#define IDMA_PAGE CPM_CR_IDMA3_PAGE
#define IDMA_SBLOCK CPM_CR_IDMA3_SBLOCK
#endif
#ifdef CONFIG_8260_PCI9_IDMA4
#define IDMA_CHAN 3
#define PROFF_IDMA PROFF_IDMA4_BASE
#define IDMA_PAGE CPM_CR_IDMA4_PAGE
#define IDMA_SBLOCK CPM_CR_IDMA4_SBLOCK
#endif
void idma_pci9_init(void)
{
uint dpram_offset;
volatile idma_t *pram;
volatile im_idma_t *idma_reg;
volatile cpm2_map_t *immap = cpm2_immr;
/* allocate IDMA dpram */
dpram_offset = cpm2_dpalloc(sizeof(idma_dpram_t), 64);
idma_dpram =
(volatile idma_dpram_t *)&immap->im_dprambase[dpram_offset];
/* initialize the IDMA parameter RAM */
memset((void *)idma_dpram, 0, sizeof(idma_dpram_t));
pram = &idma_dpram->pram;
pram->ibase = dpram_offset + IDMA_BD_OFFSET;
pram->dpr_buf = dpram_offset + IDMA_XFER_BUF_OFFSET;
pram->ss_max = 32;
pram->dts = 32;
/* initialize the IDMA_BASE pointer to the IDMA parameter RAM */
*((ushort *) &immap->im_dprambase[PROFF_IDMA]) = dpram_offset;
/* initialize the IDMA registers */
idma_reg = (volatile im_idma_t *) &immap->im_sdma.sdma_idsr1;
idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */
idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */
printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
IDMA_CHAN + 1);
return;
}
/* Use the IDMA controller to transfer data from I/O memory to local RAM.
* The src address must be a physical address suitable for use by the DMA
* controller with no translation. The dst address must be a kernel virtual
* address. The dst address is translated to a physical address via
* virt_to_phys().
* The sinc argument specifies whether or not the source address is incremented
* by the DMA controller. The source address is incremented if and only if sinc
* is non-zero. The destination address is always incremented since the
* destination is always host RAM.
*/
static void
idma_pci9_read(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
{
unsigned long flags;
volatile idma_t *pram = &idma_dpram->pram;
volatile idma_bd_t *bd = &idma_dpram->bd;
volatile cpm2_map_t *immap = cpm2_immr;
local_irq_save(flags);
/* initialize IDMA parameter RAM for this transfer */
if (sinc)
pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
| IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
else
pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_DINC
| IDMA_DCM_SD_MEM2MEM;
pram->ibdptr = pram->ibase;
pram->sts = unit_size;
pram->istate = 0;
/* initialize the buffer descriptor */
bd->dst = virt_to_phys(dst);
bd->src = (uint) src;
bd->len = bytes;
bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
| IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
/* issue the START_IDMA command to the CP */
while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
CPM_CR_START_IDMA) | CPM_CR_FLG;
while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
/* wait for transfer to complete */
while(bd->flags & IDMA_BD_V);
local_irq_restore(flags);
return;
}
/* Use the IDMA controller to transfer data from I/O memory to local RAM.
* The dst address must be a physical address suitable for use by the DMA
* controller with no translation. The src address must be a kernel virtual
* address. The src address is translated to a physical address via
* virt_to_phys().
* The dinc argument specifies whether or not the dest address is incremented
* by the DMA controller. The source address is incremented if and only if sinc
* is non-zero. The source address is always incremented since the
* source is always host RAM.
*/
static void
idma_pci9_write(u8 *dst, u8 *src, int bytes, int unit_size, int dinc)
{
unsigned long flags;
volatile idma_t *pram = &idma_dpram->pram;
volatile idma_bd_t *bd = &idma_dpram->bd;
volatile cpm2_map_t *immap = cpm2_immr;
local_irq_save(flags);
/* initialize IDMA parameter RAM for this transfer */
if (dinc)
pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
| IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
else
pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
| IDMA_DCM_SD_MEM2MEM;
pram->ibdptr = pram->ibase;
pram->sts = unit_size;
pram->istate = 0;
/* initialize the buffer descriptor */
bd->dst = (uint) dst;
bd->src = virt_to_phys(src);
bd->len = bytes;
bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
| IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
/* issue the START_IDMA command to the CP */
while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
CPM_CR_START_IDMA) | CPM_CR_FLG;
while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
/* wait for transfer to complete */
while(bd->flags & IDMA_BD_V);
local_irq_restore(flags);
return;
}
/* Same as idma_pci9_read, but 16-bit little-endian byte swapping is performed
* if the unit_size is 2, and 32-bit little-endian byte swapping is performed if
* the unit_size is 4.
*/
static void
idma_pci9_read_le(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
{
int i;
u8 *p;
idma_pci9_read(dst, src, bytes, unit_size, sinc);
switch(unit_size) {
case 2:
for (i = 0, p = dst; i < bytes; i += 2, p += 2)
swab16s((u16 *) p);
break;
case 4:
for (i = 0, p = dst; i < bytes; i += 4, p += 4)
swab32s((u32 *) p);
break;
default:
break;
}
}
EXPORT_SYMBOL(idma_pci9_init);
EXPORT_SYMBOL(idma_pci9_read);
EXPORT_SYMBOL(idma_pci9_read_le);
static inline int is_pci_mem(unsigned long addr)
{
if (addr >= MPC826x_PCI_LOWER_MMIO &&
addr <= MPC826x_PCI_UPPER_MMIO)
return 1;
if (addr >= MPC826x_PCI_LOWER_MEM &&
addr <= MPC826x_PCI_UPPER_MEM)
return 1;
return 0;
}
#define is_pci_mem(pa) ( (pa > 0x80000000) && (pa < 0xc0000000))
int readb(volatile unsigned char *addr)
{
u8 val;
unsigned long pa = iopa((unsigned long) addr);
if (!is_pci_mem(pa))
return in_8(addr);
idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
return val;
}
int readw(volatile unsigned short *addr)
{
u16 val;
unsigned long pa = iopa((unsigned long) addr);
if (!is_pci_mem(pa))
return in_le16(addr);
idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
return swab16(val);
}
unsigned readl(volatile unsigned *addr)
{
u32 val;
unsigned long pa = iopa((unsigned long) addr);
if (!is_pci_mem(pa))
return in_le32(addr);
idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
return swab32(val);
}
int inb(unsigned port)
{
u8 val;
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
return val;
}
int inw(unsigned port)
{
u16 val;
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
return swab16(val);
}
unsigned inl(unsigned port)
{
u32 val;
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
return swab32(val);
}
void insb(unsigned port, void *buf, int ns)
{
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u8), sizeof(u8), 0);
}
void insw(unsigned port, void *buf, int ns)
{
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
}
void insl(unsigned port, void *buf, int nl)
{
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
}
void insw_ns(unsigned port, void *buf, int ns)
{
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
}
void insl_ns(unsigned port, void *buf, int nl)
{
u8 *addr = (u8 *)(port + _IO_BASE);
idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
}
void *memcpy_fromio(void *dest, unsigned long src, size_t count)
{
unsigned long pa = iopa((unsigned long) src);
if (is_pci_mem(pa))
idma_pci9_read((u8 *)dest, (u8 *)pa, count, 32, 1);
else
memcpy(dest, (void *)src, count);
return dest;
}
EXPORT_SYMBOL(readb);
EXPORT_SYMBOL(readw);
EXPORT_SYMBOL(readl);
EXPORT_SYMBOL(inb);
EXPORT_SYMBOL(inw);
EXPORT_SYMBOL(inl);
EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
EXPORT_SYMBOL(insw_ns);
EXPORT_SYMBOL(insl_ns);
EXPORT_SYMBOL(memcpy_fromio);
#endif /* ifdef CONFIG_8260_PCI9 */
/* Indirect PCI routines adapted from arch/ppc/kernel/indirect_pci.c.
* Copyright (C) 1998 Gabriel Paubert.
*/
#ifndef CONFIG_8260_PCI9
#define cfg_read(val, addr, type, op) *val = op((type)(addr))
#else
#define cfg_read(val, addr, type, op) \
idma_pci9_read_le((u8*)(val),(u8*)(addr),sizeof(*(val)),sizeof(*(val)),0)
#endif
#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
static int indirect_write_config(struct pci_bus *pbus, unsigned int devfn, int where,
int size, u32 value)
{
struct pci_controller *hose = pbus->sysdata;
u8 cfg_type = 0;
if (ppc_md.pci_exclude_device)
if (ppc_md.pci_exclude_device(pbus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
if (hose->set_cfg_type)
if (pbus->number != hose->first_busno)
cfg_type = 1;
out_be32(hose->cfg_addr,
(((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
| ((pbus->number - hose->bus_offset) << 8) | 0x80);
switch (size)
{
case 1:
cfg_write(value, hose->cfg_data + (where & 3), u8, out_8);
break;
case 2:
cfg_write(value, hose->cfg_data + (where & 2), u16, out_le16);
break;
case 4:
cfg_write(value, hose->cfg_data + (where & 0), u32, out_le32);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int indirect_read_config(struct pci_bus *pbus, unsigned int devfn, int where,
int size, u32 *value)
{
struct pci_controller *hose = pbus->sysdata;
u8 cfg_type = 0;
if (ppc_md.pci_exclude_device)
if (ppc_md.pci_exclude_device(pbus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
if (hose->set_cfg_type)
if (pbus->number != hose->first_busno)
cfg_type = 1;
out_be32(hose->cfg_addr,
(((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
| ((pbus->number - hose->bus_offset) << 8) | 0x80);
switch (size)
{
case 1:
cfg_read(value, hose->cfg_data + (where & 3), u8 *, in_8);
break;
case 2:
cfg_read(value, hose->cfg_data + (where & 2), u16 *, in_le16);
break;
case 4:
cfg_read(value, hose->cfg_data + (where & 0), u32 *, in_le32);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops indirect_pci_ops =
{
.read = indirect_read_config,
.write = indirect_write_config,
};
void
setup_m8260_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
{
hose->ops = &indirect_pci_ops;
hose->cfg_addr = (unsigned int *) ioremap(cfg_addr, 4);
hose->cfg_data = (unsigned char *) ioremap(cfg_data, 4);
}
......@@ -39,12 +39,12 @@
#include <asm/pgtable.h>
#include <asm/ide.h>
#include <asm/mpc8260.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
#include <asm/machdep.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
#include "ppc8260_pic.h"
#include "cpm2_pic.h"
static int m8260_set_rtc_time(unsigned long time);
static unsigned long m8260_get_rtc_time(void);
......@@ -52,14 +52,23 @@ static void m8260_calibrate_decr(void);
unsigned char __res[sizeof(bd_t)];
extern void m8260_cpm_reset(void);
extern void cpm2_reset(void);
extern void m8260_find_bridges(void);
extern void idma_pci9_init(void);
static void __init
m8260_setup_arch(void)
{
/* Reset the Communication Processor Module.
*/
m8260_cpm_reset();
cpm2_reset();
#ifdef CONFIG_8260_PCI9
/* Initialise IDMA for PCI erratum workaround */
idma_pci9_init();
#endif
#ifdef CONFIG_PCI_8260
m8260_find_bridges();
#endif
}
/* The decrementer counts at the system (internal) clock frequency
......@@ -142,9 +151,9 @@ m8260_show_percpuinfo(struct seq_file *m, int i)
bp = (bd_t *)__res;
seq_printf(m, "core clock\t: %d MHz\n"
"CPM clock\t: %d MHz\n"
"bus clock\t: %d MHz\n",
seq_printf(m, "core clock\t: %ld MHz\n"
"CPM clock\t: %ld MHz\n"
"bus clock\t: %ld MHz\n",
bp->bi_intfreq / 1000000,
bp->bi_cpmfreq / 1000000,
bp->bi_busfreq / 1000000);
......@@ -164,15 +173,15 @@ m8260_init_IRQ(void)
void cpm_interrupt_init(void);
for ( i = 0 ; i < NR_SIU_INTS ; i++ )
irq_desc[i].handler = &ppc8260_pic;
irq_desc[i].handler = &cpm2_pic;
/* Initialize the default interrupt mapping priorities,
* in case the boot rom changed something on us.
*/
immr->im_intctl.ic_sicr = 0;
immr->im_intctl.ic_siprr = 0x05309770;
immr->im_intctl.ic_scprrh = 0x05309770;
immr->im_intctl.ic_scprrl = 0x05309770;
cpm2_immr->im_intctl.ic_sicr = 0;
cpm2_immr->im_intctl.ic_siprr = 0x05309770;
cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
}
/*
......@@ -200,7 +209,7 @@ m8260_map_io(void)
uint addr;
/* Map IMMR region to a 256MB BAT */
addr = (immr != NULL) ? (uint)immr : IMAP_ADDR;
addr = (cpm2_immr != NULL) ? (uint)cpm2_immr : CPM_MAP_ADDR;
io_block_mapping(addr, addr, 0x10000000, _PAGE_IO);
/* Map I/O region to a 256MB BAT */
......@@ -244,7 +253,7 @@ m8260_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.show_percpuinfo = m8260_show_percpuinfo;
ppc_md.irq_canonicalize = NULL;
ppc_md.init_IRQ = m8260_init_IRQ;
ppc_md.get_irq = m8260_get_irq;
ppc_md.get_irq = cpm2_get_irq;
ppc_md.init = NULL;
ppc_md.restart = m8260_restart;
......
#ifndef _PPC_KERNEL_PPC8260_H
#define _PPC_KERNEL_PPC8260_H
#include <linux/irq.h>
extern struct hw_interrupt_type ppc8260_pic;
void m8260_pic_init(void);
void m8260_do_IRQ(struct pt_regs *regs,
int cpu);
int m8260_get_irq(struct pt_regs *regs);
#endif /* _PPC_KERNEL_PPC8260_H */
......@@ -20,7 +20,7 @@
#include <linux/config.h>
#include <linux/mtd/partitions.h>
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
static struct mtd_info *sbcmtd[3];
static struct mtd_partition *sbcmtd_parts[3];
......@@ -59,7 +59,7 @@ static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
int __init init_sbc82xx_flash(void)
{
volatile memctl8260_t *mc = &immr->im_memctl;
volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
int bigflash;
int i;
......
......@@ -603,5 +603,65 @@ config SERIAL_PMACZILOG_CONSOLE
on your PowerMac as the console, you can do so by answering
Y to this option.
config SERIAL_CPM
tristate "CPM2 SCC/SMC serial port support"
depends on CPM2 || 8xx
select SERIAL_CORE
help
This driver supports the SCC and SMC serial ports on Motorola
embedded PowerPC that contain a CPM2 (8xxx) or a CPM1 (8xx)
config SERIAL_CPM_CONSOLE
bool "Support for console on CPM2 SCC/SMC serial port"
depends on SERIAL_CPM=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use a SCC or SMC CPM UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyCPM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_CPM_SCC1
bool "Support for SCC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC1 as a serial port
config SERIAL_CPM_SCC2
bool "Support for SCC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC2 as a serial port
config SERIAL_CPM_SCC3
bool "Support for SCC3 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC3 as a serial port
config SERIAL_CPM_SCC4
bool "Support for SCC4 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC4 as a serial port
config SERIAL_CPM_SMC1
bool "Support for SMC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC1 as a serial port
config SERIAL_CPM_SMC2
bool "Support for SMC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC2 as a serial port
endmenu
......@@ -38,3 +38,4 @@ obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_BAST_SIO) += bast_sio.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
#
# Makefile for the Motorola 8xx FEC ethernet controller
#
obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
# Select the correct platform objects.
cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o
cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o
cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y)
/*
* linux/drivers/serial/cpm_uart.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
*
*/
#ifndef CPM_UART_H
#define CPM_UART_H
#include <linux/config.h>
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
#elif defined(CONFIG_8xx)
#include "cpm_uart_cpm1.h"
#endif
#ifndef CONFIG_SERIAL_8250
#define SERIAL_CPM_MAJOR TTY_MAJOR
#define SERIAL_CPM_MINOR 64
#else
#define SERIAL_CPM_MAJOR 204
#define SERIAL_CPM_MINOR 42
#endif
#define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC)
#define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING)
#define FLAG_DISCARDING 0x00000004 /* when set, don't discard */
#define FLAG_SMC 0x00000002
#define FLAG_CONSOLE 0x00000001
#define UART_SMC1 0
#define UART_SMC2 1
#define UART_SCC1 2
#define UART_SCC2 3
#define UART_SCC3 4
#define UART_SCC4 5
#define UART_NR 6
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
#define TX_NUM_FIFO 4
#define TX_BUF_SIZE 32
struct uart_cpm_port {
struct uart_port port;
u16 rx_nrfifos;
u16 rx_fifosize;
u16 tx_nrfifos;
u16 tx_fifosize;
smc_t *smcp;
smc_uart_t *smcup;
scc_t *sccp;
scc_uart_t *sccup;
volatile cbd_t *rx_bd_base;
volatile cbd_t *rx_cur;
volatile cbd_t *tx_bd_base;
volatile cbd_t *tx_cur;
unsigned char *tx_buf;
unsigned char *rx_buf;
u32 flags;
void (*set_lineif)(struct uart_cpm_port *);
u8 brg;
uint dp_addr;
void *mem_addr;
dma_addr_t dma_addr;
/* helpers */
int baud;
int bits;
};
extern int cpm_uart_port_map[UART_NR];
extern int cpm_uart_nr;
extern struct uart_cpm_port cpm_uart_ports[UART_NR];
/* these are located in their respective files */
void cpm_line_cr_cmd(int line, int cmd);
int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
void smc1_lineif(struct uart_cpm_port *pinfo);
void smc2_lineif(struct uart_cpm_port *pinfo);
void scc1_lineif(struct uart_cpm_port *pinfo);
void scc2_lineif(struct uart_cpm_port *pinfo);
void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo);
#endif /* CPM_UART_H */
/*
* linux/drivers/serial/cpm_uart.c
*
* Driver for CPM (SCC/SMC) serial ports; core driver
*
* Based on arch/ppc/cpm2_io/uart.c by Dan Malek
* Based on ppc8xx.c by Thomas Gleixner
* Based on drivers/serial/amba.c by Russell King
*
* Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
*
* 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 <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/***********************************************************************/
/* Track which ports are configured as uarts */
int cpm_uart_port_map[UART_NR];
/* How many ports did we config as uarts */
int cpm_uart_nr;
/**************************************************************/
static int cpm_uart_tx_pump(struct uart_port *port);
static void cpm_uart_init_smc(struct uart_cpm_port *pinfo, int bits, u16 cval);
static void cpm_uart_init_scc(struct uart_cpm_port *pinfo, int sbits, u16 sval);
/**************************************************************/
/*
* Check, if transmit buffers are processed
*/
static unsigned int cpm_uart_tx_empty(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile cbd_t *bdp = pinfo->tx_bd_base;
int ret = 0;
while (1) {
if (bdp->cbd_sc & BD_SC_READY)
break;
if (bdp->cbd_sc & BD_SC_WRAP) {
ret = TIOCSER_TEMT;
break;
}
bdp++;
}
pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
return ret;
}
static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* Whee. Do nothing. */
}
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
{
/* Whee. Do nothing. */
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
/*
* Stop transmitter
*/
static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
volatile scc_t *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop tx\n", port->line);
if (IS_SMC(pinfo))
smcp->smc_smcm &= ~SMCM_TX;
else
sccp->scc_sccm &= ~UART_SCCM_TX;
}
/*
* Start transmitter
*/
static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
volatile scc_t *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:start tx\n", port->line);
/* if in the middle of discarding return */
if (IS_DISCARDING(pinfo))
return;
if (IS_SMC(pinfo)) {
if (smcp->smc_smcm & SMCM_TX)
return;
} else {
if (sccp->scc_sccm & UART_SCCM_TX)
return;
}
if (cpm_uart_tx_pump(port) != 0) {
if (IS_SMC(pinfo))
smcp->smc_smcm |= SMCM_TX;
else
sccp->scc_sccm |= UART_SCCM_TX;
}
}
/*
* Stop receiver
*/
static void cpm_uart_stop_rx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
volatile scc_t *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop rx\n", port->line);
if (IS_SMC(pinfo))
smcp->smc_smcm &= ~SMCM_RX;
else
sccp->scc_sccm &= ~UART_SCCM_RX;
}
/*
* Enable Modem status interrupts
*/
static void cpm_uart_enable_ms(struct uart_port *port)
{
pr_debug("CPM uart[%d]:enable ms\n", port->line);
}
/*
* Generate a break.
*/
static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
break_state);
if (break_state)
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_STOP_TX);
else
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_RESTART_TX);
}
/*
* Transmit characters, refill buffer descriptor, if possible
*/
static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs)
{
pr_debug("CPM uart[%d]:TX INT\n", port->line);
cpm_uart_tx_pump(port);
}
/*
* Receive characters
*/
static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
{
int i;
unsigned char ch, *cp;
struct tty_struct *tty = port->info->tty;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile cbd_t *bdp;
u16 status;
unsigned int flg;
pr_debug("CPM uart[%d]:RX INT\n", port->line);
/* Just loop through the closed BDs and copy the characters into
* the buffer.
*/
bdp = pinfo->rx_cur;
for (;;) {
/* get status */
status = bdp->cbd_sc;
/* If this one is empty, return happy */
if (status & BD_SC_EMPTY)
break;
/* get number of characters, and check spce in flip-buffer */
i = bdp->cbd_datlen;
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
*/
if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
tty->flip.work.func((void *)tty);
if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
printk(KERN_WARNING "TTY_DONT_FLIP set\n");
return;
}
}
/* get pointer */
cp = (unsigned char *)bus_to_virt(bdp->cbd_bufaddr);
/* loop through the buffer */
while (i-- > 0) {
ch = *cp++;
port->icount.rx++;
flg = TTY_NORMAL;
if (status &
(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
goto handle_error;
if (uart_handle_sysrq_char(port, ch, regs))
continue;
error_return:
*tty->flip.char_buf_ptr++ = ch;
*tty->flip.flag_buf_ptr++ = flg;
tty->flip.count++;
} /* End while (i--) */
/* This BD is ready to be used again. Clear status. get next */
bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
bdp->cbd_sc |= BD_SC_EMPTY;
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = pinfo->rx_bd_base;
else
bdp++;
} /* End for (;;) */
/* Write back buffer pointer */
pinfo->rx_cur = (volatile cbd_t *) bdp;
/* activate BH processing */
tty_flip_buffer_push(tty);
return;
/* Error processing */
handle_error:
/* Statistics */
if (status & BD_SC_BR)
port->icount.brk++;
if (status & BD_SC_PR)
port->icount.parity++;
if (status & BD_SC_FR)
port->icount.frame++;
if (status & BD_SC_OV)
port->icount.overrun++;
/* Mask out ignored conditions */
status &= port->read_status_mask;
/* Handle the remaining ones */
if (status & BD_SC_BR)
flg = TTY_BREAK;
else if (status & BD_SC_PR)
flg = TTY_PARITY;
else if (status & BD_SC_FR)
flg = TTY_FRAME;
/* overrun does not affect the current character ! */
if (status & BD_SC_OV) {
ch = 0;
flg = TTY_OVERRUN;
/* We skip this buffer */
/* CHECK: Is really nothing senseful there */
/* ASSUMPTION: it contains nothing valid */
i = 0;
}
#ifdef SUPPORT_SYSRQ
port->sysrq = 0;
#endif
goto error_return;
}
/*
* Asynchron mode interrupt handler
*/
static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs)
{
u8 events;
struct uart_port *port = (struct uart_port *)data;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile smc_t *smcp = pinfo->smcp;
volatile scc_t *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:IRQ\n", port->line);
if (IS_SMC(pinfo)) {
events = smcp->smc_smce;
if (events & SMCM_BRKE)
uart_handle_break(port);
if (events & SMCM_RX)
cpm_uart_int_rx(port, regs);
if (events & SMCM_TX)
cpm_uart_int_tx(port, regs);
smcp->smc_smce = events;
} else {
events = sccp->scc_scce;
if (events & UART_SCCM_BRKE)
uart_handle_break(port);
if (events & UART_SCCM_RX)
cpm_uart_int_rx(port, regs);
if (events & UART_SCCM_TX)
cpm_uart_int_tx(port, regs);
sccp->scc_scce = events;
}
return (events) ? IRQ_HANDLED : IRQ_NONE;
}
static int cpm_uart_startup(struct uart_port *port)
{
int retval;
pr_debug("CPM uart[%d]:startup\n", port->line);
/* Install interrupt handler. */
retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
if (retval)
return retval;
return 0;
}
/*
* Shutdown the uart
*/
static void cpm_uart_shutdown(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
pr_debug("CPM uart[%d]:shutdown\n", port->line);
/* free interrupt handler */
free_irq(port->irq, port);
/* If the port is not the console, disable Rx and Tx. */
if (!(pinfo->flags & FLAG_CONSOLE)) {
/* Stop uarts */
if (IS_SMC(pinfo)) {
volatile smc_t *smcp = pinfo->smcp;
smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
} else {
volatile scc_t *sccp = pinfo->sccp;
sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
}
/* Shut them really down and reinit buffer descriptors */
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_INIT_TRX);
}
}
static void cpm_uart_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old)
{
int baud;
unsigned long flags;
u16 cval, scval;
int bits, sbits;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
volatile cbd_t *bdp;
pr_debug("CPM uart[%d]:set_termios\n", port->line);
spin_lock_irqsave(&port->lock, flags);
/* disable uart interrupts */
if (IS_SMC(pinfo))
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
else
pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
pinfo->flags |= FLAG_DISCARDING;
spin_unlock_irqrestore(&port->lock, flags);
/* if previous configuration exists wait for tx to finish */
if (pinfo->baud != 0 && pinfo->bits != 0) {
/* point to the last txed bd */
bdp = pinfo->tx_cur;
if (bdp == pinfo->tx_bd_base)
bdp = pinfo->tx_bd_base + pinfo->tx_nrfifos;
else
bdp--;
/* wait for it to be transmitted */
while ((bdp->cbd_sc & BD_SC_READY) != 0)
schedule();
/* and delay for the hw fifo to drain */
udelay((3 * 1000000 * pinfo->bits) / pinfo->baud);
}
spin_lock_irqsave(&port->lock, flags);
/* Send the CPM an initialize command. */
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_STOP_TX);
/* Stop uart */
if (IS_SMC(pinfo))
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
else
pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
/* Send the CPM an initialize command. */
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_INIT_TRX);
spin_unlock_irqrestore(&port->lock, flags);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
* 1 or 2 stop bits, minus 1.
* The value 'bits' counts this for us.
*/
cval = 0;
scval = 0;
/* byte size */
switch (termios->c_cflag & CSIZE) {
case CS5:
bits = 5;
break;
case CS6:
bits = 6;
break;
case CS7:
bits = 7;
break;
case CS8:
bits = 8;
break;
/* Never happens, but GCC is too dumb to figure it out */
default:
bits = 8;
break;
}
sbits = bits - 5;
if (termios->c_cflag & CSTOPB) {
cval |= SMCMR_SL; /* Two stops */
scval |= SCU_PSMR_SL;
bits++;
}
if (termios->c_cflag & PARENB) {
cval |= SMCMR_PEN;
scval |= SCU_PSMR_PEN;
bits++;
if (!(termios->c_cflag & PARODD)) {
cval |= SMCMR_PM_EVEN;
scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
}
}
/*
* Set up parity check flag
*/
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
if (termios->c_iflag & INPCK)
port->read_status_mask |= BD_SC_FR | BD_SC_PR;
if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
port->read_status_mask |= BD_SC_BR;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= BD_SC_BR;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= BD_SC_OV;
}
/*
* !!! ignore all characters if CREAD is not set
*/
if ((termios->c_cflag & CREAD) == 0)
port->read_status_mask &= ~BD_SC_EMPTY;
spin_lock_irqsave(&port->lock, flags);
cpm_set_brg(pinfo->brg - 1, baud);
/* Start bit has not been added (so don't, because we would just
* subtract it later), and we need to add one for the number of
* stops bits (there is always at least one).
*/
bits++;
/* re-init */
if (IS_SMC(pinfo))
cpm_uart_init_smc(pinfo, bits, cval);
else
cpm_uart_init_scc(pinfo, sbits, scval);
pinfo->baud = baud;
pinfo->bits = bits;
pinfo->flags &= ~FLAG_DISCARDING;
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *cpm_uart_type(struct uart_port *port)
{
pr_debug("CPM uart[%d]:uart_type\n", port->line);
return port->type == PORT_CPM ? "CPM UART" : NULL;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int cpm_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
int ret = 0;
pr_debug("CPM uart[%d]:verify_port\n", port->line);
if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
/*
* Transmit characters, refill buffer descriptor, if possible
*/
static int cpm_uart_tx_pump(struct uart_port *port)
{
volatile cbd_t *bdp;
unsigned char *p;
int count;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
struct circ_buf *xmit = &port->info->xmit;
/* Handle xon/xoff */
if (port->x_char) {
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
p = bus_to_virt(bdp->cbd_bufaddr);
*p++ = xmit->buf[xmit->tail];
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
/* Get next BD. */
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
pinfo->tx_cur = bdp;
port->icount.tx++;
port->x_char = 0;
return 1;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
cpm_uart_stop_tx(port, 0);
return 0;
}
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
count = 0;
p = bus_to_virt(bdp->cbd_bufaddr);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
count++;
if (xmit->head == xmit->tail)
break;
}
bdp->cbd_datlen = count;
bdp->cbd_sc |= BD_SC_READY;
/* Get next BD. */
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
}
pinfo->tx_cur = bdp;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) {
cpm_uart_stop_tx(port, 0);
return 0;
}
return 1;
}
static void cpm_uart_init_scc(struct uart_cpm_port *pinfo, int bits, u16 scval)
{
volatile scc_t *scp;
volatile scc_uart_t *sup;
u8 *mem_addr;
volatile cbd_t *bdp;
int i;
pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
scp = pinfo->sccp;
sup = pinfo->sccup;
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
pinfo->rx_cur = pinfo->rx_bd_base;
mem_addr = pinfo->mem_addr;
for (bdp = pinfo->rx_bd_base, i = 0; i < pinfo->rx_nrfifos; i++, bdp++) {
bdp->cbd_bufaddr = virt_to_bus(mem_addr);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT | (i < (pinfo->rx_nrfifos - 1) ? 0 : BD_SC_WRAP);
mem_addr += pinfo->rx_fifosize;
}
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
pinfo->tx_cur = pinfo->tx_bd_base;
for (bdp = pinfo->tx_bd_base, i = 0; i < pinfo->tx_nrfifos; i++, bdp++) {
bdp->cbd_bufaddr = virt_to_bus(mem_addr);
bdp->cbd_sc = BD_SC_INTRPT | (i < (pinfo->tx_nrfifos - 1) ? 0 : BD_SC_WRAP);
mem_addr += pinfo->tx_fifosize;
bdp++;
}
/* Store address */
pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE;
pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE;
/* Set up the uart parameters in the
* parameter ram.
*/
cpm_set_scc_fcr(sup);
sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize;
sup->scc_maxidl = pinfo->rx_fifosize;
sup->scc_brkcr = 1;
sup->scc_parec = 0;
sup->scc_frmec = 0;
sup->scc_nosec = 0;
sup->scc_brkec = 0;
sup->scc_uaddr1 = 0;
sup->scc_uaddr2 = 0;
sup->scc_toseq = 0;
sup->scc_char1 = 0x8000;
sup->scc_char2 = 0x8000;
sup->scc_char3 = 0x8000;
sup->scc_char4 = 0x8000;
sup->scc_char5 = 0x8000;
sup->scc_char6 = 0x8000;
sup->scc_char7 = 0x8000;
sup->scc_char8 = 0x8000;
sup->scc_rccm = 0xc0ff;
/* Send the CPM an initialize command.
*/
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_INIT_TRX);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
scp->scc_gsmrh = 0;
scp->scc_gsmrl =
(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
/* Enable rx interrupts and clear all pending events. */
scp->scc_sccm = UART_SCCM_RX;
scp->scc_scce = 0xffff;
scp->scc_dsr = 0x7e7e;
scp->scc_psmr = (bits << 12) | scval;
scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
static void cpm_uart_init_smc(struct uart_cpm_port *pinfo, int bits, u16 cval)
{
volatile smc_t *sp;
volatile smc_uart_t *up;
volatile u8 *mem_addr;
volatile cbd_t *bdp;
int i;
pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
sp = pinfo->smcp;
up = pinfo->smcup;
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr = pinfo->mem_addr;
pinfo->rx_cur = pinfo->rx_bd_base;
for (bdp = pinfo->rx_bd_base, i = 0; i < pinfo->rx_nrfifos; i++, bdp++) {
bdp->cbd_bufaddr = virt_to_bus(mem_addr);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT | (i < (pinfo->rx_nrfifos - 1) ? 0 : BD_SC_WRAP);
mem_addr += pinfo->rx_fifosize;
}
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
* virtual address for us to work with.
*/
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
pinfo->tx_cur = pinfo->tx_bd_base;
for (bdp = pinfo->tx_bd_base, i = 0; i < pinfo->tx_nrfifos; i++, bdp++) {
bdp->cbd_bufaddr = virt_to_bus(mem_addr);
bdp->cbd_sc = BD_SC_INTRPT | (i < (pinfo->tx_nrfifos - 1) ? 0 : BD_SC_WRAP);
mem_addr += pinfo->tx_fifosize;
}
/* Store address */
pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
/* Set up the uart parameters in the
* parameter ram.
*/
cpm_set_smc_fcr(up);
/* Using idle charater time requires some additional tuning. */
up->smc_mrblr = pinfo->rx_fifosize;
up->smc_maxidl = pinfo->rx_fifosize;
up->smc_brkcr = 1;
cpm_line_cr_cmd(pinfo->port.line, CPM_CR_INIT_TRX);
/* Set UART mode, according to the parameters */
sp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
/* Enable only rx interrupts clear all pending events. */
sp->smc_smcm = SMCM_RX;
sp->smc_smce = 0xff;
sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
}
/*
* Initialize port. This is called from early_console stuff
* so we have to be careful here !
*/
static int cpm_uart_request_port(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
int ret;
pr_debug("CPM uart[%d]:request port\n", port->line);
if (pinfo->flags & FLAG_CONSOLE)
return 0;
/*
* Setup any port IO, connect any baud rate generators,
* etc. This is expected to be handled by board
* dependant code
*/
if (pinfo->set_lineif)
pinfo->set_lineif(pinfo);
ret = cpm_uart_allocbuf(pinfo, 0);
if (ret)
return ret;
return 0;
}
static void cpm_uart_release_port(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
if (!(pinfo->flags & FLAG_CONSOLE))
cpm_uart_freebuf(pinfo);
}
/*
* Configure/autoconfigure the port.
*/
static void cpm_uart_config_port(struct uart_port *port, int flags)
{
pr_debug("CPM uart[%d]:config_port\n", port->line);
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_CPM;
cpm_uart_request_port(port);
}
}
static struct uart_ops cpm_uart_pops = {
.tx_empty = cpm_uart_tx_empty,
.set_mctrl = cpm_uart_set_mctrl,
.get_mctrl = cpm_uart_get_mctrl,
.stop_tx = cpm_uart_stop_tx,
.start_tx = cpm_uart_start_tx,
.stop_rx = cpm_uart_stop_rx,
.enable_ms = cpm_uart_enable_ms,
.break_ctl = cpm_uart_break_ctl,
.startup = cpm_uart_startup,
.shutdown = cpm_uart_shutdown,
.set_termios = cpm_uart_set_termios,
.type = cpm_uart_type,
.release_port = cpm_uart_release_port,
.request_port = cpm_uart_request_port,
.config_port = cpm_uart_config_port,
.verify_port = cpm_uart_verify_port,
};
struct uart_cpm_port cpm_uart_ports[UART_NR] = {
[UART_SMC1] = {
.port = {
.irq = SMC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
.line = UART_SMC1,
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = smc1_lineif,
},
[UART_SMC2] = {
.port = {
.irq = SMC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = smc2_lineif,
},
[UART_SCC1] = {
.port = {
.irq = SCC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
.line = UART_SCC1,
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = scc1_lineif,
},
[UART_SCC2] = {
.port = {
.irq = SCC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = scc2_lineif,
},
[UART_SCC3] = {
.port = {
.irq = SCC3_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = scc3_lineif,
},
[UART_SCC4] = {
.port = {
.irq = SCC4_IRQ,
.ops = &cpm_uart_pops,
.iotype = SERIAL_IO_MEM,
.line = UART_SCC4,
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = scc4_lineif,
},
};
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* Note that this is called with interrupts already disabled
*/
static void cpm_uart_console_write(struct console *co, const char *s,
u_int count)
{
struct uart_cpm_port *pinfo =
&cpm_uart_ports[cpm_uart_port_map[co->index]];
unsigned int i;
volatile cbd_t *bdp, *bdbase;
volatile unsigned char *cp;
if (IS_DISCARDING(pinfo))
return;
/* Get the address of the host memory buffer.
*/
bdp = pinfo->tx_cur;
bdbase = pinfo->tx_bd_base;
/*
* Now, do each character. This is not as bad as it looks
* since this is a holding FIFO and not a transmitting FIFO.
* We could add the complexity of filling the entire transmit
* buffer, but we would just wait longer between accesses......
*/
for (i = 0; i < count; i++, s++) {
/* Wait for transmitter fifo to empty.
* Ready indicates output is ready, and xmt is doing
* that, not that it is ready for us to send.
*/
while ((bdp->cbd_sc & BD_SC_READY) != 0)
;
/* Send the character out.
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR)
cp = (unsigned char *) (bdp->cbd_bufaddr);
else
cp = bus_to_virt(bdp->cbd_bufaddr);
*cp = *s;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
/* if a LF, also do CR... */
if (*s == 10) {
while ((bdp->cbd_sc & BD_SC_READY) != 0)
;
if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR)
cp = (unsigned char *) (bdp->cbd_bufaddr);
else
cp = bus_to_virt(bdp->cbd_bufaddr);
*cp = 13;
bdp->cbd_datlen = 1;
bdp->cbd_sc |= BD_SC_READY;
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
}
}
/*
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
while ((bdp->cbd_sc & BD_SC_READY) != 0)
;
pinfo->tx_cur = (volatile cbd_t *) bdp;
}
/*
* Setup console. Be careful is called early !
*/
static int __init cpm_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
struct uart_cpm_port *pinfo;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
port =
(struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]];
pinfo = (struct uart_cpm_port *)port;
pinfo->flags |= FLAG_CONSOLE;
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
} else {
bd_t *bd = (bd_t *) __res;
if (bd->bi_baudrate)
baud = bd->bi_baudrate;
else
baud = 9600;
}
/*
* Setup any port IO, connect any baud rate generators,
* etc. This is expected to be handled by board
* dependant code
*/
if (pinfo->set_lineif)
pinfo->set_lineif(pinfo);
ret = cpm_uart_allocbuf(pinfo, 1);
if (ret)
return ret;
uart_set_options(port, co, baud, parity, bits, flow);
return 0;
}
extern struct uart_driver cpm_reg;
static struct console cpm_scc_uart_console = {
.name "ttyCPM",
.write cpm_uart_console_write,
.device uart_console_device,
.setup cpm_uart_console_setup,
.flags CON_PRINTBUFFER,
.index -1,
.data = &cpm_reg,
};
int __init cpm_uart_console_init(void)
{
int ret = cpm_uart_init_portdesc();
if (!ret)
register_console(&cpm_scc_uart_console);
return ret;
}
console_initcall(cpm_uart_console_init);
#define CPM_UART_CONSOLE &cpm_scc_uart_console
#else
#define CPM_UART_CONSOLE NULL
#endif
static struct uart_driver cpm_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyCPM",
.dev_name = "ttyCPM",
.major = SERIAL_CPM_MAJOR,
.minor = SERIAL_CPM_MINOR,
.cons = CPM_UART_CONSOLE,
};
static int __init cpm_uart_init(void)
{
int ret, i;
printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n");
#ifndef CONFIG_SERIAL_CPM_CONSOLE
ret = cpm_uart_init_portdesc();
if (ret)
return ret;
#endif
cpm_reg.nr = cpm_uart_nr;
ret = uart_register_driver(&cpm_reg);
if (ret)
return ret;
for (i = 0; i < cpm_uart_nr; i++) {
int con = cpm_uart_port_map[i];
cpm_uart_ports[con].port.line = i;
cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
}
return ret;
}
static void __exit cpm_uart_exit(void)
{
int i;
for (i = 0; i < cpm_uart_nr; i++) {
int con = cpm_uart_port_map[i];
uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port);
}
uart_unregister_driver(&cpm_reg);
}
module_init(cpm_uart_init);
module_exit(cpm_uart_exit);
MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
/*
* linux/drivers/serial/cpm_uart.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
*
* Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
*
* 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 <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void cpm_line_cr_cmd(int line, int cmd)
{
ushort val;
volatile cpm8xx_t *cp = cpmp;
switch (line) {
case UART_SMC1:
val = mk_cr_cmd(CPM_CR_CH_SMC1, cmd) | CPM_CR_FLG;
break;
case UART_SMC2:
val = mk_cr_cmd(CPM_CR_CH_SMC2, cmd) | CPM_CR_FLG;
break;
case UART_SCC1:
val = mk_cr_cmd(CPM_CR_CH_SCC1, cmd) | CPM_CR_FLG;
break;
case UART_SCC2:
val = mk_cr_cmd(CPM_CR_CH_SCC2, cmd) | CPM_CR_FLG;
break;
case UART_SCC3:
val = mk_cr_cmd(CPM_CR_CH_SCC3, cmd) | CPM_CR_FLG;
break;
case UART_SCC4:
val = mk_cr_cmd(CPM_CR_CH_SCC4, cmd) | CPM_CR_FLG;
break;
default:
return;
}
cp->cp_cpcr = val;
while (cp->cp_cpcr & CPM_CR_FLG) ;
}
void smc1_lineif(struct uart_cpm_port *pinfo)
{
volatile cpm8xx_t *cp = cpmp;
cp->cp_pbpar |= 0x000000c0;
cp->cp_pbdir &= ~0x000000c0;
cp->cp_pbodr &= ~0x000000c0;
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SMC2: insert port configuration here */
pinfo->brg = 2;
}
void scc1_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC1: insert port configuration here */
pinfo->brg = 1;
}
void scc2_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC2: insert port configuration here */
pinfo->brg = 2;
}
void scc3_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC3: insert port configuration here */
pinfo->brg = 3;
}
void scc4_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC4: insert port configuration here */
pinfo->brg = 4;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
uint dp_addr;
u8 *mem_addr;
dma_addr_t dma_addr;
pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_addr = m8xx_cpm_dpalloc(dpmemsz);
if (dp_addr == CPM_DP_NOSPACE) {
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
return -ENOMEM;
}
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con) {
mem_addr = (u8 *) m8xx_cpm_hostalloc(memsz);
dma_addr = 0;
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
/* We cant really from memory allocated via cpm2_dpalloc,
* fix this if in the future we can */
if (mem_addr == NULL) {
/* XXX cpm_dpalloc does not yet free */
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate coherent memory\n");
return -ENOMEM;
}
pinfo->dp_addr = dp_addr;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
pinfo->rx_bd_base = (volatile cbd_t *)(DPRAM_BASE + dp_addr);
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
}
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), pinfo->mem_addr,
pinfo->dma_addr);
/* XXX cannot free dpmem yet */
}
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0];
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1];
cpm_uart_ports[UART_SMC1].port.mapbase =
(unsigned long)&cpmp->cp_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports[UART_SMC2].smcp = &cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcup =
(smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC2];
cpm_uart_ports[UART_SMC2].port.mapbase =
(unsigned long)&cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports[UART_SCC1].sccp = &cpmp->cp_scc[0];
cpm_uart_ports[UART_SCC1].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC1];
cpm_uart_ports[UART_SCC1].port.mapbase =
(unsigned long)&cpmp->cp_scc[0];
cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports[UART_SCC2].sccp = &cpmp->cp_scc[1];
cpm_uart_ports[UART_SCC2].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC2];
cpm_uart_ports[UART_SCC2].port.mapbase =
(unsigned long)&cpmp->cp_scc[1];
cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports[UART_SCC3].sccp = &cpmp->cp_scc[2];
cpm_uart_ports[UART_SCC3].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC3];
cpm_uart_ports[UART_SCC3].port.mapbase =
(unsigned long)&cpmp->cp_scc[2];
cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports[UART_SCC4].sccp = &cpmp->cp_scc[3];
cpm_uart_ports[UART_SCC4].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC4];
cpm_uart_ports[UART_SCC4].port.mapbase =
(unsigned long)&cpmp->cp_scc[3];
cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
}
/*
* linux/drivers/serial/cpm_uart_cpm1.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm1
*
*/
#ifndef CPM_UART_CPM1_H
#define CPM_UART_CPM1_H
#include <asm/commproc.h>
/* defines for IRQs */
#define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1)
#define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2)
#define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1)
#define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2)
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
/* the CPM address */
#define CPM_ADDR IMAP_ADDR
static inline void cpm_set_brg(int brg, int baud)
{
m8xx_cpm_setbrg(brg, baud);
}
static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
{
sup->scc_genscc.scc_rfcr = SMC_EB;
sup->scc_genscc.scc_tfcr = SMC_EB;
}
static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
{
up->smc_rfcr = SMC_EB;
up->smc_tfcr = SMC_EB;
}
#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0])
#endif
/*
* linux/drivers/serial/cpm_uart_cpm2.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
*
* Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
*
* 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 <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void cpm_line_cr_cmd(int line, int cmd)
{
volatile cpm_cpm2_t *cp = cpmp;
ulong val;
switch (line) {
case UART_SMC1:
val = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SMC2:
val = mk_cr_cmd(CPM_CR_SMC2_PAGE, CPM_CR_SMC2_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC1:
val = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC2:
val = mk_cr_cmd(CPM_CR_SCC2_PAGE, CPM_CR_SCC2_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC3:
val = mk_cr_cmd(CPM_CR_SCC3_PAGE, CPM_CR_SCC3_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC4:
val = mk_cr_cmd(CPM_CR_SCC4_PAGE, CPM_CR_SCC4_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
default:
return;
}
cp->cp_cpcr = val;
while (cp->cp_cpcr & CPM_CR_FLG) ;
}
void smc1_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* SMC1 is only on port D */
io->iop_ppard |= 0x00c00000;
io->iop_pdird |= 0x00400000;
io->iop_pdird &= ~0x00800000;
io->iop_psord &= ~0x00c00000;
/* Wire BRG1 to SMC1 */
cpm2_immr->im_cpmux.cmx_smr &= 0x0f;
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* SMC2 is only on port A */
io->iop_ppara |= 0x00c00000;
io->iop_pdira |= 0x00400000;
io->iop_pdira &= ~0x00800000;
io->iop_psora &= ~0x00c00000;
/* Wire BRG2 to SMC2 */
cpm2_immr->im_cpmux.cmx_smr &= 0xf0;
pinfo->brg = 2;
}
void scc1_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* Use Port D for SCC1 instead of other functions. */
io->iop_ppard |= 0x00000003;
io->iop_psord &= ~0x00000001; /* Rx */
io->iop_psord |= 0x00000002; /* Tx */
io->iop_pdird &= ~0x00000001; /* Rx */
io->iop_pdird |= 0x00000002; /* Tx */
/* Wire BRG1 to SCC1 */
cpm2_immr->im_cpmux.cmx_scr &= ~0x00ffffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00000000;
pinfo->brg = 1;
}
void scc2_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
cpm2_immr->im_cpmux.cmx_scr &= ~0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
}
void scc3_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
cpm2_immr->im_cpmux.cmx_scr &= ~0xffff00ff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00001200;
pinfo->brg = 3;
}
void scc4_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_ppard |= 0x00000600;
io->iop_psord &= ~0x00000600; /* Tx/Rx */
io->iop_pdird &= ~0x00000200; /* Rx */
io->iop_pdird |= 0x00000400; /* Tx */
cpm2_immr->im_cpmux.cmx_scr &= ~0xffffff00;
cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b;
pinfo->brg = 4;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
uint dp_addr;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_addr = cpm2_dpalloc(dpmemsz, 8);
if (dp_addr == CPM_DP_NOSPACE) {
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
return -ENOMEM;
}
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con)
mem_addr = alloc_bootmem(memsz);
else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
/* We cant really from memory allocated via cpm2_dpalloc,
* fix this if in the future we can */
if (mem_addr == NULL) {
/* XXX cpm_dpalloc does not yet free */
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate coherent memory\n");
return -ENOMEM;
}
pinfo->dp_addr = dp_addr;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
pinfo->rx_bd_base = (volatile cbd_t *)(DPRAM_BASE + dp_addr);
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
}
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), pinfo->mem_addr,
pinfo->dma_addr);
/* XXX cannot free dpmem yet */
}
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
cpm_uart_ports[UART_SMC1].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
cpm_uart_ports[UART_SMC2].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0];
cpm_uart_ports[UART_SCC1].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1];
cpm_uart_ports[UART_SCC1].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[0];
cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1];
cpm_uart_ports[UART_SCC2].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2];
cpm_uart_ports[UART_SCC2].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[1];
cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2];
cpm_uart_ports[UART_SCC3].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3];
cpm_uart_ports[UART_SCC3].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[2];
cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3];
cpm_uart_ports[UART_SCC4].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4];
cpm_uart_ports[UART_SCC4].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[3];
cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
}
/*
* linux/drivers/serial/cpm_uart_cpm2.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm2
*
*/
#ifndef CPM_UART_CPM2_H
#define CPM_UART_CPM2_H
#include <asm/cpm2.h>
/* defines for IRQs */
#define SMC1_IRQ SIU_INT_SMC1
#define SMC2_IRQ SIU_INT_SMC2
#define SCC1_IRQ SIU_INT_SCC1
#define SCC2_IRQ SIU_INT_SCC2
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
/* the CPM address */
#define CPM_ADDR CPM_MAP_ADDR
static inline void cpm_set_brg(int brg, int baud)
{
cpm2_setbrg(brg, baud);
}
static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
{
sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
}
static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
{
up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
}
#define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0])
#endif
/*
* MPC8260 Communication Processor Module.
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
* Communication Processor Module v2.
*
* This file contains structures and information for the communication
* processor channels found in the dual port RAM or parameter RAM.
* All CPM control and status is available through the MPC8260 internal
* memory map. See immap.h for details.
* All CPM control and status is available through the CPM2 internal
* memory map. See immap_cpm2.h for details.
*/
#ifdef __KERNEL__
#ifndef __CPM_82XX__
#define __CPM_82XX__
#ifndef __CPM2__
#define __CPM2__
#include <asm/immap_8260.h>
#include <asm/immap_cpm2.h>
/* CPM Command register.
*/
......@@ -72,6 +71,8 @@
#define CPM_CR_STOP_TX ((ushort)0x0004)
#define CPM_CR_RESTART_TX ((ushort)0x0006)
#define CPM_CR_SET_GADDR ((ushort)0x0008)
#define CPM_CR_START_IDMA ((ushort)0x0009)
#define CPM_CR_STOP_IDMA ((ushort)0x000b)
#define mk_cr_cmd(PG, SBC, MCN, OP) \
((PG << 26) | (SBC << 21) | (MCN << 6) | OP)
......@@ -83,9 +84,14 @@
* downloading RAM microcode.
*/
#define CPM_DATAONLY_BASE ((uint)128)
#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE)
#define CPM_DP_NOSPACE ((uint)0x7fffffff)
#ifdef CONFIG_8272
#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE)
#define CPM_FCC_SPECIAL_BASE ((uint)0x00009000)
#else
#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE)
#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000)
#endif
/* The number of pages of host memory we allocate for CPM. This is
* done early in kernel initialization to get physically contiguous
......@@ -97,11 +103,11 @@
/* Export the base address of the communication processor registers
* and dual port ram.
*/
extern cpm8260_t *cpmp; /* Pointer to comm processor */
uint m8260_cpm_dpalloc(uint size, uint align);
uint m8260_cpm_hostalloc(uint size, uint align);
void m8260_cpm_setbrg(uint brg, uint rate);
void m8260_cpm_fastbrg(uint brg, uint rate, int div16);
extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */
uint cpm2_dpalloc(uint size, uint align);
uint cpm2_hostalloc(uint size, uint align);
void cpm2_setbrg(uint brg, uint rate);
void cpm2_fastbrg(uint brg, uint rate, int div16);
/* Buffer descriptors used by many of the CPM protocols.
*/
......@@ -504,21 +510,21 @@ typedef struct scc_uart {
#define UART_SCCM_TX ((ushort)0x0002)
#define UART_SCCM_RX ((ushort)0x0001)
/* The SCC PMSR when used as a UART.
/* The SCC PSMR when used as a UART.
*/
#define SCU_PMSR_FLC ((ushort)0x8000)
#define SCU_PMSR_SL ((ushort)0x4000)
#define SCU_PMSR_CL ((ushort)0x3000)
#define SCU_PMSR_UM ((ushort)0x0c00)
#define SCU_PMSR_FRZ ((ushort)0x0200)
#define SCU_PMSR_RZS ((ushort)0x0100)
#define SCU_PMSR_SYN ((ushort)0x0080)
#define SCU_PMSR_DRT ((ushort)0x0040)
#define SCU_PMSR_PEN ((ushort)0x0010)
#define SCU_PMSR_RPM ((ushort)0x000c)
#define SCU_PMSR_REVP ((ushort)0x0008)
#define SCU_PMSR_TPM ((ushort)0x0003)
#define SCU_PMSR_TEVP ((ushort)0x0003)
#define SCU_PSMR_FLC ((ushort)0x8000)
#define SCU_PSMR_SL ((ushort)0x4000)
#define SCU_PSMR_CL ((ushort)0x3000)
#define SCU_PSMR_UM ((ushort)0x0c00)
#define SCU_PSMR_FRZ ((ushort)0x0200)
#define SCU_PSMR_RZS ((ushort)0x0100)
#define SCU_PSMR_SYN ((ushort)0x0080)
#define SCU_PSMR_DRT ((ushort)0x0040)
#define SCU_PSMR_PEN ((ushort)0x0010)
#define SCU_PSMR_RPM ((ushort)0x000c)
#define SCU_PSMR_REVP ((ushort)0x0008)
#define SCU_PSMR_TPM ((ushort)0x0003)
#define SCU_PSMR_TEVP ((ushort)0x0003)
/* CPM Transparent mode SCC.
*/
......@@ -612,7 +618,7 @@ typedef struct fcc_enet {
ushort fen_paddrm;
ushort fen_paddrl;
ushort fen_ibdcount; /* Internal BD counter */
ushort fen_idbstart; /* Internal BD start pointer */
ushort fen_ibdstart; /* Internal BD start pointer */
ushort fen_ibdend; /* Internal BD end pointer */
ushort fen_txlen; /* Internal Tx frame length counter */
uint fen_ibdbase[8]; /* Internal use */
......@@ -696,7 +702,336 @@ typedef struct iic {
uint iic_txtmp; /* Internal */
} iic_t;
/* SPI parameter RAM.
*/
typedef struct spi {
ushort spi_rbase; /* Rx Buffer descriptor base address */
ushort spi_tbase; /* Tx Buffer descriptor base address */
u_char spi_rfcr; /* Rx function code */
u_char spi_tfcr; /* Tx function code */
ushort spi_mrblr; /* Max receive buffer length */
uint spi_rstate; /* Internal */
uint spi_rdp; /* Internal */
ushort spi_rbptr; /* Internal */
ushort spi_rbc; /* Internal */
uint spi_rxtmp; /* Internal */
uint spi_tstate; /* Internal */
uint spi_tdp; /* Internal */
ushort spi_tbptr; /* Internal */
ushort spi_tbc; /* Internal */
uint spi_txtmp; /* Internal */
uint spi_res; /* Tx temp. */
uint spi_res1[4]; /* SDMA temp. */
} spi_t;
/* SPI Mode register.
*/
#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */
#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */
#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */
#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */
#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */
#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */
#define SPMODE_EN ((ushort)0x0100) /* Enable */
#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */
#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */
#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4)
#define SPMODE_PM(x) ((x) &0xF)
#define SPI_EB ((u_char)0x10) /* big endian byte order */
#define BD_IIC_START ((ushort)0x0400)
#endif /* __CPM_82XX__ */
/* IDMA parameter RAM
*/
typedef struct idma {
ushort ibase; /* IDMA buffer descriptor table base address */
ushort dcm; /* DMA channel mode */
ushort ibdptr; /* IDMA current buffer descriptor pointer */
ushort dpr_buf; /* IDMA transfer buffer base address */
ushort buf_inv; /* internal buffer inventory */
ushort ss_max; /* steady-state maximum transfer size */
ushort dpr_in_ptr; /* write pointer inside the internal buffer */
ushort sts; /* source transfer size */
ushort dpr_out_ptr; /* read pointer inside the internal buffer */
ushort seob; /* source end of burst */
ushort deob; /* destination end of burst */
ushort dts; /* destination transfer size */
ushort ret_add; /* return address when working in ERM=1 mode */
ushort res0; /* reserved */
uint bd_cnt; /* internal byte count */
uint s_ptr; /* source internal data pointer */
uint d_ptr; /* destination internal data pointer */
uint istate; /* internal state */
u_char res1[20]; /* pad to 64-byte length */
} idma_t;
/* DMA channel mode bit fields
*/
#define IDMA_DCM_FB ((ushort)0x8000) /* fly-by mode */
#define IDMA_DCM_LP ((ushort)0x4000) /* low priority */
#define IDMA_DCM_TC2 ((ushort)0x0400) /* value driven on TC[2] */
#define IDMA_DCM_DMA_WRAP_MASK ((ushort)0x01c0) /* mask for DMA wrap */
#define IDMA_DCM_DMA_WRAP_64 ((ushort)0x0000) /* 64-byte DMA xfer buffer */
#define IDMA_DCM_DMA_WRAP_128 ((ushort)0x0040) /* 128-byte DMA xfer buffer */
#define IDMA_DCM_DMA_WRAP_256 ((ushort)0x0080) /* 256-byte DMA xfer buffer */
#define IDMA_DCM_DMA_WRAP_512 ((ushort)0x00c0) /* 512-byte DMA xfer buffer */
#define IDMA_DCM_DMA_WRAP_1024 ((ushort)0x0100) /* 1024-byte DMA xfer buffer */
#define IDMA_DCM_DMA_WRAP_2048 ((ushort)0x0140) /* 2048-byte DMA xfer buffer */
#define IDMA_DCM_SINC ((ushort)0x0020) /* source inc addr */
#define IDMA_DCM_DINC ((ushort)0x0010) /* destination inc addr */
#define IDMA_DCM_ERM ((ushort)0x0008) /* external request mode */
#define IDMA_DCM_DT ((ushort)0x0004) /* DONE treatment */
#define IDMA_DCM_SD_MASK ((ushort)0x0003) /* mask for SD bit field */
#define IDMA_DCM_SD_MEM2MEM ((ushort)0x0000) /* memory-to-memory xfer */
#define IDMA_DCM_SD_PER2MEM ((ushort)0x0002) /* peripheral-to-memory xfer */
#define IDMA_DCM_SD_MEM2PER ((ushort)0x0001) /* memory-to-peripheral xfer */
/* IDMA Buffer Descriptors
*/
typedef struct idma_bd {
uint flags;
uint len; /* data length */
uint src; /* source data buffer pointer */
uint dst; /* destination data buffer pointer */
} idma_bd_t;
/* IDMA buffer descriptor flag bit fields
*/
#define IDMA_BD_V ((uint)0x80000000) /* valid */
#define IDMA_BD_W ((uint)0x20000000) /* wrap */
#define IDMA_BD_I ((uint)0x10000000) /* interrupt */
#define IDMA_BD_L ((uint)0x08000000) /* last */
#define IDMA_BD_CM ((uint)0x02000000) /* continuous mode */
#define IDMA_BD_SDN ((uint)0x00400000) /* source done */
#define IDMA_BD_DDN ((uint)0x00200000) /* destination done */
#define IDMA_BD_DGBL ((uint)0x00100000) /* destination global */
#define IDMA_BD_DBO_LE ((uint)0x00040000) /* little-end dest byte order */
#define IDMA_BD_DBO_BE ((uint)0x00080000) /* big-end dest byte order */
#define IDMA_BD_DDTB ((uint)0x00010000) /* destination data bus */
#define IDMA_BD_SGBL ((uint)0x00002000) /* source global */
#define IDMA_BD_SBO_LE ((uint)0x00000800) /* little-end src byte order */
#define IDMA_BD_SBO_BE ((uint)0x00001000) /* big-end src byte order */
#define IDMA_BD_SDTB ((uint)0x00000200) /* source data bus */
/* per-channel IDMA registers
*/
typedef struct im_idma {
u_char idsr; /* IDMAn event status register */
u_char res0[3];
u_char idmr; /* IDMAn event mask register */
u_char res1[3];
} im_idma_t;
/* IDMA event register bit fields
*/
#define IDMA_EVENT_SC ((unsigned char)0x08) /* stop completed */
#define IDMA_EVENT_OB ((unsigned char)0x04) /* out of buffers */
#define IDMA_EVENT_EDN ((unsigned char)0x02) /* external DONE asserted */
#define IDMA_EVENT_BC ((unsigned char)0x01) /* buffer descriptor complete */
/* RISC Controller Configuration Register (RCCR) bit fields
*/
#define RCCR_TIME ((uint)0x80000000) /* timer enable */
#define RCCR_TIMEP_MASK ((uint)0x3f000000) /* mask for timer period bit field */
#define RCCR_DR0M ((uint)0x00800000) /* IDMA0 request mode */
#define RCCR_DR1M ((uint)0x00400000) /* IDMA1 request mode */
#define RCCR_DR2M ((uint)0x00000080) /* IDMA2 request mode */
#define RCCR_DR3M ((uint)0x00000040) /* IDMA3 request mode */
#define RCCR_DR0QP_MASK ((uint)0x00300000) /* mask for IDMA0 req priority */
#define RCCR_DR0QP_HIGH ((uint)0x00000000) /* IDMA0 has high req priority */
#define RCCR_DR0QP_MED ((uint)0x00100000) /* IDMA0 has medium req priority */
#define RCCR_DR0QP_LOW ((uint)0x00200000) /* IDMA0 has low req priority */
#define RCCR_DR1QP_MASK ((uint)0x00030000) /* mask for IDMA1 req priority */
#define RCCR_DR1QP_HIGH ((uint)0x00000000) /* IDMA1 has high req priority */
#define RCCR_DR1QP_MED ((uint)0x00010000) /* IDMA1 has medium req priority */
#define RCCR_DR1QP_LOW ((uint)0x00020000) /* IDMA1 has low req priority */
#define RCCR_DR2QP_MASK ((uint)0x00000030) /* mask for IDMA2 req priority */
#define RCCR_DR2QP_HIGH ((uint)0x00000000) /* IDMA2 has high req priority */
#define RCCR_DR2QP_MED ((uint)0x00000010) /* IDMA2 has medium req priority */
#define RCCR_DR2QP_LOW ((uint)0x00000020) /* IDMA2 has low req priority */
#define RCCR_DR3QP_MASK ((uint)0x00000003) /* mask for IDMA3 req priority */
#define RCCR_DR3QP_HIGH ((uint)0x00000000) /* IDMA3 has high req priority */
#define RCCR_DR3QP_MED ((uint)0x00000001) /* IDMA3 has medium req priority */
#define RCCR_DR3QP_LOW ((uint)0x00000002) /* IDMA3 has low req priority */
#define RCCR_EIE ((uint)0x00080000) /* external interrupt enable */
#define RCCR_SCD ((uint)0x00040000) /* scheduler configuration */
#define RCCR_ERAM_MASK ((uint)0x0000e000) /* mask for enable RAM microcode */
#define RCCR_ERAM_0KB ((uint)0x00000000) /* use 0KB of dpram for microcode */
#define RCCR_ERAM_2KB ((uint)0x00002000) /* use 2KB of dpram for microcode */
#define RCCR_ERAM_4KB ((uint)0x00004000) /* use 4KB of dpram for microcode */
#define RCCR_ERAM_6KB ((uint)0x00006000) /* use 6KB of dpram for microcode */
#define RCCR_ERAM_8KB ((uint)0x00008000) /* use 8KB of dpram for microcode */
#define RCCR_ERAM_10KB ((uint)0x0000a000) /* use 10KB of dpram for microcode */
#define RCCR_ERAM_12KB ((uint)0x0000c000) /* use 12KB of dpram for microcode */
#define RCCR_EDM0 ((uint)0x00000800) /* DREQ0 edge detect mode */
#define RCCR_EDM1 ((uint)0x00000400) /* DREQ1 edge detect mode */
#define RCCR_EDM2 ((uint)0x00000200) /* DREQ2 edge detect mode */
#define RCCR_EDM3 ((uint)0x00000100) /* DREQ3 edge detect mode */
#define RCCR_DEM01 ((uint)0x00000008) /* DONE0/DONE1 edge detect mode */
#define RCCR_DEM23 ((uint)0x00000004) /* DONE2/DONE3 edge detect mode */
/*-----------------------------------------------------------------------
* CMXFCR - CMX FCC Clock Route Register
*/
#define CMXFCR_FC1 0x40000000 /* FCC1 connection */
#define CMXFCR_RF1CS_MSK 0x38000000 /* Receive FCC1 Clock Source Mask */
#define CMXFCR_TF1CS_MSK 0x07000000 /* Transmit FCC1 Clock Source Mask */
#define CMXFCR_FC2 0x00400000 /* FCC2 connection */
#define CMXFCR_RF2CS_MSK 0x00380000 /* Receive FCC2 Clock Source Mask */
#define CMXFCR_TF2CS_MSK 0x00070000 /* Transmit FCC2 Clock Source Mask */
#define CMXFCR_FC3 0x00004000 /* FCC3 connection */
#define CMXFCR_RF3CS_MSK 0x00003800 /* Receive FCC3 Clock Source Mask */
#define CMXFCR_TF3CS_MSK 0x00000700 /* Transmit FCC3 Clock Source Mask */
#define CMXFCR_RF1CS_BRG5 0x00000000 /* Receive FCC1 Clock Source is BRG5 */
#define CMXFCR_RF1CS_BRG6 0x08000000 /* Receive FCC1 Clock Source is BRG6 */
#define CMXFCR_RF1CS_BRG7 0x10000000 /* Receive FCC1 Clock Source is BRG7 */
#define CMXFCR_RF1CS_BRG8 0x18000000 /* Receive FCC1 Clock Source is BRG8 */
#define CMXFCR_RF1CS_CLK9 0x20000000 /* Receive FCC1 Clock Source is CLK9 */
#define CMXFCR_RF1CS_CLK10 0x28000000 /* Receive FCC1 Clock Source is CLK10 */
#define CMXFCR_RF1CS_CLK11 0x30000000 /* Receive FCC1 Clock Source is CLK11 */
#define CMXFCR_RF1CS_CLK12 0x38000000 /* Receive FCC1 Clock Source is CLK12 */
#define CMXFCR_TF1CS_BRG5 0x00000000 /* Transmit FCC1 Clock Source is BRG5 */
#define CMXFCR_TF1CS_BRG6 0x01000000 /* Transmit FCC1 Clock Source is BRG6 */
#define CMXFCR_TF1CS_BRG7 0x02000000 /* Transmit FCC1 Clock Source is BRG7 */
#define CMXFCR_TF1CS_BRG8 0x03000000 /* Transmit FCC1 Clock Source is BRG8 */
#define CMXFCR_TF1CS_CLK9 0x04000000 /* Transmit FCC1 Clock Source is CLK9 */
#define CMXFCR_TF1CS_CLK10 0x05000000 /* Transmit FCC1 Clock Source is CLK10 */
#define CMXFCR_TF1CS_CLK11 0x06000000 /* Transmit FCC1 Clock Source is CLK11 */
#define CMXFCR_TF1CS_CLK12 0x07000000 /* Transmit FCC1 Clock Source is CLK12 */
#define CMXFCR_RF2CS_BRG5 0x00000000 /* Receive FCC2 Clock Source is BRG5 */
#define CMXFCR_RF2CS_BRG6 0x00080000 /* Receive FCC2 Clock Source is BRG6 */
#define CMXFCR_RF2CS_BRG7 0x00100000 /* Receive FCC2 Clock Source is BRG7 */
#define CMXFCR_RF2CS_BRG8 0x00180000 /* Receive FCC2 Clock Source is BRG8 */
#define CMXFCR_RF2CS_CLK13 0x00200000 /* Receive FCC2 Clock Source is CLK13 */
#define CMXFCR_RF2CS_CLK14 0x00280000 /* Receive FCC2 Clock Source is CLK14 */
#define CMXFCR_RF2CS_CLK15 0x00300000 /* Receive FCC2 Clock Source is CLK15 */
#define CMXFCR_RF2CS_CLK16 0x00380000 /* Receive FCC2 Clock Source is CLK16 */
#define CMXFCR_TF2CS_BRG5 0x00000000 /* Transmit FCC2 Clock Source is BRG5 */
#define CMXFCR_TF2CS_BRG6 0x00010000 /* Transmit FCC2 Clock Source is BRG6 */
#define CMXFCR_TF2CS_BRG7 0x00020000 /* Transmit FCC2 Clock Source is BRG7 */
#define CMXFCR_TF2CS_BRG8 0x00030000 /* Transmit FCC2 Clock Source is BRG8 */
#define CMXFCR_TF2CS_CLK13 0x00040000 /* Transmit FCC2 Clock Source is CLK13 */
#define CMXFCR_TF2CS_CLK14 0x00050000 /* Transmit FCC2 Clock Source is CLK14 */
#define CMXFCR_TF2CS_CLK15 0x00060000 /* Transmit FCC2 Clock Source is CLK15 */
#define CMXFCR_TF2CS_CLK16 0x00070000 /* Transmit FCC2 Clock Source is CLK16 */
#define CMXFCR_RF3CS_BRG5 0x00000000 /* Receive FCC3 Clock Source is BRG5 */
#define CMXFCR_RF3CS_BRG6 0x00000800 /* Receive FCC3 Clock Source is BRG6 */
#define CMXFCR_RF3CS_BRG7 0x00001000 /* Receive FCC3 Clock Source is BRG7 */
#define CMXFCR_RF3CS_BRG8 0x00001800 /* Receive FCC3 Clock Source is BRG8 */
#define CMXFCR_RF3CS_CLK13 0x00002000 /* Receive FCC3 Clock Source is CLK13 */
#define CMXFCR_RF3CS_CLK14 0x00002800 /* Receive FCC3 Clock Source is CLK14 */
#define CMXFCR_RF3CS_CLK15 0x00003000 /* Receive FCC3 Clock Source is CLK15 */
#define CMXFCR_RF3CS_CLK16 0x00003800 /* Receive FCC3 Clock Source is CLK16 */
#define CMXFCR_TF3CS_BRG5 0x00000000 /* Transmit FCC3 Clock Source is BRG5 */
#define CMXFCR_TF3CS_BRG6 0x00000100 /* Transmit FCC3 Clock Source is BRG6 */
#define CMXFCR_TF3CS_BRG7 0x00000200 /* Transmit FCC3 Clock Source is BRG7 */
#define CMXFCR_TF3CS_BRG8 0x00000300 /* Transmit FCC3 Clock Source is BRG8 */
#define CMXFCR_TF3CS_CLK13 0x00000400 /* Transmit FCC3 Clock Source is CLK13 */
#define CMXFCR_TF3CS_CLK14 0x00000500 /* Transmit FCC3 Clock Source is CLK14 */
#define CMXFCR_TF3CS_CLK15 0x00000600 /* Transmit FCC3 Clock Source is CLK15 */
#define CMXFCR_TF3CS_CLK16 0x00000700 /* Transmit FCC3 Clock Source is CLK16 */
/*-----------------------------------------------------------------------
* CMXSCR - CMX SCC Clock Route Register
*/
#define CMXSCR_GR1 0x80000000 /* Grant Support of SCC1 */
#define CMXSCR_SC1 0x40000000 /* SCC1 connection */
#define CMXSCR_RS1CS_MSK 0x38000000 /* Receive SCC1 Clock Source Mask */
#define CMXSCR_TS1CS_MSK 0x07000000 /* Transmit SCC1 Clock Source Mask */
#define CMXSCR_GR2 0x00800000 /* Grant Support of SCC2 */
#define CMXSCR_SC2 0x00400000 /* SCC2 connection */
#define CMXSCR_RS2CS_MSK 0x00380000 /* Receive SCC2 Clock Source Mask */
#define CMXSCR_TS2CS_MSK 0x00070000 /* Transmit SCC2 Clock Source Mask */
#define CMXSCR_GR3 0x00008000 /* Grant Support of SCC3 */
#define CMXSCR_SC3 0x00004000 /* SCC3 connection */
#define CMXSCR_RS3CS_MSK 0x00003800 /* Receive SCC3 Clock Source Mask */
#define CMXSCR_TS3CS_MSK 0x00000700 /* Transmit SCC3 Clock Source Mask */
#define CMXSCR_GR4 0x00000080 /* Grant Support of SCC4 */
#define CMXSCR_SC4 0x00000040 /* SCC4 connection */
#define CMXSCR_RS4CS_MSK 0x00000038 /* Receive SCC4 Clock Source Mask */
#define CMXSCR_TS4CS_MSK 0x00000007 /* Transmit SCC4 Clock Source Mask */
#define CMXSCR_RS1CS_BRG1 0x00000000 /* SCC1 Rx Clock Source is BRG1 */
#define CMXSCR_RS1CS_BRG2 0x08000000 /* SCC1 Rx Clock Source is BRG2 */
#define CMXSCR_RS1CS_BRG3 0x10000000 /* SCC1 Rx Clock Source is BRG3 */
#define CMXSCR_RS1CS_BRG4 0x18000000 /* SCC1 Rx Clock Source is BRG4 */
#define CMXSCR_RS1CS_CLK11 0x20000000 /* SCC1 Rx Clock Source is CLK11 */
#define CMXSCR_RS1CS_CLK12 0x28000000 /* SCC1 Rx Clock Source is CLK12 */
#define CMXSCR_RS1CS_CLK3 0x30000000 /* SCC1 Rx Clock Source is CLK3 */
#define CMXSCR_RS1CS_CLK4 0x38000000 /* SCC1 Rx Clock Source is CLK4 */
#define CMXSCR_TS1CS_BRG1 0x00000000 /* SCC1 Tx Clock Source is BRG1 */
#define CMXSCR_TS1CS_BRG2 0x01000000 /* SCC1 Tx Clock Source is BRG2 */
#define CMXSCR_TS1CS_BRG3 0x02000000 /* SCC1 Tx Clock Source is BRG3 */
#define CMXSCR_TS1CS_BRG4 0x03000000 /* SCC1 Tx Clock Source is BRG4 */
#define CMXSCR_TS1CS_CLK11 0x04000000 /* SCC1 Tx Clock Source is CLK11 */
#define CMXSCR_TS1CS_CLK12 0x05000000 /* SCC1 Tx Clock Source is CLK12 */
#define CMXSCR_TS1CS_CLK3 0x06000000 /* SCC1 Tx Clock Source is CLK3 */
#define CMXSCR_TS1CS_CLK4 0x07000000 /* SCC1 Tx Clock Source is CLK4 */
#define CMXSCR_RS2CS_BRG1 0x00000000 /* SCC2 Rx Clock Source is BRG1 */
#define CMXSCR_RS2CS_BRG2 0x00080000 /* SCC2 Rx Clock Source is BRG2 */
#define CMXSCR_RS2CS_BRG3 0x00100000 /* SCC2 Rx Clock Source is BRG3 */
#define CMXSCR_RS2CS_BRG4 0x00180000 /* SCC2 Rx Clock Source is BRG4 */
#define CMXSCR_RS2CS_CLK11 0x00200000 /* SCC2 Rx Clock Source is CLK11 */
#define CMXSCR_RS2CS_CLK12 0x00280000 /* SCC2 Rx Clock Source is CLK12 */
#define CMXSCR_RS2CS_CLK3 0x00300000 /* SCC2 Rx Clock Source is CLK3 */
#define CMXSCR_RS2CS_CLK4 0x00380000 /* SCC2 Rx Clock Source is CLK4 */
#define CMXSCR_TS2CS_BRG1 0x00000000 /* SCC2 Tx Clock Source is BRG1 */
#define CMXSCR_TS2CS_BRG2 0x00010000 /* SCC2 Tx Clock Source is BRG2 */
#define CMXSCR_TS2CS_BRG3 0x00020000 /* SCC2 Tx Clock Source is BRG3 */
#define CMXSCR_TS2CS_BRG4 0x00030000 /* SCC2 Tx Clock Source is BRG4 */
#define CMXSCR_TS2CS_CLK11 0x00040000 /* SCC2 Tx Clock Source is CLK11 */
#define CMXSCR_TS2CS_CLK12 0x00050000 /* SCC2 Tx Clock Source is CLK12 */
#define CMXSCR_TS2CS_CLK3 0x00060000 /* SCC2 Tx Clock Source is CLK3 */
#define CMXSCR_TS2CS_CLK4 0x00070000 /* SCC2 Tx Clock Source is CLK4 */
#define CMXSCR_RS3CS_BRG1 0x00000000 /* SCC3 Rx Clock Source is BRG1 */
#define CMXSCR_RS3CS_BRG2 0x00000800 /* SCC3 Rx Clock Source is BRG2 */
#define CMXSCR_RS3CS_BRG3 0x00001000 /* SCC3 Rx Clock Source is BRG3 */
#define CMXSCR_RS3CS_BRG4 0x00001800 /* SCC3 Rx Clock Source is BRG4 */
#define CMXSCR_RS3CS_CLK5 0x00002000 /* SCC3 Rx Clock Source is CLK5 */
#define CMXSCR_RS3CS_CLK6 0x00002800 /* SCC3 Rx Clock Source is CLK6 */
#define CMXSCR_RS3CS_CLK7 0x00003000 /* SCC3 Rx Clock Source is CLK7 */
#define CMXSCR_RS3CS_CLK8 0x00003800 /* SCC3 Rx Clock Source is CLK8 */
#define CMXSCR_TS3CS_BRG1 0x00000000 /* SCC3 Tx Clock Source is BRG1 */
#define CMXSCR_TS3CS_BRG2 0x00000100 /* SCC3 Tx Clock Source is BRG2 */
#define CMXSCR_TS3CS_BRG3 0x00000200 /* SCC3 Tx Clock Source is BRG3 */
#define CMXSCR_TS3CS_BRG4 0x00000300 /* SCC3 Tx Clock Source is BRG4 */
#define CMXSCR_TS3CS_CLK5 0x00000400 /* SCC3 Tx Clock Source is CLK5 */
#define CMXSCR_TS3CS_CLK6 0x00000500 /* SCC3 Tx Clock Source is CLK6 */
#define CMXSCR_TS3CS_CLK7 0x00000600 /* SCC3 Tx Clock Source is CLK7 */
#define CMXSCR_TS3CS_CLK8 0x00000700 /* SCC3 Tx Clock Source is CLK8 */
#define CMXSCR_RS4CS_BRG1 0x00000000 /* SCC4 Rx Clock Source is BRG1 */
#define CMXSCR_RS4CS_BRG2 0x00000008 /* SCC4 Rx Clock Source is BRG2 */
#define CMXSCR_RS4CS_BRG3 0x00000010 /* SCC4 Rx Clock Source is BRG3 */
#define CMXSCR_RS4CS_BRG4 0x00000018 /* SCC4 Rx Clock Source is BRG4 */
#define CMXSCR_RS4CS_CLK5 0x00000020 /* SCC4 Rx Clock Source is CLK5 */
#define CMXSCR_RS4CS_CLK6 0x00000028 /* SCC4 Rx Clock Source is CLK6 */
#define CMXSCR_RS4CS_CLK7 0x00000030 /* SCC4 Rx Clock Source is CLK7 */
#define CMXSCR_RS4CS_CLK8 0x00000038 /* SCC4 Rx Clock Source is CLK8 */
#define CMXSCR_TS4CS_BRG1 0x00000000 /* SCC4 Tx Clock Source is BRG1 */
#define CMXSCR_TS4CS_BRG2 0x00000001 /* SCC4 Tx Clock Source is BRG2 */
#define CMXSCR_TS4CS_BRG3 0x00000002 /* SCC4 Tx Clock Source is BRG3 */
#define CMXSCR_TS4CS_BRG4 0x00000003 /* SCC4 Tx Clock Source is BRG4 */
#define CMXSCR_TS4CS_CLK5 0x00000004 /* SCC4 Tx Clock Source is CLK5 */
#define CMXSCR_TS4CS_CLK6 0x00000005 /* SCC4 Tx Clock Source is CLK6 */
#define CMXSCR_TS4CS_CLK7 0x00000006 /* SCC4 Tx Clock Source is CLK7 */
#define CMXSCR_TS4CS_CLK8 0x00000007 /* SCC4 Tx Clock Source is CLK8 */
#endif /* __CPM2__ */
#endif /* __KERNEL__ */
/*
* MPC8260 Internal Memory Map
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
*
* The Internal Memory Map of the 8260. I don't know how generic
* this will be, as I don't have any knowledge of the subsequent
* parts at this time. I copied this from the 8xx_immap.h.
*/
#ifdef __KERNEL__
#ifndef __IMMAP_82XX__
#define __IMMAP_82XX__
/* System configuration registers.
*/
typedef struct sys_conf {
uint sc_siumcr;
uint sc_sypcr;
char res1[6];
ushort sc_swsr;
char res2[20];
uint sc_bcr;
u_char sc_ppc_acr;
char res3[3];
uint sc_ppc_alrh;
uint sc_ppc_alrl;
u_char sc_lcl_acr;
char res4[3];
uint sc_lcl_alrh;
uint sc_lcl_alrl;
uint sc_tescr1;
uint sc_tescr2;
uint sc_ltescr1;
uint sc_ltescr2;
uint sc_pdtea;
u_char sc_pdtem;
char res5[3];
uint sc_ldtea;
u_char sc_ldtem;
char res6[163];
} sysconf8260_t;
/* Memory controller registers.
*/
typedef struct mem_ctlr {
uint memc_br0;
uint memc_or0;
uint memc_br1;
uint memc_or1;
uint memc_br2;
uint memc_or2;
uint memc_br3;
uint memc_or3;
uint memc_br4;
uint memc_or4;
uint memc_br5;
uint memc_or5;
uint memc_br6;
uint memc_or6;
uint memc_br7;
uint memc_or7;
uint memc_br8;
uint memc_or8;
uint memc_br9;
uint memc_or9;
uint memc_br10;
uint memc_or10;
uint memc_br11;
uint memc_or11;
char res1[8];
uint memc_mar;
char res2[4];
uint memc_mamr;
uint memc_mbmr;
uint memc_mcmr;
char res3[8];
ushort memc_mptpr;
char res4[2];
uint memc_mdr;
char res5[4];
uint memc_psdmr;
uint memc_lsdmr;
u_char memc_purt;
char res6[3];
u_char memc_psrt;
char res7[3];
u_char memc_lurt;
char res8[3];
u_char memc_lsrt;
char res9[3];
uint memc_immr;
char res10[84];
} memctl8260_t;
/* System Integration Timers.
*/
typedef struct sys_int_timers {
char res1[32];
ushort sit_tmcntsc;
char res2[2];
uint sit_tmcnt;
char res3[4];
uint sit_tmcntal;
char res4[16];
ushort sit_piscr;
char res5[2];
uint sit_pitc;
uint sit_pitr;
char res6[94];
char res7[2390];
} sit8260_t;
#define PISCR_PIRQ_MASK ((ushort)0xff00)
#define PISCR_PS ((ushort)0x0080)
#define PISCR_PIE ((ushort)0x0004)
#define PISCR_PTF ((ushort)0x0002)
#define PISCR_PTE ((ushort)0x0001)
/* Interrupt Controller.
*/
typedef struct interrupt_controller {
ushort ic_sicr;
char res1[2];
uint ic_sivec;
uint ic_sipnrh;
uint ic_sipnrl;
uint ic_siprr;
uint ic_scprrh;
uint ic_scprrl;
uint ic_simrh;
uint ic_simrl;
uint ic_siexr;
char res2[88];
} intctl8260_t;
/* Clocks and Reset.
*/
typedef struct clk_and_reset {
uint car_sccr;
char res1[4];
uint car_scmr;
char res2[4];
uint car_rsr;
uint car_rmr;
char res[104];
} car8260_t;
/* Input/Output Port control/status registers.
* Names consistent with processor manual, although they are different
* from the original 8xx names.......
*/
typedef struct io_port {
uint iop_pdira;
uint iop_ppara;
uint iop_psora;
uint iop_podra;
uint iop_pdata;
char res1[12];
uint iop_pdirb;
uint iop_pparb;
uint iop_psorb;
uint iop_podrb;
uint iop_pdatb;
char res2[12];
uint iop_pdirc;
uint iop_pparc;
uint iop_psorc;
uint iop_podrc;
uint iop_pdatc;
char res3[12];
uint iop_pdird;
uint iop_ppard;
uint iop_psord;
uint iop_podrd;
uint iop_pdatd;
char res4[12];
} iop8260_t;
/* Communication Processor Module Timers
*/
typedef struct cpm_timers {
u_char cpmt_tgcr1;
char res1[3];
u_char cpmt_tgcr2;
char res2[11];
ushort cpmt_tmr1;
ushort cpmt_tmr2;
ushort cpmt_trr1;
ushort cpmt_trr2;
ushort cpmt_tcr1;
ushort cpmt_tcr2;
ushort cpmt_tcn1;
ushort cpmt_tcn2;
ushort cpmt_tmr3;
ushort cpmt_tmr4;
ushort cpmt_trr3;
ushort cpmt_trr4;
ushort cpmt_tcr3;
ushort cpmt_tcr4;
ushort cpmt_tcn3;
ushort cpmt_tcn4;
ushort cpmt_ter1;
ushort cpmt_ter2;
ushort cpmt_ter3;
ushort cpmt_ter4;
char res3[584];
} cpmtimer8260_t;
/* DMA control/status registers.
*/
typedef struct sdma_csr {
char res0[24];
u_char sdma_sdsr;
char res1[3];
u_char sdma_sdmr;
char res2[3];
u_char sdma_idsr1;
char res3[3];
u_char sdma_idmr1;
char res4[3];
u_char sdma_idsr2;
char res5[3];
u_char sdma_idmr2;
char res6[3];
u_char sdma_idsr3;
char res7[3];
u_char sdma_idmr3;
char res8[3];
u_char sdma_idsr4;
char res9[3];
u_char sdma_idmr4;
char res10[707];
} sdma8260_t;
/* Fast controllers
*/
typedef struct fcc {
uint fcc_gfmr;
uint fcc_fpsmr;
ushort fcc_ftodr;
char res1[2];
ushort fcc_fdsr;
char res2[2];
ushort fcc_fcce;
char res3[2];
ushort fcc_fccm;
char res4[2];
u_char fcc_fccs;
char res5[3];
u_char fcc_ftirr_phy[4];
} fcc_t;
/* I2C
*/
typedef struct i2c {
u_char i2c_i2mod;
char res1[3];
u_char i2c_i2add;
char res2[3];
u_char i2c_i2brg;
char res3[3];
u_char i2c_i2com;
char res4[3];
u_char i2c_i2cer;
char res5[3];
u_char i2c_i2cmr;
char res6[331];
} i2c8260_t;
typedef struct scc { /* Serial communication channels */
uint scc_gsmrl;
uint scc_gsmrh;
ushort scc_pmsr;
char res1[2];
ushort scc_todr;
ushort scc_dsr;
ushort scc_scce;
char res2[2];
ushort scc_sccm;
char res3;
u_char scc_sccs;
char res4[8];
} scc_t;
typedef struct smc { /* Serial management channels */
char res1[2];
ushort smc_smcmr;
char res2[2];
u_char smc_smce;
char res3[3];
u_char smc_smcm;
char res4[5];
} smc_t;
/* Serial Peripheral Interface.
*/
typedef struct spi {
ushort spi_spmode;
char res1[4];
u_char spi_spie;
char res2[3];
u_char spi_spim;
char res3[2];
u_char spi_spcom;
char res4[82];
} spi_t;
/* CPM Mux.
*/
typedef struct cpmux {
u_char cmx_si1cr;
char res1;
u_char cmx_si2cr;
char res2;
uint cmx_fcr;
uint cmx_scr;
u_char cmx_smr;
char res3;
ushort cmx_uar;
char res4[16];
} cpmux_t;
/* SIRAM control
*/
typedef struct siram {
ushort si_amr;
ushort si_bmr;
ushort si_cmr;
ushort si_dmr;
u_char si_gmr;
char res1;
u_char si_cmdr;
char res2;
u_char si_str;
char res3;
ushort si_rsr;
} siramctl_t;
typedef struct mcc {
ushort mcc_mcce;
char res1[2];
ushort mcc_mccm;
char res2[2];
u_char mcc_mccf;
char res3[7];
} mcc_t;
typedef struct comm_proc {
uint cp_cpcr;
uint cp_rccr;
char res1[14];
ushort cp_rter;
char res2[2];
ushort cp_rtmr;
ushort cp_rtscr;
char res3[2];
uint cp_rtsr;
char res4[12];
} cpm8260_t;
/* ...and the whole thing wrapped up....
*/
typedef struct immap {
/* Some references are into the unique and known dpram spaces,
* others are from the generic base.
*/
#define im_dprambase im_dpram1
u_char im_dpram1[16*1024];
char res1[16*1024];
u_char im_dpram2[4*1024];
char res2[8*1024];
u_char im_dpram3[4*1024];
char res3[16*1024];
sysconf8260_t im_siu_conf; /* SIU Configuration */
memctl8260_t im_memctl; /* Memory Controller */
sit8260_t im_sit; /* System Integration Timers */
intctl8260_t im_intctl; /* Interrupt Controller */
car8260_t im_clkrst; /* Clocks and reset */
iop8260_t im_ioport; /* IO Port control/status */
cpmtimer8260_t im_cpmtimer; /* CPM timers */
sdma8260_t im_sdma; /* SDMA control/status */
fcc_t im_fcc[3]; /* Three FCCs */
char res4[159];
/* First set of baud rate generators.
*/
char res4a[496];
uint im_brgc5;
uint im_brgc6;
uint im_brgc7;
uint im_brgc8;
char res5[608];
i2c8260_t im_i2c; /* I2C control/status */
cpm8260_t im_cpm; /* Communication processor */
/* Second set of baud rate generators.
*/
uint im_brgc1;
uint im_brgc2;
uint im_brgc3;
uint im_brgc4;
scc_t im_scc[4]; /* Four SCCs */
smc_t im_smc[2]; /* Couple of SMCs */
spi_t im_spi; /* A SPI */
cpmux_t im_cpmux; /* CPM clock route mux */
siramctl_t im_siramctl1; /* First SI RAM Control */
mcc_t im_mcc1; /* First MCC */
siramctl_t im_siramctl2; /* Second SI RAM Control */
mcc_t im_mcc2; /* Second MCC */
char res6[1184];
ushort im_si1txram[256];
char res7[512];
ushort im_si1rxram[256];
char res8[512];
ushort im_si2txram[256];
char res9[512];
ushort im_si2rxram[256];
char res10[512];
char res11[4096];
} immap_t;
extern immap_t *immr;
#endif /* __IMMAP_82XX__ */
#endif /* __KERNEL__ */
/*
* CPM2 Internal Memory Map
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
*
* The Internal Memory Map for devices with CPM2 on them. This
* is the superset of all CPM2 devices (8260, 8266, 8280, 8272,
* 8560).
*/
#ifdef __KERNEL__
#ifndef __IMMAP_CPM2__
#define __IMMAP_CPM2__
/* System configuration registers.
*/
typedef struct sys_82xx_conf {
u32 sc_siumcr;
u32 sc_sypcr;
u8 res1[6];
u16 sc_swsr;
u8 res2[20];
u32 sc_bcr;
u8 sc_ppc_acr;
u8 res3[3];
u32 sc_ppc_alrh;
u32 sc_ppc_alrl;
u8 sc_lcl_acr;
u8 res4[3];
u32 sc_lcl_alrh;
u32 sc_lcl_alrl;
u32 sc_tescr1;
u32 sc_tescr2;
u32 sc_ltescr1;
u32 sc_ltescr2;
u32 sc_pdtea;
u8 sc_pdtem;
u8 res5[3];
u32 sc_ldtea;
u8 sc_ldtem;
u8 res6[163];
} sysconf_82xx_cpm2_t;
typedef struct sys_85xx_conf {
u32 sc_cear;
u16 sc_ceer;
u16 sc_cemr;
u8 res1[70];
u32 sc_smaer;
u8 res2[4];
u32 sc_smevr;
u32 sc_smctr;
u32 sc_lmaer;
u8 res3[4];
u32 sc_lmevr;
u32 sc_lmctr;
u8 res4[144];
} sysconf_85xx_cpm2_t;
typedef union sys_conf {
sysconf_82xx_cpm2_t siu_82xx;
sysconf_85xx_cpm2_t siu_85xx;
} sysconf_cpm2_t;
/* Memory controller registers.
*/
typedef struct mem_ctlr {
u32 memc_br0;
u32 memc_or0;
u32 memc_br1;
u32 memc_or1;
u32 memc_br2;
u32 memc_or2;
u32 memc_br3;
u32 memc_or3;
u32 memc_br4;
u32 memc_or4;
u32 memc_br5;
u32 memc_or5;
u32 memc_br6;
u32 memc_or6;
u32 memc_br7;
u32 memc_or7;
u32 memc_br8;
u32 memc_or8;
u32 memc_br9;
u32 memc_or9;
u32 memc_br10;
u32 memc_or10;
u32 memc_br11;
u32 memc_or11;
u8 res1[8];
u32 memc_mar;
u8 res2[4];
u32 memc_mamr;
u32 memc_mbmr;
u32 memc_mcmr;
u8 res3[8];
u16 memc_mptpr;
u8 res4[2];
u32 memc_mdr;
u8 res5[4];
u32 memc_psdmr;
u32 memc_lsdmr;
u8 memc_purt;
u8 res6[3];
u8 memc_psrt;
u8 res7[3];
u8 memc_lurt;
u8 res8[3];
u8 memc_lsrt;
u8 res9[3];
u32 memc_immr;
u32 memc_pcibr0;
u32 memc_pcibr1;
u8 res10[16];
u32 memc_pcimsk0;
u32 memc_pcimsk1;
u8 res11[52];
} memctl_cpm2_t;
/* System Integration Timers.
*/
typedef struct sys_int_timers {
u8 res1[32];
u16 sit_tmcntsc;
u8 res2[2];
u32 sit_tmcnt;
u8 res3[4];
u32 sit_tmcntal;
u8 res4[16];
u16 sit_piscr;
u8 res5[2];
u32 sit_pitc;
u32 sit_pitr;
u8 res6[92];
u8 res7[390];
} sit_cpm2_t;
#define PISCR_PIRQ_MASK ((u16)0xff00)
#define PISCR_PS ((u16)0x0080)
#define PISCR_PIE ((u16)0x0004)
#define PISCR_PTF ((u16)0x0002)
#define PISCR_PTE ((u16)0x0001)
/* PCI Controller.
*/
typedef struct pci_ctlr {
u32 pci_omisr;
u32 pci_omimr;
u8 res1[8];
u32 pci_ifqpr;
u32 pci_ofqpr;
u8 res2[8];
u32 pci_imr0;
u32 pci_imr1;
u32 pci_omr0;
u32 pci_omr1;
u32 pci_odr;
u8 res3[4];
u32 pci_idr;
u8 res4[20];
u32 pci_imisr;
u32 pci_imimr;
u8 res5[24];
u32 pci_ifhpr;
u8 res6[4];
u32 pci_iftpr;
u8 res7[4];
u32 pci_iphpr;
u8 res8[4];
u32 pci_iptpr;
u8 res9[4];
u32 pci_ofhpr;
u8 res10[4];
u32 pci_oftpr;
u8 res11[4];
u32 pci_ophpr;
u8 res12[4];
u32 pci_optpr;
u8 res13[8];
u32 pci_mucr;
u8 res14[8];
u32 pci_qbar;
u8 res15[12];
u32 pci_dmamr0;
u32 pci_dmasr0;
u32 pci_dmacdar0;
u8 res16[4];
u32 pci_dmasar0;
u8 res17[4];
u32 pci_dmadar0;
u8 res18[4];
u32 pci_dmabcr0;
u32 pci_dmandar0;
u8 res19[86];
u32 pci_dmamr1;
u32 pci_dmasr1;
u32 pci_dmacdar1;
u8 res20[4];
u32 pci_dmasar1;
u8 res21[4];
u32 pci_dmadar1;
u8 res22[4];
u32 pci_dmabcr1;
u32 pci_dmandar1;
u8 res23[88];
u32 pci_dmamr2;
u32 pci_dmasr2;
u32 pci_dmacdar2;
u8 res24[4];
u32 pci_dmasar2;
u8 res25[4];
u32 pci_dmadar2;
u8 res26[4];
u32 pci_dmabcr2;
u32 pci_dmandar2;
u8 res27[88];
u32 pci_dmamr3;
u32 pci_dmasr3;
u32 pci_dmacdar3;
u8 res28[4];
u32 pci_dmasar3;
u8 res29[4];
u32 pci_dmadar3;
u8 res30[4];
u32 pci_dmabcr3;
u32 pci_dmandar3;
u8 res31[344];
u32 pci_potar0;
u8 res32[4];
u32 pci_pobar0;
u8 res33[4];
u32 pci_pocmr0;
u8 res34[4];
u32 pci_potar1;
u8 res35[4];
u32 pci_pobar1;
u8 res36[4];
u32 pci_pocmr1;
u8 res37[4];
u32 pci_potar2;
u8 res38[4];
u32 pci_pobar2;
u8 res39[4];
u32 pci_pocmr2;
u8 res40[50];
u32 pci_ptcr;
u32 pci_gpcr;
u32 pci_gcr;
u32 pci_esr;
u32 pci_emr;
u32 pci_ecr;
u32 pci_eacr;
u8 res41[4];
u32 pci_edcr;
u8 res42[4];
u32 pci_eccr;
u8 res43[44];
u32 pci_pitar1;
u8 res44[4];
u32 pci_pibar1;
u8 res45[4];
u32 pci_picmr1;
u8 res46[4];
u32 pci_pitar0;
u8 res47[4];
u32 pci_pibar0;
u8 res48[4];
u32 pci_picmr0;
u8 res49[4];
u32 pci_cfg_addr;
u32 pci_cfg_data;
u32 pci_int_ack;
u8 res50[756];
} pci_cpm2_t;
/* Interrupt Controller.
*/
typedef struct interrupt_controller {
u16 ic_sicr;
u8 res1[2];
u32 ic_sivec;
u32 ic_sipnrh;
u32 ic_sipnrl;
u32 ic_siprr;
u32 ic_scprrh;
u32 ic_scprrl;
u32 ic_simrh;
u32 ic_simrl;
u32 ic_siexr;
u8 res2[88];
} intctl_cpm2_t;
/* Clocks and Reset.
*/
typedef struct clk_and_reset {
u32 car_sccr;
u8 res1[4];
u32 car_scmr;
u8 res2[4];
u32 car_rsr;
u32 car_rmr;
u8 res[104];
} car_cpm2_t;
/* Input/Output Port control/status registers.
* Names consistent with processor manual, although they are different
* from the original 8xx names.......
*/
typedef struct io_port {
u32 iop_pdira;
u32 iop_ppara;
u32 iop_psora;
u32 iop_podra;
u32 iop_pdata;
u8 res1[12];
u32 iop_pdirb;
u32 iop_pparb;
u32 iop_psorb;
u32 iop_podrb;
u32 iop_pdatb;
u8 res2[12];
u32 iop_pdirc;
u32 iop_pparc;
u32 iop_psorc;
u32 iop_podrc;
u32 iop_pdatc;
u8 res3[12];
u32 iop_pdird;
u32 iop_ppard;
u32 iop_psord;
u32 iop_podrd;
u32 iop_pdatd;
u8 res4[12];
} iop_cpm2_t;
/* Communication Processor Module Timers
*/
typedef struct cpm_timers {
u8 cpmt_tgcr1;
u8 res1[3];
u8 cpmt_tgcr2;
u8 res2[11];
u16 cpmt_tmr1;
u16 cpmt_tmr2;
u16 cpmt_trr1;
u16 cpmt_trr2;
u16 cpmt_tcr1;
u16 cpmt_tcr2;
u16 cpmt_tcn1;
u16 cpmt_tcn2;
u16 cpmt_tmr3;
u16 cpmt_tmr4;
u16 cpmt_trr3;
u16 cpmt_trr4;
u16 cpmt_tcr3;
u16 cpmt_tcr4;
u16 cpmt_tcn3;
u16 cpmt_tcn4;
u16 cpmt_ter1;
u16 cpmt_ter2;
u16 cpmt_ter3;
u16 cpmt_ter4;
u8 res3[584];
} cpmtimer_cpm2_t;
/* DMA control/status registers.
*/
typedef struct sdma_csr {
u8 res0[24];
u8 sdma_sdsr;
u8 res1[3];
u8 sdma_sdmr;
u8 res2[3];
u8 sdma_idsr1;
u8 res3[3];
u8 sdma_idmr1;
u8 res4[3];
u8 sdma_idsr2;
u8 res5[3];
u8 sdma_idmr2;
u8 res6[3];
u8 sdma_idsr3;
u8 res7[3];
u8 sdma_idmr3;
u8 res8[3];
u8 sdma_idsr4;
u8 res9[3];
u8 sdma_idmr4;
u8 res10[707];
} sdma_cpm2_t;
/* Fast controllers
*/
typedef struct fcc {
u32 fcc_gfmr;
u32 fcc_fpsmr;
u16 fcc_ftodr;
u8 res1[2];
u16 fcc_fdsr;
u8 res2[2];
u16 fcc_fcce;
u8 res3[2];
u16 fcc_fccm;
u8 res4[2];
u8 fcc_fccs;
u8 res5[3];
u8 fcc_ftirr_phy[4];
} fcc_t;
/* Fast controllers continued
*/
typedef struct fcc_c {
u32 fcc_firper;
u32 fcc_firer;
u32 fcc_firsr_hi;
u32 fcc_firsr_lo;
u8 fcc_gfemr;
u8 res1[15];
} fcc_c_t;
/* TC Layer
*/
typedef struct tclayer {
u16 tc_tcmode;
u16 tc_cdsmr;
u16 tc_tcer;
u16 tc_rcc;
u16 tc_tcmr;
u16 tc_fcc;
u16 tc_ccc;
u16 tc_icc;
u16 tc_tcc;
u16 tc_ecc;
u8 res1[12];
} tclayer_t;
/* I2C
*/
typedef struct i2c {
u8 i2c_i2mod;
u8 res1[3];
u8 i2c_i2add;
u8 res2[3];
u8 i2c_i2brg;
u8 res3[3];
u8 i2c_i2com;
u8 res4[3];
u8 i2c_i2cer;
u8 res5[3];
u8 i2c_i2cmr;
u8 res6[331];
} i2c_cpm2_t;
typedef struct scc { /* Serial communication channels */
u32 scc_gsmrl;
u32 scc_gsmrh;
u16 scc_psmr;
u8 res1[2];
u16 scc_todr;
u16 scc_dsr;
u16 scc_scce;
u8 res2[2];
u16 scc_sccm;
u8 res3;
u8 scc_sccs;
u8 res4[8];
} scc_t;
typedef struct smc { /* Serial management channels */
u8 res1[2];
u16 smc_smcmr;
u8 res2[2];
u8 smc_smce;
u8 res3[3];
u8 smc_smcm;
u8 res4[5];
} smc_t;
/* Serial Peripheral Interface.
*/
typedef struct spi_ctrl {
u16 spi_spmode;
u8 res1[4];
u8 spi_spie;
u8 res2[3];
u8 spi_spim;
u8 res3[2];
u8 spi_spcom;
u8 res4[82];
} spictl_cpm2_t;
/* CPM Mux.
*/
typedef struct cpmux {
u8 cmx_si1cr;
u8 res1;
u8 cmx_si2cr;
u8 res2;
u32 cmx_fcr;
u32 cmx_scr;
u8 cmx_smr;
u8 res3;
u16 cmx_uar;
u8 res4[16];
} cpmux_t;
/* SIRAM control
*/
typedef struct siram {
u16 si_amr;
u16 si_bmr;
u16 si_cmr;
u16 si_dmr;
u8 si_gmr;
u8 res1;
u8 si_cmdr;
u8 res2;
u8 si_str;
u8 res3;
u16 si_rsr;
} siramctl_t;
typedef struct mcc {
u16 mcc_mcce;
u8 res1[2];
u16 mcc_mccm;
u8 res2[2];
u8 mcc_mccf;
u8 res3[7];
} mcc_t;
typedef struct comm_proc {
u32 cp_cpcr;
u32 cp_rccr;
u8 res1[14];
u16 cp_rter;
u8 res2[2];
u16 cp_rtmr;
u16 cp_rtscr;
u8 res3[2];
u32 cp_rtsr;
u8 res4[12];
} cpm_cpm2_t;
/* USB Controller.
*/
typedef struct usb_ctlr {
u8 usb_usmod;
u8 usb_usadr;
u8 usb_uscom;
u8 res1[1];
u16 usb_usep1;
u16 usb_usep2;
u16 usb_usep3;
u16 usb_usep4;
u8 res2[4];
u16 usb_usber;
u8 res3[2];
u16 usb_usbmr;
u8 usb_usbs;
u8 res4[7];
} usb_cpm2_t;
/* ...and the whole thing wrapped up....
*/
typedef struct immap {
/* Some references are into the unique and known dpram spaces,
* others are from the generic base.
*/
#define im_dprambase im_dpram1
u8 im_dpram1[16*1024];
u8 res1[16*1024];
u8 im_dpram2[4*1024];
u8 res2[8*1024];
u8 im_dpram3[4*1024];
u8 res3[16*1024];
sysconf_cpm2_t im_siu_conf; /* SIU Configuration */
memctl_cpm2_t im_memctl; /* Memory Controller */
sit_cpm2_t im_sit; /* System Integration Timers */
pci_cpm2_t im_pci; /* PCI Controller */
intctl_cpm2_t im_intctl; /* Interrupt Controller */
car_cpm2_t im_clkrst; /* Clocks and reset */
iop_cpm2_t im_ioport; /* IO Port control/status */
cpmtimer_cpm2_t im_cpmtimer; /* CPM timers */
sdma_cpm2_t im_sdma; /* SDMA control/status */
fcc_t im_fcc[3]; /* Three FCCs */
u8 res4z[32];
fcc_c_t im_fcc_c[3]; /* Continued FCCs */
u8 res4[32];
tclayer_t im_tclayer[8]; /* Eight TCLayers */
u16 tc_tcgsr;
u16 tc_tcger;
/* First set of baud rate generators.
*/
u8 res[236];
u32 im_brgc5;
u32 im_brgc6;
u32 im_brgc7;
u32 im_brgc8;
u8 res5[608];
i2c_cpm2_t im_i2c; /* I2C control/status */
cpm_cpm2_t im_cpm; /* Communication processor */
/* Second set of baud rate generators.
*/
u32 im_brgc1;
u32 im_brgc2;
u32 im_brgc3;
u32 im_brgc4;
scc_t im_scc[4]; /* Four SCCs */
smc_t im_smc[2]; /* Couple of SMCs */
spictl_cpm2_t im_spi; /* A SPI */
cpmux_t im_cpmux; /* CPM clock route mux */
siramctl_t im_siramctl1; /* First SI RAM Control */
mcc_t im_mcc1; /* First MCC */
siramctl_t im_siramctl2; /* Second SI RAM Control */
mcc_t im_mcc2; /* Second MCC */
usb_cpm2_t im_usb; /* USB Controller */
u8 res6[1153];
u16 im_si1txram[256];
u8 res7[512];
u16 im_si1rxram[256];
u8 res8[512];
u16 im_si2txram[256];
u8 res9[512];
u16 im_si2rxram[256];
u8 res10[512];
u8 res11[4096];
} cpm2_map_t;
extern cpm2_map_t *cpm2_immr;
#endif /* __IMMAP_CPM2__ */
#endif /* __KERNEL__ */
......@@ -140,18 +140,27 @@ extern __inline__ void name(unsigned int val, unsigned int port) \
: : "r" (val), "r" (port + _IO_BASE)); \
}
__do_in_asm(inb, "lbzx")
__do_out_asm(outb, "stbx")
#ifdef CONFIG_APUS
__do_in_asm(inb, "lbzx")
__do_in_asm(inw, "lhz%U1%X1")
__do_in_asm(inl, "lwz%U1%X1")
__do_out_asm(outl,"stw%U0%X0")
__do_out_asm(outw, "sth%U0%X0")
#elif defined (CONFIG_8260_PCI9)
/* in asm cannot be defined if PCI9 workaround is used */
#define inb(port) in_8((u8 *)((port)+_IO_BASE))
#define inw(port) in_le16((u16 *)((port)+_IO_BASE))
#define inl(port) in_le32((u32 *)((port)+_IO_BASE))
__do_out_asm(outw, "sthbrx")
__do_out_asm(outl, "stwbrx")
#else
__do_in_asm(inb, "lbzx")
__do_in_asm(inw, "lhbrx")
__do_in_asm(inl, "lwbrx")
__do_out_asm(outw, "sthbrx")
__do_out_asm(outl, "stwbrx")
#endif
#define inb_p(port) inb((port))
......@@ -391,4 +400,9 @@ static inline int isa_check_signature(unsigned long io_addr,
}
#endif /* _PPC_IO_H */
#ifdef CONFIG_8260_PCI9
#include <asm/mpc8260_pci9.h>
#endif
#endif /* __KERNEL__ */
......@@ -177,17 +177,55 @@ static __inline__ int irq_canonicalize(int irq)
*/
#define NR_SIU_INTS 64
/* There are many more than these, we will add them as we need them.
*/
#define SIU_INT_ERROR ((uint)0x00)
#define SIU_INT_I2C ((uint)0x01)
#define SIU_INT_SPI ((uint)0x02)
#define SIU_INT_RISC ((uint)0x03)
#define SIU_INT_SMC1 ((uint)0x04)
#define SIU_INT_SMC2 ((uint)0x05)
#define SIU_INT_IDMA1 ((uint)0x06)
#define SIU_INT_IDMA2 ((uint)0x07)
#define SIU_INT_IDMA3 ((uint)0x08)
#define SIU_INT_IDMA4 ((uint)0x09)
#define SIU_INT_SDMA ((uint)0x0a)
#define SIU_INT_TIMER1 ((uint)0x0c)
#define SIU_INT_TIMER2 ((uint)0x0d)
#define SIU_INT_TIMER3 ((uint)0x0e)
#define SIU_INT_TIMER4 ((uint)0x0f)
#define SIU_INT_TMCNT ((uint)0x10)
#define SIU_INT_PIT ((uint)0x11)
#define SIU_INT_IRQ1 ((uint)0x13)
#define SIU_INT_IRQ2 ((uint)0x14)
#define SIU_INT_IRQ3 ((uint)0x15)
#define SIU_INT_IRQ4 ((uint)0x16)
#define SIU_INT_IRQ5 ((uint)0x17)
#define SIU_INT_IRQ6 ((uint)0x18)
#define SIU_INT_IRQ7 ((uint)0x19)
#define SIU_INT_FCC1 ((uint)0x20)
#define SIU_INT_FCC2 ((uint)0x21)
#define SIU_INT_FCC3 ((uint)0x22)
#define SIU_INT_MCC1 ((uint)0x24)
#define SIU_INT_MCC2 ((uint)0x25)
#define SIU_INT_SCC1 ((uint)0x28)
#define SIU_INT_SCC2 ((uint)0x29)
#define SIU_INT_SCC3 ((uint)0x2a)
#define SIU_INT_SCC4 ((uint)0x2b)
#define SIU_INT_PC15 ((uint)0x30)
#define SIU_INT_PC14 ((uint)0x31)
#define SIU_INT_PC13 ((uint)0x32)
#define SIU_INT_PC12 ((uint)0x33)
#define SIU_INT_PC11 ((uint)0x34)
#define SIU_INT_PC10 ((uint)0x35)
#define SIU_INT_PC9 ((uint)0x36)
#define SIU_INT_PC8 ((uint)0x37)
#define SIU_INT_PC7 ((uint)0x38)
#define SIU_INT_PC6 ((uint)0x39)
#define SIU_INT_PC5 ((uint)0x3a)
#define SIU_INT_PC4 ((uint)0x3b)
#define SIU_INT_PC3 ((uint)0x3c)
#define SIU_INT_PC2 ((uint)0x3d)
#define SIU_INT_PC1 ((uint)0x3e)
#define SIU_INT_PC0 ((uint)0x3f)
#endif /* CONFIG_8260 */
......
/*
* include/asm-ppc/m8260_pci.h
*
* Definitions for the MPC8250/MPC8265/MPC8266 integrated PCI host bridge.
*
* 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.
*/
#ifdef __KERNEL__
#ifndef __M8260_PCI_H
#define __M8260_PCI_H
#include <linux/pci_ids.h>
/*
* Define the vendor/device ID for the MPC8265.
*/
#define PCI_DEVICE_ID_MPC8265 ((0x18C0 << 16) | PCI_VENDOR_ID_MOTOROLA)
#define M8265_PCIBR0 0x101ac
#define M8265_PCIBR1 0x101b0
#define M8265_PCIMSK0 0x101c4
#define M8265_PCIMSK1 0x101c8
/* Bit definitions for PCIBR registers */
#define PCIBR_ENABLE 0x00000001
/* Bit definitions for PCIMSK registers */
#define PCIMSK_32KiB 0xFFFF8000 /* Size of window, smallest */
#define PCIMSK_64KiB 0xFFFF0000
#define PCIMSK_128KiB 0xFFFE0000
#define PCIMSK_256KiB 0xFFFC0000
#define PCIMSK_512KiB 0xFFF80000
#define PCIMSK_1MiB 0xFFF00000
#define PCIMSK_2MiB 0xFFE00000
#define PCIMSK_4MiB 0xFFC00000
#define PCIMSK_8MiB 0xFF800000
#define PCIMSK_16MiB 0xFF000000
#define PCIMSK_32MiB 0xFE000000
#define PCIMSK_64MiB 0xFC000000
#define PCIMSK_128MiB 0xF8000000
#define PCIMSK_256MiB 0xF0000000
#define PCIMSK_512MiB 0xE0000000
#define PCIMSK_1GiB 0xC0000000 /* Size of window, largest */
#define M826X_SCCR_PCI_MODE_EN 0x100
/*
* Outbound ATU registers (3 sets). These registers control how 60x bus (local)
* addresses are translated to PCI addresses when the MPC826x is a PCI bus
* master (initiator).
*/
#define POTAR_REG0 0x10800 /* PCI Outbound Translation Addr registers */
#define POTAR_REG1 0x10818
#define POTAR_REG2 0x10830
#define POBAR_REG0 0x10808 /* PCI Outbound Base Addr registers */
#define POBAR_REG1 0x10820
#define POBAR_REG2 0x10838
#define POCMR_REG0 0x10810 /* PCI Outbound Comparison Mask registers */
#define POCMR_REG1 0x10828
#define POCMR_REG2 0x10840
/* Bit definitions for POMCR registers */
#define POCMR_MASK_4KiB 0x000FFFFF
#define POCMR_MASK_8KiB 0x000FFFFE
#define POCMR_MASK_16KiB 0x000FFFFC
#define POCMR_MASK_32KiB 0x000FFFF8
#define POCMR_MASK_64KiB 0x000FFFF0
#define POCMR_MASK_128KiB 0x000FFFE0
#define POCMR_MASK_256KiB 0x000FFFC0
#define POCMR_MASK_512KiB 0x000FFF80
#define POCMR_MASK_1MiB 0x000FFF00
#define POCMR_MASK_2MiB 0x000FFE00
#define POCMR_MASK_4MiB 0x000FFC00
#define POCMR_MASK_8MiB 0x000FF800
#define POCMR_MASK_16MiB 0x000FF000
#define POCMR_MASK_32MiB 0x000FE000
#define POCMR_MASK_64MiB 0x000FC000
#define POCMR_MASK_128MiB 0x000F8000
#define POCMR_MASK_256MiB 0x000F0000
#define POCMR_MASK_512MiB 0x000E0000
#define POCMR_MASK_1GiB 0x000C0000
#define POCMR_ENABLE 0x80000000
#define POCMR_PCI_IO 0x40000000
#define POCMR_PREFETCH_EN 0x20000000
/* Soft PCI reset */
#define PCI_GCR_REG 0x10880
/* Bit definitions for PCI_GCR registers */
#define PCIGCR_PCI_BUS_EN 0x1
#define PCI_EMR_REG 0x10888
/*
* Inbound ATU registers (2 sets). These registers control how PCI addresses
* are translated to 60x bus (local) addresses when the MPC826x is a PCI bus target.
*/
#define PITAR_REG1 0x108D0
#define PIBAR_REG1 0x108D8
#define PICMR_REG1 0x108E0
#define PITAR_REG0 0x108E8
#define PIBAR_REG0 0x108F0
#define PICMR_REG0 0x108F8
/* Bit definitions for PCI Inbound Comparison Mask registers */
#define PICMR_MASK_4KiB 0x000FFFFF
#define PICMR_MASK_8KiB 0x000FFFFE
#define PICMR_MASK_16KiB 0x000FFFFC
#define PICMR_MASK_32KiB 0x000FFFF8
#define PICMR_MASK_64KiB 0x000FFFF0
#define PICMR_MASK_128KiB 0x000FFFE0
#define PICMR_MASK_256KiB 0x000FFFC0
#define PICMR_MASK_512KiB 0x000FFF80
#define PICMR_MASK_1MiB 0x000FFF00
#define PICMR_MASK_2MiB 0x000FFE00
#define PICMR_MASK_4MiB 0x000FFC00
#define PICMR_MASK_8MiB 0x000FF800
#define PICMR_MASK_16MiB 0x000FF000
#define PICMR_MASK_32MiB 0x000FE000
#define PICMR_MASK_64MiB 0x000FC000
#define PICMR_MASK_128MiB 0x000F8000
#define PICMR_MASK_256MiB 0x000F0000
#define PICMR_MASK_512MiB 0x000E0000
#define PICMR_MASK_1GiB 0x000C0000
#define PICMR_ENABLE 0x80000000
#define PICMR_NO_SNOOP_EN 0x40000000
#define PICMR_PREFETCH_EN 0x20000000
/* PCI error Registers */
#define PCI_ERROR_STATUS_REG 0x10884
#define PCI_ERROR_MASK_REG 0x10888
#define PCI_ERROR_CONTROL_REG 0x1088C
#define PCI_ERROR_ADRS_CAPTURE_REG 0x10890
#define PCI_ERROR_DATA_CAPTURE_REG 0x10898
#define PCI_ERROR_CTRL_CAPTURE_REG 0x108A0
/* PCI error Register bit defines */
#define PCI_ERROR_PCI_ADDR_PAR 0x00000001
#define PCI_ERROR_PCI_DATA_PAR_WR 0x00000002
#define PCI_ERROR_PCI_DATA_PAR_RD 0x00000004
#define PCI_ERROR_PCI_NO_RSP 0x00000008
#define PCI_ERROR_PCI_TAR_ABT 0x00000010
#define PCI_ERROR_PCI_SERR 0x00000020
#define PCI_ERROR_PCI_PERR_RD 0x00000040
#define PCI_ERROR_PCI_PERR_WR 0x00000080
#define PCI_ERROR_I2O_OFQO 0x00000100
#define PCI_ERROR_I2O_IPQO 0x00000200
#define PCI_ERROR_IRA 0x00000400
#define PCI_ERROR_NMI 0x00000800
#define PCI_ERROR_I2O_DBMC 0x00001000
/*
* Register pair used to generate configuration cycles on the PCI bus
* and access the MPC826x's own PCI configuration registers.
*/
#define PCI_CFG_ADDR_REG 0x10900
#define PCI_CFG_DATA_REG 0x10904
/* Bus parking decides where the bus control sits when idle */
/* If modifying memory controllers for PCI park on the core */
#define PPC_ACR_BUS_PARK_CORE 0x6
#define PPC_ACR_BUS_PARK_PCI 0x3
#endif /* __M8260_PCI_H */
#endif /* __KERNEL__ */
......@@ -36,6 +36,10 @@
#include <platforms/tqm8260.h>
#endif
#ifdef CONFIG_PQ2ADS
#include <platforms/pq2ads.h>
#endif
/* Make sure the memory translation stuff is there if PCI not used.
*/
#ifndef _IO_BASE
......
/* include/asm-ppc/mpc8260_pci9.h
*
* Undefine the PCI read* and in* macros so we can define them as functions
* that implement the workaround for the MPC8260 device erratum PCI 9.
*
* This header file should only be included at the end of include/asm-ppc/io.h
* and never included directly anywhere else.
*
* Author: andy_lowe@mvista.com
*
* 2003 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#ifndef _PPC_IO_H
#error "Do not include mpc8260_pci9.h directly."
#endif
#ifdef __KERNEL__
#ifndef __CONFIG_8260_PCI9_DEFS
#define __CONFIG_8260_PCI9_DEFS
#undef readb
#undef readw
#undef readl
#undef insb
#undef insw
#undef insl
#undef inb
#undef inw
#undef inl
#undef insw_ns
#undef insl_ns
#undef memcpy_fromio
extern int readb(volatile unsigned char *addr);
extern int readw(volatile unsigned short *addr);
extern unsigned readl(volatile unsigned *addr);
extern void insb(unsigned port, void *buf, int ns);
extern void insw(unsigned port, void *buf, int ns);
extern void insl(unsigned port, void *buf, int nl);
extern int inb(unsigned port);
extern int inw(unsigned port);
extern unsigned inl(unsigned port);
extern void insw_ns(unsigned port, void *buf, int ns);
extern void insl_ns(unsigned port, void *buf, int nl);
extern void *memcpy_fromio(void *dest, unsigned long src, size_t count);
#endif /* !__CONFIG_8260_PCI9_DEFS */
#endif /* __KERNEL__ */
......@@ -52,7 +52,7 @@ typedef struct bd_info {
unsigned long bi_flashoffset; /* reserved area for startup monitor */
unsigned long bi_sramstart; /* start of SRAM memory */
unsigned long bi_sramsize; /* size of SRAM memory */
#if defined(CONFIG_8xx) || defined(CONFIG_8260) || defined(CONFIG_85xx)
#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx)
unsigned long bi_immr_base; /* base of IMMR register */
#endif
unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
......@@ -61,7 +61,7 @@ typedef struct bd_info {
unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
unsigned long bi_intfreq; /* Internal Freq, in MHz */
unsigned long bi_busfreq; /* Bus Freq, in MHz */
#if defined(CONFIG_8260)
#if defined(CONFIG_CPM2)
unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */
unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */
unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */
......
......@@ -80,6 +80,9 @@
/* SGI IP22 aka Indy / Challenge S / Indigo 2 */
#define PORT_IP22ZILOG 56
/* PPC CPM type number */
#define PORT_CPM 57
#ifdef __KERNEL__
#include <linux/config.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment