Merge master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc

* master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc: (194 commits)
  [POWERPC] Add missing EXPORTS for mpc52xx support
  [POWERPC] Remove obsolete PPC_52xx and update CLASSIC32 comment
  [POWERPC] ps3: add a default zImage target
  [POWERPC] Add of_platform_bus support to mpc52xx psc uart driver
  [POWERPC] typo fix and whitespace cleanup on mpc52xx-uart driver
  [POWERPC] Fix debug printks for 32-bit resources in the PCI code
  [POWERPC] Replace kmalloc+memset with kzalloc
  [POWERPC] Linkstation / kurobox support
  [POWERPC] Add the e300c3 core to the CPU table.
  [POWERPC] ppc: m48t35 add missing bracket
  [POWERPC] iSeries: don't build head_64.o unnecessarily
  [POWERPC] iSeries: stop dt_mod.o being rebuilt unnecessarily
  [POWERPC] Fix cputable.h for combined build
  [POWERPC] Allow CONFIG_BOOTX_TEXT on iSeries
  [POWERPC] Allow xmon to build on legacy iSeries
  [POWERPC] Change ppc64_defconfig to use AUTOFS_V4 not V3
  [POWERPC] Tell firmware we can handle POWER6 compatible mode
  [POWERPC] Clean images in arch/powerpc/boot
  [POWERPC] Fix OF pci flags parsing
  [POWERPC] defconfig for lite5200 board
  ...
This commit is contained in:
Linus Torvalds 2006-12-04 19:22:33 -08:00
commit 15a4cb9c25
298 changed files with 25464 additions and 5051 deletions

View file

@ -77,3 +77,4 @@ obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_PPC_PS3) += ps3/

View file

@ -759,6 +759,8 @@ static struct vio_driver viodasd_driver = {
}
};
static int need_delete_probe;
/*
* Initialize the whole device driver. Handle module and non-module
* versions
@ -773,46 +775,67 @@ static int __init viodasd_init(void)
if (viopath_hostLp == HvLpIndexInvalid) {
printk(VIOD_KERN_WARNING "invalid hosting partition\n");
return -EIO;
rc = -EIO;
goto early_fail;
}
printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n",
viopath_hostLp);
/* register the block device */
if (register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME)) {
rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
if (rc) {
printk(VIOD_KERN_WARNING
"Unable to get major number %d for %s\n",
VIODASD_MAJOR, VIOD_GENHD_NAME);
return -EIO;
goto early_fail;
}
/* Actually open the path to the hosting partition */
if (viopath_open(viopath_hostLp, viomajorsubtype_blockio,
VIOMAXREQ + 2)) {
rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
VIOMAXREQ + 2);
if (rc) {
printk(VIOD_KERN_WARNING
"error opening path to host partition %d\n",
viopath_hostLp);
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
return -EIO;
goto unregister_blk;
}
/* Initialize our request handler */
vio_setHandler(viomajorsubtype_blockio, handle_block_event);
rc = vio_register_driver(&viodasd_driver);
if (rc == 0)
driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
if (rc) {
printk(VIOD_KERN_WARNING "vio_register_driver failed\n");
goto unset_handler;
}
/*
* If this call fails, it just means that we cannot dynamically
* add virtual disks, but the driver will still work fine for
* all existing disk, so ignore the failure.
*/
if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe))
need_delete_probe = 1;
return 0;
unset_handler:
vio_clearHandler(viomajorsubtype_blockio);
viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
unregister_blk:
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
early_fail:
return rc;
}
module_init(viodasd_init);
void viodasd_exit(void)
void __exit viodasd_exit(void)
{
driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
if (need_delete_probe)
driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
vio_unregister_driver(&viodasd_driver);
vio_clearHandler(viomajorsubtype_blockio);
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
}
module_exit(viodasd_exit);

View file

@ -35,7 +35,7 @@
#include <linux/ide.h>
#include <asm/io.h>
#ifdef CONFIG_PPC_MULTIPLATFORM
#ifdef CONFIG_PPC_CHRP
#include <asm/processor.h>
#endif
@ -442,7 +442,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
hwif->speedproc = &via_set_drive;
#if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32)
#ifdef CONFIG_PPC_CHRP
if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
hwif->irq = hwif->channel ? 15 : 14;
}

View file

@ -228,4 +228,11 @@ config ANSLCD
tristate "Support for ANS LCD display"
depends on ADB_CUDA && PPC_PMAC
config PMAC_RACKMETER
tristate "Support for Apple XServe front panel LEDs"
depends on PPC_PMAC
help
This driver procides some support to control the front panel
blue LEDs "vu-meter" of the XServer macs.
endmenu

View file

@ -42,3 +42,4 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
windfarm_smu_sensors.o \
windfarm_max6690_sensor.o \
windfarm_lm75_sensor.o windfarm_pid.o
obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o

View file

