aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2011-10-17 16:24:34 -0700
committerIliyan Malchev <malchev@google.com>2011-10-17 16:24:34 -0700
commit538081533cd0bf0493a639d9072e8c494efbed39 (patch)
tree699cee8b6431256295212db6988405c5a548a2e0 /arch/arm/plat-omap
parentfd15d12179fc16a3a3c9a0a61f1eb0eb6c26a5bc (diff)
parent02c360221040924c2542113c4a72fe9d6af2d1ce (diff)
downloadkernel_samsung_tuna-538081533cd0bf0493a639d9072e8c494efbed39.zip
kernel_samsung_tuna-538081533cd0bf0493a639d9072e8c494efbed39.tar.gz
kernel_samsung_tuna-538081533cd0bf0493a639d9072e8c494efbed39.tar.bz2
Merge branch 'linux-omap-3.0' into android-omap-3.0
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r--arch/arm/plat-omap/dma.c18
-rw-r--r--arch/arm/plat-omap/include/plat/omap-serial.h1
-rw-r--r--arch/arm/plat-omap/mailbox.c20
-rw-r--r--arch/arm/plat-omap/omap_rpmsg.c117
4 files changed, 81 insertions, 75 deletions
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c22217c..3ec7ec5 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1024,12 +1024,26 @@ EXPORT_SYMBOL(omap_set_dma_callback);
*/
dma_addr_t omap_get_dma_src_pos(int lch)
{
+ u32 cdac;
dma_addr_t offset = 0;
if (cpu_is_omap15xx())
offset = p->dma_read(CPC, lch);
- else
- offset = p->dma_read(CSAC, lch);
+ else {
+ /*
+ * CDAC != 0 indicates that the DMA transfer on the channel has
+ * been started already.
+ * If CDAC == 0, we can not trust the CSAC value since it has
+ * not been updated, and can contain random number.
+ * Return the start address in case the DMA has not jet started.
+ * This is valid since in fact the DMA has not yet progressed.
+ */
+ cdac = p->dma_read(CDAC, lch);
+ if (likely(cdac))
+ offset = p->dma_read(CSAC, lch);
+ else
+ offset = p->dma_read(CSSA, lch);
+ }
if (IS_DMA_ERRATA(DMA_ERRATA_3_3) && offset == 0)
offset = p->dma_read(CSAC, lch);
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 56b63f8..2fbb5f0 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -141,6 +141,7 @@ struct uart_omap_port {
unsigned char wer;
int use_dma;
+ bool suspended;
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index a80e424..653153e 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -267,13 +267,6 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
}
if (!mbox->use_count++) {
- ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
- mbox->name, mbox);
- if (unlikely(ret)) {
- pr_err("failed to register mailbox interrupt:%d\n",
- ret);
- goto fail_request_irq;
- }
mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
if (!mq) {
ret = -ENOMEM;
@@ -288,15 +281,22 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
}
mbox->rxq = mq;
mq->mbox = mbox;
+ ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
+ mbox->name, mbox);
+ if (unlikely(ret)) {
+ pr_err("failed to register mailbox interrupt:%d\n",
+ ret);
+ goto fail_request_irq;
+ }
}
mutex_unlock(&mbox_configured_lock);
return 0;
+fail_request_irq:
+ mbox_queue_free(mbox->rxq);
fail_alloc_rxq:
mbox_queue_free(mbox->txq);
fail_alloc_txq:
- free_irq(mbox->irq, mbox);
-fail_request_irq:
if (mbox->ops->shutdown)
mbox->ops->shutdown(mbox);
mbox->use_count--;
@@ -315,7 +315,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
if (!--mbox->use_count) {
free_irq(mbox->irq, mbox);
tasklet_kill(&mbox->txq->tasklet);
- flush_work_sync(&mbox->rxq->work);
+ flush_work_sync(&mbox->rxq->work);
mbox_queue_free(mbox->txq);
mbox_queue_free(mbox->rxq);
}
diff --git a/arch/arm/plat-omap/omap_rpmsg.c b/arch/arm/plat-omap/omap_rpmsg.c
index 0cfd716..08f223e 100644
--- a/arch/arm/plat-omap/omap_rpmsg.c
+++ b/arch/arm/plat-omap/omap_rpmsg.c
@@ -50,10 +50,9 @@ struct omap_rpmsg_vproc {
struct rproc *rproc;
struct notifier_block nb;
struct notifier_block rproc_nb;
- struct notifier_block rproc_nb_pos_suspend;
- struct notifier_block rproc_nb_resume;
- struct notifier_block rproc_nb_error;
struct work_struct reset_work;
+ bool slave_reset;
+ struct omap_rpmsg_vproc *slave_next;
struct virtqueue *vq[2];
int base_vq_id;
int num_of_vqs;
@@ -201,39 +200,34 @@ static int omap_rpmsg_mbox_callback(struct notifier_block *this,
return NOTIFY_DONE;
}
-static int rpmsg_rproc_error(struct notifier_block *this,
- unsigned long type, void *data)
+static void rpmsg_reset_devices(struct omap_rpmsg_vproc *rpdev)
{
- struct omap_rpmsg_vproc *rpdev =
- container_of(this, struct omap_rpmsg_vproc, rproc_nb_error);
+ /* wait until previous reset requests have finished */
+ flush_work_sync(&rpdev->reset_work);
+ schedule_work(&rpdev->reset_work);
+}
+static int rpmsg_rproc_error(struct omap_rpmsg_vproc *rpdev)
+{
pr_err("Fatal error in %s\n", rpdev->rproc_name);
#ifdef CONFIG_OMAP_RPMSG_RECOVERY
- schedule_work(&rpdev->reset_work);
+ if (rpdev->slave_reset)
+ return NOTIFY_DONE;
+ rpmsg_reset_devices(rpdev);
#endif
return NOTIFY_DONE;
}
-static int rpmsg_rproc_suspend(struct notifier_block *this,
- unsigned long type, void *data)
+static int rpmsg_rproc_suspend(struct omap_rpmsg_vproc *rpdev)
{
- struct omap_rpmsg_vproc *rpdev =
- container_of(this, struct omap_rpmsg_vproc, rproc_nb);
-
if (virtqueue_more_used(rpdev->vq[0]))
return NOTIFY_BAD;
return NOTIFY_DONE;
}
-static int rpmsg_rproc_pos_suspend(struct notifier_block *this,
- unsigned long type, void *data)
+static int rpmsg_rproc_pos_suspend(struct omap_rpmsg_vproc *rpdev)
{
- struct omap_rpmsg_vproc *rpdev =
- container_of(this,
- struct omap_rpmsg_vproc,
- rproc_nb_pos_suspend);
-
if (rpdev->mbox) {
omap_mbox_put(rpdev->mbox, &rpdev->nb);
rpdev->mbox = NULL;
@@ -242,19 +236,33 @@ static int rpmsg_rproc_pos_suspend(struct notifier_block *this,
return NOTIFY_DONE;
}
-static int rpmsg_rproc_resume(struct notifier_block *this,
- unsigned long type, void *data)
+static int rpmsg_rproc_resume(struct omap_rpmsg_vproc *rpdev)
{
- struct omap_rpmsg_vproc *rpdev =
- container_of(this,
- struct omap_rpmsg_vproc,
- rproc_nb_resume);
-
if (!rpdev->mbox)
rpdev->mbox = omap_mbox_get(rpdev->mbox_name, &rpdev->nb);
return NOTIFY_DONE;
}
+
+static int rpmsg_rproc_events(struct notifier_block *this,
+ unsigned long type, void *data)
+{
+ struct omap_rpmsg_vproc *rpdev = container_of(this,
+ struct omap_rpmsg_vproc, rproc_nb);
+
+ switch (type) {
+ case RPROC_ERROR:
+ return rpmsg_rproc_error(rpdev);
+ case RPROC_PRE_SUSPEND:
+ return rpmsg_rproc_suspend(rpdev);
+ case RPROC_POS_SUSPEND:
+ return rpmsg_rproc_pos_suspend(rpdev);
+ case RPROC_RESUME:
+ return rpmsg_rproc_resume(rpdev);
+ }
+ return NOTIFY_DONE;
+}
+
static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
unsigned index,
void (*callback)(struct virtqueue *vq),
@@ -311,17 +319,7 @@ static void omap_rpmsg_del_vqs(struct virtio_device *vdev)
struct virtqueue *vq, *n;
struct omap_rpmsg_vproc *rpdev = to_omap_rpdev(vdev);
- rproc_event_unregister(rpdev->rproc, &rpdev->rproc_nb,
- RPROC_PRE_SUSPEND);
-
- rproc_event_unregister(rpdev->rproc, &rpdev->rproc_nb_pos_suspend,
- RPROC_POS_SUSPEND);
-
- rproc_event_unregister(rpdev->rproc, &rpdev->rproc_nb_resume,
- RPROC_RESUME);
-
- rproc_event_unregister(rpdev->rproc, &rpdev->rproc_nb_error,
- RPROC_ERROR);
+ rproc_event_unregister(rpdev->rproc, &rpdev->rproc_nb);
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
struct omap_rpmsg_vq_info *rpvq = vq->priv;
@@ -411,24 +409,9 @@ static int omap_rpmsg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
err = -EINVAL;
goto put_mbox;
}
- /* register for remoteproc pre-suspend */
- rpdev->rproc_nb.notifier_call = rpmsg_rproc_suspend;
- rproc_event_register(rpdev->rproc, &rpdev->rproc_nb, RPROC_PRE_SUSPEND);
-
- /* register for remoteproc post-suspend */
- rpdev->rproc_nb_pos_suspend.notifier_call = rpmsg_rproc_pos_suspend;
- rproc_event_register(rpdev->rproc,
- &rpdev->rproc_nb_pos_suspend, RPROC_POS_SUSPEND);
-
- /* register for remoteproc resume */
- rpdev->rproc_nb_resume.notifier_call = rpmsg_rproc_resume;
- rproc_event_register(rpdev->rproc,
- &rpdev->rproc_nb_resume, RPROC_RESUME);
-
- /* register for fatal errors */
- INIT_WORK(&rpdev->reset_work, rpmsg_reset_work);
- rpdev->rproc_nb_error.notifier_call = rpmsg_rproc_error;
- rproc_event_register(rpdev->rproc, &rpdev->rproc_nb_error, RPROC_ERROR);
+ /* register for remoteproc events */
+ rpdev->rproc_nb.notifier_call = rpmsg_rproc_events;
+ rproc_event_register(rpdev->rproc, &rpdev->rproc_nb);
return 0;
@@ -483,15 +466,20 @@ static void rpmsg_reset_work(struct work_struct *work)
{
struct omap_rpmsg_vproc *rpdev =
container_of(work, struct omap_rpmsg_vproc, reset_work);
+ struct omap_rpmsg_vproc *tmp;
int ret;
- pr_err("reseting virtio device %d\n", rpdev->vdev.index);
- unregister_virtio_device(&rpdev->vdev);
- memset(&rpdev->vdev.dev, 0, sizeof(struct device));
- rpdev->vdev.dev.release = omap_rpmsg_vproc_release;
- ret = register_virtio_device(&rpdev->vdev);
- if (ret)
- pr_err("error creating virtio device %d\n", ret);
+ for (tmp = rpdev; tmp; tmp = tmp->slave_next) {
+ pr_err("reseting virtio device %d\n", tmp->vdev.index);
+ unregister_virtio_device(&tmp->vdev);
+ }
+ for (tmp = rpdev; tmp; tmp = tmp->slave_next) {
+ memset(&tmp->vdev.dev, 0, sizeof(struct device));
+ tmp->vdev.dev.release = omap_rpmsg_vproc_release;
+ ret = register_virtio_device(&tmp->vdev);
+ if (ret)
+ pr_err("error creating virtio device %d\n", ret);
+ }
}
static struct virtio_config_ops omap_rpmsg_config_ops = {
@@ -525,6 +513,7 @@ static struct omap_rpmsg_vproc omap_rpmsg_vprocs[] = {
.rproc_name = "ipu",
.base_vq_id = 0,
.hardcoded_chnls = omap_ipuc0_hardcoded_chnls,
+ .slave_next = &omap_rpmsg_vprocs[1],
},
/* ipu_c1's rpmsg backend */
{
@@ -534,6 +523,7 @@ static struct omap_rpmsg_vproc omap_rpmsg_vprocs[] = {
.rproc_name = "ipu",
.base_vq_id = 2,
.hardcoded_chnls = omap_ipuc1_hardcoded_chnls,
+ .slave_reset = true,
},
};
@@ -561,6 +551,7 @@ static int __init omap_rpmsg_ini(void)
rpdev->buf_size = RPMSG_BUFS_SPACE;
rpdev->vring[0] = paddr + RPMSG_BUFS_SPACE;
rpdev->vring[1] = paddr + RPMSG_BUFS_SPACE + RPMSG_RING_SIZE;
+ INIT_WORK(&rpdev->reset_work, rpmsg_reset_work);
paddr += RPMSG_IPC_MEM;
psize -= RPMSG_IPC_MEM;