summaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
commitf1da2c3860e301527d56a1ef0b56c649ee7c4b1b (patch)
tree562b5d2e8b9cb62eb983d78ff6bcf9789e08fcf6 /arch/ppc
parent00f11569ac8ca73cbcdef8822de1583e79aee571 (diff)
Merge with Linux 2.4.0-test5-pre1. This works again on Origin UP.
The IP22 cache bugs which are plaguing some machines are still unfixed.
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/8xx_io/Config.in12
-rw-r--r--arch/ppc/8xx_io/commproc.h79
-rw-r--r--arch/ppc/8xx_io/enet.c55
-rw-r--r--arch/ppc/8xx_io/uart.c656
-rw-r--r--arch/ppc/coffboot/Makefile4
-rw-r--r--arch/ppc/config.in38
-rw-r--r--arch/ppc/kernel/Makefile3
-rw-r--r--arch/ppc/kernel/bitops.c197
-rw-r--r--arch/ppc/kernel/chrp_pci.c2
-rw-r--r--arch/ppc/kernel/chrp_setup.c2
-rw-r--r--arch/ppc/kernel/chrp_time.c2
-rw-r--r--arch/ppc/kernel/entry.S14
-rw-r--r--arch/ppc/kernel/feature.c170
-rw-r--r--arch/ppc/kernel/gemini_setup.c2
-rw-r--r--arch/ppc/kernel/head.S47
-rw-r--r--arch/ppc/kernel/idle.c1
-rw-r--r--arch/ppc/kernel/irq.c22
-rw-r--r--arch/ppc/kernel/m8260_setup.c2
-rw-r--r--arch/ppc/kernel/m8xx_setup.c2
-rw-r--r--arch/ppc/kernel/misc.S13
-rw-r--r--arch/ppc/kernel/oak_setup.c2
-rw-r--r--arch/ppc/kernel/open_pic.c7
-rw-r--r--arch/ppc/kernel/pci.c147
-rw-r--r--arch/ppc/kernel/pmac_backlight.c148
-rw-r--r--arch/ppc/kernel/pmac_nvram.c39
-rw-r--r--arch/ppc/kernel/pmac_pci.c107
-rw-r--r--arch/ppc/kernel/pmac_pic.c34
-rw-r--r--arch/ppc/kernel/pmac_setup.c64
-rw-r--r--arch/ppc/kernel/pmac_time.c56
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c19
-rw-r--r--arch/ppc/kernel/prep_setup.c2
-rw-r--r--arch/ppc/kernel/prep_time.c2
-rw-r--r--arch/ppc/kernel/prom.c87
-rw-r--r--arch/ppc/kernel/setup.c26
-rw-r--r--arch/ppc/kernel/signal.c211
-rw-r--r--arch/ppc/kernel/smp.c2
-rw-r--r--arch/ppc/kernel/syscalls.c10
-rw-r--r--arch/ppc/kernel/time.c12
-rw-r--r--arch/ppc/kernel/time.h42
-rw-r--r--arch/ppc/kernel/walnut_setup.c2
-rw-r--r--arch/ppc/mbxboot/m8xx_tty.c45
-rw-r--r--arch/ppc/mbxboot/misc.c4
-rw-r--r--arch/ppc/mm/init.c8
-rw-r--r--arch/ppc/xmon/xmon.c8
44 files changed, 1691 insertions, 716 deletions
diff --git a/arch/ppc/8xx_io/Config.in b/arch/ppc/8xx_io/Config.in
index 412b50338..090c09cb4 100644
--- a/arch/ppc/8xx_io/Config.in
+++ b/arch/ppc/8xx_io/Config.in
@@ -13,8 +13,16 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
fi
bool '860T FEC Ethernet' CONFIG_FEC_ENET
- bool 'Use SMC2 for UART' CONFIG_8xxSMC2
- bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC
+ bool 'Use Big CPM Ethernet Buffers' CONFIG_ENET_BIG_BUFFERS
+fi
+bool 'Use SMC2 for UART' CONFIG_8xxSMC2
+if [ "$CONFIG_8xxSMC2" = "y" ]; then
+ bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_8xx_ALTSMC2
+fi
+bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC
+
+if [ "$CONFIG_TQM860" = "y" -o "$CONFIG_TQM860L" = "y" -o "$CONFIG_TQM8xxL" = "y" ]; then
+ bool 'Use SMC2 for Console' TQM_SMC2_CONSOLE
fi
# This doesn't really belong here, but it is convenient to ask
diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h
index 7e7e9896d..7faae4ca3 100644
--- a/arch/ppc/8xx_io/commproc.h
+++ b/arch/ppc/8xx_io/commproc.h
@@ -191,7 +191,9 @@ typedef struct smc_centronics {
/* SMC Event and Mask register.
*/
-#define SMCM_TXE ((unsigned char)0x10)
+#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */
+#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */
+#define SMCM_TXE ((unsigned char)0x10) /* When in Transparent Mode */
#define SMCM_BSY ((unsigned char)0x04)
#define SMCM_TX ((unsigned char)0x02)
#define SMCM_RX ((unsigned char)0x01)
@@ -457,6 +459,81 @@ typedef struct scc_enet {
#define SICR_ENET_CLKRT ((uint)0x0000003d)
#endif
+#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L))
+/*
+ * TQM860 and TQM860L Configuration:
+ *
+ * Signal PAR DIR ODR DAT Function
+ * Port A, 5 1 0 - - TCLK (CLK3) for Ethernet
+ * Port A, 7 1 0 - - RCLK (CLK1) for Ethernet
+ * Port A, 14 1 0 - - TXD for Ethernet (SCC1)
+ * Port A, 15 1 0 - - RXD for Ethernet (SCC1)
+ * Port C, 7 0 0 0 - -> ETH-LOOP
+ * Port C, 10 0 0 1 - CD for Ethernet (SCC1)
+ * Port C, 11 0 0 1 - CTS for Ethernet (SCC1)
+ * Port C, 15 * * 0 - TENA/RTS for Ethernet
+ */
+
+#define PA_ENET_RXD ((ushort)0x0001) /* PA 15 */
+#define PA_ENET_TXD ((ushort)0x0002) /* PA 14 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+
+#define PC_ENET_TENA ((ushort)0x0001) /* PC 15 */
+#define PC_ENET_CLSN ((ushort)0x0010) /* PC 11 */
+#define PC_ENET_RENA ((ushort)0x0020) /* PC 10 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x00000026)
+
+#endif /* CONFIG_TQM860, TQM860L */
+
+#ifdef CONFIG_TQM8xxL
+/*
+ * TQM8xxL Configuration (except TQM860L):
+ *
+ * Signal PAR DIR ODR DAT Function
+ * Port A, 5 1 0 - - TCLK (CLK3) for Ethernet
+ * Port A, 7 1 0 - - RCLK (CLK1) for Ethernet
+ * Port A, 12 1 0 - - TXD for Ethernet (SCC2)
+ * Port A, 13 1 0 - - RXD for Ethernet (SCC2)
+ * Port B, 18 1 1 - - TENA/RTS for Ethernet on STK8xx
+ * Port C, 7 0 0 0 - -> ETH-LOOP
+ * Port C, 8 0 0 1 - CD for Ethernet (SCC2)
+ * Port C, 9 0 0 1 - CTS for Ethernet (SCC2)
+ * Port C, 14 * * 0 - TENA/RTS for Ethernet on FPS850
+ *
+ * Note: Using PC14 as RTS2 (TENA) does not work on the TQM850L when
+ * used with the starter-kit mainboard; we *must* use PB18 instead.
+ * For the FPS850 system, we *must* use PC14 :-(
+ */
+
+#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */
+#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#ifndef CONFIG_FPS850 /* not valid on FPS board */
+#define PB_ENET_TENA ((uint)0x00002000)
+#endif /* !CONFIG_FPS850 */
+
+#ifdef CONFIG_FPS850 /* FPS uses default configuration */
+#define PC_ENET_TENA ((ushort)0x0002) /* PC 14 */
+#endif /* CONFIG_FPS850 */
+#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */
+#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00002600)
+
+#endif /* CONFIG_TQM8xxL */
+
/* SCC Event register as used by Ethernet.
*/
#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 4d95bc9eb..730453bbb 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -73,40 +73,14 @@
* finished otherwise it sets the 'lp->tx_full' flag.
*
* The MBX has a control register external to the MPC8xx that has some
- * control of the Ethernet interface. Control Register 1 has the
- * following format:
- * bit 0 - Set to enable Ethernet transceiver
- * bit 1 - Set to enable Ethernet internal loopback
- * bit 2 - Set to auto select AUI or TP port
- * bit 3 - if bit 2 is 0, set to select TP port
- * bit 4 - Set to disable full duplex (loopback)
- * bit 5 - Set to disable XCVR collision test
- * bit 6, 7 - Used for RS-232 control.
+ * control of the Ethernet interface. Information is in the manual for
+ * your board.
*
- * EPPC-Bug sets this register to 0x98 for normal Ethernet operation,
- * so we should not have to touch it.
+ * The RPX boards have an external control/status register. Consult the
+ * programming documents for details unique to your board.
*
- * The following I/O is used by the MBX implementation of the MPC8xx to
- * the MC68160 transceiver. It DOES NOT exactly follow the cookbook
- * example from the MPC860 manual.
- * Port A, 15 - SCC1 Ethernet Rx
- * Port A, 14 - SCC1 Ethernet Tx
- * Port A, 6 (CLK2) - SCC1 Ethernet Tx Clk
- * Port A, 4 (CLK4) - SCC1 Ethernet Rx Clk
- * Port C, 15 - SCC1 Ethernet Tx Enable
- * Port C, 11 - SCC1 Ethernet Collision
- * Port C, 10 - SCC1 Ethernet Rx Enable
- *
- * The RPX-Lite (that I had :-), was the MPC850SAR. It has a control
- * register to enable Ethernet functions in the 68160, and the Ethernet
- * was controlled by SCC2. So, the pin I/O was like this:
- * Port A, 13 - SCC2 Ethernet Rx
- * Port A, 12 - SCC2 Ethernet Tx
- * Port A, 6 (CLK2) - Ethernet Tx Clk
- * Port A, 4 (CLK4) - Ethernet Rx Clk
- * Port B, 18 (RTS2) - Ethernet Tx Enable
- * Port C, 8 (CD2) - Ethernet Rx Enable
- * Port C, 9 (CTS2) - SCC Ethernet Collision
+ * For the TQM8xx(L) modules, there is no control register interface.
+ * All functions are directly controlled using I/O pins. See commproc.h.
*/
/* The transmitter timeout
@@ -119,12 +93,21 @@
* We don't need to allocate pages for the transmitter. We just use
* the skbuffer directly.
*/
+#ifdef CONFIG_ENET_BIG_BUFFERS
+#define CPM_ENET_RX_PAGES 32
+#define CPM_ENET_RX_FRSIZE 2048
+#define CPM_ENET_RX_FRPPG (PAGE_SIZE / CPM_ENET_RX_FRSIZE)
+#define RX_RING_SIZE (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES)
+#define TX_RING_SIZE 64 /* Must be power of two */
+#define TX_RING_MOD_MASK 63 /* for this to work */
+#else
#define CPM_ENET_RX_PAGES 4
#define CPM_ENET_RX_FRSIZE 2048
#define CPM_ENET_RX_FRPPG (PAGE_SIZE / CPM_ENET_RX_FRSIZE)
#define RX_RING_SIZE (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES)
#define TX_RING_SIZE 8 /* Must be power of two */
#define TX_RING_MOD_MASK 7 /* for this to work */
+#endif
/* The CPM stores dest/src/type, data, and checksum for receive packets.
*/
@@ -896,11 +879,16 @@ int __init scc_enet_init(void)
/* It is now OK to enable the Ethernet transmitter.
* Unfortunately, there are board implementation differences here.
*/
-#ifdef CONFIG_MBX
+#if (defined(CONFIG_MBX) || defined(CONFIG_TQM860) || defined(CONFIG_TQM860L) || defined(CONFIG_FPS850))
immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
#endif
+#if (defined(CONFIG_TQM8xxL) && !defined(CONFIG_FPS850))
+ cp->cp_pbpar |= PB_ENET_TENA;
+ cp->cp_pbdir |= PB_ENET_TENA;
+#endif
+
#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
cp->cp_pbpar |= PB_ENET_TENA;
cp->cp_pbdir |= PB_ENET_TENA;
@@ -928,6 +916,7 @@ int __init scc_enet_init(void)
immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK;
#endif
+
dev->base_addr = (unsigned long)ep;
dev->priv = cep;
#if 0
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
index 00f4fa86c..b9f791832 100644
--- a/arch/ppc/8xx_io/uart.c
+++ b/arch/ppc/8xx_io/uart.c
@@ -41,8 +41,10 @@
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>
#include "commproc.h"
-
+
#ifdef CONFIG_KGDB
+extern void breakpoint(void);
+extern void set_debug_traps(void);
extern int kgdb_output_string (const char* s, unsigned int count);
#endif
@@ -56,10 +58,17 @@ extern int kgdb_output_string (const char* s, unsigned int count);
#endif
#endif
+#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.02";
+static char *serial_version = "0.03";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -89,54 +98,33 @@ static int serial_console_setup(struct console *co, char *options);
* needs. For example, the port address is the CPM parameter ram
* offset for the SCC or SMC. The maximum number of ports is 4 SCCs and
* 2 SMCs. The "hub6" field is used to indicate the channel number, with
- * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs.
- * Since these ports are so versatile, I don't yet have a strategy for
- * their management. For example, SCC1 is used for Ethernet. Right
- * now, just don't put them in the table. Of course, right now I just
- * want the SMC to work as a uart :-)..
+ * 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 CMS or SCC.
+ * type of SMC or SCC.
* The SMCs do not support any modem control signals.
*/
#define smc_scc_num hub6
-
-#ifdef CONFIG_8xxSMC2
-/* SMC2 is sometimes used for low performance TDM interfaces. Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-#else
-#define USE_SMC2 0
-#endif
-
-/* Define SCC to ttySx mapping.
-*/
-#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port. These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE 1 /* table index */
+#define NUM_IS_SCC ((int)0x00010000)
+#define PORT_NUM(P) ((P) & 0x0000ffff)
/* 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 */
{ 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */
-#if USE_SMC2
+#ifdef CONFIG_8xxSMC2
{ 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */
#endif
#ifdef CONFIG_8xxSCC
- { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, SCC_NUM_BASE}, /* SCC2 ttyS2 */
- { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, SCC_NUM_BASE + 1}, /* SCC3 ttyS3 */
+ { 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
};
@@ -245,13 +233,14 @@ static void rs_8xx_stop(struct tty_struct *tty)
return;
save_flags(flags); cli();
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
- smcp = &cpmp->cp_smc[idx];
- smcp->smc_smcm &= ~SMCM_TX;
+ 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 {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- sccp->scc_sccm &= ~UART_SCCM_TX;
+ smcp = &cpmp->cp_smc[idx];
+ smcp->smc_smcm &= ~SMCM_TX;
}
restore_flags(flags);
}
@@ -267,14 +256,15 @@ static void rs_8xx_start(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_stop"))
return;
+ idx = PORT_NUM(info->state->smc_scc_num);
save_flags(flags); cli();
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
- smcp = &cpmp->cp_smc[idx];
- smcp->smc_smcm |= SMCM_TX;
+ if (info->state->smc_scc_num & NUM_IS_SCC) {
+ sccp = &cpmp->cp_scc[idx];
+ sccp->scc_sccm |= UART_SCCM_TX;
}
else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- sccp->scc_sccm |= UART_SCCM_TX;
+ smcp = &cpmp->cp_smc[idx];
+ smcp->smc_smcm |= SMCM_TX;
}
restore_flags(flags);
}
@@ -372,7 +362,7 @@ static _INLINE_ void receive_chars(ser_info_t *info)
icount->rx++;
#ifdef SERIAL_DEBUG_INTR
- printk("DR%02x:%02x...", ch, *status);
+ printk("DR%02x:%02x...", ch, status);
#endif
*tty->flip.flag_buf_ptr = 0;
if (status & (BD_SC_BR | BD_SC_FR |
@@ -452,10 +442,28 @@ static _INLINE_ void receive_chars(ser_info_t *info)
queue_task(&tty->flip.tqueue, &tq_timer);
}
+static _INLINE_ void receive_break(ser_info_t *info)
+{
+ struct tty_struct *tty = info->tty;
+
+ info->state->icount.brk++;
+ /* 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)
{
- if (info->flags & TX_WAKEUP) {
+ if ((info->flags & TX_WAKEUP) ||
+ (info->tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
}
@@ -549,24 +557,27 @@ static void rs_8xx_interrupt(void *dev_id)
info = (ser_info_t *)dev_id;
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ 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 & SCCM_RX)
+ receive_chars(info);
+ if (events & SCCM_TX)
+ transmit_chars(info);
+ sccp->scc_scce = events;
+ }
+ else {
smcp = &cpmp->cp_smc[idx];
events = smcp->smc_smce;
+ if (events & SMCM_BRKE)
+ receive_break(info);
if (events & SMCM_RX)
receive_chars(info);
if (events & SMCM_TX)
transmit_chars(info);
smcp->smc_smce = events;
}
- else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- events = sccp->scc_scce;
- if (events & SCCM_RX)
- receive_chars(info);
- if (events & SCCM_TX)
- transmit_chars(info);
- sccp->scc_scce = events;
- }
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d, %x)...",
@@ -691,7 +702,16 @@ static int startup(ser_info_t *info)
*/
change_speed(info);
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ 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.
@@ -708,22 +728,10 @@ static int startup(ser_info_t *info)
* 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 */
}
- else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- 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);
- }
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
@@ -758,7 +766,19 @@ static void shutdown(ser_info_t * info)
save_flags(flags); cli(); /* Disable interrupts */
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ 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.
@@ -768,15 +788,10 @@ static void shutdown(ser_info_t * info)
/* We can't disable the transmitter if this is the
* system console.
*/
- if (idx != CONFIG_SERIAL_CONSOLE_PORT)
+ if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
#endif
smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
}
- else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- }
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -795,6 +810,7 @@ static void change_speed(ser_info_t *info)
unsigned cflag, cval, scval, prev_mode;
int i, bits, sbits, idx;
unsigned long flags;
+ struct serial_state *state;
volatile smc_t *smcp;
volatile scc_t *sccp;
@@ -802,6 +818,8 @@ static void change_speed(ser_info_t *info)
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.
@@ -903,7 +921,12 @@ static void change_speed(ser_info_t *info)
* stops bits (there is always at least one).
*/
bits++;
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ idx = PORT_NUM(state->smc_scc_num);
+ if (state->smc_scc_num & NUM_IS_SCC) {
+ sccp = &cpmp->cp_scc[idx];
+ sccp->scc_pmsr = (sbits << 12) | scval;
+ }
+ else {
smcp = &cpmp->cp_smc[idx];
/* Set the mode register. We want to keep a copy of the
@@ -914,12 +937,8 @@ static void change_speed(ser_info_t *info)
smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
}
- else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- sccp->scc_pmsr = (sbits << 12) | scval;
- }
- m8xx_cpm_setbrg(info->state->smc_scc_num, baud_rate);
+ m8xx_cpm_setbrg((state - rs_table), baud_rate);
restore_flags(flags);
}
@@ -961,9 +980,9 @@ static int rs_8xx_write(struct tty_struct * tty, int from_user,
volatile cbd_t *bdp;
#ifdef CONFIG_KGDB
- /* Try to let stub handle output. Returns true if it did. */
- if (kgdb_output_string(buf, count))
- return ret;
+ /* 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->device, "rs_write"))
@@ -986,8 +1005,7 @@ static int rs_8xx_write(struct tty_struct * tty, int from_user,
}
if (from_user) {
- c -= copy_from_user(__va(bdp->cbd_bufaddr), buf, c);
- if (!c) {
+ if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
if (!ret)
ret = -EFAULT;
break;
@@ -1271,30 +1289,31 @@ static int set_modem_info(ser_info_t *info, unsigned int cmd,
* 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;
- ushort num;
+ int idx;
cp = cpmp;
- if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
- if (num == 0)
- chan = CPM_CR_CH_SMC1;
- else
- chan = CPM_CR_CH_SMC2;
- }
- else {
- num -= SCC_NUM_BASE;
- switch (num) {
- case 0: chan = CPM_CR_CH_SCC1; break;
- case 1: chan = CPM_CR_CH_SCC2; break;
- case 2: chan = CPM_CR_CH_SCC3; break;
- case 3: chan = CPM_CR_CH_SCC4; break;
- default: return;
- }
- }
+ 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);
}
@@ -1303,26 +1322,15 @@ static void end_break(ser_info_t *info)
{
volatile cpm8xx_t *cp;
ushort chan;
- ushort num;
+ int idx;
cp = cpmp;
- if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
- if (num == 0)
- chan = CPM_CR_CH_SMC1;
- else
- chan = CPM_CR_CH_SMC2;
- }
- else {
- num -= SCC_NUM_BASE;
- switch (num) {
- case 0: chan = CPM_CR_CH_SCC1; break;
- case 1: chan = CPM_CR_CH_SCC2; break;
- case 2: chan = CPM_CR_CH_SCC3; break;
- case 3: chan = CPM_CR_CH_SCC4; break;
- default: return;
- }
- }
+ 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);
}
@@ -1623,16 +1631,17 @@ static void rs_8xx_close(struct tty_struct *tty, struct file * filp)
*/
info->read_status_mask &= ~BD_SC_EMPTY;
if (info->flags & ASYNC_INITIALIZED) {
- if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ 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;
}
- else {
- sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE];
- sccp->scc_sccm &= ~UART_SCCM_RX;
- sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
- }
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@@ -1713,7 +1722,18 @@ static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
break;
if (timeout && ((orig_jiffies + timeout) < jiffies))
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
@@ -1803,7 +1823,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR)) ||
- (info->state->smc_scc_num < SCC_NUM_BASE)) {
+ !(info->state->smc_scc_num & NUM_IS_SCC)) {
if (info->flags & ASYNC_CALLOUT_ACTIVE)
return -EBUSY;
info->flags |= ASYNC_NORMAL_ACTIVE;
@@ -1981,8 +2001,8 @@ static int inline line_info(char *buf, struct serial_state *state)
ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
state->line,
- (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
- state->port, state->irq);
+ (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");
@@ -2070,7 +2090,7 @@ int rs_8xx_read_proc(char *page, char **start, off_t off, int count,
done:
if (off >= len+begin)
return 0;
- *start = page + (off-begin);
+ *start = page + (begin-off);
return ((count < begin+len-off) ? count : begin+len-off);
}
@@ -2229,7 +2249,7 @@ putDebugChar(char ch)
/*
* Receive character from the serial port. This only works well
- * before the port is initialize for real use.
+ * before the port is initialized for real use.
*/
static int my_console_wait_key(int idx, int xmon, char *obuf)
{
@@ -2350,7 +2370,7 @@ void kgdb_map_scc(void)
/* 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 allcoated.
+ * 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.
*/
@@ -2382,7 +2402,7 @@ void kgdb_map_scc(void)
static kdev_t serial_console_device(struct console *c)
{
- return MKDEV(TTYAUX_MAJOR, 64 + c->index);
+ return MKDEV(TTY_MAJOR, 64 + c->index);
}
@@ -2411,12 +2431,9 @@ long __init console_8xx_init(long kmem_start, long kmem_end)
#endif
-/* This will be used for all boards when the MBX board information
- * is modified to include a default baud rate.
- */
-#ifndef CONFIG_MBX
+/* Index in baud rate table of the default console baud rate.
+*/
static int baud_idx;
-#endif
/*
* The serial driver boot-time initialization code!
@@ -2425,7 +2442,7 @@ int __init rs_8xx_init(void)
{
struct serial_state * state;
ser_info_t *info;
- uint mem_addr, dp_addr;
+ uint mem_addr, dp_addr, iobits;
int i, j, idx;
ushort chan;
volatile cbd_t *bdp;
@@ -2442,7 +2459,6 @@ int __init rs_8xx_init(void)
/* Initialize the tty_driver structure */
- /*memset(&serial_driver, 0, sizeof(struct tty_driver));*/
__clear_user(&serial_driver,sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
serial_driver.driver_name = "serial";
@@ -2454,11 +2470,7 @@ int __init rs_8xx_init(void)
serial_driver.subtype = SERIAL_TYPE_NORMAL;
serial_driver.init_termios = tty_std_termios;
serial_driver.init_termios.c_cflag =
-#ifndef CONFIG_MBX
baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
-#else
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-#endif
serial_driver.flags = TTY_DRIVER_REAL_RAW;
serial_driver.refcount = &serial_refcount;
serial_driver.table = serial_table;
@@ -2502,29 +2514,16 @@ int __init rs_8xx_init(void)
cp = cpmp; /* Get pointer to Communication Processor */
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
- /* Configure SMCs Tx/Rx instead of port B parallel I/O.
- */
-#if USE_SMC2
- cp->cp_pbpar |= 0x00000cc0;
- cp->cp_pbdir &= ~0x00000cc0;
- cp->cp_pbodr &= ~0x00000cc0;
-#else
- /* This will only enable SMC1 if you want SMC2 for something else.
- */
- cp->cp_pbpar |= 0x000000c0;
- cp->cp_pbdir &= ~0x000000c0;
- cp->cp_pbodr &= ~0x000000c0;
-#endif
- /* Configure SCC2 and SCC3 instead of port A parallel I/O.
+ /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
*/
-#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T)
+#ifdef CONFIG_8xxSCC
#ifndef CONFIG_MBX
/* The "standard" configuration through the 860.
*/
- immap->im_ioport.iop_papar |= 0x003c;
- immap->im_ioport.iop_padir &= ~0x003c;
- immap->im_ioport.iop_paodr &= ~0x003c;
+ 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.
*/
@@ -2547,11 +2546,21 @@ int __init rs_8xx_init(void)
*/
cp->cp_sicr &= ~0x00ffff00;
cp->cp_sicr |= 0x001b1200;
-#endif
- /* Wire BRG1 to SMC1 and BRG2 to SMC2.
+#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_simode = 0x10000000;
+ 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;
@@ -2568,8 +2577,8 @@ int __init rs_8xx_init(void)
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
- i, state->port,
- (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");
+ 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
@@ -2581,7 +2590,6 @@ int __init rs_8xx_init(void)
#endif
info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
if (info) {
- /*memset(info, 0, sizeof(ser_info_t));*/
__clear_user(info,sizeof(ser_info_t));
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
@@ -2621,16 +2629,17 @@ int __init rs_8xx_init(void)
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
- if ((idx = state->smc_scc_num) < SCC_NUM_BASE) {
+ 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_addr;
+ }
+ else {
sp = &cp->cp_smc[idx];
up = (smc_uart_t *)&cp->cp_dparam[state->port];
up->smc_rbase = dp_addr;
}
- else {
- scp = &cp->cp_scc[idx - SCC_IDX_BASE];
- sup = (scc_uart_t *)&cp->cp_dparam[state->port];
- sup->scc_genscc.scc_rbase = dp_addr;
- }
dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO);
@@ -2654,56 +2663,21 @@ int __init rs_8xx_init(void)
bdp->cbd_bufaddr = __pa(mem_addr);
bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
- if (idx < SCC_NUM_BASE) {
- up->smc_tbase = dp_addr;
+ if (info->state->smc_scc_num & NUM_IS_SCC) {
+ sup->scc_genscc.scc_tbase = dp_addr;
/* Set up the uart parameters in the
* parameter ram.
*/
- up->smc_rfcr = SMC_EB;
- up->smc_tfcr = SMC_EB;
+ 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.
*/
- up->smc_mrblr = RX_BUF_SIZE;
- up->smc_maxidl = RX_BUF_SIZE;
- up->smc_brkcr = 1;
-
- /* Send the CPM an initialize command.
- */
- if (state->smc_scc_num == 0)
- chan = CPM_CR_CH_SMC1;
- else
- chan = CPM_CR_CH_SMC2;
-
- 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;
- }
- else {
- sup->scc_genscc.scc_tbase = dp_addr;
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- sup->scc_genscc.scc_rfcr = SMC_EB;
- sup->scc_genscc.scc_tfcr = SMC_EB;
-
- sup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
- sup->scc_maxidl = RX_BUF_SIZE;
+ sup->scc_genscc.scc_mrblr = 1;
+ sup->scc_maxidl = 0;
sup->scc_brkcr = 1;
sup->scc_parec = 0;
sup->scc_frmec = 0;
@@ -2724,10 +2698,7 @@ int __init rs_8xx_init(void)
/* Send the CPM an initialize command.
*/
- if (state->smc_scc_num == 2)
- chan = CPM_CR_CH_SCC2;
- else
- chan = CPM_CR_CH_SCC3;
+ chan = scc_chan_map[idx];
cp->cp_cpcr = mk_cr_cmd(chan,
CPM_CR_INIT_TRX) | CPM_CR_FLG;
@@ -2747,6 +2718,91 @@ int __init rs_8xx_init(void)
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_8xx_ALTSMC2
+ iobits = 0xc0 << (idx * 4);
+ cp->cp_pbpar |= iobits;
+ cp->cp_pbdir &= ~iobits;
+ cp->cp_pbodr &= ~iobits;
+#else
+ if (idx == 0) {
+ /* SMC1 on Port B, like all 8xx.
+ */
+ iobits = 0xc0;
+ cp->cp_pbpar |= iobits;
+ cp->cp_pbdir &= ~iobits;
+ cp->cp_pbodr &= ~iobits;
+ }
+ else {
+ /* SMC2 is on Port A.
+ */
+ iobits = 0x300;
+ immap->im_ioport.iop_papar |= iobits;
+ immap->im_ioport.iop_padir &= ~iobits;
+ immap->im_ioport.iop_paodr &= ~iobits;
+ }
+#endif
+
+ /* 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_addr;
+
+ /* 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.
@@ -2755,19 +2811,8 @@ int __init rs_8xx_init(void)
/* Set up the baud rate generator.
*/
-#ifndef CONFIG_MBX
- m8xx_cpm_setbrg(state->smc_scc_num,
- baud_table[baud_idx]);
-#else
- m8xx_cpm_setbrg(state->smc_scc_num, 9600);
-#endif
+ m8xx_cpm_setbrg(i, baud_table[baud_idx]);
- /* 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
}
}
@@ -2780,13 +2825,14 @@ int __init rs_8xx_init(void)
static int __init serial_console_setup(struct console *co, char *options)
{
struct serial_state *ser;
- uint mem_addr, dp_addr, bidx;
+ uint mem_addr, dp_addr, bidx, idx;
+ ushort chan;
volatile cbd_t *bdp;
volatile cpm8xx_t *cp;
volatile smc_t *sp;
+ volatile scc_t *scp;
volatile smc_uart_t *up;
-
-#ifndef CONFIG_MBX
+ volatile scc_uart_t *sup;
bd_t *bd;
bd = (bd_t *)__res;
@@ -2797,40 +2843,41 @@ static int __init serial_console_setup(struct console *co, char *options)
co->cflag = CREAD|CLOCAL|bidx|CS8;
baud_idx = bidx;
-#else
- co->cflag = CREAD|CLOCAL|B9600|CS8;
-#endif
ser = rs_table + co->index;
cp = cpmp; /* Get pointer to Communication Processor */
- /* Right now, assume we are using SMCs.
- */
- sp = &cp->cp_smc[ser->smc_scc_num];
+ 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.
*/
- up = (smc_uart_t *)&cp->cp_dparam[ser->port];
- cp->cp_pbpar = 0x00c0; /* Enable SMC1 instead of Port B I/O */
/* Allocate space for two buffer descriptors in the DP ram.
*/
dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 2);
- /* Allocate space for an input FIFO, plus a few bytes for output.
- * Allocate bytes to maintain word alignment.
- */
- mem_addr = m8xx_cpm_hostalloc(RX_BUF_SIZE + 4);
+ /* Allocate space for two 2 byte FIFOs in the host memory.
+ */
+ mem_addr = m8xx_cpm_hostalloc(8);
/* Set the physical address of the host memory buffers in
* the buffer descriptors.
*/
bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
bdp->cbd_bufaddr = __pa(mem_addr);
- (bdp+1)->cbd_bufaddr = __pa(mem_addr+RX_BUF_SIZE);
+ (bdp+1)->cbd_bufaddr = __pa(mem_addr+4);
/* For the receive, set empty and wrap.
* For transmit, set wrap.
@@ -2840,39 +2887,98 @@ static int __init serial_console_setup(struct console *co, char *options)
/* Set up the uart parameters in the parameter ram.
*/
- up->smc_rbase = dp_addr; /* Base of receive buffer desc. */
- up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */
- up->smc_rfcr = SMC_EB;
- up->smc_tfcr = SMC_EB;
+ if (ser->smc_scc_num & NUM_IS_SCC) {
- up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */
- up->smc_maxidl = RX_BUF_SIZE;
+ sup->scc_genscc.scc_rbase = dp_addr;
+ sup->scc_genscc.scc_tbase = dp_addr + sizeof(cbd_t);
- /* Send the CPM an initialize command.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- /*
- * delay for a bit - this is necessary on my board!
- * -- Cort
- */
- printk("");
- while (cp->cp_cpcr & CPM_CR_FLG);
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+ /* Set up the uart parameters in the
+ * parameter ram.
+ */
+ sup->scc_genscc.scc_rfcr = SMC_EB;
+ sup->scc_genscc.scc_tfcr = SMC_EB;
- /* Set up the baud rate generator.
- */
-#ifndef CONFIG_MBX
- m8xx_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate);
-#else
- m8xx_cpm_setbrg(ser->smc_scc_num, 9600);
-#endif
+ /* 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_addr; /* Base of receive buffer desc. */
+ up->smc_tbase = dp_addr+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 */
- /* And finally, enable Rx and Tx.
+ /* 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("");
+ 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.
*/
- sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+ m8xx_cpm_setbrg((ser - rs_table), bd->bi_baudrate);
return 0;
}
+
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
index c8541965d..23afda4a8 100644
--- a/arch/ppc/coffboot/Makefile
+++ b/arch/ppc/coffboot/Makefile
@@ -42,7 +42,7 @@ znetboot: vmlinux.coff vmlinux.elf zImage
cp vmlinux.coff $(TFTPIMAGE)
cp vmlinux.elf $(TFTPIMAGE).elf
-znetboot.initrd: vmlinux.coff.initrd
+znetboot.initrd: vmlinux.coff.initrd vmlinux.elf.initrd
cp vmlinux.coff.initrd $(TFTPIMAGE)
cp vmlinux.elf.initrd $(TFTPIMAGE).elf
@@ -81,7 +81,7 @@ vmlinux.coff: coffboot hack-coff
ln -sf vmlinux.coff zImage
vmlinux.coff.initrd: coffboot.initrd hack-coff
- $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd $@
./hack-coff $@
vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 33f6eaa95..3e0721cb4 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -12,17 +12,28 @@ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
+ bool ' Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
comment 'Platform support'
define_bool CONFIG_PPC y
choice 'Processor Type' \
"6xx/7xx/7400 CONFIG_6xx \
4xx CONFIG_4xx \
- POWER3/POWER4(64-Bit) CONFIG_PPC64BRIDGE \
+ POWER3 CONFIG_POWER3 \
+ POWER4 CONFIG_POWER4 \
8260 CONFIG_8260 \
8xx CONFIG_8xx" 6xx
-if [ "$CONFIG_PPC64BRIDGE" = "y" ]; then
- bool 'Power 4 support' CONFIG_POWER4
+if [ "$CONFIG_POWER3" = "y" -o "$CONFIG_POWER4" = "y" ]; then
+ define_bool CONFIG_PPC64BRIDGE y
+ define_bool CONFIG_ALL_PPC y
fi
if [ "$CONFIG_8260" = "y" ]; then
@@ -43,6 +54,9 @@ if [ "$CONFIG_8xx" = "y" ]; then
"RPX-Lite CONFIG_RPXLITE \
RPX-Classic CONFIG_RPXCLASSIC \
BSE-IP CONFIG_BSEIP \
+ TQM8xxL CONFIG_TQM8xxL \
+ TQM860L CONFIG_TQM860L \
+ TQM860 CONFIG_TQM860 \
MBX CONFIG_MBX \
WinCept CONFIG_WINCEPT" RPX-Lite
fi
@@ -54,14 +68,14 @@ if [ "$CONFIG_6xx" = "y" ]; then
APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP
fi
-if [ "$CONFIG_PPC64BRIDGE" = "y" ]; then
- define_bool CONFIG_ALL_PPC y
-fi
-
if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then
define_bool CONFIG_ALL_PPC n
fi
+if [ "$CONFIG_TQM8xxL" = "y" ]; then
+ bool 'FPS850 Mainboard' CONFIG_FPS850
+fi
+
bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_6xx" = "y" ];then
bool 'AltiVec Support' CONFIG_ALTIVEC
@@ -77,15 +91,6 @@ fi
endmenu
mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
- bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
- bool ' Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
comment 'General setup'
define_bool CONFIG_ISA n
@@ -149,6 +154,7 @@ if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD
bool 'Support for ADB mouse' CONFIG_ADBMOUSE
fi
+ tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 501ed931a..0369ad800 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -99,7 +99,8 @@ endif
ifeq ($(CONFIG_ALL_PPC),y)
O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \
chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \
- prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o
+ prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o \
+ pmac_backlight.o
OX_OBJS += prep_setup.o
endif
ifeq ($(CONFIG_GEMINI),y)
diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
index fb5a19e3a..69e07057a 100644
--- a/arch/ppc/kernel/bitops.c
+++ b/arch/ppc/kernel/bitops.c
@@ -6,60 +6,58 @@
#include <asm/bitops.h>
/*
- * I left these here since the problems with "cc" make it difficult to keep
- * them in bitops.h -- Cort
+ * If the bitops are not inlined in bitops.h, they are defined here.
+ * -- paulus
*/
-void set_bit(int nr, volatile void *addr)
+#if !__INLINE_BITOPS
+void set_bit(int nr, volatile void * addr)
{
- unsigned int t;
- unsigned int mask = 1 << (nr & 0x1f);
- volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
-
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%2
- or %0,%0,%1
- stwcx. %0,0,%2
+ unsigned long old;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%3
+ or %0,%0,%2
+ stwcx. %0,0,%3
bne 1b"
- : "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
- : "cc");
+ SMP_MB
+ : "=&r" (old), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
+ : "cc" );
}
void clear_bit(int nr, volatile void *addr)
{
- unsigned int t;
- unsigned int mask = 1 << (nr & 0x1f);
- volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+ unsigned long old;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%2
- andc %0,%0,%1
- stwcx. %0,0,%2
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%3
+ andc %0,%0,%2
+ stwcx. %0,0,%3
bne 1b"
- : "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
+ SMP_MB
+ : "=&r" (old), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
: "cc");
}
void change_bit(int nr, volatile void *addr)
{
- unsigned int t;
- unsigned int mask = 1 << (nr & 0x1f);
- volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+ unsigned long old;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%2
- xor %0,%0,%1
- stwcx. %0,0,%2
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%3
+ xor %0,%0,%2
+ stwcx. %0,0,%3
bne 1b"
- : "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
+ SMP_MB
+ : "=&r" (old), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
: "cc");
}
@@ -69,15 +67,14 @@ int test_and_set_bit(int nr, volatile void *addr)
unsigned int mask = 1 << (nr & 0x1f);
volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%3
- or %1,%0,%2
- stwcx. %1,0,%3
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%4
+ or %1,%0,%3
+ stwcx. %1,0,%4
bne 1b"
- : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
+ SMP_MB
+ : "=&r" (old), "=&r" (t), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
: "cc");
return (old & mask) != 0;
@@ -89,15 +86,14 @@ int test_and_clear_bit(int nr, volatile void *addr)
unsigned int mask = 1 << (nr & 0x1f);
volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%3
- andc %1,%0,%2
- stwcx. %1,0,%3
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%4
+ andc %1,%0,%3
+ stwcx. %1,0,%4
bne 1b"
- : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
+ SMP_MB
+ : "=&r" (old), "=&r" (t), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
: "cc");
return (old & mask) != 0;
@@ -109,93 +105,16 @@ int test_and_change_bit(int nr, volatile void *addr)
unsigned int mask = 1 << (nr & 0x1f);
volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
- if ((unsigned long)addr & 3)
- printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%3
- xor %1,%0,%2
- stwcx. %1,0,%3
+ __asm__ __volatile__(SMP_WMB "\
+1: lwarx %0,0,%4
+ xor %1,%0,%3
+ stwcx. %1,0,%4
bne 1b"
- : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
- : "r" (mask), "r" (p)
+ SMP_MB
+ : "=&r" (old), "=&r" (t), "=m" (*p)
+ : "r" (mask), "r" (p), "m" (*p)
: "cc");
return (old & mask) != 0;
}
-
-/* I put it in bitops.h -- Cort */
-#if 0
-int ffz(unsigned int x)
-{
- int n;
-
- x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
- __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
- return 31 - n;
-}
-
-/*
- * This implementation of find_{first,next}_zero_bit was stolen from
- * Linus' asm-alpha/bitops.h.
- */
-
-int find_first_zero_bit(void * addr, int size)
-{
- unsigned int * p = ((unsigned int *) addr);
- unsigned int result = 0;
- unsigned int tmp;
-
- if (size == 0)
- return 0;
- while (size & ~31UL) {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = *p;
- tmp |= ~0UL << size;
-found_middle:
- return result + ffz(tmp);
-}
-
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-int find_next_zero_bit(void * addr, int size, int offset)
-{
- unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
- unsigned int result = offset & ~31UL;
- unsigned int tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset &= 31UL;
- if (offset) {
- tmp = *(p++);
- tmp |= ~0UL >> (32-offset);
- if (size < 32)
- goto found_first;
- if (~tmp)
- goto found_middle;
- size -= 32;
- result += 32;
- }
- while (size & ~31UL) {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = *p;
-found_first:
- tmp |= ~0UL << size;
-found_middle:
- return result + ffz(tmp);
-}
-#endif
+#endif /* !__INLINE_BITOPS */
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 0d614fba1..c43296c42 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -288,7 +288,9 @@ void __init
chrp_pcibios_fixup(void)
{
struct pci_dev *dev;
+#ifdef CONFIG_POWER4
int i;
+#endif
int *brp;
struct device_node *np;
extern struct pci_ops generic_pci_ops;
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index d75ccaf5c..8d6649231 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -51,7 +51,7 @@
#include <asm/keyboard.h>
#include <asm/init.h>
-#include "time.h"
+#include <asm/time.h>
#include "local_irq.h"
#include "i8259.h"
#include "open_pic.h"
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index 6d275e517..54b4a76bb 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -26,7 +26,7 @@
#include <asm/nvram.h>
#include <asm/prom.h>
#include <asm/init.h>
-#include "time.h"
+#include <asm/time.h>
static int nvram_as1 = NVRAM_AS1;
static int nvram_as0 = NVRAM_AS0;
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 354686c2d..8ccb0f571 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -5,8 +5,8 @@
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ * Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP
+ * Copyright (C) 1996 Cort Dougan <cort@fsmlabs.com>
* Adapted for Power Macintosh by Paul Mackerras.
* Low-level exception handlers and MMU support
* rewritten by Paul Mackerras.
@@ -83,7 +83,9 @@ _GLOBAL(DoSyscall)
#endif /* SHOW_SYSCALLS */
cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
beq- 10f
- lwz r10,TASK_PTRACE(r2)
+ cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */
+ beq- 16f
+ lwz r10,TASK_FLAGS(r2)
andi. r10,r10,PT_TRACESYS
bne- 50f
cmpli 0,r0,NR_syscalls
@@ -129,6 +131,12 @@ ret_from_syscall_1:
/* sys_sigreturn */
10: addi r3,r1,STACK_FRAME_OVERHEAD
bl sys_sigreturn
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge ret_from_except
+ b 20b
+/* sys_rt_sigreturn */
+16: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl sys_rt_sigreturn
cmpi 0,r3,0 /* Check for restarted system call */
bge ret_from_except
b 20b
diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c
index e47befdd3..4b63d5dc0 100644
--- a/arch/ppc/kernel/feature.c
+++ b/arch/ppc/kernel/feature.c
@@ -2,6 +2,7 @@
* arch/ppc/kernel/feature.c
*
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ * Ben. Herrenschmidt (bh40@calva.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,7 +31,7 @@
#undef DEBUG_FEATURE
#define MAX_FEATURE_CONTROLLERS 2
-#define MAX_FEATURE_OFFSET 0x50
+#define MAX_FEATURE_OFFSET 0x100
#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
typedef struct feature_bit {
@@ -70,6 +71,7 @@ static fbit feature_bits_ohare_pbook[] = {
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/* Those bits are from a PowerBook. It's possible that desktop machines
@@ -102,6 +104,7 @@ static fbit feature_bits_heathrow[] = {
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/*
@@ -135,6 +138,7 @@ static fbit feature_bits_paddington[] = {
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
@@ -166,6 +170,7 @@ static fbit feature_bits_keylargo[] = {
{0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
{0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */
{0x34,0,0x00000100}, /* FEATURE_Mediabay_content */
+ {0x40,1,0x08000000}, /* FEATURE_Airport_reset */
};
/* definition of a feature controller object */
@@ -177,22 +182,33 @@ struct feature_controller {
};
/* static functions */
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits);
static struct feature_controller*
feature_lookup_controller(struct device_node *device);
-/* static varialbles */
+static void heathrow_prepare_for_sleep(struct feature_controller* ctrler);
+static void heathrow_wakeup(struct feature_controller* ctrler);
+static void core99_prepare_for_sleep(struct feature_controller* ctrler);
+static void core99_wake_up(struct feature_controller* ctrler);
+
+/* static variables */
static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
+/* Core99 stuffs */
+static volatile u32* uninorth_base = NULL;
+static volatile u32* keylargo_base = NULL;
+static int uninorth_rev;
+static int keylargo_rev;
void
feature_init(void)
{
struct device_node *np;
-
+ u32 *rev;
+
if (_machine != _MACH_Pmac)
return;
@@ -202,7 +218,14 @@ feature_init(void)
* plus some gpio's which could eventually be handled here.
*/
if (device_is_compatible(np, "Keylargo")) {
- feature_add_controller(np, feature_bits_keylargo);
+ struct feature_controller* ctrler =
+ feature_add_controller(np, feature_bits_keylargo);
+ if (ctrler) {
+ keylargo_base = ctrler->reg;
+ rev = (u32 *)get_property(ctrler->device, "revision-id", NULL);
+ if (rev)
+ keylargo_rev = *rev;
+ }
} else if (device_is_compatible(np, "paddington")) {
feature_add_controller(np, feature_bits_paddington);
} else {
@@ -222,6 +245,18 @@ feature_init(void)
}
}
+ /* Handle core99 Uni-N */
+ np = find_devices("uni-n");
+ if (np && np->n_addrs > 0) {
+ uninorth_base = ioremap(np->addrs[0].address, 0x1000);
+ rev = (u32 *)get_property(np, "device-rev", NULL);
+ if (rev)
+ uninorth_rev = *rev;
+ }
+ if (uninorth_base && keylargo_base)
+ printk("Uni-N revision: %d, KeyLargo revision: %d\n",
+ uninorth_rev, keylargo_rev);
+
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
@@ -236,7 +271,7 @@ feature_init(void)
#endif
}
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
@@ -244,7 +279,7 @@ feature_add_controller(struct device_node *controller_device, fbit* bits)
if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
controller_device->full_name, MAX_FEATURE_CONTROLLERS);
- return;
+ return NULL;
}
controller = &controllers[controller_count];
@@ -253,7 +288,7 @@ feature_add_controller(struct device_node *controller_device, fbit* bits)
if (controller_device->n_addrs == 0) {
printk(KERN_ERR "No addresses for %s\n",
controller_device->full_name);
- return;
+ return NULL;
}
controller->reg = (volatile u32 *)ioremap(
@@ -262,12 +297,14 @@ feature_add_controller(struct device_node *controller_device, fbit* bits)
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
- return;
+ return NULL;
}
spin_lock_init(&controller->lock);
controller_count++;
+
+ return controller;
}
static struct feature_controller*
@@ -389,3 +426,118 @@ feature_test(struct device_node* device, enum system_feature f)
return bit->polarity ? (value == 0) : (value == bit->mask);
}
+/*
+ * Core99 functions
+ *
+ * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo
+ * chip, which is the case on all Core99 machines so far
+ */
+
+/* Only one GMAC is assumed */
+void
+feature_set_gmac_power(struct device_node* device, int power)
+{
+ if (!uninorth_base)
+ return;
+ if (power)
+ out_le32(uninorth_base + 0x20/4,
+ in_le32(uninorth_base + 0x20/4) | 0x02000000);
+ else
+ out_le32(uninorth_base + 0x20/4,
+ in_le32(uninorth_base + 0x20/4) & ~0x02000000);
+ udelay(20);
+}
+
+/* Pass the node of the correct controller, please */
+void
+feature_set_usb_power(struct device_node* device, int power)
+{
+}
+
+/* Not yet implemented */
+void
+feature_set_firewire_power(struct device_node* device, int power)
+{
+}
+
+void
+feature_prepare_for_sleep(void)
+{
+ /* We assume gatwick is second */
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_prepare_for_sleep(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_prepare_for_sleep(ctrler);
+ return;
+ }
+}
+
+
+void
+feature_wake_up(void)
+{
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_wakeup(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_wake_up(ctrler);
+ return;
+ }
+}
+
+static u32 save_fcr0;
+//static u32 save_fcr1;
+//static u32 save_fcr2;
+static u32 save_mbcr;
+
+static void
+heathrow_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ save_mbcr = in_le32(FREG(ctrler, 0x34));
+ save_fcr0 = in_le32(FREG(ctrler, 0x38));
+
+ out_le32(FREG(ctrler, 0x38), save_fcr0 & ~HRW_IOBUS_ENABLE);
+}
+
+static void
+heathrow_wakeup(struct feature_controller* ctrler)
+{
+ out_le32(FREG(ctrler, 0x38), save_fcr0);
+ out_le32(FREG(ctrler, 0x34), save_mbcr);
+
+ out_le32(FREG(ctrler, 0x38), save_fcr0 | HRW_IOBUS_ENABLE);
+}
+
+static void
+core99_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ /* Not yet implemented */
+}
+
+static void
+core99_wake_up(struct feature_controller* ctrler)
+{
+ /* Not yet implemented */
+}
+
diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c
index e069baf5b..7be4675c2 100644
--- a/arch/ppc/kernel/gemini_setup.c
+++ b/arch/ppc/kernel/gemini_setup.c
@@ -30,7 +30,7 @@
#include <asm/m48t35.h>
#include <asm/gemini.h>
-#include "time.h"
+#include <asm/time.h>
#include "local_irq.h"
#include "open_pic.h"
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 8c5911d30..067581f5d 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -171,6 +171,9 @@ __after_prom_start:
#ifndef CONFIG_POWER4
/* POWER4 doesn't have BATs */
bl initial_bats
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+ bl setup_disp_bat
+#endif
#else /* CONFIG_POWER4 */
/*
* Load up the SDR1 and segment register values now
@@ -1603,23 +1606,37 @@ initial_bats:
mtspr DBAT0U,r11 /* bit in upper BAT register */
mtspr IBAT0L,r8
mtspr IBAT0U,r11
-#if 0 /* Useful debug code, please leave in for now so I don't have to
- * look at docs when I need to setup a BAT ...
- */
-setup_screen_bat:
- li r3,0
- mtspr DBAT1U,r3
- lis r3,0xfa00
- CLR_TOP32(r3)
- lis r4,0xfa00
- CLR_TOP32(r4)
- ori r4,r4,0x2a
- mtspr DBAT1L,r4
- ori r3,r3,(BL_16M<<2)|0x2 /* set up BAT registers for 604 */
- mtspr DBAT1U,r3
-#endif
isync
blr
+
+#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+setup_disp_bat:
+ /*
+ * setup the display bat prepared for us in prom.c
+ */
+ mflr r8
+ bl reloc_offset
+ mtlr r8
+ lis r8, disp_BATL@h
+ ori r8, r8, disp_BATL@l
+ add r8, r3, r8
+ lwz r8, 0(r8)
+ lis r11, disp_BATU@h
+ ori r11, r11, disp_BATU@l
+ add r11, r3, r11
+ lwz r11, 0(r11)
+ mtspr IBAT3L,r8
+ mtspr IBAT3U,r11
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ beq 1f
+ mtspr DBAT3L,r8
+ mtspr DBAT3U,r11
+1:
+ blr
+
+#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
#endif /* CONFIG_POWER4 */
#ifdef CONFIG_8260
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index a81156102..d29f7bd20 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -304,3 +304,4 @@ void power_save(void)
return;
}
}
+
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index b055f23ec..ee63ca902 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -74,8 +74,7 @@ volatile unsigned char *chrp_int_ack_special;
irq_desc_t irq_desc[NR_IRQS];
int ppc_spurious_interrupts = 0;
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
+irq_cpustat_t irq_stat [NR_CPUS];
struct irqaction *ppc_irq_action[NR_IRQS];
unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
@@ -248,6 +247,7 @@ int get_irq_list(char *buf)
len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
else
len += sprintf(buf+len, " None ");
+ len += sprintf(buf+len, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge ");
len += sprintf(buf+len, " %s",action->name);
for (action=action->next; action; action = action->next) {
len += sprintf(buf+len, ", %s", action->name);
@@ -368,12 +368,12 @@ static void show(char * str)
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
atomic_read(&global_irq_count),
- local_irq_count[0],
- local_irq_count[1]);
+ local_irq_count(0),
+ local_irq_count(1));
printk("bh: %d [%d %d]\n",
atomic_read(&global_bh_count),
- local_bh_count[0],
- local_bh_count[1]);
+ local_bh_count(0),
+ local_bh_count(1));
stack = (unsigned long *) &str;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
@@ -408,7 +408,7 @@ static inline void wait_on_irq(int cpu)
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu]
+ if (local_bh_count(cpu)
|| !atomic_read(&global_bh_count))
break;
}
@@ -430,7 +430,7 @@ static inline void wait_on_irq(int cpu)
continue;
if (global_irq_lock)
continue;
- if (!local_bh_count[cpu]
+ if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
if (!test_and_set_bit(0,&global_irq_lock))
@@ -521,7 +521,7 @@ void __global_cli(void)
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!local_irq_count(cpu))
get_irqlock(cpu);
}
}
@@ -530,7 +530,7 @@ void __global_sti(void)
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!local_irq_count(cpu))
release_irqlock(cpu);
__sti();
}
@@ -554,7 +554,7 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
- if (!local_irq_count[smp_processor_id()]) {
+ if (!local_irq_count(smp_processor_id())) {
if (local_enabled)
retval = 1;
if (global_irq_holder == (unsigned char) smp_processor_id())
diff --git a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c
index 2ce3790c3..891b0ca44 100644
--- a/arch/ppc/kernel/m8260_setup.c
+++ b/arch/ppc/kernel/m8260_setup.c
@@ -44,7 +44,7 @@
#include <asm/immap_8260.h>
#include <asm/machdep.h>
-#include "time.h"
+#include <asm/time.h>
#include "ppc8260_pic.h"
static int m8260_set_rtc_time(unsigned long time);
diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
index 9f0a517e3..a00a8c452 100644
--- a/arch/ppc/kernel/m8xx_setup.c
+++ b/arch/ppc/kernel/m8xx_setup.c
@@ -45,7 +45,7 @@
#include <asm/8xx_immap.h>
#include <asm/machdep.h>
-#include "time.h"
+#include <asm/time.h>
#include "ppc8xx_pic.h"
static int m8xx_set_rtc_time(unsigned long time);
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index f8d230c7e..19a218bd4 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1205,6 +1205,17 @@ _GLOBAL(sys_call_table)
.long sys_ni_syscall /* streams2 */
.long sys_vfork
.long sys_getrlimit /* 190 */
- .rept NR_syscalls-190
+ .long sys_ni_syscall /* 191 */ /* Unused */
+ .long sys_ni_syscall /* 192 - reserved - mmap2 */
+ .long sys_ni_syscall /* 193 - reserved - truncate64 */
+ .long sys_ni_syscall /* 194 - reserved - ftruncate64 */
+ .long sys_ni_syscall /* 195 - reserved - stat64 */
+ .long sys_ni_syscall /* 196 - reserved - lstat64 */
+ .long sys_ni_syscall /* 197 - reserved - fstat64 */
+ .long sys_pciconfig_read /* 198 */
+ .long sys_pciconfig_write /* 199 */
+ .long sys_pciconfig_iobase /* 200 */
+ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */
+ .rept NR_syscalls-201
.long sys_ni_syscall
.endr
diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c
index f3c142e2b..09e6e6e6f 100644
--- a/arch/ppc/kernel/oak_setup.c
+++ b/arch/ppc/kernel/oak_setup.c
@@ -28,7 +28,7 @@
#include "local_irq.h"
#include "ppc4xx_pic.h"
-#include "time.h"
+#include <asm/time.h>
#include "oak_setup.h"
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 21001a7ce..416137934 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -261,12 +261,15 @@ void __init openpic_init(int main_pic)
while(np) {
int j, pri;
pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
- for (j=0;j<np->n_intrs;j++)
+ for (j=0;j<np->n_intrs;j++) {
openpic_initirq( np->intrs[j].line,
pri,
np->intrs[j].line,
- np->intrs[j].sense,
+ 0,
np->intrs[j].sense);
+ if (np->intrs[j].sense)
+ irq_desc[np->intrs[j].line].status = IRQ_LEVEL;
+ }
np = np->next;
}
}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 773c99b5c..cfa26b67d 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -4,11 +4,14 @@
*/
#include <linux/kernel.h>
+#include <linux/config.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/openpic.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/processor.h>
@@ -19,6 +22,7 @@
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/gg2.h>
+#include <asm/uaccess.h>
#include "pci.h"
@@ -184,3 +188,146 @@ int pcibios_enable_device(struct pci_dev *dev)
}
return 0;
}
+
+/*
+ * Those syscalls are derived from the Alpha versions, they
+ * allow userland apps to retreive the per-device iobase and
+ * mem-base. They also provide wrapper for userland to do
+ * config space accesses.
+ * The "host_number" returns the number of the Uni-N sub bridge
+ */
+
+asmlinkage int
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ long err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!pcibios_present())
+ return -ENOSYS;
+
+ switch (len) {
+ case 1:
+ err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, buf);
+ break;
+ case 2:
+ err = pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, (unsigned short *)buf);
+ break;
+ case 4:
+ err = pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, (unsigned int *)buf);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+asmlinkage int
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ long err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!pcibios_present())
+ return -ENOSYS;
+
+ switch (len) {
+ case 1:
+ err = get_user(ubyte, buf);
+ if (err)
+ break;
+ err = pcibios_write_config_byte(bus, dfn, off, ubyte);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ case 2:
+ err = get_user(ushort, (unsigned short *)buf);
+ if (err)
+ break;
+ err = pcibios_write_config_word(bus, dfn, off, ushort);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ case 4:
+ err = get_user(uint, (unsigned int *)buf);
+ if (err)
+ break;
+ err = pcibios_write_config_dword(bus, dfn, off, uint);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+void *
+pci_dev_io_base(unsigned char bus, unsigned char devfn)
+{
+ /* Defaults to old way */
+ if (!ppc_md.pci_dev_io_base)
+ return pci_io_base(bus);
+ return ppc_md.pci_dev_io_base(bus, devfn);
+}
+
+void *
+pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+ /* Default memory base is 0 (1:1 mapping) */
+ if (!ppc_md.pci_dev_mem_base)
+ return 0;
+ return ppc_md.pci_dev_mem_base(bus, devfn);
+}
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int
+pci_dev_root_bridge(unsigned char bus, unsigned char devfn)
+{
+ /* Defaults to 0 */
+ if (!ppc_md.pci_dev_root_bridge)
+ return 0;
+ return ppc_md.pci_dev_root_bridge(bus, devfn);
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory. Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+ switch (which) {
+ case IOBASE_BRIDGE_NUMBER:
+ return (long)pci_dev_root_bridge(bus, devfn);
+ case IOBASE_MEMORY:
+ return (long)pci_dev_mem_base(bus, devfn);
+ case IOBASE_IO:
+ return (long)pci_dev_io_base(bus, devfn);
+ }
+
+ return -EOPNOTSUPP;
+}
+
diff --git a/arch/ppc/kernel/pmac_backlight.c b/arch/ppc/kernel/pmac_backlight.c
new file mode 100644
index 000000000..c4426a0b0
--- /dev/null
+++ b/arch/ppc/kernel/pmac_backlight.c
@@ -0,0 +1,148 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the backlight.
+ *
+ * Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <asm/init.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <asm/backlight.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+static struct backlight_controller *backlighter = NULL;
+static void* backlighter_data = NULL;
+static int backlight_autosave = 0;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+
+void __pmac
+register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+{
+ struct device_node* bk_node;
+ char *prop;
+ int valid = 0;
+
+ bk_node = find_devices("backlight");
+
+#ifdef CONFIG_ADB_PMU
+ /* Special case for the old PowerBook since I can't test on it */
+ if ((machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500")
+ || machine_is_compatible("AAPL,PowerBook1998")
+ || machine_is_compatible("AAPL,PowerBook1999"))
+ && !strcmp(type, "pmu"))
+ valid = 1;
+ else
+#endif
+ {
+ if (bk_node)
+ prop = get_property(bk_node, "backlight-control", NULL);
+ if (prop && !strncmp(prop, type, strlen(type)))
+ valid = 1;
+ }
+ if (!valid)
+ return;
+ backlighter = ctrler;
+ backlighter_data = data;
+
+ if (bk_node && !backlight_autosave)
+ prop = get_property(bk_node, "bklt", NULL);
+ else
+ prop = NULL;
+ if (prop) {
+ backlight_level = ((*prop)+1) >> 1;
+ if (backlight_level > BACKLIGHT_MAX)
+ backlight_level = BACKLIGHT_MAX;
+ }
+
+#ifdef CONFIG_ADB_PMU
+ backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500");
+ if (backlight_autosave) {
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ while (!req.complete)
+ pmu_poll();
+ backlight_level = req.reply[1] >> 4;
+ }
+#endif
+ if (!backlighter->set_enable(1, backlight_level, data))
+ backlight_enabled = 1;
+
+ printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
+ type, backlight_level);
+}
+
+void __pmac
+unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+{
+ /* We keep the current backlight level (for now) */
+ if (ctrler == backlighter && data == backlighter_data)
+ backlighter = NULL;
+}
+
+int __pmac
+set_backlight_enable(int enable)
+{
+ int rc;
+
+ if (!backlighter)
+ return -ENODEV;
+ rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+ if (!rc)
+ backlight_enabled = enable;
+ return rc;
+}
+
+int __pmac
+get_backlight_enable(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_enabled;
+}
+
+int __pmac
+set_backlight_level(int level)
+{
+ int rc = 0;
+
+ if (!backlighter)
+ return -ENODEV;
+ if (level < BACKLIGHT_MIN)
+ level = BACKLIGHT_OFF;
+ if (level > BACKLIGHT_MAX)
+ level = BACKLIGHT_MAX;
+ if (backlight_enabled)
+ rc = backlighter->set_level(level, backlighter_data);
+ if (!rc)
+ backlight_level = level;
+ if (!rc && !backlight_autosave) {
+ level <<=1;
+ if (level & 0x10)
+ level |= 0x01;
+ // -- todo: save to property "bklt"
+ }
+ return rc;
+}
+
+int __pmac
+get_backlight_level(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_level;
+}
diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c
index db0632238..d8de113ec 100644
--- a/arch/ppc/kernel/pmac_nvram.c
+++ b/arch/ppc/kernel/pmac_nvram.c
@@ -19,20 +19,8 @@
#undef DEBUG
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static char* nvram_image;
-static int core99_bank = 0;
-
-extern int pmac_newworld;
-
#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
-
+
#define CORE99_SIGNATURE 0x5a
#define CORE99_ADLER_START 0x14
@@ -60,8 +48,29 @@ struct core99_header {
u32 reserved[2];
};
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
static int nvram_partitions[3];
+/* FIXME: kmalloc fails to allocate the image now that I had to move it
+ * before time_init(). For now, I allocate a static buffer here
+ * but it's a waste of space on all but core99 machines
+ */
+#if 0
+static char* nvram_image;
+#else
+__pmac static char nvram_image[NVRAM_SIZE];
+#endif
+
+extern int pmac_newworld;
+
+
static u8
chrp_checksum(struct chrp_header* hdr)
{
@@ -189,6 +198,7 @@ lookup_partitions(void)
hdr = (struct chrp_header *)buffer;
offset = 0;
+ buffer[16] = 0;
do {
for (i=0;i<16;i++)
buffer[i] = nvram_read_byte(offset+i);
@@ -234,11 +244,13 @@ void pmac_nvram_init(void)
printk(KERN_ERR "nvram: no address\n");
return;
}
+#if 0
nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
if (!nvram_image) {
printk(KERN_ERR "nvram: can't allocate image\n");
return;
}
+#endif
nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
#ifdef DEBUG
printk("nvram: Checking bank 0...\n");
@@ -267,6 +279,7 @@ void pmac_nvram_init(void)
printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
nvram_naddrs);
}
+ lookup_partitions();
}
void
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index ee54ba37d..ced029722 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -34,6 +34,7 @@ struct uninorth_data {
struct device_node* node;
volatile unsigned int* cfg_addr;
volatile unsigned int* cfg_data;
+ void* iobase;
};
static struct uninorth_data uninorth_bridges[3];
@@ -54,6 +55,7 @@ static void add_bridges(struct device_node *dev);
#define BANDIT_MAGIC 0x50
#define BANDIT_COHERENT 0x40
+/* Obsolete, should be replaced by pmac_pci_dev_io_base() (below) */
__pmac
void *pci_io_base(unsigned int bus)
{
@@ -83,6 +85,72 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
return 0;
}
+/* This routines figures out on which root bridge a given PCI device
+ * is attached.
+ */
+__pmac
+int
+pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn)
+{
+ struct device_node *node, *bridge_node;
+ int bridge = uninorth_default;
+
+ if (uninorth_count == 0)
+ return 0;
+ if (bus == 0 && PCI_SLOT(dev_fn) < 11)
+ return 0;
+
+ /* We look for the OF device corresponding to this bus/devfn pair. If we
+ * don't find it, we default to the external PCI */
+ bridge_node = NULL;
+ node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+ if (node) {
+ /* note: we don't stop on the first occurence since we need to go
+ * up to the root bridge */
+ do {
+ if (node->type && !strcmp(node->type, "pci")
+ && device_is_compatible(node, "uni-north"))
+ bridge_node = node;
+ node=node->parent;
+ } while (node);
+ }
+ if (bridge_node) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ if (uninorth_bridges[i].node == bridge_node) {
+ bridge = i;
+ break;
+ }
+ }
+
+ if (bridge == -1) {
+ printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+ return 0;
+ }
+
+ return bridge;
+}
+
+__pmac
+void *
+pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn)
+{
+ int bridge;
+ if (uninorth_count == 0)
+ return pci_io_base(bus);
+ bridge = pmac_pci_dev_root_bridge(bus, devfn);
+ if (bridge == -1)
+ return pci_io_base(bus);
+ return uninorth_bridges[bridge].iobase;
+}
+
+__pmac
+void *
+pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+ return 0;
+}
+
/* This function only works for bus 0, uni-N uses a different mecanism for
* other busses (see below)
*/
@@ -98,48 +166,20 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
|(((unsigned long)(off)) & 0xFCUL) \
|1UL)
-/* We should really use RTAS here, unfortunately, it's not available with BootX.
- * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
- * later, once I have something that works enough with BootX.
- */
__pmac static
unsigned int
uni_north_access_data(unsigned char bus, unsigned char dev_fn,
unsigned char offset)
{
- struct device_node *node, *bridge_node;
- int bridge = uninorth_default;
+ int bridge;
unsigned int caddr;
- if (bus == 0) {
- if (PCI_SLOT(dev_fn) < 11) {
- return 0;
- }
- /* We look for the OF device corresponding to this bus/devfn pair. If we
- * don't find it, we default to the external PCI */
- bridge_node = NULL;
- node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
- if (node) {
- /* note: we don't stop on the first occurence since we need to go
- * up to the root bridge */
- do {
- if (!strcmp(node->type, "pci"))
- bridge_node = node;
- node=node->parent;
- } while (node);
- }
- if (bridge_node) {
- int i;
- for (i=0;i<uninorth_count;i++)
- if (uninorth_bridges[i].node == bridge_node) {
- bridge = i;
- break;
- }
- }
+ bridge = pmac_pci_dev_root_bridge(bus, dev_fn);
+ if (bus == 0)
caddr = UNI_N_CFA0(dev_fn, offset);
- } else
+ else
caddr = UNI_N_CFA1(bus, dev_fn, offset);
-
+
if (bridge == -1) {
printk(KERN_WARNING "pmac_pci: no default bridge !\n");
return 0;
@@ -609,6 +649,7 @@ static void __init add_bridges(struct device_node *dev)
uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
uninorth_bridges[i].node = dev;
+ uninorth_bridges[i].iobase = (void *)addr->address;
/* XXX This is the bridge with the PCI expansion bus. This is also the
* address of the bus that will receive type 1 config accesses and io
* accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
index ab2fdbc15..e0e654305 100644
--- a/arch/ppc/kernel/pmac_pic.c
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -61,14 +61,32 @@ static void pmac_openpic_unmask_irq(unsigned int irq_nr)
openpic_enable_irq(irq_nr);
}
+static void pmac_openpic_ack_irq(unsigned int irq_nr)
+{
+ if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+ openpic_eoi(smp_processor_id());
+ openpic_disable_irq(irq_nr);
+}
+
+static void pmac_openpic_end_irq(unsigned int irq_nr)
+{
+ if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
+ openpic_eoi(smp_processor_id());
+ openpic_enable_irq(irq_nr);
+}
+
struct hw_interrupt_type pmac_open_pic = {
" OpenPIC ",
NULL,
NULL,
pmac_openpic_unmask_irq,
pmac_openpic_mask_irq,
- pmac_openpic_mask_irq,
- 0
+ /* Theorically, the mask&ack should be NULL for OpenPIC. However, doing
+ * so shows tons of bogus interrupts coming in.
+ */
+ pmac_openpic_ack_irq,
+ pmac_openpic_end_irq,
+ NULL
};
static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
@@ -141,7 +159,8 @@ struct hw_interrupt_type pmac_pic = {
pmac_unmask_irq,
pmac_mask_irq,
pmac_mask_and_ack_irq,
- 0
+ pmac_unmask_irq,
+ NULL
};
struct hw_interrupt_type gatwick_pic = {
@@ -151,7 +170,8 @@ struct hw_interrupt_type gatwick_pic = {
pmac_unmask_irq,
pmac_mask_irq,
pmac_mask_and_ack_irq,
- 0
+ pmac_unmask_irq,
+ NULL
};
static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
@@ -199,17 +219,13 @@ pmac_get_irq(struct pt_regs *regs)
}
#endif /* CONFIG_SMP */
- /* Yeah, I know, this could be a separate get_irq function */
- if (has_openpic)
- {
+ if (has_openpic) {
irq = openpic_irq(smp_processor_id());
if (irq == OPENPIC_VEC_SPURIOUS)
/* We get those when doing polled ADB requests,
* using -2 is a temp hack to disable the printk
*/
irq = -2; /*-1; */
- else
- openpic_eoi(smp_processor_id());
}
else
{
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 35aa7a76d..ec8c6eca4 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -62,17 +62,18 @@
#include <asm/dma.h>
#include <asm/bootx.h>
-#include "time.h"
+#include <asm/time.h>
#include "local_irq.h"
#include "pmac_pic.h"
#undef SHOW_GATWICK_IRQS
-unsigned long pmac_get_rtc_time(void);
-int pmac_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void pmac_calibrate_decr(void);
-void pmac_setup_pci_ptrs(void);
+extern void pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_setup_pci_ptrs(void);
extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int mackbd_getkeycode(unsigned int scancode);
@@ -91,6 +92,11 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
+extern void pmac_nvram_update(void);
+
+extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn);
+extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
unsigned char drive_info;
@@ -98,6 +104,8 @@ int ppc_override_l2cr = 0;
int ppc_override_l2cr_value;
int has_l2cache = 0;
+static int current_root_goodness = -1;
+
extern char saved_command_line[];
extern int pmac_newworld;
@@ -300,7 +308,9 @@ pmac_setup_arch(void)
#ifdef CONFIG_ADB_PMU
find_via_pmu();
#endif
-
+#ifdef CONFIG_NVRAM
+ pmac_nvram_init();
+#endif
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
@@ -364,27 +374,25 @@ static void __init
init_uninorth(void)
{
/*
- * Turns on the gmac clock so that it responds to PCI cycles
- * later, the driver may want to turn it off again to save
- * power when interface is down
+ * Turns OFF the gmac clock. The gmac driver will turn
+ * it back ON when the interface is enabled. This save
+ * power on portables.
+ *
+ * Note: We could also try to turn OFF the PHY. Since this
+ * has to be done by both the gmac driver and this code,
+ * I'll probably end-up moving some of this out of the
+ * modular gmac driver into a non-modular stub containing
+ * some basic PHY management and power management stuffs
*/
- struct device_node* uni_n = find_devices("uni-n");
struct device_node* gmac = find_devices("ethernet");
- unsigned long* addr;
-
- if (!uni_n || uni_n->n_addrs < 1)
- return;
- addr = ioremap(uni_n->addrs[0].address, 0x300);
while(gmac) {
if (device_is_compatible(gmac, "gmac"))
break;
gmac = gmac->next;
}
- if (gmac) {
- *(addr + 8) |= 2;
- eieio();
- }
+ if (gmac)
+ feature_set_gmac_power(gmac, 0);
}
extern char *bootpath;
@@ -402,9 +410,6 @@ pmac_init2(void)
#ifdef CONFIG_ADB_PMU
via_pmu_start();
#endif
-#ifdef CONFIG_NVRAM
- pmac_nvram_init();
-#endif
#ifdef CONFIG_PMAC_PBOOK
media_bay_init();
#endif
@@ -476,13 +481,14 @@ void __init find_boot_device(void)
/* can't be __init - can be called whenever a disk is first accessed */
__pmac
-void note_bootable_part(kdev_t dev, int part)
+void note_bootable_part(kdev_t dev, int part, int goodness)
{
static int found_boot = 0;
char *p;
/* Do nothing if the root has been set already. */
- if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+ if ((goodness < current_root_goodness) &&
+ (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
return;
p = strstr(saved_command_line, "root=");
if (p != NULL && (p == saved_command_line || p[-1] == ' '))
@@ -495,7 +501,7 @@ void note_bootable_part(kdev_t dev, int part)
if (boot_dev == 0 || dev == boot_dev) {
ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
boot_dev = NODEV;
- printk(" (root on %d)", part);
+ current_root_goodness = goodness;
}
}
@@ -666,11 +672,15 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.power_off = pmac_power_off;
ppc_md.halt = pmac_halt;
- ppc_md.time_init = NULL;
+ ppc_md.time_init = pmac_time_init;
ppc_md.set_rtc_time = pmac_set_rtc_time;
ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr;
+ ppc_md.pci_dev_io_base = pmac_pci_dev_io_base;
+ ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base;
+ ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge;
+
#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD)
ppc_md.kbd_setkeycode = mackbd_setkeycode;
ppc_md.kbd_getkeycode = mackbd_getkeycode;
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
index ebd0037de..9eb326bf9 100644
--- a/arch/ppc/kernel/pmac_time.c
+++ b/arch/ppc/kernel/pmac_time.c
@@ -26,7 +26,8 @@
#include <asm/pgtable.h>
#include <asm/machdep.h>
-#include "time.h"
+#include <asm/time.h>
+#include <asm/nvram.h>
extern rwlock_t xtime_lock;
@@ -54,8 +55,30 @@ extern rwlock_t xtime_lock;
/* Bits in IFR and IER */
#define T1_INT 0x40 /* Timer 1 interrupt */
-__pmac
+extern struct timezone sys_tz;
+
+__init
+void pmac_time_init(void)
+{
+#ifdef CONFIG_NVRAM
+ s32 delta = 0;
+ int dst;
+
+ delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+ delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+ delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+ if (delta & 0x00800000UL)
+ delta |= 0xFF000000UL;
+ dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+ printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+ dst ? "on" : "off");
+ sys_tz.tz_minuteswest = -delta/60;
+ /* I _suppose_ this is 0:off, 1:on */
+ sys_tz.tz_dsttime = dst;
+#endif
+}
+__pmac
unsigned long pmac_get_rtc_time(void)
{
#ifdef CONFIG_ADB
@@ -95,7 +118,34 @@ unsigned long pmac_get_rtc_time(void)
int pmac_set_rtc_time(unsigned long nowtime)
{
- return 0;
+ struct adb_request req;
+
+ nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60;
+
+ switch (sys_ctrler) {
+ case SYS_CTRLER_CUDA:
+ if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+// if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+ case SYS_CTRLER_PMU:
+ if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len != 5)
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+ default:
+ return 0;
+ }
}
/*
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 76809881b..b140dd25c 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -35,10 +35,11 @@
#include <asm/dma.h>
#include <asm/machdep.h>
#include <asm/hw_irq.h>
+#include <asm/nvram.h>
#ifdef CONFIG_SMP
#include <asm/smplock.h>
#endif /* CONFIG_SMP */
-#include "time.h"
+#include <asm/time.h>
/* Tell string.h we don't want memcpy etc. as cpp defines */
#define EXPORT_SYMTAB_STROPS
@@ -76,8 +77,7 @@ EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
-EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(irq_stat);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(kernel_flag);
#endif /* CONFIG_SMP */
@@ -96,6 +96,10 @@ EXPORT_SYMBOL(_prep_type);
EXPORT_SYMBOL(ucSystemType);
#endif
#endif
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_dev_io_base);
+EXPORT_SYMBOL(pci_dev_mem_base);
+#endif
#if !__INLINE_BITOPS
EXPORT_SYMBOL(set_bit);
@@ -234,6 +238,9 @@ EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
+EXPORT_SYMBOL(feature_set_gmac_power);
+EXPORT_SYMBOL(feature_set_usb_power);
+EXPORT_SYMBOL(feature_set_firewire_power);
#endif /* defined(CONFIG_ALL_PPC) */
#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(note_scsi_host);
@@ -242,7 +249,13 @@ EXPORT_SYMBOL(kd_mksound);
#ifdef CONFIG_NVRAM
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
#endif /* CONFIG_NVRAM */
+#ifdef CONFIG_PPC_RTC
+EXPORT_SYMBOL(mktime);
+EXPORT_SYMBOL(to_tm);
+#endif
EXPORT_SYMBOL_NOVERS(__ashrdi3);
EXPORT_SYMBOL_NOVERS(__ashldi3);
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index cb1110eca..a09b4cf81 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -49,7 +49,7 @@
#include <asm/raven.h>
#include <asm/keyboard.h>
-#include "time.h"
+#include <asm/time.h>
#include "local_irq.h"
#include "i8259.h"
#include "open_pic.h"
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
index f720841be..7274dfd0b 100644
--- a/arch/ppc/kernel/prep_time.c
+++ b/arch/ppc/kernel/prep_time.c
@@ -27,7 +27,7 @@
#include <asm/prep_nvram.h>
#include <asm/mk48t59.h>
-#include "time.h"
+#include <asm/time.h>
/*
* The motorola uses the m48t18 rtc (includes DS1643) whose registers
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index 7f51ca13f..1d661fa71 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -118,10 +118,16 @@ static struct device_node *allnodes = 0;
#ifdef CONFIG_BOOTX_TEXT
+#define NO_SCROLL
+
static void clearscreen(void);
static void flushscreen(void);
+#ifndef NO_SCROLL
static void scrollscreen(void);
+#endif
+
+static void prepare_disp_BAT(void);
static void draw_byte(unsigned char c, long locX, long locY);
static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
@@ -134,6 +140,9 @@ static long g_loc_Y = 0;
static long g_max_loc_X = 0;
static long g_max_loc_Y = 0;
+unsigned long disp_BATL = 0;
+unsigned long disp_BATU = 0;
+
#define cmapsz (16*256)
static unsigned char vga_font[cmapsz];
@@ -473,9 +482,10 @@ bootx_init(unsigned long r4, unsigned long phys)
}
#ifdef CONFIG_BOOTX_TEXT
+ prepare_disp_BAT();
prom_drawstring(RELOC("booting...\n"));
flushscreen();
- RELOC(bootx_text_mapped) = 0;
+ RELOC(bootx_text_mapped) = 1;
#endif
}
@@ -748,11 +758,15 @@ prom_init(int r3, int r4, prom_entry pp)
#ifdef CONFIG_BOOTX_TEXT
if (!chrp && RELOC(disp_bi)) {
+ RELOC(prom_stdout) = 0; /* stop OF output */
clearscreen();
+ prepare_disp_BAT();
prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
prom_drawstring(RELOC("booting...\n"));
+ RELOC(bootx_text_mapped) = 1;
+ } else {
+ RELOC(bootx_text_mapped) = 0;
}
- RELOC(bootx_text_mapped) = 0;
#endif
prom_print(RELOC("returning from prom_init\n"));
@@ -820,6 +834,45 @@ prom_welcome(boot_infos_t* bi, unsigned long phys)
}
prom_drawstring(RELOC("\n\n"));
}
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BATH and disp_BATL. Those values are then used
+ * from head.S to map the display during identify_machine()
+ * and MMU_Init()
+ *
+ * For now, the display is mapped in place (1:1). This should
+ * be changed if the display physical address overlaps
+ * KERNELBASE, which is fortunately not the case on any machine
+ * I know of. This mapping is temporary and will disappear as
+ * soon as the setup done by MMU_Init() is applied
+ *
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+__init
+static void
+prepare_disp_BAT(void)
+{
+ unsigned long offset = reloc_offset();
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
+ unsigned long addr = (unsigned long)bi->dispDeviceBase;
+
+ if ((_get_PVR() >> 16) != 1) {
+ /* 603, 604, G3, G4, ... */
+ addr &= 0xFF000000UL;
+ RELOC(disp_BATU) = addr | (BL_16M<<2) | 2;
+ RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
+ } else {
+ /* 601 */
+ addr &= 0xFF800000UL;
+ RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+ RELOC(disp_BATL) = addr | BL_8M | 0x40;
+ }
+ bi->logicalDisplayBase = bi->dispDeviceBase;
+}
+
#endif
static int prom_set_color(ihandle ih, int i, int r, int g, int b)
@@ -1133,14 +1186,14 @@ finish_device_tree(void)
/* All newworld machines now use the interrupt tree */
struct device_node *np = allnodes;
- while(np) {
+ while(np && (_machine == _MACH_Pmac)) {
if (get_property(np, "interrupt-parent", 0)) {
pmac_newworld = 1;
break;
}
np = np->allnext;
}
- if (boot_infos == 0 && pmac_newworld)
+ if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
use_of_interrupt_tree = 1;
mem = finish_node(allnodes, mem, NULL, 0, 0);
@@ -1746,8 +1799,17 @@ find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
int l;
for (np = allnodes; np != 0; np = np->allnext) {
- if (np->parent == NULL || np->parent->type == NULL
- || strcmp(np->parent->type, "pci") != 0)
+ int in_macio = 0;
+ struct device_node* parent = np->parent;
+ while(parent) {
+ char *pname = (char *)get_property(parent, "name", &l);
+ if (pname && strcmp(pname, "mac-io") == 0) {
+ in_macio = 1;
+ break;
+ }
+ parent = parent->parent;
+ }
+ if (in_macio)
continue;
reg = (unsigned int *) get_property(np, "reg", &l);
if (reg == 0 || l < sizeof(struct reg_property))
@@ -2014,11 +2076,14 @@ __init
void
map_bootx_text(void)
{
+ unsigned long base, offset, size;
if (disp_bi == 0)
return;
- disp_bi->logicalDisplayBase =
- ioremap((unsigned long) disp_bi->dispDeviceBase,
- disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
+ base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
+ offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
+ size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
+ + disp_bi->dispDeviceRect[0];
+ disp_bi->logicalDisplayBase = ioremap(base, size) + offset;
bootx_text_mapped = 1;
}
@@ -2084,6 +2149,7 @@ flushscreen(void)
}
}
+#ifndef NO_SCROLL
__pmac
static void
scrollscreen(void)
@@ -2113,6 +2179,7 @@ scrollscreen(void)
dst += (bi->dispDeviceRowBytes >> 2);
}
}
+#endif /* ndef NO_SCROLL */
__pmac
void
@@ -2148,7 +2215,7 @@ prom_drawchar(char c)
RELOC(g_loc_Y)++;
cline = 1;
}
-#if 0
+#ifndef NO_SCROLL
while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
scrollscreen();
RELOC(g_loc_Y)--;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 6c0c38273..67387cca0 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -75,9 +75,6 @@ extern void gemini_init(unsigned long r3,
unsigned long r6,
unsigned long r7);
-#ifdef CONFIG_BOOTX_TEXT
-extern void map_bootx_text(void);
-#endif
#ifdef CONFIG_XMON
extern void xmon_map_scc(void);
#endif
@@ -110,6 +107,14 @@ unsigned long SYSRQ_KEY;
struct machdep_calls ppc_md;
/*
+ * These are used in binfmt_elf.c to put aux entries on the stack
+ * for each elf executable being started.
+ */
+int dcache_bsize;
+int icache_bsize;
+int ucache_bsize;
+
+/*
* Perhaps we can put the pmac screen_info[] here
* on pmac as well so we don't need the ifdef's.
* Until we get multiple-console support in here
@@ -131,14 +136,6 @@ struct screen_info screen_info = {
};
/*
- * These are used in binfmt_elf.c to put aux entries on the stack
- * for each elf executable being started.
- */
-int dcache_bsize;
-int icache_bsize;
-int ucache_bsize;
-
-/*
* I really need to add multiple-console support... -- Cort
*/
int __init pmac_display_supported(char *name)
@@ -286,7 +283,7 @@ int get_cpuinfo(char *buffer)
case 0x000C:
len += sprintf(len+buffer, "7400 (G4");
#ifdef CONFIG_ALTIVEC
- len += sprintf(len+buffer, ", altivec enabled");
+ len += sprintf(len+buffer, ", altivec supported");
#endif /* CONFIG_ALTIVEC */
len += sprintf(len+buffer, ")\n");
break;
@@ -686,14 +683,9 @@ void __init setup_arch(char **cmdline_p)
extern char *klimit;
extern void do_init_bootmem(void);
-#ifdef CONFIG_BOOTX_TEXT
- map_bootx_text();
-#endif
-
#ifdef CONFIG_ALL_PPC
feature_init();
#endif
-
#ifdef CONFIG_XMON
xmon_map_scc();
if (strstr(cmd_line, "xmon"))
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index ee7ba852c..79847fa0d 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -1,8 +1,6 @@
/*
* linux/arch/ppc/kernel/signal.c
*
- * $Id: signal.c,v 1.27 1999/08/03 19:16:38 cort Exp $
- *
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
@@ -156,13 +154,6 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
}
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
- printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n",
- current->comm,current->pid);
- do_exit(SIGSEGV);
-}
-
asmlinkage int
sys_sigaltstack(const stack_t *uss, stack_t *uoss)
{
@@ -206,13 +197,11 @@ sys_sigaction(int sig, const struct old_sigaction *act,
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* a sigregs struct
- * one or more sigcontext structs
+ * one or more sigcontext structs with
* a gap of __SIGNAL_FRAMESIZE bytes
*
* Each of these things must be a multiple of 16 bytes in size.
*
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
*/
struct sigregs {
elf_gregset_t gp_regs;
@@ -223,6 +212,149 @@ struct sigregs {
int abigap[56];
};
+struct rt_sigframe
+{
+ unsigned long _unused[2];
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+
+/*
+ * When we have rt signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ * a sigregs struct
+ * one rt_sigframe struct (siginfo + ucontext)
+ * a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ */
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe *rt_sf;
+ struct sigcontext_struct sigctx;
+ struct sigregs *sr;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
+ sigset_t set;
+ stack_t st;
+ unsigned long prevsp;
+
+ rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
+ || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
+ || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ rt_sf++; /* Look at next rt_sigframe */
+ if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers -
+ * sigctx is initialized to point to the
+ * preamble frame (where registers are stored)
+ * see handle_signal()
+ */
+ sr = (struct sigregs *) sigctx.regs;
+ if (regs->msr & MSR_FP )
+ giveup_fpu(current);
+ if (copy_from_user(saved_regs, &sr->gp_regs,
+ sizeof(sr->gp_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs, GP_REGS_SIZE);
+ if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+ sizeof(sr->fp_regs)))
+ goto badframe;
+ /* This function sets back the stack flags into
+ the current task structure. */
+ sys_sigaltstack(&st, NULL);
+
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ /* Set up registers for next signal handler */
+ regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
+ goto badframe;
+ sr = (struct sigregs *) sigctx.regs;
+ regs->gpr[3] = ret = sigctx.signal;
+ /* Get the siginfo */
+ get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
+ /* Get the ucontext */
+ get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
+ regs->gpr[6] = (unsigned long) rt_sf;
+
+ regs->link = (unsigned long) &sr->tramp;
+ regs->nip = sigctx.handler;
+ if (get_user(prevsp, &sr->gp_regs[PT_R1])
+ || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+ goto badframe;
+ }
+ return ret;
+
+badframe:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+static void
+setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
+ signed long newsp)
+{
+ struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+
+ /* Set up preamble frame */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto badframe;
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
+ if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
+ || __copy_to_user(&frame->fp_regs, current->thread.fpr,
+ ELF_NFPREG * sizeof(double))
+ /* Set up to return from user space.
+ It calls the sc exception at offset 0x9999
+ for sys_rt_sigreturn().
+ */
+ || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */
+ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
+ goto badframe;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+
+ /* Retrieve rt_sigframe from stack and
+ set up registers for signal handler
+ */
+ newsp -= __SIGNAL_FRAMESIZE;
+ if (put_user(regs->gpr[1], (unsigned long *)newsp)
+ || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
+ || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+ || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
+ || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+ goto badframe;
+
+ regs->gpr[1] = newsp;
+ regs->gpr[6] = (unsigned long) rt_sf;
+ regs->link = (unsigned long) frame->tramp;
+
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+ regs, frame, newsp);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -341,6 +473,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
unsigned long *newspp, unsigned long frame)
{
struct sigcontext_struct *sc;
+ struct rt_sigframe *rt_sf;
if (regs->trap == 0x0C00 /* System Call! */
&& ((int)regs->result == -ERESTARTNOHAND ||
@@ -348,20 +481,47 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
!(ka->sa.sa_flags & SA_RESTART))))
regs->result = -EINTR;
- /* Put another sigcontext on the stack */
- *newspp -= sizeof(*sc);
- sc = (struct sigcontext_struct *) *newspp;
- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
- goto badframe;
+ /* Set up Signal Frame */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* Put a Real Time Context onto stack */
+ *newspp -= sizeof(*rt_sf);
+ rt_sf = (struct rt_sigframe *) *newspp;
+ if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
+ goto badframe;
- if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
- || __put_user(oldset->sig[0], &sc->oldmask)
+ if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
+ || __put_user(&rt_sf->info, &rt_sf->pinfo)
+ || __put_user(&rt_sf->uc, &rt_sf->puc)
+ /* Put the siginfo */
+ || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+ /* Create the ucontext */
+ || __put_user(0, &rt_sf->uc.uc_flags)
+ || __put_user(0, &rt_sf->uc.uc_link)
+ || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+ || __put_user(sas_ss_flags(regs->gpr[1]),
+ &rt_sf->uc.uc_stack.ss_flags)
+ || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+ || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
+ /* mcontext.regs points to preamble register frame */
+ || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
+ || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
+ goto badframe;
+ } else {
+ /* Put another sigcontext on the stack */
+ *newspp -= sizeof(*sc);
+ sc = (struct sigcontext_struct *) *newspp;
+ if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+ goto badframe;
+
+ if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+ || __put_user(oldset->sig[0], &sc->oldmask)
#if _NSIG_WORDS > 1
- || __put_user(oldset->sig[1], &sc->_unused[3])
+ || __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user((struct pt_regs *)frame, &sc->regs)
- || __put_user(sig, &sc->signal))
- goto badframe;
+ || __put_user((struct pt_regs *)frame, &sc->regs)
+ || __put_user(sig, &sc->signal))
+ goto badframe;
+ }
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
@@ -517,7 +677,10 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (newsp == frame)
return 0; /* no signals delivered */
- setup_frame(regs, (struct sigregs *) frame, newsp);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+ else
+ setup_frame(regs, (struct sigregs *) frame, newsp);
return 1;
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 176a47ca5..8cb68c6b2 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -39,7 +39,7 @@
#include <asm/smp.h>
#include <asm/gemini.h>
-#include "time.h"
+#include <asm/time.h>
#include "open_pic.h"
int smp_threads_ready = 0;
volatile int smp_commenced = 0;
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index 11aa42cad..4c1802135 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -274,3 +274,13 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
error = error ? -EFAULT : 0;
return error;
}
+
+#ifndef CONFIG_PCI
+/*
+ * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
+ * not defined, this file is not linked at all, so here are the "empty" versions
+ */
+asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
+asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
+asmlinkage long sys_pciconfig_iobase() { return -ENOSYS; }
+#endif
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 3303bf785..aff4838b3 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -44,7 +44,7 @@
#include <asm/8xx_immap.h>
#include <asm/machdep.h>
-#include "time.h"
+#include <asm/time.h>
void smp_local_timer_interrupt(struct pt_regs *);
@@ -70,7 +70,9 @@ unsigned long last_tb;
int timer_interrupt(struct pt_regs * regs)
{
int dval, d;
+#if 0
unsigned long flags;
+#endif
unsigned long cpu = smp_processor_id();
hardirq_enter(cpu);
@@ -120,6 +122,13 @@ int timer_interrupt(struct pt_regs * regs)
if ( !smp_processor_id() )
{
do_timer(regs);
+#if 0
+ /* -- BenH -- I'm removing this for now since it can cause various
+ * troubles with local-time RTCs. Now that we have a
+ * /dev/rtc that uses ppc_md.set_rtc_time() on mac, it
+ * should be possible to program the RTC from userland
+ * in all cases.
+ */
/*
* update the rtc when needed
*/
@@ -135,6 +144,7 @@ int timer_interrupt(struct pt_regs * regs)
last_rtc_update = xtime.tv_sec;
}
read_unlock_irqrestore(&xtime_lock, flags);
+#endif
}
#ifdef CONFIG_SMP
smp_local_timer_interrupt(regs);
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
deleted file mode 100644
index 05d791546..000000000
--- a/arch/ppc/kernel/time.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * $Id: time.h,v 1.12 1999/08/27 04:21:23 cort Exp $
- * Common time prototypes and such for all ppc machines.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu) to merge
- * Paul Mackerras' version and mine for PReP and Pmac.
- */
-
-#include <linux/config.h>
-#include <linux/mc146818rtc.h>
-
-#include <asm/processor.h>
-
-/* time.c */
-extern unsigned decrementer_count;
-extern unsigned count_period_num;
-extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int);
-extern void to_tm(int tim, struct rtc_time * tm);
-extern time_t last_rtc_update;
-
-int via_calibrate_decr(void);
-
-/* Accessor functions for the decrementer register. */
-static __inline__ unsigned int get_dec(void)
-{
-#if defined(CONFIG_4xx)
- return (mfspr(SPRN_PIT));
-#else
- return (mfspr(SPRN_DEC));
-#endif
-}
-
-static __inline__ void set_dec(unsigned int val)
-{
-#if defined(CONFIG_4xx)
- mtspr(SPRN_PIT, val);
-#else
- mtspr(SPRN_DEC, val);
-#endif
-}
diff --git a/arch/ppc/kernel/walnut_setup.c b/arch/ppc/kernel/walnut_setup.c
index 284c732c1..768c36a94 100644
--- a/arch/ppc/kernel/walnut_setup.c
+++ b/arch/ppc/kernel/walnut_setup.c
@@ -28,7 +28,7 @@
#include "local_irq.h"
#include "ppc4xx_pic.h"
-#include "time.h"
+#include <asm/time.h>
#include "walnut_setup.h"
diff --git a/arch/ppc/mbxboot/m8xx_tty.c b/arch/ppc/mbxboot/m8xx_tty.c
index a591d824d..811a13796 100644
--- a/arch/ppc/mbxboot/m8xx_tty.c
+++ b/arch/ppc/mbxboot/m8xx_tty.c
@@ -21,6 +21,17 @@
#define CSR1_COMEN (u_char)0x02
#endif
+#ifdef TQM_SMC2_CONSOLE
+#define PROFF_CONS PROFF_SMC2
+#define CPM_CR_CH_CONS CPM_CR_CH_SMC2
+#define SMC_INDEX 1
+static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport);
+#else
+#define PROFF_CONS PROFF_SMC1
+#define CPM_CR_CH_CONS CPM_CR_CH_SMC1
+#define SMC_INDEX 0
+#endif
+
static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
void
@@ -33,8 +44,8 @@ serial_init(bd_t *bd)
uint dpaddr, memaddr;
cp = cpmp;
- sp = (smc_t*)&(cp->cp_smc[0]);
- up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
+ sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]);
+ up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS];
/* Disable transmitter/receiver.
*/
@@ -42,18 +53,26 @@ serial_init(bd_t *bd)
#ifndef CONFIG_MBX
{
- /* Initialize SMC1 and use it for the console port.
+ /* Initialize SMCx and use it for the console port.
*/
/* Enable SDMA.
*/
((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1;
+#ifdef TQM_SMC2_CONSOLE
+ /* Use Port A for SMC2 instead of other functions.
+ */
+ iopp->iop_papar |= 0x00c0;
+ iopp->iop_padir &= ~0x00c0;
+ iopp->iop_paodr &= ~0x00c0;
+#else
/* Use Port B for SMCs instead of other functions.
*/
cp->cp_pbpar |= 0x00000cc0;
cp->cp_pbdir &= ~0x00000cc0;
cp->cp_pbodr &= ~0x00000cc0;
+#endif
/* Allocate space for two buffer descriptors in the DP ram.
* For now, this address seems OK, but it may have to
@@ -61,8 +80,7 @@ serial_init(bd_t *bd)
*/
dpaddr = 0x0800;
- /* Grab a few bytes from the top of memory. EPPC-Bug isn't
- * running any more, so we can do this.
+ /* Grab a few bytes from the top of memory for SMC FIFOs.
*/
memaddr = (bd->bi_memsize - 32) & ~15;
@@ -95,9 +113,14 @@ serial_init(bd_t *bd)
/* Set up the baud rate generator.
* See 8xx_io/commproc.c for details.
+ * This wires BRG1 to SMC1 and BRG2 to SMC2;
*/
cp->cp_simode = 0x10000000;
+#ifdef TQM_SMC2_CONSOLE
+ cp->cp_brgc2 =
+#else
cp->cp_brgc1 =
+#endif
((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN;
#else /* CONFIG_MBX */
@@ -167,14 +190,14 @@ serial_init(bd_t *bd)
}
else {
#endif /* ndef CONFIG_MBX */
- /* SMC1 is used as console port.
+ /* SMCx is used as console port.
*/
tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase];
rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase];
/* Issue a stop transmit, and wait for it.
*/
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1,
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS,
CPM_CR_STOP_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
@@ -191,7 +214,7 @@ serial_init(bd_t *bd)
/* Initialize Tx/Rx parameters.
*/
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Enable transmitter/receiver.
@@ -206,7 +229,7 @@ serial_putchar(const char c)
volatile char *buf;
volatile smc_uart_t *up;
- up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
/* Wait for last character to go.
@@ -227,7 +250,7 @@ serial_getc()
volatile smc_uart_t *up;
char c;
- up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
/* Wait for character to show up.
@@ -246,7 +269,7 @@ serial_tstc()
volatile cbd_t *rbdf;
volatile smc_uart_t *up;
- up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
return(!(rbdf->cbd_sc & BD_SC_EMPTY));
diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c
index d5a44df1e..60563122d 100644
--- a/arch/ppc/mbxboot/misc.c
+++ b/arch/ppc/mbxboot/misc.c
@@ -225,7 +225,9 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
s.avail_out = dstlen;
r = inflate(&s, Z_FINISH);
if (r != Z_OK && r != Z_STREAM_END) {
- puts("inflate returned %d\n");
+ puts("inflate returned ");
+ puthex(r);
+ puts("\n");
exit();
}
*lenp = s.next_out - (unsigned char *) dst;
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 0cfb5916c..16c3bc694 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -931,6 +931,9 @@ MMU_init(void)
/* How about ppc_md.md_find_end_of_memory instead of these
* ifdefs? -- Dan.
*/
+#ifdef CONFIG_BOOTX_TEXT
+extern boot_infos_t *disp_bi;
+#endif
void __init MMU_init(void)
{
if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
@@ -1050,6 +1053,11 @@ void __init MMU_init(void)
#endif
#endif /* CONFIG_8xx */
if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211);
+#ifdef CONFIG_BOOTX_TEXT
+ /* Must be done last, or ppc_md.progress will die */
+ if (_machine == _MACH_Pmac)
+ map_bootx_text();
+#endif
}
#endif /* CONFIG_4xx */
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
index 4abc138cf..75160d9b8 100644
--- a/arch/ppc/xmon/xmon.c
+++ b/arch/ppc/xmon/xmon.c
@@ -84,8 +84,10 @@ static void insert_bpts(void);
static struct bpt *at_breakpoint(unsigned pc);
static void bpt_cmds(void);
static void cacheflush(void);
+#if 0 /* Makes compile with -Wall */
static char *pretty_print_addr(unsigned long addr);
static char *lookup_name(unsigned long addr);
+#endif
static void csum(void);
extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
@@ -1493,6 +1495,7 @@ char *str;
lineptr = str;
}
+#if 0 /* Makes compile with -Wall */
static char *pretty_print_addr(unsigned long addr)
{
printf("%08x", addr);
@@ -1500,14 +1503,15 @@ static char *pretty_print_addr(unsigned long addr)
printf(" %s", lookup_name(addr) );
return NULL;
}
+#endif
+#if 0 /* Makes compile with -Wall */
static char *lookup_name(unsigned long addr)
{
extern char *sysmap;
extern unsigned long sysmap_size;
char *c = sysmap;
unsigned long cmp;
-
if ( !sysmap || !sysmap_size )
return NULL;
return NULL;
@@ -1525,4 +1529,4 @@ return NULL;
return last;
#endif
}
-
+#endif