@ -0,0 +1,612 @@
/*
* RackMac vu-meter driver
*
* (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
* Released under the term of the GNU GPL v2.
*
* Support the CPU-meter LEDs of the Xserve G5
*
* TODO: Implement PWM to do variable intensity and provide userland
* interface for fun. Also, the CPU-meter could be made nicer by being
* a bit less "immediate" but giving instead a more average load over
* time. Patches welcome :-)
*
*/
#undef DEBUG
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/kernel_stat.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
#include <asm/dbdma.h>
#include <asm/macio.h>
#include <asm/keylargo.h>
/* Number of samples in a sample buffer */
#define SAMPLE_COUNT 256
/* CPU meter sampling rate in ms */
#define CPU_SAMPLING_RATE 250
struct rackmeter_dma {
struct dbdma_cmd cmd[4] ____cacheline_aligned;
u32 mark ____cacheline_aligned;
u32 buf1[SAMPLE_COUNT] ____cacheline_aligned;
u32 buf2[SAMPLE_COUNT] ____cacheline_aligned;
} ____cacheline_aligned;
struct rackmeter_cpu {
struct work_struct sniffer;
cputime64_t prev_wall;
cputime64_t prev_idle;
int zero;
} ____cacheline_aligned;
struct rackmeter {
struct macio_dev *mdev;
unsigned int irq;
struct device_node *i2s;
u8 *ubuf;
struct dbdma_regs __iomem *dma_regs;
void __iomem *i2s_regs;
dma_addr_t dma_buf_p;
struct rackmeter_dma *dma_buf_v;
int stale_irq;
struct rackmeter_cpu cpu[2];
int paused;
struct mutex sem;
};
/* To be set as a tunable */
static int rackmeter_ignore_nice;
/* This GPIO is whacked by the OS X driver when initializing */
#define RACKMETER_MAGIC_GPIO 0x78
/* This is copied from cpufreq_ondemand, maybe we should put it in
* a common header somewhere
*/
static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
{
cputime64_t retval;
retval = cputime64_add(kstat_cpu(cpu).cpustat.idle,
kstat_cpu(cpu).cpustat.iowait);
if (rackmeter_ignore_nice)
retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice);
return retval;
}
static void rackmeter_setup_i2s(struct rackmeter *rm)
{
struct macio_chip *macio = rm->mdev->bus->chip;
/* First whack magic GPIO */
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, RACKMETER_MAGIC_GPIO, 5);
/* Call feature code to enable the sound channel and the proper
* clock sources
*/
pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, rm->i2s, 0, 1);
/* Power i2s and stop i2s clock. We whack MacIO FCRs directly for now.
* This is a bit racy, thus we should add new platform functions to
* handle that. snd-aoa needs that too
*/
MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE);
MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
(void)MACIO_IN32(KEYLARGO_FCR1);
udelay(10);
/* Then setup i2s. For now, we use the same magic value that
* the OS X driver seems to use. We might want to play around
* with the clock divisors later
*/
out_le32(rm->i2s_regs + 0x10, 0x01fa0000);
(void)in_le32(rm->i2s_regs + 0x10);
udelay(10);
/* Fully restart i2s*/
MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE |
KL1_I2S0_CLK_ENABLE_BIT);
(void)MACIO_IN32(KEYLARGO_FCR1);
udelay(10);
}
static void rackmeter_set_default_pattern(struct rackmeter *rm)
{
int i;
for (i = 0; i < 16; i++) {
if (i < 8)
rm->ubuf[i] = (i & 1) * 255;
else
rm->ubuf[i] = ((~i) & 1) * 255;
}
}
static void rackmeter_do_pause(struct rackmeter *rm, int pause)
{
struct rackmeter_dma *rdma = rm->dma_buf_v;
pr_debug("rackmeter: %s\n", pause ? "paused" : "started");
rm->paused = pause;
if (pause) {
DBDMA_DO_STOP(rm->dma_regs);
return;
}
memset(rdma->buf1, 0, SAMPLE_COUNT & sizeof(u32));
memset(rdma->buf2, 0, SAMPLE_COUNT & sizeof(u32));
rm->dma_buf_v->mark = 0;
mb();
out_le32(&rm->dma_regs->cmdptr_hi, 0);
out_le32(&rm->dma_regs->cmdptr, rm->dma_buf_p);
out_le32(&rm->dma_regs->control, (RUN << 16) | RUN);
}
static void rackmeter_setup_dbdma(struct rackmeter *rm)
{
struct rackmeter_dma *db = rm->dma_buf_v;
struct dbdma_cmd *cmd = db->cmd;
/* Make sure dbdma is reset */
DBDMA_DO_RESET(rm->dma_regs);
pr_debug("rackmeter: mark offset=0x%lx\n",
offsetof(struct rackmeter_dma, mark));
pr_debug("rackmeter: buf1 offset=0x%lx\n",
offsetof(struct rackmeter_dma, buf1));
pr_debug("rackmeter: buf2 offset=0x%lx\n",
offsetof(struct rackmeter_dma, buf2));
/* Prepare 4 dbdma commands for the 2 buffers */
memset(cmd, 0, 4 * sizeof(struct dbdma_cmd));
st_le16(&cmd->req_count, 4);
st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
st_le32(&cmd->phy_addr, rm->dma_buf_p +
offsetof(struct rackmeter_dma, mark));
st_le32(&cmd->cmd_dep, 0x02000000);
cmd++;
st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
st_le16(&cmd->command, OUTPUT_MORE);
st_le32(&cmd->phy_addr, rm->dma_buf_p +
offsetof(struct rackmeter_dma, buf1));
cmd++;
st_le16(&cmd->req_count, 4);
st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
st_le32(&cmd->phy_addr, rm->dma_buf_p +
offsetof(struct rackmeter_dma, mark));
st_le32(&cmd->cmd_dep, 0x01000000);
cmd++;
st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
st_le16(&cmd->command, OUTPUT_MORE | BR_ALWAYS);
st_le32(&cmd->phy_addr, rm->dma_buf_p +
offsetof(struct rackmeter_dma, buf2));
st_le32(&cmd->cmd_dep, rm->dma_buf_p);
rackmeter_do_pause(rm, 0);
}
static void rackmeter_do_timer(void *data)
{
struct rackmeter *rm = data;
unsigned int cpu = smp_processor_id();
struct rackmeter_cpu *rcpu = &rm->cpu[cpu];
cputime64_t cur_jiffies, total_idle_ticks;
unsigned int total_ticks, idle_ticks;
int i, offset, load, cumm, pause;
cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
total_ticks = (unsigned int)cputime64_sub(cur_jiffies,
rcpu->prev_wall);
rcpu->prev_wall = cur_jiffies;
total_idle_ticks = get_cpu_idle_time(cpu);
idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks,
rcpu->prev_idle);
rcpu->prev_idle = total_idle_ticks;
/* We do a very dumb calculation to update the LEDs for now,
* we'll do better once we have actual PWM implemented
*/
load = (9 * (total_ticks - idle_ticks)) / total_ticks;
offset = cpu << 3;
cumm = 0;
for (i = 0; i < 8; i++) {
u8 ub = (load > i) ? 0xff : 0;
rm->ubuf[i + offset] = ub;
cumm |= ub;
}
rcpu->zero = (cumm == 0);
/* Now check if LEDs are all 0, we can stop DMA */
pause = (rm->cpu[0].zero && rm->cpu[1].zero);
if (pause != rm->paused) {
mutex_lock(&rm->sem);
pause = (rm->cpu[0].zero && rm->cpu[1].zero);
rackmeter_do_pause(rm, pause);
mutex_unlock(&rm->sem);
}
schedule_delayed_work_on(cpu, &rcpu->sniffer,
msecs_to_jiffies(CPU_SAMPLING_RATE));
}
static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
{
unsigned int cpu;
/* This driver works only with 1 or 2 CPUs numbered 0 and 1,
* but that's really all we have on Apple Xserve. It doesn't
* play very nice with CPU hotplug neither but we don't do that
* on those machines yet
*/
INIT_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer, rm);
INIT_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer, rm);
for_each_online_cpu(cpu) {
struct rackmeter_cpu *rcpu;
if (cpu > 1)
continue;
rcpu = &rm->cpu[cpu];;
rcpu->prev_idle = get_cpu_idle_time(cpu);
rcpu->prev_wall = jiffies64_to_cputime64(get_jiffies_64());
schedule_delayed_work_on(cpu, &rm->cpu[cpu].sniffer,
msecs_to_jiffies(CPU_SAMPLING_RATE));
}
}
static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
{
cancel_rearming_delayed_work(&rm->cpu[0].sniffer);
cancel_rearming_delayed_work(&rm->cpu[1].sniffer);
}
static int rackmeter_setup(struct rackmeter *rm)
{
pr_debug("rackmeter: setting up i2s..\n");
rackmeter_setup_i2s(rm);
pr_debug("rackmeter: setting up default pattern..\n");
rackmeter_set_default_pattern(rm);
pr_debug("rackmeter: setting up dbdma..\n");
rackmeter_setup_dbdma(rm);
pr_debug("rackmeter: start CPU measurements..\n");
rackmeter_init_cpu_sniffer(rm);
printk(KERN_INFO "RackMeter initialized\n");
return 0;
}
/* XXX FIXME: No PWM yet, this is 0/1 */
static u32 rackmeter_calc_sample(struct rackmeter *rm, unsigned int index)
{
int led;
u32 sample = 0;
for (led = 0; led < 16; led++) {
sample >>= 1;
sample |= ((rm->ubuf[led] >= 0x80) << 15);
}
return (sample << 17) | (sample >> 15);
}
static irqreturn_t rackmeter_irq(int irq, void *arg)
{
struct rackmeter *rm = arg;
struct rackmeter_dma *db = rm->dma_buf_v;
unsigned int mark, i;
u32 *buf;
/* Flush PCI buffers with an MMIO read. Maybe we could actually
* check the status one day ... in case things go wrong, though
* this never happened to me
*/
(void)in_le32(&rm->dma_regs->status);
/* Make sure the CPU gets us in order */
rmb();
/* Read mark */
mark = db->mark;
if (mark != 1 && mark != 2) {
printk(KERN_WARNING "rackmeter: Incorrect DMA mark 0x%08x\n",
mark);
/* We allow for 3 errors like that (stale DBDMA irqs) */
if (++rm->stale_irq > 3) {
printk(KERN_ERR "rackmeter: Too many errors,"
" stopping DMA\n");
DBDMA_DO_RESET(rm->dma_regs);
}
return IRQ_HANDLED;
}
/* Next buffer we need to fill is mark value */
buf = mark == 1 ? db->buf1 : db->buf2;
/* Fill it now. This routine converts the 8 bits depth sample array
* into the PWM bitmap for each LED.
*/
for (i = 0; i < SAMPLE_COUNT; i++)
buf[i] = rackmeter_calc_sample(rm, i);
return IRQ_HANDLED;
}
static int __devinit rackmeter_probe(struct macio_dev* mdev,
const struct of_device_id *match)
{
struct device_node *i2s = NULL, *np = NULL;
struct rackmeter *rm = NULL;
struct resource ri2s, rdma;
int rc = -ENODEV;
pr_debug("rackmeter_probe()\n");
/* Get i2s-a node */
while ((i2s = of_get_next_child(mdev->ofdev.node, i2s)) != NULL)
if (strcmp(i2s->name, "i2s-a") == 0)
break;
if (i2s == NULL) {
pr_debug(" i2s-a child not found\n");
goto bail;
}
/* Get lightshow or virtual sound */
while ((np = of_get_next_child(i2s, np)) != NULL) {
if (strcmp(np->name, "lightshow") == 0)
break;
if ((strcmp(np->name, "sound") == 0) &&
get_property(np, "virtual", NULL) != NULL)
break;
}
if (np == NULL) {
pr_debug(" lightshow or sound+virtual child not found\n");
goto bail;
}
/* Create and initialize our instance data */
rm = kzalloc(sizeof(struct rackmeter), GFP_KERNEL);
if (rm == NULL) {
printk(KERN_ERR "rackmeter: failed to allocate memory !\n");
rc = -ENOMEM;
goto bail_release;
}
rm->mdev = mdev;
rm->i2s = i2s;
mutex_init(&rm->sem);
dev_set_drvdata(&mdev->ofdev.dev, rm);
/* Check resources availability. We need at least resource 0 and 1 */
#if 0 /* Use that when i2s-a is finally an mdev per-se */
if (macio_resource_count(mdev) < 2 || macio_irq_count(mdev) < 2) {
printk(KERN_ERR
"rackmeter: found match but lacks resources: %s"
" (%d resources, %d interrupts)\n",
mdev->ofdev.node->full_name);
rc = -ENXIO;
goto bail_free;
}
if (macio_request_resources(mdev, "rackmeter")) {
printk(KERN_ERR
"rackmeter: failed to request resources: %s\n",
mdev->ofdev.node->full_name);
rc = -EBUSY;
goto bail_free;
}
rm->irq = macio_irq(mdev, 1);
#else
rm->irq = irq_of_parse_and_map(i2s, 1);
if (rm->irq == NO_IRQ ||
of_address_to_resource(i2s, 0, &ri2s) ||
of_address_to_resource(i2s, 1, &rdma)) {
printk(KERN_ERR
"rackmeter: found match but lacks resources: %s",
mdev->ofdev.node->full_name);
rc = -ENXIO;
goto bail_free;
}
#endif
pr_debug(" i2s @0x%08x\n", (unsigned int)ri2s.start);
pr_debug(" dma @0x%08x\n", (unsigned int)rdma.start);
pr_debug(" irq %d\n", rm->irq);
rm->ubuf = (u8 *)__get_free_page(GFP_KERNEL);
if (rm->ubuf == NULL) {
printk(KERN_ERR
"rackmeter: failed to allocate samples page !\n");
rc = -ENOMEM;
goto bail_release;
}
rm->dma_buf_v = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev,
sizeof(struct rackmeter_dma),
&rm->dma_buf_p, GFP_KERNEL);
if (rm->dma_buf_v == NULL) {
printk(KERN_ERR
"rackmeter: failed to allocate dma buffer !\n");
rc = -ENOMEM;
goto bail_free_samples;
}
#if 0
rm->i2s_regs = ioremap(macio_resource_start(mdev, 0), 0x1000);
#else
rm->i2s_regs = ioremap(ri2s.start, 0x1000);
#endif
if (rm->i2s_regs == NULL) {
printk(KERN_ERR
"rackmeter: failed to map i2s registers !\n");
rc = -ENXIO;
goto bail_free_dma;
}
#if 0
rm->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x100);
#else
rm->dma_regs = ioremap(rdma.start, 0x100);
#endif
if (rm->dma_regs == NULL) {
printk(KERN_ERR
"rackmeter: failed to map dma registers !\n");
rc = -ENXIO;
goto bail_unmap_i2s;
}
rc = rackmeter_setup(rm);
if (rc) {
printk(KERN_ERR
"rackmeter: failed to initialize !\n");
rc = -ENXIO;
goto bail_unmap_dma;
}
rc = request_irq(rm->irq, rackmeter_irq, 0, "rackmeter", rm);
if (rc != 0) {
printk(KERN_ERR
"rackmeter: failed to request interrupt !\n");
goto bail_stop_dma;
}
of_node_put(np);
return 0;
bail_stop_dma:
DBDMA_DO_RESET(rm->dma_regs);
bail_unmap_dma:
iounmap(rm->dma_regs);
bail_unmap_i2s:
iounmap(rm->i2s_regs);
bail_free_dma:
dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
sizeof(struct rackmeter_dma),
rm->dma_buf_v, rm->dma_buf_p);
bail_free_samples:
free_page((unsigned long)rm->ubuf);
bail_release:
#if 0
macio_release_resources(mdev);
#endif
bail_free:
kfree(rm);
bail:
of_node_put(i2s);
of_node_put(np);
dev_set_drvdata(&mdev->ofdev.dev, NULL);
return rc;
}
static int __devexit rackmeter_remove(struct macio_dev* mdev)
{
struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
/* Stop CPU sniffer timer & work queues */
rackmeter_stop_cpu_sniffer(rm);
/* Clear reference to private data */
dev_set_drvdata(&mdev->ofdev.dev, NULL);
/* Stop/reset dbdma */
DBDMA_DO_RESET(rm->dma_regs);
/* Release the IRQ */
free_irq(rm->irq, rm);
/* Unmap registers */
iounmap(rm->dma_regs);
iounmap(rm->i2s_regs);
/* Free DMA */
dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
sizeof(struct rackmeter_dma),
rm->dma_buf_v, rm->dma_buf_p);
/* Free samples */
free_page((unsigned long)rm->ubuf);
#if 0
/* Release resources */
macio_release_resources(mdev);
#endif
/* Get rid of me */
kfree(rm);
return 0;
}
static int rackmeter_shutdown(struct macio_dev* mdev)
{
struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
if (rm == NULL)
return -ENODEV;
/* Stop CPU sniffer timer & work queues */
rackmeter_stop_cpu_sniffer(rm);
/* Stop/reset dbdma */
DBDMA_DO_RESET(rm->dma_regs);
return 0;
}
static struct of_device_id rackmeter_match[] = {
{ .name = "i2s" },
{ }
};
static struct macio_driver rackmeter_drv = {
.name = "rackmeter",
.owner = THIS_MODULE,
.match_table = rackmeter_match,
.probe = rackmeter_probe,
.remove = rackmeter_remove,
.shutdown = rackmeter_shutdown,
};
static int __init rackmeter_init(void)
{
pr_debug("rackmeter_init()\n");
return macio_register_driver(&rackmeter_drv);
}
static void __exit rackmeter_exit(void)
{
pr_debug("rackmeter_exit()\n");
macio_unregister_driver(&rackmeter_drv);
}
module_init(rackmeter_init);
module_exit(rackmeter_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
MODULE_DESCRIPTION("RackMeter: Support vu-meter on XServe front panel");

View file

@ -46,6 +46,7 @@
#include <asm/abs_addr.h>
#include <asm/uaccess.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#define VERSION "0.7"
#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void)
* I'm a bit too far from figuring out how that works with those
* new chipsets, but that will come back and bite us
*/
of_register_driver(&smu_of_platform_driver);
of_register_platform_driver(&smu_of_platform_driver);
return 0;
}

