diff options
author | Tianyu Jiang <tianyuj@google.com> | 2022-02-02 14:25:28 -0800 |
---|---|---|
committer | Tianyu Jiang <tianyuj@google.com> | 2022-02-08 13:42:27 -0800 |
commit | 798cbc8256fef2aba93fd98345f020fe5ca7bfd1 (patch) | |
tree | b9d01d97c43eb51d23d22982bfc9eb5065ccf974 /platform | |
parent | 6df5fae118e967fc99c70f986820c252d242f96e (diff) | |
download | lwis-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.c | 304 | ||||
-rw-r--r-- | platform/casablanca/lwis_platform_casablanca.h | 22 | ||||
-rw-r--r-- | platform/casablanca/lwis_platform_casablanca_dma.c | 64 |
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; +} |