aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/Kconfig14
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/pata_mpc52xx.c6
-rw-r--r--drivers/ata/pata_of_platform.c114
-rw-r--r--drivers/ata/pata_platform.c144
-rw-r--r--drivers/char/hw_random/Kconfig2
-rw-r--r--drivers/char/hw_random/pasemi-rng.c7
-rw-r--r--drivers/edac/pasemi_edac.c4
-rw-r--r--drivers/macintosh/adb.c174
-rw-r--r--drivers/macintosh/mediabay.c14
-rw-r--r--drivers/macintosh/therm_adt746x.c24
-rw-r--r--drivers/macintosh/therm_pm72.c64
-rw-r--r--drivers/macintosh/therm_windtunnel.c42
-rw-r--r--drivers/macintosh/via-pmu-backlight.c48
-rw-r--r--drivers/macintosh/via-pmu.c664
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/fec_8xx/fec_8xx-netta.c2
-rw-r--r--drivers/net/fec_8xx/fec_main.c2
-rw-r--r--drivers/net/fec_8xx/fec_mii.c2
-rw-r--r--drivers/net/fec_mpc52xx.c6
-rw-r--r--drivers/net/fec_mpc52xx_phy.c8
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c9
-rw-r--r--drivers/net/fs_enet/fs_enet.h2
-rw-r--r--drivers/net/fs_enet/mac-fcc.c10
-rw-r--r--drivers/net/fs_enet/mac-fec.c2
-rw-r--r--drivers/net/fs_enet/mac-scc.c13
-rw-r--r--drivers/net/ibm_newemac/core.c1
-rw-r--r--drivers/net/phy/Kconfig32
-rw-r--r--drivers/net/phy/fixed.c445
-rw-r--r--drivers/net/ps3_gelic_net.c4
-rw-r--r--drivers/net/ucc_geth.c55
-rw-r--r--drivers/net/ucc_geth_mii.c3
-rw-r--r--drivers/of/base.c58
-rw-r--r--drivers/of/device.c29
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c2
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/ps3-lpm.c1248
-rw-r--r--drivers/ps3/ps3-sys-manager.c14
-rw-r--r--drivers/ps3/ps3-vuart.c38
-rw-r--r--drivers/rapidio/rio.c5
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c6
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c10
-rw-r--r--drivers/serial/mpc52xx_uart.c217
-rw-r--r--drivers/serial/uartlite.c6
-rw-r--r--drivers/serial/ucc_uart.c1514
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c77
-rw-r--r--drivers/spi/spi_mpc83xx.c6
-rw-r--r--drivers/usb/host/ohci-ppc-of.c2
52 files changed, 3833 insertions, 1335 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 2478cca653d..ae19c9b30d1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -184,7 +184,7 @@ config PATA_ACPI
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
- depends on PPC_MPC837x
+ depends on FSL_SOC
help
This option enables support for Freescale 3.0Gbps SATA controller.
It can be found on MPC837x and MPC8315.
@@ -616,13 +616,23 @@ config PATA_WINBOND_VLB
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || ARCH_RPC
+ depends on EMBEDDED || ARCH_RPC || PPC
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
If unsure, say N.
+config PATA_OF_PLATFORM
+ tristate "OpenFirmware platform device PATA support"
+ depends on PATA_PLATFORM && PPC_OF
+ help
+ This option enables support for generic directly connected ATA
+ devices commonly found on embedded systems with OpenFirmware
+ bindings.
+
+ If unsure, say N.
+
config PATA_ICSIDE
tristate "Acorn ICS PATA support"
depends on ARM && ARCH_ACORN
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 82550c16818..701651e37c8 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
+obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index dc401626cdb..5413ebfa72e 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -494,10 +494,8 @@ mpc52xx_ata_resume(struct of_device *op)
static struct of_device_id mpc52xx_ata_of_match[] = {
- {
- .type = "ata",
- .compatible = "mpc5200-ata",
- },
+ { .compatible = "fsl,mpc5200-ata", },
+ { .compatible = "mpc5200-ata", },
{},
};
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
new file mode 100644
index 00000000000..938f48a807e
--- /dev/null
+++ b/drivers/ata/pata_of_platform.c
@@ -0,0 +1,114 @@
+/*
+ * OF-platform PATA driver
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pata_platform.h>
+
+static int __devinit pata_of_platform_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ int ret;
+ struct device_node *dn = ofdev->node;
+ struct resource io_res;
+ struct resource ctl_res;
+ struct resource irq_res;
+ unsigned int reg_shift = 0;
+ int pio_mode = 0;
+ int pio_mask;
+ const u32 *prop;
+
+ ret = of_address_to_resource(dn, 0, &io_res);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't get IO address from "
+ "device tree\n");
+ return -EINVAL;
+ }
+
+ if (of_device_is_compatible(dn, "electra-ide")) {
+ /* Altstatus is really at offset 0x3f6 from the primary window
+ * on electra-ide. Adjust ctl_res and io_res accordingly.
+ */
+ ctl_res = io_res;
+ ctl_res.start = ctl_res.start+0x3f6;
+ io_res.end = ctl_res.start-1;
+ } else {
+ ret = of_address_to_resource(dn, 1, &ctl_res);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't get CTL address from "
+ "device tree\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = of_irq_to_resource(dn, 0, &irq_res);
+ if (ret == NO_IRQ)
+ irq_res.start = irq_res.end = -1;
+ else
+ irq_res.flags = 0;
+
+ prop = of_get_property(dn, "reg-shift", NULL);
+ if (prop)
+ reg_shift = *prop;
+
+ prop = of_get_property(dn, "pio-mode", NULL);
+ if (prop) {
+ pio_mode = *prop;
+ if (pio_mode > 6) {
+ dev_err(&ofdev->dev, "invalid pio-mode\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_info(&ofdev->dev, "pio-mode unspecified, assuming PIO0\n");
+ }
+
+ pio_mask = 1 << pio_mode;
+ pio_mask |= (1 << pio_mode) - 1;
+
+ return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, &irq_res,
+ reg_shift, pio_mask);
+}
+
+static int __devexit pata_of_platform_remove(struct of_device *ofdev)
+{
+ return __pata_platform_remove(&ofdev->dev);
+}
+
+static struct of_device_id pata_of_platform_match[] = {
+ { .compatible = "ata-generic", },
+ { .compatible = "electra-ide", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pata_of_platform_match);
+
+static struct of_platform_driver pata_of_platform_driver = {
+ .name = "pata_of_platform",
+ .match_table = pata_of_platform_match,
+ .probe = pata_of_platform_probe,
+ .remove = __devexit_p(pata_of_platform_remove),
+};
+
+static int __init pata_of_platform_init(void)
+{
+ return of_register_platform_driver(&pata_of_platform_driver);
+}
+module_init(pata_of_platform_init);
+
+static void __exit pata_of_platform_exit(void)
+{
+ of_unregister_platform_driver(&pata_of_platform_driver);
+}
+module_exit(pata_of_platform_exit);
+
+MODULE_DESCRIPTION("OF-platform PATA driver");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index ac03a90a616..224bb6c2030 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -93,14 +93,9 @@ static struct ata_port_operations pata_platform_port_ops = {
};
static void pata_platform_setup_port(struct ata_ioports *ioaddr,
- struct pata_platform_info *info)
+ unsigned int shift)
{
- unsigned int shift = 0;
-
/* Fixup the port shift for platforms that need it */
- if (info && info->ioport_shift)
- shift = info->ioport_shift;
-
ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift);
ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift);
ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift);
@@ -114,8 +109,13 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
}
/**
- * pata_platform_probe - attach a platform interface
- * @pdev: platform device
+ * __pata_platform_probe - attach a platform interface
+ * @dev: device
+ * @io_res: Resource representing I/O base
+ * @ctl_res: Resource representing CTL base
+ * @irq_res: Resource representing IRQ and its flags
+ * @ioport_shift: I/O port shift
+ * @__pio_mask: PIO mask
*
* Register a platform bus IDE interface. Such interfaces are PIO and we
* assume do not support IRQ sharing.
@@ -135,42 +135,18 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
*
* If no IRQ resource is present, PIO polling mode is used instead.
*/
-static int __devinit pata_platform_probe(struct platform_device *pdev)
+int __devinit __pata_platform_probe(struct device *dev,
+ struct resource *io_res,
+ struct resource *ctl_res,
+ struct resource *irq_res,
+ unsigned int ioport_shift,
+ int __pio_mask)
{
- struct resource *io_res, *ctl_res;
struct ata_host *host;
struct ata_port *ap;
- struct pata_platform_info *pp_info;
unsigned int mmio;
- int irq;
-
- /*
- * Simple resource validation ..
- */
- if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) {
- dev_err(&pdev->dev, "invalid number of resources\n");
- return -EINVAL;
- }
-
- /*
- * Get the I/O base first
- */
- io_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (io_res == NULL) {
- io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(io_res == NULL))
- return -EINVAL;
- }
-
- /*
- * Then the CTL base
- */
- ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
- if (ctl_res == NULL) {
- ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (unlikely(ctl_res == NULL))
- return -EINVAL;
- }
+ int irq = 0;
+ int irq_flags = 0;
/*
* Check for MMIO
@@ -181,20 +157,21 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
/*
* And the IRQ
*/
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- irq = 0; /* no irq */
+ if (irq_res && irq_res->start > 0) {
+ irq = irq_res->start;
+ irq_flags = irq_res->flags;
+ }
/*
* Now that that's out of the way, wire up the port..
*/
- host = ata_host_alloc(&pdev->dev, 1);
+ host = ata_host_alloc(dev, 1);
if (!host)
return -ENOMEM;
ap = host->ports[0];
ap->ops = &pata_platform_port_ops;
- ap->pio_mask = pio_mask;
+ ap->pio_mask = __pio_mask;
ap->flags |= ATA_FLAG_SLAVE_POSS;
/*
@@ -209,25 +186,24 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
* Handle the MMIO case
*/
if (mmio) {
- ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioremap(dev, io_res->start,
io_res->end - io_res->start + 1);
- ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioremap(dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
} else {
- ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioport_map(dev, io_res->start,
io_res->end - io_res->start + 1);
- ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioport_map(dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
}
if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
- dev_err(&pdev->dev, "failed to map IO/CTL base\n");
+ dev_err(dev, "failed to map IO/CTL base\n");
return -ENOMEM;
}
ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pp_info = pdev->dev.platform_data;
- pata_platform_setup_port(&ap->ioaddr, pp_info);
+ pata_platform_setup_port(&ap->ioaddr, ioport_shift);
ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
(unsigned long long)io_res->start,
@@ -235,26 +211,78 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
/* activate */
return ata_host_activate(host, irq, irq ? ata_interrupt : NULL,
- pp_info ? pp_info->irq_flags : 0,
- &pata_platform_sht);
+ irq_flags, &pata_platform_sht);
}
+EXPORT_SYMBOL_GPL(__pata_platform_probe);
/**
- * pata_platform_remove - unplug a platform interface
- * @pdev: platform device
+ * __pata_platform_remove - unplug a platform interface
+ * @dev: device
*
* A platform bus ATA device has been unplugged. Perform the needed
* cleanup. Also called on module unload for any active devices.
*/
-static int __devexit pata_platform_remove(struct platform_device *pdev)
+int __devexit __pata_platform_remove(struct device *dev)
{
- struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
return 0;
}
+EXPORT_SYMBOL_GPL(__pata_platform_remove);
+
+static int __devinit pata_platform_probe(struct platform_device *pdev)
+{
+ struct resource *io_res;
+ struct resource *ctl_res;
+ struct resource *irq_res;
+ struct pata_platform_info *pp_info = pdev->dev.platform_data;
+
+ /*
+ * Simple resource validation ..
+ */
+ if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Get the I/O base first
+ */
+ io_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (io_res == NULL) {
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(io_res == NULL))
+ return -EINVAL;
+ }
+
+ /*
+ * Then the CTL base
+ */
+ ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ if (ctl_res == NULL) {
+ ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (unlikely(ctl_res == NULL))
+ return -EINVAL;
+ }
+
+ /*
+ * And the IRQ
+ */
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq_res)
+ irq_res->flags = pp_info ? pp_info->irq_flags : 0;
+
+ return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res,
+ pp_info ? pp_info->ioport_shift : 0,
+ pio_mask);
+}
+
+static int __devexit pata_platform_remove(struct platform_device *pdev)
+{
+ return __pata_platform_remove(&pdev->dev);
+}
static struct platform_driver pata_platform_driver = {
.probe = pata_platform_probe,
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 2d7cd486e02..6bbd4fa50f3 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -98,7 +98,7 @@ config HW_RANDOM_PASEMI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
- Generator hardware found on PA6T-1682M processor.
+ Generator hardware found on PA Semi PWRficient SoCs.
To compile this driver as a module, choose M here: the
module will be called pasemi-rng.
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index e2ea210cfa5..6d50e9bc700 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -134,10 +134,9 @@ static int __devexit rng_remove(struct of_device *dev)
}
static struct of_device_id rng_match[] = {
- {
- .compatible = "1682m-rng",
- },
- {},
+ { .compatible = "1682m-rng", },
+ { .compatible = "pasemi,pwrficient-rng", },
+ { },
};
static struct of_platform_driver rng_driver = {
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 9007d067722..90320917be2 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -225,7 +225,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
EDAC_FLAG_NONE;
mci->mod_name = MODULE_NAME;
mci->dev_name = pci_name(pdev);
- mci->ctl_name = "pasemi,1682m-mc";
+ mci->ctl_name = "pasemi,pwrficient-mc";
mci->edac_check = pasemi_edac_check;
mci->ctl_page_to_phys = NULL;
pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub);
@@ -297,4 +297,4 @@ module_exit(pasemi_edac_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
-MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller");
+MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller");
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index b7adde4324e..7ce0ea64465 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/device.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -82,21 +83,11 @@ struct adb_driver *adb_controller;
BLOCKING_NOTIFIER_HEAD(adb_client_list);
static int adb_got_sleep;
static int adb_inited;
-static pid_t adb_probe_task_pid;
static DECLARE_MUTEX(adb_probe_mutex);
-static struct completion adb_probe_task_comp;
static int sleepy_trackpad;
static int autopoll_devs;
int __adb_probe_sync;
-#ifdef CONFIG_PM_SLEEP
-static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier adb_sleep_notifier = {
- adb_notify_sleep,
- SLEEP_LEVEL_ADB,
-};
-#endif
-
static int adb_scan_bus(void);
static int do_adb_reset_bus(void);
static void adbdev_init(void);
@@ -134,16 +125,6 @@ static void printADBreply(struct adb_request *req)
}
#endif
-
-static __inline__ void adb_wait_ms(unsigned int ms)
-{
- if (current->pid && adb_probe_task_pid &&
- adb_probe_task_pid == current->pid)
- msleep(ms);
- else
- mdelay(ms);
-}
-
static int adb_scan_bus(void)
{
int i, highFree=0, noMovement;
@@ -248,13 +229,10 @@ static int adb_scan_bus(void)
static int
adb_probe_task(void *x)
{
- strcpy(current->comm, "kadbprobe");
-
printk(KERN_INFO "adb: starting probe task...\n");
do_adb_reset_bus();
printk(KERN_INFO "adb: finished probe task...\n");
- adb_probe_task_pid = 0;
up(&adb_probe_mutex);
return 0;
@@ -263,7 +241,7 @@ adb_probe_task(void *x)
static void
__adb_probe_task(struct work_struct *bullshit)
{
- adb_probe_task_pid = kernel_thread(adb_probe_task, NULL, SIGCHLD | CLONE_KERNEL);
+ kthread_run(adb_probe_task, NULL, "kadbprobe");
}
static DECLARE_WORK(adb_reset_work, __adb_probe_task);
@@ -281,6 +259,36 @@ adb_reset_bus(void)
return 0;
}
+#ifdef CONFIG_PM
+/*
+ * notify clients before sleep
+ */
+static int adb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ adb_got_sleep = 1;
+ /* We need to get a lock on the probe thread */
+ down(&adb_probe_mutex);
+ /* Stop autopoll */
+ if (adb_controller->autopoll)
+ adb_controller->autopoll(0);
+ blocking_notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+
+ return 0;
+}
+
+/*
+ * reset bus after sleep
+ */
+static int adb_resume(struct platform_device *dev)
+{
+ adb_got_sleep = 0;
+ up(&adb_probe_mutex);
+ adb_reset_bus();
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
int __init adb_init(void)
{
struct adb_driver *driver;
@@ -313,15 +321,12 @@ int __init adb_init(void)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
adb_controller = NULL;
} else {
-#ifdef CONFIG_PM_SLEEP
- pmu_register_sleep_notifier(&adb_sleep_notifier);
-#endif /* CONFIG_PM */
#ifdef CONFIG_PPC
if (machine_is_compatible("AAPL,PowerBook1998") ||
machine_is_compatible("PowerBook1,1"))
sleepy_trackpad = 1;
#endif /* CONFIG_PPC */
- init_completion(&adb_probe_task_comp);
+
adbdev_init();
adb_reset_bus();
}
@@ -330,33 +335,6 @@ int __init adb_init(void)
__initcall(adb_init);
-#ifdef CONFIG_PM
-/*
- * notify clients before sleep and reset bus afterwards
- */
-void
-adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- adb_got_sleep = 1;
- /* We need to get a lock on the probe thread */
- down(&adb_probe_mutex);
- /* Stop autopoll */
- if (adb_controller->autopoll)
- adb_controller->autopoll(0);
- blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_POWERDOWN, NULL);
- break;
- case PBOOK_WAKE:
- adb_got_sleep = 0;
- up(&adb_probe_mutex);
- adb_reset_bus();
- break;
- }
-}
-#endif /* CONFIG_PM */
-
static int
do_adb_reset_bus(void)
{
@@ -373,7 +351,7 @@ do_adb_reset_bus(void)
if (sleepy_trackpad) {
/* Let the trackpad settle down */
- adb_wait_ms(500);
+ msleep(500);
}
down(&adb_handler_sem);
@@ -389,7 +367,7 @@ do_adb_reset_bus(void)
if (sleepy_trackpad) {
/* Let the trackpad settle down */
- adb_wait_ms(1500);
+ msleep(1500);
}
if (!ret) {
@@ -413,41 +391,27 @@ adb_poll(void)
adb_controller->poll();
}
-static void
-adb_probe_wakeup(struct adb_request *req)
+static void adb_sync_req_done(struct adb_request *req)
{
- complete(&adb_probe_task_comp);
-}
+ struct completion *comp = req->arg;
-/* Static request used during probe */
-static struct adb_request adb_sreq;
-static unsigned long adb_sreq_lock; // Use semaphore ! */
+ complete(comp);
+}
int
adb_request(struct adb_request *req, void (*done)(struct adb_request *),
int flags, int nbytes, ...)
{
va_list list;
- int i, use_sreq;
+ int i;
int rc;
+ struct completion comp;
if ((adb_controller == NULL) || (adb_controller->send_request == NULL))
return -ENXIO;
if (nbytes < 1)
return -EINVAL;
- if (req == NULL && (flags & ADBREQ_NOSEND))
- return -EINVAL;
-
- if (req == NULL) {
- if (test_and_set_bit(0,&adb_sreq_lock)) {
- printk("adb.c: Warning: contention on static request !\n");
- return -EPERM;
- }
- req = &adb_sreq;
- flags |= ADBREQ_SYNC;
- use_sreq = 1;
- } else
- use_sreq = 0;
+
req->nbytes = nbytes+1;
req->done = done;
req->reply_expected = flags & ADBREQ_REPLY;
@@ -460,25 +424,18 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
if (flags & ADBREQ_NOSEND)
return 0;
- /* Synchronous requests send from the probe thread cause it to
- * block. Beware that the "done" callback will be overriden !
- */
- if ((flags & ADBREQ_SYNC) &&
- (current->pid && adb_probe_task_pid &&
- adb_probe_task_pid == current->pid)) {
- req->done = adb_probe_wakeup;
- rc = adb_controller->send_request(req, 0);
- if (rc || req->complete)
- goto bail;
- wait_for_completion(&adb_probe_task_comp);
- rc = 0;
- goto bail;
+ /* Synchronous requests block using an on-stack completion */
+ if (flags & ADBREQ_SYNC) {
+ WARN_ON(done);
+ req->done = adb_sync_req_done;
+ req->arg = &comp;
+ init_completion(&comp);
}
- rc = adb_controller->send_request(req, flags & ADBREQ_SYNC);
-bail:
- if (use_sreq)
- clear_bit(0, &adb_sreq_lock);
+ rc = adb_controller->send_request(req, 0);
+
+ if ((flags & ADBREQ_SYNC) && !rc && !req->complete)
+ wait_for_completion(&comp);
return rc;
}
@@ -864,7 +821,29 @@ static const struct file_operations adb_fops = {
.release = adb_release,
};
-static void
+static struct platform_driver adb_pfdrv = {
+ .driver = {
+ .name = "adb",
+ },
+#ifdef CONFIG_PM
+ .suspend = adb_suspend,
+ .resume = adb_resume,
+#endif
+};
+
+static struct platform_device adb_pfdev = {
+ .name = "adb",
+};
+
+static int __init
+adb_dummy_probe(struct platform_device *dev)
+{
+ if (dev == &adb_pfdev)
+ return 0;
+ return -ENODEV;
+}
+
+static void __init
adbdev_init(void)
{
if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) {
@@ -876,4 +855,7 @@ adbdev_init(void)
if (IS_ERR(adb_dev_class))
return;
device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb");
+
+ platform_device_register(&adb_pfdev);
+ platform_driver_probe(&adb_pfdrv, adb_dummy_probe);
}
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index eaba4a9b231..18dde2a2720 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -20,6 +20,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/ide.h>
+#include <linux/kthread.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -35,7 +36,6 @@
#define MB_DEBUG
-#define MB_IGNORE_SIGNALS
#ifdef MB_DEBUG
#define MBDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg)
@@ -623,12 +623,7 @@ static int media_bay_task(void *x)
{
int i;
- strcpy(current->comm, "media-bay");
-#ifdef MB_IGNORE_SIGNALS
- sigfillset(&current->blocked);
-#endif
-
- for (;;) {
+ while (!kthread_should_stop()) {
for (i = 0; i < media_bay_count; ++i) {
down(&media_bays[i].lock);
if (!media_bays[i].sleeping)
@@ -637,9 +632,8 @@ static int media_bay_task(void *x)
}
msleep_interruptible(MB_POLL_DELAY);
- if (signal_pending(current))
- return 0;
}
+ return 0;
}
static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match)
@@ -700,7 +694,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de
/* Startup kernel thread */
if (i == 0)
- kernel_thread(media_bay_task, NULL, CLONE_KERNEL);
+ kthread_run(media_bay_task, NULL, "media-bay");
return 0;
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 276945d5151..54f4942a296 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -553,6 +553,7 @@ thermostat_init(void)
struct device_node* np;
const u32 *prop;
int i = 0, offset = 0;
+ int err;
np = of_find_node_by_name(NULL, "fan");
if (!np)
@@ -612,17 +613,20 @@ thermostat_init(void)
return -ENODEV;
}
- device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
- device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
- device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
+ err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
+ err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
+ err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
if(therm_type == ADT7460)
- device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
+ if (err)
+ printk(KERN_WARNING
+ "Failed to create tempertaure attribute file(s).\n");
#ifndef CONFIG_I2C_POWERMAC
request_module("i2c-powermac");
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index e43554e754a..1e0a69a5e81 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -121,6 +121,7 @@
#include <linux/reboot.h>
#include <linux/kmod.h>
#include <linux/i2c.h>
+#include <linux/kthread.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
@@ -161,7 +162,7 @@ static struct slots_pid_state slots_state;
static int state;
static int cpu_count;
static int cpu_pid_type;
-static pid_t ctrl_task;
+static struct task_struct *ctrl_task;
static struct completion ctrl_complete;
static int critical_state;
static int rackmac;
@@ -1156,6 +1157,8 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state)
*/
static int init_cpu_state(struct cpu_pid_state *state, int index)
{
+ int err;
+
state->index = index;
state->first = 1;
state->rpm = (cpu_pid_type == CPU_PID_TYPE_RACKMAC) ? 4000 : 1000;
@@ -1181,18 +1184,21 @@ static int init_cpu_state(struct cpu_pid_state *state, int index)
DBG("CPU %d Using %d power history entries\n", index, state->count_power);
if (index == 0) {
- device_create_file(&of_dev->dev, &dev_attr_cpu0_temperature);
- device_create_file(&of_dev->dev, &dev_attr_cpu0_voltage);
- device_create_file(&of_dev->dev, &dev_attr_cpu0_current);
- device_create_file(&of_dev->dev, &dev_attr_cpu0_exhaust_fan_rpm);
- device_create_file(&of_dev->dev, &dev_attr_cpu0_intake_fan_rpm);
+ err = device_create_file(&of_dev->dev, &dev_attr_cpu0_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu0_voltage);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu0_current);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu0_exhaust_fan_rpm);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu0_intake_fan_rpm);
} else {
- device_create_file(&of_dev->dev, &dev_attr_cpu1_temperature);
- device_create_file(&of_dev->dev, &dev_attr_cpu1_voltage);
- device_create_file(&of_dev->dev, &dev_attr_cpu1_current);
- device_create_file(&of_dev->dev, &dev_attr_cpu1_exhaust_fan_rpm);
- device_create_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
+ err = device_create_file(&of_dev->dev, &dev_attr_cpu1_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu1_voltage);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu1_current);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu1_exhaust_fan_rpm);
+ err |= device_create_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
}
+ if (err)
+ printk(KERN_WARNING "Failed to create some of the atribute"
+ "files for CPU %d\n", index);
return 0;
fail:
@@ -1328,6 +1334,7 @@ static int init_backside_state(struct backside_pid_state *state)
{
struct device_node *u3;
int u3h = 1; /* conservative by default */
+ int err;
/*
* There are different PID params for machines with U3 and machines
@@ -1379,8 +1386,11 @@ static int init_backside_state(struct backside_pid_state *state)
if (state->monitor == NULL)
return -ENODEV;
- device_create_file(&of_dev->dev, &dev_attr_backside_temperature);
- device_create_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
+ err = device_create_file(&of_dev->dev, &dev_attr_backside_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
+ if (err)
+ printk(KERN_WARNING "Failed to create attribute file(s)"
+ " for backside fan\n");
return 0;
}
@@ -1491,6 +1501,8 @@ static void do_monitor_drives(struct drives_pid_state *state)
*/
static int init_drives_state(struct drives_pid_state *state)
{
+ int err;
+
state->ticks = 1;
state->first = 1;
state->rpm = 1000;
@@ -1499,8 +1511,11 @@ static int init_drives_state(struct drives_pid_state *state)
if (state->monitor == NULL)
return -ENODEV;
- device_create_file(&of_dev->dev, &dev_attr_drives_temperature);
- device_create_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
+ err = device_create_file(&of_dev->dev, &dev_attr_drives_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
+ if (err)
+ printk(KERN_WARNING "Failed to create attribute file(s)"
+ " for drives bay fan\n");
return 0;
}
@@ -1621,7 +1636,9 @@ static int init_dimms_state(struct dimm_pid_state *state)
if (state->monitor == NULL)
return -ENODEV;
- device_create_file(&of_dev->dev, &dev_attr_dimms_temperature);
+ if (device_create_file(&of_dev->dev, &dev_attr_dimms_temperature))
+ printk(KERN_WARNING "Failed to create attribute file"
+ " for DIMM temperature\n");
return 0;
}
@@ -1731,6 +1748,8 @@ static void do_monitor_slots(struct slots_pid_state *state)
*/
static int init_slots_state(struct slots_pid_state *state)
{
+ int err;
+
state->ticks = 1;
state->first = 1;
state->pwm = 50;
@@ -1739,8 +1758,11 @@ static int init_slots_state(struct slots_pid_state *state)
if (state->monitor == NULL)
return -ENODEV;
- device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
- device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+ err = device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
+ err |= device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+ if (err)
+ printk(KERN_WARNING "Failed to create attribute file(s)"
+ " for slots bay fan\n");
return 0;
}
@@ -1779,8 +1801,6 @@ static int call_critical_overtemp(void)
*/
static int main_control_loop(void *x)
{
- daemonize("kfand");
-
DBG("main_control_loop started\n");
down(&driver_lock);
@@ -1956,7 +1976,7 @@ static void start_control_loops(void)
{
init_completion(&ctrl_complete);
- ctrl_task = kernel_thread(main_control_loop, NULL, SIGCHLD | CLONE_KERNEL);
+ ctrl_task = kthread_run(main_control_loop, NULL, "kfand");
}
/*
@@ -1964,7 +1984,7 @@ static void start_control_loops(void)
*/
static void stop_control_loops(void)
{
- if (ctrl_task != 0)
+ if (ctrl_task)
wait_for_completion(&ctrl_complete);
}
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index b66da74caa5..d11821af3b8 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -36,6 +36,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/kthread.h>
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -59,8 +60,7 @@ I2C_CLIENT_INSMOD;
static struct {
volatile int running;
- struct completion completion;
- pid_t poll_task;
+ struct task_struct *poll_task;
struct semaphore lock;
struct of_device *of_dev;
@@ -221,6 +221,7 @@ static void
setup_hardware( void )
{
int val;
+ int err;
/* save registers (if we unload the module) */
x.r0 = read_reg( x.fan, 0x00, 1 );
@@ -263,8 +264,11 @@ setup_hardware( void )
x.upind = -1;
/* tune_fan( fan_up_table[x.upind].fan_setting ); */
- device_create_file( &x.of_dev->dev, &dev_attr_cpu_temperature );
- device_create_file( &x.of_dev->dev, &dev_attr_case_temperature );
+ err = device_create_file( &x.of_dev->dev, &dev_attr_cpu_temperature );
+ err |= device_create_file( &x.of_dev->dev, &dev_attr_case_temperature );
+ if (err)
+ printk(KERN_WARNING
+ "Failed to create temperature attribute file(s).\n");
}
static void
@@ -280,27 +284,27 @@ restore_regs( void )
write_reg( x.fan, 0x00, x.r0, 1 );
}
-static int
-control_loop( void *dummy )
+static int control_loop(void *dummy)
{
- daemonize("g4fand");
-
- down( &x.lock );
+ down(&x.lock);
setup_hardware();
+ up(&x.lock);
- while( x.running ) {
- up( &x.lock );
-
+ for (;;) {
msleep_interruptible(8000);
-
- down( &x.lock );
+ if (kthread_should_stop())
+ break;
+
+ down(&x.lock);
poll_temp();
+ up(&x.lock);
}
+ down(&x.lock);
restore_regs();
- up( &x.lock );
+ up(&x.lock);
- complete_and_exit( &x.completion, 0 );
+ return 0;
}
@@ -320,8 +324,7 @@ do_attach( struct i2c_adapter *adapter )
ret = i2c_probe( adapter, &addr_data, &do_probe );
if( x.thermostat && x.fan ) {
x.running = 1;
- init_completion( &x.completion );
- x.poll_task = kernel_thread( control_loop, NULL, SIGCHLD | CLONE_KERNEL );
+ x.poll_task = kthread_run(control_loop, NULL, "g4fand");
}
}
return ret;
@@ -337,7 +340,8 @@ do_detach( struct i2c_client *client )
else {
if( x.running ) {
x.running = 0;
- wait_for_completion( &x.completion );
+ kthread_stop(x.poll_task);
+ x.poll_task = NULL;
}
if( client == x.thermostat )
x.thermostat = NULL;
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 7e27071746e..741a2e3f4fc 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -22,7 +22,7 @@ static u8 bl_curve[FB_BACKLIGHT_LEVELS];
static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
{
- unsigned int i, flat, count, range = (max - min);
+ int i, flat, count, range = (max - min);
bl_curve[0] = off;
@@ -68,17 +68,11 @@ static int pmu_backlight_get_level_brightness(int level)
return pmulevel;
}
-static int pmu_backlight_update_status(struct backlight_device *bd)
+static int __pmu_backlight_update_status(struct backlight_device *bd)
{
struct adb_request req;
- unsigned long flags;
int level = bd->props.brightness;
- spin_lock_irqsave(&pmu_backlight_lock, flags);
-
- /* Don't update brightness when sleeping */
- if (sleeping)
- goto out;
if (bd->props.power != FB_BLANK_UNBLANK ||
bd->props.fb_blank != FB_BLANK_UNBLANK)
@@ -99,12 +93,23 @@ static int pmu_backlight_update_status(struct backlight_device *bd)
pmu_wait_complete(&req);
}
-out:
- spin_unlock_irqrestore(&pmu_backlight_lock, flags);
-
return 0;
}
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+ /* Don't update brightness when sleeping */
+ if (!sleeping)
+ rc = __pmu_backlight_update_status(bd);
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
+ return rc;
+}
+
+
static int pmu_backlight_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
@@ -123,6 +128,16 @@ void pmu_backlight_set_sleep(int sleep)
spin_lock_irqsave(&pmu_backlight_lock, flags);
sleeping = sleep;
+ if (pmac_backlight) {
+ if (sleep) {
+ struct adb_request req;
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_OFF);
+ pmu_wait_complete(&req);
+ } else
+ __pmu_backlight_update_status(pmac_backlight);
+ }
spin_unlock_irqrestore(&pmu_backlight_lock, flags);
}
#endif /* CONFIG_PM */
@@ -148,8 +163,8 @@ void __init pmu_backlight_init()
bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data);
if (IS_ERR(bd)) {
- printk("pmubl: Backlight registration failed\n");
- goto error;
+ printk(KERN_ERR "PMU Backlight registration failed\n");
+ return;
}
bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
@@ -171,10 +186,5 @@ void __init pmu_backlight_init()
bd->props.power = FB_BLANK_UNBLANK;
backlight_update_status(bd);
- printk("pmubl: Backlight initialized (%s)\n", name);
-
- return;
-
-error:
- return;
+ printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);
}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index ac420b17e16..ebec663d5d3 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -10,13 +10,11 @@
*
* Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
* Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006-2007 Johannes Berg
*
* THIS DRIVER IS BECOMING A TOTAL MESS !
* - Cleanup atomically disabling reply to PMU events after
* a sleep or a freq. switch
- * - Move sleep code out of here to pmac_pm, merge into new
- * common PM infrastructure
- * - Save/Restore PCI space properly
*
*/
#include <stdarg.h>
@@ -33,7 +31,6 @@
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/cuda.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
@@ -65,9 +62,7 @@
#include "via-pmu-event.h"
/* Some compile options */
-#undef SUSPEND_USES_PMU
-#define DEBUG_SLEEP
-#undef HACKED_PCI_SAVE
+#undef DEBUG_SLEEP
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
@@ -152,12 +147,9 @@ static spinlock_t pmu_lock;
static u8 pmu_intr_mask;
static int pmu_version;
static int drop_interrupts;
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
-#if (defined(CONFIG_PM_SLEEP)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
-static int sleep_in_progress;
-#endif
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11];
@@ -177,7 +169,6 @@ static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
int __fake_sleep;
int asleep;
-BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
#ifdef CONFIG_ADB
static int adb_dev_map;
@@ -224,7 +215,7 @@ extern void enable_kernel_fp(void);
#ifdef DEBUG_SLEEP
int pmu_polled_request(struct adb_request *req);
-int pmu_wink(struct adb_request *req);
+void pmu_blink(int n);
#endif
/*
@@ -875,7 +866,7 @@ proc_read_options(char *page, char **start, off_t off,
{
char *p = page;
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
@@ -916,7 +907,7 @@ proc_write_options(struct file *file, const char __user *buffer,
*(val++) = 0;
while(*val == ' ')
val++;
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
if (!strcmp(label, "lid_wakeup"))
@@ -1256,9 +1247,7 @@ void
pmu_suspend(void)
{
unsigned long flags;
-#ifdef SUSPEND_USES_PMU
- struct adb_request *req;
-#endif
+
if (!via)
return;
@@ -1276,17 +1265,10 @@ pmu_suspend(void)
via_pmu_interrupt(0, NULL);
spin_lock_irqsave(&pmu_lock, flags);
if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
-#ifdef SUSPEND_USES_PMU
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
- spin_unlock_irqrestore(&pmu_lock, flags);
- while(!req.complete)
- pmu_poll();
-#else /* SUSPEND_USES_PMU */
if (gpio_irq >= 0)
disable_irq_nosync(gpio_irq);
out_8(&via[IER], CB1_INT | IER_CLR);
spin_unlock_irqrestore(&pmu_lock, flags);
-#endif /* SUSPEND_USES_PMU */
break;
}
} while (1);
@@ -1307,18 +1289,11 @@ pmu_resume(void)
return;
}
adb_int_pending = 1;
-#ifdef SUSPEND_USES_PMU
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
- spin_unlock_irqrestore(&pmu_lock, flags);
- while(!req.complete)
- pmu_poll();
-#else /* SUSPEND_USES_PMU */
if (gpio_irq >= 0)
enable_irq(gpio_irq);
out_8(&via[IER], CB1_INT | IER_SET);
spin_unlock_irqrestore(&pmu_lock, flags);
pmu_poll();
-#endif /* SUSPEND_USES_PMU */
}
/* Interrupt data could be the result data from an ADB cmd */
@@ -1738,228 +1713,7 @@ pmu_present(void)
return via != 0;
}
-#ifdef CONFIG_PM_SLEEP
-
-static LIST_HEAD(sleep_notifiers);
-
-int
-pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
-{
- struct list_head *list;
- struct pmu_sleep_notifier *notifier;
-
- for (list = sleep_notifiers.next; list != &sleep_notifiers;
- list = list->next) {
- notifier = list_entry(list, struct pmu_sleep_notifier, list);
- if (n->priority > notifier->priority)
- break;
- }
- __list_add(&n->list, list->prev, list);
- return 0;
-}
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-
-int
-pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
-{
- if (n->list.next == 0)
- return -ENOENT;
- list_del(&n->list);
- n->list.next = NULL;
- return 0;
-}
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-#endif /* CONFIG_PM_SLEEP */
-
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
-
-/* Sleep is broadcast last-to-first */
-static void broadcast_sleep(int when)
-{
- struct list_head *list;
- struct pmu_sleep_notifier *notifier;
-
- for (list = sleep_notifiers.prev; list != &sleep_notifiers;
- list = list->prev) {
- notifier = list_entry(list, struct pmu_sleep_notifier, list);
- notifier->notifier_call(notifier, when);
- }
-}
-
-/* Wake is broadcast first-to-last */
-static void broadcast_wake(void)
-{
- struct list_head *list;
- struct pmu_sleep_notifier *notifier;
-
- for (list = sleep_notifiers.next; list != &sleep_notifiers;
- list = list->next) {
- notifier = list_entry(list, struct pmu_sleep_notifier, list);
- notifier->notifier_call(notifier, PBOOK_WAKE);
- }
-}
-
-/*
- * This struct is used to store config register values for
- * PCI devices which may get powered off when we sleep.
- */
-static struct pci_save {
-#ifndef HACKED_PCI_SAVE
- u16 command;
- u16 cache_lat;
- u16 intr;
- u32 rom_address;
-#else
- u32 config[16];
-#endif
-} *pbook_pci_saves;
-static int pbook_npci_saves;
-
-static void
-pbook_alloc_pci_save(void)
-{
- int npci;
- struct pci_dev *pd = NULL;
-
- npci = 0;
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
- ++npci;
- }
- if (npci == 0)
- return;
- pbook_pci_saves = (struct pci_save *)
- kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
- pbook_npci_saves = npci;
-}
-
-static void
-pbook_free_pci_save(void)
-{
- if (pbook_pci_saves == NULL)
- return;
- kfree(pbook_pci_saves);
- pbook_pci_saves = NULL;
- pbook_npci_saves = 0;
-}
-
-static void
-pbook_pci_save(void)
-{
- struct pci_save *ps = pbook_pci_saves;
- struct pci_dev *pd = NULL;
- int npci = pbook_npci_saves;
-
- if (ps == NULL)
- return;
-
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
- if (npci-- == 0) {
- pci_dev_put(pd);
- return;
- }
-#ifndef HACKED_PCI_SAVE
- pci_read_config_word(pd, PCI_COMMAND, &ps->command);
- pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
- pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
- pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
-#else
- int i;
- for (i=1;i<16;i++)
- pci_read_config_dword(pd, i<<4, &ps->config[i]);
-#endif
- ++ps;
- }
-}
-
-/* For this to work, we must take care of a few things: If gmac was enabled
- * during boot, it will be in the pci dev list. If it's disabled at this point
- * (and it will probably be), then you can't access it's config space.
- */
-static void
-pbook_pci_restore(void)
-{
- u16 cmd;
- struct pci_save *ps = pbook_pci_saves - 1;
- struct pci_dev *pd = NULL;
- int npci = pbook_npci_saves;
- int j;
-
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-#ifdef HACKED_PCI_SAVE
- int i;
- if (npci-- == 0) {
- pci_dev_put(pd);
- return;
- }
- ps++;
- for (i=2;i<16;i++)
- pci_write_config_dword(pd, i<<4, ps->config[i]);
- pci_write_config_dword(pd, 4, ps->config[1]);
-#else
- if (npci-- == 0)
- return;
- ps++;
- if (ps->command == 0)
- continue;
- pci_read_config_word(pd, PCI_COMMAND, &cmd);
- if ((ps->command & ~cmd) == 0)
- continue;
- switch (pd->hdr_type) {
- case PCI_HEADER_TYPE_NORMAL:
- for (j = 0; j < 6; ++j)
- pci_write_config_dword(pd,
- PCI_BASE_ADDRESS_0 + j*4,
- pd->resource[j].start);
- pci_write_config_dword(pd, PCI_ROM_ADDRESS,
- ps->rom_address);
- pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
- ps->cache_lat);
- pci_write_config_word(pd, PCI_INTERRUPT_LINE,
- ps->intr);
- pci_write_config_word(pd, PCI_COMMAND, ps->command);
- break;
- }
-#endif
- }
-}
-
-#ifdef DEBUG_SLEEP
-/* N.B. This doesn't work on the 3400 */
-void
-pmu_blink(int n)
-{
- struct adb_request req;
-
- memset(&req, 0, sizeof(req));
-
- for (; n > 0; --n) {
- req.nbytes = 4;
- req.done = NULL;
- req.data[0] = 0xee;
- req.data[1] = 4;
- req.data[2] = 0;
- req.data[3] = 1;
- req.reply[0] = ADB_RET_OK;
- req.reply_len = 1;
- req.reply_expected = 0;
- pmu_polled_request(&req);
- mdelay(50);
- req.nbytes = 4;
- req.done = NULL;
- req.data[0] = 0xee;
- req.data[1] = 4;
- req.data[2] = 0;
- req.data[3] = 0;
- req.reply[0] = ADB_RET_OK;
- req.reply_len = 1;
- req.reply_expected = 0;
- pmu_polled_request(&req);
- mdelay(50);
- }
- mdelay(50);
-}
-#endif
-
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
/*
* Put the powerbook to sleep.
*/
@@ -1994,134 +1748,6 @@ restore_via_state(void)
out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
}
-extern void pmu_backlight_set_sleep(int sleep);
-
-static int
-pmac_suspend_devices(void)
-{
- int ret;
-
- pm_prepare_console();
-
- /* Notify old-style device drivers */
- broadcast_sleep(PBOOK_SLEEP_REQUEST);
-
- /* Sync the disks. */
- /* XXX It would be nice to have some way to ensure that
- * nobody is dirtying any new buffers while we wait. That
- * could be achieved using the refrigerator for processes
- * that swsusp uses
- */
- sys_sync();
-
- broadcast_sleep(PBOOK_SLEEP_NOW);
-
- /* Send suspend call to devices, hold the device core's dpm_sem */
- ret = device_suspend(PMSG_SUSPEND);
- if (ret) {
- broadcast_wake();
- printk(KERN_ERR "Driver sleep failed\n");
- return -EBUSY;
- }
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code not to muck around with the chip anymore */
- pmu_backlight_set_sleep(1);
-#endif
-
- /* Call platform functions marked "on sleep" */
- pmac_pfunc_i2c_suspend();
- pmac_pfunc_base_suspend();
-
- /* Stop preemption */
- preempt_disable();
-
- /* Make sure the decrementer won't interrupt us */
- asm volatile("mtdec %0" : : "r" (0x7fffffff));
- /* Make sure any pending DEC interrupt occurring while we did
- * the above didn't re-enable the DEC */
- mb();
- asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
- /* We can now disable MSR_EE. This code of course works properly only
- * on UP machines... For SMP, if we ever implement sleep, we'll have to
- * stop the "other" CPUs way before we do all that stuff.
- */
- local_irq_disable();
-
- /* Broadcast power down irq
- * This isn't that useful in most cases (only directly wired devices can
- * use this but still... This will take care of sysdev's as well, so
- * we exit from here with local irqs disabled and PIC off.
- */
- ret = device_power_down(PMSG_SUSPEND);
- if (ret) {
- wakeup_decrementer();
- local_irq_enable();
- preempt_enable();
- device_resume();
- broadcast_wake();
- printk(KERN_ERR "Driver powerdown failed\n");
- return -EBUSY;
- }
-
- /* Wait for completion of async requests */
- while (!batt_req.complete)
- pmu_poll();
-
- /* Giveup the lazy FPU & vec so we don't have to back them
- * up from the low level code
- */
- enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
- if (cpu_has_feature(CPU_FTR_ALTIVEC))
- enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
- return 0;
-}
-
-static int
-pmac_wakeup_devices(void)
-{
- mdelay(100);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code it can use the chip again */
- pmu_backlight_set_sleep(0);
-#endif
-
- /* Power back up system devices (including the PIC) */
- device_power_up();
-
- /* Force a poll of ADB interrupts */
- adb_int_pending = 1;
- via_pmu_interrupt(0, NULL);
-
- /* Restart jiffies & scheduling */
- wakeup_decrementer();
-
- /* Re-enable local CPU interrupts */
- local_irq_enable();
- mdelay(10);
- preempt_enable();
-
- /* Call platform functions marked "on wake" */
- pmac_pfunc_base_resume();
- pmac_pfunc_i2c_resume();
-
- /* Resume devices */
- device_resume();
-
- /* Notify old style drivers */
- broadcast_wake();
-
- pm_restore_console();
-
- return 0;
-}
-
#define GRACKLE_PM (1<<7)
#define GRACKLE_DOZE (1<<5)
#define GRACKLE_NAP (1<<4)
@@ -2132,19 +1758,12 @@ static int powerbook_sleep_grackle(void)
unsigned long save_l2cr;
unsigned short pmcr1;
struct adb_request req;
- int ret;
struct pci_dev *grackle;
grackle = pci_get_bus_and_slot(0, 0);
if (!grackle)
return -ENODEV;
- ret = pmac_suspend_devices();
- if (ret) {
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
/* Turn off various things. Darwin does some retry tests here... */
pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
pmu_wait_complete(&req);
@@ -2207,8 +1826,6 @@ static int powerbook_sleep_grackle(void)
PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
pmu_wait_complete(&req);
- pmac_wakeup_devices();
-
return 0;
}
@@ -2218,7 +1835,6 @@ powerbook_sleep_Core99(void)
unsigned long save_l2cr;
unsigned long save_l3cr;
struct adb_request req;
- int ret;
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
printk(KERN_ERR "Sleep mode not supported on this machine\n");
@@ -2228,12 +1844,6 @@ powerbook_sleep_Core99(void)
if (num_online_cpus() > 1 || cpu_is_offline(0))
return -EAGAIN;
- ret = pmac_suspend_devices();
- if (ret) {
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
/* Stop environment and ADB interrupts */
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
pmu_wait_complete(&req);
@@ -2304,45 +1914,33 @@ powerbook_sleep_Core99(void)
/* Restore LPJ, cpufreq will adjust the cpu frequency */
loops_per_jiffy /= 2;
- pmac_wakeup_devices();
-
return 0;
}
#define PB3400_MEM_CTRL 0xf8000000
#define PB3400_MEM_CTRL_SLEEP 0x70
-static int
-powerbook_sleep_3400(void)
+static void __iomem *pb3400_mem_ctrl;
+
+static void powerbook_sleep_init_3400(void)
+{
+ /* map in the memory controller registers */
+ pb3400_mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
+ if (pb3400_mem_ctrl == NULL)
+ printk(KERN_WARNING "ioremap failed: sleep won't be possible");
+}
+
+static int powerbook_sleep_3400(void)
{
- int ret, i, x;
+ int i, x;
unsigned int hid0;
- unsigned long p;
+ unsigned long msr;
struct adb_request sleep_req;
- void __iomem *mem_ctrl;
unsigned int __iomem *mem_ctrl_sleep;
- /* first map in the memory controller registers */
- mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
- if (mem_ctrl == NULL) {
- printk("powerbook_sleep_3400: ioremap failed\n");
+ if (pb3400_mem_ctrl == NULL)
return -ENOMEM;
- }
- mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
-
- /* Allocate room for PCI save */
- pbook_alloc_pci_save();
-
- ret = pmac_suspend_devices();
- if (ret) {
- pbook_free_pci_save();
- iounmap(mem_ctrl);
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
- /* Save the state of PCI config space for some slots */
- pbook_pci_save();
+ mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP;
/* Set the memory controller to keep the memory refreshed
while we're asleep */
@@ -2357,41 +1955,34 @@ powerbook_sleep_3400(void)
/* Ask the PMU to put us to sleep */
pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!sleep_req.complete)
- mb();
+ pmu_wait_complete(&sleep_req);
+ pmu_unlock();
- pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
+ pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
- /* displacement-flush the L2 cache - necessary? */
- for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
- i = *(volatile int *)p;
asleep = 1;
/* Put the CPU into sleep mode */
hid0 = mfspr(SPRN_HID0);
hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
mtspr(SPRN_HID0, hid0);
- mtmsr(mfmsr() | MSR_POW | MSR_EE);
- udelay(10);
+ local_irq_enable();
+ msr = mfmsr() | MSR_POW;
+ while (asleep) {
+ mb();
+ mtmsr(msr);
+ isync();
+ }
+ local_irq_disable();
/* OK, we're awake again, start restoring things */
out_be32(mem_ctrl_sleep, 0x3f);
- pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
- pbook_pci_restore();
- pmu_unlock();
-
- /* wait for the PMU interrupt sequence to complete */
- while (asleep)
- mb();
-
- pmac_wakeup_devices();
- pbook_free_pci_save();
- iounmap(mem_ctrl);
+ pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
return 0;
}
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
/*
* Support for /dev/pmu device
@@ -2548,7 +2139,6 @@ pmu_release(struct inode *inode, struct file *file)
struct pmu_private *pp = file->private_data;
unsigned long flags;
- lock_kernel();
if (pp != 0) {
file->private_data = NULL;
spin_lock_irqsave(&all_pvt_lock, flags);
@@ -2562,10 +2152,96 @@ pmu_release(struct inode *inode, struct file *file)
kfree(pp);
}
- unlock_kernel();
return 0;
}
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
+static void pmac_suspend_disable_irqs(void)
+{
+ /* Call platform functions marked "on sleep" */
+ pmac_pfunc_i2c_suspend();
+ pmac_pfunc_base_suspend();
+}
+
+static int powerbook_sleep(suspend_state_t state)
+{
+ int error = 0;
+
+ /* Wait for completion of async requests */
+ while (!batt_req.complete)
+ pmu_poll();
+
+ /* Giveup the lazy FPU & vec so we don't have to back them
+ * up from the low level code
+ */
+ enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+ switch (pmu_kind) {
+ case PMU_OHARE_BASED:
+ error = powerbook_sleep_3400();
+ break;
+ case PMU_HEATHROW_BASED:
+ case PMU_PADDINGTON_BASED:
+ error = powerbook_sleep_grackle();
+ break;
+ case PMU_KEYLARGO_BASED:
+ error = powerbook_sleep_Core99();
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ if (error)
+ return error;
+
+ mdelay(100);
+
+ return 0;
+}
+
+static void pmac_suspend_enable_irqs(void)
+{
+ /* Force a poll of ADB interrupts */
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, NULL);
+
+ mdelay(10);
+
+ /* Call platform functions marked "on wake" */
+ pmac_pfunc_base_resume();
+ pmac_pfunc_i2c_resume();
+}
+
+static int pmu_sleep_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM
+ && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0);
+}
+
+static struct platform_suspend_ops pmu_pm_ops = {
+ .enter = powerbook_sleep,
+ .valid = pmu_sleep_valid,
+};
+
+static int register_pmu_pm_ops(void)
+{
+ if (pmu_kind == PMU_OHARE_BASED)
+ powerbook_sleep_init_3400();
+ ppc_md.suspend_disable_irqs = pmac_suspend_disable_irqs;
+ ppc_md.suspend_enable_irqs = pmac_suspend_enable_irqs;
+ suspend_set_ops(&pmu_pm_ops);
+
+ return 0;
+}
+
+device_initcall(register_pmu_pm_ops);
+#endif
+
static int
pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
@@ -2574,35 +2250,15 @@ pmu_ioctl(struct inode * inode, struct file *filp,
int error = -EINVAL;
switch (cmd) {
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (sleep_in_progress)
- return -EBUSY;
- sleep_in_progress = 1;
- switch (pmu_kind) {
- case PMU_OHARE_BASED:
- error = powerbook_sleep_3400();
- break;
- case PMU_HEATHROW_BASED:
- case PMU_PADDINGTON_BASED:
- error = powerbook_sleep_grackle();
- break;
- case PMU_KEYLARGO_BASED:
- error = powerbook_sleep_Core99();
- break;
- default:
- error = -ENOSYS;
- }
- sleep_in_progress = 0;
- break;
+ return pm_suspend(PM_SUSPEND_MEM);
case PMU_IOC_CAN_SLEEP:
- if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
+ if (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) < 0)
return put_user(0, argp);
else
return put_user(1, argp);
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
/* Compatibility ioctl's for backlight */
@@ -2610,9 +2266,6 @@ pmu_ioctl(struct inode * inode, struct file *filp,
{
int brightness;
- if (sleep_in_progress)
- return -EBUSY;
-
brightness = pmac_backlight_get_legacy_brightness();
if (brightness < 0)
return brightness;
@@ -2624,9 +2277,6 @@ pmu_ioctl(struct inode * inode, struct file *filp,
{
int brightness;
- if (sleep_in_progress)
- return -EBUSY;
-
error = get_user(brightness, argp);
if (error)
return error;
@@ -2751,15 +2401,43 @@ pmu_polled_request(struct adb_request *req)
local_irq_restore(flags);
return 0;
}
-#endif /* DEBUG_SLEEP */
+/* N.B. This doesn't work on the 3400 */
+void pmu_blink(int n)
+{
+ struct adb_request req;
-/* FIXME: This is a temporary set of callbacks to enable us
- * to do suspend-to-disk.
- */
+ memset(&req, 0, sizeof(req));
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+ for (; n > 0; --n) {
+ req.nbytes = 4;
+ req.done = NULL;
+ req.data[0] = 0xee;
+ req.data[1] = 4;
+ req.data[2] = 0;
+ req.data[3] = 1;
+ req.reply[0] = ADB_RET_OK;
+ req.reply_len = 1;
+ req.reply_expected = 0;
+ pmu_polled_request(&req);
+ mdelay(50);
+ req.nbytes = 4;
+ req.done = NULL;
+ req.data[0] = 0xee;
+ req.data[1] = 4;
+ req.data[2] = 0;
+ req.data[3] = 0;
+ req.reply[0] = ADB_RET_OK;
+ req.reply_len = 1;
+ req.reply_expected = 0;
+ pmu_polled_request(&req);
+ mdelay(50);
+ }
+ mdelay(50);
+}
+#endif /* DEBUG_SLEEP */
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
int pmu_sys_suspended;
static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
@@ -2767,10 +2445,15 @@ static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
return 0;
- /* Suspend PMU event interrupts */
+ /* Suspend PMU event interrupts */\
pmu_suspend();
-
pmu_sys_suspended = 1;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code not to muck around with the chip anymore */
+ pmu_backlight_set_sleep(1);
+#endif
+
return 0;
}
@@ -2785,15 +2468,18 @@ static int pmu_sys_resume(struct sys_device *sysdev)
pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
pmu_wait_complete(&req);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code it can use the chip again */
+ pmu_backlight_set_sleep(0);
+#endif
/* Resume PMU event interrupts */
pmu_resume();
-
pmu_sys_suspended = 0;
return 0;
}
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
static struct sysdev_class pmu_sysclass = {
.name = "pmu",
@@ -2804,10 +2490,10 @@ static struct sys_device device_pmu = {
};
static struct sysdev_driver driver_pmu = {
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
.suspend = &pmu_sys_suspend,
.resume = &pmu_sys_resume,
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
};
static int __init init_pmu_sysfs(void)
@@ -2842,10 +2528,10 @@ EXPORT_SYMBOL(pmu_wait_complete);
EXPORT_SYMBOL(pmu_suspend);
EXPORT_SYMBOL(pmu_resume);
EXPORT_SYMBOL(pmu_unlock);
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
EXPORT_SYMBOL(pmu_batteries);
EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6c575403bd3..389980f0e59 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2356,7 +2356,7 @@ config GELIC_NET
config GIANFAR
tristate "Gianfar Ethernet"
- depends on 85xx || 83xx || PPC_86xx
+ depends on FSL_SOC
select PHYLIB
select CRC32
help
diff --git a/drivers/net/fec_8xx/fec_8xx-netta.c b/drivers/net/fec_8xx/fec_8xx-netta.c
index e492eb84f94..79deee222e2 100644
--- a/drivers/net/fec_8xx/fec_8xx-netta.c
+++ b/drivers/net/fec_8xx/fec_8xx-netta.c
@@ -26,7 +26,7 @@
#include <asm/mpc8xx.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
#include "fec_8xx.h"
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index ab9637ab3a8..ca8d2e83ab0 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -35,7 +35,7 @@
#include <asm/mpc8xx.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
#include "fec_8xx.h"
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index e8e10a02d20..3b6ca29d31f 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -34,7 +34,7 @@
#include <asm/mpc8xx.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
/*************************************************/
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index f91ee700e60..58b71e60204 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -1057,10 +1057,8 @@ static int mpc52xx_fec_of_resume(struct of_device *op)
#endif
static struct of_device_id mpc52xx_fec_match[] = {
- {
- .type = "network",
- .compatible = "mpc5200-fec",
- },
+ { .type = "network", .compatible = "fsl,mpc5200-fec", },
+ { .type = "network", .compatible = "mpc5200-fec", },
{ }
};
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index ba6e8b218e0..1837584c450 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -177,11 +177,9 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of)
static struct of_device_id mpc52xx_fec_mdio_match[] = {
- {
- .type = "mdio",
- .compatible = "mpc5200b-fec-phy",
- },
- {},
+ { .compatible = "fsl,mpc5200b-mdio", },
+ { .compatible = "mpc5200b-fec-phy", },
+ {}
};
struct of_platform_driver mpc52xx_fec_mdio_driver = {
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index c83bd656008..42d94edeee2 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1178,8 +1178,15 @@ static int __devinit find_phy(struct device_node *np,
struct device_node *phynode, *mdionode;
struct resource res;
int ret = 0, len;
+ const u32 *data;
+
+ data = of_get_property(np, "fixed-link", NULL);
+ if (data) {
+ snprintf(fpi->bus_id, 16, PHY_ID_FMT, 0, *data);
+ return 0;
+ }
- const u32 *data = of_get_property(np, "phy-handle", &len);
+ data = of_get_property(np, "phy-handle", &len);
if (!data || len != 4)
return -EINVAL;
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index c675e29aadc..e05389c49bb 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -12,7 +12,7 @@
#include <asm/fs_pd.h>
#ifdef CONFIG_CPM1
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
struct fec_info {
fec_t __iomem *fecp;
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index da4efbca646..e36321152d5 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -81,16 +81,8 @@
static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
- int i;
-
- W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
- for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
- if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- return 0;
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
+ return cpm_command(fpi->cp_command, op);
}
static int do_pd_setup(struct fs_enet_private *fep)
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index c1fee48517e..8a311d1e435 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -40,7 +40,7 @@
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
#endif
#ifdef CONFIG_PPC_CPM_NEW_BINDING
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 48f2f300593..d7ca31945c8 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -40,7 +40,7 @@
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
#endif
#ifdef CONFIG_PPC_CPM_NEW_BINDING
@@ -89,21 +89,12 @@
* Delay to wait for SCC reset command to complete (in us)
*/
#define SCC_RESET_DELAY 50
-#define MAX_CR_CMD_LOOPS 10000
static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
- int i;
-
- W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
- for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
- if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- return 0;
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
+ return cpm_command(fpi->cp_command, op);
}
static int do_pd_setup(struct fs_enet_private *fep)
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index b24bd2dfb72..e6c69f77259 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -37,6 +37,7 @@
#include <linux/mii.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
+#include <linux/of.h>
#include <asm/processor.h>
#include <asm/io.h>
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 54b2ba99664..7fe03ce774b 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -61,34 +61,12 @@ config ICPLUS_PHY
Currently supports the IP175C PHY.
config FIXED_PHY
- tristate "Drivers for PHY emulation on fixed speed/link"
+ bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
---help---
- Adds the driver to PHY layer to cover the boards that do not have any PHY bound,
- but with the ability to manipulate the speed/link in software. The relevant MII
- speed/duplex parameters could be effectively handled in a user-specified function.
- Currently tested with mpc866ads.
-
-config FIXED_MII_10_FDX
- bool "Emulation for 10M Fdx fixed PHY behavior"
- depends on FIXED_PHY
-
-config FIXED_MII_100_FDX
- bool "Emulation for 100M Fdx fixed PHY behavior"
- depends on FIXED_PHY
-
-config FIXED_MII_1000_FDX
- bool "Emulation for 1000M Fdx fixed PHY behavior"
- depends on FIXED_PHY
-
-config FIXED_MII_AMNT
- int "Number of emulated PHYs to allocate "
- depends on FIXED_PHY
- default "1"
- ---help---
- Sometimes it is required to have several independent emulated
- PHYs on the bus (in case of multi-eth but phy-less HW for instance).
- This control will have specified number allocated for each fixed
- PHY type enabled.
+ Adds the platform "fixed" MDIO Bus to cover the boards that use
+ PHYs that are not connected to the real MDIO bus.
+
+ Currently tested with mpc866ads and mpc8349e-mitx.
config MDIO_BITBANG
tristate "Support for bitbanged MDIO buses"
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 56191822fa2..73b6d39ef6b 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -1,362 +1,253 @@
/*
- * drivers/net/phy/fixed.c
+ * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
*
- * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode.
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
*
- * Author: Vitaly Bordug
- *
- * Copyright (c) 2006 MontaVista Software, Inc.
+ * Copyright (c) 2006-2007 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
- *
*/
+
#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
#include <linux/mii.h>
-#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/phy_fixed.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#define MII_REGS_NUM 29
-/* we need to track the allocated pointers in order to free them on exit */
-static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
-
-/*-----------------------------------------------------------------------------
- * If something weird is required to be done with link/speed,
- * network driver is able to assign a function to implement this.
- * May be useful for PHY's that need to be software-driven.
- *-----------------------------------------------------------------------------*/
-int fixed_mdio_set_link_update(struct phy_device *phydev,
- int (*link_update) (struct net_device *,
- struct fixed_phy_status *))
-{
- struct fixed_info *fixed;
-
- if (link_update == NULL)
- return -EINVAL;
-
- if (phydev) {
- if (phydev->bus) {
- fixed = phydev->bus->priv;
- fixed->link_update = link_update;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-EXPORT_SYMBOL(fixed_mdio_set_link_update);
+struct fixed_mdio_bus {
+ int irqs[PHY_MAX_ADDR];
+ struct mii_bus mii_bus;
+ struct list_head phys;
+};
-struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
-{
- if (phydev_ind >= MAX_PHY_AMNT)
- return NULL;
- return fixed_phy_ptrs[phydev_ind];
-}
+struct fixed_phy {
+ int id;
+ u16 regs[MII_REGS_NUM];
+ struct phy_device *phydev;
+ struct fixed_phy_status status;
+ int (*link_update)(struct net_device *, struct fixed_phy_status *);
+ struct list_head node;
+};
-EXPORT_SYMBOL(fixed_mdio_get_phydev);
+static struct platform_device *pdev;
+static struct fixed_mdio_bus platform_fmb = {
+ .phys = LIST_HEAD_INIT(platform_fmb.phys),
+};
-/*-----------------------------------------------------------------------------
- * This is used for updating internal mii regs from the status
- *-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
-static int fixed_mdio_update_regs(struct fixed_info *fixed)
+static int fixed_phy_update_regs(struct fixed_phy *fp)
{
- u16 *regs = fixed->regs;
- u16 bmsr = 0;
+ u16 bmsr = BMSR_ANEGCAPABLE;
u16 bmcr = 0;
+ u16 lpagb = 0;
+ u16 lpa = 0;
- if (!regs) {
- printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
- return -EINVAL;
- }
-
- if (fixed->phy_status.link)
- bmsr |= BMSR_LSTATUS;
-
- if (fixed->phy_status.duplex) {
+ if (fp->status.duplex) {
bmcr |= BMCR_FULLDPLX;
- switch (fixed->phy_status.speed) {
+ switch (fp->status.speed) {
+ case 1000:
+ bmsr |= BMSR_ESTATEN;
+ bmcr |= BMCR_SPEED1000;
+ lpagb |= LPA_1000FULL;
+ break;
case 100:
bmsr |= BMSR_100FULL;
bmcr |= BMCR_SPEED100;
+ lpa |= LPA_100FULL;
break;
-
case 10:
bmsr |= BMSR_10FULL;
+ lpa |= LPA_10FULL;
break;
+ default:
+ printk(KERN_WARNING "fixed phy: unknown speed\n");
+ return -EINVAL;
}
} else {
- switch (fixed->phy_status.speed) {
+ switch (fp->status.speed) {
+ case 1000:
+ bmsr |= BMSR_ESTATEN;
+ bmcr |= BMCR_SPEED1000;
+ lpagb |= LPA_1000HALF;
+ break;
case 100:
bmsr |= BMSR_100HALF;
bmcr |= BMCR_SPEED100;
+ lpa |= LPA_100HALF;
break;
-
case 10:
- bmsr |= BMSR_100HALF;
+ bmsr |= BMSR_10HALF;
+ lpa |= LPA_10HALF;
break;
+ default:
+ printk(KERN_WARNING "fixed phy: unknown speed\n");
+ return -EINVAL;
}
}
- regs[MII_BMCR] = bmcr;
- regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */
+ if (fp->status.link)
+ bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
+
+ if (fp->status.pause)
+ lpa |= LPA_PAUSE_CAP;
+
+ if (fp->status.asym_pause)
+ lpa |= LPA_PAUSE_ASYM;
+
+ fp->regs[MII_PHYSID1] = fp->id >> 16;
+ fp->regs[MII_PHYSID2] = fp->id;
+
+ fp->regs[MII_BMSR] = bmsr;
+ fp->regs[MII_BMCR] = bmcr;
+ fp->regs[MII_LPA] = lpa;
+ fp->regs[MII_STAT1000] = lpagb;
return 0;
}
-static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
+static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num)
{
- struct fixed_info *fixed = bus->priv;
-
- /* if user has registered link update callback, use it */
- if (fixed->phydev)
- if (fixed->phydev->attached_dev) {
- if (fixed->link_update) {
- fixed->link_update(fixed->phydev->attached_dev,
- &fixed->phy_status);
- fixed_mdio_update_regs(fixed);
+ struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus,
+ mii_bus);
+ struct fixed_phy *fp;
+
+ if (reg_num >= MII_REGS_NUM)
+ return -1;
+
+ list_for_each_entry(fp, &fmb->phys, node) {
+ if (fp->id == phy_id) {
+ /* Issue callback if user registered it. */
+ if (fp->link_update) {
+ fp->link_update(fp->phydev->attached_dev,
+ &fp->status);
+ fixed_phy_update_regs(fp);
}
+ return fp->regs[reg_num];
}
+ }
- if ((unsigned int)location >= fixed->regs_num)
- return -1;
- return fixed->regs[location];
+ return 0xFFFF;
}
-static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
- u16 val)
+static int fixed_mdio_write(struct mii_bus *bus, int phy_id, int reg_num,
+ u16 val)
{
- /* do nothing for now */
return 0;
}
-static int fixed_mii_reset(struct mii_bus *bus)
+/*
+ * If something weird is required to be done with link/speed,
+ * network driver is able to assign a function to implement this.
+ * May be useful for PHY's that need to be software-driven.
+ */
+int fixed_phy_set_link_update(struct phy_device *phydev,
+ int (*link_update)(struct net_device *,
+ struct fixed_phy_status *))
{
- /*nothing here - no way/need to reset it */
- return 0;
-}
-#endif
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp;
-static int fixed_config_aneg(struct phy_device *phydev)
-{
- /* :TODO:03/13/2006 09:45:37 PM::
- The full autoneg funcionality can be emulated,
- but no need to have anything here for now
- */
- return 0;
-}
+ if (!link_update || !phydev || !phydev->bus)
+ return -EINVAL;
-/*-----------------------------------------------------------------------------
- * the manual bind will do the magic - with phy_id_mask == 0
- * match will never return true...
- *-----------------------------------------------------------------------------*/
-static struct phy_driver fixed_mdio_driver = {
- .name = "Fixed PHY",
-#ifdef CONFIG_FIXED_MII_1000_FDX
- .features = PHY_GBIT_FEATURES,
-#else
- .features = PHY_BASIC_FEATURES,
-#endif
- .config_aneg = fixed_config_aneg,
- .read_status = genphy_read_status,
- .driver = { .owner = THIS_MODULE, },
-};
+ list_for_each_entry(fp, &fmb->phys, node) {
+ if (fp->id == phydev->phy_id) {
+ fp->link_update = link_update;
+ fp->phydev = phydev;
+ return 0;
+ }
+ }
-static void fixed_mdio_release(struct device *dev)
-{
- struct phy_device *phydev = container_of(dev, struct phy_device, dev);
- struct mii_bus *bus = phydev->bus;
- struct fixed_info *fixed = bus->priv;
-
- kfree(phydev);
- kfree(bus->dev);
- kfree(bus);
- kfree(fixed->regs);
- kfree(fixed);
+ return -ENOENT;
}
+EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
-/*-----------------------------------------------------------------------------
- * This func is used to create all the necessary stuff, bind
- * the fixed phy driver and register all it on the mdio_bus_type.
- * speed is either 10 or 100 or 1000, duplex is boolean.
- * number is used to create multiple fixed PHYs, so that several devices can
- * utilize them simultaneously.
- *
- * The device on mdio bus will look like [bus_id]:[phy_id],
- * bus_id = number
- * phy_id = speed+duplex.
- *-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
-struct fixed_info *fixed_mdio_register_device(
- int bus_id, int speed, int duplex, u8 phy_id)
+int fixed_phy_add(unsigned int irq, int phy_id,
+ struct fixed_phy_status *status)
{
- struct mii_bus *new_bus;
- struct fixed_info *fixed;
- struct phy_device *phydev;
- int err;
+ int ret;
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp;
- struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
- if (dev == NULL)
- goto err_dev_alloc;
+ memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM);
- new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ fmb->irqs[phy_id] = irq;
- if (new_bus == NULL)
- goto err_bus_alloc;
+ fp->id = phy_id;
+ fp->status = *status;
- fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
+ ret = fixed_phy_update_regs(fp);
+ if (ret)
+ goto err_regs;
- if (fixed == NULL)
- goto err_fixed_alloc;
+ list_add_tail(&fp->node, &fmb->phys);
- fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
- if (NULL == fixed->regs)
- goto err_fixed_regs_alloc;
+ return 0;
- fixed->regs_num = MII_REGS_NUM;
- fixed->phy_status.speed = speed;
- fixed->phy_status.duplex = duplex;
- fixed->phy_status.link = 1;
+err_regs:
+ kfree(fp);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_add);
- new_bus->name = "Fixed MII Bus";
- new_bus->read = &fixed_mii_read;
- new_bus->write = &fixed_mii_write;
- new_bus->reset = &fixed_mii_reset;
- /*set up workspace */
- fixed_mdio_update_regs(fixed);
- new_bus->priv = fixed;
+static int __init fixed_mdio_bus_init(void)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ int ret;
- new_bus->dev = dev;
- dev_set_drvdata(dev, new_bus);
+ pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err_pdev;
+ }
- /* create phy_device and register it on the mdio bus */
- phydev = phy_device_create(new_bus, 0, 0);
- if (phydev == NULL)
- goto err_phy_dev_create;
+ fmb->mii_bus.id = 0;
+ fmb->mii_bus.name = "Fixed MDIO Bus";
+ fmb->mii_bus.dev = &pdev->dev;
+ fmb->mii_bus.read = &fixed_mdio_read;
+ fmb->mii_bus.write = &fixed_mdio_write;
+ fmb->mii_bus.irq = fmb->irqs;
- /*
- * Put the phydev pointer into the fixed pack so that bus read/write
- * code could be able to access for instance attached netdev. Well it
- * doesn't have to do so, only in case of utilizing user-specified
- * link-update...
- */
+ ret = mdiobus_register(&fmb->mii_bus);
+ if (ret)
+ goto err_mdiobus_reg;
- fixed->phydev = phydev;
- phydev->speed = speed;
- phydev->duplex = duplex;
+ return 0;
- phydev->irq = PHY_IGNORE_INTERRUPT;
- phydev->dev.bus = &mdio_bus_type;
+err_mdiobus_reg:
+ platform_device_unregister(pdev);
+err_pdev:
+ return ret;
+}
+module_init(fixed_mdio_bus_init);
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- PHY_ID_FMT, bus_id, phy_id);
+static void __exit fixed_mdio_bus_exit(void)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp;
- phydev->bus = new_bus;
+ mdiobus_unregister(&fmb->mii_bus);
+ platform_device_unregister(pdev);
- phydev->dev.driver = &fixed_mdio_driver.driver;
- phydev->dev.release = fixed_mdio_release;
- err = phydev->dev.driver->probe(&phydev->dev);
- if (err < 0) {
- printk(KERN_ERR "Phy %s: problems with fixed driver\n",
- phydev->dev.bus_id);
- goto err_out;
- }
- err = device_register(&phydev->dev);
- if (err) {
- printk(KERN_ERR "Phy %s failed to register\n",
- phydev->dev.bus_id);
- goto err_out;
+ list_for_each_entry(fp, &fmb->phys, node) {
+ list_del(&fp->node);
+ kfree(fp);
}
- //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
- return fixed;
-
-err_out:
- kfree(phydev);
-err_phy_dev_create:
- kfree(fixed->regs);
-err_fixed_regs_alloc:
- kfree(fixed);
-err_fixed_alloc:
- kfree(new_bus);
-err_bus_alloc:
- kfree(dev);
-err_dev_alloc:
-
- return NULL;
-
}
-#endif
+module_exit(fixed_mdio_bus_exit);
-MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
+MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
MODULE_AUTHOR("Vitaly Bordug");
MODULE_LICENSE("GPL");
-
-static int __init fixed_init(void)
-{
- int cnt = 0;
- int i;
-/* register on the bus... Not expected to be matched
- * with anything there...
- *
- */
- phy_driver_register(&fixed_mdio_driver);
-
-/* We will create several mdio devices here, and will bound the upper
- * driver to them.
- *
- * Then the external software can lookup the phy bus by searching
- * for 0:101, to be connected to the virtual 100M Fdx phy.
- *
- * In case several virtual PHYs required, the bus_id will be in form
- * [num]:[duplex]+[speed], which make it able even to define
- * driver-specific link control callback, if for instance PHY is
- * completely SW-driven.
- */
- for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
-#ifdef CONFIG_FIXED_MII_1000_FDX
- fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
-#endif
-#ifdef CONFIG_FIXED_MII_100_FDX
- fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
-#endif
-#ifdef CONFIG_FIXED_MII_10_FDX
- fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
-#endif
- }
-
- return 0;
-}
-
-static void __exit fixed_exit(void)
-{
- int i;
-
- phy_driver_unregister(&fixed_mdio_driver);
- for (i=0; i < MAX_PHY_AMNT; i++)
- if ( fixed_phy_ptrs[i] )
- device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
-}
-
-module_init(fixed_init);
-module_exit(fixed_exit);
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 0a42bf51746..055af081e02 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -58,11 +58,11 @@ static inline struct device *ctodev(struct gelic_net_card *card)
{
return &card->dev->core;
}
-static inline unsigned int bus_id(struct gelic_net_card *card)
+static inline u64 bus_id(struct gelic_net_card *card)
{
return card->dev->bus_id;
}
-static inline unsigned int dev_id(struct gelic_net_card *card)
+static inline u64 dev_id(struct gelic_net_card *card)
{
return card->dev->dev_id;
}
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 73d6ac9406b..4ffd8739f8b 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3819,6 +3819,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
int err, ucc_num, max_speed = 0;
const phandle *ph;
const unsigned int *prop;
+ const char *sprop;
const void *mac_addr;
phy_interface_t phy_interface;
static const int enet_to_speed[] = {
@@ -3851,10 +3852,56 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ug_info->uf_info.ucc_num = ucc_num;
- prop = of_get_property(np, "rx-clock", NULL);
- ug_info->uf_info.rx_clock = *prop;
- prop = of_get_property(np, "tx-clock", NULL);
- ug_info->uf_info.tx_clock = *prop;
+ sprop = of_get_property(np, "rx-clock-name", NULL);
+ if (sprop) {
+ ug_info->uf_info.rx_clock = qe_clock_source(sprop);
+ if ((ug_info->uf_info.rx_clock < QE_CLK_NONE) ||
+ (ug_info->uf_info.rx_clock > QE_CLK24)) {
+ printk(KERN_ERR
+ "ucc_geth: invalid rx-clock-name property\n");
+ return -EINVAL;
+ }
+ } else {
+ prop = of_get_property(np, "rx-clock", NULL);
+ if (!prop) {
+ /* If both rx-clock-name and rx-clock are missing,
+ we want to tell people to use rx-clock-name. */
+ printk(KERN_ERR
+ "ucc_geth: missing rx-clock-name property\n");
+ return -EINVAL;
+ }
+ if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
+ printk(KERN_ERR
+ "ucc_geth: invalid rx-clock propperty\n");
+ return -EINVAL;
+ }
+ ug_info->uf_info.rx_clock = *prop;
+ }
+
+ sprop = of_get_property(np, "tx-clock-name", NULL);
+ if (sprop) {
+ ug_info->uf_info.tx_clock = qe_clock_source(sprop);
+ if ((ug_info->uf_info.tx_clock < QE_CLK_NONE) ||
+ (ug_info->uf_info.tx_clock > QE_CLK24)) {
+ printk(KERN_ERR
+ "ucc_geth: invalid tx-clock-name property\n");
+ return -EINVAL;
+ }
+ } else {
+ prop = of_get_property(np, "rx-clock", NULL);
+ if (!prop) {
+ printk(KERN_ERR
+ "ucc_geth: mising tx-clock-name property\n");
+ return -EINVAL;
+ }
+ if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
+ printk(KERN_ERR
+ "ucc_geth: invalid tx-clock property\n");
+ return -EINVAL;
+ }
+ ug_info->uf_info.tx_clock = *prop;
+ }
+
err = of_address_to_resource(np, 0, &res);
if (err)
return -EINVAL;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index df884f0ad8e..e3ba14a1991 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -256,6 +256,9 @@ static struct of_device_id uec_mdio_match[] = {
.type = "mdio",
.compatible = "ucc_geth_phy",
},
+ {
+ .compatible = "fsl,ucc-mdio",
+ },
{},
};
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 9377f3bc410..b306fef1ac4 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -273,3 +273,61 @@ struct device_node *of_find_compatible_node(struct device_node *from,
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @matches: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= node->name
+ && !strcmp(matches->name, node->name);
+ if (matches->type[0])
+ match &= node->type
+ && !strcmp(matches->type, node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_find_matching_node - Find a node based on an of_device_id match
+ * table.
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @matches: array of of device match structures to search in
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_matching_node(struct device_node *from,
+ const struct of_device_id *matches)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ if (of_match_node(matches, np) && of_node_get(np))
+ break;
+ }
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_matching_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 6245f060fb7..29681c4b700 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -10,35 +10,6 @@
#include <asm/errno.h>
/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @ids: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
- const struct device_node *node)
-{
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= node->name
- && !strcmp(matches->name, node->name);
- if (matches->type[0])
- match &= node->type
- && !strcmp(matches->type, node->type);
- if (matches->compatible[0])
- match &= of_device_is_compatible(node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_match_node);
-
-/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ids: array of of device match structures to search in
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 55505565073..f697f3d728e 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -32,7 +32,7 @@ obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
obj-$(CONFIG_PARISC) += setup-bus.o
obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
obj-$(CONFIG_PPC32) += setup-irq.o
-obj-$(CONFIG_PPC64) += setup-bus.o
+obj-$(CONFIG_PPC) += setup-bus.o
obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index b169b0e2647..191954bc8e5 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -155,7 +155,7 @@ static void dlpar_pci_add_bus(struct device_node *dn)
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
of_scan_pci_bridge(dn, dev);
- pcibios_fixup_new_pci_devices(dev->subordinate,0);
+ pcibios_fixup_new_pci_devices(dev->subordinate);
/* Claim new bus resources */
pcibios_claim_one_bus(dev->bus);
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index 1f5a2d33bf5..ccea15c11c1 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -4,3 +4,4 @@ ps3av_mod-objs += ps3av.o ps3av_cmd.o
obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
+obj-$(CONFIG_PS3_LPM) += ps3-lpm.o
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
new file mode 100644
index 00000000000..4c066545d17
--- /dev/null
+++ b/drivers/ps3/ps3-lpm.c
@@ -0,0 +1,1248 @@
+/*
+ * PS3 Logical Performance Monitor.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+#include <asm/cell-pmu.h>
+
+
+/* BOOKMARK tag macros */
+#define PS3_PM_BOOKMARK_START 0x8000000000000000ULL
+#define PS3_PM_BOOKMARK_STOP 0x4000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_KERNEL 0x1000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_USER 0x3000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_HI 0xF000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_LO 0x0F00000000000000ULL
+
+/* CBE PM CONTROL register macros */
+#define PS3_PM_CONTROL_PPU_TH0_BOOKMARK 0x00001000
+#define PS3_PM_CONTROL_PPU_TH1_BOOKMARK 0x00000800
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_MASK 0x000C0000
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_PROBLEM 0x00080000
+#define PS3_WRITE_PM_MASK 0xFFFFFFFFFFFFFFFFULL
+
+/* CBE PM START STOP register macros */
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START 0x02000000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START 0x01000000
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP 0x00020000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP 0x00010000
+#define PS3_PM_START_STOP_START_MASK 0xFF000000
+#define PS3_PM_START_STOP_STOP_MASK 0x00FF0000
+
+/* CBE PM COUNTER register macres */
+#define PS3_PM_COUNTER_MASK_HI 0xFFFFFFFF00000000ULL
+#define PS3_PM_COUNTER_MASK_LO 0x00000000FFFFFFFFULL
+
+/* BASE SIGNAL GROUP NUMBER macros */
+#define PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER 0
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER1 6
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER2 7
+#define PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER 7
+#define PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER 15
+#define PM_SPU_TRIGGER_SIGNAL_GROUP_NUMBER 17
+#define PM_SPU_EVENT_SIGNAL_GROUP_NUMBER 18
+#define PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER 18
+#define PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER 24
+#define PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER 49
+#define PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER 52
+#define PM_SIG_GROUP_SPU 41
+#define PM_SIG_GROUP_SPU_TRIGGER 42
+#define PM_SIG_GROUP_SPU_EVENT 43
+#define PM_SIG_GROUP_MFC_MAX 60
+
+/**
+ * struct ps3_lpm_shadow_regs - Performance monitor shadow registers.
+ *
+ * @pm_control: Shadow of the processor's pm_control register.
+ * @pm_start_stop: Shadow of the processor's pm_start_stop register.
+ * @pm_interval: Shadow of the processor's pm_interval register.
+ * @group_control: Shadow of the processor's group_control register.
+ * @debug_bus_control: Shadow of the processor's debug_bus_control register.
+ *
+ * The logical performance monitor provides a write-only interface to
+ * these processor registers. These shadow variables cache the processor
+ * register values for reading.
+ *
+ * The initial value of the shadow registers at lpm creation is
+ * PS3_LPM_SHADOW_REG_INIT.
+ */
+
+struct ps3_lpm_shadow_regs {
+ u64 pm_control;
+ u64 pm_start_stop;
+ u64 pm_interval;
+ u64 group_control;
+ u64 debug_bus_control;
+};
+
+#define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
+
+/**
+ * struct ps3_lpm_priv - Private lpm device data.
+ *
+ * @open: An atomic variable indicating the lpm driver has been opened.
+ * @rights: The lpm rigths granted by the system policy module. A logical
+ * OR of enum ps3_lpm_rights.
+ * @node_id: The node id of a BE prosessor whose performance monitor this
+ * lpar has the right to use.
+ * @pu_id: The lv1 id of the logical PU.
+ * @lpm_id: The lv1 id of this lpm instance.
+ * @outlet_id: The outlet created by lv1 for this lpm instance.
+ * @tb_count: The number of bytes of data held in the lv1 trace buffer.
+ * @tb_cache: Kernel buffer to receive the data from the lv1 trace buffer.
+ * Must be 128 byte aligned.
+ * @tb_cache_size: Size of the kernel @tb_cache buffer. Must be 128 byte
+ * aligned.
+ * @tb_cache_internal: An unaligned buffer allocated by this driver to be
+ * used for the trace buffer cache when ps3_lpm_open() is called with a
+ * NULL tb_cache argument. Otherwise unused.
+ * @shadow: Processor register shadow of type struct ps3_lpm_shadow_regs.
+ * @sbd: The struct ps3_system_bus_device attached to this driver.
+ *
+ * The trace buffer is a buffer allocated and used internally to the lv1
+ * hypervisor to collect trace data. The trace buffer cache is a guest
+ * buffer that accepts the trace data from the trace buffer.
+ */
+
+struct ps3_lpm_priv {
+ atomic_t open;
+ u64 rights;
+ u64 node_id;
+ u64 pu_id;
+ u64 lpm_id;
+ u64 outlet_id;
+ u64 tb_count;
+ void *tb_cache;
+ u64 tb_cache_size;
+ void *tb_cache_internal;
+ struct ps3_lpm_shadow_regs shadow;
+ struct ps3_system_bus_device *sbd;
+};
+
+enum {
+ PS3_LPM_DEFAULT_TB_CACHE_SIZE = 0x4000,
+};
+
+/**
+ * lpm_priv - Static instance of the lpm data.
+ *
+ * Since the exported routines don't support the notion of a device
+ * instance we need to hold the instance in this static variable
+ * and then only allow at most one instance at a time to be created.
+ */
+
+static struct ps3_lpm_priv *lpm_priv;
+
+static struct device *sbd_core(void)
+{
+ BUG_ON(!lpm_priv || !lpm_priv->sbd);
+ return &lpm_priv->sbd->core;
+}
+
+/**
+ * use_start_stop_bookmark - Enable the PPU bookmark trace.
+ *
+ * And it enables PPU bookmark triggers ONLY if the other triggers are not set.
+ * The start/stop bookmarks are inserted at ps3_enable_pm() and ps3_disable_pm()
+ * to start/stop LPM.
+ *
+ * Used to get good quality of the performance counter.
+ */
+
+enum {use_start_stop_bookmark = 1,};
+
+void ps3_set_bookmark(u64 bookmark)
+{
+ /*
+ * As per the PPE book IV, to avoid bookmark loss there must
+ * not be a traced branch within 10 cycles of setting the
+ * SPRN_BKMK register. The actual text is unclear if 'within'
+ * includes cycles before the call.
+ */
+
+ asm volatile("or 29, 29, 29;"); /* db10cyc */
+ mtspr(SPRN_BKMK, bookmark);
+ asm volatile("or 29, 29, 29;"); /* db10cyc */
+}
+EXPORT_SYMBOL_GPL(ps3_set_bookmark);
+
+void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
+{
+ u64 bookmark;
+
+ bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
+ PS3_PM_BOOKMARK_TAG_KERNEL;
+ bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
+ (incident << 48) | (th_id << 32) | bookmark;
+ ps3_set_bookmark(bookmark);
+}
+EXPORT_SYMBOL_GPL(ps3_set_pm_bookmark);
+
+/**
+ * ps3_read_phys_ctr - Read physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr)
+{
+ int result;
+ u64 counter0415;
+ u64 counter2637;
+
+ if (phys_ctr >= NR_PHYS_CTRS) {
+ dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+ __LINE__, phys_ctr);
+ return 0;
+ }
+
+ result = lv1_set_lpm_counter(lpm_priv->lpm_id, 0, 0, 0, 0, &counter0415,
+ &counter2637);
+ if (result) {
+ dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+ "phys_ctr %u, %s\n", __func__, __LINE__, phys_ctr,
+ ps3_result(result));
+ return 0;
+ }
+
+ switch (phys_ctr) {
+ case 0:
+ return counter0415 >> 32;
+ case 1:
+ return counter0415 & PS3_PM_COUNTER_MASK_LO;
+ case 2:
+ return counter2637 >> 32;
+ case 3:
+ return counter2637 & PS3_PM_COUNTER_MASK_LO;
+ default:
+ BUG();
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_phys_ctr);
+
+/**
+ * ps3_write_phys_ctr - Write physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
+{
+ u64 counter0415;
+ u64 counter0415_mask;
+ u64 counter2637;
+ u64 counter2637_mask;
+ int result;
+
+ if (phys_ctr >= NR_PHYS_CTRS) {
+ dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+ __LINE__, phys_ctr);
+ return;
+ }
+
+ switch (phys_ctr) {
+ case 0:
+ counter0415 = (u64)val << 32;
+ counter0415_mask = PS3_PM_COUNTER_MASK_HI;
+ counter2637 = 0x0;
+ counter2637_mask = 0x0;
+ break;
+ case 1:
+ counter0415 = (u64)val;
+ counter0415_mask = PS3_PM_COUNTER_MASK_LO;
+ counter2637 = 0x0;
+ counter2637_mask = 0x0;
+ break;
+ case 2:
+ counter0415 = 0x0;
+ counter0415_mask = 0x0;
+ counter2637 = (u64)val << 32;
+ counter2637_mask = PS3_PM_COUNTER_MASK_HI;
+ break;
+ case 3:
+ counter0415 = 0x0;
+ counter0415_mask = 0x0;
+ counter2637 = (u64)val;
+ counter2637_mask = PS3_PM_COUNTER_MASK_LO;
+ break;
+ default:
+ BUG();
+ }
+
+ result = lv1_set_lpm_counter(lpm_priv->lpm_id,
+ counter0415, counter0415_mask,
+ counter2637, counter2637_mask,
+ &counter0415, &counter2637);
+ if (result)
+ dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+ "phys_ctr %u, val %u, %s\n", __func__, __LINE__,
+ phys_ctr, val, ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_phys_ctr);
+
+/**
+ * ps3_read_ctr - Read counter.
+ *
+ * Read 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+u32 ps3_read_ctr(u32 cpu, u32 ctr)
+{
+ u32 val;
+ u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+ val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+ if (ps3_get_ctr_size(cpu, phys_ctr) == 16)
+ val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(ps3_read_ctr);
+
+/**
+ * ps3_write_ctr - Write counter.
+ *
+ * Write 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+void ps3_write_ctr(u32 cpu, u32 ctr, u32 val)
+{
+ u32 phys_ctr;
+ u32 phys_val;
+
+ phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+ if (ps3_get_ctr_size(cpu, phys_ctr) == 16) {
+ phys_val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+ if (ctr < NR_PHYS_CTRS)
+ val = (val << 16) | (phys_val & 0xffff);
+ else
+ val = (val & 0xffff) | (phys_val & 0xffff0000);
+ }
+
+ ps3_write_phys_ctr(cpu, phys_ctr, val);
+}
+EXPORT_SYMBOL_GPL(ps3_write_ctr);
+
+/**
+ * ps3_read_pm07_control - Read counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+u32 ps3_read_pm07_control(u32 cpu, u32 ctr)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm07_control);
+
+/**
+ * ps3_write_pm07_control - Write counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val)
+{
+ int result;
+ static const u64 mask = 0xFFFFFFFFFFFFFFFFULL;
+ u64 old_value;
+
+ if (ctr >= NR_CTRS) {
+ dev_dbg(sbd_core(), "%s:%u: ctr too big: %u\n", __func__,
+ __LINE__, ctr);
+ return;
+ }
+
+ result = lv1_set_lpm_counter_control(lpm_priv->lpm_id, ctr, val, mask,
+ &old_value);
+ if (result)
+ dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter_control "
+ "failed: ctr %u, %s\n", __func__, __LINE__, ctr,
+ ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm07_control);
+
+/**
+ * ps3_read_pm - Read Other LPM control registers.
+ */
+
+u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg)
+{
+ int result = 0;
+ u64 val = 0;
+
+ switch (reg) {
+ case pm_control:
+ return lpm_priv->shadow.pm_control;
+ case trace_address:
+ return CBE_PM_TRACE_BUF_EMPTY;
+ case pm_start_stop:
+ return lpm_priv->shadow.pm_start_stop;
+ case pm_interval:
+ return lpm_priv->shadow.pm_interval;
+ case group_control:
+ return lpm_priv->shadow.group_control;
+ case debug_bus_control:
+ return lpm_priv->shadow.debug_bus_control;
+ case pm_status:
+ result = lv1_get_lpm_interrupt_status(lpm_priv->lpm_id,
+ &val);
+ if (result) {
+ val = 0;
+ dev_dbg(sbd_core(), "%s:%u: lv1 get_lpm_status failed: "
+ "reg %u, %s\n", __func__, __LINE__, reg,
+ ps3_result(result));
+ }
+ return (u32)val;
+ case ext_tr_timer:
+ return 0;
+ default:
+ dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+ __LINE__, reg);
+ BUG();
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm);
+
+/**
+ * ps3_write_pm - Write Other LPM control registers.
+ */
+
+void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
+{
+ int result = 0;
+ u64 dummy;
+
+ switch (reg) {
+ case group_control:
+ if (val != lpm_priv->shadow.group_control)
+ result = lv1_set_lpm_group_control(lpm_priv->lpm_id,
+ val,
+ PS3_WRITE_PM_MASK,
+ &dummy);
+ lpm_priv->shadow.group_control = val;
+ break;
+ case debug_bus_control:
+ if (val != lpm_priv->shadow.debug_bus_control)
+ result = lv1_set_lpm_debug_bus_control(lpm_priv->lpm_id,
+ val,
+ PS3_WRITE_PM_MASK,
+ &dummy);
+ lpm_priv->shadow.debug_bus_control = val;
+ break;
+ case pm_control:
+ if (use_start_stop_bookmark)
+ val |= (PS3_PM_CONTROL_PPU_TH0_BOOKMARK |
+ PS3_PM_CONTROL_PPU_TH1_BOOKMARK);
+ if (val != lpm_priv->shadow.pm_control)
+ result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
+ val,
+ PS3_WRITE_PM_MASK,
+ 0, 0, &dummy,
+ &dummy);
+ lpm_priv->shadow.pm_control = val;
+ break;
+ case pm_interval:
+ if (val != lpm_priv->shadow.pm_interval)
+ result = lv1_set_lpm_interval(lpm_priv->lpm_id, val,
+ PS3_WRITE_PM_MASK, &dummy);
+ lpm_priv->shadow.pm_interval = val;
+ break;
+ case pm_start_stop:
+ if (val != lpm_priv->shadow.pm_start_stop)
+ result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+ val,
+ PS3_WRITE_PM_MASK,
+ &dummy);
+ lpm_priv->shadow.pm_start_stop = val;
+ break;
+ case trace_address:
+ case ext_tr_timer:
+ case pm_status:
+ break;
+ default:
+ dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+ __LINE__, reg);
+ BUG();
+ break;
+ }
+
+ if (result)
+ dev_err(sbd_core(), "%s:%u: lv1 set_control failed: "
+ "reg %u, %s\n", __func__, __LINE__, reg,
+ ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm);
+
+/**
+ * ps3_get_ctr_size - Get the size of a physical counter.
+ *
+ * Returns either 16 or 32.
+ */
+
+u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr)
+{
+ u32 pm_ctrl;
+
+ if (phys_ctr >= NR_PHYS_CTRS) {
+ dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+ __LINE__, phys_ctr);
+ return 0;
+ }
+
+ pm_ctrl = ps3_read_pm(cpu, pm_control);
+ return (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
+}
+EXPORT_SYMBOL_GPL(ps3_get_ctr_size);
+
+/**
+ * ps3_set_ctr_size - Set the size of a physical counter to 16 or 32 bits.
+ */
+
+void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
+{
+ u32 pm_ctrl;
+
+ if (phys_ctr >= NR_PHYS_CTRS) {
+ dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+ __LINE__, phys_ctr);
+ return;
+ }
+
+ pm_ctrl = ps3_read_pm(cpu, pm_control);
+
+ switch (ctr_size) {
+ case 16:
+ pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
+ ps3_write_pm(cpu, pm_control, pm_ctrl);
+ break;
+
+ case 32:
+ pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
+ ps3_write_pm(cpu, pm_control, pm_ctrl);
+ break;
+ default:
+ BUG();
+ }
+}
+EXPORT_SYMBOL_GPL(ps3_set_ctr_size);
+
+static u64 pm_translate_signal_group_number_on_island2(u64 subgroup)
+{
+
+ if (subgroup == 2)
+ subgroup = 3;
+
+ if (subgroup <= 6)
+ return PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+ else if (subgroup == 7)
+ return PM_ISLAND2_SIGNAL_GROUP_NUMBER1;
+ else
+ return PM_ISLAND2_SIGNAL_GROUP_NUMBER2;
+}
+
+static u64 pm_translate_signal_group_number_on_island3(u64 subgroup)
+{
+
+ switch (subgroup) {
+ case 2:
+ case 3:
+ case 4:
+ subgroup += 2;
+ break;
+ case 5:
+ subgroup = 8;
+ break;
+ default:
+ break;
+ }
+ return PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
+{
+ return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island5(u64 subgroup)
+{
+
+ switch (subgroup) {
+ case 3:
+ subgroup = 4;
+ break;
+ case 4:
+ subgroup = 6;
+ break;
+ default:
+ break;
+ }
+ return PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island6(u64 subgroup,
+ u64 subsubgroup)
+{
+ switch (subgroup) {
+ case 3:
+ case 4:
+ case 5:
+ subgroup += 1;
+ break;
+ default:
+ break;
+ }
+
+ switch (subsubgroup) {
+ case 4:
+ case 5:
+ case 6:
+ subsubgroup += 2;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ subsubgroup += 4;
+ break;
+ case 11:
+ case 12:
+ case 13:
+ subsubgroup += 5;
+ break;
+ default:
+ break;
+ }
+
+ if (subgroup <= 5)
+ return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup);
+ else
+ return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup
+ + subsubgroup - 1);
+}
+
+static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
+{
+ return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
+{
+ return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
+{
+ u64 island;
+ u64 subgroup;
+ u64 subsubgroup;
+
+ subgroup = 0;
+ subsubgroup = 0;
+ island = 0;
+ if (group < 1000) {
+ if (group < 100) {
+ if (20 <= group && group < 30) {
+ island = 2;
+ subgroup = group - 20;
+ } else if (30 <= group && group < 40) {
+ island = 3;
+ subgroup = group - 30;
+ } else if (40 <= group && group < 50) {
+ island = 4;
+ subgroup = group - 40;
+ } else if (50 <= group && group < 60) {
+ island = 5;
+ subgroup = group - 50;
+ } else if (60 <= group && group < 70) {
+ island = 6;
+ subgroup = group - 60;
+ } else if (70 <= group && group < 80) {
+ island = 7;
+ subgroup = group - 70;
+ } else if (80 <= group && group < 90) {
+ island = 8;
+ subgroup = group - 80;
+ }
+ } else if (200 <= group && group < 300) {
+ island = 2;
+ subgroup = group - 200;
+ } else if (600 <= group && group < 700) {
+ island = 6;
+ subgroup = 5;
+ subsubgroup = group - 650;
+ }
+ } else if (6000 <= group && group < 7000) {
+ island = 6;
+ subgroup = 5;
+ subsubgroup = group - 6500;
+ }
+
+ switch (island) {
+ case 2:
+ return pm_translate_signal_group_number_on_island2(subgroup);
+ case 3:
+ return pm_translate_signal_group_number_on_island3(subgroup);
+ case 4:
+ return pm_translate_signal_group_number_on_island4(subgroup);
+ case 5:
+ return pm_translate_signal_group_number_on_island5(subgroup);
+ case 6:
+ return pm_translate_signal_group_number_on_island6(subgroup,
+ subsubgroup);
+ case 7:
+ return pm_translate_signal_group_number_on_island7(subgroup);
+ case 8:
+ return pm_translate_signal_group_number_on_island8(subgroup);
+ default:
+ dev_dbg(sbd_core(), "%s:%u: island not found: %lu\n", __func__,
+ __LINE__, group);
+ BUG();
+ break;
+ }
+ return 0;
+}
+
+static u64 pm_bus_word_to_ps3_lv1_bus_word(u8 word)
+{
+
+ switch (word) {
+ case 1:
+ return 0xF000;
+ case 2:
+ return 0x0F00;
+ case 4:
+ return 0x00F0;
+ case 8:
+ default:
+ return 0x000F;
+ }
+}
+
+static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
+ u64 signal_select, u64 attr1, u64 attr2, u64 attr3)
+{
+ int ret;
+
+ ret = lv1_set_lpm_signal(lpm_priv->lpm_id, lv1_signal_group, bus_select,
+ signal_select, attr1, attr2, attr3);
+ if (ret)
+ dev_err(sbd_core(),
+ "%s:%u: error:%d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+ __func__, __LINE__, ret, lv1_signal_group, bus_select,
+ signal_select, attr1, attr2, attr3);
+
+ return ret;
+}
+
+int ps3_set_signal(u64 signal_group, u8 signal_bit, u16 sub_unit,
+ u8 bus_word)
+{
+ int ret;
+ u64 lv1_signal_group;
+ u64 bus_select;
+ u64 signal_select;
+ u64 attr1, attr2, attr3;
+
+ if (signal_group == 0)
+ return __ps3_set_signal(0, 0, 0, 0, 0, 0);
+
+ lv1_signal_group =
+ pm_signal_group_to_ps3_lv1_signal_group(signal_group);
+ bus_select = pm_bus_word_to_ps3_lv1_bus_word(bus_word);
+
+ switch (signal_group) {
+ case PM_SIG_GROUP_SPU_TRIGGER:
+ signal_select = 1;
+ signal_select = signal_select << (63 - signal_bit);
+ break;
+ case PM_SIG_GROUP_SPU_EVENT:
+ signal_select = 1;
+ signal_select = (signal_select << (63 - signal_bit)) | 0x3;
+ break;
+ default:
+ signal_select = 0;
+ break;
+ }
+
+ /*
+ * 0: physical object.
+ * 1: logical object.
+ * This parameter is only used for the PPE and SPE signals.
+ */
+ attr1 = 1;
+
+ /*
+ * This parameter is used to specify the target physical/logical
+ * PPE/SPE object.
+ */
+ if (PM_SIG_GROUP_SPU <= signal_group &&
+ signal_group < PM_SIG_GROUP_MFC_MAX)
+ attr2 = sub_unit;
+ else
+ attr2 = lpm_priv->pu_id;
+
+ /*
+ * This parameter is only used for setting the SPE signal.
+ */
+ attr3 = 0;
+
+ ret = __ps3_set_signal(lv1_signal_group, bus_select, signal_select,
+ attr1, attr2, attr3);
+ if (ret)
+ dev_err(sbd_core(), "%s:%u: __ps3_set_signal failed: %d\n",
+ __func__, __LINE__, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ps3_set_signal);
+
+u32 ps3_get_hw_thread_id(int cpu)
+{
+ return get_hard_smp_processor_id(cpu);
+}
+EXPORT_SYMBOL_GPL(ps3_get_hw_thread_id);
+
+/**
+ * ps3_enable_pm - Enable the entire performance monitoring unit.
+ *
+ * When we enable the LPM, all pending writes to counters get committed.
+ */
+
+void ps3_enable_pm(u32 cpu)
+{
+ int result;
+ u64 tmp;
+ int insert_bookmark = 0;
+
+ lpm_priv->tb_count = 0;
+
+ if (use_start_stop_bookmark) {
+ if (!(lpm_priv->shadow.pm_start_stop &
+ (PS3_PM_START_STOP_START_MASK
+ | PS3_PM_START_STOP_STOP_MASK))) {
+ result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+ (PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START |
+ PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START |
+ PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP |
+ PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP),
+ 0xFFFFFFFFFFFFFFFFULL, &tmp);
+
+ if (result)
+ dev_err(sbd_core(), "%s:%u: "
+ "lv1_set_lpm_trigger_control failed: "
+ "%s\n", __func__, __LINE__,
+ ps3_result(result));
+
+ insert_bookmark = !result;
+ }
+ }
+
+ result = lv1_start_lpm(lpm_priv->lpm_id);
+
+ if (result)
+ dev_err(sbd_core(), "%s:%u: lv1_start_lpm failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ if (use_start_stop_bookmark && !result && insert_bookmark)
+ ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_START);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm);
+
+/**
+ * ps3_disable_pm - Disable the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm(u32 cpu)
+{
+ int result;
+ u64 tmp;
+
+ ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_STOP);
+
+ result = lv1_stop_lpm(lpm_priv->lpm_id, &tmp);
+
+ if (result) {
+ if(result != LV1_WRONG_STATE)
+ dev_err(sbd_core(), "%s:%u: lv1_stop_lpm failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return;
+ }
+
+ lpm_priv->tb_count = tmp;
+
+ dev_dbg(sbd_core(), "%s:%u: tb_count %lu (%lxh)\n", __func__, __LINE__,
+ lpm_priv->tb_count, lpm_priv->tb_count);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm);
+
+/**
+ * ps3_lpm_copy_tb - Copy data from the trace buffer to a kernel buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: Copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ * bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
+ unsigned long *bytes_copied)
+{
+ int result;
+
+ *bytes_copied = 0;
+
+ if (!lpm_priv->tb_cache)
+ return -EPERM;
+
+ if (offset >= lpm_priv->tb_count)
+ return 0;
+
+ count = min(count, lpm_priv->tb_count - offset);
+
+ while (*bytes_copied < count) {
+ const unsigned long request = count - *bytes_copied;
+ u64 tmp;
+
+ result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+ request, &tmp);
+ if (result) {
+ dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+ __func__, __LINE__, request, offset);
+
+ dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+ "failed: %s\n", __func__, __LINE__,
+ ps3_result(result));
+ return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+ }
+
+ memcpy(buf, lpm_priv->tb_cache, tmp);
+ buf += tmp;
+ *bytes_copied += tmp;
+ offset += tmp;
+ }
+ dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+ *bytes_copied);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb);
+
+/**
+ * ps3_lpm_copy_tb_to_user - Copy data from the trace buffer to a user buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: A __user copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ * bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
+ unsigned long count, unsigned long *bytes_copied)
+{
+ int result;
+
+ *bytes_copied = 0;
+
+ if (!lpm_priv->tb_cache)
+ return -EPERM;
+
+ if (offset >= lpm_priv->tb_count)
+ return 0;
+
+ count = min(count, lpm_priv->tb_count - offset);
+
+ while (*bytes_copied < count) {
+ const unsigned long request = count - *bytes_copied;
+ u64 tmp;
+
+ result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+ request, &tmp);
+ if (result) {
+ dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+ __func__, __LINE__, request, offset);
+ dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+ "failed: %s\n", __func__, __LINE__,
+ ps3_result(result));
+ return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+ }
+
+ result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
+
+ if (result) {
+ dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%p\n",
+ __func__, __LINE__, tmp, buf);
+ dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
+ __func__, __LINE__, result);
+ return -EFAULT;
+ }
+
+ buf += tmp;
+ *bytes_copied += tmp;
+ offset += tmp;
+ }
+ dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+ *bytes_copied);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb_to_user);
+
+/**
+ * ps3_get_and_clear_pm_interrupts -
+ *
+ * Clearing interrupts for the entire performance monitoring unit.
+ * Reading pm_status clears the interrupt bits.
+ */
+
+u32 ps3_get_and_clear_pm_interrupts(u32 cpu)
+{
+ return ps3_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(ps3_get_and_clear_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Enabling interrupts for the entire performance monitoring unit.
+ * Enables the interrupt bits in the pm_status register.
+ */
+
+void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
+{
+ if (mask)
+ ps3_write_pm(cpu, pm_status, mask);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Disabling interrupts for the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm_interrupts(u32 cpu)
+{
+ ps3_get_and_clear_pm_interrupts(cpu);
+ ps3_write_pm(cpu, pm_status, 0);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts);
+
+/**
+ * ps3_lpm_open - Open the logical performance monitor device.
+ * @tb_type: Specifies the type of trace buffer lv1 sould use for this lpm
+ * instance, specified by one of enum ps3_lpm_tb_type.
+ * @tb_cache: Optional user supplied buffer to use as the trace buffer cache.
+ * If NULL, the driver will allocate and manage an internal buffer.
+ * Unused when when @tb_type is PS3_LPM_TB_TYPE_NONE.
+ * @tb_cache_size: The size in bytes of the user supplied @tb_cache buffer.
+ * Unused when @tb_cache is NULL or @tb_type is PS3_LPM_TB_TYPE_NONE.
+ */
+
+int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
+ u64 tb_cache_size)
+{
+ int result;
+ u64 tb_size;
+
+ BUG_ON(!lpm_priv);
+ BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
+ && tb_type != PS3_LPM_TB_TYPE_INTERNAL);
+
+ if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
+ dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
+
+ if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
+ dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
+ return -EBUSY;
+ }
+
+ /* Note tb_cache needs 128 byte alignment. */
+
+ if (tb_type == PS3_LPM_TB_TYPE_NONE) {
+ lpm_priv->tb_cache_size = 0;
+ lpm_priv->tb_cache_internal = NULL;
+ lpm_priv->tb_cache = NULL;
+ } else if (tb_cache) {
+ if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128)
+ || tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) {
+ dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
+ __func__, __LINE__);
+ result = -EINVAL;
+ goto fail_align;
+ }
+ lpm_priv->tb_cache_size = tb_cache_size;
+ lpm_priv->tb_cache_internal = NULL;
+ lpm_priv->tb_cache = tb_cache;
+ } else {
+ lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
+ lpm_priv->tb_cache_internal = kzalloc(
+ lpm_priv->tb_cache_size + 127, GFP_KERNEL);
+ if (!lpm_priv->tb_cache_internal) {
+ dev_err(sbd_core(), "%s:%u: alloc internal tb_cache "
+ "failed\n", __func__, __LINE__);
+ result = -ENOMEM;
+ goto fail_malloc;
+ }
+ lpm_priv->tb_cache = (void *)_ALIGN_UP(
+ (unsigned long)lpm_priv->tb_cache_internal, 128);
+ }
+
+ result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
+ ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
+ lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
+ &lpm_priv->outlet_id, &tb_size);
+
+ if (result) {
+ dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ result = -EINVAL;
+ goto fail_construct;
+ }
+
+ lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
+ lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
+ lpm_priv->shadow.pm_interval = PS3_LPM_SHADOW_REG_INIT;
+ lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
+ lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
+
+ dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%lx, outlet_id 0x%lx, "
+ "tb_size 0x%lx\n", __func__, __LINE__, lpm_priv->lpm_id,
+ lpm_priv->outlet_id, tb_size);
+
+ return 0;
+
+fail_construct:
+ kfree(lpm_priv->tb_cache_internal);
+ lpm_priv->tb_cache_internal = NULL;
+fail_malloc:
+fail_align:
+ atomic_dec(&lpm_priv->open);
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_open);
+
+/**
+ * ps3_lpm_close - Close the lpm device.
+ *
+ */
+
+int ps3_lpm_close(void)
+{
+ dev_dbg(sbd_core(), "%s:%u\n", __func__, __LINE__);
+
+ lv1_destruct_lpm(lpm_priv->lpm_id);
+ lpm_priv->lpm_id = 0;
+
+ kfree(lpm_priv->tb_cache_internal);
+ lpm_priv->tb_cache_internal = NULL;
+
+ atomic_dec(&lpm_priv->open);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_close);
+
+static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
+{
+ dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
+
+ if (lpm_priv) {
+ dev_info(&dev->core, "%s:%u: called twice\n",
+ __func__, __LINE__);
+ return -EBUSY;
+ }
+
+ lpm_priv = kzalloc(sizeof(*lpm_priv), GFP_KERNEL);
+
+ if (!lpm_priv)
+ return -ENOMEM;
+
+ lpm_priv->sbd = dev;
+ lpm_priv->node_id = dev->lpm.node_id;
+ lpm_priv->pu_id = dev->lpm.pu_id;
+ lpm_priv->rights = dev->lpm.rights;
+
+ dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+
+ return 0;
+}
+
+static int ps3_lpm_remove(struct ps3_system_bus_device *dev)
+{
+ dev_dbg(&dev->core, " -> %s:%u:\n", __func__, __LINE__);
+
+ ps3_lpm_close();
+
+ kfree(lpm_priv);
+ lpm_priv = NULL;
+
+ dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3_lpm_driver = {
+ .match_id = PS3_MATCH_ID_LPM,
+ .core.name = "ps3-lpm",
+ .core.owner = THIS_MODULE,
+ .probe = ps3_lpm_probe,
+ .remove = ps3_lpm_remove,
+ .shutdown = ps3_lpm_remove,
+};
+
+static int __init ps3_lpm_init(void)
+{
+ pr_debug("%s:%d:\n", __func__, __LINE__);
+ return ps3_system_bus_driver_register(&ps3_lpm_driver);
+}
+
+static void __exit ps3_lpm_exit(void)
+{
+ pr_debug("%s:%d:\n", __func__, __LINE__);
+ ps3_system_bus_driver_unregister(&ps3_lpm_driver);
+}
+
+module_init(ps3_lpm_init);
+module_exit(ps3_lpm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_LPM);
diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c
index 8461b08ab9f..c3c3aba3ffc 100644
--- a/drivers/ps3/ps3-sys-manager.c
+++ b/drivers/ps3/ps3-sys-manager.c
@@ -452,7 +452,7 @@ static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
case PS3_SM_EVENT_THERMAL_ALERT:
dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
__func__, __LINE__, event.value);
- printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value);
+ pr_info("PS3 Thermal Alert Zone %u\n", event.value);
break;
case PS3_SM_EVENT_THERMAL_CLEARED:
dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
@@ -488,7 +488,7 @@ static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
BUG_ON(result && "need to retry here");
- if(result)
+ if (result)
return result;
if (cmd.version != 1) {
@@ -521,7 +521,7 @@ static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
result = ps3_vuart_read(dev, &header,
sizeof(struct ps3_sys_manager_header));
- if(result)
+ if (result)
return result;
if (header.version != 1) {
@@ -589,9 +589,9 @@ static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
PS3_SM_WAKE_DEFAULT);
ps3_sys_manager_send_request_shutdown(dev);
- printk(KERN_EMERG "System Halted, OK to turn off power\n");
+ pr_emerg("System Halted, OK to turn off power\n");
- while(1)
+ while (1)
ps3_sys_manager_handle_msg(dev);
}
@@ -626,9 +626,9 @@ static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
PS3_SM_WAKE_DEFAULT);
ps3_sys_manager_send_request_shutdown(dev);
- printk(KERN_EMERG "System Halted, OK to turn off power\n");
+ pr_emerg("System Halted, OK to turn off power\n");
- while(1)
+ while (1)
ps3_sys_manager_handle_msg(dev);
}
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index bb8d5b1eec9..90c097a7a47 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -108,18 +108,18 @@ static struct ps3_vuart_port_priv *to_port_priv(
struct ports_bmp {
u64 status;
u64 unused[3];
-} __attribute__ ((aligned (32)));
+} __attribute__((aligned(32)));
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
static void __maybe_unused _dump_ports_bmp(
- const struct ports_bmp* bmp, const char* func, int line)
+ const struct ports_bmp *bmp, const char *func, int line)
{
pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
}
#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
static void __maybe_unused _dump_port_params(unsigned int port_number,
- const char* func, int line)
+ const char *func, int line)
{
#if defined(DEBUG)
static const char *strings[] = {
@@ -363,7 +363,7 @@ int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev)
*/
static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
- const void* buf, unsigned int bytes, unsigned long *bytes_written)
+ const void *buf, unsigned int bytes, unsigned long *bytes_written)
{
int result;
struct ps3_vuart_port_priv *priv = to_port_priv(dev);
@@ -431,7 +431,7 @@ void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
int result;
struct ps3_vuart_port_priv *priv = to_port_priv(dev);
u64 bytes_waiting;
- void* tmp;
+ void *tmp;
result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting);
@@ -526,9 +526,8 @@ int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
- if (!lb) {
+ if (!lb)
return -ENOMEM;
- }
memcpy(lb->data, buf, bytes);
lb->head = lb->data;
@@ -878,7 +877,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev)
struct vuart_bus_priv {
struct ports_bmp *bmp;
unsigned int virq;
- struct semaphore probe_mutex;
+ struct mutex probe_mutex;
int use_count;
struct ps3_system_bus_device *devices[PORT_COUNT];
} static vuart_bus_priv;
@@ -926,9 +925,8 @@ static int ps3_vuart_bus_interrupt_get(void)
BUG_ON(vuart_bus_priv.use_count > 2);
- if (vuart_bus_priv.use_count != 1) {
+ if (vuart_bus_priv.use_count != 1)
return 0;
- }
BUG_ON(vuart_bus_priv.bmp);
@@ -1017,7 +1015,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
return -EINVAL;
}
- down(&vuart_bus_priv.probe_mutex);
+ mutex_lock(&vuart_bus_priv.probe_mutex);
result = ps3_vuart_bus_interrupt_get();
@@ -1077,7 +1075,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
goto fail_probe;
}
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
return result;
@@ -1090,7 +1088,7 @@ fail_dev_malloc:
fail_busy:
ps3_vuart_bus_interrupt_put();
fail_setup_interrupt:
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);
return result;
}
@@ -1129,7 +1127,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
BUG_ON(!dev);
- down(&vuart_bus_priv.probe_mutex);
+ mutex_lock(&vuart_bus_priv.probe_mutex);
dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
dev->match_id);
@@ -1137,7 +1135,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
if (!dev->core.driver) {
dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
__LINE__);
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
return 0;
}
@@ -1160,7 +1158,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
priv = NULL;
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
return 0;
}
@@ -1180,7 +1178,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
BUG_ON(!dev);
- down(&vuart_bus_priv.probe_mutex);
+ mutex_lock(&vuart_bus_priv.probe_mutex);
dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
dev->match_id);
@@ -1188,7 +1186,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
if (!dev->core.driver) {
dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
__LINE__);
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
return 0;
}
@@ -1212,7 +1210,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
- up(&vuart_bus_priv.probe_mutex);
+ mutex_unlock(&vuart_bus_priv.probe_mutex);
return 0;
}
@@ -1223,7 +1221,7 @@ static int __init ps3_vuart_bus_init(void)
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ENODEV;
- init_MUTEX(&vuart_bus_priv.probe_mutex);
+ mutex_init(&vuart_bus_priv.probe_mutex);
return 0;
}
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index f644807da2f..80c5f1ba2e4 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/interrupt.h>
#include "rio.h"
@@ -476,8 +477,8 @@ int rio_init_mports(void)
port->iores.end - port->iores.start,
port->name)) {
printk(KERN_ERR
- "RIO: Error requesting master port region %8.8lx-%8.8lx\n",
- port->iores.start, port->iores.end - 1);
+ "RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
+ (u64)port->iores.start, (u64)port->iores.end - 1);
rc = -ENOMEM;
goto out;
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996e2fe..d962b74e311 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1284,4 +1284,14 @@ config SERIAL_OF_PLATFORM
Currently, only 8250 compatible ports are supported, but
others can easily be added.
+config SERIAL_QE
+ tristate "Freescale QUICC Engine serial port support"
+ depends on QUICC_ENGINE
+ select SERIAL_CORE
+ select FW_LOADER
+ default n
+ help
+ This driver supports the QE serial ports on Freescale embedded
+ PowerPC that contain a QUICC Engine.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index af6377d480d..7eb45534778 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -64,3 +64,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 52fb044bb79..6ea0366e26a 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -52,11 +52,7 @@
#ifdef CONFIG_PPC_CPM_NEW_BINDING
void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
- u16 __iomem *cpcr = &cpmp->cp_cpcr;
-
- out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG);
- while (in_be16(cpcr) & CPM_CR_FLG)
- ;
+ cpm_command(port->command, cmd);
}
#else
void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 9b5465fb0bb..ddf46d3c964 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -10,7 +10,7 @@
#ifndef CPM_UART_CPM1_H
#define CPM_UART_CPM1_H
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
/* defines for IRQs */
#ifndef CONFIG_PPC_CPM_NEW_BINDING
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 882dbc17d59..d9af06a791b 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -52,13 +52,7 @@
#ifdef CONFIG_PPC_CPM_NEW_BINDING
void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
- cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm);
-
- out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG);
- while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG)
- ;
-
- cpm2_unmap(cp);
+ cpm_command(port->command, cmd);
}
#else
void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
@@ -171,9 +165,9 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
* really has to get out of the driver so boards can
* be supported in a sane fashion.
*/
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
#ifndef CONFIG_STX_GP3
volatile iop_cpm2_t *io = cpm2_map(im_ioport);
- volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index ec36ad78d2f..3c4d29e59b2 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -36,7 +36,7 @@
* DCD. However, the pin multiplexing aren't changed and should be set either
* by the bootloader or in the platform init code.
*
- * The idx field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2,
+ * The idx field must be equal to the PSC index (e.g. 0 for PSC1, 1 for PSC2,
* and so on). So the PSC1 is mapped to /dev/ttyPSC0, PSC2 to /dev/ttyPSC1 and
* so on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly
* fpr the console code : without this 1:1 mapping, at early boot time, when we
@@ -68,11 +68,12 @@
#include <linux/sysrq.h>
#include <linux/console.h>
-#include <asm/delay.h>
-#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/io.h>
#if defined(CONFIG_PPC_MERGE)
-#include <asm/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#else
#include <linux/platform_device.h>
#endif
@@ -111,23 +112,27 @@ static void mpc52xx_uart_of_enumerate(void);
#endif
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
+#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
/* Forward declaration of the interruption handling routine */
-static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
+static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
/* Simple macro to test if a port is console or not. This one is taken
* for serial_core.c and maybe should be moved to serial_core.h ? */
#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
+#define uart_console(port) \
+ ((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
#if defined(CONFIG_PPC_MERGE)
static struct of_device_id mpc52xx_uart_of_match[] = {
- { .type = "serial", .compatible = "mpc5200-psc-uart", },
+ { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", },
+ { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */
+ { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */
{},
};
#endif
@@ -162,7 +167,7 @@ mpc52xx_uart_stop_tx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
- out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void
@@ -170,7 +175,7 @@ mpc52xx_uart_start_tx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
- out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void
@@ -184,7 +189,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
/* Make sure tx interrupts are on */
/* Truly necessary ??? They should be anyway */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
- out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
spin_unlock_irqrestore(&port->lock, flags);
@@ -195,7 +200,7 @@ mpc52xx_uart_stop_rx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
- out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
static void
@@ -210,10 +215,10 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- if ( ctl == -1 )
- out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
+ if (ctl == -1)
+ out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
else
- out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
+ out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -222,6 +227,7 @@ static int
mpc52xx_uart_startup(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
+ struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
int ret;
/* Request IRQ */
@@ -231,23 +237,23 @@ mpc52xx_uart_startup(struct uart_port *port)
return ret;
/* 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_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_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);
- out_be16(&psc->tfalarm, 0x80);
+ out_8(&fifo->rfcntl, 0x00);
+ out_be16(&fifo->rfalarm, 0x1ff);
+ out_8(&fifo->tfcntl, 0x07);
+ out_be16(&fifo->tfalarm, 0x80);
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
- out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+ 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);
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+ out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
return 0;
}
@@ -258,12 +264,12 @@ mpc52xx_uart_shutdown(struct uart_port *port)
struct mpc52xx_psc __iomem *psc = PSC(port);
/* Shut down the port. Leave TX active if on a console port */
- out_8(&psc->command,MPC52xx_PSC_RST_RX);
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
if (!uart_console(port))
- out_8(&psc->command,MPC52xx_PSC_RST_TX);
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
- out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
/* Release interrupt */
free_irq(port->irq, port);
@@ -271,7 +277,7 @@ mpc52xx_uart_shutdown(struct uart_port *port)
static void
mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
- struct ktermios *old)
+ struct ktermios *old)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
@@ -283,14 +289,14 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
mr1 = 0;
switch (new->c_cflag & CSIZE) {
- case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS;
- break;
- case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS;
- break;
- case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS;
- break;
- case CS8:
- default: mr1 |= MPC52xx_PSC_MODE_8_BITS;
+ case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS;
+ break;
+ case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS;
+ break;
+ case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS;
+ break;
+ case CS8:
+ default: mr1 |= MPC52xx_PSC_MODE_8_BITS;
}
if (new->c_cflag & PARENB) {
@@ -332,24 +338,24 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
udelay(1);
if (!j)
- printk( KERN_ERR "mpc52xx_uart.c: "
+ 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);
- out_8(&psc->command,MPC52xx_PSC_RST_TX);
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
/* Send new mode settings */
- out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
- out_8(&psc->mode,mr1);
- out_8(&psc->mode,mr2);
- out_8(&psc->ctur,ctr >> 8);
- out_8(&psc->ctlr,ctr & 0xff);
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ out_8(&psc->mode, mr1);
+ 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);
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+ out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
/* We're all set, release the lock */
spin_unlock_irqrestore(&port->lock, flags);
@@ -364,7 +370,8 @@ mpc52xx_uart_type(struct uart_port *port)
static void
mpc52xx_uart_release_port(struct uart_port *port)
{
- if (port->flags & UPF_IOREMAP) { /* remapped by us ? */
+ /* remapped by us ? */
+ if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
port->membase = NULL;
}
@@ -379,7 +386,7 @@ mpc52xx_uart_request_port(struct uart_port *port)
if (port->flags & UPF_IOREMAP) /* Need to remap ? */
port->membase = ioremap(port->mapbase,
- sizeof(struct mpc52xx_psc));
+ sizeof(struct mpc52xx_psc));
if (!port->membase)
return -EINVAL;
@@ -398,22 +405,22 @@ mpc52xx_uart_request_port(struct uart_port *port)
static void
mpc52xx_uart_config_port(struct uart_port *port, int flags)
{
- if ( (flags & UART_CONFIG_TYPE) &&
- (mpc52xx_uart_request_port(port) == 0) )
- port->type = PORT_MPC52xx;
+ if ((flags & UART_CONFIG_TYPE)
+ && (mpc52xx_uart_request_port(port) == 0))
+ port->type = PORT_MPC52xx;
}
static int
mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx )
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
return -EINVAL;
- if ( (ser->irq != port->irq) ||
- (ser->io_type != SERIAL_IO_MEM) ||
- (ser->baud_base != port->uartclk) ||
- (ser->iomem_base != (void*)port->mapbase) ||
- (ser->hub6 != 0 ) )
+ if ((ser->irq != port->irq) ||
+ (ser->io_type != SERIAL_IO_MEM) ||
+ (ser->baud_base != port->uartclk) ||
+ (ser->iomem_base != (void *)port->mapbase) ||
+ (ser->hub6 != 0))
return -EINVAL;
return 0;
@@ -455,8 +462,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
unsigned short status;
/* While we can read, do so ! */
- while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
- MPC52xx_PSC_SR_RXRDY) {
+ while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
+ MPC52xx_PSC_SR_RXRDY) {
/* Get the char */
ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
@@ -474,9 +481,9 @@ 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_PE |
+ MPC52xx_PSC_SR_FE |
+ MPC52xx_PSC_SR_RB)) {
if (status & MPC52xx_PSC_SR_RB) {
flag = TTY_BREAK;
@@ -487,7 +494,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
flag = TTY_FRAME;
/* Clear error condition */
- out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT);
+ out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
}
tty_insert_flip_char(tty, ch, flag);
@@ -568,16 +575,16 @@ mpc52xx_uart_int(int irq, void *dev_id)
/* Do we need to receive chars ? */
/* For this RX interrupts must be on and some chars waiting */
- if ( status & MPC52xx_PSC_IMR_RXRDY )
+ if (status & MPC52xx_PSC_IMR_RXRDY)
keepgoing |= mpc52xx_uart_int_rx_chars(port);
/* Do we need to send chars ? */
/* For this, TX must be ready and TX interrupt enabled */
- if ( status & MPC52xx_PSC_IMR_TXRDY )
+ if (status & MPC52xx_PSC_IMR_TXRDY)
keepgoing |= mpc52xx_uart_int_tx_chars(port);
/* Limit number of iteration */
- if ( !(--pass) )
+ if (!(--pass))
keepgoing = 0;
} while (keepgoing);
@@ -596,7 +603,7 @@ mpc52xx_uart_int(int irq, void *dev_id)
static void __init
mpc52xx_console_get_options(struct uart_port *port,
- int *baud, int *parity, int *bits, int *flow)
+ int *baud, int *parity, int *bits, int *flow)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned char mr1;
@@ -604,7 +611,7 @@ mpc52xx_console_get_options(struct uart_port *port,
pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
/* Read the mode registers */
- out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
mr1 = in_8(&psc->mode);
/* CT{U,L}R are write-only ! */
@@ -616,11 +623,18 @@ mpc52xx_console_get_options(struct uart_port *port,
/* Parse them */
switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
- case MPC52xx_PSC_MODE_5_BITS: *bits = 5; break;
- case MPC52xx_PSC_MODE_6_BITS: *bits = 6; break;
- case MPC52xx_PSC_MODE_7_BITS: *bits = 7; break;
- case MPC52xx_PSC_MODE_8_BITS:
- default: *bits = 8;
+ case MPC52xx_PSC_MODE_5_BITS:
+ *bits = 5;
+ break;
+ case MPC52xx_PSC_MODE_6_BITS:
+ *bits = 6;
+ break;
+ case MPC52xx_PSC_MODE_7_BITS:
+ *bits = 7;
+ break;
+ case MPC52xx_PSC_MODE_8_BITS:
+ default:
+ *bits = 8;
}
if (mr1 & MPC52xx_PSC_MODE_PARNONE)
@@ -657,7 +671,7 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
/* Wait the TX buffer to be empty */
j = 20000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) &
- MPC52xx_PSC_SR_TXEMP) && --j)
+ MPC52xx_PSC_SR_TXEMP) && --j)
udelay(1);
}
@@ -730,16 +744,18 @@ mpc52xx_console_setup(struct console *co, char *options)
}
pr_debug("Console on ttyPSC%x is %s\n",
- co->index, mpc52xx_uart_nodes[co->index]->full_name);
+ co->index, mpc52xx_uart_nodes[co->index]->full_name);
/* Fetch register locations */
- if ((ret = of_address_to_resource(np, 0, &res)) != 0) {
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
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) {
+ ipb_freq = mpc52xx_find_ipb_freq(np);
+ if (ipb_freq == 0) {
pr_debug("Could not find IPB bus frequency!\n");
return -EINVAL;
}
@@ -757,7 +773,8 @@ mpc52xx_console_setup(struct console *co, char *options)
return -EINVAL;
pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
- (void*)port->mapbase, port->membase, port->irq, port->uartclk);
+ (void *)port->mapbase, port->membase,
+ port->irq, port->uartclk);
/* Setup the port parameters accoding to options */
if (options)
@@ -766,7 +783,7 @@ mpc52xx_console_setup(struct console *co, char *options)
mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
- baud, bits, parity, flow);
+ baud, bits, parity, flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
@@ -781,7 +798,7 @@ static struct console mpc52xx_console = {
.device = uart_console_device,
.setup = mpc52xx_console_setup,
.flags = CON_PRINTBUFFER,
- .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0 ) */
+ .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */
.data = &mpc52xx_uart_driver,
};
@@ -809,7 +826,6 @@ console_initcall(mpc52xx_console_init);
/* ======================================================================== */
static struct uart_driver mpc52xx_uart_driver = {
- .owner = THIS_MODULE,
.driver_name = "mpc52xx_psc_uart",
.dev_name = "ttyPSC",
.major = SERIAL_PSC_MAJOR,
@@ -837,7 +853,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
- if (!mpc52xx_match_psc_function(idx,"uart"))
+ if (!mpc52xx_match_psc_function(idx, "uart"))
return -ENODEV;
/* Init the port structure */
@@ -848,13 +864,13 @@ mpc52xx_uart_probe(struct platform_device *dev)
port->fifosize = 512;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF |
- ( uart_console(port) ? 0 : UPF_IOREMAP );
+ (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++) {
+ for (i = 0 ; i < dev->num_resources ; i++, res++) {
if (res->flags & IORESOURCE_MEM)
port->mapbase = res->start;
else if (res->flags & IORESOURCE_IRQ)
@@ -866,7 +882,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
if (!ret)
- platform_set_drvdata(dev, (void*)port);
+ platform_set_drvdata(dev, (void *)port);
return ret;
}
@@ -917,6 +933,7 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
.resume = mpc52xx_uart_resume,
#endif
.driver = {
+ .owner = THIS_MODULE,
.name = "mpc52xx-psc",
},
};
@@ -946,10 +963,11 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
if (idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
pr_debug("Found %s assigned to ttyPSC%x\n",
- mpc52xx_uart_nodes[idx]->full_name, idx);
+ 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) {
+ ipb_freq = mpc52xx_find_ipb_freq(op->node);
+ if (ipb_freq == 0) {
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
return -EINVAL;
}
@@ -962,22 +980,23 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
port->fifosize = 512;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF |
- ( uart_console(port) ? 0 : UPF_IOREMAP );
+ (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)
+ ret = of_address_to_resource(op->node, 0, &res);
+ if (ret)
return ret;
port->mapbase = res.start;
port->irq = irq_of_parse_and_map(op->node, 0);
dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
- (void*)port->mapbase, port->irq, port->uartclk);
+ (void *)port->mapbase, port->irq, port->uartclk);
- if ((port->irq==NO_IRQ) || !port->mapbase) {
+ if ((port->irq == NO_IRQ) || !port->mapbase) {
printk(KERN_ERR "Could not allocate resources for PSC\n");
return -EINVAL;
}
@@ -985,7 +1004,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
/* 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);
+ dev_set_drvdata(&op->dev, (void *)port);
return ret;
}
@@ -1048,6 +1067,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx)
if (idx < 0)
return; /* No free slot; abort */
+ of_node_get(np);
/* 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];
@@ -1057,7 +1077,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx)
static void
mpc52xx_uart_of_enumerate(void)
{
- static int enum_done = 0;
+ static int enum_done;
struct device_node *np;
const unsigned int *devno;
int i;
@@ -1071,7 +1091,7 @@ mpc52xx_uart_of_enumerate(void)
/* Is a particular device number requested? */
devno = of_get_property(np, "port-number", NULL);
- mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
+ mpc52xx_uart_of_assign(np, devno ? *devno : -1);
}
enum_done = 1;
@@ -1079,15 +1099,13 @@ mpc52xx_uart_of_enumerate(void)
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);
+ 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,
@@ -1113,7 +1131,8 @@ mpc52xx_uart_init(void)
printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
- if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) {
+ ret = uart_register_driver(&mpc52xx_uart_driver);
+ if (ret) {
printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
__FILE__, ret);
return ret;
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 3f593247c41..80943409edb 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -539,7 +539,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
*
* @dev: pointer to device structure
*/
-static int __devinit ulite_release(struct device *dev)
+static int __devexit ulite_release(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
int rc = 0;
@@ -572,14 +572,14 @@ static int __devinit ulite_probe(struct platform_device *pdev)
return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
}
-static int ulite_remove(struct platform_device *pdev)
+static int __devexit ulite_remove(struct platform_device *pdev)
{
return ulite_release(&pdev->dev);
}
static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
- .remove = ulite_remove,
+ .remove = __devexit_p(ulite_remove),
.driver = {
.owner = THIS_MODULE,
.name = "uartlite",
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
new file mode 100644
index 00000000000..e0994f06100
--- /dev/null
+++ b/drivers/serial/ucc_uart.c
@@ -0,0 +1,1514 @@
+/*
+ * Freescale QUICC Engine UART device driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007 Freescale Semiconductor, 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.
+ *
+ * This driver adds support for UART devices via Freescale's QUICC Engine
+ * found on some Freescale SOCs.
+ *
+ * If Soft-UART support is needed but not already present, then this driver
+ * will request and upload the "Soft-UART" microcode upon probe. The
+ * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X"
+ * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC,
+ * (e.g. "11" for 1.1).
+ */
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/fs_uart_pd.h>
+#include <asm/ucc_slow.h>
+
+#include <linux/firmware.h>
+#include <asm/reg.h>
+
+/*
+ * The GUMR flag for Soft UART. This would normally be defined in qe.h,
+ * but Soft-UART is a hack and we want to keep everything related to it in
+ * this file.
+ */
+#define UCC_SLOW_GUMR_H_SUART 0x00004000 /* Soft-UART */
+
+/*
+ * soft_uart is 1 if we need to use Soft-UART mode
+ */
+static int soft_uart;
+/*
+ * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise.
+ */
+static int firmware_loaded;
+
+/* Enable this macro to configure all serial ports in internal loopback
+ mode */
+/* #define LOOPBACK */
+
+/* The major and minor device numbers are defined in
+ * http://www.lanana.org/docs/device-list/devices-2.6+.txt. For the QE
+ * UART, we have major number 204 and minor numbers 46 - 49, which are the
+ * same as for the CPM2. This decision was made because no Freescale part
+ * has both a CPM and a QE.
+ */
+#define SERIAL_QE_MAJOR 204
+#define SERIAL_QE_MINOR 46
+
+/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */
+#define UCC_MAX_UART 4
+
+/* The number of buffer descriptors for receiving characters. */
+#define RX_NUM_FIFO 4
+
+/* The number of buffer descriptors for transmitting characters. */
+#define TX_NUM_FIFO 4
+
+/* The maximum size of the character buffer for a single RX BD. */
+#define RX_BUF_SIZE 32
+
+/* The maximum size of the character buffer for a single TX BD. */
+#define TX_BUF_SIZE 32
+
+/*
+ * The number of jiffies to wait after receiving a close command before the
+ * device is actually closed. This allows the last few characters to be
+ * sent over the wire.
+ */
+#define UCC_WAIT_CLOSING 100
+
+struct ucc_uart_pram {
+ struct ucc_slow_pram common;
+ u8 res1[8]; /* reserved */
+ __be16 maxidl; /* Maximum idle chars */
+ __be16 idlc; /* temp idle counter */
+ __be16 brkcr; /* Break count register */
+ __be16 parec; /* receive parity error counter */
+ __be16 frmec; /* receive framing error counter */
+ __be16 nosec; /* receive noise counter */
+ __be16 brkec; /* receive break condition counter */
+ __be16 brkln; /* last received break length */
+ __be16 uaddr[2]; /* UART address character 1 & 2 */
+ __be16 rtemp; /* Temp storage */
+ __be16 toseq; /* Transmit out of sequence char */
+ __be16 cchars[8]; /* control characters 1-8 */
+ __be16 rccm; /* receive control character mask */
+ __be16 rccr; /* receive control character register */
+ __be16 rlbc; /* receive last break character */
+ __be16 res2; /* reserved */
+ __be32 res3; /* reserved, should be cleared */
+ u8 res4; /* reserved, should be cleared */
+ u8 res5[3]; /* reserved, should be cleared */
+ __be32 res6; /* reserved, should be cleared */
+ __be32 res7; /* reserved, should be cleared */
+ __be32 res8; /* reserved, should be cleared */
+ __be32 res9; /* reserved, should be cleared */
+ __be32 res10; /* reserved, should be cleared */
+ __be32 res11; /* reserved, should be cleared */
+ __be32 res12; /* reserved, should be cleared */
+ __be32 res13; /* reserved, should be cleared */
+/* The rest is for Soft-UART only */
+ __be16 supsmr; /* 0x90, Shadow UPSMR */
+ __be16 res92; /* 0x92, reserved, initialize to 0 */
+ __be32 rx_state; /* 0x94, RX state, initialize to 0 */
+ __be32 rx_cnt; /* 0x98, RX count, initialize to 0 */
+ u8 rx_length; /* 0x9C, Char length, set to 1+CL+PEN+1+SL */
+ u8 rx_bitmark; /* 0x9D, reserved, initialize to 0 */
+ u8 rx_temp_dlst_qe; /* 0x9E, reserved, initialize to 0 */
+ u8 res14[0xBC - 0x9F]; /* reserved */
+ __be32 dump_ptr; /* 0xBC, Dump pointer */
+ __be32 rx_frame_rem; /* 0xC0, reserved, initialize to 0 */
+ u8 rx_frame_rem_size; /* 0xC4, reserved, initialize to 0 */
+ u8 tx_mode; /* 0xC5, mode, 0=AHDLC, 1=UART */
+ __be16 tx_state; /* 0xC6, TX state */
+ u8 res15[0xD0 - 0xC8]; /* reserved */
+ __be32 resD0; /* 0xD0, reserved, initialize to 0 */
+ u8 resD4; /* 0xD4, reserved, initialize to 0 */
+ __be16 resD5; /* 0xD5, reserved, initialize to 0 */
+} __attribute__ ((packed));
+
+/* SUPSMR definitions, for Soft-UART only */
+#define UCC_UART_SUPSMR_SL 0x8000
+#define UCC_UART_SUPSMR_RPM_MASK 0x6000
+#define UCC_UART_SUPSMR_RPM_ODD 0x0000
+#define UCC_UART_SUPSMR_RPM_LOW 0x2000
+#define UCC_UART_SUPSMR_RPM_EVEN 0x4000
+#define UCC_UART_SUPSMR_RPM_HIGH 0x6000
+#define UCC_UART_SUPSMR_PEN 0x1000
+#define UCC_UART_SUPSMR_TPM_MASK 0x0C00
+#define UCC_UART_SUPSMR_TPM_ODD 0x0000
+#define UCC_UART_SUPSMR_TPM_LOW 0x0400
+#define UCC_UART_SUPSMR_TPM_EVEN 0x0800
+#define UCC_UART_SUPSMR_TPM_HIGH 0x0C00
+#define UCC_UART_SUPSMR_FRZ 0x0100
+#define UCC_UART_SUPSMR_UM_MASK 0x00c0
+#define UCC_UART_SUPSMR_UM_NORMAL 0x0000
+#define UCC_UART_SUPSMR_UM_MAN_MULTI 0x0040
+#define UCC_UART_SUPSMR_UM_AUTO_MULTI 0x00c0
+#define UCC_UART_SUPSMR_CL_MASK 0x0030
+#define UCC_UART_SUPSMR_CL_8 0x0030
+#define UCC_UART_SUPSMR_CL_7 0x0020
+#define UCC_UART_SUPSMR_CL_6 0x0010
+#define UCC_UART_SUPSMR_CL_5 0x0000
+
+#define UCC_UART_TX_STATE_AHDLC 0x00
+#define UCC_UART_TX_STATE_UART 0x01
+#define UCC_UART_TX_STATE_X1 0x00
+#define UCC_UART_TX_STATE_X16 0x80
+
+#define UCC_UART_PRAM_ALIGNMENT 0x100
+
+#define UCC_UART_SIZE_OF_BD UCC_SLOW_SIZE_OF_BD
+#define NUM_CONTROL_CHARS 8
+
+/* Private per-port data structure */
+struct uart_qe_port {
+ struct uart_port port;
+ struct ucc_slow __iomem *uccp;
+ struct ucc_uart_pram __iomem *uccup;
+ struct ucc_slow_info us_info;
+ struct ucc_slow_private *us_private;
+ struct device_node *np;
+ unsigned int ucc_num; /* First ucc is 0, not 1 */
+
+ u16 rx_nrfifos;
+ u16 rx_fifosize;
+ u16 tx_nrfifos;
+ u16 tx_fifosize;
+ int wait_closing;
+ u32 flags;
+ struct qe_bd *rx_bd_base;
+ struct qe_bd *rx_cur;
+ struct qe_bd *tx_bd_base;
+ struct qe_bd *tx_cur;
+ unsigned char *tx_buf;
+ unsigned char *rx_buf;
+ void *bd_virt; /* virtual address of the BD buffers */
+ dma_addr_t bd_dma_addr; /* bus address of the BD buffers */
+ unsigned int bd_size; /* size of BD buffer space */
+};
+
+static struct uart_driver ucc_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyQE",
+ .major = SERIAL_QE_MAJOR,
+ .minor = SERIAL_QE_MINOR,
+ .nr = UCC_MAX_UART,
+};
+
+/*
+ * Virtual to physical address translation.
+ *
+ * Given the virtual address for a character buffer, this function returns
+ * the physical (DMA) equivalent.
+ */
+static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
+{
+ if (likely((addr >= qe_port->bd_virt)) &&
+ (addr < (qe_port->bd_virt + qe_port->bd_size)))
+ return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
+
+ /* something nasty happened */
+ printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr);
+ BUG();
+ return 0;
+}
+
+/*
+ * Physical to virtual address translation.
+ *
+ * Given the physical (DMA) address for a character buffer, this function
+ * returns the virtual equivalent.
+ */
+static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
+{
+ /* sanity check */
+ if (likely((addr >= qe_port->bd_dma_addr) &&
+ (addr < (qe_port->bd_dma_addr + qe_port->bd_size))))
+ return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
+
+ /* something nasty happened */
+ printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr);
+ BUG();
+ return NULL;
+}
+
+/*
+ * Return 1 if the QE is done transmitting all buffers for this port
+ *
+ * This function scans each BD in sequence. If we find a BD that is not
+ * ready (READY=1), then we return 0 indicating that the QE is still sending
+ * data. If we reach the last BD (WRAP=1), then we know we've scanned
+ * the entire list, and all BDs are done.
+ */
+static unsigned int qe_uart_tx_empty(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ struct qe_bd *bdp = qe_port->tx_bd_base;
+
+ while (1) {
+ if (in_be16(&bdp->status) & BD_SC_READY)
+ /* This BD is not done, so return "not done" */
+ return 0;
+
+ if (in_be16(&bdp->status) & BD_SC_WRAP)
+ /*
+ * This BD is done and it's the last one, so return
+ * "done"
+ */
+ return 1;
+
+ bdp++;
+ };
+}
+
+/*
+ * Set the modem control lines
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), we
+ * don't need that support. This function must exist, however, otherwise
+ * the kernel will panic.
+ */
+void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Get the current modem control line status
+ *
+ * Although the QE can control the modem control lines (e.g. CTS), this
+ * driver currently doesn't support that, so we always return Carrier
+ * Detect, Data Set Ready, and Clear To Send.
+ */
+static unsigned int qe_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/*
+ * Disable the transmit interrupt.
+ *
+ * Although this function is called "stop_tx", it does not actually stop
+ * transmission of data. Instead, it tells the QE to not generate an
+ * interrupt when the UCC is finished sending characters.
+ */
+static void qe_uart_stop_tx(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+
+ clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Transmit as many characters to the HW as possible.
+ *
+ * This function will attempt to stuff of all the characters from the
+ * kernel's transmit buffer into TX BDs.
+ *
+ * A return value of non-zero indicates that it sucessfully stuffed all
+ * characters from the kernel buffer.
+ *
+ * A return value of zero indicates that there are still characters in the
+ * kernel's buffer that have not been transmitted, but there are no more BDs
+ * available. This function should be called again after a BD has been made
+ * available.
+ */
+static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
+{
+ struct qe_bd *bdp;
+ unsigned char *p;
+ unsigned int count;
+ struct uart_port *port = &qe_port->port;
+ struct circ_buf *xmit = &port->info->xmit;
+
+ bdp = qe_port->rx_cur;
+
+ /* Handle xon/xoff */
+ if (port->x_char) {
+ /* Pick next descriptor and fill from buffer */
+ bdp = qe_port->tx_cur;
+
+ p = qe2cpu_addr(bdp->buf, qe_port);
+
+ *p++ = port->x_char;
+ out_be16(&bdp->length, 1);
+ setbits16(&bdp->status, BD_SC_READY);
+ /* Get next BD. */
+ if (in_be16(&bdp->status) & BD_SC_WRAP)
+ bdp = qe_port->tx_bd_base;
+ else
+ bdp++;
+ qe_port->tx_cur = bdp;
+
+ port->icount.tx++;
+ port->x_char = 0;
+ return 1;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ qe_uart_stop_tx(port);
+ return 0;
+ }
+
+ /* Pick next descriptor and fill from buffer */
+ bdp = qe_port->tx_cur;
+
+ while (!(in_be16(&bdp->status) & BD_SC_READY) &&
+ (xmit->tail != xmit->head)) {
+ count = 0;
+ p = qe2cpu_addr(bdp->buf, qe_port);
+ while (count < qe_port->tx_fifosize) {
+ *p++ = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ count++;
+ if (xmit->head == xmit->tail)
+ break;
+ }
+
+ out_be16(&bdp->length, count);
+ setbits16(&bdp->status, BD_SC_READY);
+
+ /* Get next BD. */
+ if (in_be16(&bdp->status) & BD_SC_WRAP)
+ bdp = qe_port->tx_bd_base;
+ else
+ bdp++;
+ }
+ qe_port->tx_cur = bdp;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit)) {
+ /* The kernel buffer is empty, so turn off TX interrupts. We
+ don't need to be told when the QE is finished transmitting
+ the data. */
+ qe_uart_stop_tx(port);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Start transmitting data
+ *
+ * This function will start transmitting any available data, if the port
+ * isn't already transmitting data.
+ */
+static void qe_uart_start_tx(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+
+ /* If we currently are transmitting, then just return */
+ if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX)
+ return;
+
+ /* Otherwise, pump the port and start transmission */
+ if (qe_uart_tx_pump(qe_port))
+ setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX);
+}
+
+/*
+ * Stop transmitting data
+ */
+static void qe_uart_stop_rx(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+
+ clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+}
+
+/*
+ * Enable status change interrupts
+ *
+ * We don't support status change interrupts, but we need to define this
+ * function otherwise the kernel will panic.
+ */
+static void qe_uart_enable_ms(struct uart_port *port)
+{
+}
+
+/* Start or stop sending break signal
+ *
+ * This function controls the sending of a break signal. If break_state=1,
+ * then we start sending a break signal. If break_state=0, then we stop
+ * sending the break signal.
+ */
+static void qe_uart_break_ctl(struct uart_port *port, int break_state)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+
+ if (break_state)
+ ucc_slow_stop_tx(qe_port->us_private);
+ else
+ ucc_slow_restart_tx(qe_port->us_private);
+}
+
+/* ISR helper function for receiving character.
+ *
+ * This function is called by the ISR to handling receiving characters
+ */
+static void qe_uart_int_rx(struct uart_qe_port *qe_port)
+{
+ int i;
+ unsigned char ch, *cp;
+ struct uart_port *port = &qe_port->port;
+ struct tty_struct *tty = port->info->tty;
+ struct qe_bd *bdp;
+ u16 status;
+ unsigned int flg;
+
+ /* Just loop through the closed BDs and copy the characters into
+ * the buffer.
+ */
+ bdp = qe_port->rx_cur;
+ while (1) {
+ status = in_be16(&bdp->status);
+
+ /* If this one is empty, then we assume we've read them all */
+ if (status & BD_SC_EMPTY)
+ break;
+
+ /* get number of characters, and check space in RX buffer */
+ i = in_be16(&bdp->length);
+
+ /* If we don't have enough room in RX buffer for the entire BD,
+ * then we try later, which will be the next RX interrupt.
+ */
+ if (tty_buffer_request_room(tty, i) < i) {
+ dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n");
+ return;
+ }
+
+ /* get pointer */
+ cp = qe2cpu_addr(bdp->buf, qe_port);
+
+ /* loop through the buffer */
+ while (i-- > 0) {
+ ch = *cp++;
+ port->icount.rx++;
+ flg = TTY_NORMAL;
+
+ if (!i && status &
+ (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+ goto handle_error;
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+error_return:
+ tty_insert_flip_char(tty, ch, flg);
+
+ }
+
+ /* This BD is ready to be used again. Clear status. get next */
+ clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+ BD_SC_OV | BD_SC_ID, BD_SC_EMPTY);
+ if (in_be16(&bdp->status) & BD_SC_WRAP)
+ bdp = qe_port->rx_bd_base;
+ else
+ bdp++;
+
+ }
+
+ /* Write back buffer pointer */
+ qe_port->rx_cur = bdp;
+
+ /* Activate BH processing */
+ tty_flip_buffer_push(tty);
+
+ return;
+
+ /* Error processing */
+
+handle_error:
+ /* Statistics */
+ if (status & BD_SC_BR)
+ port->icount.brk++;
+ if (status & BD_SC_PR)
+ port->icount.parity++;
+ if (status & BD_SC_FR)
+ port->icount.frame++;
+ if (status & BD_SC_OV)
+ port->icount.overrun++;
+
+ /* Mask out ignored conditions */
+ status &= port->read_status_mask;
+
+ /* Handle the remaining ones */
+ if (status & BD_SC_BR)
+ flg = TTY_BREAK;
+ else if (status & BD_SC_PR)
+ flg = TTY_PARITY;
+ else if (status & BD_SC_FR)
+ flg = TTY_FRAME;
+
+ /* Overrun does not affect the current character ! */
+ if (status & BD_SC_OV)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+#ifdef SUPPORT_SYSRQ
+ port->sysrq = 0;
+#endif
+ goto error_return;
+}
+
+/* Interrupt handler
+ *
+ * This interrupt handler is called after a BD is processed.
+ */
+static irqreturn_t qe_uart_int(int irq, void *data)
+{
+ struct uart_qe_port *qe_port = (struct uart_qe_port *) data;
+ struct ucc_slow __iomem *uccp = qe_port->uccp;
+ u16 events;
+
+ /* Clear the interrupts */
+ events = in_be16(&uccp->ucce);
+ out_be16(&uccp->ucce, events);
+
+ if (events & UCC_UART_UCCE_BRKE)
+ uart_handle_break(&qe_port->port);
+
+ if (events & UCC_UART_UCCE_RX)
+ qe_uart_int_rx(qe_port);
+
+ if (events & UCC_UART_UCCE_TX)
+ qe_uart_tx_pump(qe_port);
+
+ return events ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/* Initialize buffer descriptors
+ *
+ * This function initializes all of the RX and TX buffer descriptors.
+ */
+static void qe_uart_initbd(struct uart_qe_port *qe_port)
+{
+ int i;
+ void *bd_virt;
+ struct qe_bd *bdp;
+
+ /* Set the physical address of the host memory buffers in the buffer
+ * descriptors, and the virtual address for us to work with.
+ */
+ bd_virt = qe_port->bd_virt;
+ bdp = qe_port->rx_bd_base;
+ qe_port->rx_cur = qe_port->rx_bd_base;
+ for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) {
+ out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT);
+ out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+ out_be16(&bdp->length, 0);
+ bd_virt += qe_port->rx_fifosize;
+ bdp++;
+ }
+
+ /* */
+ out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
+ out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+ out_be16(&bdp->length, 0);
+
+ /* Set the physical address of the host memory
+ * buffers in the buffer descriptors, and the
+ * virtual address for us to work with.
+ */
+ bd_virt = qe_port->bd_virt +
+ L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+ qe_port->tx_cur = qe_port->tx_bd_base;
+ bdp = qe_port->tx_bd_base;
+ for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) {
+ out_be16(&bdp->status, BD_SC_INTRPT);
+ out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+ out_be16(&bdp->length, 0);
+ bd_virt += qe_port->tx_fifosize;
+ bdp++;
+ }
+
+ /* Loopback requires the preamble bit to be set on the first TX BD */
+#ifdef LOOPBACK
+ setbits16(&qe_port->tx_cur->status, BD_SC_P);
+#endif
+
+ out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT);
+ out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port));
+ out_be16(&bdp->length, 0);
+}
+
+/*
+ * Initialize a UCC for UART.
+ *
+ * This function configures a given UCC to be used as a UART device. Basic
+ * UCC initialization is handled in qe_uart_request_port(). This function
+ * does all the UART-specific stuff.
+ */
+static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
+{
+ u32 cecr_subblock;
+ struct ucc_slow __iomem *uccp = qe_port->uccp;
+ struct ucc_uart_pram *uccup = qe_port->uccup;
+
+ unsigned int i;
+
+ /* First, disable TX and RX in the UCC */
+ ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+ /* Program the UCC UART parameter RAM */
+ out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+ out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE);
+ out_be16(&uccup->common.mrblr, qe_port->rx_fifosize);
+ out_be16(&uccup->maxidl, 0x10);
+ out_be16(&uccup->brkcr, 1);
+ out_be16(&uccup->parec, 0);
+ out_be16(&uccup->frmec, 0);
+ out_be16(&uccup->nosec, 0);
+ out_be16(&uccup->brkec, 0);
+ out_be16(&uccup->uaddr[0], 0);
+ out_be16(&uccup->uaddr[1], 0);
+ out_be16(&uccup->toseq, 0);
+ for (i = 0; i < 8; i++)
+ out_be16(&uccup->cchars[i], 0xC000);
+ out_be16(&uccup->rccm, 0xc0ff);
+
+ /* Configure the GUMR registers for UART */
+ if (soft_uart)
+ /* Soft-UART requires a 1X multiplier for TX */
+ clrsetbits_be32(&uccp->gumr_l,
+ UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+ UCC_SLOW_GUMR_L_RDCR_MASK,
+ UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 |
+ UCC_SLOW_GUMR_L_RDCR_16);
+ else
+ clrsetbits_be32(&uccp->gumr_l,
+ UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+ UCC_SLOW_GUMR_L_RDCR_MASK,
+ UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 |
+ UCC_SLOW_GUMR_L_RDCR_16);
+
+ clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW,
+ UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX);
+
+#ifdef LOOPBACK
+ clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+ UCC_SLOW_GUMR_L_DIAG_LOOP);
+ clrsetbits_be32(&uccp->gumr_h,
+ UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN,
+ UCC_SLOW_GUMR_H_CDS);
+#endif
+
+ /* Enable rx interrupts and clear all pending events. */
+ out_be16(&uccp->uccm, 0);
+ out_be16(&uccp->ucce, 0xffff);
+ out_be16(&uccp->udsr, 0x7e7e);
+
+ /* Initialize UPSMR */
+ out_be16(&uccp->upsmr, 0);
+
+ if (soft_uart) {
+ out_be16(&uccup->supsmr, 0x30);
+ out_be16(&uccup->res92, 0);
+ out_be32(&uccup->rx_state, 0);
+ out_be32(&uccup->rx_cnt, 0);
+ out_8(&uccup->rx_bitmark, 0);
+ out_8(&uccup->rx_length, 10);
+ out_be32(&uccup->dump_ptr, 0x4000);
+ out_8(&uccup->rx_temp_dlst_qe, 0);
+ out_be32(&uccup->rx_frame_rem, 0);
+ out_8(&uccup->rx_frame_rem_size, 0);
+ /* Soft-UART requires TX to be 1X */
+ out_8(&uccup->tx_mode,
+ UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1);
+ out_be16(&uccup->tx_state, 0);
+ out_8(&uccup->resD4, 0);
+ out_be16(&uccup->resD5, 0);
+
+ /* Set UART mode.
+ * Enable receive and transmit.
+ */
+
+ /* From the microcode errata:
+ * 1.GUMR_L register, set mode=0010 (QMC).
+ * 2.Set GUMR_H[17] bit. (UART/AHDLC mode).
+ * 3.Set GUMR_H[19:20] (Transparent mode)
+ * 4.Clear GUMR_H[26] (RFW)
+ * ...
+ * 6.Receiver must use 16x over sampling
+ */
+ clrsetbits_be32(&uccp->gumr_l,
+ UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK |
+ UCC_SLOW_GUMR_L_RDCR_MASK,
+ UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 |
+ UCC_SLOW_GUMR_L_RDCR_16);
+
+ clrsetbits_be32(&uccp->gumr_h,
+ UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN,
+ UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX |
+ UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL);
+
+#ifdef LOOPBACK
+ clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK,
+ UCC_SLOW_GUMR_L_DIAG_LOOP);
+ clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP |
+ UCC_SLOW_GUMR_H_CDS);
+#endif
+
+ cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num);
+ qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ }
+}
+
+/*
+ * Initialize the port.
+ */
+static int qe_uart_startup(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ int ret;
+
+ /*
+ * If we're using Soft-UART mode, then we need to make sure the
+ * firmware has been uploaded first.
+ */
+ if (soft_uart && !firmware_loaded) {
+ dev_err(port->dev, "Soft-UART firmware not uploaded\n");
+ return -ENODEV;
+ }
+
+ qe_uart_initbd(qe_port);
+ qe_uart_init_ucc(qe_port);
+
+ /* Install interrupt handler. */
+ ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart",
+ qe_port);
+ if (ret) {
+ dev_err(port->dev, "could not claim IRQ %u\n", port->irq);
+ return ret;
+ }
+
+ /* Startup rx-int */
+ setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
+ ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+
+ return 0;
+}
+
+/*
+ * Shutdown the port.
+ */
+static void qe_uart_shutdown(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ struct ucc_slow __iomem *uccp = qe_port->uccp;
+ unsigned int timeout = 20;
+
+ /* Disable RX and TX */
+
+ /* Wait for all the BDs marked sent */
+ while (!qe_uart_tx_empty(port)) {
+ if (!--timeout) {
+ dev_warn(port->dev, "shutdown timeout\n");
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(2);
+ }
+
+ if (qe_port->wait_closing) {
+ /* Wait a bit longer */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(qe_port->wait_closing);
+ }
+
+ /* Stop uarts */
+ ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX);
+ clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX);
+
+ /* Shut them really down and reinit buffer descriptors */
+ ucc_slow_graceful_stop_tx(qe_port->us_private);
+ qe_uart_initbd(qe_port);
+
+ free_irq(port->irq, qe_port);
+}
+
+/*
+ * Set the serial port parameters.
+ */
+static void qe_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ struct ucc_slow __iomem *uccp = qe_port->uccp;
+ unsigned int baud;
+ unsigned long flags;
+ u16 upsmr = in_be16(&uccp->upsmr);
+ struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
+ u16 supsmr = in_be16(&uccup->supsmr);
+ u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */
+
+ /* Character length programmed into the mode register is the
+ * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+ * 1 or 2 stop bits, minus 1.
+ * The value 'bits' counts this for us.
+ */
+
+ /* byte size */
+ upsmr &= UCC_UART_UPSMR_CL_MASK;
+ supsmr &= UCC_UART_SUPSMR_CL_MASK;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ upsmr |= UCC_UART_UPSMR_CL_5;
+ supsmr |= UCC_UART_SUPSMR_CL_5;
+ char_length += 5;
+ break;
+ case CS6:
+ upsmr |= UCC_UART_UPSMR_CL_6;
+ supsmr |= UCC_UART_SUPSMR_CL_6;
+ char_length += 6;
+ break;
+ case CS7:
+ upsmr |= UCC_UART_UPSMR_CL_7;
+ supsmr |= UCC_UART_SUPSMR_CL_7;
+ char_length += 7;
+ break;
+ default: /* case CS8 */
+ upsmr |= UCC_UART_UPSMR_CL_8;
+ supsmr |= UCC_UART_SUPSMR_CL_8;
+ char_length += 8;
+ break;
+ }
+
+ /* If CSTOPB is set, we want two stop bits */
+ if (termios->c_cflag & CSTOPB) {
+ upsmr |= UCC_UART_UPSMR_SL;
+ supsmr |= UCC_UART_SUPSMR_SL;
+ char_length++; /* + SL */
+ }
+
+ if (termios->c_cflag & PARENB) {
+ upsmr |= UCC_UART_UPSMR_PEN;
+ supsmr |= UCC_UART_SUPSMR_PEN;
+ char_length++; /* + PEN */
+
+ if (!(termios->c_cflag & PARODD)) {
+ upsmr &= ~(UCC_UART_UPSMR_RPM_MASK |
+ UCC_UART_UPSMR_TPM_MASK);
+ upsmr |= UCC_UART_UPSMR_RPM_EVEN |
+ UCC_UART_UPSMR_TPM_EVEN;
+ supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK |
+ UCC_UART_SUPSMR_TPM_MASK);
+ supsmr |= UCC_UART_SUPSMR_RPM_EVEN |
+ UCC_UART_SUPSMR_TPM_EVEN;
+ }
+ }
+
+ /*
+ * Set up parity check flag
+ */
+ port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= BD_SC_BR;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= BD_SC_BR;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= BD_SC_OV;
+ }
+ /*
+ * !!! ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->read_status_mask &= ~BD_SC_EMPTY;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 115200);
+
+ /* Do we really need a spinlock here? */
+ spin_lock_irqsave(&port->lock, flags);
+
+ out_be16(&uccp->upsmr, upsmr);
+ if (soft_uart) {
+ out_be16(&uccup->supsmr, supsmr);
+ out_8(&uccup->rx_length, char_length);
+
+ /* Soft-UART requires a 1X multiplier for TX */
+ qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+ qe_setbrg(qe_port->us_info.tx_clock, baud, 1);
+ } else {
+ qe_setbrg(qe_port->us_info.rx_clock, baud, 16);
+ qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return a pointer to a string that describes what kind of port this is.
+ */
+static const char *qe_uart_type(struct uart_port *port)
+{
+ return "QE";
+}
+
+/*
+ * Allocate any memory and I/O resources required by the port.
+ */
+static int qe_uart_request_port(struct uart_port *port)
+{
+ int ret;
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ struct ucc_slow_info *us_info = &qe_port->us_info;
+ struct ucc_slow_private *uccs;
+ unsigned int rx_size, tx_size;
+ void *bd_virt;
+ dma_addr_t bd_dma_addr = 0;
+
+ ret = ucc_slow_init(us_info, &uccs);
+ if (ret) {
+ dev_err(port->dev, "could not initialize UCC%u\n",
+ qe_port->ucc_num);
+ return ret;
+ }
+
+ qe_port->us_private = uccs;
+ qe_port->uccp = uccs->us_regs;
+ qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
+ qe_port->rx_bd_base = uccs->rx_bd;
+ qe_port->tx_bd_base = uccs->tx_bd;
+
+ /*
+ * Allocate the transmit and receive data buffers.
+ */
+
+ rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
+ tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
+
+ bd_virt = dma_alloc_coherent(NULL, rx_size + tx_size, &bd_dma_addr,
+ GFP_KERNEL);
+ if (!bd_virt) {
+ dev_err(port->dev, "could not allocate buffer descriptors\n");
+ return -ENOMEM;
+ }
+
+ qe_port->bd_virt = bd_virt;
+ qe_port->bd_dma_addr = bd_dma_addr;
+ qe_port->bd_size = rx_size + tx_size;
+
+ qe_port->rx_buf = bd_virt;
+ qe_port->tx_buf = qe_port->rx_buf + rx_size;
+
+ return 0;
+}
+
+/*
+ * Configure the port.
+ *
+ * We say we're a CPM-type port because that's mostly true. Once the device
+ * is configured, this driver operates almost identically to the CPM serial
+ * driver.
+ */
+static void qe_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_CPM;
+ qe_uart_request_port(port);
+ }
+}
+
+/*
+ * Release any memory and I/O resources that were allocated in
+ * qe_uart_request_port().
+ */
+static void qe_uart_release_port(struct uart_port *port)
+{
+ struct uart_qe_port *qe_port =
+ container_of(port, struct uart_qe_port, port);
+ struct ucc_slow_private *uccs = qe_port->us_private;
+
+ dma_free_coherent(NULL, qe_port->bd_size, qe_port->bd_virt,
+ qe_port->bd_dma_addr);
+
+ ucc_slow_free(uccs);
+}
+
+/*
+ * Verify that the data in serial_struct is suitable for this device.
+ */
+static int qe_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+ return -EINVAL;
+
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ return -EINVAL;
+
+ if (ser->baud_base < 9600)
+ return -EINVAL;
+
+ return 0;
+}
+/* UART operations
+ *
+ * Details on these functions can be found in Documentation/serial/driver
+ */
+static struct uart_ops qe_uart_pops = {
+ .tx_empty = qe_uart_tx_empty,
+ .set_mctrl = qe_uart_set_mctrl,
+ .get_mctrl = qe_uart_get_mctrl,
+ .stop_tx = qe_uart_stop_tx,
+ .start_tx = qe_uart_start_tx,
+ .stop_rx = qe_uart_stop_rx,
+ .enable_ms = qe_uart_enable_ms,
+ .break_ctl = qe_uart_break_ctl,
+ .startup = qe_uart_startup,
+ .shutdown = qe_uart_shutdown,
+ .set_termios = qe_uart_set_termios,
+ .type = qe_uart_type,
+ .release_port = qe_uart_release_port,
+ .request_port = qe_uart_request_port,
+ .config_port = qe_uart_config_port,
+ .verify_port = qe_uart_verify_port,
+};
+
+/*
+ * Obtain the SOC model number and revision level
+ *
+ * This function parses the device tree to obtain the SOC model. It then
+ * reads the SVR register to the revision.
+ *
+ * The device tree stores the SOC model two different ways.
+ *
+ * The new way is:
+ *
+ * cpu@0 {
+ * compatible = "PowerPC,8323";
+ * device_type = "cpu";
+ * ...
+ *
+ *
+ * The old way is:
+ * PowerPC,8323@0 {
+ * device_type = "cpu";
+ * ...
+ *
+ * This code first checks the new way, and then the old way.
+ */
+static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
+{
+ struct device_node *np;
+ const char *soc_string;
+ unsigned int svr;
+ unsigned int soc;
+
+ /* Find the CPU node */
+ np = of_find_node_by_type(NULL, "cpu");
+ if (!np)
+ return 0;
+ /* Find the compatible property */
+ soc_string = of_get_property(np, "compatible", NULL);
+ if (!soc_string)
+ /* No compatible property, so try the name. */
+ soc_string = np->name;
+
+ /* Extract the SOC number from the "PowerPC," string */
+ if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
+ return 0;
+
+ /* Get the revision from the SVR */
+ svr = mfspr(SPRN_SVR);
+ *rev_h = (svr >> 4) & 0xf;
+ *rev_l = svr & 0xf;
+
+ return soc;
+}
+
+/*
+ * requst_firmware_nowait() callback function
+ *
+ * This function is called by the kernel when a firmware is made available,
+ * or if it times out waiting for the firmware.
+ */
+static void uart_firmware_cont(const struct firmware *fw, void *context)
+{
+ struct qe_firmware *firmware;
+ struct device *dev = context;
+ int ret;
+
+ if (!fw) {
+ dev_err(dev, "firmware not found\n");
+ return;
+ }
+
+ firmware = (struct qe_firmware *) fw->data;
+
+ if (firmware->header.length != fw->size) {
+ dev_err(dev, "invalid firmware\n");
+ return;
+ }
+
+ ret = qe_upload_firmware(firmware);
+ if (ret) {
+ dev_err(dev, "could not load firmware\n");
+ return;
+ }
+
+ firmware_loaded = 1;
+}
+
+static int ucc_uart_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ const unsigned int *iprop; /* Integer OF properties */
+ const char *sprop; /* String OF properties */
+ struct uart_qe_port *qe_port = NULL;
+ struct resource res;
+ int ret;
+
+ /*
+ * Determine if we need Soft-UART mode
+ */
+ if (of_find_property(np, "soft-uart", NULL)) {
+ dev_dbg(&ofdev->dev, "using Soft-UART mode\n");
+ soft_uart = 1;
+ }
+
+ /*
+ * If we are using Soft-UART, determine if we need to upload the
+ * firmware, too.
+ */
+ if (soft_uart) {
+ struct qe_firmware_info *qe_fw_info;
+
+ qe_fw_info = qe_get_firmware_info();
+
+ /* Check if the firmware has been uploaded. */
+ if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) {
+ firmware_loaded = 1;
+ } else {
+ char filename[32];
+ unsigned int soc;
+ unsigned int rev_h;
+ unsigned int rev_l;
+
+ soc = soc_info(&rev_h, &rev_l);
+ if (!soc) {
+ dev_err(&ofdev->dev, "unknown CPU model\n");
+ return -ENXIO;
+ }
+ sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin",
+ soc, rev_h, rev_l);
+
+ dev_info(&ofdev->dev, "waiting for firmware %s\n",
+ filename);
+
+ /*
+ * We call request_firmware_nowait instead of
+ * request_firmware so that the driver can load and
+ * initialize the ports without holding up the rest of
+ * the kernel. If hotplug support is enabled in the
+ * kernel, then we use it.
+ */
+ ret = request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_HOTPLUG, filename, &ofdev->dev,
+ &ofdev->dev, uart_firmware_cont);
+ if (ret) {
+ dev_err(&ofdev->dev,
+ "could not load firmware %s\n",
+ filename);
+ return ret;
+ }
+ }
+ }
+
+ qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL);
+ if (!qe_port) {
+ dev_err(&ofdev->dev, "can't allocate QE port structure\n");
+ return -ENOMEM;
+ }
+
+ /* Search for IRQ and mapbase */
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
+ kfree(qe_port);
+ return ret;
+ }
+ if (!res.start) {
+ dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+ qe_port->port.mapbase = res.start;
+
+ /* Get the UCC number (device ID) */
+ /* UCCs are numbered 1-7 */
+ iprop = of_get_property(np, "device-id", NULL);
+ if (!iprop || (*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
+ dev_err(&ofdev->dev,
+ "missing or invalid UCC specified in device tree\n");
+ kfree(qe_port);
+ return -ENODEV;
+ }
+ qe_port->ucc_num = *iprop - 1;
+
+ /*
+ * In the future, we should not require the BRG to be specified in the
+ * device tree. If no clock-source is specified, then just pick a BRG
+ * to use. This requires a new QE library function that manages BRG
+ * assignments.
+ */
+
+ sprop = of_get_property(np, "rx-clock-name", NULL);
+ if (!sprop) {
+ dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
+ kfree(qe_port);
+ return -ENODEV;
+ }
+
+ qe_port->us_info.rx_clock = qe_clock_source(sprop);
+ if ((qe_port->us_info.rx_clock < QE_BRG1) ||
+ (qe_port->us_info.rx_clock > QE_BRG16)) {
+ dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
+ kfree(qe_port);
+ return -ENODEV;
+ }
+
+#ifdef LOOPBACK
+ /* In internal loopback mode, TX and RX must use the same clock */
+ qe_port->us_info.tx_clock = qe_port->us_info.rx_clock;
+#else
+ sprop = of_get_property(np, "tx-clock-name", NULL);
+ if (!sprop) {
+ dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
+ kfree(qe_port);
+ return -ENODEV;
+ }
+ qe_port->us_info.tx_clock = qe_clock_source(sprop);
+#endif
+ if ((qe_port->us_info.tx_clock < QE_BRG1) ||
+ (qe_port->us_info.tx_clock > QE_BRG16)) {
+ dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
+ kfree(qe_port);
+ return -ENODEV;
+ }
+
+ /* Get the port number, numbered 0-3 */
+ iprop = of_get_property(np, "port-number", NULL);
+ if (!iprop) {
+ dev_err(&ofdev->dev, "missing port-number in device tree\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+ qe_port->port.line = *iprop;
+ if (qe_port->port.line >= UCC_MAX_UART) {
+ dev_err(&ofdev->dev, "port-number must be 0-%u\n",
+ UCC_MAX_UART - 1);
+ kfree(qe_port);
+ return -EINVAL;
+ }
+
+ qe_port->port.irq = irq_of_parse_and_map(np, 0);
+ if (qe_port->port.irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
+ qe_port->ucc_num + 1);
+ kfree(qe_port);
+ return -EINVAL;
+ }
+
+ /*
+ * Newer device trees have an "fsl,qe" compatible property for the QE
+ * node, but we still need to support older device trees.
+ */
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!np) {
+ np = of_find_node_by_type(NULL, "qe");
+ if (!np) {
+ dev_err(&ofdev->dev, "could not find 'qe' node\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+ }
+
+ iprop = of_get_property(np, "brg-frequency", NULL);
+ if (!iprop) {
+ dev_err(&ofdev->dev,
+ "missing brg-frequency in device tree\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+
+ if (*iprop)
+ qe_port->port.uartclk = *iprop;
+ else {
+ /*
+ * Older versions of U-Boot do not initialize the brg-frequency
+ * property, so in this case we assume the BRG frequency is
+ * half the QE bus frequency.
+ */
+ iprop = of_get_property(np, "bus-frequency", NULL);
+ if (!iprop) {
+ dev_err(&ofdev->dev,
+ "missing QE bus-frequency in device tree\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+ if (*iprop)
+ qe_port->port.uartclk = *iprop / 2;
+ else {
+ dev_err(&ofdev->dev,
+ "invalid QE bus-frequency in device tree\n");
+ kfree(qe_port);
+ return -EINVAL;
+ }
+ }
+
+ spin_lock_init(&qe_port->port.lock);
+ qe_port->np = np;
+ qe_port->port.dev = &ofdev->dev;
+ qe_port->port.ops = &qe_uart_pops;
+ qe_port->port.iotype = UPIO_MEM;
+
+ qe_port->tx_nrfifos = TX_NUM_FIFO;
+ qe_port->tx_fifosize = TX_BUF_SIZE;
+ qe_port->rx_nrfifos = RX_NUM_FIFO;
+ qe_port->rx_fifosize = RX_BUF_SIZE;
+
+ qe_port->wait_closing = UCC_WAIT_CLOSING;
+ qe_port->port.fifosize = 512;
+ qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+
+ qe_port->us_info.ucc_num = qe_port->ucc_num;
+ qe_port->us_info.regs = (phys_addr_t) res.start;
+ qe_port->us_info.irq = qe_port->port.irq;
+
+ qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos;
+ qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos;
+
+ /* Make sure ucc_slow_init() initializes both TX and RX */
+ qe_port->us_info.init_tx = 1;
+ qe_port->us_info.init_rx = 1;
+
+ /* Add the port to the uart sub-system. This will cause
+ * qe_uart_config_port() to be called, so the us_info structure must
+ * be initialized.
+ */
+ ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port);
+ if (ret) {
+ dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
+ qe_port->port.line);
+ kfree(qe_port);
+ return ret;
+ }
+
+ dev_set_drvdata(&ofdev->dev, qe_port);
+
+ dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
+ qe_port->ucc_num + 1, qe_port->port.line);
+
+ /* Display the mknod command for this device */
+ dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n",
+ qe_port->port.line, SERIAL_QE_MAJOR,
+ SERIAL_QE_MINOR + qe_port->port.line);
+
+ return 0;
+}
+
+static int ucc_uart_remove(struct of_device *ofdev)
+{
+ struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
+
+ dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
+
+ uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(qe_port);
+
+ return 0;
+}
+
+static struct of_device_id ucc_uart_match[] = {
+ {
+ .type = "serial",
+ .compatible = "ucc_uart",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ucc_uart_match);
+
+static struct of_platform_driver ucc_uart_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "ucc_uart",
+ .match_table = ucc_uart_match,
+ .probe = ucc_uart_probe,
+ .remove = ucc_uart_remove,
+};
+
+static int __init ucc_uart_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Freescale QUICC Engine UART device driver\n");
+#ifdef LOOPBACK
+ printk(KERN_INFO "ucc-uart: Using loopback mode\n");
+#endif
+
+ ret = uart_register_driver(&ucc_uart_driver);
+ if (ret) {
+ printk(KERN_ERR "ucc-uart: could not register UART driver\n");
+ return ret;
+ }
+
+ ret = of_register_platform_driver(&ucc_uart_of_driver);
+ if (ret)
+ printk(KERN_ERR
+ "ucc-uart: could not register platform driver\n");
+
+ return ret;
+}
+
+static void __exit ucc_uart_exit(void)
+{
+ printk(KERN_INFO
+ "Freescale QUICC Engine UART device driver unloading\n");
+
+ of_unregister_platform_driver(&ucc_uart_of_driver);
+ uart_unregister_driver(&ucc_uart_driver);
+}
+
+module_init(ucc_uart_init);
+module_exit(ucc_uart_exit);
+
+MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART");
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR);
+
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 7051e6c5edc..253ed5682a6 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -330,75 +330,13 @@ static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
{
- struct mpc52xx_cdm __iomem *cdm;
- struct mpc52xx_gpio __iomem *gpio;
struct mpc52xx_psc __iomem *psc = mps->psc;
- u32 ul;
u32 mclken_div;
int ret = 0;
-#if defined(CONFIG_PPC_MERGE)
- cdm = mpc52xx_find_and_map("mpc5200-cdm");
- gpio = mpc52xx_find_and_map("mpc5200-gpio");
-#else
- cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
- gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
-#endif
- if (!cdm || !gpio) {
- printk(KERN_ERR "Error mapping CDM/GPIO\n");
- ret = -EFAULT;
- goto unmap_regs;
- }
-
/* default sysclk is 512MHz */
- mclken_div = 0x8000 |
- (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
-
- switch (psc_id) {
- case 1:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFFFF8;
- ul |= 0x00000006;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc1, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000020;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 2:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFFF8F;
- ul |= 0x00000060;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc2, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000040;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 3:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFFFFF0FF;
- ul |= 0x00000600;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc3, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000080;
- out_be32(&cdm->clk_enables, ul);
- break;
- case 6:
- ul = in_be32(&gpio->port_config);
- ul &= 0xFF8FFFFF;
- ul |= 0x00700000;
- out_be32(&gpio->port_config, ul);
- out_be16(&cdm->mclken_div_psc6, mclken_div);
- ul = in_be32(&cdm->clk_enables);
- ul |= 0x00000010;
- out_be32(&cdm->clk_enables, ul);
- break;
- default:
- ret = -EINVAL;
- goto unmap_regs;
- }
+ mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK;
+ mpc52xx_set_psc_clkdiv(psc_id, mclken_div);
/* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
@@ -422,12 +360,6 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
mps->bits_per_word = 8;
-unmap_regs:
- if (cdm)
- iounmap(cdm);
- if (gpio)
- iounmap(gpio);
-
return ret;
}
@@ -623,8 +555,9 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
}
static struct of_device_id mpc52xx_psc_spi_of_match[] = {
- { .type = "spi", .compatible = "mpc5200-psc-spi", },
- {},
+ { .compatible = "fsl,mpc5200-psc-spi", },
+ { .compatible = "mpc5200-psc-spi", }, /* old */
+ {}
};
MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 4580b9cf625..04f7cd9fc26 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -436,11 +436,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->qe_mode = pdata->qe_mode;
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
-
- if (mpc83xx_spi->qe_mode)
- mpc83xx_spi->spibrg = pdata->sysclk / 2;
- else
- mpc83xx_spi->spibrg = pdata->sysclk;
+ mpc83xx_spi->spibrg = pdata->sysclk;
mpc83xx_spi->rx_shift = 0;
mpc83xx_spi->tx_shift = 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 0c3e6b790b7..a6725279122 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -136,6 +136,8 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
ohci = hcd_to_ohci(hcd);
if (is_bigendian) {
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
if (of_device_is_compatible(dn, "mpc5200-ohci"))
ohci->flags |= OHCI_QUIRK_FRAME_NO;
}