View file

@ -30,7 +30,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sections.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#undef DEBUG

View file

@ -129,6 +129,7 @@
#include <asm/sections.h>
#include <asm/of_device.h>
#include <asm/macio.h>
#include <asm/of_platform.h>
#include "therm_pm72.h"
@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void)
return -ENODEV;
}
of_register_driver(&fcu_of_platform_driver);
of_register_platform_driver(&fcu_of_platform_driver);
return 0;
}
static void __exit therm_pm72_exit(void)
{
of_unregister_driver(&fcu_of_platform_driver);
of_unregister_platform_driver(&fcu_of_platform_driver);
if (of_dev)
of_device_unregister(of_dev);

View file

@ -36,12 +36,13 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sections.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#include <asm/macio.h>
#define LOG_TEMP 0 /* continously log temperature */
@ -511,14 +512,14 @@ g4fan_init( void )
return -ENODEV;
}
of_register_driver( &therm_of_driver );
of_register_platform_driver( &therm_of_driver );
return 0;
}
static void __exit
g4fan_exit( void )
{
of_unregister_driver( &therm_of_driver );
of_unregister_platform_driver( &therm_of_driver );
if( x.of_dev )
of_device_unregister( x.of_dev );

View file

@ -24,6 +24,7 @@
#include <linux/netdevice.h>
#include <asm/io.h>
#include <asm/dcr.h>
/*
* These MAL "versions" probably aren't the real versions IBM uses for these
@ -191,6 +192,7 @@ struct mal_commac {
struct ibm_ocp_mal {
int dcrbase;
dcr_host_t dcrhost;
struct list_head poll_list;
struct net_device poll_dev;
@ -207,12 +209,12 @@ struct ibm_ocp_mal {
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
{
return mfdcr(mal->dcrbase + reg);
return dcr_read(mal->dcrhost, mal->dcrbase + reg);
}
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
{
mtdcr(mal->dcrbase + reg, val);
dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
}
/* Register MAL devices */

View file

@ -50,7 +50,6 @@
#include <asm/semaphore.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
#include <asm/iommu.h>
#include <asm/vio.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
@ -1000,8 +999,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
adapter->mac_addr = 0;
memcpy(&adapter->mac_addr, mac_addr_p, 6);
adapter->liobn = dev->iommu_table->it_index;
netdev->irq = dev->irq;
netdev->open = ibmveth_open;
netdev->poll = ibmveth_poll;
@ -1115,7 +1112,6 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
seq_printf(seq, "LIOBN: 0x%lx\n", adapter->liobn);
seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
current_mac[0], current_mac[1], current_mac[2],
current_mac[3], current_mac[4], current_mac[5]);

