Commit c16a85a5 authored by Finn Thain's avatar Finn Thain Committed by Michael Ellerman

macintosh/via-pmu: Add support for m68k PowerBooks

Put #ifdefs around the Open Firmware, xmon, interrupt dispatch,
battery and suspend code. Add the necessary interrupt handling to
support m68k PowerBooks.

The pmu_kind value is available to userspace using the
PMU_IOC_GET_MODEL ioctl. It is not clear yet what hardware classes
are be needed to describe m68k PowerBook models, so pmu_kind is given
the provisional value PMU_UNKNOWN.

To find out about the hardware, user programs can use /proc/bootinfo
or /proc/hardware, or send the PMU_GET_VERSION command using /dev/adb.
Tested-by: default avatarStan Johnson <userm57@yahoo.com>
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent c70c35da
...@@ -65,7 +65,7 @@ config ADB_CUDA ...@@ -65,7 +65,7 @@ config ADB_CUDA
If unsure say Y. If unsure say Y.
config ADB_PMU config ADB_PMU
bool "Support for PMU based PowerMacs" bool "Support for PMU based PowerMacs and PowerBooks"
depends on PPC_PMAC depends on PPC_PMAC
help help
On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Device driver for the via-pmu on Apple Powermacs. * Device driver for the PMU in Apple PowerBooks and PowerMacs.
* *
* The VIA (versatile interface adapter) interfaces to the PMU, * The VIA (versatile interface adapter) interfaces to the PMU,
* a 6805 microprocessor core whose primary function is to control * a 6805 microprocessor core whose primary function is to control
...@@ -49,20 +49,26 @@ ...@@ -49,20 +49,26 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <asm/prom.h> #include <linux/uaccess.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/irq.h> #include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h> #include <asm/pmac_feature.h>
#include <asm/pmac_pfunc.h> #include <asm/pmac_pfunc.h>
#include <asm/pmac_low_i2c.h> #include <asm/pmac_low_i2c.h>
#include <linux/uaccess.h> #include <asm/prom.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/backlight.h> #include <asm/backlight.h>
#else
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_via.h>
#endif
#include "via-pmu-event.h" #include "via-pmu-event.h"
...@@ -97,8 +103,13 @@ static DEFINE_MUTEX(pmu_info_proc_mutex); ...@@ -97,8 +103,13 @@ static DEFINE_MUTEX(pmu_info_proc_mutex);
#define ANH (15*RS) /* A-side data, no handshake */ #define ANH (15*RS) /* A-side data, no handshake */
/* Bits in B data register: both active low */ /* Bits in B data register: both active low */
#ifdef CONFIG_PPC_PMAC
#define TACK 0x08 /* Transfer acknowledge (input) */ #define TACK 0x08 /* Transfer acknowledge (input) */
#define TREQ 0x10 /* Transfer request (output) */ #define TREQ 0x10 /* Transfer request (output) */
#else
#define TACK 0x02
#define TREQ 0x04
#endif
/* Bits in ACR */ /* Bits in ACR */
#define SR_CTRL 0x1c /* Shift register control bits */ #define SR_CTRL 0x1c /* Shift register control bits */
...@@ -140,13 +151,15 @@ static int data_index; ...@@ -140,13 +151,15 @@ static int data_index;
static int data_len; static int data_len;
static volatile int adb_int_pending; static volatile int adb_int_pending;
static volatile int disable_poll; static volatile int disable_poll;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN; static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited; static int pmu_fully_inited;
static int pmu_has_adb; static int pmu_has_adb;
#ifdef CONFIG_PPC_PMAC
static volatile unsigned char __iomem *via1; static volatile unsigned char __iomem *via1;
static volatile unsigned char __iomem *via2; static volatile unsigned char __iomem *via2;
static struct device_node *vias;
static struct device_node *gpio_node; static struct device_node *gpio_node;
#endif
static unsigned char __iomem *gpio_reg; static unsigned char __iomem *gpio_reg;
static int gpio_irq = 0; static int gpio_irq = 0;
static int gpio_irq_enabled = -1; static int gpio_irq_enabled = -1;
...@@ -273,6 +286,7 @@ static char *pbook_type[] = { ...@@ -273,6 +286,7 @@ static char *pbook_type[] = {
int __init find_via_pmu(void) int __init find_via_pmu(void)
{ {
#ifdef CONFIG_PPC_PMAC
u64 taddr; u64 taddr;
const u32 *reg; const u32 *reg;
...@@ -355,9 +369,6 @@ int __init find_via_pmu(void) ...@@ -355,9 +369,6 @@ int __init find_via_pmu(void)
if (!init_pmu()) if (!init_pmu())
goto fail_init; goto fail_init;
printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
sys_ctrler = SYS_CTRLER_PMU; sys_ctrler = SYS_CTRLER_PMU;
return 1; return 1;
...@@ -373,6 +384,30 @@ int __init find_via_pmu(void) ...@@ -373,6 +384,30 @@ int __init find_via_pmu(void)
vias = NULL; vias = NULL;
pmu_state = uninitialized; pmu_state = uninitialized;
return 0; return 0;
#else
if (macintosh_config->adb_type != MAC_ADB_PB2)
return 0;
pmu_kind = PMU_UNKNOWN;
spin_lock_init(&pmu_lock);
pmu_has_adb = 1;
pmu_intr_mask = PMU_INT_PCEJECT |
PMU_INT_SNDBRT |
PMU_INT_ADB |
PMU_INT_TICK;
pmu_state = idle;
if (!init_pmu()) {
pmu_state = uninitialized;
return 0;
}
return 1;
#endif /* !CONFIG_PPC_PMAC */
} }
#ifdef CONFIG_ADB #ifdef CONFIG_ADB
...@@ -396,13 +431,14 @@ static int pmu_init(void) ...@@ -396,13 +431,14 @@ static int pmu_init(void)
*/ */
static int __init via_pmu_start(void) static int __init via_pmu_start(void)
{ {
unsigned int irq; unsigned int __maybe_unused irq;
if (pmu_state == uninitialized) if (pmu_state == uninitialized)
return -ENODEV; return -ENODEV;
batt_req.complete = 1; batt_req.complete = 1;
#ifdef CONFIG_PPC_PMAC
irq = irq_of_parse_and_map(vias, 0); irq = irq_of_parse_and_map(vias, 0);
if (!irq) { if (!irq) {
printk(KERN_ERR "via-pmu: can't map interrupt\n"); printk(KERN_ERR "via-pmu: can't map interrupt\n");
...@@ -439,6 +475,19 @@ static int __init via_pmu_start(void) ...@@ -439,6 +475,19 @@ static int __init via_pmu_start(void)
/* Enable interrupts */ /* Enable interrupts */
out_8(&via1[IER], IER_SET | SR_INT | CB1_INT); out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
#else
if (request_irq(IRQ_MAC_ADB_SR, via_pmu_interrupt, IRQF_NO_SUSPEND,
"VIA-PMU-SR", NULL)) {
pr_err("%s: couldn't get SR irq\n", __func__);
return -ENODEV;
}
if (request_irq(IRQ_MAC_ADB_CL, via_pmu_interrupt, IRQF_NO_SUSPEND,
"VIA-PMU-CL", NULL)) {
pr_err("%s: couldn't get CL irq\n", __func__);
free_irq(IRQ_MAC_ADB_SR, NULL);
return -ENODEV;
}
#endif /* !CONFIG_PPC_PMAC */
pmu_fully_inited = 1; pmu_fully_inited = 1;
...@@ -589,6 +638,10 @@ init_pmu(void) ...@@ -589,6 +638,10 @@ init_pmu(void)
option_server_mode ? "enabled" : "disabled"); option_server_mode ? "enabled" : "disabled");
} }
} }
printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
return 1; return 1;
} }
...@@ -627,6 +680,7 @@ static void pmu_set_server_mode(int server_mode) ...@@ -627,6 +680,7 @@ static void pmu_set_server_mode(int server_mode)
static void static void
done_battery_state_ohare(struct adb_request* req) done_battery_state_ohare(struct adb_request* req)
{ {
#ifdef CONFIG_PPC_PMAC
/* format: /* format:
* [0] : flags * [0] : flags
* 0x01 : AC indicator * 0x01 : AC indicator
...@@ -708,6 +762,7 @@ done_battery_state_ohare(struct adb_request* req) ...@@ -708,6 +762,7 @@ done_battery_state_ohare(struct adb_request* req)
pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].amperage = amperage;
pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].voltage = voltage;
pmu_batteries[pmu_cur_battery].time_remaining = time; pmu_batteries[pmu_cur_battery].time_remaining = time;
#endif /* CONFIG_PPC_PMAC */
clear_bit(0, &async_req_locks); clear_bit(0, &async_req_locks);
} }
...@@ -1356,6 +1411,7 @@ pmu_handle_data(unsigned char *data, int len) ...@@ -1356,6 +1411,7 @@ pmu_handle_data(unsigned char *data, int len)
} }
pmu_done(req); pmu_done(req);
} else { } else {
#ifdef CONFIG_XMON
if (len == 4 && data[1] == 0x2c) { if (len == 4 && data[1] == 0x2c) {
extern int xmon_wants_key, xmon_adb_keycode; extern int xmon_wants_key, xmon_adb_keycode;
if (xmon_wants_key) { if (xmon_wants_key) {
...@@ -1363,6 +1419,7 @@ pmu_handle_data(unsigned char *data, int len) ...@@ -1363,6 +1419,7 @@ pmu_handle_data(unsigned char *data, int len)
return; return;
} }
} }
#endif /* CONFIG_XMON */
#ifdef CONFIG_ADB #ifdef CONFIG_ADB
/* /*
* XXX On the [23]400 the PMU gives us an up * XXX On the [23]400 the PMU gives us an up
...@@ -1530,7 +1587,25 @@ via_pmu_interrupt(int irq, void *arg) ...@@ -1530,7 +1587,25 @@ via_pmu_interrupt(int irq, void *arg)
++disable_poll; ++disable_poll;
for (;;) { for (;;) {
/* On 68k Macs, VIA interrupts are dispatched individually.
* Unless we are polling, the relevant IRQ flag has already
* been cleared.
*/
intr = 0;
if (IS_ENABLED(CONFIG_PPC_PMAC) || !irq) {
intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT); intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT);
out_8(&via1[IFR], intr);
}
#ifndef CONFIG_PPC_PMAC
switch (irq) {
case IRQ_MAC_ADB_CL:
intr = CB1_INT;
break;
case IRQ_MAC_ADB_SR:
intr = SR_INT;
break;
}
#endif
if (intr == 0) if (intr == 0)
break; break;
handled = 1; handled = 1;
...@@ -1540,7 +1615,6 @@ via_pmu_interrupt(int irq, void *arg) ...@@ -1540,7 +1615,6 @@ via_pmu_interrupt(int irq, void *arg)
intr, in_8(&via1[IER]), pmu_state); intr, in_8(&via1[IER]), pmu_state);
break; break;
} }
out_8(&via1[IFR], intr);
if (intr & CB1_INT) { if (intr & CB1_INT) {
adb_int_pending = 1; adb_int_pending = 1;
pmu_irq_stats[0]++; pmu_irq_stats[0]++;
...@@ -1550,6 +1624,9 @@ via_pmu_interrupt(int irq, void *arg) ...@@ -1550,6 +1624,9 @@ via_pmu_interrupt(int irq, void *arg)
if (req) if (req)
break; break;
} }
#ifndef CONFIG_PPC_PMAC
break;
#endif
} }
recheck: recheck:
...@@ -1616,7 +1693,7 @@ pmu_unlock(void) ...@@ -1616,7 +1693,7 @@ pmu_unlock(void)
} }
static irqreturn_t static __maybe_unused irqreturn_t
gpio1_interrupt(int irq, void *arg) gpio1_interrupt(int irq, void *arg)
{ {
unsigned long flags; unsigned long flags;
...@@ -2250,6 +2327,7 @@ static int pmu_ioctl(struct file *filp, ...@@ -2250,6 +2327,7 @@ static int pmu_ioctl(struct file *filp,
int error = -EINVAL; int error = -EINVAL;
switch (cmd) { switch (cmd) {
#ifdef CONFIG_PPC_PMAC
case PMU_IOC_SLEEP: case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
...@@ -2259,6 +2337,7 @@ static int pmu_ioctl(struct file *filp, ...@@ -2259,6 +2337,7 @@ static int pmu_ioctl(struct file *filp,
return put_user(0, argp); return put_user(0, argp);
else else
return put_user(1, argp); return put_user(1, argp);
#endif
#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
/* Compatibility ioctl's for backlight */ /* Compatibility ioctl's for backlight */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment