Commit d9f7fc6b authored by Tom Rini's avatar Tom Rini

ppc32: Update MPC8xx code to quasi functional

From: Dan Malek <dan@embeddededge.com>
Signed-off-by: default avatarRobert P. J. Day <rpjday@mindspring.com>
Signed-off-by: default avatarTom Rini <trini@kernel.crashing.org>
parent 0b3e8d29
......@@ -74,37 +74,6 @@ config ENET_BIG_BUFFERS
Allocate large buffers for MPC8xx Etherenet. Increases throughput
and decreases the likelihood of dropped packets, but costs memory.
config SMC2_UART
bool "Use SMC2 for UART"
help
If you would like to use SMC2 as a serial port, say Y here.
If in doubt, say Y here.
config ALTSMC2
bool "Use Alternate SMC2 I/O (823/850)"
depends on SMC2_UART
help
If you have an MPC823 or MPC850 and would like to use the alternate
SMC2 for I/O, say Y here.
If in doubt, say N here.
config CONS_SMC2
bool "Use SMC2 for Console"
depends on SMC2_UART
help
If you are going to have a serial console on your device and are
using SMC2 for your serial port, say Y here, else say N.
config USE_SCC_IO
bool "Enable SCC2 and SCC3 for UART"
help
If your MPC8xx board has other SCC ports that you would like to use
for for a serial port, say Y here.
If in doubt, say N here.
config HTDMSOUND
bool "Embedded Planet HIOX Audio"
depends on SOUND=y
......@@ -134,13 +103,36 @@ config 8xx_CPU6
If in doubt, say N here.
config UCODE_PATCH
bool "I2C/SPI Microcode Patch"
choice
prompt "Microcode patch selection"
default NO_UCODE_PATCH
help
Help not implemented yet, coming soon.
config NO_UCODE_PATCH
bool "None"
config USB_SOF_UCODE_PATCH
bool "USB SOF patch"
help
Help not implemented yet, coming soon.
config I2C_SPI_UCODE_PATCH
bool "I2C/SPI relocation patch"
help
Motorola releases microcode updates for their 8xx CPM modules. The
microcode update file has updates for IIC, SMC and USB. Currently only
the USB update is available by default, if the MPC8xx USB option is
enabled. If in doubt, say 'N' here.
Help not implemented yet, coming soon.
config I2C_SPI_SMC1_UCODE_PATCH
bool "I2C/SPI/SMC1 relocation patch"
help
Help not implemented yet, coming soon.
endchoice
config UCODE_PATCH
bool
default y
depends on !NO_UCODE_PATCH
endmenu
......@@ -2,7 +2,7 @@
# Makefile for the linux MPC8xx ppc-specific parts of comm processor
#
obj-y := commproc.o uart.o
obj-y := commproc.o
obj-$(CONFIG_FEC_ENET) += fec.o
obj-$(CONFIG_SCC_ENET) += enet.o
......
......@@ -23,18 +23,20 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <asm/irq.h>
#include <asm/mpc8xx.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
#include <asm/commproc.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <asm/rheap.h>
extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
......@@ -51,64 +53,65 @@ struct cpm_action {
void *dev_id;
};
static struct cpm_action cpm_vecs[CPMVEC_NR];
static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
static void cpm_error_interrupt(void *, struct pt_regs * regs);
static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs);
static void alloc_host_memory(void);
#if 1
void
m8xx_cpm_reset(void)
{
volatile immap_t *imp;
volatile cpm8xx_t *commproc;
imp = (immap_t *)IMAP_ADDR;
commproc = (cpm8xx_t *)&imp->im_cpm;
#ifdef CONFIG_UCODE_PATCH
/* Perform a reset.
/* Define a table of names to identify CPM interrupt handlers in
* /proc/interrupts.
*/
commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
const char *cpm_int_name[] =
{ "error", "PC4", "PC5", "SMC2",
"SMC1", "SPI", "PC6", "Timer 4",
"", "PC7", "PC8", "PC9",
"Timer 3", "", "PC10", "PC11",
"I2C", "RISC Timer", "Timer 2", "",
"IDMA2", "IDMA1", "SDMA error", "PC12",
"PC13", "Timer 1", "PC14", "SCC4",
"SCC3", "SCC2", "SCC1", "PC15"
};
/* Wait for it.
*/
while (commproc->cp_cpcr & CPM_CR_FLG);
static void
cpm_mask_irq(unsigned int irq)
{
int cpm_vec = irq - CPM_IRQ_OFFSET;
cpm_load_patch(imp);
#endif
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec);
}
/* Set SDMA Bus Request priority 5.
* On 860T, this also enables FEC priority 6. I am not sure
* this is what we realy want for some applications, but the
* manual recommends it.
* Bit 25, FAM can also be set to use FEC aggressive mode (860T).
*/
imp->im_siu_conf.sc_sdcr = 1;
static void
cpm_unmask_irq(unsigned int irq)
{
int cpm_vec = irq - CPM_IRQ_OFFSET;
/* Reclaim the DP memory for our use. */
m8xx_cpm_dpinit();
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec);
}
/* Tell everyone where the comm processor resides.
*/
cpmp = (cpm8xx_t *)commproc;
static void
cpm_ack(unsigned int irq)
{
/* We do not need to do anything here. */
}
/* We used to do this earlier, but have to postpone as long as possible
* to ensure the kernel VM is now running.
*/
static void
alloc_host_memory()
cpm_eoi(unsigned int irq)
{
uint physaddr;
int cpm_vec = irq - CPM_IRQ_OFFSET;
/* Set the host page for allocation.
*/
host_buffer = (uint)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &physaddr);
host_end = host_buffer + PAGE_SIZE;
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec);
}
#else
struct hw_interrupt_type cpm_pic = {
.typename = " CPM ",
.enable = cpm_unmask_irq,
.disable = cpm_mask_irq,
.ack = cpm_ack,
.end = cpm_eoi,
};
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
void
m8xx_cpm_reset(uint host_page_addr)
m8xx_cpm_reset(uint bootpage)
{
volatile immap_t *imp;
volatile cpm8xx_t *commproc;
......@@ -140,34 +143,55 @@ m8xx_cpm_reset(uint host_page_addr)
/* Reclaim the DP memory for our use. */
m8xx_cpm_dpinit();
/* Set the host page for allocation.
*/
host_buffer = host_page_addr; /* Host virtual page address */
host_end = host_page_addr + PAGE_SIZE;
/* get the PTE for the bootpage */
if (!get_pteptr(&init_mm, bootpage, &pte))
panic("get_pteptr failed\n");
/* We need to get this page early, so I have to do it the
* hard way.
*/
if (get_pteptr(&init_mm, host_page_addr, &pte)) {
/* and make it uncachable */
pte_val(*pte) |= _PAGE_NO_CACHE;
flush_tlb_page(init_mm.mmap, host_buffer);
}
else {
panic("Huh? No CPM host page?");
}
_tlbie(bootpage);
host_buffer = bootpage;
host_end = host_buffer + PAGE_SIZE;
/* Tell everyone where the comm processor resides.
*/
cpmp = (cpm8xx_t *)commproc;
}
#endif
/* We used to do this earlier, but have to postpone as long as possible
* to ensure the kernel VM is now running.
*/
static void
alloc_host_memory(void)
{
dma_addr_t physaddr;
/* Set the host page for allocation.
*/
host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
GFP_KERNEL);
host_end = host_buffer + PAGE_SIZE;
}
/* This is called during init_IRQ. We used to do it above, but this
* was too early since init_IRQ was not yet called.
*/
static struct irqaction cpm_error_irqaction = {
.handler = cpm_error_interrupt,
.mask = CPU_MASK_NONE,
};
static struct irqaction cpm_interrupt_irqaction = {
.handler = cpm_interrupt,
.mask = CPU_MASK_NONE,
.name = "CPM cascade",
};
void
cpm_interrupt_init(void)
{
int i;
/* Initialize the CPM interrupt controller.
*/
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
......@@ -175,41 +199,52 @@ cpm_interrupt_init(void)
((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
/* Set our interrupt handler with the core CPU.
/* install the CPM interrupt controller routines for the CPM
* interrupt vectors
*/
if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
irq_desc[i].handler = &cpm_pic;
/* Set our interrupt handler with the core CPU. */
if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
panic("Could not allocate CPM IRQ!");
/* Install our own error handler.
*/
cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
/* Install our own error handler. */
cpm_error_irqaction.name = cpm_int_name[CPMVEC_ERROR];
if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
panic("Could not allocate CPM error IRQ!");
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
}
/* CPM interrupt controller interrupt.
*/
static void
cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
/*
* Get the CPM interrupt vector.
*/
int
cpm_get_irq(struct pt_regs *regs)
{
uint vec;
int cpm_vec;
/* Get the vector by setting the ACK bit and then reading
* the register.
*/
((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
vec >>= 11;
cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
cpm_vec >>= 11;
if (cpm_vecs[vec].handler != 0)
(*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs);
else
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
return cpm_vec;
}
/* After servicing the interrupt, we have to remove the status
* indicator.
/* CPM interrupt controller cascade interrupt.
*/
static irqreturn_t
cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
{
/* This interrupt handler never actually gets called. It is
* installed only to unmask the CPM cascade interrupt in the SIU
* and to make the CPM cascade interrupt visible in /proc/interrupts.
*/
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec);
return IRQ_HANDLED;
}
/* The CPM can generate the error interrupt when there is a race condition
......@@ -217,41 +252,73 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
* and return. This is a no-op function so we don't need any special
* tests in the interrupt handler.
*/
static void
cpm_error_interrupt(void *dev, struct pt_regs *regs)
static irqreturn_t
cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
{
return IRQ_HANDLED;
}
/* A helper function to translate the handler prototype required by
* request_irq() to the handler prototype required by cpm_install_handler().
*/
static irqreturn_t
cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
{
int cpm_vec = irq - CPM_IRQ_OFFSET;
(*cpm_vecs[cpm_vec].handler)(dev_id, regs);
return IRQ_HANDLED;
}
/* Install a CPM interrupt handler.
*/
* This routine accepts a CPM interrupt vector in the range 0 to 31.
* This routine is retained for backward compatibility. Rather than using
* this routine to install a CPM interrupt handler, you can now use
* request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
* CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
*
* Notice that the prototype of the interrupt handler function must be
* different depending on whether you install the handler with
* request_irq() or cpm_install_handler().
*/
void
cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs),
cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
void *dev_id)
{
int err;
/* If null handler, assume we are trying to free the IRQ.
*/
if (!handler) {
cpm_free_handler(vec);
free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
return;
}
if (cpm_vecs[vec].handler != 0)
printk("CPM interrupt %x replacing %x\n",
(uint)handler, (uint)cpm_vecs[vec].handler);
cpm_vecs[vec].handler = handler;
cpm_vecs[vec].dev_id = dev_id;
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
if (cpm_vecs[cpm_vec].handler != 0)
printk(KERN_INFO "CPM interrupt %x replacing %x\n",
(uint)handler, (uint)cpm_vecs[cpm_vec].handler);
cpm_vecs[cpm_vec].handler = handler;
cpm_vecs[cpm_vec].dev_id = dev_id;
if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
0, cpm_int_name[cpm_vec], dev_id)))
printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
err, cpm_vec);
}
/* Free a CPM interrupt handler.
*/
* This routine accepts a CPM interrupt vector in the range 0 to 31.
* This routine is retained for backward compatibility.
*/
void
cpm_free_handler(int vec)
cpm_free_handler(int cpm_vec)
{
cpm_vecs[vec].handler = NULL;
cpm_vecs[vec].dev_id = NULL;
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
cpm_vecs[cpm_vec].dev_id);
cpm_vecs[cpm_vec].handler = NULL;
cpm_vecs[cpm_vec].dev_id = NULL;
}
/* We also own one page of host buffer space for the allocation of
......@@ -262,10 +329,8 @@ m8xx_cpm_hostalloc(uint size)
{
uint retloc;
#if 1
if (host_buffer == 0)
alloc_host_memory();
#endif
if ((host_buffer + size) >= host_end)
return(0);
......
......@@ -38,6 +38,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <asm/8xx_immap.h>
......@@ -581,10 +582,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_PMSR_PRO;
cep->sccp->scc_psmr |= SCC_PSMR_PRO;
} else {
cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO;
cep->sccp->scc_psmr &= ~SCC_PSMR_PRO;
if (dev->flags & IFF_ALLMULTI) {
/* Catch all multicast addresses, so set the
......@@ -835,7 +836,8 @@ static int __init scc_enet_init(void)
/* Allocate a page.
*/
ba = (unsigned char *)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &mem_addr);
ba = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE,
&mem_addr, GFP_KERNEL);
/* BUG: no check for failure */
/* Initialize the BD for every fragment in the page.
......@@ -889,7 +891,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_PMSR_ENCRC | SCC_PMSR_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.
......
......@@ -1684,7 +1684,7 @@ static int __init fec_enet_init(void)
/* Install our interrupt handler.
*/
if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
panic("Could not allocate FEC IRQ!");
#ifdef CONFIG_RPXCLASSIC
......@@ -1705,7 +1705,7 @@ static int __init fec_enet_init(void)
((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
(0x80000000 >> PHY_INTERRUPT);
if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
panic("Could not allocate MII IRQ!");
#endif
......
......@@ -19,18 +19,12 @@
#include <asm/8xx_immap.h>
#include <asm/commproc.h>
/* Define this to get SMC patches as well. You need to modify the uart
* driver as well......
#define USE_SMC_PATCH 1
/*
* I2C/SPI relocation patch arrays.
*/
#ifdef CONFIG_USB_MPC8xx
#define USE_USB_SOF_PATCH
#endif
#ifdef CONFIG_I2C_SPI_UCODE_PATCH
#ifdef USE_IIC_PATCH
#define PATCH_DEFINED
/* IIC/SPI */
uint patch_2000[] = {
0x7FFFEFD9,
0x3FFD0000,
......@@ -183,11 +177,12 @@ uint patch_2f00[] = {
};
#endif
#ifdef USE_SMC_PATCH
#define PATCH_DEFINED
/* SMC2/IIC/SPI Patch */
/* This is the area from 0x2000 to 0x23ff.
*/
/*
* I2C/SPI/SMC1 relocation patch arrays.
*/
#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
uint patch_2000[] = {
0x3fff0000,
0x3ffd0000,
......@@ -511,8 +506,6 @@ uint patch_2000[] = {
0x6079e2bb
};
/* This is from 0x2f00 to 0x2fff
*/
uint patch_2f00[] = {
0x30303030,
0x3e3e3434,
......@@ -581,8 +574,6 @@ uint patch_2f00[] = {
};
uint patch_2e00[] = {
/* This is from 0x2e00 to 0x2e3c
*/
0x27eeeeee,
0xeeeeeeee,
0xeeeeeeee,
......@@ -602,8 +593,12 @@ uint patch_2e00[] = {
};
#endif
#ifdef USE_USB_SOF_PATCH
#define PATCH_DEFINED
/*
* USB SOF patch arrays.
*/
#ifdef CONFIG_USB_SOF_UCODE_PATCH
uint patch_2000[] = {
0x7fff0000,
0x7ffd0000,
......@@ -626,33 +621,21 @@ uint patch_2f00[] = {
};
#endif
/* Load the microcode patch. This is called early in the CPM initialization
* with the controller in the reset state. We enable the processor after
* we load the patch.
*/
void
cpm_load_patch(volatile immap_t *immr)
{
#ifdef PATCH_DEFINED
volatile uint *dp;
volatile uint *dp; /* Dual-ported RAM. */
volatile cpm8xx_t *commproc;
volatile iic_t *iip;
volatile spi_t *spp;
volatile smc_uart_t *smp;
int i;
commproc = (cpm8xx_t *)&immr->im_cpm;
/* We work closely with commproc.c. We know it only allocates
* from data only space.
* For this particular patch, we only use the bottom 512 bytes
* and the upper 256 byte extension. We will use the space
* starting at 1K for the relocated parameters, as the general
* CPM allocation won't come from that area.
*/
#ifdef CONFIG_USB_SOF_UCODE_PATCH
commproc->cp_rccr = 0;
/* Copy the patch into DPRAM.
*/
dp = (uint *)(commproc->cp_dpmem);
for (i=0; i<(sizeof(patch_2000)/4); i++)
*dp++ = patch_2000[i];
......@@ -661,29 +644,26 @@ cpm_load_patch(volatile immap_t *immr)
for (i=0; i<(sizeof(patch_2f00)/4); i++)
*dp++ = patch_2f00[i];
#ifdef USE_USB_SOF_PATCH
#if 0 /* usb patch should not relocate iic */
iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
#define RPBASE 0x0030
iip->iic_rpbase = RPBASE;
commproc->cp_rccr = 0x0009;
/* Put SPI above the IIC, also 32-byte aligned.
*/
i = (RPBASE + sizeof(iic_t) + 31) & ~31;
spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
spp->spi_rpbase = i;
#endif
printk("USB SOF microcode patch installed\n");
#endif /* CONFIG_USB_SOF_UCODE_PATCH */
/* Enable uCode fetches from DPRAM. */
commproc->cp_rccr = 0x0009;
#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
commproc->cp_rccr = 0;
printk("USB uCode patch installed\n");
#endif /* USE_USB_SOF_PATCH */
dp = (uint *)(commproc->cp_dpmem);
for (i=0; i<(sizeof(patch_2000)/4); i++)
*dp++ = patch_2000[i];
#if defined(USE_SMC_PATCH) || defined(USE_IIC_PATCH)
dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
for (i=0; i<(sizeof(patch_2f00)/4); i++)
*dp++ = patch_2f00[i];
iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
#define RPBASE 0x0400
# define RPBASE 0x0500
iip->iic_rpbase = RPBASE;
/* Put SPI above the IIC, also 32-byte aligned.
......@@ -692,58 +672,46 @@ cpm_load_patch(volatile immap_t *immr)
spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
spp->spi_rpbase = i;
#ifdef USE_SMC_PATCH
# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
commproc->cp_cpmcr1 = 0x802a;
commproc->cp_cpmcr2 = 0x8028;
commproc->cp_cpmcr3 = 0x802e;
commproc->cp_cpmcr4 = 0x802c;
commproc->cp_rccr = 1;
printk("I2C/SPI microcode patch installed.\n");
# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
for (i=0; i<(sizeof(patch_2e00)/4); i++)
*dp++ = patch_2e00[i];
/* Enable the traps to get to it.
*/
commproc->cp_cpmcr1 = 0x8080;
commproc->cp_cpmcr2 = 0x808a;
commproc->cp_cpmcr3 = 0x8028;
commproc->cp_cpmcr4 = 0x802a;
/* Enable uCode fetches from DPRAM.
*/
commproc->cp_rccr = 3;
#endif
#ifdef USE_IIC_PATCH
/* Enable the traps to get to it.
*/
commproc->cp_cpmcr1 = 0x802a;
commproc->cp_cpmcr2 = 0x8028;
commproc->cp_cpmcr3 = 0x802e;
commproc->cp_cpmcr4 = 0x802c;
/* Enable uCode fetches from DPRAM.
*/
commproc->cp_rccr = 1;
smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
smp->smc_rpbase = 0x1FC0;
printk("I2C uCode patch installed\n");
#endif
printk("I2C/SPI/SMC1 microcode patch installed.\n");
# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
/* Relocate the IIC and SPI parameter areas. These have to
* aligned on 32-byte boundaries.
*/
iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
iip->iic_rpbase = RPBASE;
#endif /* some variation of the I2C/SPI patch was selected */
}
/* Put SPI above the IIC, also 32-byte aligned.
/*
* Take this entire routine out, since no one calls it and its
* logic is suspect.
*/
i = (RPBASE + sizeof(iic_t) + 31) & ~31;
spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
spp->spi_rpbase = i;
#endif /* USE_SMC_PATCH || USE_IIC_PATCH */
#endif /* PATCH_DEFINED */
}
#if 0
void
verify_patch(volatile immap_t *immr)
{
#ifdef PATCH_DEFINED
volatile uint *dp;
volatile cpm8xx_t *commproc;
int i;
......@@ -772,6 +740,5 @@ verify_patch(volatile immap_t *immr)
}
commproc->cp_rccr = 0x0009;
#endif /* PATCH_DEFINED */
}
#endif
/*
* UART driver for MPC860 CPM SCC or SMC
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
*
* I used the serial.c driver as the framework for this driver.
* Give credit to those guys.
* The original code was written for the MBX860 board. I tried to make
* it generic, but there may be some assumptions in the structures that
* have to be fixed later.
* 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, but this has never been tested, nor is it complete.
* 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/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/8xx_immap.h>
#include <asm/mpc8xx.h>
#include <asm/commproc.h>
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#endif
#ifdef CONFIG_KGDB
#include <asm/kgdb.h>
#endif
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
/* this defines the index into rs_table for the port to use
*/
# ifndef CONFIG_SERIAL_CONSOLE_PORT
# ifdef CONFIG_SCC3_ENET
# ifdef CONFIG_CONS_SMC2
# define CONFIG_SERIAL_CONSOLE_PORT 0 /* Console on SMC2 is 1st port */
# else
# error "Can't use SMC1 for console with Ethernet on SCC3"
# endif
# else /* ! CONFIG_SCC3_ENET */
# ifdef CONFIG_CONS_SMC2 /* Console on SMC2 */
# define CONFIG_SERIAL_CONSOLE_PORT 1
# else /* Console on SMC1 */
# define CONFIG_SERIAL_CONSOLE_PORT 0
# endif /* CONFIG_CONS_SMC2 */
# endif /* CONFIG_SCC3_ENET */
# endif /* CONFIG_SERIAL_CONSOLE_PORT */
#endif /* CONFIG_SERIAL_CONSOLE */
#if 0
/* SCC2 for console
*/
#undef CONFIG_SERIAL_CONSOLE_PORT
#define CONFIG_SERIAL_CONSOLE_PORT 2
#endif
#define TX_WAKEUP ASYNC_SHARE_IRQ
static char *serial_name = "CPM UART driver";
static char *serial_version = "0.03";
static DECLARE_TASK_QUEUE(tq_serial);
static struct tty_driver *serial_driver;
static int 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
* a flag indicating SCC or SMC, and the number is used as an index into
* the CPM parameter area for this device.
* 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 SMC or SCC.
* The SMCs do not support any modem control signals.
*/
#define smc_scc_num hub6
#define NUM_IS_SCC ((int)0x00010000)
#define PORT_NUM(P) ((P) & 0x0000ffff)
/* 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
/* Processors other than the 860 only get SMCs configured by default.
* Either they don't have SCCs or they are allocated somewhere else.
* Of course, there are now 860s without some SCCs, so we will need to
* address that someday.
* The Embedded Planet Multimedia I/O cards use TDM interfaces to the
* stereo codec parts, and we use SMC2 to help support that.
*/
static struct serial_state rs_table[] = {
/* UART CLK PORT IRQ FLAGS NUM */
#ifndef CONFIG_SCC3_ENET /* SMC1 not usable with Ethernet on SCC3 */
{ 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */
#endif
#if !defined(CONFIG_USB_MPC8xx) && !defined(CONFIG_USB_CLIENT_MPC8xx)
# ifdef CONFIG_SMC2_UART
{ 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */
# endif
# ifdef CONFIG_USE_SCC_IO
{ 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) }, /* SCC2 ttyS2 */
{ 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */
# endif
#else /* CONFIG_USB_xxx */
# ifdef CONFIG_USE_SCC_IO
{ 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */
# endif
#endif /* CONFIG_USB_xxx */
};
#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 tq_struct tqueue;
struct tq_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;
/* Virtual addresses for the FIFOs because we can't __va() a
* physical address anymore.
*/
unsigned char *rx_va_base;
unsigned char *tx_va_base;
} 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();
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
sccp->scc_sccm &= ~UART_SCCM_TX;
}
else {
smcp = &cpmp->cp_smc[idx];
smcp->smc_smcm &= ~SMCM_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;
idx = PORT_NUM(info->state->smc_scc_num);
save_flags(flags); cli();
if (info->state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
sccp->scc_sccm |= UART_SCCM_TX;
}
else {
smcp = &cpmp->cp_smc[idx];
smcp->smc_smcm |= SMCM_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;
queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
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 = info->rx_va_base + ((bdp - info->rx_bd_base) * RX_BUF_SIZE);
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;
queue_task(&tty->flip.tqueue, &tq_timer);
}
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++;
queue_task(&tty->flip.tqueue, &tq_timer);
}
static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs)
{
if ((info->flags & TX_WAKEUP) ||
(info->tty->flags & (1 << TTY_DO_WRITE_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_task(&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 void rs_8xx_interrupt(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;
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
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;
}
else {
smcp = &cpmp->cp_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;
}
#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
}
/*
* -------------------------------------------------------------------
* 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_serial_bh(void)
{
run_task_queue(&tq_serial);
}
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 tqueue 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);
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
scup = (scc_uart_t *)&cpmp->cp_dparam[state->port];
scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
scup->scc_maxidl = RX_BUF_SIZE;
sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
else {
smcp = &cpmp->cp_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 *)&cpmp->cp_dparam[state->port];
up->smc_mrblr = RX_BUF_SIZE;
up->smc_maxidl = RX_BUF_SIZE;
up->smc_brkcr = 1; /* number of break chars */
}
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 */
idx = PORT_NUM(state->smc_scc_num);
if (state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
#ifdef CONFIG_SERIAL_CONSOLE
/* We can't disable the transmitter if this is the
* system console.
*/
if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
#endif
sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
}
else {
smcp = &cpmp->cp_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 ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
#endif
smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
}
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, new_mode;
int i, bits, sbits, idx;
unsigned long flags;
struct serial_state *state;
volatile smc_t *smcp;
volatile scc_t *sccp;
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
state = info->state;
/* 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++;
idx = PORT_NUM(state->smc_scc_num);
if (state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
new_mode = (sbits << 12) | scval;
prev_mode = sccp->scc_pmsr;
if (!(prev_mode & SCU_PMSR_PEN))
/* If parity is disabled, mask out even/odd */
prev_mode &= ~(SCU_PMSR_TPM|SCU_PMSR_RPM);
if (prev_mode != new_mode)
sccp->scc_pmsr = new_mode;
}
else {
smcp = &cpmp->cp_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;
new_mode = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
new_mode |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
if (!(prev_mode & SMCMR_PEN))
/* If parity is disabled, mask out even/odd */
prev_mode &= ~SMCMR_PM_EVEN;
if (prev_mode != new_mode)
smcp->smc_smcmr = new_mode;
}
m8xx_cpm_setbrg((state - rs_table), 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;
unsigned char *cp;
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);
cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);
*cp = 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,
const unsigned char *buf, int count)
{
int c, ret = 0;
ser_info_t *info = (ser_info_t *)tty->driver_data;
volatile cbd_t *bdp;
unsigned char *cp;
#ifdef CONFIG_KGDB_CONSOLE
/* Try to let stub handle output. Returns true if it did. */
if (kgdb_output_string(buf, count))
return ret;
#endif
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;
}
cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);
memcpy((void *)cp, 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;
unsigned char *cp;
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);
cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);
*cp = 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 ushort smc_chan_map[] = {
CPM_CR_CH_SMC1,
CPM_CR_CH_SMC2
};
static ushort scc_chan_map[] = {
CPM_CR_CH_SCC1,
CPM_CR_CH_SCC2,
CPM_CR_CH_SCC3,
CPM_CR_CH_SCC4
};
static void begin_break(ser_info_t *info)
{
volatile cpm8xx_t *cp;
ushort chan;
int idx;
cp = cpmp;
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC)
chan = scc_chan_map[idx];
else
chan = smc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
static void end_break(ser_info_t *info)
{
volatile cpm8xx_t *cp;
ushort chan;
int idx;
cp = cpmp;
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC)
chan = scc_chan_map[idx];
else
chan = smc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan, 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) {
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
sccp = &cpmp->cp_scc[idx];
sccp->scc_sccm &= ~UART_SCCM_RX;
sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
}
else {
smcp = &cpmp->cp_smc[idx];
smcp->smc_smcm &= ~SMCM_RX;
smcp->smc_smcmr &= ~SMCMR_REN;
}
/*
* 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, 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;
/* The 'tx_cur' is really the next buffer to send. We
* have to back up to the previous BD and wait for it
* to go. This isn't perfect, because all this indicates
* is the buffer is available. There are still characters
* in the CPM FIFO.
*/
bdp = info->tx_cur;
if (bdp == info->tx_bd_base)
bdp += (TX_NUM_FIFO-1);
else
bdp--;
} 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);
#endif
struct serial_state *state = info->state;
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 & NUM_IS_SCC)) {
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...", tty->name);
#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 & NUM_IS_SCC) ? "SCC" : "SMC",
(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
/* I need this just so I can store the virtual addresses and have
* common functions for the early console printing.
*/
static ser_info_t consinfo;
/*
* Print a string to the serial port trying not to disturb any possible
* real use of the port...
*/
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 *)&cpmp->cp_dparam[ser->port];
/* Get the address of the host memory buffer.
*/
bdp = bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
info = &consinfo;
}
/*
* 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 = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);
*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 = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);
*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)
{
#ifdef CONFIG_KGDB_CONSOLE
/* 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(0, s, count);
return(count);
}
#endif
#ifdef CONFIG_KGDB
void
putDebugChar(char ch)
{
my_console_write(0, &ch, 1);
}
#endif
/*
* Receive character from the serial port. This only works well
* before the port is initialized 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 *)&cpmp->cp_dparam[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 *)&cpmp->cp_dpmem[up->smc_rbase];
info = &consinfo;
}
/*
* 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 = info->rx_va_base + ((bdp - info->rx_bd_base) * RX_BUF_SIZE);
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);
}
#ifdef CONFIG_XMON
int
xmon_8xx_read_poll(void)
{
return(my_console_wait_key(0, 1, NULL));
}
int
xmon_8xx_read_char(void)
{
return(my_console_wait_key(0, 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(0, 0, kgdb_buf);
kgdp = kgdb_buf;
}
kgdb_chars--;
return(*kgdp++);
}
void kgdb_interruptible(int yes)
{
volatile smc_t *smcp;
smcp = &cpmp->cp_smc[KGDB_SER_IDX];
if (yes == 1)
smcp->smc_smcm |= SMCM_RX;
else
smcp->smc_smcm &= ~SMCM_RX;
}
void kgdb_map_scc(void)
{
struct serial_state *ser;
uint mem_addr;
volatile cbd_t *bdp;
volatile smc_uart_t *up;
cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
/* To avoid data cache CPM DMA coherency problems, allocate a
* buffer in the CPM DPRAM. This will work until the CPM and
* serial ports are initialized. At that time a memory buffer
* will be allocated.
* The port is already initialized from the boot procedure, all
* we do here is give it a different buffer and make it a FIFO.
*/
ser = rs_table;
/* Right now, assume we are using SMCs.
*/
up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
/* Allocate space for an input FIFO, plus a few bytes for output.
* Allocate bytes to maintain word alignment.
*/
mem_addr = (uint)(&cpmp->cp_dpmem[0xa00]);
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
bdp->cbd_bufaddr = mem_addr;
bdp = (cbd_t *)&cpmp->cp_dpmem[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 void __init console_8xx_init(long kmem_start, long kmem_end)
{
register_console(&sercons);
}
console_initcall(console_8xx_init);
#endif
/* Index in baud rate table of the default console baud rate.
*/
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, iobits, dp_offset;
int i, j, idx;
ushort chan;
volatile cbd_t *bdp;
volatile cpm8xx_t *cp;
volatile smc_t *sp;
volatile smc_uart_t *up;
volatile scc_t *scp;
volatile scc_uart_t *sup;
volatile immap_t *immap;
serial_driver = alloc_tty_driver(NR_PORTS);
if (!serial_driver)
return -ENOMEM;
init_bh(SERIAL_BH, do_serial_bh);
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");
cp = cpmp; /* Get pointer to Communication Processor */
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
/* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
*/
#ifdef CONFIG_USE_SCC_IO
#ifndef CONFIG_MBX
/* The "standard" configuration through the 860.
*/
immap->im_ioport.iop_papar |= 0x00fc;
immap->im_ioport.iop_padir &= ~0x00fc;
immap->im_ioport.iop_paodr &= ~0x00fc;
#else
/* On the MBX, SCC3 is through Port D.
*/
immap->im_ioport.iop_papar |= 0x000c; /* SCC2 on port A */
immap->im_ioport.iop_padir &= ~0x000c;
immap->im_ioport.iop_paodr &= ~0x000c;
immap->im_ioport.iop_pdpar |= 0x0030; /* SCC3 on port D */
#endif
/* Since we don't yet do modem control, connect the port C pins
* as general purpose I/O. This will assert CTS and CD for the
* SCC ports.
*/
immap->im_ioport.iop_pcdir |= 0x03c6;
immap->im_ioport.iop_pcpar &= ~0x03c6;
/* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and
* BRG4 to SCC3.
*/
cp->cp_sicr &= ~0x00ffff00;
cp->cp_sicr |= 0x001b1200;
#ifdef CONFIG_PP04
/* Frequentis PP04 forced to RS-232 until we know better.
* Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
*/
immap->im_ioport.iop_pcdir |= 0x000c;
immap->im_ioport.iop_pcpar &= ~0x000c;
immap->im_ioport.iop_pcdat &= ~0x000c;
/* This enables the TX driver.
*/
cp->cp_pbpar &= ~0x6000;
cp->cp_pbdat &= ~0x6000;
#endif
#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 at 0x%04x is a %s\n",
i, (unsigned int)(state->port),
(state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
#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(2);
#endif
info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
if (info) {
__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;
info->tqueue.routine = do_softint;
info->tqueue.data = info;
info->tqueue_hangup.routine = do_serial_hangup;
info->tqueue_hangup.data = 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_offset = cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8);
/* Allocate space for FIFOs in the host memory.
*/
mem_addr = m8xx_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE);
info->rx_va_base = (unsigned char *)mem_addr;
/* 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 *)&cp->cp_dpmem[dp_offset];
info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;
for (j=0; j<(RX_NUM_FIFO-1); j++) {
bdp->cbd_bufaddr = iopa(mem_addr);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
mem_addr += RX_BUF_SIZE;
bdp++;
}
bdp->cbd_bufaddr = iopa(mem_addr);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
scp = &cp->cp_scc[idx];
sup = (scc_uart_t *)&cp->cp_dparam[state->port];
sup->scc_genscc.scc_rbase = dp_offset;
}
else {
sp = &cp->cp_smc[idx];
up = (smc_uart_t *)&cp->cp_dparam[state->port];
up->smc_rbase = dp_offset;
}
dp_offset = cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8);
/* Allocate space for FIFOs in the host memory.
*/
mem_addr = m8xx_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE);
info->tx_va_base = (unsigned char *)mem_addr;
/* 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 *)&cp->cp_dpmem[dp_offset];
info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;
for (j=0; j<(TX_NUM_FIFO-1); j++) {
bdp->cbd_bufaddr = iopa(mem_addr);
bdp->cbd_sc = BD_SC_INTRPT;
mem_addr += TX_BUF_SIZE;
bdp++;
}
bdp->cbd_bufaddr = iopa(mem_addr);
bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
if (info->state->smc_scc_num & NUM_IS_SCC) {
sup->scc_genscc.scc_tbase = dp_offset;
/* Set up the uart parameters in the
* parameter ram.
*/
sup->scc_genscc.scc_rfcr = SMC_EB;
sup->scc_genscc.scc_tfcr = SMC_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.
*/
chan = scc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan,
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;
/* If the port is the console, enable Rx and Tx.
*/
#ifdef CONFIG_SERIAL_CONSOLE
if (i == CONFIG_SERIAL_CONSOLE_PORT)
scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
#endif
}
else {
/* Configure SMCs Tx/Rx instead of port B
* parallel I/O. On 823/850 these are on
* port A for SMC2.
*/
#ifndef CONFIG_ALTSMC2
iobits = 0xc0 << (idx * 4);
cp->cp_pbpar |= iobits;
cp->cp_pbdir &= ~iobits;
cp->cp_pbodr &= ~iobits;
#else
iobits = 0xc0;
if (idx == 0) {
/* SMC1 on Port B, like all 8xx.
*/
cp->cp_pbpar |= iobits;
cp->cp_pbdir &= ~iobits;
cp->cp_pbodr &= ~iobits;
}
else {
/* SMC2 is on Port A.
*/
immap->im_ioport.iop_papar |= iobits;
immap->im_ioport.iop_padir &= ~iobits;
immap->im_ioport.iop_paodr &= ~iobits;
}
#endif /* CONFIG_ALTSMC2 */
/* Connect the baud rate generator to the
* SMC based upon index in rs_table. Also
* make sure it is connected to NMSI.
*/
cp->cp_simode &= ~(0xffff << (idx * 16));
cp->cp_simode |= (i << ((idx * 16) + 12));
up->smc_tbase = dp_offset;
/* Set up the uart parameters in the
* parameter ram.
*/
up->smc_rfcr = SMC_EB;
up->smc_tfcr = SMC_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.
*/
chan = smc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan,
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;
/* If the port is the console, enable Rx and Tx.
*/
#ifdef CONFIG_SERIAL_CONSOLE
if (i == CONFIG_SERIAL_CONSOLE_PORT)
sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
#endif
}
/* Install interrupt handler.
*/
cpm_install_handler(state->irq, rs_8xx_interrupt, info);
/* Set up the baud rate generator.
*/
m8xx_cpm_setbrg(i, baud_table[baud_idx]);
}
}
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, bidx, idx, dp_offset;
ushort chan;
volatile cbd_t *bdp;
volatile cpm8xx_t *cp;
volatile smc_t *sp;
volatile scc_t *scp;
volatile smc_uart_t *up;
volatile scc_uart_t *sup;
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;
/* make sure we have a useful value */
if (bidx == (sizeof(baud_table) / sizeof(int)))
bidx = 13; /* B9600 */
co->cflag = CREAD|CLOCAL|bidx|CS8;
baud_idx = bidx;
ser = rs_table + co->index;
cp = cpmp; /* Get pointer to Communication Processor */
idx = PORT_NUM(ser->smc_scc_num);
if (ser->smc_scc_num & NUM_IS_SCC) {
scp = &cp->cp_scc[idx];
sup = (scc_uart_t *)&cp->cp_dparam[ser->port];
}
else {
sp = &cp->cp_smc[idx];
up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
}
/* 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.
*/
/* Allocate space for two FIFOs. We can't allocate from host
* memory yet because vm allocator isn't initialized
* during this early console init.
*/
dp_offset = cpm_dpalloc(8, 8);
mem_addr = (uint)(&cpmp->cp_dpmem[dp_offset]);
/* Allocate space for two buffer descriptors in the DP ram.
*/
dp_offset = cpm_dpalloc(sizeof(cbd_t) * 2, 8);
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
bdp = (cbd_t *)&cp->cp_dpmem[dp_offset];
bdp->cbd_bufaddr = iopa(mem_addr);
(bdp+1)->cbd_bufaddr = iopa(mem_addr+4);
consinfo.rx_va_base = mem_addr;
consinfo.rx_bd_base = bdp;
consinfo.tx_va_base = mem_addr + 4;
consinfo.tx_bd_base = bdp+1;
/* 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.
*/
if (ser->smc_scc_num & NUM_IS_SCC) {
sup->scc_genscc.scc_rbase = dp_offset;
sup->scc_genscc.scc_tbase = dp_offset + sizeof(cbd_t);
/* Set up the uart parameters in the
* parameter ram.
*/
sup->scc_genscc.scc_rfcr = SMC_EB;
sup->scc_genscc.scc_tfcr = SMC_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.
*/
chan = scc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan, 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;
scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
else {
up->smc_rbase = dp_offset; /* Base of receive buffer desc. */
up->smc_tbase = dp_offset+sizeof(cbd_t); /* Base of xmt buffer desc. */
up->smc_rfcr = SMC_EB;
up->smc_tfcr = SMC_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.
*/
chan = smc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
printk("%s", "");
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;
/* And finally, enable Rx and Tx.
*/
sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
}
/* Set up the baud rate generator.
*/
m8xx_cpm_setbrg((ser - rs_table), bd->bi_baudrate);
return 0;
}
......@@ -74,6 +74,7 @@ config POWER4
bool "POWER4 and 970 (G5)"
config 8xx
depends on BROKEN
bool "8xx"
config E500
......@@ -756,11 +757,6 @@ config PC_KEYBOARD
bool "PC PS/2 style Keyboard"
depends on 4xx || CPM2
config SERIAL_CONSOLE
bool
depends on 8xx
default y
config SERIAL_CONSOLE_BAUD
int
depends on EV64260
......
......@@ -295,25 +295,27 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
# CONFIG_SERIAL_CPM_ALT_SMC2 is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -478,10 +480,6 @@ CONFIG_SCC1_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
# CONFIG_ALTSMC2 is not set
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -319,25 +319,26 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
# CONFIG_SERIAL_CPM_SMC2 is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -507,8 +508,6 @@ CONFIG_FEC_LXT970=y
CONFIG_FEC_LXT971=y
CONFIG_FEC_QS6612=y
CONFIG_ENET_BIG_BUFFERS=y
# CONFIG_SMC2_UART is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -92,7 +92,8 @@ CONFIG_KERNEL_ELF=y
# Parallel port support
#
# CONFIG_PARPORT is not set
# CONFIG_CMDLINE_BOOL is not set
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="console=ttyCPM1"
#
# Advanced setup
......@@ -296,25 +297,27 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_SERIAL_CPM_ALT_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -479,10 +482,6 @@ CONFIG_SCC_ENET=y
CONFIG_SCC3_ENET=y
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
CONFIG_ALTSMC2=y
CONFIG_CONS_SMC2=y
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -295,25 +295,27 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
# CONFIG_SERIAL_CPM_SMC2 is not set
CONFIG_SERIAL_CPM_ALT_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -478,10 +480,6 @@ CONFIG_SCC2_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
CONFIG_ALTSMC2=y
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -296,25 +296,27 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_SERIAL_CPM_ALT_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -479,10 +481,6 @@ CONFIG_SCC2_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
CONFIG_ALTSMC2=y
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -296,25 +296,27 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_SERIAL_CPM_ALT_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -479,10 +481,6 @@ CONFIG_SCC2_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
CONFIG_ALTSMC2=y
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -320,25 +320,26 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -508,10 +509,6 @@ CONFIG_SCC1_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
# CONFIG_ALTSMC2 is not set
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -292,25 +292,26 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -476,10 +477,6 @@ CONFIG_SCC2_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
# CONFIG_ENET_BIG_BUFFERS is not set
CONFIG_SMC2_UART=y
# CONFIG_ALTSMC2 is not set
# CONFIG_CONS_SMC2 is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
......
......@@ -289,24 +289,26 @@ CONFIG_SOUND_GAMEPORT=y
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
CONFIG_SERIAL_CPM_SCC2=y
CONFIG_SERIAL_CPM_SCC3=y
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
#
# I2C support
......@@ -470,10 +472,6 @@ CONFIG_SCC1_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
# CONFIG_ALTSMC2 is not set
# CONFIG_CONS_SMC2 is not set
CONFIG_USE_SCC_IO=y
#
# Generic MPC8xx Options
......
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.10-rc1
# Mon Nov 1 16:41:04 2004
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=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 is not set
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_LOCALVERSION=""
# CONFIG_SWAP is not set
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_KOBJECT_UEVENT is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
CONFIG_FUTEX=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SHMEM is not set
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
CONFIG_TINY_SHMEM=y
#
# Loadable module support
......@@ -28,21 +51,23 @@ CONFIG_FUTEX=y
# CONFIG_MODULES is not set
#
# Platform support
# Processor
#
CONFIG_PPC=y
CONFIG_PPC32=y
# CONFIG_6xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
CONFIG_8xx=y
# CONFIG_E500 is not set
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
CONFIG_EMBEDDEDBOOT=y
CONFIG_NOT_COHERENT_CACHE=y
#
# IBM 4xx options
# Platform options
#
CONFIG_EMBEDDEDBOOT=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_NOT_COHERENT_CACHE=y
# CONFIG_RPXLITE is not set
CONFIG_RPXCLASSIC=y
# CONFIG_BSEIP is not set
......@@ -66,27 +91,17 @@ CONFIG_RPXCLASSIC=y
# CONFIG_WINCEPT is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
#
# General setup
#
# CONFIG_HIGHMEM is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS is not set
# CONFIG_PCI_QSPAN is not set
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_HOTPLUG is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Parallel port support
# Bus options
#
# CONFIG_PARPORT is not set
# CONFIG_CMDLINE_BOOL is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS is not set
# CONFIG_PCI_QSPAN is not set
#
# Advanced setup
......@@ -100,51 +115,88 @@ CONFIG_HIGHMEM_START=0xfe000000
CONFIG_LOWMEM_SIZE=0x30000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_TASK_SIZE=0x80000000
CONFIG_CONSISTENT_START=0xff100000
CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_BOOT_LOAD=0x00400000
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
# CONFIG_PNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD 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_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
# Multi-device support (RAID and LVM)
# IO Schedulers
#
# CONFIG_MD is not set
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
#
# ATA/IDE/MFM/RLL support
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
#
# SCSI support
# 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
#
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -156,66 +208,70 @@ CONFIG_NET=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER 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_DHCP is not set
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_INET_ECN is not set
CONFIG_SYN_COOKIES=y
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_IPV6 is not set
# CONFIG_XFRM_USER is not set
# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE 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_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
# CONFIG_NET_CLS_ROUTE 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
# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_MII is not set
# CONFIG_OAKNET is not set
#
......@@ -225,48 +281,34 @@ CONFIG_MII=y
#
# Ethernet (10000 Mbit)
#
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
# Token Ring devices
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices (depends on LLC=y)
# Wireless LAN (non-hamradio)
#
# CONFIG_SHAPER is not set
# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
# CONFIG_IRDA 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_BOOL is not set
#
# Graphics support
#
# CONFIG_FB is not set
# CONFIG_ISDN is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
# Telephony Support
#
# CONFIG_CD_NO_IDESCSI is not set
# CONFIG_PHONE is not set
#
# Input device support
......@@ -283,54 +325,38 @@ CONFIG_MII=y
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
# CONFIG_SERIO_I8042 is not set
#
# Input Device Drivers
#
#
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
CONFIG_SERIAL_CPM_SCC2=y
CONFIG_SERIAL_CPM_SCC3=y
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
CONFIG_SERIAL_CPM_SMC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# I2C Hardware Sensors Mainboard support
#
#
# I2C Hardware Sensors Chip support
#
# CONFIG_I2C_SENSOR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_LEGACY_PTYS is not set
#
# IPMI
......@@ -346,16 +372,27 @@ 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
# CONFIG_HANGCHECK_TIMER is not set
#
# I2C support
#
# CONFIG_I2C is not set
#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
#
# Misc devices
#
#
# Multimedia devices
......@@ -367,6 +404,27 @@ CONFIG_GEN_RTC=y
#
# CONFIG_DVB is not set
#
# Graphics support
#
# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
#
# File systems
#
......@@ -385,6 +443,7 @@ CONFIG_FS_MBCACHE=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
......@@ -397,17 +456,22 @@ CONFIG_FS_MBCACHE=y
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_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=y
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
......@@ -416,6 +480,7 @@ CONFIG_RAMFS=y
# 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
......@@ -432,17 +497,18 @@ CONFIG_RAMFS=y
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_SUNRPC_GSS is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 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_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
......@@ -456,16 +522,15 @@ CONFIG_PARTITION_ADVANCED=y
# 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
#
# Sound
# Native Language Support
#
# CONFIG_SOUND is not set
# CONFIG_NLS is not set
#
# MPC8xx CPM Options
......@@ -477,42 +542,38 @@ CONFIG_SCC1_ENET=y
CONFIG_FEC_ENET=y
# CONFIG_USE_MDIO is not set
CONFIG_ENET_BIG_BUFFERS=y
CONFIG_SMC2_UART=y
# CONFIG_ALTSMC2 is not set
# CONFIG_CONS_SMC2 is not set
CONFIG_USE_SCC_IO=y
#
# Generic MPC8xx Options
#
CONFIG_8xx_COPYBACK=y
# CONFIG_8xx_CPU6 is not set
# CONFIG_UCODE_PATCH is not set
#
# USB support
#
# CONFIG_USB_GADGET is not set
CONFIG_NO_UCODE_PATCH=y
# CONFIG_USB_SOF_UCODE_PATCH is not set
# CONFIG_I2C_SPI_UCODE_PATCH is not set
# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
#
# Bluetooth support
# Library routines
#
# CONFIG_BT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
#
# Library routines
# Profiling support
#
# CONFIG_CRC32 is not set
# CONFIG_PROFILING is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_KALLSYMS is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
......
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.10-rc1
# Mon Nov 1 16:41:09 2004
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=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 is not set
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_LOCALVERSION=""
# CONFIG_SWAP is not set
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_KOBJECT_UEVENT is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
CONFIG_FUTEX=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SHMEM is not set
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
CONFIG_TINY_SHMEM=y
#
# Loadable module support
......@@ -28,21 +51,23 @@ CONFIG_FUTEX=y
# CONFIG_MODULES is not set
#
# Platform support
# Processor
#
CONFIG_PPC=y
CONFIG_PPC32=y
# CONFIG_6xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_POWER3 is not set
# CONFIG_POWER4 is not set
CONFIG_8xx=y
# CONFIG_E500 is not set
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
CONFIG_EMBEDDEDBOOT=y
CONFIG_NOT_COHERENT_CACHE=y
#
# IBM 4xx options
# Platform options
#
CONFIG_EMBEDDEDBOOT=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_NOT_COHERENT_CACHE=y
CONFIG_RPXLITE=y
# CONFIG_RPXCLASSIC is not set
# CONFIG_BSEIP is not set
......@@ -66,27 +91,17 @@ CONFIG_RPXLITE=y
# CONFIG_WINCEPT is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
#
# General setup
#
# CONFIG_HIGHMEM is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS is not set
# CONFIG_PCI_QSPAN is not set
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_HOTPLUG is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Parallel port support
# Bus options
#
# CONFIG_PARPORT is not set
# CONFIG_CMDLINE_BOOL is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS is not set
# CONFIG_PCI_QSPAN is not set
#
# Advanced setup
......@@ -100,51 +115,88 @@ CONFIG_HIGHMEM_START=0xfe000000
CONFIG_LOWMEM_SIZE=0x30000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_TASK_SIZE=0x80000000
CONFIG_CONSISTENT_START=0xff100000
CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_BOOT_LOAD=0x00400000
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
# CONFIG_PNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD 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_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
# Multi-device support (RAID and LVM)
# IO Schedulers
#
# CONFIG_MD is not set
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
#
# ATA/IDE/MFM/RLL support
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
#
# SCSI support
# 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
#
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -156,60 +208,64 @@ CONFIG_NET=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER 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_DHCP is not set
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_INET_ECN is not set
CONFIG_SYN_COOKIES=y
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_IPV6 is not set
# CONFIG_XFRM_USER is not set
# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE 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_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
# CONFIG_NET_CLS_ROUTE 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
# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
......@@ -225,48 +281,34 @@ CONFIG_NET_ETHERNET=y
#
# Ethernet (10000 Mbit)
#
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
# Token Ring devices
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices (depends on LLC=y)
# Wireless LAN (non-hamradio)
#
# CONFIG_SHAPER is not set
# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
# CONFIG_IRDA 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_BOOL is not set
#
# Graphics support
#
# CONFIG_FB is not set
# CONFIG_ISDN is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
# Telephony Support
#
# CONFIG_CD_NO_IDESCSI is not set
# CONFIG_PHONE is not set
#
# Input device support
......@@ -283,54 +325,38 @@ CONFIG_NET_ETHERNET=y
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
# CONFIG_SERIO_I8042 is not set
#
# Input Device Drivers
#
#
# Macintosh device drivers
#
#
# Character devices
#
# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
# CONFIG_SERIAL_CPM_SCC1 is not set
# CONFIG_SERIAL_CPM_SCC2 is not set
# CONFIG_SERIAL_CPM_SCC3 is not set
# CONFIG_SERIAL_CPM_SCC4 is not set
CONFIG_SERIAL_CPM_SMC1=y
# CONFIG_SERIAL_CPM_SMC2 is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# I2C Hardware Sensors Mainboard support
#
#
# I2C Hardware Sensors Chip support
#
# CONFIG_I2C_SENSOR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_LEGACY_PTYS is not set
#
# IPMI
......@@ -346,16 +372,27 @@ 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
# CONFIG_HANGCHECK_TIMER is not set
#
# I2C support
#
# CONFIG_I2C is not set
#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
#
# Misc devices
#
#
# Multimedia devices
......@@ -367,6 +404,27 @@ CONFIG_GEN_RTC=y
#
# CONFIG_DVB is not set
#
# Graphics support
#
# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
#
# File systems
#
......@@ -385,6 +443,7 @@ CONFIG_FS_MBCACHE=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
......@@ -397,17 +456,22 @@ CONFIG_FS_MBCACHE=y
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_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=y
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
......@@ -416,6 +480,7 @@ CONFIG_RAMFS=y
# 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
......@@ -432,17 +497,18 @@ CONFIG_RAMFS=y
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_SUNRPC_GSS is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 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_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
......@@ -456,16 +522,15 @@ CONFIG_PARTITION_ADVANCED=y
# 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
#
# Sound
# Native Language Support
#
# CONFIG_SOUND is not set
# CONFIG_NLS is not set
#
# MPC8xx CPM Options
......@@ -476,40 +541,38 @@ CONFIG_SCC2_ENET=y
# CONFIG_SCC3_ENET is not set
# CONFIG_FEC_ENET is not set
# CONFIG_ENET_BIG_BUFFERS is not set
# CONFIG_SMC2_UART is not set
# CONFIG_USE_SCC_IO is not set
#
# Generic MPC8xx Options
#
CONFIG_8xx_COPYBACK=y
# CONFIG_8xx_CPU6 is not set
# CONFIG_UCODE_PATCH is not set
#
# USB support
#
# CONFIG_USB_GADGET is not set
CONFIG_NO_UCODE_PATCH=y
# CONFIG_USB_SOF_UCODE_PATCH is not set
# CONFIG_I2C_SPI_UCODE_PATCH is not set
# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
#
# Bluetooth support
# Library routines
#
# CONFIG_BT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
#
# Library routines
# Profiling support
#
# CONFIG_CRC32 is not set
# CONFIG_PROFILING is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_KALLSYMS is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
......
......@@ -25,7 +25,7 @@ obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
ifdef CONFIG_MATH_EMULATION
ifndef CONFIG_MATH_EMULATION
obj-$(CONFIG_8xx) += softemu8xx.o
endif
......@@ -32,14 +32,18 @@
#include <asm/ppc_asm.h>
#include <asm/offsets.h>
/* Macro to make the code more readable. */
#ifdef CONFIG_8xx_CPU6
#define DO_8xx_CPU6(val, reg) \
li reg, val; \
stw reg, 12(r0); \
lwz reg, 12(r0);
#else
#define DO_8xx_CPU6(val, reg)
#endif
.text
.globl _stext
_stext:
/*
* _start is defined this way because the XCOFF loader in the OpenFirmware
* on the powermac expects the entry point to be a procedure descriptor.
*/
.text
.globl _start
_start:
......@@ -77,7 +81,6 @@ _start:
* and the CCR at memory location 0.....Someday I'll fix this.....
* -- Dan
*/
.globl __start
__start:
mr r31,r3 /* save parameters */
......@@ -85,7 +88,6 @@ __start:
mr r29,r5
mr r28,r6
mr r27,r7
li r24,0 /* cpu # */
/* We have to turn on the MMU right away so we get cache modes
* set correctly.
......@@ -113,63 +115,106 @@ turn_on_mmu:
* task's thread_struct.
*/
#define EXCEPTION_PROLOG \
mtspr SPRG0,r20; \
mtspr SPRG1,r21; \
mfcr r20; \
mfspr r21,SPRG2; /* exception stack to use from */ \
cmpwi 0,r21,0; /* user mode or RTAS */ \
bne 1f; \
tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \
subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\
1: stw r20,_CCR(r21); /* save registers */ \
stw r22,GPR22(r21); \
stw r23,GPR23(r21); \
mfspr r20,SPRG0; \
stw r20,GPR20(r21); \
mfspr r22,SPRG1; \
stw r22,GPR21(r21); \
mflr r20; \
stw r20,_LINK(r21); \
mfctr r22; \
stw r22,_CTR(r21); \
mfspr r20,XER; \
stw r20,_XER(r21); \
mfspr r22,SRR0; \
mfspr r23,SRR1; \
stw r0,GPR0(r21); \
stw r1,GPR1(r21); \
stw r2,GPR2(r21); \
stw r1,0(r21); \
tovirt(r1,r21); /* set new kernel sp */ \
SAVE_4GPRS(3, r21); \
SAVE_GPR(7, r21);
mtspr SPRG0,r10; \
mtspr SPRG1,r11; \
mfcr r10; \
EXCEPTION_PROLOG_1; \
EXCEPTION_PROLOG_2
#define EXCEPTION_PROLOG_1 \
mfspr r11,SRR1; /* check whether user or kernel */ \
andi. r11,r11,MSR_PR; \
tophys(r11,r1); /* use tophys(r1) if kernel */ \
beq 1f; \
mfspr r11,SPRG3; \
lwz r11,THREAD_INFO-THREAD(r11); \
addi r11,r11,THREAD_SIZE; \
tophys(r11,r11); \
1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */
#define EXCEPTION_PROLOG_2 \
CLR_TOP32(r11); \
stw r10,_CCR(r11); /* save registers */ \
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
mfspr r10,SPRG0; \
stw r10,GPR10(r11); \
mfspr r12,SPRG1; \
stw r12,GPR11(r11); \
mflr r10; \
stw r10,_LINK(r11); \
mfspr r12,SRR0; \
mfspr r9,SRR1; \
stw r1,GPR1(r11); \
stw r1,0(r11); \
tovirt(r1,r11); /* set new kernel sp */ \
li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
MTMSRD(r10); /* (except for mach check in rtas) */ \
stw r0,GPR0(r11); \
SAVE_4GPRS(3, r11); \
SAVE_2GPRS(7, r11)
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
* r21, r22 (SRR0), and r23 (SRR1).
* r11, r12 (SRR0), and r9 (SRR1).
*
* Note2: once we have set r1 we are in a position to take exceptions
* again, and we could thus set MSR:RI at that point.
*/
/*
* Exception vectors.
*/
#define STD_EXCEPTION(n, label, hdlr) \
#define EXCEPTION(n, label, hdlr, xfer) \
. = n; \
label: \
EXCEPTION_PROLOG; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
li r20,MSR_KERNEL; \
bl transfer_to_handler; \
xfer(n, hdlr)
#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \
li r10,trap; \
stw r10,TRAP(r11); \
li r10,MSR_KERNEL; \
copyee(r10, r9); \
bl tfer; \
i##n: \
.long hdlr; \
.long ret_from_except
.long ret
#define COPY_EE(d, s) rlwimi d,s,0,16,16
#define NOCOPY(d, s)
#define EXC_XFER_STD(n, hdlr) \
EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \
ret_from_except_full)
#define EXC_XFER_LITE(n, hdlr) \
EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
ret_from_except)
#define EXC_XFER_EE(n, hdlr) \
EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
ret_from_except_full)
#define EXC_XFER_EE_LITE(n, hdlr) \
EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
ret_from_except)
/* System reset */
#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
#else
STD_EXCEPTION(0x100, Reset, UnknownException)
#endif
EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD)
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
. = 0x200
MachineCheck:
EXCEPTION_PROLOG
mfspr r4,DAR
stw r4,_DAR(r11)
mfspr r5,DSISR
stw r5,_DSISR(r11)
addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_STD(0x200, MachineCheckException)
/* Data access exception.
* This is "never generated" by the MPC8xx. We jump to it for other
......@@ -178,17 +223,11 @@ label: \
. = 0x300
DataAccess:
EXCEPTION_PROLOG
mfspr r20,DSISR
stw r20,_DSISR(r21)
mr r5,r20
mfspr r10,DSISR
stw r10,_DSISR(r11)
mr r5,r10
mfspr r4,DAR
stw r4,_DAR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
bl transfer_to_handler
.long do_page_fault
.long ret_from_except
EXC_XFER_EE_LITE(0x300, handle_page_fault)
/* Instruction access exception.
* This is "never generated" by the MPC8xx. We jump to it for other
......@@ -197,94 +236,52 @@ DataAccess:
. = 0x400
InstructionAccess:
EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r22
mr r5,r23
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
bl transfer_to_handler
.long do_page_fault
.long ret_from_except
mr r4,r12
mr r5,r9
EXC_XFER_EE_LITE(0x400, handle_page_fault)
/* External interrupt */
. = 0x500;
HardwareInterrupt:
EXCEPTION_PROLOG;
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
li r4,0
bl transfer_to_handler
.globl do_IRQ_intercept
do_IRQ_intercept:
.long do_IRQ;
.long ret_from_intercept
EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
/* Alignment exception */
. = 0x600
Alignment:
EXCEPTION_PROLOG
mfspr r4,DAR
stw r4,_DAR(r21)
stw r4,_DAR(r11)
mfspr r5,DSISR
stw r5,_DSISR(r21)
stw r5,_DSISR(r11)
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
bl transfer_to_handler
.long AlignmentException
.long ret_from_except
EXC_XFER_EE(0x600, AlignmentException)
/* Program check exception */
. = 0x700
ProgramCheck:
EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
bl transfer_to_handler
.long ProgramCheckException
.long ret_from_except
EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD)
/* No FPU on MPC8xx. This exception is not supposed to happen.
*/
STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD)
. = 0x900
Decrementer:
EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
bl transfer_to_handler
.globl timer_interrupt_intercept
timer_interrupt_intercept:
.long timer_interrupt
.long ret_from_intercept
/* Decrementer */
EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE)
EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE)
/* System call */
. = 0xc00
SystemCall:
EXCEPTION_PROLOG
stw r3,ORIG_GPR3(r21)
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
bl transfer_to_handler
.long DoSyscall
.long ret_from_except
EXC_XFER_EE_LITE(0xc00, DoSyscall)
/* Single step - not used on 601 */
STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD)
EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE)
EXCEPTION(0xf00, Trap_0f, UnknownException, EXC_XFER_EE)
/* On the MPC8xx, this is a software emulation interrupt. It occurs
* for all unimplemented and illegal instructions.
*/
STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation)
EXCEPTION(0x1000, SoftEmu, SoftwareEmulation, EXC_XFER_STD)
. = 0x1100
/*
......@@ -302,58 +299,43 @@ SystemCall:
InstructionTLBMiss:
#ifdef CONFIG_8xx_CPU6
stw r3, 8(r0)
li r3, 0x3f80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr M_TW, r20 /* Save a couple of working registers */
mfcr r20
stw r20, 0(r0)
stw r21, 4(r0)
mfspr r20, SRR0 /* Get effective address of fault */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3780
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */
mfspr r20, M_TWB /* Get level 1 table entry address */
DO_8xx_CPU6(0x3f80, r3)
mtspr M_TW, r10 /* Save a couple of working registers */
mfcr r10
stw r10, 0(r0)
stw r11, 4(r0)
mfspr r10, SRR0 /* Get effective address of fault */
DO_8xx_CPU6(0x3780, r3)
mtspr MD_EPN, r10 /* Have to use MD_EPN for walk, MI_EPN can't */
mfspr r10, M_TWB /* Get level 1 table entry address */
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
andi. r21, r20, 0x0800 /* Address >= 0x80000000 */
andi. r11, r10, 0x0800 /* Address >= 0x80000000 */
beq 3f
lis r21, swapper_pg_dir@h
ori r21, r21, swapper_pg_dir@l
rlwimi r20, r21, 0, 2, 19
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
rlwimi r10, r11, 0, 2, 19
3:
lwz r21, 0(r20) /* Get the level 1 entry */
rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
lwz r11, 0(r10) /* Get the level 1 entry */
rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
beq 2f /* If zero, don't try to find a pte */
/* We have a pte table, so load the MI_TWC with the attributes
* for this "segment."
*/
tophys(r21,r21)
ori r21,r21,1 /* Set valid bit */
#ifdef CONFIG_8xx_CPU6
li r3, 0x2b80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MI_TWC, r21 /* Set segment attributes */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3b80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_TWC, r21 /* Load pte table base address */
mfspr r21, MD_TWC /* ....and get the pte address */
lwz r20, 0(r21) /* Get the pte */
ori r11,r11,1 /* Set valid bit */
DO_8xx_CPU6(0x2b80, r3)
mtspr MI_TWC, r11 /* Set segment attributes */
DO_8xx_CPU6(0x3b80, r3)
mtspr MD_TWC, r11 /* Load pte table base address */
mfspr r11, MD_TWC /* ....and get the pte address */
lwz r10, 0(r11) /* Get the pte */
ori r20, r20, _PAGE_ACCESSED
stw r20, 0(r21)
ori r10, r10, _PAGE_ACCESSED
stw r10, 0(r11)
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
......@@ -361,29 +343,24 @@ InstructionTLBMiss:
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
li r21, 0x00f0
rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */
#ifdef CONFIG_8xx_CPU6
li r3, 0x2d80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MI_RPN, r20 /* Update TLB entry */
li r11, 0x00f0
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x2d80, r3)
mtspr MI_RPN, r10 /* Update TLB entry */
mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
rfi
2: mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
2: mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
......@@ -393,41 +370,34 @@ InstructionTLBMiss:
DataStoreTLBMiss:
#ifdef CONFIG_8xx_CPU6
stw r3, 8(r0)
li r3, 0x3f80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr M_TW, r20 /* Save a couple of working registers */
mfcr r20
stw r20, 0(r0)
stw r21, 4(r0)
mfspr r20, M_TWB /* Get level 1 table entry address */
DO_8xx_CPU6(0x3f80, r3)
mtspr M_TW, r10 /* Save a couple of working registers */
mfcr r10
stw r10, 0(r0)
stw r11, 4(r0)
mfspr r10, M_TWB /* Get level 1 table entry address */
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
andi. r21, r20, 0x0800
andi. r11, r10, 0x0800
beq 3f
lis r21, swapper_pg_dir@h
ori r21, r21, swapper_pg_dir@l
rlwimi r20, r21, 0, 2, 19
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
rlwimi r10, r11, 0, 2, 19
3:
lwz r21, 0(r20) /* Get the level 1 entry */
rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
lwz r11, 0(r10) /* Get the level 1 entry */
rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
beq 2f /* If zero, don't try to find a pte */
/* We have a pte table, so load fetch the pte from the table.
*/
tophys(r21, r21)
ori r21, r21, 1 /* Set valid bit in physical L2 page */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3b80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_TWC, r21 /* Load pte table base address */
mfspr r20, MD_TWC /* ....and get the pte address */
lwz r20, 0(r20) /* Get the pte */
ori r11, r11, 1 /* Set valid bit in physical L2 page */
DO_8xx_CPU6(0x3b80, r3)
mtspr MD_TWC, r11 /* Load pte table base address */
mfspr r10, MD_TWC /* ....and get the pte address */
lwz r10, 0(r10) /* Get the pte */
/* Insert the Guarded flag into the TWC from the Linux PTE.
* It is bit 27 of both the Linux PTE and the TWC (at least
......@@ -435,17 +405,13 @@ DataStoreTLBMiss:
* this into the Linux pgd/pmd and load it in the operation
* above.
*/
rlwimi r21, r20, 0, 27, 27
#ifdef CONFIG_8xx_CPU6
li r3, 0x3b80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_TWC, r21
rlwimi r11, r10, 0, 27, 27
DO_8xx_CPU6(0x3b80, r3)
mtspr MD_TWC, r11
mfspr r21, MD_TWC /* get the pte address again */
ori r20, r20, _PAGE_ACCESSED
stw r20, 0(r21)
mfspr r11, MD_TWC /* get the pte address again */
ori r10, r10, _PAGE_ACCESSED
stw r10, 0(r11)
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
......@@ -453,29 +419,24 @@ DataStoreTLBMiss:
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
li r21, 0x00f0
rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */
li r11, 0x00f0
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x3d80, r3)
mtspr MD_RPN, r10 /* Update TLB entry */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3d80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_RPN, r20 /* Update TLB entry */
mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
rfi
2: mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
2: mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
......@@ -501,19 +462,17 @@ InstructionTLBError:
DataTLBError:
#ifdef CONFIG_8xx_CPU6
stw r3, 8(r0)
li r3, 0x3f80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr M_TW, r20 /* Save a couple of working registers */
mfcr r20
stw r20, 0(r0)
stw r21, 4(r0)
DO_8xx_CPU6(0x3f80, r3)
mtspr M_TW, r10 /* Save a couple of working registers */
mfcr r10
stw r10, 0(r0)
stw r11, 4(r0)
/* First, make sure this was a store operation.
*/
mfspr r20, DSISR
andis. r21, r20, 0x0200 /* If set, indicates store op */
mfspr r10, DSISR
andis. r11, r10, 0x0200 /* If set, indicates store op */
beq 2f
/* The EA of a data TLB miss is automatically stored in the MD_EPN
......@@ -532,54 +491,45 @@ DataTLBError:
* are initialized in mapin_ram(). This will avoid the problem,
* assuming we only use the dcbi instruction on kernel addresses.
*/
mfspr r20, DAR
rlwinm r21, r20, 0, 0, 19
ori r21, r21, MD_EVALID
mfspr r20, M_CASID
rlwimi r21, r20, 0, 28, 31
#ifdef CONFIG_8xx_CPU6
li r3, 0x3780
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_EPN, r21
mfspr r10, DAR
rlwinm r11, r10, 0, 0, 19
ori r11, r11, MD_EVALID
mfspr r10, M_CASID
rlwimi r11, r10, 0, 28, 31
DO_8xx_CPU6(0x3780, r3)
mtspr MD_EPN, r11
mfspr r20, M_TWB /* Get level 1 table entry address */
mfspr r10, M_TWB /* Get level 1 table entry address */
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
andi. r21, r20, 0x0800
andi. r11, r10, 0x0800
beq 3f
lis r21, swapper_pg_dir@h
ori r21, r21, swapper_pg_dir@l
rlwimi r20, r21, 0, 2, 19
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
rlwimi r10, r11, 0, 2, 19
3:
lwz r21, 0(r20) /* Get the level 1 entry */
rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
lwz r11, 0(r10) /* Get the level 1 entry */
rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
beq 2f /* If zero, bail */
/* We have a pte table, so fetch the pte from the table.
*/
tophys(r21, r21)
ori r21, r21, 1 /* Set valid bit in physical L2 page */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3b80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_TWC, r21 /* Load pte table base address */
mfspr r21, MD_TWC /* ....and get the pte address */
lwz r20, 0(r21) /* Get the pte */
ori r11, r11, 1 /* Set valid bit in physical L2 page */
DO_8xx_CPU6(0x3b80, r3)
mtspr MD_TWC, r11 /* Load pte table base address */
mfspr r11, MD_TWC /* ....and get the pte address */
lwz r10, 0(r11) /* Get the pte */
andi. r21, r20, _PAGE_RW /* Is it writeable? */
andi. r11, r10, _PAGE_RW /* Is it writeable? */
beq 2f /* Bail out if not */
/* Update 'changed', among others.
*/
ori r20, r20, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
mfspr r21, MD_TWC /* Get pte address again */
stw r20, 0(r21) /* and update pte in table */
ori r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
mfspr r11, MD_TWC /* Get pte address again */
stw r10, 0(r11) /* and update pte in table */
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
......@@ -587,50 +537,45 @@ DataTLBError:
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
li r21, 0x00f0
rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */
#ifdef CONFIG_8xx_CPU6
li r3, 0x3d80
stw r3, 12(r0)
lwz r3, 12(r0)
#endif
mtspr MD_RPN, r20 /* Update TLB entry */
li r11, 0x00f0
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x3d80, r3)
mtspr MD_RPN, r10 /* Update TLB entry */
mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
rfi
2:
mfspr r20, M_TW /* Restore registers */
lwz r21, 0(r0)
mtcr r21
lwz r21, 4(r0)
mfspr r10, M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
b DataAccess
STD_EXCEPTION(0x1500, Trap_15, UnknownException)
STD_EXCEPTION(0x1600, Trap_16, UnknownException)
STD_EXCEPTION(0x1700, Trap_17, TAUException)
STD_EXCEPTION(0x1800, Trap_18, UnknownException)
STD_EXCEPTION(0x1900, Trap_19, UnknownException)
STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE)
/* On the MPC8xx, these next four traps are used for development
* support of breakpoints and such. Someday I will get around to
* using them.
*/
STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE)
EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE)
. = 0x2000
......
......@@ -321,9 +321,6 @@ EXPORT_SYMBOL(cpm_free_handler);
#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx)
EXPORT_SYMBOL(__res);
#endif
#if defined(CONFIG_8xx)
EXPORT_SYMBOL(request_8xxirq);
#endif
EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context);
......
......@@ -133,7 +133,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
print_8xx_pte(current->mm,regs->nip);
pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
pa |= (regs->nip & ~PAGE_MASK);
pa = __va(pa);
pa = (unsigned long)__va(pa);
printk("Kernel VA for NIP %x ", pa);
print_8xx_pte(current->mm,pa);
}
......
......@@ -82,7 +82,6 @@ extern bd_t m8xx_board_info;
/* for pcmcia sandisk */
#ifdef CONFIG_IDE
# define MAX_HWIFS 1
# define request_irq(irq,hand,flg,dev,id) request_8xxirq((irq),(hand),(flg),(dev),(id))
#endif
#endif
......
......@@ -68,7 +68,6 @@ extern bd_t m8xx_board_info;
#ifdef CONFIG_IDE
# define MAX_HWIFS 1
# define request_irq(irq,hand,flg,dev,id) request_8xxirq((irq),(hand),(flg),(dev),(id))
#endif
/* CPM Ethernet through SCCx.
......
......@@ -72,8 +72,6 @@ static __inline__ void ide_led(int on)
#define IDE0_INTERRUPT 13
#ifdef CONFIG_IDE
#define ide_request_irq(irq,hand,flg,dev,id) \
request_8xxirq((irq),(hand),(flg),(dev),(id))
#endif
/*-----------------------------------------------------------------------
......
......@@ -57,8 +57,10 @@ unsigned char __res[sizeof(bd_t)];
extern void m8xx_ide_init(void);
extern unsigned long find_available_memory(void);
extern void m8xx_cpm_reset(uint);
extern void m8xx_cpm_reset(uint cpm_page);
extern void m8xx_wdt_handler_install(bd_t *bp);
extern void rpxfb_alloc_pages(void);
extern void cpm_interrupt_init(void);
void __attribute__ ((weak))
board_init(void)
......@@ -123,11 +125,19 @@ abort(void)
}
/* A place holder for time base interrupts, if they are ever enabled. */
void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
{
printk ("timebase_interrupt()\n");
return IRQ_HANDLED;
}
static struct irqaction tbint_irqaction = {
.handler = timebase_interrupt,
.mask = CPU_MASK_NONE,
.name = "tbint",
};
/* The decrementer counts at the system (internal) clock frequency divided by
* sixteen, or external oscillator divided by four. We force the processor
* to use system clock divided by sixteen.
......@@ -192,8 +202,15 @@ void __init m8xx_calibrate_decr(void)
((mk_int_int_mask(DEC_INTERRUPT) << 8) |
(TBSCR_TBF | TBSCR_TBE));
if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
if (setup_irq(DEC_INTERRUPT, &tbint_irqaction))
panic("Could not allocate timer IRQ!");
#ifdef CONFIG_8xx_WDT
/* Install watchdog timer handler early because it might be
* already enabled by the bootloader
*/
m8xx_wdt_handler_install(binfo);
#endif
}
/* The RTC on the MPC8xx is an internal register.
......@@ -261,6 +278,14 @@ m8xx_show_percpuinfo(struct seq_file *m, int i)
return 0;
}
#ifdef CONFIG_PCI
static struct irqaction mbx_i8259_irqaction = {
.handler = mbx_i8259_action,
.mask = CPU_MASK_NONE,
.name = "i8259 cascade",
};
#endif
/* Initialize the internal interrupt controller. The number of
* interrupts supported can vary with the processor type, and the
* 82xx family can have up to 64.
......@@ -271,25 +296,26 @@ static void __init
m8xx_init_IRQ(void)
{
int i;
void cpm_interrupt_init(void);
for ( i = 0 ; i < NR_SIU_INTS ; i++ )
for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
irq_desc[i].handler = &ppc8xx_pic;
/* We could probably incorporate the CPM into the multilevel
* interrupt structure.
*/
cpm_interrupt_init();
unmask_irq(CPM_INTERRUPT);
#if defined(CONFIG_PCI)
for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
irq_desc[i].handler = &i8259_pic;
i8259_pic.irq_offset = NR_SIU_INTS;
i8259_init();
request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
i8259_pic_irq_offset = I8259_IRQ_OFFSET;
i8259_init(0);
/* The i8259 cascade interrupt must be level sensitive. */
((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &=
~(0x80000000 >> ISA_BRIDGE_INT);
if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction))
enable_irq(ISA_BRIDGE_INT);
#endif
#endif /* CONFIG_PCI */
}
/* -------------------------------------------------------------------- */
......@@ -340,7 +366,7 @@ m8xx_map_io(void)
io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
#endif
#ifdef CONFIG_HTDMSOUND
#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
#endif
#ifdef CONFIG_FADS
......@@ -349,6 +375,9 @@ m8xx_map_io(void)
#ifdef CONFIG_PCI
io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
#endif
#if defined(CONFIG_NETTA)
io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
}
void __init
......
......@@ -4,11 +4,14 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>
#include "ppc8xx_pic.h"
extern int cpm_get_irq(struct pt_regs *regs);
/* The 8xx internal interrupt controller. It is usually
* the only interrupt controller. Some boards, like the MBX and
* Sandpoint have the 8259 as a secondary controller. Depending
......@@ -72,46 +75,13 @@ static void m8xx_mask_and_ack(unsigned int irq_nr)
}
struct hw_interrupt_type ppc8xx_pic = {
" 8xx SIU ",
NULL,
NULL,
m8xx_unmask_irq,
m8xx_mask_irq,
m8xx_mask_and_ack,
m8xx_end_irq,
0
.typename = " 8xx SIU ",
.enable = m8xx_unmask_irq,
.disable = m8xx_mask_irq,
.ack = m8xx_mask_and_ack,
.end = m8xx_end_irq,
};
#if 0
void
m8xx_do_IRQ(struct pt_regs *regs,
int cpu)
{
int irq;
unsigned long bits = 0;
/* For MPC8xx, read the SIVEC register and shift the bits down
* to get the irq number. */
bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
irq = bits >> 26;
#if 0
irq += ppc8xx_pic.irq_offset;
#endif
bits = 1UL << irq;
if (irq < 0) {
printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
irq, regs->nip);
ppc_spurious_interrupts++;
}
else {
__do_IRQ(irq, regs);
}
}
#endif
/*
* We either return a valid interrupt or -1 if there is nothing pending
*/
......@@ -129,73 +99,32 @@ m8xx_get_irq(struct pt_regs *regs)
* When we read the sivec without an interrupt to process, we will
* get back SIU_LEVEL7. In this case, return -1
*/
if (irq == SIU_LEVEL7)
return -1;
if (irq == CPM_INTERRUPT)
irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
#if defined(CONFIG_PCI)
else if (irq == ISA_BRIDGE_INT) {
int isa_irq;
if ((isa_irq = i8259_poll(regs)) >= 0)
irq = I8259_IRQ_OFFSET + isa_irq;
}
#endif /* CONFIG_PCI */
else if (irq == SIU_LEVEL7)
irq = -1;
return irq;
}
/* The MBX is the only 8xx board that uses the 8259.
*/
#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
{
int bits, irq;
/* A bug in the QSpan chip causes it to give us 0xff always
* when doing a character read. So read 32 bits and shift.
* This doesn't seem to return useful values anyway, but
* read it to make sure things are acked.
* -- Cort
*/
irq = (inl(0x508) >> 24)&0xff;
if ( irq != 0xff ) printk("iack %d\n", irq);
outb(0x0C, 0x20);
irq = inb(0x20) & 7;
if (irq == 2)
{
outb(0x0C, 0xA0);
irq = inb(0xA0);
irq = (irq&7) + 8;
}
bits = 1UL << irq;
irq += i8259_pic.irq_offset;
__do_IRQ(irq, regs);
}
#endif
/* Only the MBX uses the external 8259. This allows us to catch standard
* drivers that may mess up the internal interrupt controllers, and also
* allow them to run without modification on the MBX.
*/
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname, void *dev_id)
void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
{
#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
irq += i8259_pic.irq_offset;
return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
#else
/*
* Handle other "well-known" interrupts, but panic on unknown ones.
/* This interrupt handler never actually gets called. It is
* installed only to unmask the 8259 cascade interrupt in the SIU
* and to make the 8259 cascade interrupt visible in /proc/interrupts.
*/
switch (irq) {
#ifdef IDE0_INTERRUPT
case IDE0_INTERRUPT: /* IDE0 */
return (request_8xxirq(irq, handler, irqflags, devname,
dev_id));
#endif
#ifdef IDE1_INTERRUPT
case IDE1_INTERRUPT: /* IDE1 */
return (request_8xxirq(irq, handler, irqflags, devname,
dev_id));
#endif
default: /* unknown IRQ -> panic */
panic("request_irq");
}
#endif
}
EXPORT_SYMBOL(request_irq);
#endif /* CONFIG_PCI */
......@@ -70,6 +70,8 @@ struct uart_cpm_port {
/* helpers */
int baud;
int bits;
/* Keep track of 'odd' SMC2 wirings */
int is_portb;
};
extern int cpm_uart_port_map[UART_NR];
......
......@@ -743,6 +743,18 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
/*
* In case SMC1 is being relocated...
*/
#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
up->smc_rbptr = pinfo->smcup->smc_rbase;
up->smc_tbptr = pinfo->smcup->smc_tbase;
up->smc_rstate = 0;
up->smc_tstate = 0;
up->smc_brkcr = 1; /* number of break chars */
up->smc_brkec = 0;
#endif
/* Set up the uart parameters in the
* parameter ram.
*/
......@@ -872,6 +884,9 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.rx_nrfifos = RX_NUM_FIFO,
.rx_fifosize = RX_BUF_SIZE,
.set_lineif = smc2_lineif,
#ifdef CONFIG_SERIAL_CPM_ALT_SMC2
.is_portb = 1,
#endif
},
[UART_SCC1] = {
.port = {
......
......@@ -82,10 +82,17 @@ void cpm_line_cr_cmd(int line, int cmd)
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;
unsigned int iobits = 0x000000c0;
if (!pinfo->is_portb) {
cp->cp_pbpar |= iobits;
cp->cp_pbdir &= ~iobits;
cp->cp_pbodr &= ~iobits;
} else {
((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
}
pinfo->brg = 1;
}
......@@ -194,8 +201,16 @@ int cpm_uart_init_portdesc(void)
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0];
/*
* Is SMC1 being relocated?
*/
# ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpmp->cp_dparam[0x3C0];
# else
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1];
# endif
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);
......
......@@ -92,23 +92,77 @@ typedef struct mem_ctlr {
char res3[0x80];
} memctl8xx_t;
/*-----------------------------------------------------------------------
* BR - Memory Controler: Base Register 16-9
*/
#define BR_BA_MSK 0xffff8000 /* Base Address Mask */
#define BR_AT_MSK 0x00007000 /* Address Type Mask */
#define BR_PS_MSK 0x00000c00 /* Port Size Mask */
#define BR_PS_32 0x00000000 /* 32 bit port size */
#define BR_PS_16 0x00000800 /* 16 bit port size */
#define BR_PS_8 0x00000400 /* 8 bit port size */
#define BR_PARE 0x00000200 /* Parity Enable */
#define BR_WP 0x00000100 /* Write Protect */
#define BR_MS_MSK 0x000000c0 /* Machine Select Mask */
#define BR_MS_GPCM 0x00000000 /* G.P.C.M. Machine Select */
#define BR_MS_UPMA 0x00000080 /* U.P.M.A Machine Select */
#define BR_MS_UPMB 0x000000c0 /* U.P.M.B Machine Select */
#define BR_V 0x00000001 /* Bank Valid */
/*-----------------------------------------------------------------------
* OR - Memory Controler: Option Register 16-11
*/
#define OR_AM_MSK 0xffff8000 /* Address Mask Mask */
#define OR_ATM_MSK 0x00007000 /* Address Type Mask Mask */
#define OR_CSNT_SAM 0x00000800 /* Chip Select Negation Time/ Start */
/* Address Multiplex */
#define OR_ACS_MSK 0x00000600 /* Address to Chip Select Setup mask */
#define OR_ACS_DIV1 0x00000000 /* CS is output at the same time */
#define OR_ACS_DIV4 0x00000400 /* CS is output 1/4 a clock later */
#define OR_ACS_DIV2 0x00000600 /* CS is output 1/2 a clock later */
#define OR_G5LA 0x00000400 /* Output #GPL5 on #GPL_A5 */
#define OR_G5LS 0x00000200 /* Drive #GPL high on falling edge of...*/
#define OR_BI 0x00000100 /* Burst inhibit */
#define OR_SCY_MSK 0x000000f0 /* Cycle Lenght in Clocks */
#define OR_SCY_0_CLK 0x00000000 /* 0 clock cycles wait states */
#define OR_SCY_1_CLK 0x00000010 /* 1 clock cycles wait states */
#define OR_SCY_2_CLK 0x00000020 /* 2 clock cycles wait states */
#define OR_SCY_3_CLK 0x00000030 /* 3 clock cycles wait states */
#define OR_SCY_4_CLK 0x00000040 /* 4 clock cycles wait states */
#define OR_SCY_5_CLK 0x00000050 /* 5 clock cycles wait states */
#define OR_SCY_6_CLK 0x00000060 /* 6 clock cycles wait states */
#define OR_SCY_7_CLK 0x00000070 /* 7 clock cycles wait states */
#define OR_SCY_8_CLK 0x00000080 /* 8 clock cycles wait states */
#define OR_SCY_9_CLK 0x00000090 /* 9 clock cycles wait states */
#define OR_SCY_10_CLK 0x000000a0 /* 10 clock cycles wait states */
#define OR_SCY_11_CLK 0x000000b0 /* 11 clock cycles wait states */
#define OR_SCY_12_CLK 0x000000c0 /* 12 clock cycles wait states */
#define OR_SCY_13_CLK 0x000000d0 /* 13 clock cycles wait states */
#define OR_SCY_14_CLK 0x000000e0 /* 14 clock cycles wait states */
#define OR_SCY_15_CLK 0x000000f0 /* 15 clock cycles wait states */
#define OR_SETA 0x00000008 /* External Transfer Acknowledge */
#define OR_TRLX 0x00000004 /* Timing Relaxed */
#define OR_EHTR 0x00000002 /* Extended Hold Time on Read */
/* System Integration Timers.
*/
typedef struct sys_int_timers {
ushort sit_tbscr;
char res0[0x02];
uint sit_tbreff0;
uint sit_tbreff1;
char res1[0x14];
ushort sit_rtcsc;
char res2[0x02];
uint sit_rtc;
uint sit_rtsec;
uint sit_rtcal;
char res2[0x10];
char res3[0x10];
ushort sit_piscr;
char res3[2];
char res4[2];
uint sit_pitc;
uint sit_pitr;
char res4[0x34];
char res5[0x34];
} sit8xx_t;
#define TBSCR_TBIRQ_MASK ((ushort)0xff00)
......@@ -174,20 +228,38 @@ typedef struct cark {
*/
#define KAPWR_KEY ((unsigned int)0x55ccaa33)
/* LCD interface. MPC821 and MPC823 Only.
/* Video interface. MPC823 Only.
*/
typedef struct vid823 {
ushort vid_vccr;
ushort res1;
u_char vid_vsr;
u_char res2;
u_char vid_vcmr;
u_char res3;
uint vid_vbcb;
uint res4;
uint vid_vfcr0;
uint vid_vfaa0;
uint vid_vfba0;
uint vid_vfcr1;
uint vid_vfaa1;
uint vid_vfba1;
u_char res5[0x18];
} vid823_t;
/* LCD interface. 823 Only.
*/
typedef struct lcd {
ushort lcd_lcolr[16];
char res[0x20];
uint lcd_lccr;
uint lcd_lchcr;
uint lcd_lcvcr;
char res2[4];
char res1[4];
uint lcd_lcfaa;
uint lcd_lcfba;
char lcd_lcsr;
char res3[0x7];
} lcd8xx_t;
char res2[0x7];
} lcd823_t;
/* I2C
*/
......@@ -254,7 +326,8 @@ typedef struct io_port {
ushort iop_pdpar;
char res3[2];
ushort iop_pddat;
char res4[8];
uint utmode;
char res4[4];
} iop8xx_t;
/* Communication Processor Module Timers
......@@ -290,7 +363,7 @@ typedef struct cpm_timers {
typedef struct scc { /* Serial communication channels */
uint scc_gsmrl;
uint scc_gsmrh;
ushort scc_pmsr;
ushort scc_psmr;
char res1[2];
ushort scc_todr;
ushort scc_dsr;
......@@ -315,41 +388,44 @@ typedef struct smc { /* Serial management channels */
/* MPC860T Fast Ethernet Controller. It isn't part of the CPM, but
* it fits within the address space.
*/
typedef struct fec {
uint fec_addr_low; /* LS 32 bits of station address */
ushort fec_addr_high; /* MS 16 bits of address */
ushort res1;
uint fec_hash_table_high;
uint fec_hash_table_low;
uint fec_r_des_start;
uint fec_x_des_start;
uint fec_r_buff_size;
uint res2[9];
uint fec_ecntrl;
uint fec_ievent;
uint fec_imask;
uint fec_ivec;
uint fec_r_des_active;
uint fec_x_des_active;
uint res3[10];
uint fec_mii_data;
uint fec_mii_speed;
uint res4[17];
uint fec_r_bound;
uint fec_r_fstart;
uint res5[6];
uint fec_x_fstart;
uint res6[17];
uint fec_fun_code;
uint res7[3];
uint fec_r_cntrl;
uint fec_r_hash;
uint res8[14];
uint fec_x_cntrl;
uint res9[0x1e];
uint fec_addr_low; /* lower 32 bits of station address */
ushort fec_addr_high; /* upper 16 bits of station address */
ushort res1; /* reserved */
uint fec_hash_table_high; /* upper 32-bits of hash table */
uint fec_hash_table_low; /* lower 32-bits of hash table */
uint fec_r_des_start; /* beginning of Rx descriptor ring */
uint fec_x_des_start; /* beginning of Tx descriptor ring */
uint fec_r_buff_size; /* Rx buffer size */
uint res2[9]; /* reserved */
uint fec_ecntrl; /* ethernet control register */
uint fec_ievent; /* interrupt event register */
uint fec_imask; /* interrupt mask register */
uint fec_ivec; /* interrupt level and vector status */
uint fec_r_des_active; /* Rx ring updated flag */
uint fec_x_des_active; /* Tx ring updated flag */
uint res3[10]; /* reserved */
uint fec_mii_data; /* MII data register */
uint fec_mii_speed; /* MII speed control register */
uint res4[17]; /* reserved */
uint fec_r_bound; /* end of RAM (read-only) */
uint fec_r_fstart; /* Rx FIFO start address */
uint res5[6]; /* reserved */
uint fec_x_fstart; /* Tx FIFO start address */
uint res6[17]; /* reserved */
uint fec_fun_code; /* fec SDMA function code */
uint res7[3]; /* reserved */
uint fec_r_cntrl; /* Rx control register */
uint fec_r_hash; /* Rx hash register */
uint res8[14]; /* reserved */
uint fec_x_cntrl; /* Tx control register */
uint res9[0x1e]; /* reserved */
} fec_t;
/* We need this as the fec and fb cmap use the same address space */
/* The FEC and LCD color map share the same address space....
* I guess we will never see an 823T :-).
*/
union fec_lcd {
fec_t fl_un_fec;
u_char fl_un_cmap[0x200];
......@@ -359,18 +435,20 @@ typedef struct comm_proc {
/* General control and status registers.
*/
ushort cp_cpcr;
char res1[2];
u_char res1[2];
ushort cp_rccr;
char res2[6];
u_char res2;
u_char cp_rmds;
u_char res3[4];
ushort cp_cpmcr1;
ushort cp_cpmcr2;
ushort cp_cpmcr3;
ushort cp_cpmcr4;
char res3[2];
u_char res4[2];
ushort cp_rter;
char res4[2];
u_char res5[2];
ushort cp_rtmr;
char res5[0x14];
u_char res6[0x14];
/* Baud rate generators.
*/
......@@ -390,56 +468,75 @@ typedef struct comm_proc {
/* Serial Peripheral Interface.
*/
ushort cp_spmode;
char res6[4];
u_char res7[4];
u_char cp_spie;
char res7[3];
u_char res8[3];
u_char cp_spim;
char res8[2];
u_char res9[2];
u_char cp_spcom;
char res9[2];
u_char res10[2];
/* Parallel Interface Port.
*/
char res10[2];
u_char res11[2];
ushort cp_pipc;
char res11[2];
u_char res12[2];
ushort cp_ptpr;
uint cp_pbdir;
uint cp_pbpar;
char res12[2];
u_char res13[2];
ushort cp_pbodr;
uint cp_pbdat;
char res13[0x18];
/* Port E - MPC87x/88x only.
*/
uint cp_pedir;
uint cp_pepar;
uint cp_peso;
uint cp_peodr;
uint cp_pedat;
/* Communications Processor Timing Register -
Contains RMII Timing for the FECs on MPC87x/88x only.
*/
uint cp_cptr;
/* Serial Interface and Time Slot Assignment.
*/
uint cp_simode;
u_char cp_sigmr;
char res14;
u_char res15;
u_char cp_sistr;
u_char cp_sicmr;
char res15[4];
u_char res16[4];
uint cp_sicr;
uint cp_sirp;
char res16[0x10c];
u_char res17[0xc];
/* 256 bytes of MPC823 video controller RAM array.
*/
u_char cp_vcram[0x100];
u_char cp_siram[0x200];
/* The fast ethernet controller is not really part of the CPM,
* but it resides in the address space.
*
* The colormap for the LCD controller is also located here
* The LCD color map is also here.
*/
union fec_lcd fl_un;
#define cp_fec fl_un.fl_un_fec
#define lcd_cmap fl_un.fl_un_cmap
char res18[0x1000];
char res18[0xE00];
/* The DUET family has a second FEC here */
fec_t cp_fec2;
#define cp_fec1 cp_fec /* consistency macro */
/* Dual Ported RAM follows.
* There are many different formats for this memory area
* depending upon the devices used and options chosen.
* Some processors don't have all of it populated.
*/
u_char cp_dpmem[0x1000]; /* BD / Data / ucode */
u_char res19[0xc00];
u_char cp_dpmem[0x1C00]; /* BD / Data / ucode */
u_char cp_dparam[0x400]; /* Parameter RAM */
} cpm8xx_t;
......@@ -453,7 +550,8 @@ typedef struct immap {
car8xx_t im_clkrst; /* Clocks and reset */
sitk8xx_t im_sitk; /* Sys int timer keys */
cark8xx_t im_clkrstk; /* Clocks and reset keys */
lcd8xx_t im_lcd; /* LCD (821 and 823 only) */
vid823_t im_vid; /* Video (823 only) */
lcd823_t im_lcd; /* LCD (823 only) */
i2c8xx_t im_i2c; /* I2C control/status */
sdma8xx_t im_sdma; /* SDMA control/status */
cpic8xx_t im_cpic; /* CPM Interrupt Controller */
......
......@@ -19,6 +19,7 @@
#include <linux/config.h>
#include <asm/8xx_immap.h>
#include <asm/ptrace.h>
/* CPM Command register.
*/
......@@ -78,7 +79,9 @@ extern void cpm_dpdump(void);
extern void *cpm_dpram_addr(uint offset);
extern void cpm_setbrg(uint brg, uint rate);
uint m8xx_cpm_hostalloc(uint size);
extern uint m8xx_cpm_hostalloc(uint size);
extern int m8xx_cpm_hostfree(uint start);
extern void m8xx_cpm_hostdump(void);
/* Buffer descriptors used by many of the CPM protocols.
*/
......@@ -142,6 +145,8 @@ typedef struct smc_uart {
ushort smc_brkec; /* rcv'd break condition counter */
ushort smc_brkcr; /* xmt break count register */
ushort smc_rmask; /* Temporary bit mask */
char res1[8]; /* Reserved */
ushort smc_rpbase; /* Relocation pointer */
} smc_uart_t;
/* Function code bits.
......@@ -309,6 +314,7 @@ typedef struct smc_centronics {
#define SCC_GSMRL_ENR ((uint)0x00000020)
#define SCC_GSMRL_ENT ((uint)0x00000010)
#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c)
#define SCC_GSMRL_MODE_QMC ((uint)0x0000000a)
#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009)
#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008)
#define SCC_GSMRL_MODE_V14 ((uint)0x00000007)
......@@ -418,19 +424,19 @@ typedef struct scc_enet {
/* SCC Mode Register (PMSR) as used by Ethernet.
*/
#define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */
#define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */
#define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */
#define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */
#define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */
#define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */
#define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */
#define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */
#define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */
#define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */
#define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */
#define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */
#define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */
#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */
#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */
#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */
#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */
#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */
#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */
#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */
#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */
#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */
#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */
#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */
#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */
#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */
/* Buffer descriptor control/status used by Ethernet receive.
*/
......@@ -471,8 +477,7 @@ typedef struct scc_enet {
*/
typedef struct scc_uart {
sccp_t scc_genscc;
uint scc_res1; /* Reserved */
uint scc_res2; /* Reserved */
char res1[8]; /* Reserved */
ushort scc_maxidl; /* Maximum idle chars */
ushort scc_idlc; /* temp idle counter */
ushort scc_brkcr; /* Break count register */
......@@ -514,19 +519,19 @@ typedef struct scc_uart {
/* The SCC PMSR 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)0x0002)
#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)0x0002)
/* CPM Transparent mode SCC.
*/
......@@ -556,9 +561,9 @@ typedef struct iic {
ushort iic_tbptr; /* Internal */
ushort iic_tbc; /* Internal */
uint iic_txtmp; /* Internal */
uint iic_res; /* reserved */
char res1[4]; /* Reserved */
ushort iic_rpbase; /* Relocation pointer */
ushort iic_res2; /* reserved */
char res2[2]; /* Reserved */
} iic_t;
#define BD_IIC_START ((ushort)0x0400)
......
......@@ -81,6 +81,10 @@ irq_canonicalize(int irq)
#elif defined(CONFIG_8xx)
/* Now include the board configuration specific associations.
*/
#include <asm/mpc8xx.h>
/* The MPC8xx cores have 16 possible interrupts. There are eight
* possible level sensitive interrupts assigned and generated internally
* from such devices as CPM, PCMCIA, RTC, PIT, TimeBase and Decrementer.
......@@ -89,10 +93,22 @@ irq_canonicalize(int irq)
*
* On some implementations, there is also the possibility of an 8259
* through the PCI and PCI-ISA bridges.
*
* We are "flattening" the interrupt vectors of the cascaded CPM
* and 8259 interrupt controllers so that we can uniquely identify
* any interrupt source with a single integer.
*/
#define NR_SIU_INTS 16
#define NR_CPM_INTS 32
#ifndef NR_8259_INTS
#define NR_8259_INTS 0
#endif
#define NR_IRQS (NR_SIU_INTS + NR_8259_INTS)
#define SIU_IRQ_OFFSET 0
#define CPM_IRQ_OFFSET (SIU_IRQ_OFFSET + NR_SIU_INTS)
#define I8259_IRQ_OFFSET (CPM_IRQ_OFFSET + NR_CPM_INTS)
#define NR_IRQS (NR_SIU_INTS + NR_CPM_INTS + NR_8259_INTS)
/* These values must be zero-based and map 1:1 with the SIU configuration.
* They are used throughout the 8xx I/O subsystem to generate
......@@ -117,10 +133,6 @@ irq_canonicalize(int irq)
#define SIU_IRQ7 (14)
#define SIU_LEVEL7 (15)
/* Now include the board configuration specific associations.
*/
#include <asm/mpc8xx.h>
/* The internal interrupts we can configure as we see fit.
* My personal preference is CPM at level 2, which puts it above the
* MBX PCI/ISA/IDE interrupts.
......
......@@ -96,11 +96,7 @@
extern unsigned char __res[];
struct pt_regs;
extern int request_8xxirq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long flags,
const char *device,
void *dev_id);
#endif /* !__ASSEMBLY__ */
#endif /* CONFIG_8xx */
#endif /* __CONFIG_8xx_DEFS */
......
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