View file

@ -118,7 +118,6 @@ struct ibmveth_adapter {
struct net_device_stats stats;
unsigned int mcastFilterSize;
unsigned long mac_addr;
unsigned long liobn;
void * buffer_list_addr;
void * filter_list_addr;
dma_addr_t buffer_list_dma;

View file

@ -254,7 +254,7 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
goto device_create_fail;
}
phydev->irq = -1;
phydev->irq = PHY_IGNORE_INTERRUPT;
phydev->dev.bus = &mdio_bus_type;
if(number)

View file

@ -88,12 +88,11 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
static inline u32
spider_net_read_reg(struct spider_net_card *card, u32 reg)
{
u32 value;
value = readl(card->regs + reg);
value = le32_to_cpu(value);
return value;
/* We use the powerpc specific variants instead of readl_be() because
* we know spidernet is not a real PCI device and we can thus avoid the
* performance hit caused by the PCI workarounds.
*/
return in_be32(card->regs + reg);
}
/**
@ -105,8 +104,11 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg)
static inline void
spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
{
value = cpu_to_le32(value);
writel(value, card->regs + reg);
/* We use the powerpc specific variants instead of writel_be() because
* we know spidernet is not a real PCI device and we can thus avoid the
* performance hit caused by the PCI workarounds.
*/
out_be32(card->regs + reg, value);
}
/** spider_net_write_phy - write to phy register

View file

@ -473,9 +473,9 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
#ifdef CONFIG_PPC_MULTIPLATFORM
#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
#endif /* CONFIG_PPC_MULTIPLATFORM */
#endif /* CONFIG_PPC_PMAC */
#include "de4x5.h"
@ -4151,7 +4151,7 @@ get_hw_addr(struct net_device *dev)
/* If possible, try to fix a broken card - SMC only so far */
srom_repair(dev, broken);
#ifdef CONFIG_PPC_MULTIPLATFORM
#ifdef CONFIG_PPC_PMAC
/*
** If the address starts with 00 a0, we have to bit-reverse
** each byte of the address.
@ -4168,7 +4168,7 @@ get_hw_addr(struct net_device *dev)
dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
}
}
#endif /* CONFIG_PPC_MULTIPLATFORM */
#endif /* CONFIG_PPC_PMAC */
/* Test for a bad enet address */
status = test_bad_enet(dev, status);

