diff options
Diffstat (limited to 'drivers/firmware/tegra/bpmp.c')
| -rw-r--r-- | drivers/firmware/tegra/bpmp.c | 469 |
1 files changed, 207 insertions, 262 deletions
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 689478b92bce..e74bba7ccc44 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -1,22 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. */ #include <linux/clk/tegra.h> #include <linux/genalloc.h> #include <linux/mailbox_client.h> +#include <linux/module.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/semaphore.h> @@ -26,14 +18,18 @@ #include <soc/tegra/bpmp-abi.h> #include <soc/tegra/ivc.h> +#include "bpmp-private.h" + #define MSG_ACK BIT(0) #define MSG_RING BIT(1) #define TAG_SZ 32 -static inline struct tegra_bpmp * -mbox_client_to_bpmp(struct mbox_client *client) +static inline const struct tegra_bpmp_ops * +channel_to_ops(struct tegra_bpmp_channel *channel) { - return container_of(client, struct tegra_bpmp, mbox.client); + struct tegra_bpmp *bpmp = channel->bpmp; + + return bpmp->soc->ops; } struct tegra_bpmp *tegra_bpmp_get(struct device *dev) @@ -96,22 +92,21 @@ static bool tegra_bpmp_message_valid(const struct tegra_bpmp_message *msg) (msg->rx.size == 0 || msg->rx.data); } -static bool tegra_bpmp_master_acked(struct tegra_bpmp_channel *channel) +static bool tegra_bpmp_is_response_ready(struct tegra_bpmp_channel *channel) { - void *frame; + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); - frame = tegra_ivc_read_get_next_frame(channel->ivc); - if (IS_ERR(frame)) { - channel->ib = NULL; - return false; - } + return ops->is_response_ready(channel); +} - channel->ib = frame; +static bool tegra_bpmp_is_request_ready(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); - return true; + return ops->is_request_ready(channel); } -static int tegra_bpmp_wait_ack(struct tegra_bpmp_channel *channel) +static int tegra_bpmp_wait_response(struct tegra_bpmp_channel *channel) { unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; ktime_t end; @@ -119,29 +114,45 @@ static int tegra_bpmp_wait_ack(struct tegra_bpmp_channel *channel) end = ktime_add_us(ktime_get(), timeout); do { - if (tegra_bpmp_master_acked(channel)) + if (tegra_bpmp_is_response_ready(channel)) return 0; } while (ktime_before(ktime_get(), end)); return -ETIMEDOUT; } -static bool tegra_bpmp_master_free(struct tegra_bpmp_channel *channel) +static int tegra_bpmp_ack_response(struct tegra_bpmp_channel *channel) { - void *frame; + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); - frame = tegra_ivc_write_get_next_frame(channel->ivc); - if (IS_ERR(frame)) { - channel->ob = NULL; - return false; - } + return ops->ack_response(channel); +} - channel->ob = frame; +static int tegra_bpmp_ack_request(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); + + return ops->ack_request(channel); +} + +static bool +tegra_bpmp_is_request_channel_free(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); - return true; + return ops->is_request_channel_free(channel); } -static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) +static bool +tegra_bpmp_is_response_channel_free(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); + + return ops->is_response_channel_free(channel); +} + +static int +tegra_bpmp_wait_request_channel_free(struct tegra_bpmp_channel *channel) { unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; ktime_t start, now; @@ -149,7 +160,7 @@ static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) start = ns_to_ktime(local_clock()); do { - if (tegra_bpmp_master_free(channel)) + if (tegra_bpmp_is_request_channel_free(channel)) return 0; now = ns_to_ktime(local_clock()); @@ -158,19 +169,38 @@ static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) return -ETIMEDOUT; } +static int tegra_bpmp_post_request(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); + + return ops->post_request(channel); +} + +static int tegra_bpmp_post_response(struct tegra_bpmp_channel *channel) +{ + const struct tegra_bpmp_ops *ops = channel_to_ops(channel); + + return ops->post_response(channel); +} + +static int tegra_bpmp_ring_doorbell(struct tegra_bpmp *bpmp) +{ + return bpmp->soc->ops->ring_doorbell(bpmp); +} + static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, void *data, size_t size, int *ret) { int err; if (data && size > 0) - memcpy(data, channel->ib->data, size); + tegra_bpmp_mb_read(data, &channel->ib, size); - err = tegra_ivc_read_advance(channel->ivc); + err = tegra_bpmp_ack_response(channel); if (err < 0) return err; - *ret = channel->ib->code; + *ret = tegra_bpmp_mb_read_field(&channel->ib, code); return 0; } @@ -204,13 +234,13 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, unsigned int mrq, unsigned long flags, const void *data, size_t size) { - channel->ob->code = mrq; - channel->ob->flags = flags; + tegra_bpmp_mb_write_field(&channel->ob, code, mrq); + tegra_bpmp_mb_write_field(&channel->ob, flags, flags); if (data && size > 0) - memcpy(channel->ob->data, data, size); + tegra_bpmp_mb_write(&channel->ob, data, size); - return tegra_ivc_write_advance(channel->ivc); + return tegra_bpmp_post_request(channel); } static struct tegra_bpmp_channel * @@ -238,7 +268,7 @@ tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq, channel = &bpmp->threaded_channels[index]; - if (!tegra_bpmp_master_free(channel)) { + if (!tegra_bpmp_is_request_channel_free(channel)) { err = -EBUSY; goto unlock; } @@ -270,13 +300,15 @@ static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, { int err; - err = tegra_bpmp_wait_master_free(channel); + err = tegra_bpmp_wait_request_channel_free(channel); if (err < 0) return err; return __tegra_bpmp_channel_write(channel, mrq, flags, data, size); } +static int __maybe_unused tegra_bpmp_resume(struct device *dev); + int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, struct tegra_bpmp_message *msg) { @@ -289,6 +321,14 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, if (!tegra_bpmp_message_valid(msg)) return -EINVAL; + if (bpmp->suspended) { + /* Reset BPMP IPC channels during resume based on flags passed */ + if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) + tegra_bpmp_resume(bpmp->dev); + else + return -EAGAIN; + } + channel = bpmp->tx_channel; spin_lock(&bpmp->atomic_tx_lock); @@ -302,13 +342,11 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, spin_unlock(&bpmp->atomic_tx_lock); - err = mbox_send_message(bpmp->mbox.channel, NULL); + err = tegra_bpmp_ring_doorbell(bpmp); if (err < 0) return err; - mbox_client_txdone(bpmp->mbox.channel, 0); - - err = tegra_bpmp_wait_ack(channel); + err = tegra_bpmp_wait_response(channel); if (err < 0) return err; @@ -330,17 +368,23 @@ int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, if (!tegra_bpmp_message_valid(msg)) return -EINVAL; + if (bpmp->suspended) { + /* Reset BPMP IPC channels during resume based on flags passed */ + if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) + tegra_bpmp_resume(bpmp->dev); + else + return -EAGAIN; + } + channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data, msg->tx.size); if (IS_ERR(channel)) return PTR_ERR(channel); - err = mbox_send_message(bpmp->mbox.channel, NULL); + err = tegra_bpmp_ring_doorbell(bpmp); if (err < 0) return err; - mbox_client_txdone(bpmp->mbox.channel, 0); - timeout = usecs_to_jiffies(bpmp->soc->channels.thread.timeout); err = wait_for_completion_timeout(&channel->completion, timeout); @@ -367,40 +411,36 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp, void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code, const void *data, size_t size) { - unsigned long flags = channel->ib->flags; + unsigned long flags = tegra_bpmp_mb_read_field(&channel->ib, flags); struct tegra_bpmp *bpmp = channel->bpmp; - struct tegra_bpmp_mb_data *frame; int err; if (WARN_ON(size > MSG_DATA_MIN_SZ)) return; - err = tegra_ivc_read_advance(channel->ivc); + err = tegra_bpmp_ack_request(channel); if (WARN_ON(err < 0)) return; if ((flags & MSG_ACK) == 0) return; - frame = tegra_ivc_write_get_next_frame(channel->ivc); - if (WARN_ON(IS_ERR(frame))) + if (WARN_ON(!tegra_bpmp_is_response_channel_free(channel))) return; - frame->code = code; + tegra_bpmp_mb_write_field(&channel->ob, code, code); if (data && size > 0) - memcpy(frame->data, data, size); + tegra_bpmp_mb_write(&channel->ob, data, size); - err = tegra_ivc_write_advance(channel->ivc); + err = tegra_bpmp_post_response(channel); if (WARN_ON(err < 0)) return; if (flags & MSG_RING) { - err = mbox_send_message(bpmp->mbox.channel, NULL); + err = tegra_bpmp_ring_doorbell(bpmp); if (WARN_ON(err < 0)) return; - - mbox_client_txdone(bpmp->mbox.channel, 0); } } EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_return); @@ -473,7 +513,7 @@ EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) { - struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; + struct mrq_query_abi_request req = { .mrq = mrq }; struct mrq_query_abi_response resp; struct tegra_bpmp_message msg = { .mrq = MRQ_QUERY_ABI, @@ -486,10 +526,10 @@ bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) .size = sizeof(resp), }, }; - int ret; + int err; - ret = tegra_bpmp_transfer(bpmp, &msg); - if (ret || msg.rx.ret) + err = tegra_bpmp_transfer(bpmp, &msg); + if (err || msg.rx.ret) return false; return resp.status == 0; @@ -500,13 +540,13 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, struct tegra_bpmp_channel *channel, void *data) { - struct mrq_ping_request *request; + struct mrq_ping_request request; struct mrq_ping_response response; - request = (struct mrq_ping_request *)channel->ib->data; + tegra_bpmp_mb_read(&request, &channel->ib, sizeof(request)); memset(&response, 0, sizeof(response)); - response.reply = request->challenge << 1; + response.reply = request.challenge << 1; tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response)); } @@ -619,7 +659,7 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) { - unsigned long flags = channel->ob->flags; + unsigned long flags = tegra_bpmp_mb_read_field(&channel->ob, flags); if ((flags & MSG_RING) == 0) return; @@ -627,9 +667,8 @@ static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) complete(&channel->completion); } -static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) +void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp) { - struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client); struct tegra_bpmp_channel *channel; unsigned int i, count; unsigned long *busy; @@ -638,8 +677,11 @@ static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) count = bpmp->soc->channels.thread.count; busy = bpmp->threaded.busy; - if (tegra_bpmp_master_acked(channel)) - tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel); + if (tegra_bpmp_is_request_ready(channel)) { + unsigned int mrq = tegra_bpmp_mb_read_field(&channel->ib, code); + + tegra_bpmp_handle_mrq(bpmp, mrq, channel); + } spin_lock(&bpmp->lock); @@ -648,7 +690,7 @@ static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) channel = &bpmp->threaded_channels[i]; - if (tegra_bpmp_master_acked(channel)) { + if (tegra_bpmp_is_response_ready(channel)) { tegra_bpmp_channel_signal(channel); clear_bit(i, busy); } @@ -657,74 +699,9 @@ static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) spin_unlock(&bpmp->lock); } -static void tegra_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data) -{ - struct tegra_bpmp *bpmp = data; - int err; - - if (WARN_ON(bpmp->mbox.channel == NULL)) - return; - - err = mbox_send_message(bpmp->mbox.channel, NULL); - if (err < 0) - return; - - mbox_client_txdone(bpmp->mbox.channel, 0); -} - -static int tegra_bpmp_channel_init(struct tegra_bpmp_channel *channel, - struct tegra_bpmp *bpmp, - unsigned int index) -{ - size_t message_size, queue_size; - unsigned int offset; - int err; - - channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc), - GFP_KERNEL); - if (!channel->ivc) - return -ENOMEM; - - message_size = tegra_ivc_align(MSG_MIN_SZ); - queue_size = tegra_ivc_total_queue_size(message_size); - offset = queue_size * index; - - err = tegra_ivc_init(channel->ivc, NULL, - bpmp->rx.virt + offset, bpmp->rx.phys + offset, - bpmp->tx.virt + offset, bpmp->tx.phys + offset, - 1, message_size, tegra_bpmp_ivc_notify, - bpmp); - if (err < 0) { - dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n", - index, err); - return err; - } - - init_completion(&channel->completion); - channel->bpmp = bpmp; - - return 0; -} - -static void tegra_bpmp_channel_reset(struct tegra_bpmp_channel *channel) -{ - /* reset the channel state */ - tegra_ivc_reset(channel->ivc); - - /* sync the channel state with BPMP */ - while (tegra_ivc_notified(channel->ivc)) - ; -} - -static void tegra_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel) -{ - tegra_ivc_cleanup(channel->ivc); -} - static int tegra_bpmp_probe(struct platform_device *pdev) { struct tegra_bpmp *bpmp; - unsigned int i; char tag[TAG_SZ]; size_t size; int err; @@ -736,32 +713,6 @@ static int tegra_bpmp_probe(struct platform_device *pdev) bpmp->soc = of_device_get_match_data(&pdev->dev); bpmp->dev = &pdev->dev; - bpmp->tx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 0); - if (!bpmp->tx.pool) { - dev_err(&pdev->dev, "TX shmem pool not found\n"); - return -ENOMEM; - } - - bpmp->tx.virt = gen_pool_dma_alloc(bpmp->tx.pool, 4096, &bpmp->tx.phys); - if (!bpmp->tx.virt) { - dev_err(&pdev->dev, "failed to allocate from TX pool\n"); - return -ENOMEM; - } - - bpmp->rx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 1); - if (!bpmp->rx.pool) { - dev_err(&pdev->dev, "RX shmem pool not found\n"); - err = -ENOMEM; - goto free_tx; - } - - bpmp->rx.virt = gen_pool_dma_alloc(bpmp->rx.pool, 4096, &bpmp->rx.phys); - if (!bpmp->rx.virt) { - dev_err(&pdev->dev, "failed to allocate from RX pool\n"); - err = -ENOMEM; - goto free_tx; - } - INIT_LIST_HEAD(&bpmp->mrqs); spin_lock_init(&bpmp->lock); @@ -771,81 +722,40 @@ static int tegra_bpmp_probe(struct platform_device *pdev) size = BITS_TO_LONGS(bpmp->threaded.count) * sizeof(long); bpmp->threaded.allocated = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!bpmp->threaded.allocated) { - err = -ENOMEM; - goto free_rx; - } + if (!bpmp->threaded.allocated) + return -ENOMEM; bpmp->threaded.busy = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!bpmp->threaded.busy) { - err = -ENOMEM; - goto free_rx; - } + if (!bpmp->threaded.busy) + return -ENOMEM; spin_lock_init(&bpmp->atomic_tx_lock); bpmp->tx_channel = devm_kzalloc(&pdev->dev, sizeof(*bpmp->tx_channel), GFP_KERNEL); - if (!bpmp->tx_channel) { - err = -ENOMEM; - goto free_rx; - } + if (!bpmp->tx_channel) + return -ENOMEM; bpmp->rx_channel = devm_kzalloc(&pdev->dev, sizeof(*bpmp->rx_channel), GFP_KERNEL); - if (!bpmp->rx_channel) { - err = -ENOMEM; - goto free_rx; - } + if (!bpmp->rx_channel) + return -ENOMEM; bpmp->threaded_channels = devm_kcalloc(&pdev->dev, bpmp->threaded.count, sizeof(*bpmp->threaded_channels), GFP_KERNEL); - if (!bpmp->threaded_channels) { - err = -ENOMEM; - goto free_rx; - } + if (!bpmp->threaded_channels) + return -ENOMEM; - err = tegra_bpmp_channel_init(bpmp->tx_channel, bpmp, - bpmp->soc->channels.cpu_tx.offset); - if (err < 0) - goto free_rx; + platform_set_drvdata(pdev, bpmp); - err = tegra_bpmp_channel_init(bpmp->rx_channel, bpmp, - bpmp->soc->channels.cpu_rx.offset); + err = bpmp->soc->ops->init(bpmp); if (err < 0) - goto cleanup_tx_channel; - - for (i = 0; i < bpmp->threaded.count; i++) { - err = tegra_bpmp_channel_init( - &bpmp->threaded_channels[i], bpmp, - bpmp->soc->channels.thread.offset + i); - if (err < 0) - goto cleanup_threaded_channels; - } - - /* mbox registration */ - bpmp->mbox.client.dev = &pdev->dev; - bpmp->mbox.client.rx_callback = tegra_bpmp_handle_rx; - bpmp->mbox.client.tx_block = false; - bpmp->mbox.client.knows_txdone = false; - - bpmp->mbox.channel = mbox_request_channel(&bpmp->mbox.client, 0); - if (IS_ERR(bpmp->mbox.channel)) { - err = PTR_ERR(bpmp->mbox.channel); - dev_err(&pdev->dev, "failed to get HSP mailbox: %d\n", err); - goto cleanup_threaded_channels; - } - - /* reset message channels */ - tegra_bpmp_channel_reset(bpmp->tx_channel); - tegra_bpmp_channel_reset(bpmp->rx_channel); - for (i = 0; i < bpmp->threaded.count; i++) - tegra_bpmp_channel_reset(&bpmp->threaded_channels[i]); + return err; err = tegra_bpmp_request_mrq(bpmp, MRQ_PING, tegra_bpmp_mrq_handle_ping, bpmp); if (err < 0) - goto free_mbox; + goto deinit; err = tegra_bpmp_ping(bpmp); if (err < 0) { @@ -861,23 +771,27 @@ static int tegra_bpmp_probe(struct platform_device *pdev) dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag); - platform_set_drvdata(pdev, bpmp); - err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev); if (err < 0) goto free_mrq; - err = tegra_bpmp_init_clocks(bpmp); - if (err < 0) - goto free_mrq; + if (of_property_present(pdev->dev.of_node, "#clock-cells")) { + err = tegra_bpmp_init_clocks(bpmp); + if (err < 0) + goto free_mrq; + } - err = tegra_bpmp_init_resets(bpmp); - if (err < 0) - goto free_mrq; + if (of_property_present(pdev->dev.of_node, "#reset-cells")) { + err = tegra_bpmp_init_resets(bpmp); + if (err < 0) + goto free_mrq; + } - err = tegra_bpmp_init_powergates(bpmp); - if (err < 0) - goto free_mrq; + if (of_property_present(pdev->dev.of_node, "#power-domain-cells")) { + err = tegra_bpmp_init_powergates(bpmp); + if (err < 0) + goto free_mrq; + } err = tegra_bpmp_init_debugfs(bpmp); if (err < 0) @@ -887,41 +801,43 @@ static int tegra_bpmp_probe(struct platform_device *pdev) free_mrq: tegra_bpmp_free_mrq(bpmp, MRQ_PING, bpmp); -free_mbox: - mbox_free_channel(bpmp->mbox.channel); -cleanup_threaded_channels: - for (i = 0; i < bpmp->threaded.count; i++) { - if (bpmp->threaded_channels[i].bpmp) - tegra_bpmp_channel_cleanup(&bpmp->threaded_channels[i]); - } +deinit: + if (bpmp->soc->ops->deinit) + bpmp->soc->ops->deinit(bpmp); - tegra_bpmp_channel_cleanup(bpmp->rx_channel); -cleanup_tx_channel: - tegra_bpmp_channel_cleanup(bpmp->tx_channel); -free_rx: - gen_pool_free(bpmp->rx.pool, (unsigned long)bpmp->rx.virt, 4096); -free_tx: - gen_pool_free(bpmp->tx.pool, (unsigned long)bpmp->tx.virt, 4096); return err; } -static int __maybe_unused tegra_bpmp_resume(struct device *dev) +static int __maybe_unused tegra_bpmp_suspend(struct device *dev) { struct tegra_bpmp *bpmp = dev_get_drvdata(dev); - unsigned int i; - /* reset message channels */ - tegra_bpmp_channel_reset(bpmp->tx_channel); - tegra_bpmp_channel_reset(bpmp->rx_channel); - - for (i = 0; i < bpmp->threaded.count; i++) - tegra_bpmp_channel_reset(&bpmp->threaded_channels[i]); + bpmp->suspended = true; return 0; } -static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume); +static int __maybe_unused tegra_bpmp_resume(struct device *dev) +{ + struct tegra_bpmp *bpmp = dev_get_drvdata(dev); + + bpmp->suspended = false; + + if (bpmp->soc->ops->resume) + return bpmp->soc->ops->resume(bpmp); + else + return 0; +} + +static const struct dev_pm_ops tegra_bpmp_pm_ops = { + .suspend_noirq = tegra_bpmp_suspend, + .resume_noirq = tegra_bpmp_resume, +}; +#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_264_SOC) static const struct tegra_bpmp_soc tegra186_soc = { .channels = { .cpu_tx = { @@ -938,11 +854,44 @@ static const struct tegra_bpmp_soc tegra186_soc = { .timeout = 0, }, }, + .ops = &tegra186_bpmp_ops, .num_resets = 193, }; +#endif + +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) +static const struct tegra_bpmp_soc tegra210_soc = { + .channels = { + .cpu_tx = { + .offset = 0, + .count = 1, + .timeout = 60 * USEC_PER_SEC, + }, + .thread = { + .offset = 4, + .count = 1, + .timeout = 600 * USEC_PER_SEC, + }, + .cpu_rx = { + .offset = 8, + .count = 1, + .timeout = 0, + }, + }, + .ops = &tegra210_bpmp_ops, +}; +#endif static const struct of_device_id tegra_bpmp_match[] = { +#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_264_SOC) { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc }, +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) + { .compatible = "nvidia,tegra210-bpmp", .data = &tegra210_soc }, +#endif { } }; @@ -951,12 +900,8 @@ static struct platform_driver tegra_bpmp_driver = { .name = "tegra-bpmp", .of_match_table = tegra_bpmp_match, .pm = &tegra_bpmp_pm_ops, + .suppress_bind_attrs = true, }, .probe = tegra_bpmp_probe, }; - -static int __init tegra_bpmp_init(void) -{ - return platform_driver_register(&tegra_bpmp_driver); -} -core_initcall(tegra_bpmp_init); +builtin_platform_driver(tegra_bpmp_driver); |
