summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorTianyu Jiang <tianyuj@google.com>2022-02-02 14:25:28 -0800
committerTianyu Jiang <tianyuj@google.com>2022-02-08 13:42:27 -0800
commit798cbc8256fef2aba93fd98345f020fe5ca7bfd1 (patch)
treeb9d01d97c43eb51d23d22982bfc9eb5065ccf974 /platform
parent6df5fae118e967fc99c70f986820c252d242f96e (diff)
downloadlwis-798cbc8256fef2aba93fd98345f020fe5ca7bfd1.tar.gz
Add lwis casablanca module
copy the platform/anchorage files to platform/casablanca folder with minor changes to correct the names Commented out pm_qos function calls as is not supported currently. Bug: 202049395 Test: Build Signed-off-by: Tianyu Jiang <tianyuj@google.com> Change-Id: I5832e2075441c7810c317ceb5a68f2e2c9a37a73
Diffstat (limited to 'platform')
-rw-r--r--platform/casablanca/lwis_platform_casablanca.c304
-rw-r--r--platform/casablanca/lwis_platform_casablanca.h22
-rw-r--r--platform/casablanca/lwis_platform_casablanca_dma.c64
3 files changed, 390 insertions, 0 deletions
diff --git a/platform/casablanca/lwis_platform_casablanca.c b/platform/casablanca/lwis_platform_casablanca.c
new file mode 100644
index 0000000..f8d1e4c
--- /dev/null
+++ b/platform/casablanca/lwis_platform_casablanca.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Google LWIS Casablanca Platform-Specific Functions
+ *
+ * Copyright (c) 2022 Google, LLC
+ */
+
+#include "lwis_platform_casablanca.h"
+
+#include <linux/iommu.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <soc/google/bts.h>
+
+#include "lwis_commands.h"
+#include "lwis_device_dpm.h"
+#include "lwis_debug.h"
+#include "lwis_platform.h"
+
+/* Uncomment to let kernel panic when IOMMU hits a page fault. */
+/* #define ENABLE_PAGE_FAULT_PANIC */
+
+int lwis_platform_probe(struct lwis_device *lwis_dev)
+{
+ struct lwis_platform *platform;
+
+ if (!lwis_dev)
+ return -ENODEV;
+
+ platform = kzalloc(sizeof(*platform), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(platform))
+ return -ENOMEM;
+ lwis_dev->platform = platform;
+
+ /* Enable runtime power management for the platform device */
+ pm_runtime_enable(&lwis_dev->plat_dev->dev);
+
+ lwis_dev->bts_index = BTS_UNSUPPORTED;
+ /* Only IOREG devices will access DMA resources */
+ if (lwis_dev->type != DEVICE_TYPE_IOREG)
+ return 0;
+ /* Register to bts */
+ lwis_dev->bts_index = bts_get_bwindex(lwis_dev->name);
+ if (lwis_dev->bts_index < 0)
+ dev_err(lwis_dev->dev, "Failed to register to BTS, ret: %d\n", lwis_dev->bts_index);
+ lwis_dev->bts_index = BTS_UNSUPPORTED;
+
+ return 0;
+}
+
+static int lwis_iommu_fault_handler(struct iommu_fault *fault, void *param)
+{
+ struct lwis_device *lwis_dev = (struct lwis_device *)param;
+ struct lwis_mem_page_fault_event_payload event_payload;
+
+ pr_err("############ LWIS IOMMU PAGE FAULT ############\n");
+ pr_err("\n");
+ pr_err("Device: %s IOMMU Page Fault at Address: %p Flag: 0x%08x\n", lwis_dev->name,
+ (void *)fault->event.addr, fault->event.flags);
+ pr_err("\n");
+ lwis_debug_print_transaction_info(lwis_dev);
+ pr_err("\n");
+ lwis_debug_print_event_states_info(lwis_dev);
+ pr_err("\n");
+ lwis_debug_print_buffer_info(lwis_dev);
+ pr_err("\n");
+ pr_err("###############################################\n");
+
+ event_payload.fault_address = fault->event.addr;
+ event_payload.fault_flags = fault->event.flags;
+ lwis_device_error_event_emit(lwis_dev, LWIS_ERROR_EVENT_ID_MEMORY_PAGE_FAULT,
+ &event_payload, sizeof(event_payload));
+
+#ifdef ENABLE_PAGE_FAULT_PANIC
+ return -EFAULT;
+#else
+ return -EAGAIN;
+#endif /* ENABLE_PAGE_FAULT_PANIC */
+}
+
+int lwis_platform_device_enable(struct lwis_device *lwis_dev)
+{
+ int ret;
+ struct lwis_platform *platform;
+
+ const int core_clock_qos = 67000;
+ /* const int hpg_qos = 1; */
+
+ if (!lwis_dev)
+ return -ENODEV;
+
+ platform = lwis_dev->platform;
+ if (!platform)
+ return -ENODEV;
+
+ /* Upref the runtime power management controls for the platform dev */
+ ret = pm_runtime_get_sync(&lwis_dev->plat_dev->dev);
+ if (ret < 0) {
+ pr_err("Unable to enable platform device\n");
+ return ret;
+ }
+
+ if (lwis_dev->has_iommu) {
+ /* Activate IOMMU for the platform device */
+ ret = iommu_register_device_fault_handler(&lwis_dev->plat_dev->dev,
+ lwis_iommu_fault_handler, lwis_dev);
+ if (ret < 0) {
+ pr_err("Failed to register fault handler for the device: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /*
+ * PM_QOS_CPU_ONLINE_MIN is not defined in 5.4 branch, will need to
+ * revisit and see if a replacement is needed.
+ *
+ * // Set hardcoded DVFS levels
+ * if (!exynos_pm_qos_request_active(&platform->pm_qos_hpg)) {
+ * exynos_pm_qos_add_request(&platform->pm_qos_hpg,
+ * PM_QOS_CPU_ONLINE_MIN, hpg_qos);
+ * }
+ */
+
+ if (lwis_dev->clock_family != CLOCK_FAMILY_INVALID &&
+ lwis_dev->clock_family < NUM_CLOCK_FAMILY) {
+ ret = lwis_platform_update_qos(lwis_dev, core_clock_qos, lwis_dev->clock_family);
+ if (ret < 0) {
+ dev_err(lwis_dev->dev, "Failed to enable core clock\n");
+ return ret;
+ }
+ /* TODO(b/173493818): We currently see some stability issue on specific device
+ * and sensor due to INT clock vote to 100 MHz. Set the minimum INT requirement
+ * to 200Mhz for now.
+ */
+ ret = lwis_platform_update_qos(lwis_dev, 200000, CLOCK_FAMILY_INT);
+ if (ret < 0) {
+ dev_err(lwis_dev->dev, "Failed to initial INT clock\n");
+ return ret;
+ }
+ }
+
+ if (lwis_dev->bts_scenario_name) {
+ lwis_dev->bts_scenario = bts_get_scenindex(lwis_dev->bts_scenario_name);
+ if (!lwis_dev->bts_scenario) {
+ dev_err(lwis_dev->dev, "Failed to get default camera BTS scenario.\n");
+ return -EINVAL;
+ }
+ bts_add_scenario(lwis_dev->bts_scenario);
+ }
+ return 0;
+}
+
+int lwis_platform_device_disable(struct lwis_device *lwis_dev)
+{
+ struct lwis_platform *platform;
+
+ if (!lwis_dev)
+ return -ENODEV;
+
+ platform = lwis_dev->platform;
+ if (!platform)
+ return -ENODEV;
+
+ if (lwis_dev->bts_scenario_name)
+ bts_del_scenario(lwis_dev->bts_scenario);
+
+ /* We can't remove fault handlers, so there's no call corresponding
+ * to the iommu_register_device_fault_handler above
+ */
+
+ lwis_platform_remove_qos(lwis_dev);
+
+ if (lwis_dev->has_iommu) {
+ /* Deactivate IOMMU */
+ iommu_unregister_device_fault_handler(&lwis_dev->plat_dev->dev);
+ }
+
+ /* Disable platform device */
+ return pm_runtime_put_sync(&lwis_dev->plat_dev->dev);
+}
+
+int lwis_platform_update_qos(struct lwis_device *lwis_dev, int value,
+ int32_t clock_family)
+{
+ struct lwis_platform *platform;
+ struct exynos_pm_qos_request *qos_req;
+ int qos_class;
+
+ if (!lwis_dev)
+ return -ENODEV;
+
+ platform = lwis_dev->platform;
+ if (!platform)
+ return -ENODEV;
+
+ switch (clock_family) {
+ case CLOCK_FAMILY_INTCAM:
+ qos_req = &platform->pm_qos_int_cam;
+ qos_class = PM_QOS_INTCAM_THROUGHPUT;
+ break;
+ case CLOCK_FAMILY_CAM:
+ qos_req = &platform->pm_qos_cam;
+ qos_class = PM_QOS_CAM_THROUGHPUT;
+ break;
+ case CLOCK_FAMILY_TNR:
+ qos_req = &platform->pm_qos_tnr;
+ qos_class = PM_QOS_TNR_THROUGHPUT;
+ break;
+ case CLOCK_FAMILY_MIF:
+ qos_req = &platform->pm_qos_mem;
+ qos_class = PM_QOS_BUS_THROUGHPUT;
+ break;
+ case CLOCK_FAMILY_INT:
+ qos_req = &platform->pm_qos_int;
+ qos_class = PM_QOS_DEVICE_THROUGHPUT;
+ break;
+ default:
+ dev_err(lwis_dev->dev, "%s clk family %d is invalid\n", lwis_dev->name,
+ lwis_dev->clock_family);
+ return -EINVAL;
+ }
+ /* Should uncomment this block once pm_qos is supported.
+ * if (!exynos_pm_qos_request_active(qos_req))
+ * exynos_pm_qos_add_request(qos_req, qos_class, value);
+ * else
+ * exynos_pm_qos_update_request(qos_req, value);
+ */
+
+ dev_info(lwis_dev->dev, "Updating clock for clock_family %d, freq to %u\n", clock_family,
+ value);
+
+ return 0;
+}
+
+int lwis_platform_remove_qos(struct lwis_device *lwis_dev)
+{
+ struct lwis_platform *platform;
+
+ if (!lwis_dev)
+ return -ENODEV;
+
+ platform = lwis_dev->platform;
+ if (!platform)
+ return -ENODEV;
+ /* Should uncomment this block once pm_qos is supported.
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_int))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_int);
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_mem))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_mem);
+ */
+
+ /*
+ * pm_qos_hpg is not being used, see comments above regarding
+ * PM_QOS_CPU_ONLINE_MIN
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_hpg))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_hpg);
+ */
+
+ /* Should uncomment this block once pm_qos is supported.
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_int_cam))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_int_cam);
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_cam))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_cam);
+ * if (exynos_pm_qos_request_active(&platform->pm_qos_tnr))
+ * exynos_pm_qos_remove_request(&platform->pm_qos_tnr);
+ */
+ return 0;
+}
+
+int lwis_platform_update_bts(struct lwis_device *lwis_dev, unsigned int bw_kb_peak,
+ unsigned int bw_kb_read, unsigned int bw_kb_write,
+ unsigned int bw_kb_rt)
+{
+ int ret = 0;
+ struct bts_bw bts_request;
+
+ if (lwis_dev->bts_index == BTS_UNSUPPORTED) {
+ dev_info(lwis_dev->dev, "%s doesn't support bts\n", lwis_dev->name);
+ return ret;
+ }
+
+ bts_request.peak = bw_kb_peak;
+ bts_request.read = bw_kb_read;
+ bts_request.write = bw_kb_write;
+ bts_request.rt = bw_kb_rt;
+ ret = bts_update_bw(lwis_dev->bts_index, bts_request);
+ if (ret < 0) {
+ dev_err(lwis_dev->dev, "Failed to update bandwidth to bts, ret: %d\n", ret);
+ } else {
+ dev_info(lwis_dev->dev,
+ "Updated bandwidth to bts for device %s: peak: %u, read: %u, write: %u, rt: %u\n",
+ lwis_dev->name, bw_kb_peak, bw_kb_read, bw_kb_write, bw_kb_rt);
+ }
+ return ret;
+}
+
+int lwis_plaform_set_default_irq_affinity(unsigned int irq)
+{
+ const int cpu = 0x2;
+
+ return irq_set_affinity_hint(irq, cpumask_of(cpu));
+}
diff --git a/platform/casablanca/lwis_platform_casablanca.h b/platform/casablanca/lwis_platform_casablanca.h
new file mode 100644
index 0000000..c354451
--- /dev/null
+++ b/platform/casablanca/lwis_platform_casablanca.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Google LWIS Casablanca Platform-Specific Functions
+ *
+ * Copyright (c) 2022 Google, LLC
+ */
+
+#ifndef LWIS_PLATFORM_CASABLANCA_H_
+#define LWIS_PLATFORM_CASABLANCA_H_
+
+#include <soc/google/exynos_pm_qos.h>
+
+struct lwis_platform {
+ struct exynos_pm_qos_request pm_qos_int_cam;
+ struct exynos_pm_qos_request pm_qos_int;
+ struct exynos_pm_qos_request pm_qos_cam;
+ struct exynos_pm_qos_request pm_qos_mem;
+ struct exynos_pm_qos_request pm_qos_tnr;
+ /* struct exynos_pm_qos_request pm_qos_hpg; */
+};
+
+#endif /* LWIS_PLATFORM_CASABLANCA_H_ */
diff --git a/platform/casablanca/lwis_platform_casablanca_dma.c b/platform/casablanca/lwis_platform_casablanca_dma.c
new file mode 100644
index 0000000..1173f5a
--- /dev/null
+++ b/platform/casablanca/lwis_platform_casablanca_dma.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Google LWIS Casablanca Platform-Specific DMA Functions
+ *
+ * Copyright (c) 2022 Google, LLC
+ */
+
+#include <linux/slab.h>
+
+#include <linux/dma-buf.h>
+#include <linux/dma-heap.h>
+#include "lwis_commands.h"
+#include "lwis_init.h"
+#include "lwis_platform.h"
+#include "lwis_platform_dma.h"
+struct dma_buf *lwis_platform_dma_buffer_alloc(size_t len, unsigned int flags)
+{
+ const char *heap_name;
+ struct dma_heap *heap;
+ struct dma_buf *dmabuf;
+
+ if ((flags & LWIS_DMA_BUFFER_SECURE) && IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION))
+ heap_name = "farawimg-secure";
+ else if (flags & LWIS_DMA_BUFFER_CACHED)
+ heap_name = "system";
+ else
+ heap_name = "system-uncached";
+
+ heap = dma_heap_find(heap_name);
+ if (!heap) {
+ pr_err("Could not find %s DMA-BUF heap\n", heap_name);
+ return NULL;
+ }
+
+ dmabuf = dma_heap_buffer_alloc(heap, len, O_RDWR, 0);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ pr_err("DMA-BUF heap failed to alloc %#zx bytes. Error code %ld\n",
+ len, PTR_ERR(dmabuf));
+ dmabuf = NULL;
+ }
+
+ dma_heap_put(heap);
+
+ return dmabuf;
+}
+
+dma_addr_t lwis_platform_dma_buffer_map(struct lwis_device *lwis_dev,
+ struct lwis_enrolled_buffer *lwis_buffer, off_t offset,
+ size_t size, int flags)
+{
+ return sg_dma_address(lwis_buffer->sg_table->sgl);
+}
+
+/*
+ * We don't ever do dma_buf_vmap before. Instead, use the upstream dma-buf
+ * interface to map ION buffers, so we don't need to do dma_buf_vunmap.
+ * Keep this function by default return 0
+ */
+int lwis_platform_dma_buffer_unmap(struct lwis_device *lwis_dev,
+ struct dma_buf_attachment *attachment, dma_addr_t address)
+{
+ return 0;
+}