1
drivers/ps3/Makefile Normal file
View file

@ -0,0 +1 @@
obj-y += system-bus.o

362
drivers/ps3/system-bus.c Normal file
View file

@ -0,0 +1,362 @@
/*
* PS3 system bus driver.
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <asm/udbg.h>
#include <asm/ps3.h>
#include <asm/lv1call.h>
#include <asm/firmware.h>
#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
static void _dump_mmio_region(const struct ps3_mmio_region* r,
const char* func, int line)
{
pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
r->did.dev_id);
pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
pr_debug("%s:%d: len %lxh\n", func, line, r->len);
pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
}
int ps3_mmio_region_create(struct ps3_mmio_region *r)
{
int result;
result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
r->bus_addr, r->len, r->page_size, &r->lpar_addr);
if (result) {
pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
r->lpar_addr = r->len = r->bus_addr = 0;
}
dump_mmio_region(r);
return result;
}
int ps3_free_mmio_region(struct ps3_mmio_region *r)
{
int result;
result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
r->bus_addr);
if (result)
pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
r->lpar_addr = r->len = r->bus_addr = 0;
return result;
}
static int ps3_system_bus_match(struct device *_dev,
struct device_driver *_drv)
{
int result;
struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
result = dev->match_id == drv->match_id;
pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
(result ? "match" : "miss"));
return result;
}
static int ps3_system_bus_probe(struct device *_dev)
{
int result;
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
struct ps3_system_bus_driver *drv =
to_ps3_system_bus_driver(_dev->driver);
result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
if (result) {
pr_debug("%s:%d: lv1_open_device failed (%d)\n",
__func__, __LINE__, result);
result = -EACCES;
goto clean_none;
}
if (dev->d_region->did.bus_id) {
result = ps3_dma_region_create(dev->d_region);
if (result) {
pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
__func__, __LINE__, result);
BUG_ON("check region type");
result = -EINVAL;
goto clean_device;
}
}
BUG_ON(!drv);
if (drv->probe)
result = drv->probe(dev);
else
pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
dev->core.bus_id);
if (result) {
pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
goto clean_dma;
}
return result;
clean_dma:
ps3_dma_region_free(dev->d_region);
clean_device:
lv1_close_device(dev->did.bus_id, dev->did.dev_id);
clean_none:
return result;
}
static int ps3_system_bus_remove(struct device *_dev)
{
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
struct ps3_system_bus_driver *drv =
to_ps3_system_bus_driver(_dev->driver);
if (drv->remove)
drv->remove(dev);
else
pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
dev->core.bus_id);
ps3_dma_region_free(dev->d_region);
ps3_free_mmio_region(dev->m_region);
lv1_close_device(dev->did.bus_id, dev->did.dev_id);
return 0;
}
struct bus_type ps3_system_bus_type = {
.name = "ps3_system_bus",
.match = ps3_system_bus_match,
.probe = ps3_system_bus_probe,
.remove = ps3_system_bus_remove,
};
int __init ps3_system_bus_init(void)
{
int result;
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return 0;
result = bus_register(&ps3_system_bus_type);
BUG_ON(result);
return result;
}
core_initcall(ps3_system_bus_init);
/* Allocates a contiguous real buffer and creates mappings over it.
* Returns the virtual address of the buffer and sets dma_handle
* to the dma address (mapping) of the first page.
*/
static void * ps3_alloc_coherent(struct device *_dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
int result;
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
unsigned long virt_addr;
BUG_ON(!dev->d_region->bus_addr);
flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
flag |= __GFP_ZERO;
virt_addr = __get_free_pages(flag, get_order(size));
if (!virt_addr) {
pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
goto clean_none;
}
result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
__func__, __LINE__, result);
BUG_ON("check region type");
goto clean_alloc;
}
return (void*)virt_addr;
clean_alloc:
free_pages(virt_addr, get_order(size));
clean_none:
dma_handle = NULL;
return NULL;
}
static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
ps3_dma_unmap(dev->d_region, dma_handle, size);
free_pages((unsigned long)vaddr, get_order(size));
}
/* Creates TCEs for a user provided buffer. The user buffer must be
* contiguous real kernel storage (not vmalloc). The address of the buffer
* passed here is the kernel (virtual) address of the buffer. The buffer
* need not be page aligned, the dma_addr_t returned will point to the same
* byte within the page as vaddr.
*/
static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
int result;
unsigned long bus_addr;
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
&bus_addr);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
__func__, __LINE__, result);
}
return bus_addr;
}
static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction direction)
{
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
int result;
result = ps3_dma_unmap(dev->d_region, dma_addr, size);
if (result) {
pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
__func__, __LINE__, result);
}
}
static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
BUG_ON("do");
#endif
return 0;
}
static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
BUG_ON("do");
#endif
}
static int ps3_dma_supported(struct device *_dev, u64 mask)
{
return 1;
}
static struct dma_mapping_ops ps3_dma_ops = {
.alloc_coherent = ps3_alloc_coherent,
.free_coherent = ps3_free_coherent,
.map_single = ps3_map_single,
.unmap_single = ps3_unmap_single,
.map_sg = ps3_map_sg,
.unmap_sg = ps3_unmap_sg,
.dma_supported = ps3_dma_supported
};
/**
* ps3_system_bus_release_device - remove a device from the system bus
*/
static void ps3_system_bus_release_device(struct device *_dev)
{
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
kfree(dev);
}
/**
* ps3_system_bus_device_register - add a device to the system bus
*
* ps3_system_bus_device_register() expects the dev object to be allocated
* dynamically by the caller. The system bus takes ownership of the dev
* object and frees the object in ps3_system_bus_release_device().
*/
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
{
int result;
static unsigned int dev_count = 1;
dev->core.parent = NULL;
dev->core.bus = &ps3_system_bus_type;
dev->core.release = ps3_system_bus_release_device;
dev->core.archdata.of_node = NULL;
dev->core.archdata.dma_ops = &ps3_dma_ops;
dev->core.archdata.numa_node = 0;
snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
dev_count++);
pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
result = device_register(&dev->core);
return result;
}
EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
{
int result;
drv->core.bus = &ps3_system_bus_type;
result = driver_register(&drv->core);
return result;
}
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
{
driver_unregister(&drv->core);
}
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);

