summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@stericsson.com>2012-06-04 19:45:37 +0800
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-06-04 19:45:37 +0800
commitd3aeada8de410edd0ea3cb1b73381ebae469c584 (patch)
tree8b22bec8a39e599c9250e50ab4078425ca749b35 /arch
parent591e5e125f9de0513a732371378eeffe09ef4da5 (diff)
parent7338b0ab88d72b11989f40394069164d9326afbf (diff)
Merge topic branch 'modem' into integration-linux-ux500
Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-ux500/Kconfig14
-rw-r--r--arch/arm/mach-ux500/include/mach/isa_ioctl.h50
-rw-r--r--arch/arm/mach-ux500/include/mach/mbox-db5500.h7
-rw-r--r--arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h82
-rw-r--r--arch/arm/mach-ux500/include/mach/mloader-dbx500.h48
-rw-r--r--arch/arm/mach-ux500/include/mach/sim_detect.h15
-rw-r--r--arch/arm/mach-ux500/mloader-db5500.c202
-rw-r--r--arch/arm/mach-ux500/mloader-db8500.c91
-rw-r--r--arch/arm/mach-ux500/modem-irq-db5500.c6
9 files changed, 512 insertions, 3 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 5b81df73186..1527359d2bf 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -208,4 +208,18 @@ source "arch/arm/mach-ux500/test/Kconfig"
source "arch/arm/mach-ux500/Kconfig-arch"
+config DB8500_MLOADER
+ bool "Modem firmware upload/download support"
+ depends on UX500_SOC_DB8500
+ select DBX500_MLOADER
+ help
+ Adds Modem firmware upload/download support to DB8500.
+
+config U5500_MLOADER
+ bool "mLoader, mem config from kernel boot args exported to sysfs"
+ depends on UX500_SOC_DB5500
+ help
+ Link between boot args and user space program that loads the modem ELF.
+ This is used to expose the modem parameters using sysfs interface.
+
endif
diff --git a/arch/arm/mach-ux500/include/mach/isa_ioctl.h b/arch/arm/mach-ux500/include/mach/isa_ioctl.h
new file mode 100644
index 00000000000..b1f3ba159da
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/isa_ioctl.h
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* 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.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* 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, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+#ifndef __MODEM_IPC_INCLUDED
+#define __MODEM_IPC_INCLUDED
+
+#define DLP_IOCTL_MAGIC_NUMBER 'M'
+#define COMMON_BUFFER_SIZE (1024*1024)
+
+/**
+DLP Message Structure for Userland
+*/
+struct t_dlp_message{
+ unsigned int offset;
+ unsigned int size;
+};
+
+/**
+mmap constants.
+*/
+enum t_dlp_mmap_params {
+ MMAP_DLQUEUE,
+ MMAP_ULQUEUE
+};
+
+/**
+DLP IOCTLs for Userland
+*/
+#define DLP_IOC_ALLOCATE_BUFFER \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 0, struct t_dlp_message *)
+#define DLP_IOC_DEALLOCATE_BUFFER \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 1, struct t_dlp_message *)
+#define DLP_IOC_GET_MESSAGE \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 2, struct t_dlp_message *)
+#define DLP_IOC_PUT_MESSAGE \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 3, struct t_dlp_message *)
+
+#endif /*__MODEM_IPC_INCLUDED*/
diff --git a/arch/arm/mach-ux500/include/mach/mbox-db5500.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h
index 7f9da4d2fbd..2da180b8df6 100644
--- a/arch/arm/mach-ux500/include/mach/mbox-db5500.h
+++ b/arch/arm/mach-ux500/include/mach/mbox-db5500.h
@@ -40,6 +40,7 @@ typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
* @lock: Spinlock to protect this mailbox instance.
* @write_index: Index in internal buffer to write to.
* @read_index: Index in internal buffer to read from.
+ * @irq: mailbox interrupt.
* @allocated: Indicates whether this particular mailbox
* id has been allocated by someone.
*/
@@ -57,7 +58,11 @@ struct mbox {
spinlock_t lock;
u8 write_index;
u8 read_index;
+ int irq;
bool allocated;
+#if defined(CONFIG_DEBUG_FS)
+ struct dentry *dentry;
+#endif
};
/**
@@ -84,5 +89,5 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
* specify "block" in order to block until send is possible).
*/
int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
-
+void mbox_state_reset(void);
#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h b/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h
new file mode 100644
index 00000000000..69616c4cdec
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/mbox_channels-db5500.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com> for ST-Ericsson.
+ * Bibek Basu <bibek.basu@stericsson.com>
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __INC_MBOX_CHANNELS_H
+#define __INC_MBOX_CHANNELS_H
+
+/* Maximum number of datawords which can be send in one PDU */
+#define MAILBOX_NR_OF_DATAWORDS 3
+
+/* Number of buffers */
+#define NUM_DSP_BUFFER 32
+
+/**
+ * mbox_channel_cb_t - Definition of the mailbox channel callback.
+ * @data: Pointer to the data.
+ * @length: Length of the data.
+ * @priv: The client's private data.
+ *
+ * This function will be called upon reception of complete mbox channel PDU
+ * or after completion of send operation.
+ */
+typedef void mbox_channel_cb_t (u32 *data, u32 length, void *priv);
+
+/**
+ * struct mbox_channel_msg - Definition of mbox channel message
+ * @channel: Channel number.
+ * @data: Pointer to data to be sent.
+ * @length: Length of data to be sent.
+ * @cb: Pointer to the callback function to be called when send
+ * operation will be finished.
+ * @priv: The client's private data.
+ *
+ * This structure describes mailbox channel message.
+ */
+struct mbox_channel_msg {
+ u16 channel;
+ u32 *data;
+ u8 length;
+ mbox_channel_cb_t *cb;
+ void *priv;
+};
+
+/**
+ * mbox_channel_register - Set up a given mailbox channel.
+ * @channel: Mailbox channel number.
+ * @cb: Pointer to the callback function to be called when a new message
+ * is received.
+ * @priv: Client user data which will be returned in the callback.
+ *
+ * Returns 0 on success or a negative error code on error.
+ */
+int mbox_channel_register(u16 channel, mbox_channel_cb_t *cb, void *priv);
+
+/**
+ * mbox_channel_send - Send data on given mailbox channel.
+ * @msg: Mailbox channel message to be sent.
+ *
+ * Returns 0 on success or a negative error code on error.
+ */
+int mbox_channel_send(struct mbox_channel_msg *msg);
+
+/**
+ * mbox_channel_revoke_messages - Revoke messages on given mailbox channel.
+ * @channel: Mailbox channel number.
+ *
+ * Returns 0 on success or a negative error code on error.
+ */
+int mbox_channel_revoke_messages(u16 channel);
+
+/**
+ * mbox_channel_deregister - de-register given mailbox channel.
+ * @channel: Mailbox channel number.
+ *
+ * Returns 0 on success or a negative error code on error.
+ */
+int mbox_channel_deregister(u16 channel);
+
+#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/mloader-dbx500.h b/arch/arm/mach-ux500/include/mach/mloader-dbx500.h
new file mode 100644
index 00000000000..68fa55a3f53
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/mloader-dbx500.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Ludovic Barre <ludovic.barre@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _MLOADER_UX500_H_
+#define _MLOADER_UX500_H_
+
+/**
+ * struct dbx500_ml_area - data structure for modem memory areas description
+ * @name: name of the area
+ * @start: start address of the area
+ * @size: size of the area
+ */
+struct dbx500_ml_area {
+ const char *name;
+ u32 start;
+ u32 size;
+};
+
+/**
+ * struct dbx500_ml_fw - data stucture for modem firmwares description
+ * @name: firmware name
+ * @area: area where firmware is uploaded
+ * @offset: offset in the area where firmware is uploaded
+ */
+struct dbx500_ml_fw {
+ const char *name;
+ struct dbx500_ml_area *area;
+ u32 offset;
+};
+
+/**
+ * struct dbx500_mloader_pdata - data structure for platform specific data
+ * @fws: pointer on firmwares table
+ * @nr_fws: number of firmwares
+ * @areas: pointer on areas table
+ * @nr_areas: number of areas
+ */
+struct dbx500_mloader_pdata {
+ struct dbx500_ml_fw *fws;
+ int nr_fws;
+ struct dbx500_ml_area *areas;
+ int nr_areas;
+};
+
+#endif /* _MLOADER_UX500_H_ */
diff --git a/arch/arm/mach-ux500/include/mach/sim_detect.h b/arch/arm/mach-ux500/include/mach/sim_detect.h
new file mode 100644
index 00000000000..4dae656b7e0
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/sim_detect.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright ST-Ericsson 2010 SA.
+ *
+ * Author: Bibek Basu <bibek.basu@stericsson.com>
+ * Licensed under GPLv2.
+ */
+
+#ifndef _AB8500_SIM_DETECT_H
+#define _AB8500_SIM_DETECT_H
+
+struct sim_detect_platform_data {
+ int irq_num;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/mloader-db5500.c b/arch/arm/mach-ux500/mloader-db5500.c
new file mode 100644
index 00000000000..bc3a57af28b
--- /dev/null
+++ b/arch/arm/mach-ux500/mloader-db5500.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors: Jonas Aaberg <jonas.aberg@stericsson.com>
+ * Paer-Olof Haakansson <par-olof.hakansson@stericsson.com>
+ * for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+
+static ssize_t db5500_mloader_sysfs_addr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static ssize_t db5500_mloader_sysfs_finalize(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t db5500_mloader_sysfs_itpmode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static DEVICE_ATTR(addr, S_IRUSR|S_IRGRP, db5500_mloader_sysfs_addr, NULL);
+static DEVICE_ATTR(finalize, S_IWUSR, NULL, db5500_mloader_sysfs_finalize);
+static DEVICE_ATTR(is_itpmode, S_IRUSR|S_IRGRP, db5500_mloader_sysfs_itpmode, NULL);
+
+static unsigned int db5500_bootargs_memmap_modem_start;
+static unsigned int db5500_bootargs_memmap_modem_total_size;
+static unsigned int db5500_mloader_itpmode;
+static unsigned int db5500_mloader_shm_total_size;
+module_param_named(shm_total_size, db5500_mloader_shm_total_size, uint, 0600);
+MODULE_PARM_DESC(shm_total_size, "Total Size of SHM shared memory");
+
+static int __init db5500_bootargs_modem_memmap(char *p)
+{
+ db5500_bootargs_memmap_modem_total_size = memparse(p, &p);
+ if (*p == '@')
+ db5500_bootargs_memmap_modem_start = memparse(p + 1, &p);
+
+ return 0;
+}
+early_param("mem_modem", db5500_bootargs_modem_memmap);
+
+static int __init db5500_bootargs_shm_total_size(char *str)
+{
+ int ret;
+ ret = strict_strtoul(str, 0, &db5500_mloader_shm_total_size);
+ if (ret < 0)
+ return -EINVAL;
+ return 1;
+}
+early_param("mloader.shm_total_size", db5500_bootargs_shm_total_size);
+
+static int __init db5500_bootargs_itpmode(char *p)
+{
+ int ret;
+ int count = 3;
+ if (!memcmp(p, "itp", count))
+ db5500_mloader_itpmode = true;
+ else
+ db5500_mloader_itpmode = false;
+ return 1;
+}
+early_param("modem_boot_type", db5500_bootargs_itpmode);
+
+static int __exit db5500_mloader_remove(struct platform_device *pdev)
+{
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_finalize.attr);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_is_itpmode.attr);
+
+ return 0;
+}
+
+
+static struct platform_driver db5500_mloader_driver = {
+ .driver = {
+ .name = "db5500_mloader",
+ },
+ .remove = __exit_p(db5500_mloader_remove),
+};
+
+struct db5500_mloader {
+ struct work_struct work;
+ struct platform_device *pdev;
+};
+
+static void db5500_mloader_clean_up(struct work_struct *work)
+{
+ struct db5500_mloader *m = container_of(work,
+ struct db5500_mloader,
+ work);
+
+ /* Remove this module */
+ platform_device_unregister(m->pdev);
+
+ platform_driver_unregister(&db5500_mloader_driver);
+ kfree(m);
+
+}
+
+static ssize_t db5500_mloader_sysfs_addr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x 0x%x 0x%x\n",
+ db5500_bootargs_memmap_modem_start,
+ db5500_bootargs_memmap_modem_total_size,
+ db5500_mloader_shm_total_size);
+}
+
+static ssize_t db5500_mloader_sysfs_itpmode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x\n",
+ db5500_mloader_itpmode);
+}
+
+static ssize_t db5500_mloader_sysfs_finalize(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct db5500_mloader *m;
+
+ m = kmalloc(sizeof(struct db5500_mloader), GFP_KERNEL);
+
+ m->pdev = container_of(dev,
+ struct platform_device,
+ dev);
+
+ INIT_WORK(&m->work, db5500_mloader_clean_up);
+
+ /* The module can not remove itself while being in a sysfs function,
+ * it has to use a workqueue.
+ */
+ schedule_work(&m->work);
+
+ return count;
+}
+
+static void db5500_mloader_release(struct device *dev)
+{
+ /* Nothing to release */
+}
+
+static int __init db5500_mloader_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pdev->dev.release = db5500_mloader_release;
+
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ if (ret)
+ return ret;
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_finalize.attr);
+
+ if (ret) {
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ return ret;
+ }
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_is_itpmode.attr);
+ if (ret) {
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_finalize.attr);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ return ret;
+ }
+ return 0;
+
+}
+
+static int __init db5500_mloader_init(void)
+{
+/*
+ * mloader for Fairbanks. It exports the physical
+ * address where the modem side ELF should be located in a sysfs
+ * file to make it available for a user space utility.
+ * When the mLoader utility has picked up these settings, this module is no
+ * longer needed and can be removed by writing to sysfs finalize.
+ *
+ * The modem side should be loaded via mmap'ed /dev/mem
+ *
+ */
+
+ return platform_driver_probe(&db5500_mloader_driver,
+ db5500_mloader_probe);
+}
+module_init(db5500_mloader_init);
+
+
+static void __exit mloader_exit(void)
+{
+ platform_driver_unregister(&db5500_mloader_driver);
+}
+module_exit(mloader_exit);
+
+MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ux500/mloader-db8500.c b/arch/arm/mach-ux500/mloader-db8500.c
new file mode 100644
index 00000000000..8f08e6af969
--- /dev/null
+++ b/arch/arm/mach-ux500/mloader-db8500.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 ST-Ericsson
+ *
+ * Author: Maxime Coquelin <maxime.coquelin-nonst@stericsson.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/types.h>
+#include <linux/platform_device.h>
+
+#include <mach/mloader-dbx500.h>
+#include <mach/hardware.h>
+
+static struct dbx500_ml_area modem_areas[] = {
+ { .name = "modem_trace", .start = 0x6000000, .size = 0xf00000 },
+ { .name = "modem_shared", .start = 0x6f00000, .size = 0x100000 },
+ { .name = "modem_priv", .start = 0x7000000, .size = 0x1000000 },
+};
+
+static struct dbx500_ml_fw modem_fws[] = {
+ { .name = "MODEM", .area = &modem_areas[0], .offset = 0x0 },
+ { .name = "IPL", .area = &modem_areas[1], .offset = 0x00 },
+};
+
+static struct dbx500_mloader_pdata mloader_fw_data = {
+ .fws = modem_fws,
+ .nr_fws = ARRAY_SIZE(modem_fws),
+ .areas = modem_areas,
+ .nr_areas = ARRAY_SIZE(modem_areas),
+};
+
+static struct resource mloader_fw_rsrc[] = {
+ {
+ .start = (U8500_BACKUPRAM1_BASE + 0xF70),
+ .end = (U8500_BACKUPRAM1_BASE + 0xF7C),
+ .flags = IORESOURCE_MEM
+ }
+};
+
+struct platform_device mloader_fw_device = {
+ .name = "dbx500_mloader_fw",
+ .id = -1,
+ .dev = {
+ .platform_data = &mloader_fw_data,
+ },
+ .resource = mloader_fw_rsrc,
+ .num_resources = ARRAY_SIZE(mloader_fw_rsrc)
+};
+
+/* Default areas can be overloaded in cmdline */
+static int __init early_modem_priv(char *p)
+{
+ struct dbx500_ml_area *area = &modem_areas[2];
+
+ area->size = memparse(p, &p);
+
+ if (*p == '@')
+ area->start = memparse(p + 1, &p);
+
+ return 0;
+}
+early_param("mem_modem", early_modem_priv);
+
+static int __init early_modem_shared(char *p)
+{
+ struct dbx500_ml_area *area = &modem_areas[1];
+
+ area->size = memparse(p, &p);
+
+ if (*p == '@')
+ area->start = memparse(p + 1, &p);
+
+ return 0;
+}
+early_param("mem_mshared", early_modem_shared);
+
+static int __init early_modem_trace(char *p)
+{
+ struct dbx500_ml_area *area = &modem_areas[0];
+
+ area->size = memparse(p, &p);
+
+ if (*p == '@')
+ area->start = memparse(p + 1, &p);
+
+ return 0;
+}
+early_param("mem_mtrace", early_modem_trace);
diff --git a/arch/arm/mach-ux500/modem-irq-db5500.c b/arch/arm/mach-ux500/modem-irq-db5500.c
index 6b86416c94c..7c2947af984 100644
--- a/arch/arm/mach-ux500/modem-irq-db5500.c
+++ b/arch/arm/mach-ux500/modem-irq-db5500.c
@@ -81,7 +81,7 @@ static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
virt_irq);
if (virt_irq != 0)
- generic_handle_irq(virt_irq);
+ handle_nested_irq(virt_irq);
pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
@@ -91,6 +91,7 @@ static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
{
irq_set_chip_and_handler(irq, modem_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(irq, 1);
set_irq_flags(irq, IRQF_VALID);
pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
@@ -131,7 +132,8 @@ static int modem_irq_init(void)
create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
- modem_cpu_irq_handler, IRQF_ONESHOT,
+ modem_cpu_irq_handler,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
"modem_irq", mi);
if (err)
pr_err("modem_irq: Could not register IRQ %d\n",