@@ -49,3 +49,4 @@ obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
+obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-tpiu.o
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010-2013
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <mach/hardware.h>
+
+#define TPIU_PORT_SIZE 0x4
+#define TPIU_TRIGGER_COUNTER 0x104
+#define TPIU_TRIGGER_MULTIPLIER 0x108
+#define TPIU_CURRENT_TEST_PATTERN 0x204
+#define TPIU_TEST_PATTERN_REPEAT 0x208
+#define TPIU_FORMATTER 0x304
+#define TPIU_FORMATTER_SYNC 0x308
+#define TPIU_LOCK_ACCESS_REGISTER 0xFB0
+
+#define TPIU_UNLOCK_CODE 0xc5acce55
+
+/* The context of the Trace Port Interface Unit (TPIU) */
+static struct {
+ void __iomem *base;
+ u32 port_size;
+ u32 trigger_counter;
+ u32 trigger_multiplier;
+ u32 current_test_pattern;
+ u32 test_pattern_repeat;
+ u32 formatter;
+ u32 formatter_sync;
+} context_tpiu;
+
+/*
+ * Save the context of the DB8500 Trace Port Interface Unit (TPIU).
+ * Saving/restoring is needed for the PTM tracing to work together
+ * with sleep states where the APE power domain is turned off.
+ */
+static void tpiu_save_context(void)
+{
+ context_tpiu.port_size = readl(context_tpiu.base +
+ TPIU_PORT_SIZE);
+ context_tpiu.trigger_counter = readl(context_tpiu.base +
+ TPIU_TRIGGER_COUNTER);
+ context_tpiu.trigger_multiplier = readl(context_tpiu.base +
+ TPIU_TRIGGER_MULTIPLIER);
+ context_tpiu.current_test_pattern = readl(context_tpiu.base +
+ TPIU_CURRENT_TEST_PATTERN);
+ context_tpiu.test_pattern_repeat = readl(context_tpiu.base +
+ TPIU_TEST_PATTERN_REPEAT);
+ context_tpiu.formatter = readl(context_tpiu.base +
+ TPIU_FORMATTER);
+ context_tpiu.formatter_sync = readl(context_tpiu.base +
+ TPIU_FORMATTER_SYNC);
+}
+
+/*
+ * Restore the context of the DB8500 Trace Port Interface Unit (TPIU).
+ * Saving/restoring is needed for the PTM tracing to work together
+ * with the sleep states where the APE power domain is turned off.
+ */
+static void tpiu_restore_context(void)
+{
+ writel(TPIU_UNLOCK_CODE,
+ context_tpiu.base + TPIU_LOCK_ACCESS_REGISTER);
+
+ writel(context_tpiu.port_size,
+ context_tpiu.base + TPIU_PORT_SIZE);
+ writel(context_tpiu.trigger_counter,
+ context_tpiu.base + TPIU_TRIGGER_COUNTER);
+ writel(context_tpiu.trigger_multiplier,
+ context_tpiu.base + TPIU_TRIGGER_MULTIPLIER);
+ writel(context_tpiu.current_test_pattern,
+ context_tpiu.base + TPIU_CURRENT_TEST_PATTERN);
+ writel(context_tpiu.test_pattern_repeat,
+ context_tpiu.base + TPIU_TEST_PATTERN_REPEAT);
+ writel(context_tpiu.formatter,
+ context_tpiu.base + TPIU_FORMATTER);
+ writel(context_tpiu.formatter_sync,
+ context_tpiu.base + TPIU_FORMATTER_SYNC);
+}
+
+static int tpiu_context_call(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ bool power_on = (bool)event;
+
+ if (power_on)
+ tpiu_restore_context();
+ else
+ tpiu_save_context();
+
+ return 0;
+}
+
+static struct notifier_block tpiu_context_notifier = {
+ .notifier_call = tpiu_context_call,
+};
+
+static const struct of_device_id dbx500_tpiu_match[] = {
+ { .compatible = "stericsson,dbx500-tpiu", },
+ {},
+};
+
+static struct platform_driver dbx500_tpiu_plat_driver = {
+ .driver = {
+ .name = "dbx500-tpiu",
+ .of_match_table = dbx500_tpiu_match,
+ },
+ .remove = __exit_p(dbx500_tpiu_remove),
+};
+
+static int __init dbx500_tpiu_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ return -EBUSY;
+ }
+
+ context_tpiu.base = ioremap(res->start, resource_size(res));
+ if (!context_tpiu.base) {
+ ret = -ENOMEM;
+ goto err_free_mem_region;
+ }
+
+ ret = pm_genpd_register_on_off_notifier(&pdev->dev,
+ &tpiu_context_notifier);
+ if (ret)
+ goto err_iounmap;
+
+ return ret;
+
+ err_iounmap:
+ iounmap(context_tpiu.base);
+ err_free_mem_region:
+ release_mem_region(res->start, resource_size(res));
+ return ret;
+}
+
+static int __exit dbx500_tpiu_remove(struct platform_device *pdev)
+{
+ int ret;
+
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ret = pm_genpd_unregister_on_off_notifier(&pdev->dev,
+ &tpiu_context_notifier);
+ iounmap(context_tpiu.base);
+ release_mem_region(res->start, resource_size(res));
+
+ return ret;
+}
+
+static int __init dbx500_tpiu_init(void)
+{
+ return platform_driver_probe(&dbx500_tpiu_plat_driver,
+ dbx500_tpiu_probe);
+}
+
+static void __exit dbx500_tpiu_exit(void)
+{
+ return platform_driver_unregister(&dbx500_tpiu_plat_driver);
+}
+
+arch_initcall(dbx500_tpiu_init);
+module_exit(dbx500_tpiu_exit);
+
+MODULE_DESCRIPTION("TPIU driver for dbx500");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rickard Andersson <rickard.andersson@stericsson.com>");
TPIU is Trace Port Interface Unit. Ux500 needs a TPIU driver because in Ux500 the TPIU hardware block loses its settings when the APE power domain is turned off. Settings needs to be saved before the sleep state ApSleep or ApDeepSleep is reached and the block needs to be unlocked and restored when leaving those sleep states. If this is not done PTM tracing with debugger stops working after the first sleep where the power domain is off. Signed-off-by: Rickard Andersson <rickard.andersson@stericsson.com> --- drivers/misc/Makefile | 1 + drivers/misc/dbx500-tpiu.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 drivers/misc/dbx500-tpiu.c