View file

@ -282,7 +282,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
}
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
int __init cpm_uart_init_portdesc(void)
{
#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
u32 addr;

View file

@ -1,6 +1,4 @@
/*
* drivers/serial/mpc52xx_uart.c
*
* Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
*
* FIXME According to the usermanual the status bits in the status register
@ -14,18 +12,20 @@
*
*
* Maintainer : Sylvain Munaut <tnt@246tNt.com>
*
*
* Some of the code has been inspired/copied from the 2.4 code written
* by Dale Farnsworth <dfarnsworth@mvista.com>.
*
* Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
*
* Copyright (C) 2006 Secret Lab Technologies Ltd.
* Grant Likely <grant.likely@secretlab.ca>
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003 MontaVista, Software, Inc.
*
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
/* Platform device Usage :
*
* Since PSCs can have multiple function, the correct driver for each one
@ -44,7 +44,24 @@
* will be mapped to.
*/
#include <linux/platform_device.h>
/* OF Platform device Usage :
*
* This driver is only used for PSCs configured in uart mode. The device
* tree will have a node for each PSC in uart mode w/ device_type = "serial"
* and "mpc52xx-psc-uart" in the compatible string
*
* By default, PSC devices are enumerated in the order they are found. However
* a particular PSC number can be forces by adding 'device_no = <port#>'
* to the device node.
*
* The driver init all necessary registers to place the PSC in uart mode without
* DCD. However, the pin multiplexing aren't changed and should be set either
* by the bootloader or in the platform init code.
*/
#undef DEBUG
#include <linux/device.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/serial.h>
@ -54,6 +71,12 @@
#include <asm/delay.h>
#include <asm/io.h>
#if defined(CONFIG_PPC_MERGE)
#include <asm/of_platform.h>
#else
#include <linux/platform_device.h>
#endif
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
@ -80,6 +103,12 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
* it's cleared, then a memset(...,0,...) should be added to
* the console_init
*/
#if defined(CONFIG_PPC_MERGE)
/* lookup table for matching device nodes to index numbers */
static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
static void mpc52xx_uart_of_enumerate(void);
#endif
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
@ -96,32 +125,40 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
#define uart_console(port) (0)
#endif
#if defined(CONFIG_PPC_MERGE)
static struct of_device_id mpc52xx_uart_of_match[] = {
{ .type = "serial", .compatible = "mpc52xx-psc-uart", },
{ .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */
{},
};
#endif
/* ======================================================================== */
/* UART operations */
/* ======================================================================== */
static unsigned int
static unsigned int
mpc52xx_uart_tx_empty(struct uart_port *port)
{
int status = in_be16(&PSC(port)->mpc52xx_psc_status);
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
}
static void
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* Not implemented */
}
static unsigned int
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
/* Not implemented */
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void
static void
mpc52xx_uart_stop_tx(struct uart_port *port)
{
/* port->lock taken by caller */
@ -129,7 +166,7 @@ mpc52xx_uart_stop_tx(struct uart_port *port)
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
static void
static void
mpc52xx_uart_start_tx(struct uart_port *port)
{
/* port->lock taken by caller */
@ -137,12 +174,12 @@ mpc52xx_uart_start_tx(struct uart_port *port)
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
static void
static void
mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->x_char = ch;
if (ch) {
/* Make sure tx interrupts are on */
@ -150,7 +187,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
spin_unlock_irqrestore(&port->lock, flags);
}
@ -178,7 +215,7 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
else
out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
spin_unlock_irqrestore(&port->lock, flags);
}
@ -197,11 +234,11 @@ mpc52xx_uart_startup(struct uart_port *port)
/* Reset/activate the port, clear and enable interrupts */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
out_8(&psc->command,MPC52xx_PSC_RST_TX);
out_be32(&psc->sicr,0); /* UART mode DCD ignored */
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
out_8(&psc->rfcntl, 0x00);
out_be16(&psc->rfalarm, 0x1ff);
out_8(&psc->tfcntl, 0x07);
@ -209,10 +246,10 @@ mpc52xx_uart_startup(struct uart_port *port)
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
return 0;
}
@ -220,19 +257,19 @@ static void
mpc52xx_uart_shutdown(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
/* Shut down the port, interrupt and all */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
out_8(&psc->command,MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
/* Release interrupt */
free_irq(port->irq, port);
}
static void
static void
mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
struct termios *old)
{
@ -241,10 +278,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
unsigned char mr1, mr2;
unsigned short ctr;
unsigned int j, baud, quot;
/* Prepare what we're gonna write */
mr1 = 0;
switch (new->c_cflag & CSIZE) {
case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS;
break;
@ -261,8 +298,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
} else
mr1 |= MPC52xx_PSC_MODE_PARNONE;
mr2 = 0;
if (new->c_cflag & CSTOPB)
@ -276,7 +313,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
ctr = quot & 0xffff;
/* Get the lock */
spin_lock_irqsave(&port->lock, flags);
@ -290,14 +327,14 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
* boot for the console, all stuff is not yet ready to receive at that
* time and that just makes the kernel oops */
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
--j)
udelay(1);
if (!j)
printk( KERN_ERR "mpc52xx_uart.c: "
"Unable to flush RX & TX fifos in-time in set_termios."
"Some chars may have been lost.\n" );
"Some chars may have been lost.\n" );
/* Reset the TX & RX */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
@ -309,7 +346,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
out_8(&psc->mode,mr2);
out_8(&psc->ctur,ctr >> 8);
out_8(&psc->ctlr,ctr & 0xff);
/* Reenable TX & RX */
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
@ -332,7 +369,7 @@ mpc52xx_uart_release_port(struct uart_port *port)
port->membase = NULL;
}
release_mem_region(port->mapbase, MPC52xx_PSC_SIZE);
release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
}
static int
@ -341,12 +378,13 @@ mpc52xx_uart_request_port(struct uart_port *port)
int err;
if (port->flags & UPF_IOREMAP) /* Need to remap ? */
port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
port->membase = ioremap(port->mapbase,
sizeof(struct mpc52xx_psc));
if (!port->membase)
return -EINVAL;
err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
if (err && (port->flags & UPF_IOREMAP)) {
@ -373,7 +411,7 @@ mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
if ( (ser->irq != port->irq) ||
(ser->io_type != SERIAL_IO_MEM) ||
(ser->baud_base != port->uartclk) ||
(ser->baud_base != port->uartclk) ||
(ser->iomem_base != (void*)port->mapbase) ||
(ser->hub6 != 0 ) )
return -EINVAL;
@ -404,11 +442,11 @@ static struct uart_ops mpc52xx_uart_ops = {
.verify_port = mpc52xx_uart_verify_port
};
/* ======================================================================== */
/* Interrupt handling */
/* ======================================================================== */
static inline int
mpc52xx_uart_int_rx_chars(struct uart_port *port)
{
@ -435,11 +473,11 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
flag = TTY_NORMAL;
port->icount.rx++;
if ( status & (MPC52xx_PSC_SR_PE |
MPC52xx_PSC_SR_FE |
MPC52xx_PSC_SR_RB) ) {
if (status & MPC52xx_PSC_SR_RB) {
flag = TTY_BREAK;
uart_handle_break(port);
@ -464,7 +502,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
}
tty_flip_buffer_push(tty);
return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
}
@ -509,25 +547,25 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
return 1;
}
static irqreturn_t
static irqreturn_t
mpc52xx_uart_int(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
unsigned short status;
spin_lock(&port->lock);
/* While we have stuff to do, we continue */
do {
/* If we don't find anything to do, we stop */
keepgoing = 0;
keepgoing = 0;
/* Read status */
status = in_be16(&PSC(port)->mpc52xx_psc_isr);
status &= port->read_status_mask;
/* Do we need to receive chars ? */
/* For this RX interrupts must be on and some chars waiting */
if ( status & MPC52xx_PSC_IMR_RXRDY )
@ -537,15 +575,15 @@ mpc52xx_uart_int(int irq, void *dev_id)
/* For this, TX must be ready and TX interrupt enabled */
if ( status & MPC52xx_PSC_IMR_TXRDY )
keepgoing |= mpc52xx_uart_int_tx_chars(port);
/* Limit number of iteration */
if ( !(--pass) )
keepgoing = 0;
} while (keepgoing);
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@ -563,13 +601,18 @@ mpc52xx_console_get_options(struct uart_port *port,
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned char mr1;
pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
/* Read the mode registers */
out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
mr1 = in_8(&psc->mode);
/* CT{U,L}R are write-only ! */
*baud = __res.bi_baudrate ?
__res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
#if !defined(CONFIG_PPC_MERGE)
if (__res.bi_baudrate)
*baud = __res.bi_baudrate;
#endif
/* Parse them */
switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
@ -579,26 +622,26 @@ mpc52xx_console_get_options(struct uart_port *port,
case MPC52xx_PSC_MODE_8_BITS:
default: *bits = 8;
}
if (mr1 & MPC52xx_PSC_MODE_PARNONE)
*parity = 'n';
else
*parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
}
static void
static void
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &mpc52xx_uart_ports[co->index];
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned int i, j;
/* Disable interrupts */
out_be16(&psc->mpc52xx_psc_imr, 0);
/* Wait the TX buffer to be empty */
j = 5000000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
j = 5000000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
--j)
udelay(1);
@ -607,13 +650,13 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
/* Line return handling */
if (*s == '\n')
out_8(&psc->mpc52xx_psc_buffer_8, '\r');
/* Send the char */
out_8(&psc->mpc52xx_psc_buffer_8, *s);
/* Wait the TX buffer to be empty */
j = 20000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) &
j = 20000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) &
MPC52xx_PSC_SR_TXEMP) && --j)
udelay(1);
}
@ -622,6 +665,7 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
#if !defined(CONFIG_PPC_MERGE)
static int __init
mpc52xx_console_setup(struct console *co, char *options)
{
@ -634,7 +678,7 @@ mpc52xx_console_setup(struct console *co, char *options)
if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
/* Basic port init. Needed since we use some uart_??? func before
* real init for early access */
spin_lock_init(&port->lock);
@ -656,6 +700,78 @@ mpc52xx_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
#else
static int __init
mpc52xx_console_setup(struct console *co, char *options)
{
struct uart_port *port = &mpc52xx_uart_ports[co->index];
struct device_node *np = mpc52xx_uart_nodes[co->index];
unsigned int ipb_freq;
struct resource res;
int ret;
int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
int bits = 8;
int parity = 'n';
int flow = 'n';
pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
co, co->index, options);
if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) {
pr_debug("PSC%x out of range\n", co->index);
return -EINVAL;
}
if (!np) {
pr_debug("PSC%x not found in device tree\n", co->index);
return -EINVAL;
}
pr_debug("Console on ttyPSC%x is %s\n",
co->index, mpc52xx_uart_nodes[co->index]->full_name);
/* Fetch register locations */
if ((ret = of_address_to_resource(np, 0, &res)) != 0) {
pr_debug("Could not get resources for PSC%x\n", co->index);
return ret;
}
/* Search for bus-frequency property in this node or a parent */
if ((ipb_freq = mpc52xx_find_ipb_freq(np)) == 0) {
pr_debug("Could not find IPB bus frequency!\n");
return -EINVAL;
}
/* Basic port init. Needed since we use some uart_??? func before
* real init for early access */
spin_lock_init(&port->lock);
port->uartclk = ipb_freq / 2;
port->ops = &mpc52xx_uart_ops;
port->mapbase = res.start;
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
port->irq = irq_of_parse_and_map(np, 0);
if (port->membase == NULL)
return -EINVAL;
pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n",
port->mapbase, port->membase, port->irq, port->uartclk);
/* Setup the port parameters accoding to options */
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
baud, bits, parity, flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
#endif /* defined(CONFIG_PPC_MERGE) */
static struct uart_driver mpc52xx_uart_driver;
@ -669,10 +785,11 @@ static struct console mpc52xx_console = {
.data = &mpc52xx_uart_driver,
};
static int __init
static int __init
mpc52xx_console_init(void)
{
mpc52xx_uart_of_enumerate();
register_console(&mpc52xx_console);
return 0;
}
@ -700,6 +817,7 @@ static struct uart_driver mpc52xx_uart_driver = {
};
#if !defined(CONFIG_PPC_MERGE)
/* ======================================================================== */
/* Platform Driver */
/* ======================================================================== */
@ -723,8 +841,6 @@ mpc52xx_uart_probe(struct platform_device *dev)
/* Init the port structure */
port = &mpc52xx_uart_ports[idx];
memset(port, 0x00, sizeof(struct uart_port));
spin_lock_init(&port->lock);
port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
port->fifosize = 512;
@ -733,6 +849,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
( uart_console(port) ? 0 : UPF_IOREMAP );
port->line = idx;
port->ops = &mpc52xx_uart_ops;
port->dev = &dev->dev;
/* Search for IRQ and mapbase */
for (i=0 ; i<dev->num_resources ; i++, res++) {
@ -771,7 +888,7 @@ mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
{
struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
if (sport)
if (port)
uart_suspend_port(&mpc52xx_uart_driver, port);
return 0;
@ -789,6 +906,7 @@ mpc52xx_uart_resume(struct platform_device *dev)
}
#endif
static struct platform_driver mpc52xx_uart_platform_driver = {
.probe = mpc52xx_uart_probe,
.remove = mpc52xx_uart_remove,
@ -800,6 +918,184 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
.name = "mpc52xx-psc",
},
};
#endif /* !defined(CONFIG_PPC_MERGE) */
#if defined(CONFIG_PPC_MERGE)
/* ======================================================================== */
/* OF Platform Driver */
/* ======================================================================== */
static int __devinit
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
{
int idx = -1;
unsigned int ipb_freq;
struct uart_port *port = NULL;
struct resource res;
int ret;
dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
/* Check validity & presence */
for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
if (mpc52xx_uart_nodes[idx] == op->node)
break;
if (idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
pr_debug("Found %s assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[idx]->full_name, idx);
/* Search for bus-frequency property in this node or a parent */
if ((ipb_freq = mpc52xx_find_ipb_freq(op->node)) == 0) {
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
return -EINVAL;
}
/* Init the port structure */
port = &mpc52xx_uart_ports[idx];
spin_lock_init(&port->lock);
port->uartclk = ipb_freq / 2;
port->fifosize = 512;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF |
( uart_console(port) ? 0 : UPF_IOREMAP );
port->line = idx;
port->ops = &mpc52xx_uart_ops;
port->dev = &op->dev;
/* Search for IRQ and mapbase */
if ((ret = of_address_to_resource(op->node, 0, &res)) != 0)
return ret;
port->mapbase = res.start;
port->irq = irq_of_parse_and_map(op->node, 0);
dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n",
port->mapbase, port->irq, port->uartclk);
if ((port->irq==NO_IRQ) || !port->mapbase) {
printk(KERN_ERR "Could not allocate resources for PSC\n");
return -EINVAL;
}
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
if (!ret)
dev_set_drvdata(&op->dev, (void*)port);
return ret;
}
static int
mpc52xx_uart_of_remove(struct of_device *op)
{
struct uart_port *port = dev_get_drvdata(&op->dev);
dev_set_drvdata(&op->dev, NULL);
if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
return 0;
}
#ifdef CONFIG_PM
static int
mpc52xx_uart_of_suspend(struct of_device *op, pm_message_t state)
{
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
if (port)
uart_suspend_port(&mpc52xx_uart_driver, port);
return 0;
}
static int
mpc52xx_uart_of_resume(struct of_device *op)
{
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
if (port)
uart_resume_port(&mpc52xx_uart_driver, port);
return 0;
}
#endif
static void
mpc52xx_uart_of_assign(struct device_node *np, int idx)
{
int free_idx = -1;
int i;
/* Find the first free node */
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
if (mpc52xx_uart_nodes[i] == NULL) {
free_idx = i;
break;
}
}
if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
idx = free_idx;
if (idx < 0)
return; /* No free slot; abort */
/* If the slot is already occupied, then swap slots */
if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
mpc52xx_uart_nodes[i] = np;
}
static void
mpc52xx_uart_of_enumerate(void)
{
static int enum_done = 0;
struct device_node *np;
const unsigned int *devno;
int i;
if (enum_done)
return;
for_each_node_by_type(np, "serial") {
if (!of_match_node(mpc52xx_uart_of_match, np))
continue;
/* Is a particular device number requested? */
devno = get_property(np, "device_no", NULL);
mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
}
enum_done = 1;
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
if (mpc52xx_uart_nodes[i])
pr_debug("%s assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[i]->full_name, i);
}
}
MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
static struct of_platform_driver mpc52xx_uart_of_driver = {
.owner = THIS_MODULE,
.name = "mpc52xx-psc-uart",
.match_table = mpc52xx_uart_of_match,
.probe = mpc52xx_uart_of_probe,
.remove = mpc52xx_uart_of_remove,
#ifdef CONFIG_PM
.suspend = mpc52xx_uart_of_suspend,
.resume = mpc52xx_uart_of_resume,
#endif
.driver = {
.name = "mpc52xx-psc-uart",
},
};
#endif /* defined(CONFIG_PPC_MERGE) */
/* ======================================================================== */
@ -811,22 +1107,45 @@ mpc52xx_uart_init(void)
{
int ret;
printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
ret = uart_register_driver(&mpc52xx_uart_driver);
if (ret == 0) {
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
if (ret)
uart_unregister_driver(&mpc52xx_uart_driver);
if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) {
printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
__FILE__, ret);
return ret;
}
return ret;
#if defined(CONFIG_PPC_MERGE)
mpc52xx_uart_of_enumerate();
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
if (ret) {
printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
__FILE__, ret);
uart_unregister_driver(&mpc52xx_uart_driver);
return ret;
}
#else
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
if (ret) {
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
__FILE__, ret);
uart_unregister_driver(&mpc52xx_uart_driver);
return ret;
}
#endif
return 0;
}
static void __exit
mpc52xx_uart_exit(void)
{
#if defined(CONFIG_PPC_MERGE)
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
#else
platform_driver_unregister(&mpc52xx_uart_platform_driver);
#endif
uart_unregister_driver(&mpc52xx_uart_driver);
}

View file

@ -34,6 +34,7 @@
#include <asm/prom.h>
#include <asm/pgtable.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#include "macmodes.h"
#include "platinumfb.h"
@ -682,14 +683,14 @@ static int __init platinumfb_init(void)
return -ENODEV;
platinumfb_setup(option);
#endif
of_register_driver(&platinum_driver);
of_register_platform_driver(&platinum_driver);
return 0;
}
static void __exit platinumfb_exit(void)
{
of_unregister_driver(&platinum_driver);
of_unregister_platform_driver(&platinum_driver);
}
MODULE_LICENSE("GPL");