summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuma copybara merger <zuma-automerger@google.com>2022-08-25 05:46:08 +0000
committerCopybara-Service <copybara-worker@google.com>2022-08-26 00:40:04 -0700
commit8f5f253b6be533406d2e17394a866f31c8e63bfb (patch)
treed37d83ff6b9838e3e3b08476d26cbe2a880fb99e
parente91d0b6f253619f75ad466026ce654451a5b2c49 (diff)
downloadrio-8f5f253b6be533406d2e17394a866f31c8e63bfb.tar.gz
[Copybara Auto Merge] Merge branch zuma into android13-gs-pixel-5.15
gcip: implement gcip image config utilities Bug: 243500340 gcip: add gcip-image-config.h Bug: 243500340 (repeat) edgetpu: Program SSMT according to EDGETPU_NUM_SSMTS Bug: 241495826 gcip: Add linux/workqueue.h as header edgetpu: move rio SSMT init to new SoC init call for gsx01 edgetpu: move PM init before MMU attach edgetpu: Setting up SSMT to feed-through mode Bug: 241495826 (repeat) edgetpu: Use gcip.o in Kbuild Bug: 240234334 edgetpu: remove unneeded header include edgetpu: rename mobile PM functions to be edgetpu-specific edgetpu: move chip PM init call inside device add function edgetpu: move gsx01 rkci defines to new header, add gsx01 unit tests edgetpu: gsx01: fixup style a.o. issues edgetpu: move gsx01 pm_qos and bts functions to gsx01 soc source edgetpu: move gsx01-specific pm debugfs interfaces to gsx01 soc source edgetpu: support MMU_COHERENT on buffer mapping Bug: 241495826 (repeat) edgetpu: add future chip and SoC skeletal support Bug: 235693240 Signed-off-by: Zuma copybara merger <zuma-automerger@google.com> GitOrigin-RevId: e55df8c7c77503e13040518dd039abe726bb8cb6 Change-Id: I51f8fb38b3f4ffb4e46a7d1f4b971177ce6b39e8
-rw-r--r--drivers/edgetpu/Kbuild6
-rw-r--r--drivers/edgetpu/Makefile11
-rw-r--r--drivers/edgetpu/edgetpu-config.h4
-rw-r--r--drivers/edgetpu/edgetpu-core.c12
-rw-r--r--drivers/edgetpu/edgetpu-internal.h9
-rw-r--r--drivers/edgetpu/edgetpu-kci.c3
-rw-r--r--drivers/edgetpu/edgetpu-mapping.h5
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.c39
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.h2
-rw-r--r--drivers/edgetpu/edgetpu-pm.h6
-rw-r--r--drivers/edgetpu/edgetpu-soc.h21
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/Makefile2
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-image-config.c206
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-image-config.h150
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h1
-rw-r--r--drivers/edgetpu/include/soc/google/bcl.h37
-rw-r--r--drivers/edgetpu/mobile-pm.c308
-rw-r--r--drivers/edgetpu/mobile-pm.h42
-rw-r--r--drivers/edgetpu/mobile-soc-gsx01.c447
-rw-r--r--drivers/edgetpu/mobile-soc-gsx01.h23
-rw-r--r--drivers/edgetpu/rio-device.c22
-rw-r--r--drivers/edgetpu/rio-pm.c2
-rw-r--r--drivers/edgetpu/rio/config.h7
23 files changed, 869 insertions, 496 deletions
diff --git a/drivers/edgetpu/Kbuild b/drivers/edgetpu/Kbuild
index 292d42a..85e400b 100644
--- a/drivers/edgetpu/Kbuild
+++ b/drivers/edgetpu/Kbuild
@@ -13,9 +13,7 @@ endif
GCIP_DIR=gcip-kernel-driver/drivers/gcip
-gcip-objs := $(GCIP_DIR)/gcip-firmware.o $(GCIP_DIR)/gcip-kci.o $(GCIP_DIR)/gcip-mailbox.o $(GCIP_DIR)/gcip-mem-pool.o
-
-edgetpu-objs := edgetpu-mailbox.o edgetpu-kci.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o edgetpu-firmware.o edgetpu-firmware-util.o edgetpu-domain-pool.o $(gcip-objs)
+edgetpu-objs := edgetpu-mailbox.o edgetpu-kci.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o edgetpu-firmware.o edgetpu-firmware-util.o edgetpu-domain-pool.o $(GCIP_DIR)/gcip.o
rio-y := rio-device.o rio-device-group.o rio-fs.o rio-core.o rio-platform.o rio-firmware.o rio-thermal.o rio-pm.o rio-debug-dump.o rio-usage-stats.o rio-iommu.o rio-wakelock.o rio-external.o rio-soc.o $(edgetpu-objs)
@@ -33,3 +31,5 @@ CFLAGS_rio-usage-stats.o := -DCONFIG_RIO=1
CFLAGS_rio-wakelock.o := -DCONFIG_RIO=1
CFLAGS_rio-external.o := -DCONFIG_RIO=1
CFLAGS_rio-soc.o := -DCONFIG_RIO=1
+
+
diff --git a/drivers/edgetpu/Makefile b/drivers/edgetpu/Makefile
index acd14bd..27ca3a1 100644
--- a/drivers/edgetpu/Makefile
+++ b/drivers/edgetpu/Makefile
@@ -27,10 +27,19 @@ rio-objs := rio-core.o rio-debug-dump.o rio-device-group.o rio-device.o \
rio-thermal.o rio-usage-stats.o rio-wakelock.o rio-external.o \
rio-soc.o $(edgetpu-objs)
+
ccflags-y += -I$(KERNEL_SRC)/../private/google-modules/edgetpu/rio/drivers/edgetpu/include
KBUILD_OPTIONS += CONFIG_RIO=m
include $(KERNEL_SRC)/../private/google-modules/soc/gs/Makefile.include
-modules modules_install clean:
+GCIP_DIR=gcip-kernel-driver/drivers/gcip
+
+modules modules_install:
+ $(MAKE) -C $(KERNEL_SRC) M=$(M)/$(GCIP_DIR) W=1 gcip.o
+ $(MAKE) -C $(KERNEL_SRC) M=$(M) W=1 $(KBUILD_OPTIONS) \
+ EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" $(@)
+clean:
+ $(MAKE) -C $(KERNEL_SRC) M=$(M)/$(GCIP_DIR) W=1 \
+ EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" $(@)
$(MAKE) -C $(KERNEL_SRC) M=$(M) W=1 $(KBUILD_OPTIONS) \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" $(@)
diff --git a/drivers/edgetpu/edgetpu-config.h b/drivers/edgetpu/edgetpu-config.h
index 9aa87bb..c496a33 100644
--- a/drivers/edgetpu/edgetpu-config.h
+++ b/drivers/edgetpu/edgetpu-config.h
@@ -25,6 +25,10 @@
#define EDGETPU_NUM_CORES 1
#endif
+#ifndef EDGETPU_NUM_SSMTS
+#define EDGETPU_NUM_SSMTS 1
+#endif
+
/* Uses a smaller size for unittests to avoid DMA warnings. */
#if IS_ENABLED(CONFIG_EDGETPU_TEST)
#undef EDGETPU_DEBUG_DUMP_MEM_SIZE
diff --git a/drivers/edgetpu/edgetpu-core.c b/drivers/edgetpu/edgetpu-core.c
index 0aa4fd0..dc8ba6c 100644
--- a/drivers/edgetpu/edgetpu-core.c
+++ b/drivers/edgetpu/edgetpu-core.c
@@ -446,9 +446,17 @@ int edgetpu_device_add(struct edgetpu_dev *etdev,
etdev->dev_name, ret);
goto remove_dev;
}
+
+ /* Init PM in case the platform needs power up actions before MMU setup and such. */
+ ret = edgetpu_chip_pm_create(etdev);
+ if (ret) {
+ etdev_err(etdev, "Failed to initialize PM interface: %d", ret);
+ goto remove_mboxes;
+ }
+
ret = edgetpu_chip_setup_mmu(etdev);
if (ret)
- goto remove_dev;
+ goto remove_mboxes;
edgetpu_usage_stats_init(etdev);
@@ -481,6 +489,8 @@ int edgetpu_device_add(struct edgetpu_dev *etdev,
remove_usage_stats:
edgetpu_usage_stats_exit(etdev);
edgetpu_chip_remove_mmu(etdev);
+remove_mboxes:
+ edgetpu_mailbox_remove_all(etdev->mailbox_manager);
remove_dev:
edgetpu_mark_probe_fail(etdev);
edgetpu_fs_remove(etdev);
diff --git a/drivers/edgetpu/edgetpu-internal.h b/drivers/edgetpu/edgetpu-internal.h
index a8f6423..a9260e7 100644
--- a/drivers/edgetpu/edgetpu-internal.h
+++ b/drivers/edgetpu/edgetpu-internal.h
@@ -170,6 +170,7 @@ struct edgetpu_dev {
struct device *dev; /* platform/pci bus device */
uint num_ifaces; /* Number of device interfaces */
uint num_cores; /* Number of cores */
+ uint num_ssmts; /* Number of SSMTs */
/*
* Array of device interfaces
* First element is the default interface
@@ -405,14 +406,6 @@ int edgetpu_chip_setup_mmu(struct edgetpu_dev *etdev);
*/
void edgetpu_chip_remove_mmu(struct edgetpu_dev *etdev);
-/*
- * Handle chip-specific incoming requests from firmware over KCI
- * Note: This will get called from the system's work queue.
- * Code should not block for extended periods of time
- */
-void edgetpu_chip_handle_reverse_kci(struct edgetpu_dev *etdev,
- struct gcip_kci_response_element *resp);
-
/* Device -> Core API */
/* Add current thread as new TPU client */
diff --git a/drivers/edgetpu/edgetpu-kci.c b/drivers/edgetpu/edgetpu-kci.c
index 18dc690..16e4a97 100644
--- a/drivers/edgetpu/edgetpu-kci.c
+++ b/drivers/edgetpu/edgetpu-kci.c
@@ -20,6 +20,7 @@
#include "edgetpu-iremap-pool.h"
#include "edgetpu-kci.h"
#include "edgetpu-mmu.h"
+#include "edgetpu-soc.h"
#include "edgetpu-telemetry.h"
#include "edgetpu-usage-stats.h"
@@ -145,7 +146,7 @@ static void edgetpu_reverse_kci_handle_response(struct gcip_kci *kci,
struct edgetpu_dev *etdev = mailbox->etdev;
if (resp->code <= GCIP_RKCI_CHIP_CODE_LAST) {
- edgetpu_chip_handle_reverse_kci(etdev, resp);
+ edgetpu_soc_handle_reverse_kci(etdev, resp);
return;
}
diff --git a/drivers/edgetpu/edgetpu-mapping.h b/drivers/edgetpu/edgetpu-mapping.h
index ae42a3a..65547bc 100644
--- a/drivers/edgetpu/edgetpu-mapping.h
+++ b/drivers/edgetpu/edgetpu-mapping.h
@@ -160,11 +160,8 @@ static inline int mmu_flag_to_iommu_prot(u32 mmu_flags, struct device *dev,
{
int prot = 0;
- if (mmu_flags & EDGETPU_MMU_COHERENT) {
-#ifdef EDGETPU_IS_DMA_COHERENT
+ if (mmu_flags & EDGETPU_MMU_COHERENT)
prot = IOMMU_CACHE;
-#endif
- }
prot |= __dma_dir_to_iommu_prot(dir);
return prot;
}
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.c b/drivers/edgetpu/edgetpu-mobile-platform.c
index 735afdb..ce7e75c 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.c
+++ b/drivers/edgetpu/edgetpu-mobile-platform.c
@@ -18,6 +18,7 @@
#include "edgetpu-iremap-pool.h"
#include "edgetpu-mmu.h"
#include "edgetpu-mobile-platform.h"
+#include "edgetpu-soc.h"
#include "edgetpu-telemetry.h"
#include "mobile-firmware.h"
#include "mobile-pm.h"
@@ -220,29 +221,6 @@ void edgetpu_chip_remove_mmu(struct edgetpu_dev *etdev)
edgetpu_mmu_detach(etdev);
}
-static int edgetpu_platform_parse_ssmt(struct edgetpu_mobile_platform_dev *etmdev)
-{
- struct edgetpu_dev *etdev = &etmdev->edgetpu_dev;
- struct platform_device *pdev = to_platform_device(etdev->dev);
- struct resource *res;
- int ret;
- void __iomem *ssmt_base;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ssmt");
- if (!res) {
- etdev_warn(etdev, "Failed to find SSMT register base");
- return -EINVAL;
- }
- ssmt_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ssmt_base)) {
- ret = PTR_ERR(ssmt_base);
- etdev_warn(etdev, "Failed to map SSMT register base: %d", ret);
- return ret;
- }
- etmdev->ssmt_base = ssmt_base;
- return 0;
-}
-
static int edgetpu_platform_setup_irq(struct edgetpu_mobile_platform_dev *etmdev)
{
struct edgetpu_dev *etdev = &etmdev->edgetpu_dev;
@@ -331,6 +309,7 @@ static int edgetpu_mobile_platform_probe(struct platform_device *pdev,
platform_set_drvdata(pdev, etdev);
etdev->dev = dev;
etdev->num_cores = EDGETPU_NUM_CORES;
+ etdev->num_ssmts = EDGETPU_NUM_SSMTS;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (IS_ERR_OR_NULL(r)) {
@@ -346,15 +325,11 @@ static int edgetpu_mobile_platform_probe(struct platform_device *pdev,
return -ENODEV;
}
+ edgetpu_soc_init(etdev);
+
mutex_init(&etmdev->platform_pwr.policy_lock);
etmdev->platform_pwr.curr_policy = TPU_POLICY_MAX;
- ret = edgetpu_chip_pm_create(etdev);
- if (ret) {
- dev_err(dev, "Failed to initialize PM interface: %d", ret);
- return ret;
- }
-
ret = edgetpu_platform_setup_fw_region(etmdev);
if (ret) {
dev_err(dev, "setup fw regions failed: %d", ret);
@@ -391,10 +366,6 @@ static int edgetpu_mobile_platform_probe(struct platform_device *pdev,
goto out_remove_device;
}
- ret = edgetpu_platform_parse_ssmt(etmdev);
- if (ret)
- dev_warn(dev, "SSMT setup failed (%d). Context isolation not enforced", ret);
-
etmdev->log_mem = devm_kcalloc(dev, etdev->num_cores, sizeof(*etmdev->log_mem), GFP_KERNEL);
if (!etmdev->log_mem) {
ret = -ENOMEM;
@@ -469,6 +440,6 @@ static int edgetpu_mobile_platform_remove(struct platform_device *pdev)
edgetpu_platform_cleanup_fw_region(etmdev);
edgetpu_pm_put(etdev->pm);
edgetpu_pm_shutdown(etdev, true);
- mobile_pm_destroy(etdev);
+ edgetpu_mobile_pm_destroy(etdev);
return 0;
}
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.h b/drivers/edgetpu/edgetpu-mobile-platform.h
index 3aa0104..afdaa9d 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.h
+++ b/drivers/edgetpu/edgetpu-mobile-platform.h
@@ -80,7 +80,7 @@ struct edgetpu_mobile_platform_dev {
*/
struct device *gsa_dev;
/* Virtual address of the SSMT block for this chip. */
- void __iomem *ssmt_base;
+ void __iomem **ssmt_base;
/* Coherent log buffer */
struct edgetpu_coherent_mem *log_mem;
/* Coherent trace buffer */
diff --git a/drivers/edgetpu/edgetpu-pm.h b/drivers/edgetpu/edgetpu-pm.h
index 96e4a4d..4acdb45 100644
--- a/drivers/edgetpu/edgetpu-pm.h
+++ b/drivers/edgetpu/edgetpu-pm.h
@@ -72,6 +72,12 @@ void edgetpu_pm_put(struct edgetpu_pm *etpm);
int edgetpu_pm_create(struct edgetpu_dev *etdev,
const struct edgetpu_pm_handlers *handlers);
+/*
+ * Wrapper for chip-specific implementation.
+ * Typically calls mobile_pm_create after initializing the platform_pwr struct.
+ */
+int edgetpu_chip_pm_create(struct edgetpu_dev *etdev);
+
/* Destroy the power management interface associated with an edgetpu device */
void edgetpu_pm_destroy(struct edgetpu_dev *etdev);
diff --git a/drivers/edgetpu/edgetpu-soc.h b/drivers/edgetpu/edgetpu-soc.h
index 31083a4..5e87676 100644
--- a/drivers/edgetpu/edgetpu-soc.h
+++ b/drivers/edgetpu/edgetpu-soc.h
@@ -11,10 +11,14 @@
#include <linux/types.h>
#include "edgetpu-internal.h"
+#include "edgetpu-kci.h"
#include "edgetpu-thermal.h"
/* SoC-specific calls for the following functions. */
+/* Probe-time init */
+void edgetpu_soc_init(struct edgetpu_dev *etdev);
+
/* Prep for running firmware: set access control, etc. */
int edgetpu_soc_prepare_firmware(struct edgetpu_dev *etdev);
@@ -30,6 +34,23 @@ int edgetpu_soc_pm_set_init_freq(unsigned long freq);
/* Set PM policy */
int edgetpu_soc_pm_set_policy(u64 val);
+/* Power down */
+void edgetpu_soc_pm_power_down(struct edgetpu_dev *etdev);
+
+/* Init SoC PM system */
+int edgetpu_soc_pm_init(struct edgetpu_dev *etdev);
+
+/* De-init SoC PM system */
+void edgetpu_soc_pm_exit(struct edgetpu_dev *etdev);
+
+/*
+ * Handle Reverse KCI commands for SoC family.
+ * Note: This will get called from the system's work queue.
+ * Code should not block for extended periods of time
+ */
+void edgetpu_soc_handle_reverse_kci(struct edgetpu_dev *etdev,
+ struct gcip_kci_response_element *resp);
+
/* Init thermal subsystem SoC specifics for TPU */
void edgetpu_soc_thermal_init(struct edgetpu_thermal *thermal);
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/Makefile b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/Makefile
index 3056519..1b988e4 100644
--- a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/Makefile
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/Makefile
@@ -6,7 +6,7 @@
CONFIG_GCIP ?= m
obj-$(CONFIG_GCIP) += gcip.o
-gcip-objs := gcip-firmware.o gcip-kci.o gcip-mailbox.o gcip-mem-pool.o
+gcip-objs := gcip-firmware.o gcip-image-config.o gcip-kci.o gcip-mailbox.o gcip-mem-pool.o
CURRENT_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-image-config.c b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-image-config.c
new file mode 100644
index 0000000..af082b6
--- /dev/null
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-image-config.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Framework for parsing the firmware image configuration.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <gcip/gcip-image-config.h>
+
+#define SIZE_MASK 0xfff
+
+/* used by iommu_mappings */
+#define CONFIG_TO_SIZE(a) ((1U << ((a) & SIZE_MASK)) << 12)
+
+/* used by ns_iommu_mappings */
+#define CONFIG_TO_MBSIZE(a) (((a) & SIZE_MASK) << 20)
+
+static int setup_iommu_mappings(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ int i, ret;
+ dma_addr_t daddr;
+ size_t size;
+ phys_addr_t paddr;
+
+ for (i = 0; i < config->num_iommu_mappings; i++) {
+ daddr = config->iommu_mappings[i].virt_address;
+ if (unlikely(!daddr)) {
+ dev_warn(parser->dev, "Invalid config, device address is zero");
+ ret = -EIO;
+ goto err;
+ }
+ size = CONFIG_TO_SIZE(config->iommu_mappings[i].image_config_value);
+ paddr = config->iommu_mappings[i].image_config_value & ~SIZE_MASK;
+
+ dev_dbg(parser->dev, "Image config adding IOMMU mapping: %#llx -> %#llx", daddr,
+ paddr);
+
+ if (unlikely(daddr + size <= daddr || paddr + size <= paddr)) {
+ ret = -EOVERFLOW;
+ goto err;
+ }
+ ret = parser->ops->map(parser->data, daddr, paddr, size,
+ GCIP_IMAGE_CONFIG_FLAGS_SECURE);
+ if (ret) {
+ dev_err(parser->dev,
+ "Unable to Map: %d dma_addr: %#llx phys_addr: %#llx size: %#lx\n",
+ ret, daddr, paddr, size);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ while (i--) {
+ daddr = config->iommu_mappings[i].virt_address;
+ size = CONFIG_TO_SIZE(config->iommu_mappings[i].image_config_value);
+ parser->ops->unmap(parser->data, daddr, size, GCIP_IMAGE_CONFIG_FLAGS_SECURE);
+ }
+ return ret;
+}
+
+static void clear_iommu_mappings(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ dma_addr_t daddr;
+ size_t size;
+ int i;
+
+ for (i = config->num_iommu_mappings - 1; i >= 0; i--) {
+ daddr = config->iommu_mappings[i].virt_address;
+ size = CONFIG_TO_SIZE(config->iommu_mappings[i].image_config_value);
+ dev_dbg(parser->dev, "Image config removing IOMMU mapping: %#llx size=%#lx", daddr,
+ size);
+ parser->ops->unmap(parser->data, daddr, size, GCIP_IMAGE_CONFIG_FLAGS_SECURE);
+ }
+}
+
+static int setup_ns_iommu_mappings(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ dma_addr_t daddr;
+ size_t size;
+ int ret, i;
+ phys_addr_t paddr = 0;
+
+ for (i = 0; i < config->num_ns_iommu_mappings; i++) {
+ daddr = config->ns_iommu_mappings[i] & ~SIZE_MASK;
+ if (unlikely(!daddr)) {
+ dev_warn(parser->dev, "Invalid config, device address is zero");
+ ret = -EIO;
+ goto err;
+ }
+ size = CONFIG_TO_MBSIZE(config->ns_iommu_mappings[i]);
+ dev_dbg(parser->dev, "Image config adding NS IOMMU mapping: %#llx -> %#llx", daddr,
+ paddr);
+ if (unlikely(daddr + size <= daddr || paddr + size <= paddr)) {
+ ret = -EOVERFLOW;
+ goto err;
+ }
+ ret = parser->ops->map(parser->data, daddr, paddr, size, 0);
+ if (ret)
+ goto err;
+ paddr += size;
+ }
+
+ return 0;
+
+err:
+ while (i--) {
+ size = CONFIG_TO_MBSIZE(config->ns_iommu_mappings[i]);
+ daddr = config->ns_iommu_mappings[i] & ~SIZE_MASK;
+ parser->ops->unmap(parser->data, daddr, size, 0);
+ }
+ return ret;
+}
+
+static void clear_ns_iommu_mappings(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ dma_addr_t daddr;
+ size_t size;
+ int i;
+
+ for (i = config->num_ns_iommu_mappings - 1; i >= 0; i--) {
+ size = CONFIG_TO_MBSIZE(config->ns_iommu_mappings[i]);
+ daddr = config->ns_iommu_mappings[i] & ~SIZE_MASK;
+ dev_dbg(parser->dev, "Image config removing NS IOMMU mapping: %#llx size=%#lx",
+ daddr, size);
+ parser->ops->unmap(parser->data, daddr, size, 0);
+ }
+}
+
+static int map_image_config(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ int ret = setup_ns_iommu_mappings(parser, config);
+
+ if (ret)
+ return ret;
+ if (gcip_image_config_is_ns(config)) {
+ ret = setup_iommu_mappings(parser, config);
+ if (ret)
+ clear_ns_iommu_mappings(parser, config);
+ }
+ return ret;
+}
+
+static void unmap_image_config(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ if (gcip_image_config_is_ns(config))
+ clear_iommu_mappings(parser, config);
+ clear_ns_iommu_mappings(parser, config);
+}
+
+int gcip_image_config_parser_init(struct gcip_image_config_parser *parser,
+ const struct gcip_image_config_ops *ops, struct device *dev,
+ void *data)
+{
+ if (!ops->map || !ops->unmap) {
+ dev_err(dev, "Missing mandatory operations for image config parser");
+ return -EINVAL;
+ }
+ parser->dev = dev;
+ parser->data = data;
+ parser->ops = ops;
+ memset(&parser->last_config, 0, sizeof(parser->last_config));
+ return 0;
+}
+
+int gcip_image_config_parse(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config)
+{
+ int ret;
+
+ if (!memcmp(config, &parser->last_config, sizeof(*config)))
+ return 0;
+ unmap_image_config(parser, &parser->last_config);
+ ret = map_image_config(parser, config);
+ if (ret) {
+ dev_err(parser->dev, "Map image config failed: %d", ret);
+ /*
+ * Weird case as the mappings in the last config were just removed - might happen
+ * if the IOMMU driver state is corrupted. We can't help to rescue it so let's
+ * simply log a message.
+ */
+ if (unlikely(map_image_config(parser, &parser->last_config)))
+ dev_err(parser->dev, "Failed to roll back the last image config");
+ return ret;
+ }
+ memcpy(&parser->last_config, config, sizeof(parser->last_config));
+ return 0;
+}
+
+void gcip_image_config_clear(struct gcip_image_config_parser *parser)
+{
+ unmap_image_config(parser, &parser->last_config);
+ memset(&parser->last_config, 0, sizeof(parser->last_config));
+}
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-image-config.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-image-config.h
new file mode 100644
index 0000000..6c3333e
--- /dev/null
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-image-config.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Framework for parsing the firmware image configuration.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+
+#ifndef __GCIP_IMAGE_CONFIG_H__
+#define __GCIP_IMAGE_CONFIG_H__
+
+#include <linux/types.h>
+
+#define GCIP_FW_NUM_VERSIONS 4
+#define GCIP_IMG_CFG_MAX_IOMMU_MAPPINGS 23
+#define GCIP_IMG_CFG_MAX_NS_IOMMU_MAPPINGS 5
+
+#define GCIP_FW_PRIV_LEVEL_GSA 0
+#define GCIP_FW_PRIV_LEVEL_TZ 1
+#define GCIP_FW_PRIV_LEVEL_NS 2
+
+/*
+ * The image configuration attached to the signed firmware.
+ */
+struct gcip_image_config {
+ __u32 carveout_base;
+ __u32 firmware_base;
+ __u32 firmware_size;
+ __u32 firmware_versions[GCIP_FW_NUM_VERSIONS];
+ __u32 config_version;
+ __u32 privilege_level;
+ __u32 remapped_region_start;
+ __u32 remapped_region_size;
+ __u32 num_iommu_mappings;
+ struct {
+ /* Device virtual address */
+ __u32 virt_address;
+ /*
+ * contains a 12-bit aligned address and a page-order size into a
+ * 32-bit value i.e. a physical address and size in page order.
+ */
+ __u32 image_config_value;
+ } iommu_mappings[GCIP_IMG_CFG_MAX_IOMMU_MAPPINGS];
+ __u32 num_ns_iommu_mappings;
+ __u32 ns_iommu_mappings[GCIP_IMG_CFG_MAX_NS_IOMMU_MAPPINGS];
+} __packed;
+
+#define GCIP_IMAGE_CONFIG_FLAGS_SECURE (1u << 0)
+
+struct gcip_image_config_ops {
+ /*
+ * Adds an IOMMU mapping from @daddr to @paddr with size @size.
+ *
+ * It is ensured that there is no overflow on @paddr + @size before calling this function.
+ *
+ * @flags is a bit-field with the following attributes:
+ * [0:0] - Security. 1 for secure and 0 for non-secure.
+ * [31:1] - Reserved.
+ *
+ * Returns 0 on success. Otherwise a negative errno.
+ * Mandatory.
+ */
+ int (*map)(void *data, dma_addr_t daddr, phys_addr_t paddr, size_t size,
+ unsigned int flags);
+ /*
+ * Removes the IOMMU mapping previously added by @map.
+ *
+ * Mandatory.
+ */
+ void (*unmap)(void *data, dma_addr_t daddr, size_t size, unsigned int flags);
+};
+
+struct gcip_image_config_parser {
+ struct device *dev;
+ void *data; /* User-specify data, will be passed to ops. */
+ const struct gcip_image_config_ops *ops;
+ /* The last image config being successfully parsed. */
+ struct gcip_image_config last_config;
+};
+
+/*
+ * Initializes the image configuration parser.
+ *
+ * @dev is only used for logging.
+ * @data will be passed to operations.
+ *
+ * Returns 0 on success. Returns -EINVAL when any mandatory operations is NULL.
+ */
+int gcip_image_config_parser_init(struct gcip_image_config_parser *parser,
+ const struct gcip_image_config_ops *ops, struct device *dev,
+ void *data);
+
+/*
+ * Parses the image configuration and adds specified IOMMU mappings by calling pre-registered
+ * operations.
+ *
+ * Number of mappings to be added might be different according to the value of
+ * @config->privilege_level:
+ * - GCIP_FW_PRIV_LEVEL_NS:
+ * Both @iommu_mappings and @ns_iommu_mappings will be added. Because GCIP_FW_PRIV_LEVEL_NS means
+ * the firmware will run in non-secure mode and all transactions will go through the non-secure
+ * IOMMU.
+ * - Otherwise:
+ * Only @ns_iommu_mappings are considered. TZ/GSA will be the one who programs secure IOMMU for
+ * those secure IOMMU mappings.
+ *
+ * Before parsing the newly passed @config, the mappings of the last record (stored by @parser
+ * internally) will be reverted. If there is any mapping in the new config fails to be mapped, the
+ * reverted last config will be reverted again. i.e. This function will keep the mapping state the
+ * same as before calling it on any error happens. But if the IOMMU state is somehow corrupted and
+ * hence fails to roll back the reverted last image config, only an error is logged. See the pseudo
+ * code below:
+ *
+ * gcip_image_config_parse(config):
+ * unmap(last_image_config)
+ * if ret = map(config) fails:
+ * LOG("Failed to map image config, rolling back to the last image config.")
+ * if map(last_image_config) fails:
+ * LOG("Failed to roll back the last image config.")
+ * return ret
+ * else:
+ * last_image_config = config
+ * return SUCCESS
+ *
+ * A special case being considered is if the content of @config is identical to the last
+ * successfully parsed image config, this function will return 0 immediately without removing /
+ * adding any mapping.
+ *
+ * Returns 0 on success. Otherwise an errno, which usually would be the one returned by
+ * gcip_image_config_ops.map. On error no new mapping specified in @config is added.
+ */
+int gcip_image_config_parse(struct gcip_image_config_parser *parser,
+ struct gcip_image_config *config);
+
+/*
+ * Clears the mappings specified in the last image config.
+ *
+ * It's valid to call this function without any image config has been successfully parsed, or when
+ * the last image config is already cleared. In which case this function works as no-op.
+ */
+void gcip_image_config_clear(struct gcip_image_config_parser *parser);
+
+/*
+ * Returns whether the privilege level specified by @config is non-secure.
+ */
+static inline bool gcip_image_config_is_ns(struct gcip_image_config *config)
+{
+ return config->privilege_level == GCIP_FW_PRIV_LEVEL_NS;
+}
+
+#endif /* __GCIP_IMAGE_CONFIG_H__ */
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
index 1f54938..71a1e27 100644
--- a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#define CIRC_QUEUE_WRAPPED(idx, wrap_bit) ((idx)&wrap_bit)
#define CIRC_QUEUE_INDEX_MASK(wrap_bit) (wrap_bit - 1)
diff --git a/drivers/edgetpu/include/soc/google/bcl.h b/drivers/edgetpu/include/soc/google/bcl.h
deleted file mode 100644
index 506982c..0000000
--- a/drivers/edgetpu/include/soc/google/bcl.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __BCL_H__
-#define __BCL_H__
-
-struct gs101_bcl_dev;
-
-static inline unsigned int gs101_get_mpmm(struct gs101_bcl_dev *data)
-{
- return 0;
-}
-static inline unsigned int gs101_get_ppm(struct gs101_bcl_dev *data)
-{
- return 0;
-}
-static inline int gs101_set_ppm(struct gs101_bcl_dev *data, unsigned int value)
-{
- return 0;
-}
-static inline int gs101_set_mpmm(struct gs101_bcl_dev *data, unsigned int value)
-{
- return 0;
-}
-static inline struct gs101_bcl_dev *gs101_retrieve_bcl_handle(void)
-{
- return NULL;
-}
-static inline int gs101_init_gpu_ratio(struct gs101_bcl_dev *data)
-{
- return 0;
-}
-static inline int gs101_init_tpu_ratio(struct gs101_bcl_dev *data)
-{
- return 0;
-}
-
-#endif /* __BCL_H__ */
diff --git a/drivers/edgetpu/mobile-pm.c b/drivers/edgetpu/mobile-pm.c
index 5b6c979..d145c0c 100644
--- a/drivers/edgetpu/mobile-pm.c
+++ b/drivers/edgetpu/mobile-pm.c
@@ -11,8 +11,6 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <soc/google/bcl.h>
-#include <soc/google/bts.h>
-#include <soc/google/exynos_pm_qos.h>
#include "edgetpu-config.h"
#include "edgetpu-firmware.h"
@@ -27,20 +25,10 @@
#include "edgetpu-pm.c"
#include "edgetpu-soc.h"
-/*
- * Encode INT/MIF values as a 16 bit pair in the 32-bit return value
- * (in units of MHz, to provide enough range)
- */
-#define PM_QOS_INT_SHIFT (16)
-#define PM_QOS_MIF_MASK (0xFFFF)
-#define PM_QOS_FACTOR (1000)
-
static int power_state = TPU_DEFAULT_POWER_STATE;
module_param(power_state, int, 0660);
-#define MAX_VOLTAGE_VAL 1250000
-
enum edgetpu_pwr_state edgetpu_active_states[EDGETPU_NUM_STATES] = {
TPU_ACTIVE_UUD,
TPU_ACTIVE_SUD,
@@ -50,11 +38,6 @@ enum edgetpu_pwr_state edgetpu_active_states[EDGETPU_NUM_STATES] = {
uint32_t *edgetpu_states_display = edgetpu_active_states;
-/* TODO(b/240363978): Remove once ACPM is ready. */
-#if !IS_ENABLED(CONFIG_EDGETPU_TEST)
-unsigned long exynos_acpm_rate = 0;
-#endif /* IS_ENABLED(CONFIG_EDGETPU_TEST) */
-
static int mobile_pwr_state_init(struct device *dev)
{
int ret;
@@ -83,139 +66,6 @@ static int mobile_pwr_state_init(struct device *dev)
return ret;
}
-static int edgetpu_core_rate_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_CORE_DEBUG);
- return 0;
-}
-
-static int edgetpu_core_rate_set(void *data, u64 val)
-{
- unsigned long dbg_rate_req;
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_CORE_DEBUG;
- dbg_rate_req |= val;
-
- return edgetpu_soc_pm_set_rate(dbg_rate_req);
-}
-
-static int edgetpu_ctl_rate_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_CTL_DEBUG);
- return 0;
-}
-
-static int edgetpu_ctl_rate_set(void *data, u64 val)
-{
- unsigned long dbg_rate_req;
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_CTL_DEBUG;
- dbg_rate_req |= 1000;
-
- return edgetpu_soc_pm_set_rate(dbg_rate_req);
-}
-
-static int edgetpu_axi_rate_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_AXI_DEBUG);
- return 0;
-}
-
-static int edgetpu_axi_rate_set(void *data, u64 val)
-{
- unsigned long dbg_rate_req;
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_AXI_DEBUG;
- dbg_rate_req |= 1000;
-
- return edgetpu_soc_pm_set_rate(dbg_rate_req);
-}
-
-static int edgetpu_apb_rate_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_APB_DEBUG);
- return 0;
-}
-
-static int edgetpu_uart_rate_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_UART_DEBUG);
- return 0;
-}
-
-static int edgetpu_vdd_int_m_set(void *data, u64 val)
-{
- struct device *dev = (struct device *)data;
- unsigned long dbg_rate_req;
-
- if (val > MAX_VOLTAGE_VAL) {
- dev_err(dev, "Preventing INT_M voltage > %duV",
- MAX_VOLTAGE_VAL);
- return -EINVAL;
- }
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_INT_M_DEBUG;
- dbg_rate_req |= val;
-
- return edgetpu_soc_pm_set_rate(dbg_rate_req);
-}
-
-static int edgetpu_vdd_int_m_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_INT_M_DEBUG);
- return 0;
-}
-
-static int edgetpu_vdd_tpu_set(void *data, u64 val)
-{
- int ret;
- struct device *dev = (struct device *)data;
- unsigned long dbg_rate_req;
-
- if (val > MAX_VOLTAGE_VAL) {
- dev_err(dev, "Preventing VDD_TPU voltage > %duV",
- MAX_VOLTAGE_VAL);
- return -EINVAL;
- }
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_TPU_DEBUG;
- dbg_rate_req |= val;
-
- ret = edgetpu_soc_pm_set_rate(dbg_rate_req);
- return ret;
-}
-
-static int edgetpu_vdd_tpu_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_TPU_DEBUG);
- return 0;
-}
-
-static int edgetpu_vdd_tpu_m_set(void *data, u64 val)
-{
- int ret;
- struct device *dev = (struct device *)data;
- unsigned long dbg_rate_req;
-
- if (val > MAX_VOLTAGE_VAL) {
- dev_err(dev, "Preventing VDD_TPU voltage > %duV",
- MAX_VOLTAGE_VAL);
- return -EINVAL;
- }
-
- dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_TPU_M_DEBUG;
- dbg_rate_req |= val;
-
- ret = edgetpu_soc_pm_set_rate(dbg_rate_req);
- return ret;
-}
-
-static int edgetpu_vdd_tpu_m_get(void *data, u64 *val)
-{
- *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_TPU_M_DEBUG);
- return 0;
-}
-
static int mobile_pwr_state_set_locked(struct edgetpu_mobile_platform_dev *etmdev, u64 val)
{
int ret;
@@ -366,29 +216,6 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_pwr_state, mobile_pwr_state_get, mobile_pwr_st
DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_min_pwr_state, mobile_min_pwr_state_get, mobile_min_pwr_state_set,
"%llu\n");
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_core_rate, edgetpu_core_rate_get,
- edgetpu_core_rate_set, "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_ctl_rate, edgetpu_ctl_rate_get,
- edgetpu_ctl_rate_set, "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_axi_rate, edgetpu_axi_rate_get,
- edgetpu_axi_rate_set, "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_apb_rate, edgetpu_apb_rate_get, NULL,
- "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_uart_rate, edgetpu_uart_rate_get, NULL,
- "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_int_m, edgetpu_vdd_int_m_get,
- edgetpu_vdd_int_m_set, "%llu\n");
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_tpu, edgetpu_vdd_tpu_get,
- edgetpu_vdd_tpu_set, "%llu\n");
-DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_tpu_m, edgetpu_vdd_tpu_m_get,
- edgetpu_vdd_tpu_m_set, "%llu\n");
-
static int mobile_get_initial_pwr_state(struct device *dev)
{
switch (power_state) {
@@ -484,30 +311,6 @@ static int mobile_power_up(struct edgetpu_pm *etpm)
return ret;
}
-static void mobile_pm_cleanup_bts_scenario(struct edgetpu_dev *etdev)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
- int performance_scenario = platform_pwr->performance_scenario;
-
- if (!performance_scenario)
- return;
-
- mutex_lock(&platform_pwr->scenario_lock);
- while (platform_pwr->scenario_count) {
- int ret = bts_del_scenario(performance_scenario);
-
- if (ret) {
- platform_pwr->scenario_count = 0;
- etdev_warn_once(etdev, "error %d in cleaning up BTS scenario %u\n", ret,
- performance_scenario);
- break;
- }
- platform_pwr->scenario_count--;
- }
- mutex_unlock(&platform_pwr->scenario_lock);
-}
-
static void mobile_firmware_down(struct edgetpu_dev *etdev)
{
int ret = edgetpu_kci_shutdown(etdev->etkci);
@@ -569,11 +372,7 @@ static int mobile_power_down(struct edgetpu_pm *etpm)
mobile_pwr_state_set(etdev, TPU_OFF);
- /* Remove our vote for INT/MIF state (if any) */
- exynos_pm_qos_update_request(&platform_pwr->int_min, 0);
- exynos_pm_qos_update_request(&platform_pwr->mif_min, 0);
-
- mobile_pm_cleanup_bts_scenario(etdev);
+ edgetpu_soc_pm_power_down(etdev);
/*
* It should be impossible that power_down() is called when secure_client is set.
@@ -602,14 +401,6 @@ static int mobile_pm_after_create(struct edgetpu_pm *etpm)
mutex_init(&platform_pwr->state_lock);
mutex_init(&platform_pwr->scenario_lock);
- exynos_pm_qos_add_request(&platform_pwr->int_min, PM_QOS_DEVICE_THROUGHPUT, 0);
- exynos_pm_qos_add_request(&platform_pwr->mif_min, PM_QOS_BUS_THROUGHPUT, 0);
-
- platform_pwr->performance_scenario = bts_get_scenindex("tpu_performance");
- if (!platform_pwr->performance_scenario)
- dev_warn(etdev->dev, "tpu_performance BTS scenario not found\n");
- platform_pwr->scenario_count = 0;
-
ret = mobile_pwr_state_set(etdev, mobile_get_initial_pwr_state(dev));
if (ret)
return ret;
@@ -623,14 +414,7 @@ static int mobile_pm_after_create(struct edgetpu_pm *etpm)
debugfs_create_file("min_state", 0660, platform_pwr->debugfs_dir, etdev,
&fops_tpu_min_pwr_state);
debugfs_create_file("policy", 0660, platform_pwr->debugfs_dir, etdev, &fops_tpu_pwr_policy);
- debugfs_create_file("vdd_tpu", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_tpu);
- debugfs_create_file("vdd_tpu_m", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_tpu_m);
- debugfs_create_file("vdd_int_m", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_int_m);
- debugfs_create_file("core_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_core_rate);
- debugfs_create_file("ctl_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_ctl_rate);
- debugfs_create_file("axi_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_axi_rate);
- debugfs_create_file("apb_rate", 0440, platform_pwr->debugfs_dir, dev, &fops_tpu_apb_rate);
- debugfs_create_file("uart_rate", 0440, platform_pwr->debugfs_dir, dev, &fops_tpu_uart_rate);
+ edgetpu_soc_pm_init(etdev);
if (platform_pwr->after_create)
ret = platform_pwr->after_create(etdev);
@@ -649,9 +433,7 @@ static void mobile_pm_before_destroy(struct edgetpu_pm *etpm)
debugfs_remove_recursive(platform_pwr->debugfs_dir);
pm_runtime_disable(etpm->etdev->dev);
- mobile_pm_cleanup_bts_scenario(etdev);
- exynos_pm_qos_remove_request(&platform_pwr->int_min);
- exynos_pm_qos_remove_request(&platform_pwr->mif_min);
+ edgetpu_soc_pm_exit(etdev);
}
static struct edgetpu_pm_handlers mobile_pm_handlers = {
@@ -661,92 +443,12 @@ static struct edgetpu_pm_handlers mobile_pm_handlers = {
.power_down = mobile_power_down,
};
-int mobile_pm_create(struct edgetpu_dev *etdev)
+int edgetpu_mobile_pm_create(struct edgetpu_dev *etdev)
{
return edgetpu_pm_create(etdev, &mobile_pm_handlers);
}
-void mobile_pm_destroy(struct edgetpu_dev *etdev)
+void edgetpu_mobile_pm_destroy(struct edgetpu_dev *etdev)
{
edgetpu_pm_destroy(etdev);
}
-
-void mobile_pm_set_pm_qos(struct edgetpu_dev *etdev, u32 pm_qos_val)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
- s32 int_val = (pm_qos_val >> PM_QOS_INT_SHIFT) * PM_QOS_FACTOR;
- s32 mif_val = (pm_qos_val & PM_QOS_MIF_MASK) * PM_QOS_FACTOR;
-
- etdev_dbg(etdev, "%s: pm_qos request - int = %d mif = %d\n", __func__, int_val, mif_val);
-
- exynos_pm_qos_update_request(&platform_pwr->int_min, int_val);
- exynos_pm_qos_update_request(&platform_pwr->mif_min, mif_val);
-}
-
-static void mobile_pm_activate_bts_scenario(struct edgetpu_dev *etdev)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
- int performance_scenario = platform_pwr->performance_scenario;
-
- /* bts_add_scenario() keeps track of reference count internally.*/
- int ret;
-
- if (!performance_scenario)
- return;
- mutex_lock(&platform_pwr->scenario_lock);
- ret = bts_add_scenario(performance_scenario);
- if (ret)
- etdev_warn_once(etdev, "error %d adding BTS scenario %u\n", ret,
- performance_scenario);
- else
- platform_pwr->scenario_count++;
-
- etdev_dbg(etdev, "BTS Scenario activated: %d\n", platform_pwr->scenario_count);
- mutex_unlock(&platform_pwr->scenario_lock);
-}
-
-static void mobile_pm_deactivate_bts_scenario(struct edgetpu_dev *etdev)
-{
- /* bts_del_scenario() keeps track of reference count internally.*/
- int ret;
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
- int performance_scenario = platform_pwr->performance_scenario;
-
- if (!performance_scenario)
- return;
- mutex_lock(&platform_pwr->scenario_lock);
- if (!platform_pwr->scenario_count) {
- etdev_warn(etdev, "Unbalanced bts deactivate\n");
- mutex_unlock(&platform_pwr->scenario_lock);
- return;
- }
- ret = bts_del_scenario(performance_scenario);
- if (ret)
- etdev_warn_once(etdev, "error %d deleting BTS scenario %u\n", ret,
- performance_scenario);
- else
- platform_pwr->scenario_count--;
-
- etdev_dbg(etdev, "BTS Scenario deactivated: %d\n", platform_pwr->scenario_count);
- mutex_unlock(&platform_pwr->scenario_lock);
-}
-
-void mobile_pm_set_bts(struct edgetpu_dev *etdev, u16 bts_val)
-{
- etdev_dbg(etdev, "%s: bts request - val = %u\n", __func__, bts_val);
-
- switch (bts_val) {
- case 0:
- mobile_pm_deactivate_bts_scenario(etdev);
- break;
- case 1:
- mobile_pm_activate_bts_scenario(etdev);
- break;
- default:
- etdev_warn(etdev, "%s: invalid BTS request value: %u\n", __func__, bts_val);
- break;
- }
-}
diff --git a/drivers/edgetpu/mobile-pm.h b/drivers/edgetpu/mobile-pm.h
index 5f487bc..b9b86b4 100644
--- a/drivers/edgetpu/mobile-pm.h
+++ b/drivers/edgetpu/mobile-pm.h
@@ -9,55 +9,17 @@
#define __MOBILE_PM_H__
#include "edgetpu-internal.h"
-#include "edgetpu-kci.h"
-
-/*
- * Request codes from firmware
- * Values must match with firmware code base
- */
-enum mobile_reverse_kci_code {
- RKCI_CODE_PM_QOS = GCIP_RKCI_CHIP_CODE_FIRST + 1,
- RKCI_CODE_BTS = GCIP_RKCI_CHIP_CODE_FIRST + 2,
- /* The above codes have been deprecated. */
-
- RKCI_CODE_PM_QOS_BTS = GCIP_RKCI_CHIP_CODE_FIRST + 3,
-};
-
-#define MAX_VOLTAGE_VAL 1250000
-#define TPU_DEBUG_REQ (1 << 31)
-#define TPU_VDD_TPU_DEBUG (0 << 27)
-#define TPU_VDD_TPU_M_DEBUG (1 << 27)
-#define TPU_VDD_INT_M_DEBUG (2 << 27)
-#define TPU_CLK_CORE_DEBUG (3 << 27)
-#define TPU_CLK_CTL_DEBUG (4 << 27)
-#define TPU_CLK_AXI_DEBUG (5 << 27)
-#define TPU_CLK_APB_DEBUG (6 << 27)
-#define TPU_CLK_UART_DEBUG (7 << 27)
-#define TPU_CORE_PWR_DEBUG (8 << 27)
-#define TPU_DEBUG_VALUE_MASK ((1 << 27) - 1)
/*
* Initialize a power management interface for an edgetpu device on mobile
* chipsets.
* Needs to be called after the devices's platform_pwr struct has been initialized.
*/
-int mobile_pm_create(struct edgetpu_dev *etdev);
-
-/*
- * Wrapper for chip-specific implementation.
- * Typically calls mobile_pm_create after initializing the platform_pwr struct.
- */
-int edgetpu_chip_pm_create(struct edgetpu_dev *etdev);
+int edgetpu_mobile_pm_create(struct edgetpu_dev *etdev);
/*
* Destroy power management interface for an edgetpu device on mobile chipsets.
*/
-void mobile_pm_destroy(struct edgetpu_dev *etdev);
-
-/* Set required QoS value for the edgetpu device. */
-void mobile_pm_set_pm_qos(struct edgetpu_dev *etdev, u32 pm_qos_val);
-
-/* Set BTS value for the edgetpu device. */
-void mobile_pm_set_bts(struct edgetpu_dev *etdev, u16 bts_val);
+void edgetpu_mobile_pm_destroy(struct edgetpu_dev *etdev);
#endif /* __MOBILE_PM_H__ */
diff --git a/drivers/edgetpu/mobile-soc-gsx01.c b/drivers/edgetpu/mobile-soc-gsx01.c
index a969f20..b37f618 100644
--- a/drivers/edgetpu/mobile-soc-gsx01.c
+++ b/drivers/edgetpu/mobile-soc-gsx01.c
@@ -8,63 +8,123 @@
#include <linux/acpm_dvfs.h>
#include <linux/device.h>
#include <linux/gsa/gsa_tpu.h>
+#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/types.h>
+#include <soc/google/bts.h>
+#include <soc/google/exynos_pm_qos.h>
#include <soc/google/gs_tmu.h>
#include "edgetpu-internal.h"
#include "edgetpu-firmware.h"
+#include "edgetpu-kci.h"
#include "edgetpu-mobile-platform.h"
#include "edgetpu-soc.h"
#include "edgetpu-thermal.h"
#include "mobile-firmware.h"
-
+#include "mobile-soc-gsx01.h"
/* TODO(b/199681752): check whether this domain is still correct for Rio */
#define TPU_ACPM_DOMAIN 7
-#define SSMT_NS_READ_STREAM_VID_OFFSET(n) (0x1000u + (0x4u * (n)))
-#define SSMT_NS_WRITE_STREAM_VID_OFFSET(n) (0x1200u + (0x4u * (n)))
+#define MAX_VOLTAGE_VAL 1250000
+
+#define TPU_DEBUG_REQ (1 << 31)
+
+#define TPU_DEBUG_VALUE_SHIFT (27)
+#define TPU_DEBUG_VALUE_MASK ((1 << TPU_DEBUG_VALUE_SHIFT) - 1)
+#define TPU_VDD_TPU_DEBUG (0 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_VDD_TPU_M_DEBUG (1 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_VDD_INT_M_DEBUG (2 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CLK_CORE_DEBUG (3 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CLK_CTL_DEBUG (4 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CLK_AXI_DEBUG (5 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CLK_APB_DEBUG (6 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CLK_UART_DEBUG (7 << TPU_DEBUG_VALUE_SHIFT)
+#define TPU_CORE_PWR_DEBUG (8 << TPU_DEBUG_VALUE_SHIFT)
+
+/*
+ * Encode INT/MIF values as a 16 bit pair in the 32-bit return value
+ * (in units of MHz, to provide enough range)
+ */
+#define PM_QOS_INT_SHIFT (16)
+#define PM_QOS_MIF_MASK (0xFFFF)
+#define PM_QOS_FACTOR (1000)
+
+#define SSMT_NS_READ_STREAM_VID_OFFSET(n) (0x1000u + (0x4u * (n)))
+#define SSMT_NS_WRITE_STREAM_VID_OFFSET(n) (0x1200u + (0x4u * (n)))
+
+#define SSMT_NS_READ_STREAM_VID_REG(base, n) ((base) + SSMT_NS_READ_STREAM_VID_OFFSET(n))
+#define SSMT_NS_WRITE_STREAM_VID_REG(base, n) ((base) + SSMT_NS_WRITE_STREAM_VID_OFFSET(n))
+
+#define SSMT_BYPASS (1 << 31)
+
+/* TODO(b/240363978): Remove once ACPM is ready. */
+#if !IS_ENABLED(CONFIG_EDGETPU_TEST)
+unsigned long exynos_acpm_rate = 0;
+#endif /* IS_ENABLED(CONFIG_EDGETPU_TEST) */
+
+static int gsx01_parse_ssmt(struct edgetpu_mobile_platform_dev *etmdev)
+{
+ struct edgetpu_dev *etdev = &etmdev->edgetpu_dev;
+ struct platform_device *pdev = to_platform_device(etdev->dev);
+ struct resource *res;
+ int ret, i;
+ void __iomem *ssmt_base;
+ char ssmt_name[] = "ssmt_d0";
+
+ etmdev->ssmt_base =
+ devm_kcalloc(etdev->dev, etdev->num_ssmts, sizeof(*etmdev->ssmt_base), GFP_KERNEL);
+
+ if (!etmdev->ssmt_base)
+ return -ENOMEM;
+
+ for (i = 0; i < etdev->num_ssmts; i++) {
+ sprintf(ssmt_name, "ssmt_d%d", i);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ssmt_name);
+ if (!res) {
+ etdev_warn(etdev, "Failed to find SSMT_D%d register base", i);
+ return -EINVAL;
+ }
+ ssmt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ssmt_base)) {
+ ret = PTR_ERR(ssmt_base);
+ etdev_warn(etdev, "Failed to map SSMT_D%d register base: %d", i, ret);
+ return ret;
+ }
+ etmdev->ssmt_base[i] = ssmt_base;
+ }
+
+ return 0;
+}
+
+void edgetpu_soc_init(struct edgetpu_dev *etdev)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ int ret;
-#define SSMT_NS_READ_STREAM_VID_REG(base, n) \
- ((base) + SSMT_NS_READ_STREAM_VID_OFFSET(n))
-#define SSMT_NS_WRITE_STREAM_VID_REG(base, n) \
- ((base) + SSMT_NS_WRITE_STREAM_VID_OFFSET(n))
+ ret = gsx01_parse_ssmt(etmdev);
+ if (ret)
+ dev_warn(etdev->dev, "SSMT setup failed (%d). Context isolation not enforced", ret);
+}
static void gsx01_setup_ssmt(struct edgetpu_dev *etdev)
{
- int i;
struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- struct mobile_image_config *image_config = mobile_firmware_get_image_config(etdev);
+ int i, j;
- /*
- * This only works if the SSMT is set to client-driven mode, which only GSA can do.
- * Skip if GSA is not available
- */
- if (!etmdev->ssmt_base || !etmdev->gsa_dev)
- return;
+ for (i = 0; i < etdev->num_ssmts; i++)
+ if (!etmdev->ssmt_base[i])
+ return;
- etdev_dbg(etdev, "Setting up SSMT for privilege level: %d\n",
- image_config->privilege_level);
-
- /*
- * Setup non-secure SCIDs, assume VID = SCID when running at TZ or GSA level,
- * Reset the table to zeroes if running non-secure firmware, since the SSMT
- * will be in clamped mode and we want all memory accesses to go to the
- * default page table.
- *
- * TODO(b/204384254) Confirm SSMT setup for Rio
- */
- for (i = 0; i < EDGETPU_NCONTEXTS; i++) {
- int val;
-
- if (image_config->privilege_level == FW_PRIV_LEVEL_NS)
- val = 0;
- else
- val = i;
-
- writel(val, SSMT_NS_READ_STREAM_VID_REG(etmdev->ssmt_base, i));
- writel(val, SSMT_NS_WRITE_STREAM_VID_REG(etmdev->ssmt_base, i));
+ for (i = 0; i < etdev->num_ssmts; i++) {
+ etdev_dbg(etdev, "Setting up SSMT_D%d to feed-through mode\n", i);
+
+ for (j = 0; j < EDGETPU_MAX_STREAM_ID; j++) {
+ writel(SSMT_BYPASS, SSMT_NS_READ_STREAM_VID_REG(etmdev->ssmt_base[i], j));
+ writel(SSMT_BYPASS, SSMT_NS_WRITE_STREAM_VID_REG(etmdev->ssmt_base[i], j));
+ }
}
}
@@ -74,6 +134,132 @@ int edgetpu_soc_prepare_firmware(struct edgetpu_dev *etdev)
return 0;
}
+static void gsx01_cleanup_bts_scenario(struct edgetpu_dev *etdev)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+ int performance_scenario = platform_pwr->performance_scenario;
+
+ if (!performance_scenario)
+ return;
+
+ mutex_lock(&platform_pwr->scenario_lock);
+ while (platform_pwr->scenario_count) {
+ int ret = bts_del_scenario(performance_scenario);
+
+ if (ret) {
+ platform_pwr->scenario_count = 0;
+ etdev_warn_once(etdev, "error %d in cleaning up BTS scenario %u\n", ret,
+ performance_scenario);
+ break;
+ }
+ platform_pwr->scenario_count--;
+ }
+ mutex_unlock(&platform_pwr->scenario_lock);
+}
+
+static void gsx01_activate_bts_scenario(struct edgetpu_dev *etdev)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+ int performance_scenario = platform_pwr->performance_scenario;
+
+ /* bts_add_scenario() keeps track of reference count internally.*/
+ int ret;
+
+ if (!performance_scenario)
+ return;
+ mutex_lock(&platform_pwr->scenario_lock);
+ ret = bts_add_scenario(performance_scenario);
+ if (ret)
+ etdev_warn_once(etdev, "error %d adding BTS scenario %u\n", ret,
+ performance_scenario);
+ else
+ platform_pwr->scenario_count++;
+
+ etdev_dbg(etdev, "BTS Scenario activated: %d\n", platform_pwr->scenario_count);
+ mutex_unlock(&platform_pwr->scenario_lock);
+}
+
+static void gsx01_deactivate_bts_scenario(struct edgetpu_dev *etdev)
+{
+ /* bts_del_scenario() keeps track of reference count internally.*/
+ int ret;
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+ int performance_scenario = platform_pwr->performance_scenario;
+
+ if (!performance_scenario)
+ return;
+ mutex_lock(&platform_pwr->scenario_lock);
+ if (!platform_pwr->scenario_count) {
+ etdev_warn(etdev, "Unbalanced bts deactivate\n");
+ mutex_unlock(&platform_pwr->scenario_lock);
+ return;
+ }
+ ret = bts_del_scenario(performance_scenario);
+ if (ret)
+ etdev_warn_once(etdev, "error %d deleting BTS scenario %u\n", ret,
+ performance_scenario);
+ else
+ platform_pwr->scenario_count--;
+
+ etdev_dbg(etdev, "BTS Scenario deactivated: %d\n", platform_pwr->scenario_count);
+ mutex_unlock(&platform_pwr->scenario_lock);
+}
+
+static void gsx01_set_bts(struct edgetpu_dev *etdev, u16 bts_val)
+{
+ etdev_dbg(etdev, "%s: bts request - val = %u\n", __func__, bts_val);
+
+ switch (bts_val) {
+ case 0:
+ gsx01_deactivate_bts_scenario(etdev);
+ break;
+ case 1:
+ gsx01_activate_bts_scenario(etdev);
+ break;
+ default:
+ etdev_warn(etdev, "%s: invalid BTS request value: %u\n", __func__, bts_val);
+ break;
+ }
+}
+
+static void gsx01_set_pm_qos(struct edgetpu_dev *etdev, u32 pm_qos_val)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+ s32 int_val = (pm_qos_val >> PM_QOS_INT_SHIFT) * PM_QOS_FACTOR;
+ s32 mif_val = (pm_qos_val & PM_QOS_MIF_MASK) * PM_QOS_FACTOR;
+
+ etdev_dbg(etdev, "%s: pm_qos request - int = %d mif = %d\n", __func__, int_val, mif_val);
+
+ exynos_pm_qos_update_request(&platform_pwr->int_min, int_val);
+ exynos_pm_qos_update_request(&platform_pwr->mif_min, mif_val);
+}
+
+void edgetpu_soc_handle_reverse_kci(struct edgetpu_dev *etdev,
+ struct gcip_kci_response_element *resp)
+{
+ int ret;
+
+ switch (resp->code) {
+ case RKCI_CODE_PM_QOS_BTS:
+ /* FW indicates to ignore the request by setting them to undefined values. */
+ if (resp->retval != (typeof(resp->retval))~0ull)
+ gsx01_set_pm_qos(etdev, resp->retval);
+ if (resp->status != (typeof(resp->status))~0ull)
+ gsx01_set_bts(etdev, resp->status);
+ ret = edgetpu_kci_resp_rkci_ack(etdev, resp);
+ if (ret)
+ etdev_err(etdev, "failed to send rkci resp for %llu (%d)", resp->seq, ret);
+ break;
+ default:
+ etdev_warn(etdev, "%s: Unrecognized KCI request: %u\n", __func__, resp->code);
+ break;
+ }
+}
+
long edgetpu_soc_pm_get_rate(int flags)
{
return exynos_acpm_get_rate(TPU_ACPM_DOMAIN, flags);
@@ -94,6 +280,195 @@ int edgetpu_soc_pm_set_policy(u64 val)
return exynos_acpm_set_policy(TPU_ACPM_DOMAIN, val);
}
+static int edgetpu_core_rate_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_CORE_DEBUG);
+ return 0;
+}
+
+static int edgetpu_core_rate_set(void *data, u64 val)
+{
+ unsigned long dbg_rate_req;
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_CORE_DEBUG;
+ dbg_rate_req |= val;
+
+ return edgetpu_soc_pm_set_rate(dbg_rate_req);
+}
+
+static int edgetpu_ctl_rate_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_CTL_DEBUG);
+ return 0;
+}
+
+static int edgetpu_ctl_rate_set(void *data, u64 val)
+{
+ unsigned long dbg_rate_req;
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_CTL_DEBUG;
+ dbg_rate_req |= 1000;
+
+ return edgetpu_soc_pm_set_rate(dbg_rate_req);
+}
+
+static int edgetpu_axi_rate_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_AXI_DEBUG);
+ return 0;
+}
+
+static int edgetpu_axi_rate_set(void *data, u64 val)
+{
+ unsigned long dbg_rate_req;
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_CLK_AXI_DEBUG;
+ dbg_rate_req |= 1000;
+
+ return edgetpu_soc_pm_set_rate(dbg_rate_req);
+}
+
+static int edgetpu_apb_rate_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_APB_DEBUG);
+ return 0;
+}
+
+static int edgetpu_uart_rate_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_CLK_UART_DEBUG);
+ return 0;
+}
+
+static int edgetpu_vdd_int_m_set(void *data, u64 val)
+{
+ struct device *dev = (struct device *)data;
+ unsigned long dbg_rate_req;
+
+ if (val > MAX_VOLTAGE_VAL) {
+ dev_err(dev, "Preventing INT_M voltage > %duV", MAX_VOLTAGE_VAL);
+ return -EINVAL;
+ }
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_INT_M_DEBUG;
+ dbg_rate_req |= val;
+
+ return edgetpu_soc_pm_set_rate(dbg_rate_req);
+}
+
+static int edgetpu_vdd_int_m_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_INT_M_DEBUG);
+ return 0;
+}
+
+static int edgetpu_vdd_tpu_set(void *data, u64 val)
+{
+ int ret;
+ struct device *dev = (struct device *)data;
+ unsigned long dbg_rate_req;
+
+ if (val > MAX_VOLTAGE_VAL) {
+ dev_err(dev, "Preventing VDD_TPU voltage > %duV", MAX_VOLTAGE_VAL);
+ return -EINVAL;
+ }
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_TPU_DEBUG;
+ dbg_rate_req |= val;
+
+ ret = edgetpu_soc_pm_set_rate(dbg_rate_req);
+ return ret;
+}
+
+static int edgetpu_vdd_tpu_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_TPU_DEBUG);
+ return 0;
+}
+
+static int edgetpu_vdd_tpu_m_set(void *data, u64 val)
+{
+ int ret;
+ struct device *dev = (struct device *)data;
+ unsigned long dbg_rate_req;
+
+ if (val > MAX_VOLTAGE_VAL) {
+ dev_err(dev, "Preventing VDD_TPU voltage > %duV", MAX_VOLTAGE_VAL);
+ return -EINVAL;
+ }
+
+ dbg_rate_req = TPU_DEBUG_REQ | TPU_VDD_TPU_M_DEBUG;
+ dbg_rate_req |= val;
+
+ ret = edgetpu_soc_pm_set_rate(dbg_rate_req);
+ return ret;
+}
+
+static int edgetpu_vdd_tpu_m_get(void *data, u64 *val)
+{
+ *val = edgetpu_soc_pm_get_rate(TPU_DEBUG_REQ | TPU_VDD_TPU_M_DEBUG);
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_core_rate, edgetpu_core_rate_get, edgetpu_core_rate_set,
+ "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_ctl_rate, edgetpu_ctl_rate_get, edgetpu_ctl_rate_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_axi_rate, edgetpu_axi_rate_get, edgetpu_axi_rate_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_apb_rate, edgetpu_apb_rate_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_uart_rate, edgetpu_uart_rate_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_int_m, edgetpu_vdd_int_m_get, edgetpu_vdd_int_m_set,
+ "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_tpu, edgetpu_vdd_tpu_get, edgetpu_vdd_tpu_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_vdd_tpu_m, edgetpu_vdd_tpu_m_get, edgetpu_vdd_tpu_m_set,
+ "%llu\n");
+
+void edgetpu_soc_pm_power_down(struct edgetpu_dev *etdev)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+
+ /* Remove our vote for INT/MIF state (if any) */
+ exynos_pm_qos_update_request(&platform_pwr->int_min, 0);
+ exynos_pm_qos_update_request(&platform_pwr->mif_min, 0);
+
+ gsx01_cleanup_bts_scenario(etdev);
+}
+
+int edgetpu_soc_pm_init(struct edgetpu_dev *etdev)
+{
+ struct device *dev = etdev->dev;
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+
+ exynos_pm_qos_add_request(&platform_pwr->int_min, PM_QOS_DEVICE_THROUGHPUT, 0);
+ exynos_pm_qos_add_request(&platform_pwr->mif_min, PM_QOS_BUS_THROUGHPUT, 0);
+
+ platform_pwr->performance_scenario = bts_get_scenindex("tpu_performance");
+ if (!platform_pwr->performance_scenario)
+ dev_warn(etdev->dev, "tpu_performance BTS scenario not found\n");
+ platform_pwr->scenario_count = 0;
+
+ debugfs_create_file("vdd_tpu", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_tpu);
+ debugfs_create_file("vdd_tpu_m", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_tpu_m);
+ debugfs_create_file("vdd_int_m", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_vdd_int_m);
+ debugfs_create_file("core_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_core_rate);
+ debugfs_create_file("ctl_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_ctl_rate);
+ debugfs_create_file("axi_rate", 0660, platform_pwr->debugfs_dir, dev, &fops_tpu_axi_rate);
+ debugfs_create_file("apb_rate", 0440, platform_pwr->debugfs_dir, dev, &fops_tpu_apb_rate);
+ debugfs_create_file("uart_rate", 0440, platform_pwr->debugfs_dir, dev, &fops_tpu_uart_rate);
+ return 0;
+}
+
+void edgetpu_soc_pm_exit(struct edgetpu_dev *etdev)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;
+
+ gsx01_cleanup_bts_scenario(etdev);
+ exynos_pm_qos_remove_request(&platform_pwr->int_min);
+ exynos_pm_qos_remove_request(&platform_pwr->mif_min);
+}
+
static int tpu_pause_callback(enum thermal_pause_state action, void *dev)
{
int ret = -EINVAL;
diff --git a/drivers/edgetpu/mobile-soc-gsx01.h b/drivers/edgetpu/mobile-soc-gsx01.h
new file mode 100644
index 0000000..5e56dca
--- /dev/null
+++ b/drivers/edgetpu/mobile-soc-gsx01.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Definitions for GSx01 SoCs.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+
+#ifndef __MOBILE_SOC_GSX01_H__
+#define __MOBILE_SOC_GSX01_H__
+
+/*
+ * Request codes from firmware
+ * Values must match with firmware code base
+ */
+enum gsx01_reverse_kci_code {
+ RKCI_CODE_PM_QOS = GCIP_RKCI_CHIP_CODE_FIRST + 1,
+ RKCI_CODE_BTS = GCIP_RKCI_CHIP_CODE_FIRST + 2,
+ /* The above codes have been deprecated. */
+
+ RKCI_CODE_PM_QOS_BTS = GCIP_RKCI_CHIP_CODE_FIRST + 3,
+};
+
+#endif /* __MOBILE_SOC_GSX01_H__ */
diff --git a/drivers/edgetpu/rio-device.c b/drivers/edgetpu/rio-device.c
index 984e76a..bf9e1be 100644
--- a/drivers/edgetpu/rio-device.c
+++ b/drivers/edgetpu/rio-device.c
@@ -67,28 +67,6 @@ void edgetpu_mark_probe_fail(struct edgetpu_dev *etdev)
{
}
-void edgetpu_chip_handle_reverse_kci(struct edgetpu_dev *etdev,
- struct gcip_kci_response_element *resp)
-{
- int ret;
-
- switch (resp->code) {
- case RKCI_CODE_PM_QOS_BTS:
- /* FW indicates to ignore the request by setting them to undefined values. */
- if (resp->retval != (typeof(resp->retval))~0ull)
- mobile_pm_set_pm_qos(etdev, resp->retval);
- if (resp->status != (typeof(resp->status))~0ull)
- mobile_pm_set_bts(etdev, resp->status);
- ret = edgetpu_kci_resp_rkci_ack(etdev, resp);
- if (ret)
- etdev_err(etdev, "failed to send rkci resp for %llu (%d)", resp->seq, ret);
- break;
- default:
- etdev_warn(etdev, "%s: Unrecognized KCI request: %u\n", __func__, resp->code);
- break;
- }
-}
-
int edgetpu_chip_get_ext_mailbox_index(u32 mbox_type, u32 *start, u32 *end)
{
switch (mbox_type) {
diff --git a/drivers/edgetpu/rio-pm.c b/drivers/edgetpu/rio-pm.c
index 28fadb1..aab8fa5 100644
--- a/drivers/edgetpu/rio-pm.c
+++ b/drivers/edgetpu/rio-pm.c
@@ -168,5 +168,5 @@ int edgetpu_chip_pm_create(struct edgetpu_dev *etdev)
platform_pwr->lpm_down = rio_lpm_down;
platform_pwr->block_down = rio_block_down;
- return mobile_pm_create(etdev);
+ return edgetpu_mobile_pm_create(etdev);
}
diff --git a/drivers/edgetpu/rio/config.h b/drivers/edgetpu/rio/config.h
index 12eec6f..d358953 100644
--- a/drivers/edgetpu/rio/config.h
+++ b/drivers/edgetpu/rio/config.h
@@ -12,6 +12,10 @@
#define EDGETPU_NUM_CORES 2
+#define EDGETPU_NUM_SSMTS 2
+
+#define EDGETPU_MAX_STREAM_ID 64
+
/* 1 context per VII/group plus 1 for KCI */
#define EDGETPU_NCONTEXTS 16
/* Max number of virtual context IDs that can be allocated for one device. */
@@ -22,9 +26,6 @@
/* Placeholder value */
#define EDGETPU_TZ_MAILBOX_ID 31
-/* Responds to PMQoS-BTS RKCI */
-#define EDGETPU_FEATURE_RKCI_RESPONSE
-
/*
* Size of the area in remapped DRAM reserved for firmware code and internal
* data. This must match the firmware's linker file.