diff options
author | Anusha Shakarad <ashaka@codeaurora.org> | 2019-03-11 13:38:18 +0530 |
---|---|---|
committer | Anusha Shakarad <ashaka@codeaurora.org> | 2019-03-11 14:45:37 +0530 |
commit | a9ec0eb5213125786dbb980a44194d7754a56cdf (patch) | |
tree | 6169679c401442372b22491892d1f50bfb6e504e | |
parent | 976be12b72ca2e1f5479e26aeac8e1b1c12dc41b (diff) | |
parent | bb9a1580bc7a832857447b4ec5edd05e10fd2c50 (diff) |
Merge commit 'bb9a1580bc7a832857447b4ec5edd05e10fd2c50' into HEADLA.UM.7.6.2.r1-07300-89xx.0
Change-Id: I9ece2dc58a2466e56427801f9ba35249e383bcbd
Signed-off-by: Anusha Shakarad <ashaka@codeaurora.org>
177 files changed, 10744 insertions, 2603 deletions
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt index 29ea987e306d..8aa0ec530a3a 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt @@ -15,7 +15,8 @@ First Level Node - CAM IFE CSID device - compatible Usage: required Value type: <string> - Definition: Should be "qcom,csid170" or "qcom,csid-lite170". + Definition: Should be "qcom,csid170", "qcom,csid175", "qcom,csid175_200", + "qcom,csid-lite170" or "qcom,csid-lite175". - cell-index Usage: required diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index f156cc67b2aa..9750d63794d1 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -17,7 +17,8 @@ Required properties: Usage: required Value type: <string> Definition: Should specify the compatibility string for matching the - driver. e.g. "qcom,vfe170", "qcom,vfe-lite170". + driver. e.g. "qcom,vfe175", "qcom,vfe170", "qcom,vfe175_130", + "qcom,vfe-lite175", "qcom,vfe-lite175_130", "qcom,vfe-lite170". - cell-index Usage: required diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt index 8b2234e0c9fe..326f279623eb 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt @@ -13,12 +13,15 @@ Required Properties: Optional Properties: -- interrupts This indicates the IRQ number of the GPIO - connected to the STAT pin. +- interrupts This indicates the IRQ numbers of the GPIOs + connected to the STAT and usb-id pins. +- interrupt-names The irq names should be smb1360_stat_irq and + smb1360_usb_id_irq.The stat irq is mandatory + and usb_id irq is optional. - pinctrl-names: The state name of the pin configuration. Only support: "default". -- pinctrl-0: The phandle of the pin configuration node in - pinctrl for smb_int_pin. +- pinctrl-0: The phandles of the pin configuration node in + pinctrl for smb_int_pin and usb-id pin. For details of pinctrl properties, please refer to: "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" - qcom,float-voltage-mv Float Voltage in mV - the maximum voltage up to which @@ -177,6 +180,8 @@ Optional Properties: Please go through the documentation for PMIC gpio configuration details: Documentation/devicetree/bindings/gpio/qpnp-pin.txt +- qcom,usb-id-gpio GPIO for usb-id detection.This property is mandatory + if usb-id irq is specified. - qcom,parallel-charging-enabled: A bool property which enables SMB1360 to operate in the parallel mode. SMB1360 acts as the primary charger. @@ -192,9 +197,13 @@ Example: compatible = "qcom,smb1360-chg-fg"; reg = <0x1b>; interrupt-parent = <&spmi_bus>; - interrupts = <0x00 0xcd 0>; + interrupts = <0x00 0xcd 0>, + <0 0xc3 0 3>; + interrupt-names = "smb1360_stat_irq", + "smb1360_usb_id_irq"; pinctrl-names = "default"; - pinctrl-0 = <&smb_int_default>; + pinctrl-0 = <&smb_int_default>, + <&usb_id_default>; /* battery-profile selection properties */ qcom,batt-profile-select; @@ -242,5 +251,6 @@ Example: qcom,otg-fet-present; qcom,otg-fet-enable-gpio = <&pm8916_gpios 3 0>; + qcom,usb-id-gpio = <&pm8916_gpios 4 0>; }; }; diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 084e48707f58..8a5099dc084a 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -329,7 +329,6 @@ CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_MDP3=y -CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_SOUND=y diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 7801775c7e3b..c437ef1dbfac 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -59,7 +59,7 @@ }; &secure_display_memory { - status = "disabled"; + size = <0 0xa000000>; }; &sp_mem { diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi index 285f91a3e300..06aadee8c948 100644 --- a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi @@ -37,26 +37,48 @@ }; }; +&pm8916_gpios { + usb_id { + usb_id_default: usb_id_default { + pins = "gpio4"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + &i2c_2 { status ="ok"; smb1360_otg_supply: smb1360-chg-fg@14 { compatible = "qcom,smb1360-chg-fg"; reg = <0x14>; - interrupt-parent = <&tlmm>; - interrupts = <13 8>; + interrupts-extended = <&tlmm 13 8>, + <&spmi_bus 0 0xc3 0 3>; + interrupt-names = "smb1360_stat_irq", + "smb1360_usb_id_irq"; pinctrl-names = "default"; - pinctrl-0 = <&smb_int_default>; + pinctrl-0 = <&smb_int_default>, + <&usb_id_default>; qcom,empty-soc-disabled; qcom,chg-inhibit-disabled; qcom,float-voltage-mv = <4400>; qcom,iterm-ma = <100>; qcom,recharge-thresh-mv = <100>; qcom,thermal-mitigation = <1500 700 600 0>; - regulator-name = "smb1360_otg_vreg"; qcom,fg-batt-capacity-mah = <2800>; qcom,fg-cutoff-voltage-mv = <3400>; qcom,fg-iterm-ma = <130>; qcom,fg-delta-soc = <1>; + qcom,usb-id-gpio = <&pm8916_gpios 4 0>; + qcom,soft-jeita-supported; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-decidegc = <150>; + qcom,warm-bat-mv = <4200>; + qcom,cool-bat-mv = <4200>; + qcom,warm-bat-ma = <1000>; + qcom,cool-bat-ma = <1000>; status= "okay"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi index 78047bd22f9e..fd0aa8a39a33 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -194,6 +194,11 @@ }; &cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + actuator_rear: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index e0b731e70f66..c845bf57ccb3 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -779,8 +779,8 @@ static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; - /* Ignore if we don't have an event or if it's a zombie event */ - if (!event || event->state == PERF_EVENT_STATE_ZOMBIE) + /* Ignore if we don't have an event */ + if (!event || event->state != PERF_EVENT_STATE_ACTIVE) continue; /* diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 42dde2d64166..c38c08ee630d 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -1256,6 +1256,9 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, size_t array_size = count * sizeof(struct page *); int i = 0; bool is_coherent = is_dma_coherent(dev, attrs); + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int alloc_sizes = mapping->domain->pgsize_bitmap; + unsigned long order_mask; if (array_size <= PAGE_SIZE) pages = kzalloc(array_size, gfp); @@ -1284,13 +1287,26 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, * IOMMU can map any pages, so himem can also be used here */ gfp |= __GFP_NOWARN | __GFP_HIGHMEM; + order_mask = alloc_sizes >> PAGE_SHIFT; + order_mask &= (2U << MAX_ORDER) - 1; + if (!order_mask) + goto error; while (count) { - int j, order = __fls(count); + int j, order; + + order_mask &= (2U << __fls(count)) - 1; + order = __fls(order_mask); + + pages[i] = alloc_pages(order ? (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); + while (!pages[i] && order) { + order_mask &= ~(1U << order); + order = __fls(order_mask); + pages[i] = alloc_pages(order ? (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); + } - pages[i] = alloc_pages(gfp, order); - while (!pages[i] && order) - pages[i] = alloc_pages(gfp, --order); if (!pages[i]) goto error; diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 0937b2f14d77..5a1afd0e41c7 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2757,10 +2757,11 @@ err: int diag_dci_init(void) { - int ret = 0; + int ret = 0, i; driver->dci_tag = 0; - driver->dci_client_id = 0; + for (i = 0; i < MAX_DCI_CLIENTS; i++) + driver->dci_client_id[i] = 0; driver->num_dci_client = 0; mutex_init(&driver->dci_mutex); mutex_init(&dci_log_mask_mutex); @@ -2956,8 +2957,8 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) mutex_init(&new_entry->write_buf_mutex); new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE); if (!new_entry->dci_log_mask) { - pr_err("diag: Unable to create log mask for client, %d", - driver->dci_client_id); + pr_err("diag: Unable to create log mask for DCI client, tgid: %d\n", + current->tgid); goto fail_alloc; } create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); @@ -3006,17 +3007,24 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) proc_buf->buf_curr = proc_buf->buf_primary; } - list_add_tail(&new_entry->track, &driver->dci_client_list); - driver->dci_client_id++; - new_entry->client_info.client_id = driver->dci_client_id; - reg_entry->client_id = driver->dci_client_id; + for (i = 0; i < MAX_DCI_CLIENTS; i++) { + if (driver->dci_client_id[i] == 0) + break; + } + + if (i == MAX_DCI_CLIENTS) + goto fail_alloc; + driver->dci_client_id[i] = 1; + new_entry->client_info.client_id = i+1; + reg_entry->client_id = i+1; driver->num_dci_client++; + list_add_tail(&new_entry->track, &driver->dci_client_list); if (driver->num_dci_client == 1) diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP, reg_entry->token); queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); mutex_unlock(&driver->dci_mutex); - return driver->dci_client_id; + return reg_entry->client_id; fail_alloc: if (new_entry) { @@ -3075,7 +3083,11 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) */ if (!list_empty(&entry->track)) list_del(&entry->track); + + if (entry->client_info.client_id > MAX_DCI_CLIENTS) + return DIAG_DCI_NO_REG; driver->num_dci_client--; + driver->dci_client_id[entry->client_info.client_id - 1] = 0; /* * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index 2fb0e3f7adf3..835c0c1708cf 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2018-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,7 +12,6 @@ #ifndef DIAG_DCI_H #define DIAG_DCI_H -#define MAX_DCI_CLIENTS 10 #define DCI_PKT_RSP_CODE 0x93 #define DCI_DELAYED_RSP_CODE 0x94 #define DCI_CONTROL_PKT_CODE 0x9A diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index 24a9f8af728a..b8b8b3206528 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -324,8 +324,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch, DIAG_LOG(DIAG_DEBUG_MUX, "partial write_done ref %d\n", atomic_read(&entry->ref_count)); diag_ws_on_copy_complete(DIAG_WS_MUX); - spin_unlock_irqrestore(&ch->write_lock, flags); diagmem_free(driver, req, ch->mempool); + spin_unlock_irqrestore(&ch->write_lock, flags); return; } DIAG_LOG(DIAG_DEBUG_MUX, "full write_done, ctxt: %d\n", @@ -343,8 +343,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch, buf = NULL; len = 0; ctxt = 0; - spin_unlock_irqrestore(&ch->write_lock, flags); diagmem_free(driver, req, ch->mempool); + spin_unlock_irqrestore(&ch->write_lock, flags); } static void diag_usb_notifier(void *priv, unsigned int event, diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index f63d78c32b6e..5fb01ac66376 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -288,6 +288,7 @@ for (i = 0; i <= fwd_info->num_pd - 2; i++) \ #define DIAG_CNTL_TYPE 2 #define DIAG_DCI_TYPE 3 +#define MAX_DCI_CLIENTS 10 /* * List of diag ids * 0 is reserved for unknown diag id, 1 for apps, diag ids @@ -580,7 +581,7 @@ struct diagchar_dev { struct list_head dci_req_list; struct list_head dci_client_list; int dci_tag; - int dci_client_id; + int dci_client_id[MAX_DCI_CLIENTS]; struct mutex dci_mutex; int num_dci_client; unsigned char *apps_dci_buf; @@ -597,6 +598,7 @@ struct diagchar_dev { unsigned int poolsize_hdlc; unsigned int poolsize_dci; unsigned int poolsize_user; + spinlock_t diagmem_lock; /* Buffers for masks */ struct mutex diag_cntl_mutex; /* Members for Sending response */ diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 8adaf6478acb..8cf425db1589 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -213,17 +213,19 @@ static void drain_timer_func(unsigned long data) static void diag_drain_apps_data(struct diag_apps_data_t *data) { int err = 0; + unsigned long flags; if (!data || !data->buf) return; err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); + spin_lock_irqsave(&driver->diagmem_lock, flags); if (err) diagmem_free(driver, data->buf, POOL_TYPE_HDLC); - data->buf = NULL; data->len = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } void diag_update_user_client_work_fn(struct work_struct *work) @@ -294,6 +296,8 @@ static void diag_mempool_init(void) diagmem_init(driver, POOL_TYPE_HDLC); diagmem_init(driver, POOL_TYPE_USER); diagmem_init(driver, POOL_TYPE_DCI); + + spin_lock_init(&driver->diagmem_lock); } static void diag_mempool_exit(void) @@ -2744,6 +2748,7 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, struct diag_apps_data_t *data = &hdlc_data; struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; + unsigned long flags; /* * The maximum encoded size of the buffer can be atmost twice the length * of the packet. Add three bytes foe footer - 16 bit CRC (2 bytes) + @@ -2848,10 +2853,11 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, return PKT_ALLOC; fail_free_buf: + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; - + spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; } @@ -2863,6 +2869,7 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, int ret = PKT_DROP; struct diag_pkt_frame_t header; struct diag_apps_data_t *data = &non_hdlc_data; + unsigned long flags; /* * The maximum packet size, when the data is non hdlc encoded is equal * to the size of the packet frame header and the length. Add 1 for the @@ -2927,10 +2934,11 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, return PKT_ALLOC; fail_free_buf: + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; - + spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; } diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index f1bc1c5047e1..d637405a71d1 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1823,9 +1823,11 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, diagfwd_write_done(peripheral, type, num); diag_ws_on_copy(DIAG_WS_MUX); } else if (peripheral == APPS_DATA) { + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC); buf = NULL; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } else { pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n", peripheral, __func__, type); diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c index ada645d92104..2a3602568a1d 100644 --- a/drivers/char/diag/diagmem.c +++ b/drivers/char/diag/diagmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2014, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2014, 2016, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -221,7 +221,7 @@ void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type) break; } spin_lock_irqsave(&mempool->lock, flags); - if (mempool->count > 0) { + if (mempool->count > 0 && buf) { mempool_free(buf, mempool->pool); atomic_add(-1, (atomic_t *)&mempool->count); } else { diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index f2e9085cb5a2..8e8896479cce 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1306,9 +1306,7 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) u32 pattern_sent = 0x0; u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; - ctrl->catalog->update_vx_px(ctrl->catalog, - ctrl->link->phy_params.v_level, - ctrl->link->phy_params.p_level); + dp_ctrl_update_vx_px(ctrl); ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); ctrl->link->send_test_response(ctrl->link); diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c index 2c7f52c7970b..53e20e261ebd 100644 --- a/drivers/gpu/drm/msm/sde_hdcp_1x.c +++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1263,6 +1263,8 @@ static void sde_hdcp_1x_off(void *input) hdcp->sink_r0_ready = false; + hdcp1_unload_app(); + pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME); } /* hdcp_1x_off */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 2a149ac87ed1..06403a87bec8 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -64,7 +64,7 @@ static const char * const clocks[] = { "ahb_clk" }; -static unsigned int ib_votes[KGSL_MAX_BUSLEVELS]; +static unsigned long ib_votes[KGSL_MAX_BUSLEVELS]; static int last_vote_buslevel; static int max_vote_buslevel; @@ -127,7 +127,7 @@ static void _record_pwrevent(struct kgsl_device *device, /** * kgsl_get_bw() - Return latest msm bus IB vote */ -static unsigned int kgsl_get_bw(void) +static unsigned long kgsl_get_bw(void) { return ib_votes[last_vote_buslevel]; } @@ -141,8 +141,8 @@ static unsigned int kgsl_get_bw(void) static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, unsigned long *ab) { - unsigned int ib = ib_votes[last_vote_buslevel]; - unsigned int max_bw = ib_votes[max_vote_buslevel]; + unsigned long ib = ib_votes[last_vote_buslevel]; + unsigned long max_bw = ib_votes[max_vote_buslevel]; if (!ab) return; diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index 0ed17d859080..099daaf8403a 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -335,10 +335,8 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot, entry = kgsl_sharedmem_find(process, gpuaddr); - if (entry == NULL) { - KGSL_CORE_ERR("Unable to find GPU buffer 0x%016llX\n", gpuaddr); + if (entry == NULL) return -EINVAL; - } /* We can't freeze external memory, because we don't own it */ if (entry->memdesc.flags & KGSL_MEMFLAGS_USERMEM_MASK) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 36c84df078c7..30815df2ba6b 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -369,8 +369,9 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, unsigned int order = __fls(order_mask); order_size = 1U << order; - page = alloc_pages((order_mask - order_size) ? - gfp | __GFP_NORETRY : gfp, order); + page = alloc_pages(order ? + (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); if (!page) continue; if (!order) diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 2dcac176812c..87a1244206ba 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1395,7 +1395,7 @@ static ssize_t iommu_debug_test_virt_addr_read(struct file *file, else snprintf(buf, buf_len, "0x%pK\n", test_virt_addr); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1518,7 +1518,7 @@ static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf, else snprintf(buf, sizeof(buf), "pte=%016llx\n", pte); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1587,7 +1587,7 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf, snprintf(buf, 100, "%pa\n", &phys); } - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1640,7 +1640,7 @@ static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf, else snprintf(buf, sizeof(buf), "%pa\n", &phys); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1873,7 +1873,7 @@ static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf, iova = ddev->iova; snprintf(buf, sizeof(buf), "%pa\n", &iova); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; diff --git a/drivers/leds/leds-qpnp-vibrator.c b/drivers/leds/leds-qpnp-vibrator.c index d8dcdf6e0b9a..c428bfb386b9 100644 --- a/drivers/leds/leds-qpnp-vibrator.c +++ b/drivers/leds/leds-qpnp-vibrator.c @@ -398,7 +398,6 @@ static ssize_t qpnp_vib_set_activate(struct device *dev, (vib->vib_play_ms % 1000) * 1000000), HRTIMER_MODE_REL); } - vib->vib_play_ms = 0; mutex_unlock(&vib->lock); schedule_work(&vib->work); diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c index 13a653ae0399..e1809a1d789c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -509,8 +509,8 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if (!rc) { CAM_DBG(CAM_CDM, - "write BL success for cnt=%d with tag=%d", - i, core->bl_tag); + "write BL success for cnt=%d with tag=%d total_cnt=%d", + i, core->bl_tag, req->data->cmd_arrary_count); CAM_DBG(CAM_CDM, "Now commit the BL"); if (cam_hw_cdm_commit_bl_write(cdm_hw)) { @@ -550,35 +550,33 @@ static void cam_hw_cdm_work(struct work_struct *work) cdm_hw = payload->hw; core = (struct cam_cdm *)cdm_hw->core_info; - CAM_DBG(CAM_CDM, "IRQ status=%x", payload->irq_status); + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { - struct cam_cdm_bl_cb_request_entry *node; + struct cam_cdm_bl_cb_request_entry *node, *tnode; - CAM_DBG(CAM_CDM, "inline IRQ data=%x", + CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", payload->irq_data); mutex_lock(&cdm_hw->hw_mutex); - node = cam_cdm_find_request_by_bl_tag( - payload->irq_data, - &core->bl_request_list); - if (node) { + list_for_each_entry_safe(node, tnode, + &core->bl_request_list, entry) { if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_BL_SUCCESS, (void *)node); } else if (node->request_type == - CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_HW_CDM_BL_CB_INTERNAL) { CAM_ERR(CAM_CDM, "Invalid node=%pK %d", node, node->request_type); } list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } kfree(node); - } else { - CAM_ERR(CAM_CDM, - "Inval node, inline_irq st=%x data=%x", - payload->irq_status, payload->irq_data); } mutex_unlock(&cdm_hw->hw_mutex); } @@ -684,7 +682,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); work_status = queue_work(cdm_core->work_queue, &payload->work); if (work_status == false) { - CAM_ERR(CAM_CDM, "Failed to queue work for irq=%x", + CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", payload->irq_status); kfree(payload); } diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c index 9021ecabb27c..b2575825f983 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -118,6 +118,14 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, if ((!rc) && (vaddr_ptr) && (len) && (len >= cdm_cmd->cmd[i].offset)) { + + + if ((len - cdm_cmd->cmd[i].offset) <= + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, "Not enough buffer"); + rc = -EINVAL; + break; + } CAM_DBG(CAM_CDM, "hdl=%x vaddr=%pK offset=%d cmdlen=%d:%zu", cdm_cmd->cmd[i].bl_addr.mem_handle, diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c index d4f9b72f99f3..5f9d1e06d8a8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,7 +43,6 @@ int cam_context_shutdown(struct cam_context *ctx) int rc = 0; struct cam_release_dev_cmd cmd; - mutex_lock(&ctx->ctx_mutex); if (ctx->state > CAM_CTX_AVAILABLE && ctx->state < CAM_CTX_STATE_MAX) { cmd.session_handle = ctx->session_hdl; cmd.dev_handle = ctx->dev_hdl; @@ -60,7 +59,6 @@ int cam_context_shutdown(struct cam_context *ctx) ctx->dev_name, ctx->ctx_id, ctx->state); rc = -EINVAL; } - mutex_unlock(&ctx->ctx_mutex); rc = cam_destroy_device_hdl(ctx->dev_hdl); if (rc) @@ -173,6 +171,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.apply_req) { rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx, apply); @@ -181,6 +180,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, ctx->dev_hdl, ctx->state); rc = -EPROTO; } + mutex_unlock(&ctx->ctx_mutex); return rc; } @@ -243,6 +243,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].pagefault_ops) { rc = ctx->state_machine[ctx->state].pagefault_ops(ctx, iova, buf_info); @@ -250,6 +251,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", ctx->dev_hdl, ctx->state); } + mutex_unlock(&ctx->ctx_mutex); return rc; } @@ -528,6 +530,7 @@ int cam_context_init(struct cam_context *ctx, ctx->dev_name = dev_name; ctx->dev_id = dev_id; ctx->ctx_id = ctx_id; + ctx->last_flush_req = 0; ctx->ctx_crm_intf = NULL; ctx->crm_ctx_intf = crm_node_intf; ctx->hw_mgr_intf = hw_mgr_intf; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c index d98b900bc07a..e5232c482a17 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -303,6 +303,12 @@ int32_t cam_context_config_dev_to_hw( return rc; } + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + + } packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); @@ -333,6 +339,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; int32_t i = 0, j = 0; if (!ctx || !cmd) { @@ -381,11 +388,19 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); if (packet->header.request_id <= ctx->last_flush_req) { - CAM_DBG(CAM_CORE, + CAM_ERR(CAM_CORE, "request %lld has been flushed, reject packet", packet->header.request_id); rc = -EINVAL; @@ -398,6 +413,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; cfg.max_hw_update_entries = CAM_CTX_CFG_MAX; cfg.num_hw_update_entries = req->num_hw_update_entries; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h deleted file mode 100644 index 32330b1e07e4..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ - -#ifndef _CAM_CORE_DEFS_H_ -#define _CAM_CORE_DEFS_H_ - -#define CAM_CORE_TRACE_ENABLE 0 - -#if (CAM_CORE_TRACE_ENABLE == 1) - #define CAM_CORE_DBG(fmt, args...) do { \ - trace_printk("%d: [cam_core_dbg] "fmt"\n", __LINE__, ##args); \ - pr_debug("%s:%d "fmt"\n", __func__, __LINE__, ##args); \ - } while (0) - - #define CAM_CORE_WARN(fmt, args...) do { \ - trace_printk("%d: [cam_core_warn] "fmt"\n", __LINE__, ##args); \ - pr_warn("%s:%d "fmt"\n", __func__, __LINE__, ##args); \ - } while (0) - - #define CAM_CORE_ERR(fmt, args...) do { \ - trace_printk("%d: [cam_core_err] "fmt"\n", __LINE__, ##args); \ - pr_err("%s:%d "fmt"\n", __func__, __LINE__, ##args);\ - } while (0) -#else - #define CAM_CORE_DBG(fmt, args...) pr_debug("%s:%d "fmt"\n", \ - __func__, __LINE__, ##args) - - #define CAM_CORE_WARN(fmt, args...) pr_warn("%s:%d "fmt"\n", \ - __func__, __LINE__, ##args) - - #define CAM_CORE_ERR(fmt, args...) pr_err("%s:%d "fmt"\n", \ - __func__, __LINE__, ##args) -#endif - -#endif /* _CAM_CORE_DEFS_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h index fd30f115cc0c..c3d1c2eff4e9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -153,6 +153,7 @@ struct cam_hw_mgr_dump_pf_data { * struct cam_hw_prepare_update_args - Payload for prepare command * * @packet: CSL packet from user mode driver + * @remain_len Remaining length of CPU buffer after config offset * @ctxt_to_hw_map: HW context from the acquire * @max_hw_update_entries: Maximum hardware update entries supported * @hw_update_entries: Actual hardware update configuration (returned) @@ -169,6 +170,7 @@ struct cam_hw_mgr_dump_pf_data { */ struct cam_hw_prepare_update_args { struct cam_packet *packet; + size_t remain_len; void *ctxt_to_hw_map; uint32_t max_hw_update_entries; struct cam_hw_update_entry *hw_update_entries; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c index 9da340b1e766..ee9b2bfc1bfa 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -111,6 +111,7 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, goto err; } + ctx->last_flush_req = 0; rc = cam_context_handle_acquire_dev(ctx, acquire); if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", @@ -657,6 +658,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } + CAM_INFO(CAM_CORE, "Acquire HW successful"); } if (copy_to_user((void __user *)cmd->handle, acquire_ptr, @@ -763,6 +765,8 @@ acquire_kfree: "release device failed(rc = %d)", rc); } + CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc); + release_kfree: kfree(release_ptr); break; diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c index 2a91f03ecdc8..017e810e07c0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -313,6 +313,9 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, goto mnoc_node_get_fail; } axi_port->axi_port_mnoc_node = axi_port_mnoc_node; + axi_port->ib_bw_voting_needed = + of_property_read_bool(axi_port_node, + "ib-bw-voting-needed"); rc = cam_cpas_util_register_bus_client(soc_info, axi_port_mnoc_node, &axi_port->mnoc_bus); @@ -662,12 +665,19 @@ static int cam_cpas_util_apply_client_axi_vote( axi_port->camnoc_bus.src, axi_port->camnoc_bus.dst, camnoc_bw, mnoc_bw); - rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, - mnoc_bw, mnoc_bw, false); + if (axi_port->ib_bw_voting_needed) + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, + mnoc_bw, mnoc_bw, false); + else + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, + mnoc_bw, 0, false); + if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", - mnoc_bw, mnoc_bw, rc); + mnoc_bw, + (axi_port->ib_bw_voting_needed ? mnoc_bw : 0), + rc); goto unlock_axi_port; } diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h index f93d036ecfcf..8e016191edb2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -149,6 +149,7 @@ struct cam_cpas_bus_client { * @camnoc_bus: CAMNOC bus client info for this port * @mnoc_bus: MNOC bus client info for this port * @axi_port_name: Name of this AXI port + * @ib_bw_voting_needed: if this port can update ib bw dynamically * @axi_port_node: Node representing this AXI Port * @axi_port_mnoc_node: Node representing mnoc in this AXI Port * @axi_port_camnoc_node: Node representing camnoc in this AXI Port @@ -161,6 +162,7 @@ struct cam_cpas_axi_port { struct cam_cpas_bus_client camnoc_bus; struct cam_cpas_bus_client mnoc_bus; const char *axi_port_name; + bool ib_bw_voting_needed; struct device_node *axi_port_node; struct device_node *axi_port_mnoc_node; struct device_node *axi_port_camnoc_node; diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c index 8f89c4b7b5fd..49774f24ba20 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,9 +20,11 @@ #include "cam_io_util.h" #include "cam_cpas_soc.h" #include "cpastop100.h" +#include "cpastop_v150_100.h" #include "cpastop_v170_110.h" #include "cpastop_v175_100.h" #include "cpastop_v175_101.h" +#include "cpastop_v175_120.h" struct cam_camnoc_info *camnoc_info; @@ -104,6 +106,17 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->cpas_version.minor == 0) && (hw_caps->cpas_version.incr == 1)) soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -642,6 +655,12 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_175_V101: camnoc_info = &cam175_cpas101_camnoc_info; break; + case CAM_CPAS_TITAN_175_V120: + camnoc_info = &cam175_cpas120_camnoc_info; + break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; default: CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", hw_caps->camera_version.major, diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 000000000000..cf9f82d07b20 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,537 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0x5, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h new file mode 100644 index 000000000000..7212bb30940a --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h @@ -0,0 +1,769 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CPASTOP_V175_120_H_ +#define _CPASTOP_V175_120_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_120_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_120_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_120_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas120_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas120_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas120_camnoc_info = { + .specific = &cam_cpas_v175_120_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_120_camnoc_specific) / + sizeof(cam_cpas_v175_120_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_120_irq_sbm, + .irq_err = &cam_cpas_v175_120_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_120_irq_err) / + sizeof(cam_cpas_v175_120_irq_err[0]), + .err_logger = &cam175_cpas120_err_logger_offsets, + .errata_wa_list = &cam175_cpas120_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_120_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/Makefile index ed896e511963..2e4511d2b48f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw_mgr/ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile index d6e76d18e799..61c255e75158 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index ec0a906cb99a..8403d4dbe533 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,8 @@ static struct cam_fd_hw_mgr g_fd_hw_mgr; -static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -50,7 +51,7 @@ static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -162,8 +163,10 @@ static int cam_fd_mgr_util_put_frame_req( mutex_lock(&g_fd_hw_mgr.frame_req_mutex); req_ptr = *frame_req; - if (req_ptr) + if (req_ptr) { + list_del_init(&req_ptr->list); list_add_tail(&req_ptr->list, src_list); + } *frame_req = NULL; mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); @@ -608,7 +611,13 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, rc); return rc; } - + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane); + return -EINVAL; + } cpu_addr[plane] += io_cfg[i].offsets[plane]; } @@ -1444,6 +1453,16 @@ unlock_dev_flush_ctx: for (i = 0; i < flush_args->num_req_pending; i++) { flush_req = (struct cam_fd_mgr_frame_request *) flush_args->flush_req_pending[i]; + CAM_DBG(CAM_FD, "flush pending req %llu", + flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + CAM_DBG(CAM_FD, "flush active req %llu", flush_req->request_id); cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &flush_req); } @@ -1559,7 +1578,8 @@ static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_fd_mgr_util_packet_validate(prepare->packet); + rc = cam_fd_mgr_util_packet_validate(prepare->packet, + prepare->remain_len); if (rc) { CAM_ERR(CAM_FD, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile index 7fe5a4067d02..389ca4c66b8d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_dev.o cam_fd_hw_core.o cam_fd_hw_soc.o diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 12d3c6bf1060..4084c43c2902 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -427,6 +427,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, unsigned long flags; int i; + mutex_lock(&fd_hw->hw_mutex); spin_lock_irqsave(&fd_core->spin_lock, flags); if ((fd_core->core_state != CAM_FD_CORE_STATE_IDLE) || (fd_core->results_valid == false) || @@ -436,6 +437,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, fd_core->core_state, fd_core->results_valid, fd_core->hw_req_private); spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); return -EINVAL; } fd_core->core_state = CAM_FD_CORE_STATE_READING_RESULTS; @@ -516,6 +518,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, fd_core->hw_req_private = NULL; fd_core->core_state = CAM_FD_CORE_STATE_IDLE; spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index c7ef37c65659..d4c9326ed5ab 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -206,6 +206,10 @@ static const struct of_device_id cam_fd_hw_dt_match[] = { .compatible = "qcom,fd501", .data = &cam_fd_wrapper200_core501_info, }, + { + .compatible = "qcom,fd501", + .data = &cam_fd_wrapper200_core501_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h index 38137b89295e..9f81c9c7feb0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -472,7 +472,6 @@ struct ica_stab_params { struct frame_set { struct frame_buffer buffers[IPE_IO_IMAGES_MAX]; - struct ica_stab_params ica_params; uint32_t cdm_ica1_addr; uint32_t cdm_ica2_addr; } __packed; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c index da1bf9e52ce8..bf80938985f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,6 +42,9 @@ #define HFI_MAX_POLL_TRY 5 +#define HFI_MAX_PC_POLL_TRY 150 +#define HFI_POLL_TRY_SLEEP 2 + static struct hfi_info *g_hfi; unsigned int g_icp_mmu_hdl; static DEFINE_MUTEX(hfi_cmd_q_mutex); @@ -513,8 +516,8 @@ void cam_hfi_disable_cpu(void __iomem *icp_base) uint32_t val; uint32_t try = 0; - while (try < HFI_MAX_POLL_TRY) { - data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS); + while (try < HFI_MAX_PC_POLL_TRY) { + data = cam_io_r_mb(icp_base + HFI_REG_A5_CSR_A5_STATUS); CAM_DBG(CAM_HFI, "wfi status = %x\n", (int)data); if (data & ICP_CSR_A5_STATUS_WFI) @@ -523,7 +526,7 @@ void cam_hfi_disable_cpu(void __iomem *icp_base) * and Host can the proceed. No interrupt is expected from FW * at this time. */ - msleep(100); + msleep_interruptible(HFI_POLL_TRY_SLEEP); try++; } diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c index b969c92ccbc8..a330cff293d6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -226,6 +226,13 @@ static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, bool reset_bps_top_fail = false; CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_ICP, "BPS reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + /* Reset BPS CDM core*/ cam_io_w_mb((uint32_t)0xF, soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 73e42de3fa03..0f103b92ba70 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -62,6 +62,8 @@ static struct cam_icp_hw_mgr icp_hw_mgr; +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); + static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) { struct cam_hw_intf *a5_dev_intf = NULL; @@ -1834,12 +1836,13 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); rc = cam_icp_mgr_trigger_recovery(hw_mgr); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); } return rc; } -static void cam_icp_mgr_process_dbg_buf(void) +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl) { uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; struct hfi_msg_debug *dbg_msg; @@ -1861,6 +1864,8 @@ static void cam_icp_mgr_process_dbg_buf(void) timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) | dbg_msg->timestamp_lo) >> 16); trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); + if (!debug_lvl) + CAM_INFO(CAM_ICP, "FW_DBG:%s", dbg_buf); } size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> BYTE_WORD_SHIFT); @@ -1986,9 +1991,7 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) } } - if (icp_hw_mgr.a5_debug_type == - HFI_DEBUG_MODE_QUEUE) - cam_icp_mgr_process_dbg_buf(); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); if ((task_data->irq_status & A5_WDT_0) || (task_data->irq_status & A5_WDT_1)) { @@ -2508,6 +2511,7 @@ static int cam_icp_mgr_abort_handle( if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -2562,9 +2566,7 @@ static int cam_icp_mgr_destroy_handle( rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timeout: %d for %u", rc, ctx_data->ctx_id); - if (icp_hw_mgr.a5_debug_type == - HFI_DEBUG_MODE_QUEUE) - cam_icp_mgr_process_dbg_buf(); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } kfree(destroy_cmd); @@ -2871,6 +2873,7 @@ static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); @@ -3122,6 +3125,7 @@ static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -3377,7 +3381,7 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, } if (!cpu_addr) { - CAM_ERR(CAM_ICP, "Invalid cpu addr"); + CAM_ERR(CAM_ICP, "invalid number of cmd buf"); return -EINVAL; } @@ -3847,9 +3851,12 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_ICP, - "pln %d w %d h %d size %d addr 0x%x offset 0x%x memh %x", - j, io_cfg[i].planes[j].width, + "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + j, io_cfg[i].direction, + io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, (int32_t)src_buf_size, (unsigned int)iova_addr, io_cfg[i].offsets[j], @@ -3936,6 +3943,9 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet = prepare_args->packet; + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + return -EINVAL; + rc = cam_icp_mgr_pkt_validation(packet); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); @@ -4300,6 +4310,7 @@ static int cam_icp_mgr_create_handle(uint32_t dev_type, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -4346,6 +4357,7 @@ static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -4619,6 +4631,7 @@ get_io_buf_failed: hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; acquire_info_failed: cam_icp_mgr_put_ctx(ctx_data); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; @@ -4898,6 +4911,7 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_mgr->iommu_sec_hdl, hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); + break; default: CAM_ERR(CAM_ICP, "Invalid cmd"); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 234643e3d105..5a93df33925f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -128,11 +128,11 @@ struct clk_work_data { }; /** - * struct icp_frame_info - * @request_id: request id - * @io_config: the address of io config - * @hfi_cfg_io_cmd: command struct to be sent to hfi - */ + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ struct icp_frame_info { uint64_t request_id; uint64_t io_config; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 7bb9b9ed18a2..2ebe41417d1d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,7 +23,7 @@ #define CAM_ICP_A5_BW_BYTES_VOTE 40000000 -#define CAM_ICP_CTX_MAX 36 +#define CAM_ICP_CTX_MAX 54 #define CPAS_IPE1_BIT 0x2000 diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c index 142fcdc6017d..1f71c7d4cd36 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -222,6 +222,12 @@ static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, bool reset_ipe_top_fail = false; CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_HFI, "IPE reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + /* IPE CDM core reset*/ cam_io_w_mb((uint32_t)0xF, soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c index 113e1a8d5298..e510d7c91f49 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,16 +29,6 @@ static const char isp_dev_name[] = "isp"; -char *substate_name[8] = { - "CAM_ISP_CTX_ACTIVATED_SOF", - "CAM_ISP_CTX_ACTIVATED_APPLIED", - "CAM_ISP_CTX_ACTIVATED_EPOCH", - "CAM_ISP_CTX_ACTIVATED_BUBBLE", - "CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED", - "CAM_ISP_CTX_ACTIVATED_HW_ERROR", - "CAM_ISP_CTX_ACTIVATED_HALT", - "CAM_ISP_CTX_ACTIVATED_MAX", -}; #define INC_STATE_MONITOR_HEAD(head) \ (atomic64_add_return(1, head) % \ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) @@ -139,6 +129,8 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) size_t len = 0; uint32_t *buf_addr; uint32_t *buf_start, *buf_end; + size_t remain_len = 0; + bool need_put = false; for (i = 0; i < req_isp->num_cfg; i++) { rc = cam_packet_util_get_cmd_mem_addr( @@ -148,16 +140,27 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) "Failed to get_cmd_mem_addr, rc=%d", rc); } else { + if (req_isp->cfg[i].offset >= len) { + CAM_ERR(CAM_ISP, "Invalid offset"); + need_put = true; + goto put; + } + remain_len = len - req_isp->cfg[i].offset; + + if (req_isp->cfg[i].len > remain_len) { + CAM_ERR(CAM_ISP, "Invalid offset"); + need_put = true; + } +put: + if (need_put) { + need_put = false; + continue; + } + buf_start = (uint32_t *)((uint8_t *) buf_addr + req_isp->cfg[i].offset); buf_end = (uint32_t *)((uint8_t *) buf_start + req_isp->cfg[i].len - 1); - if (len < (buf_end - buf_start + 1)) { - CAM_DBG(CAM_ISP, - "Invalid len %zu, buf_start-end=%d", - len, (buf_end - buf_start + 1)); - continue; - } cam_cdm_util_dump_cmd_buf(buf_start, buf_end); } } @@ -426,11 +429,12 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( } if (!req_isp->bubble_detected) { - CAM_INFO(CAM_ISP, - "Sync with success: req %lld res 0x%x fd 0x%x", + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_SUCCESS); @@ -438,11 +442,12 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); } else if (!req_isp->bubble_report) { - CAM_INFO(CAM_ISP, - "Sync with failure: req %lld res 0x%x fd 0x%x", + CAM_ERR(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); @@ -463,9 +468,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( continue; } - CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x", + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); if (!rc) { req_isp->num_acked++; req_isp->fence_map_out[j].sync_id = -1; @@ -475,9 +480,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( if (req_isp->num_acked > req_isp->num_fence_map_out) { /* Should not happen */ CAM_ERR(CAM_ISP, - "WARNING: req_id %lld num_acked %d > map_out %d", + "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", req->request_id, req_isp->num_acked, - req_isp->num_fence_map_out); + req_isp->num_fence_map_out, ctx->ctx_id); WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); } @@ -491,17 +496,18 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( req_isp->bubble_detected = false; list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); CAM_DBG(CAM_REQ, - "Move active request %lld to pending list(cnt = %d) [bubble recovery]", - req->request_id, ctx_isp->active_req_cnt); + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, - "Move active request %lld to free list(cnt = %d) [all fences done]", - req->request_id, ctx_isp->active_req_cnt); + "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } end: @@ -571,7 +577,6 @@ static void __cam_isp_ctx_send_sof_timestamp( static int __cam_isp_ctx_reg_upd_in_epoch_state( struct cam_isp_context *ctx_isp, void *evt_data) { - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); if (ctx_isp->frame_id == 1) CAM_DBG(CAM_ISP, "Reg update for early PCR"); else @@ -589,7 +594,6 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( struct cam_context *ctx = ctx_isp->base; struct cam_isp_ctx_req *req_isp; - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); if (list_empty(&ctx->wait_req_list)) { CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); goto end; @@ -602,14 +606,15 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( if (req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { /* no io config, so the request is completed. */ list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_ISP, - "move active request %lld to free list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + "move active request %lld to free list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } /* @@ -617,7 +622,6 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( * state so change substate here. */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: @@ -633,7 +637,6 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_ctx_request *req; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is EPOCH", substate_name[ctx_isp->substate_activated]); /* * notify reqmgr with sof signal. Note, due to scheduling delay * we can run into situation that two active requests has already @@ -650,8 +653,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.trigger = CAM_TRIGGER_POINT_SOF; ctx->ctx_crm_intf->notify_trigger(¬ify); - CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", - ctx_isp->frame_id); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } list_for_each_entry(req, &ctx->active_req_list, list) { @@ -668,7 +671,9 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } else { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify SOF to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } @@ -693,14 +698,14 @@ static int __cam_isp_ctx_notify_eof_in_activated_state( notify.trigger = CAM_TRIGGER_POINT_EOF; ctx->ctx_crm_intf->notify_trigger(¬ify); - CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld\n", - ctx_isp->frame_id); + CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } else { - CAM_ERR(CAM_ISP, "Can not notify EOF to CRM"); + CAM_ERR(CAM_ISP, "Can not notify EOF to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } - CAM_INFO(CAM_ISP, "state = %s IRQ is EOF", substate_name[ctx_isp->substate_activated]); return rc; } @@ -708,7 +713,6 @@ static int __cam_isp_ctx_reg_upd_in_hw_error( struct cam_isp_context *ctx_isp, void *evt_data) { ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return 0; } @@ -733,11 +737,8 @@ static int __cam_isp_ctx_sof_in_activated_state( ctx_isp->boot_timestamp = sof_event_data->boot_time; __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); - CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", - ctx_isp->frame_id, ctx_isp->sof_timestamp_val); - CAM_INFO(CAM_ISP, "state = %s IRQ is SOF frame_id = %lld", - substate_name[ctx_isp->substate_activated], ctx_isp->frame_id); - + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id); return rc; } @@ -775,7 +776,6 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, req->request_id); } - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); end: return rc; } @@ -788,7 +788,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is EPOCH", substate_name[ctx_isp->substate_activated]); if (list_empty(&ctx->wait_req_list)) { /* * If no wait req in epoch, this is an error case. @@ -796,7 +795,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, */ CAM_ERR(CAM_ISP, "No wait request"); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, @@ -820,8 +818,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; ctx->ctx_crm_intf->notify_err(¬ify); - CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", - ctx_isp->frame_id); + atomic_set(&ctx_isp->process_bubble, 1); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld, ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } else { req_isp->bubble_report = 0; } @@ -830,8 +829,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->active_req_cnt++; list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); @@ -844,7 +843,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_REQ_MGR_SOF_EVENT_ERROR); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: @@ -868,7 +866,6 @@ static int __cam_isp_ctx_buf_done_in_applied(struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); return rc; } @@ -882,9 +879,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; struct cam_ctx_request *req; - CAM_INFO(CAM_ISP, "SURESH: state = %s IRQ is SOF frame_id = %lld", - substate_name[ctx_isp->substate_activated], ctx_isp->frame_id); - if (!evt_data) { CAM_ERR(CAM_ISP, "in valid sof event data"); return -EINVAL; @@ -898,7 +892,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, list); @@ -919,7 +912,6 @@ static int __cam_isp_ctx_buf_done_in_epoch(struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); return rc; } @@ -931,7 +923,6 @@ static int __cam_isp_ctx_buf_done_in_bubble( struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); return rc; } @@ -944,7 +935,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); /* * This means we missed the reg upd ack. So we need to * transition to BUBBLE state again. @@ -960,7 +950,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); goto end; } @@ -979,8 +968,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.error = CRM_KMD_ERR_BUBBLE; ctx->ctx_crm_intf->notify_err(¬ify); CAM_DBG(CAM_REQ, - "Notify CRM about Bubble req_id %llu frame %lld", - req->request_id, ctx_isp->frame_id); + "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); } else { req_isp->bubble_report = 0; } @@ -989,7 +978,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", req->request_id, ctx_isp->active_req_cnt); ctx_isp->active_req_cnt++; list_del_init(&req->list); @@ -1009,7 +998,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, @@ -1027,7 +1015,6 @@ static int __cam_isp_ctx_buf_done_in_bubble_applied( struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, @@ -1050,6 +1037,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, struct cam_req_mgr_error_notify notify; uint64_t error_request_id = 0; struct cam_hw_fence_map_entry *fence_map_out = NULL; + struct cam_req_mgr_message req_msg; struct cam_context *ctx = ctx_isp->base; struct cam_isp_hw_error_event_data *error_event_data = @@ -1084,7 +1072,9 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, } req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; - cam_isp_ctx_dump_req(req_isp); + + if (error_event_data->enable_reg_dump) + cam_isp_ctx_dump_req(req_isp); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); @@ -1096,9 +1086,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, for (i = 0; i < req_isp->num_fence_map_out; i++) { fence_map_out = &req_isp->fence_map_out[i]; - CAM_ERR(CAM_ISP, "req %llu, Sync fd %x", + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[i].sync_id); + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); if (req_isp->fence_map_out[i].sync_id != -1) { rc = cam_sync_signal( fence_map_out->sync_id, @@ -1125,9 +1117,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, for (i = 0; i < req_isp->num_fence_map_out; i++) { fence_map_out = &req_isp->fence_map_out[i]; - CAM_ERR(CAM_ISP, "req %llu, Sync fd %x", + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[i].sync_id); + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); if (req_isp->fence_map_out[i].sync_id != -1) { rc = cam_sync_signal( fence_map_out->sync_id, @@ -1214,14 +1208,39 @@ end: notify.error = CRM_KMD_ERR_FATAL; } - CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld\n", - error_request_id, ctx_isp->frame_id); + CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u", + error_request_id, ctx_isp->frame_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); + + /* + * Need to send error occurred in KMD + * This will help UMD to take necessary action + * and to dump relevant info + */ + + if (notify.error == CRM_KMD_ERR_OVERFLOW) { + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.err_msg.request_id = error_request_id; + req_msg.u.err_msg.resource_size = 0x0; + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the error time for req id:%lld ctx %u", + ctx_isp->last_applied_req_id, + ctx->ctx_id); + } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); } else { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify ERRROR to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } @@ -1230,6 +1249,236 @@ end: return rc; } +static int __cam_isp_ctx_fs2_sof_in_sof_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + + req = list_last_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (!(list_empty(&ctx->wait_req_list))) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + +end: + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + struct cam_context *ctx = ctx_isp->base; + int prev_active_req_cnt = 0; + int curr_req_id = 0; + struct cam_ctx_request *req; + + prev_active_req_cnt = ctx_isp->active_req_cnt; + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + curr_req_id = req->request_id; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + + if (prev_active_req_cnt == ctx_isp->active_req_cnt + 1) { + if (list_empty(&ctx->wait_req_list) && + list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "No request, move to SOF"); + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_SOF; + if (ctx_isp->reported_req_id < curr_req_id) { + ctx_isp->reported_req_id = curr_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + curr_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + } + } + + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_applied( + struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + if (req_isp->num_fence_map_out != 1) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); +end: + if (req != NULL && !rc) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + req->request_id); + } + return rc; +} + static struct cam_isp_ctx_irq_ops cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { /* SOF */ @@ -1303,6 +1552,79 @@ static struct cam_isp_ctx_irq_ops }, }; +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_fs2_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_fs2_reg_upd_in_sof, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_fs2_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + NULL, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_epoch_in_bubble_applied, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + static int __cam_isp_ctx_apply_req_in_activated_state( struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, uint32_t next_state) @@ -1330,6 +1652,14 @@ static int __cam_isp_ctx_apply_req_in_activated_state( */ ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + if (atomic_read(&ctx_isp->process_bubble)) { + CAM_DBG(CAM_ISP, + "Processing bubble cannot apply Request Id %llu", + apply->request_id); + rc = -EAGAIN; + goto end; + } + spin_lock_bh(&ctx->lock); req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); @@ -1347,15 +1677,16 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } - CAM_DBG(CAM_REQ, "Apply request %lld in substate %d", req->request_id, - ctx_isp->substate_activated); + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", + req->request_id, ctx_isp->substate_activated, ctx->ctx_id); req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "Reject apply request (id %lld) due to congestion(cnt = %d)", + "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u", req->request_id, - ctx_isp->active_req_cnt); + ctx_isp->active_req_cnt, + ctx->ctx_id); spin_lock_bh(&ctx->lock); if (!list_empty(&ctx->active_req_list)) @@ -1391,7 +1722,6 @@ static int __cam_isp_ctx_apply_req_in_activated_state( } else { spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = next_state; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); ctx_isp->last_applied_req_id = apply->request_id; list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); @@ -1420,7 +1750,6 @@ static int __cam_isp_ctx_apply_req_in_sof( rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1437,7 +1766,6 @@ static int __cam_isp_ctx_apply_req_in_epoch( rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1454,7 +1782,6 @@ static int __cam_isp_ctx_apply_req_in_bubble( rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1528,11 +1855,6 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { - struct cam_isp_context *ctx_isp = - (struct cam_isp_context *) ctx->ctx_priv; - struct cam_isp_stop_args stop_isp; - struct cam_hw_stop_args stop_args; - struct cam_isp_start_args start_isp; int rc = 0; if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { @@ -1546,47 +1868,6 @@ static int __cam_isp_ctx_flush_req_in_top_state( rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); - if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { - /* if active and wait list are empty, return */ - spin_lock_bh(&ctx->lock); - if ((list_empty(&ctx->wait_req_list)) && - (list_empty(&ctx->active_req_list))) { - spin_unlock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "active and wait list are empty"); - goto end; - } - spin_unlock_bh(&ctx->lock); - - /* Stop hw first before active list flush */ - stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; - stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; - stop_isp.stop_only = true; - stop_args.args = (void *)&stop_isp; - ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, - &stop_args); - - spin_lock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "try to flush wait list"); - rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, - flush_req); - CAM_DBG(CAM_ISP, "try to flush active list"); - rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, - flush_req); - ctx_isp->active_req_cnt = 0; - spin_unlock_bh(&ctx->lock); - - /* Start hw */ - start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; - start_isp.start_only = true; - start_isp.hw_config.priv = NULL; - - rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, - &start_isp); - } - -end: - CAM_DBG(CAM_ISP, "Flush request in top state %d", - ctx->state); return rc; } @@ -1664,6 +1945,58 @@ static struct cam_ctx_ops }, }; +static struct cam_ctx_ops + cam_isp_ctx_fs2_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + static int __cam_isp_ctx_rdi_only_sof_in_top_state( struct cam_isp_context *ctx_isp, void *evt_data) { @@ -1718,7 +2051,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); return rc; @@ -1741,7 +2073,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_applied_state( ctx_isp->frame_id, ctx_isp->sof_timestamp_val); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); return 0; @@ -1780,7 +2111,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( */ CAM_ERR(CAM_ISP, "No wait request"); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, @@ -1835,7 +2165,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( /* change the state to bubble, as reg update has not come */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: return 0; @@ -1906,7 +2235,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); @@ -1924,7 +2252,6 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( uint64_t request_id = 0; ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* notify reqmgr with sof signal*/ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { if (list_empty(&ctx->wait_req_list)) { @@ -1986,7 +2313,6 @@ error: * to SOF sub state */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return 0; } @@ -2069,7 +2395,6 @@ static int __cam_isp_ctx_rdi_only_apply_req_top_state( rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -2125,9 +2450,8 @@ static struct cam_ctx_ops }, }; -/* top level state machine */ -static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, - struct cam_release_dev_cmd *cmd) +static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, + void *cmd) { int rc = 0; struct cam_hw_release_args rel_arg; @@ -2135,28 +2459,16 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; - if (ctx->link_hdl != -1) { - CAM_ERR(CAM_ISP, "ctx expects release dev after unlink"); - rc = -EAGAIN; - return rc; - } - - if (cmd && ctx_isp->hw_ctx && ctx_isp->split_acquire) { - CAM_ERR(CAM_ISP, "ctx expects release HW before release dev"); - return rc; - } - if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &rel_arg); ctx_isp->hw_ctx = NULL; + } else { + CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); } - ctx->session_hdl = -1; - ctx->dev_hdl = -1; - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -2168,7 +2480,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, * But we still add some sanity check code here to help the debug */ if (!list_empty(&ctx->active_req_list)) - CAM_ERR(CAM_ISP, "Active list is not empty"); + CAM_WARN(CAM_ISP, "Active list is not empty"); /* Flush all the pending request list */ flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; @@ -2179,7 +2491,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); spin_unlock_bh(&ctx->lock); - ctx->state = CAM_CTX_AVAILABLE; + ctx->state = CAM_CTX_ACQUIRED; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", @@ -2187,8 +2499,9 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, return rc; } -static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, - void *cmd) +/* top level state machine */ +static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) { int rc = 0; struct cam_hw_release_args rel_arg; @@ -2196,15 +2509,23 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; + if (cmd && ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "releasing hw"); + __cam_isp_ctx_release_hw_in_top_state(ctx, NULL); + } + if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &rel_arg); ctx_isp->hw_ctx = NULL; - } else { - CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); } + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -2216,7 +2537,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, * But we still add some sanity check code here to help the debug */ if (!list_empty(&ctx->active_req_list)) - CAM_WARN(CAM_ISP, "Active list is not empty"); + CAM_ERR(CAM_ISP, "Active list is not empty"); /* Flush all the pending request list */ flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; @@ -2227,7 +2548,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); spin_unlock_bh(&ctx->lock); - ctx->state = CAM_CTX_ACQUIRED; + ctx->state = CAM_CTX_AVAILABLE; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", @@ -2244,6 +2565,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; struct cam_hw_prepare_update_args cfg; struct cam_req_mgr_add_request add_req; struct cam_isp_context *ctx_isp = @@ -2278,6 +2600,14 @@ static int __cam_isp_ctx_config_dev_in_top_state( goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr); @@ -2288,7 +2618,8 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); - if (packet->header.request_id <= ctx->last_flush_req) { + if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", packet->header.request_id); @@ -2296,12 +2627,10 @@ static int __cam_isp_ctx_config_dev_in_top_state( goto free_req; } - if (packet->header.request_id > ctx->last_flush_req) - ctx->last_flush_req = 0; - /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX; cfg.hw_update_entries = req_isp->cfg; @@ -2388,8 +2717,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( put_ref: for (--i; i >= 0; i--) { - rc = cam_sync_put_obj_ref(req_isp->fence_map_out[i].sync_id); - if (rc) + if (cam_sync_put_obj_ref(req_isp->fence_map_out[i].sync_id)) CAM_ERR(CAM_CTXT, "Failed to put ref of fence %d", req_isp->fence_map_out[i].sync_id); } @@ -2476,7 +2804,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; - isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, &hw_cmd_args); @@ -2485,7 +2813,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, goto free_hw; } - if (isp_hw_cmd_args.u.is_rdi_only_context) { + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { /* * this context has rdi only resource assign rdi only * state machine @@ -2496,6 +2824,13 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -2504,7 +2839,6 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, cam_isp_ctx_activated_state_machine; } - ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context; ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx_isp->split_acquire = false; @@ -2622,7 +2956,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; - isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, &hw_cmd_args); @@ -2631,7 +2965,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, goto free_hw; } - if (isp_hw_cmd_args.u.is_rdi_only_context) { + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { /* * this context has rdi only resource assign rdi only * state machine @@ -2642,6 +2976,13 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -2650,16 +2991,14 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, cam_isp_ctx_activated_state_machine; } - ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context; ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, - "Acquire success on session_hdl 0x%xs RDI only %d ctx %u", - ctx->session_hdl, - (isp_hw_cmd_args.u.is_rdi_only_context ? 1 : 0), ctx->ctx_id); + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); kfree(acquire_hw_info); return rc; @@ -2814,7 +3153,6 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, CAM_ISP_CTX_ACTIVATED_APPLIED : (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* * Only place to change state before calling the hw due to @@ -2876,7 +3214,6 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; spin_unlock_bh(&ctx->lock); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* stop hw first */ if (ctx_isp->hw_ctx) { @@ -2947,6 +3284,12 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_isp_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + } return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h index 5ebd82ead470..4954f2034144 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -144,6 +144,8 @@ struct cam_isp_context_state_monitor { * @base: Common context object pointer * @frame_id: Frame id tracking for the isp context * @substate_actiavted: Current substate for the activated state. + * @process_bubble: Atomic variable to check if ctx is still + * processing bubble. * @substate_machine: ISP substate machine for external interface * @substate_machine_irq: ISP substate machine for irq handling * @req_base: Common request object storage @@ -170,6 +172,7 @@ struct cam_isp_context { int64_t frame_id; uint32_t substate_activated; + atomic_t process_bubble; struct cam_ctx_ops *substate_machine; struct cam_isp_ctx_irq_ops *substate_machine_irq; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a6c96bd8929c..9fb67570b51a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,7 +43,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, @@ -51,6 +51,7 @@ static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_BW_UPDATE, CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG, }; static struct cam_ife_hw_mgr g_ife_hw_mgr; @@ -316,6 +317,11 @@ static void cam_ife_hw_mgr_deinit_hw( cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); } + /* Deint IFE RD */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + /* Deinit IFE OUT */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); @@ -366,6 +372,18 @@ static int cam_ife_hw_mgr_init_hw( } } + /* INIT IFE BUS RD */ + CAM_DBG(CAM_ISP, "INIT IFE BUS RD in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not IFE BUS RD (%d)", + hw_mgr_res->res_id); + return rc; + } + } + /* INIT IFE OUT */ CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", ctx->ctx_index); @@ -500,6 +518,13 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]); + /* ife bus rd resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + /* ife source resource */ list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, &ife_ctx->res_list_ife_src, list) { @@ -645,6 +670,91 @@ static int cam_ife_mgr_process_base_info( return 0; } +static int cam_ife_hw_mgr_acquire_res_bus_rd( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_ife_hw_mgr_res *ife_in_rd_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *ife_src_res; + int i; + + CAM_DBG(CAM_ISP, "Enter"); + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_in_rd_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, + &ife_in_rd_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_out.ctx = ife_ctx; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!ife_src_res->hw_res[i]) + continue; + + hw_intf = ife_src_res->hw_res[i]->hw_intf; + if (i == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + vfe_acquire.rsrc_type); + goto err; + } + + ife_in_rd_res->hw_res[i] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_in_rd_res->hw_res[i]->res_type, + ife_in_rd_res->hw_res[i]->res_id); + + } + ife_in_rd_res->is_dual_vfe = in_port->usage_type; + ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_BUS_RD; + } + + return 0; +err: + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + return rc; +} + static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_ife_hw_mgr_res *ife_src_res, @@ -724,6 +834,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type) CAM_ISP_RESOURCE_VFE_OUT; ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); return 0; err: @@ -817,6 +929,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( ife_out_res->res_id = out_port->res_type; ife_out_res->parent = ife_src_res; ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); } return 0; @@ -839,6 +953,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out( switch (ife_src_res->res_id) { case CAM_ISP_HW_VFE_IN_CAMIF: case CAM_ISP_HW_VFE_IN_CAMIF_LITE: + case CAM_ISP_HW_VFE_IN_RD: rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, ife_src_res, in_port); break; @@ -864,6 +979,132 @@ err: return rc; } +static int cam_ife_hw_mgr_acquire_res_ife_rd_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + int rc = -1; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + int vfe_idx = -1, i = 0; + + ife_hw_mgr = ife_ctx->hw_mgr; + + CAM_DBG(CAM_ISP, "Enter"); + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) { + CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id); + continue; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id); + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + hw_intf = + ife_hw_mgr->ife_devices[csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx]; + + vfe_idx = csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx; + + /* + * fill in more acquire information as needed + */ + if (ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] = + vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); + + if (!ife_src_res->is_dual_vfe) + goto acq; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + CAM_DBG(CAM_ISP, "vfe_idx %d is acquired", + vfe_idx); + continue; + } + + hw_intf = ife_hw_mgr->ife_devices[i]; + + /* fill in more acquire information as needed */ + if (i == CAM_ISP_HW_SPLIT_RIGHT) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + } +acq: + /* + * It should be one to one mapping between + * csid resource and ife source resource + */ + csid_res->child[0] = ife_src_res; + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + +err: + /* release resource at the entry function */ + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + return rc; +} + static int cam_ife_hw_mgr_acquire_res_ife_src( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port) @@ -976,7 +1217,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( csid_res->child[0] = ife_src_res; ife_src_res->parent = csid_res; csid_res->child[csid_res->num_children++] = ife_src_res; - CAM_DBG(CAM_ISP, "csid_res=%d num_children=%d ife_src_res=%d", + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", csid_res->res_id, csid_res->num_children, ife_src_res->res_id); } @@ -991,7 +1233,7 @@ static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, struct cam_ife_hw_mgr_res **cid_res, - enum cam_ife_pix_path_res_id csid_path) + enum cam_ife_pix_path_res_id path_res_id) { int rc = -1; int i, j; @@ -1015,8 +1257,8 @@ static int cam_ife_mgr_acquire_cid_res( csid_acquire.res_type = CAM_ISP_RESOURCE_CID; csid_acquire.in_port = in_port; - csid_acquire.res_id = csid_path; - CAM_DBG(CAM_ISP, "path %d", csid_path); + csid_acquire.res_id = path_res_id; + CAM_DBG(CAM_ISP, "path_res_id %d", path_res_id); if (in_port->num_out_res) out_port = &(in_port->data[0]); @@ -1049,12 +1291,12 @@ static int cam_ife_mgr_acquire_cid_res( csid_acquire.node_res; CAM_DBG(CAM_ISP, - "acquired csid(%s)=%d CID rsrc successfully", + "acquired from old csid(%s)=%d CID rsrc successfully", (i == 0) ? "left" : "right", hw_intf->hw_idx); if (in_port->usage_type && acquired_cnt == 1 && - csid_path == CAM_IFE_PIX_PATH_RES_IPP) + path_res_id == CAM_IFE_PIX_PATH_RES_IPP) /* * Continue to acquire Right for IPP. * Dual IFE for RDI and PPP is not currently @@ -1074,28 +1316,53 @@ static int cam_ife_mgr_acquire_cid_res( } /* Acquire Left if not already acquired */ - for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { - if (!ife_hw_mgr->csid_devices[i]) - continue; + if (ife_ctx->is_fe_enable) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire, - sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } } - } + if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } else { + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; - if (i == -1 || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d", - csid_path); - goto put_res; + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } } + acquire_successful: CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", in_port->usage_type); @@ -1114,7 +1381,7 @@ acquire_successful: * Acquire Right if not already acquired. * Dual IFE for RDI and PPP is not currently supported. */ - if (cid_res_temp->is_dual_vfe && csid_path + if (cid_res_temp->is_dual_vfe && path_res_id == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { csid_acquire.node_res = NULL; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; @@ -1147,6 +1414,8 @@ acquire_successful: cid_res_temp->parent = &ife_ctx->res_list_ife_in; ife_ctx->res_list_ife_in.child[ ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; + CAM_DBG(CAM_ISP, "IFE IN num_children = %d", + ife_ctx->res_list_ife_in.num_children); return 0; put_res: @@ -1205,6 +1474,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; } + CAM_DBG(CAM_ISP, "CSID Acq: E"); /* IPP resource needs to be from same HW as CID resource */ for (i = 0; i <= csid_res->is_dual_vfe; i++) { CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); @@ -1255,8 +1525,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_res->parent = cid_res; cid_res->child[cid_res->num_children++] = csid_res; - CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id); - + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); return 0; put_res: cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); @@ -1269,6 +1539,7 @@ static enum cam_ife_pix_path_res_id uint32_t out_port_type) { enum cam_ife_pix_path_res_id path_id; + CAM_DBG(CAM_ISP, "out_port_type %x", out_port_type); switch (out_port_type) { case CAM_ISP_IFE_OUT_RES_RDI_0: @@ -1289,7 +1560,7 @@ static enum cam_ife_pix_path_res_id break; } - CAM_DBG(CAM_ISP, "out_port %d path_id %d", out_port_type, path_id); + CAM_DBG(CAM_ISP, "out_port %x path_id %d", out_port_type, path_id); return path_id; } @@ -1307,20 +1578,20 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( struct cam_hw_intf *hw_intf; struct cam_isp_out_port_info *out_port; struct cam_csid_hw_reserve_resource_args csid_acquire; - enum cam_ife_pix_path_res_id path_type; + enum cam_ife_pix_path_res_id path_res_id; ife_hw_mgr = ife_ctx->hw_mgr; for (i = 0; i < in_port->num_out_res; i++) { out_port = &in_port->data[i]; - path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + path_res_id = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( out_port->res_type); - if (path_type == CAM_IFE_PIX_PATH_RES_MAX) + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) continue; /* get cid resource */ rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, - path_type); + path_res_id); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); goto end; @@ -1335,8 +1606,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( } memset(&csid_acquire, 0, sizeof(csid_acquire)); - csid_acquire.res_id = path_type; - + csid_acquire.res_id = path_res_id; csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.cid = cid_res->hw_res[0]->res_id; csid_acquire.in_port = in_port; @@ -1368,11 +1638,11 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_res->is_dual_vfe = 0; csid_res->hw_res[0] = csid_acquire.node_res; csid_res->hw_res[1] = NULL; - CAM_DBG(CAM_ISP, "acquire res %d", - csid_acquire.res_id); csid_res->parent = cid_res; cid_res->child[cid_res->num_children++] = csid_res; + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); } @@ -1395,7 +1665,8 @@ static int cam_ife_hw_mgr_acquire_res_root( ife_ctx->res_list_ife_in.res_type = CAM_IFE_HW_MGR_RES_ROOT; ife_ctx->res_list_ife_in.res_id = in_port->res_type; ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type; - } else if (ife_ctx->res_list_ife_in.res_id != in_port->res_type) { + } else if ((ife_ctx->res_list_ife_in.res_id != + in_port->res_type) && (!ife_ctx->is_fe_enable)) { CAM_ERR(CAM_ISP, "No Free resource for this context"); goto err; } else { @@ -1407,35 +1678,85 @@ err: return rc; } -static int cam_ife_hw_mgr_preprocess_out_port( +static int cam_ife_mgr_check_and_update_fe( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port + + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_hw_mgr_preprocess_port( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, int *ipp_count, int *rdi_count, - int *ppp_count) + int *ppp_count, + int *ife_rd_count) { int ipp_num = 0; int rdi_num = 0; int ppp_num = 0; + int ife_rd_num = 0; uint32_t i; struct cam_isp_out_port_info *out_port; struct cam_ife_hw_mgr *ife_hw_mgr; ife_hw_mgr = ife_ctx->hw_mgr; - for (i = 0; i < in_port->num_out_res; i++) { - out_port = &in_port->data[i]; - if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) - rdi_num++; - else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) - ppp_num++; - else - ipp_num++; + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_rd_num++; + } else { + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + rdi_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) + ppp_num++; + else { + CAM_DBG(CAM_ISP, "out_res_type %d", + out_port->res_type); + ipp_num++; + } + } } *ipp_count = ipp_num; *rdi_count = rdi_num; *ppp_count = ppp_num; + *ife_rd_count = ife_rd_num; + + CAM_DBG(CAM_ISP, "rdi: %d ipp: %d ppp: %d ife_rd: %d", + rdi_num, ipp_num, ppp_num, ife_rd_num); return 0; } @@ -1450,6 +1771,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( int ipp_count = 0; int rdi_count = 0; int ppp_count = 0; + int ife_rd_count = 0; is_dual_vfe = in_port->usage_type; @@ -1460,11 +1782,11 @@ static int cam_ife_mgr_acquire_hw_for_ctx( goto err; } - cam_ife_hw_mgr_preprocess_out_port(ife_ctx, in_port, - &ipp_count, &rdi_count, &ppp_count); + cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, + &ipp_count, &rdi_count, &ppp_count, &ife_rd_count); - if (!ipp_count && !rdi_count && !ppp_count) { - CAM_ERR(CAM_ISP, "No PIX or RDI or PPP resource"); + if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count) { + CAM_ERR(CAM_ISP, "No PIX or RDI or PPP or IFE RD resource"); return -EINVAL; } @@ -1502,19 +1824,26 @@ static int cam_ife_mgr_acquire_hw_for_ctx( /* get ife src resource */ - rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port); + if (ife_rd_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port); + rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port); + } else { + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port); + } + if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE SRC resource Failed"); goto err; } + CAM_DBG(CAM_ISP, "Acquiring IFE OUT resource..."); rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed"); goto err; } - *num_pix_port += ipp_count + ppp_count; + *num_pix_port += ipp_count + ppp_count + ife_rd_count; *num_rdi_port += rdi_count; return 0; @@ -1538,8 +1867,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete(&ctx->config_done_complete); CAM_DBG(CAM_ISP, - "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", - handle, userdata, status, cookie); + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); } else { CAM_WARN(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", @@ -1618,8 +1947,22 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + if (rc) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + goto free_ctx; + } + /* acquire HW resources */ for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + goto free_res; + } + in_port_length = sizeof(struct cam_isp_in_port_info) + (in_port->num_out_res - 1) * sizeof(struct cam_isp_out_port_info); @@ -1630,6 +1973,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) rc = -EINVAL; goto free_res; } + CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type); rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, &num_pix_port_per_in, &num_rdi_port_per_in); total_pix_port += num_pix_port_per_in; @@ -1745,6 +2089,8 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT) continue; + CAM_DBG(CAM_ISP, "acquire no = %d total = %d", i, + acquire_args->num_acq); CAM_DBG(CAM_ISP, "start copy from user handle %lld with len = %d", isp_resource[i].res_hdl, @@ -1882,7 +2228,8 @@ static int cam_isp_blob_bw_update( if (!hw_mgr_res->hw_res[i]) continue; - if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD)) if (i == CAM_ISP_HW_SPLIT_LEFT) { if (camif_l_bw_updated) continue; @@ -2013,8 +2360,9 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, } } - CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d", - ctx->ctx_index, cfg->num_hw_update_entries); + CAM_DBG(CAM_ISP, + "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); if (cfg->num_hw_update_entries > 0) { cdm_cmd = ctx->cdm_cmd; @@ -2047,21 +2395,21 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, msecs_to_jiffies(30)); if (rc <= 0) { CAM_ERR(CAM_ISP, - "config done completion timeout for req_id=%llu rc = %d", - cfg->request_id, rc); + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); if (rc == 0) rc = -ETIMEDOUT; } else { rc = 0; CAM_DBG(CAM_ISP, - "config done Success for req_id=%llu", - cfg->request_id); + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); } } } else { CAM_ERR(CAM_ISP, "No commands to config"); } - CAM_DBG(CAM_ISP, "Exit"); + CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); return rc; } @@ -2134,6 +2482,11 @@ static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); } + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + /* IFE out resources */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); @@ -2236,11 +2589,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) CAM_DBG(CAM_ISP, "Halting CSIDs"); - CAM_DBG(CAM_ISP, "Going to stop IFE Out"); - - /* IFE out resources */ - for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) - cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); /* get master base index first */ for (i = 0; i < ctx->num_base; i++) { if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { @@ -2249,15 +2597,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) } } - CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); - - /* IFE mux in resources */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); - } - - cam_tasklet_stop(ctx->common.tasklet_info); - /* * If Context does not have PIX resources and has only RDI resource * then take the first base index. @@ -2297,6 +2636,26 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, csid_halt_type); } + CAM_DBG(CAM_ISP, "Going to stop IFE Out"); + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + cam_tasklet_stop(ctx->common.tasklet_info); + cam_ife_mgr_pause_hw(ctx); if (stop_isp->stop_only) @@ -2386,6 +2745,17 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) } CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); + + /* Start IFE BUS RD device */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + /* Start the IFE mux in devices */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); @@ -2536,6 +2906,18 @@ start_only: } } + CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); /* Start the IFE mux in devices */ @@ -2595,7 +2977,6 @@ safe_disable: deinit_hw: cam_ife_hw_mgr_deinit_hw(ctx); - ctx->init_done = false; tasklet_stop: cam_tasklet_stop(ctx->common.tasklet_info); @@ -2667,6 +3048,78 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, return rc; } +static int cam_isp_blob_fe_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_fe_config *fe_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + int rc = -EINVAL; + uint32_t i; + struct cam_vfe_fe_update_args fe_upd_args; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + &fe_upd_args, + sizeof( + struct cam_fe_config)); + if (rc) + CAM_ERR(CAM_ISP, "fs Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + &fe_upd_args, + sizeof( + struct cam_vfe_fe_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "fe Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + return rc; +} + static int cam_isp_blob_ubwc_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -3004,7 +3457,7 @@ static int cam_isp_blob_clock_update( camif_r_clk_updated = true; } } else if ((hw_mgr_res->res_id >= - CAM_ISP_HW_VFE_IN_RDI0) && (hw_mgr_res->res_id + CAM_ISP_HW_VFE_IN_RD) && (hw_mgr_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) for (j = 0; j < clock_config->num_rdi; j++) clk_rate = max(clock_config->rdi_hz[j], @@ -3043,6 +3496,53 @@ static int cam_isp_blob_clock_update( return rc; } +void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap) +{ + + switch (resource_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + case CAM_ISP_IFE_OUT_RES_DS4: + case CAM_ISP_IFE_OUT_RES_DS16: + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + case CAM_ISP_IFE_OUT_RES_FD: + case CAM_ISP_IFE_OUT_RES_PDAF: + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + case CAM_ISP_IFE_OUT_RES_STATS_BF: + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + case CAM_ISP_IFE_OUT_RES_STATS_RS: + case CAM_ISP_IFE_OUT_RES_STATS_CS: + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + case CAM_ISP_IFE_IN_RES_RD: + set_bit(CAM_IFE_REG_UPD_CMD_PIX_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_0: + set_bit(CAM_IFE_REG_UPD_CMD_RDI0_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_1: + set_bit(CAM_IFE_REG_UPD_CMD_RDI1_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_2: + set_bit(CAM_IFE_REG_UPD_CMD_RDI2_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_3: + set_bit(CAM_IFE_REG_UPD_CMD_RDI3_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_2PD: + set_bit(CAM_IFE_REG_UPD_CMD_DUAL_PD_BIT, + res_bitmap); + break; + default: + CAM_ERR(CAM_ISP, "Invalid resource"); + break; + } +} + static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -3069,6 +3569,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return -EINVAL; } + CAM_DBG(CAM_ISP, "FS2: BLOB Type: %d", blob_type); switch (blob_type) { case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: { struct cam_isp_resource_hfr_config *hfr_config = @@ -3131,6 +3632,16 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "Clock Update Failed"); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: { + struct cam_fe_config *fe_config = + (struct cam_fe_config *)blob_data; + rc = cam_isp_blob_fe_update(blob_type, blob_info, + fe_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); + } + break; + default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; @@ -3166,7 +3677,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map; hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv; - rc = cam_packet_util_validate_packet(prepare->packet); + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); if (rc) return rc; @@ -3227,7 +3739,10 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, hw_mgr->mgr_common.img_iommu_hdl_secure, prepare, ctx->base[i].idx, &kmd_buf, ctx->res_list_ife_out, - CAM_IFE_HW_OUT_RES_MAX, fill_fence); + &ctx->res_list_ife_in_rd, + CAM_IFE_HW_OUT_RES_MAX, fill_fence, + &ctx->res_bitmap, + fill_res_bitmap); if (rc) { CAM_ERR(CAM_ISP, @@ -3268,7 +3783,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, /*Add reg update */ rc = cam_isp_add_reg_update(prepare, &ctx->res_list_ife_src, - ctx->base[i].idx, &kmd_buf); + ctx->base[i].idx, &kmd_buf, ctx->is_fe_enable, + ctx->res_bitmap); if (rc) { CAM_ERR(CAM_ISP, "Add Reg_update cmd Failed i=%d, idx=%d, rc=%d", @@ -3276,6 +3792,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, goto end; } } + ctx->res_bitmap = 0; end: return rc; @@ -3356,7 +3873,8 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, if (!io_cfg[i].mem_handle[j]) break; - if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + if (pf_buf_info && + GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == GET_FD_FROM_HANDLE(pf_buf_info)) { CAM_INFO(CAM_ISP, "Found PF at port: 0x%x mem 0x%x fd: 0x%x", @@ -3391,9 +3909,10 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_ISP, - "pln %d w %d h %d s 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", + "pln %d w %d h %d s %u size 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", j, io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, (unsigned int)src_buf_size, (unsigned int)iova_addr, (unsigned int)iova_addr + @@ -3434,12 +3953,6 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->u.internal_args; switch (isp_hw_cmd_args->cmd_type) { - case CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT: - if (ctx->is_rdi_only_context) - isp_hw_cmd_args->u.is_rdi_only_context = 1; - else - isp_hw_cmd_args->u.is_rdi_only_context = 0; - break; case CAM_ISP_HW_MGR_CMD_PAUSE_HW: cam_ife_mgr_pause_hw(ctx); break; @@ -3450,6 +3963,14 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) cam_ife_mgr_sof_irq_debug(ctx, isp_hw_cmd_args->u.sof_irq_enable); break; + case CAM_ISP_HW_MGR_CMD_CTX_TYPE: + if (ctx->is_fe_enable) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2; + else if (ctx->is_rdi_only_context) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; + else + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -3485,17 +4006,25 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i] || - (i == CAM_ISP_HW_SPLIT_RIGHT)) + if (!hw_mgr_res->hw_res[i]) continue; + /* * Get the SOF time stamp from left resource only. * Left resource is master for dual vfe case and * Rdi only context case left resource only hold * the RDI resource */ + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; if (hw_intf->hw_ops.process_cmd) { + /* + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient + */ + csid_get_time.node_res = hw_mgr_res->hw_res[i]; rc = hw_intf->hw_ops.process_cmd( @@ -3504,23 +4033,16 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( &csid_get_time, sizeof( struct cam_csid_get_time_stamp_args)); - if (!rc) { + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { *time_stamp = csid_get_time.time_stamp_val; *boot_time_stamp = csid_get_time.boot_timestamp; } - /* - * Single VFE case, Get the time stamp from available - * one csid hw in the context - * Dual VFE case, get the time stamp from master(left) - * would be sufficient - */ - goto end; } } } -end: + if (rc) CAM_ERR(CAM_ISP, "Getting sof time stamp failed"); @@ -3790,6 +4312,8 @@ static int cam_ife_hw_mgr_get_err_type( core_idx = evt_payload->core_index; evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + evt_payload->enable_reg_dump = + g_ife_hw_mgr.debug_cfg.enable_reg_dump; list_for_each_entry(isp_ife_camif_res, &ife_hwr_mgr_ctx->res_list_ife_src, list) { @@ -3860,23 +4384,26 @@ static int cam_ife_hw_mgr_handle_camif_error( error_status = cam_ife_hw_mgr_get_err_type(ife_hwr_mgr_ctx, evt_payload); - - if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) - return error_status; + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { + rc = error_status; + goto end; + } switch (error_status) { case CAM_ISP_HW_ERROR_OVERFLOW: case CAM_ISP_HW_ERROR_P2I_ERROR: case CAM_ISP_HW_ERROR_VIOLATION: CAM_ERR(CAM_ISP, "Enter: error_type (%d)", error_status); - rc = -EFAULT; - + rc = error_status; if (g_ife_hw_mgr.debug_cfg.enable_recovery) error_event_data.recovery_enabled = true; error_event_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + error_event_data.enable_reg_dump = + g_ife_hw_mgr.debug_cfg.enable_reg_dump; + cam_ife_hw_mgr_find_affected_ctx(ife_hwr_mgr_ctx, &error_event_data, core_idx, @@ -3897,6 +4424,7 @@ static int cam_ife_hw_mgr_handle_camif_error( break; } +end: return rc; } @@ -3946,6 +4474,7 @@ static int cam_ife_hw_mgr_handle_reg_update( case CAM_ISP_HW_VFE_IN_CAMIF_LITE: break; case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: if (ife_src_res->is_dual_vfe) /* It checks for slave core RUP ACK*/ hw_res = ife_src_res->hw_res[1]; @@ -3999,7 +4528,8 @@ static int cam_ife_hw_mgr_handle_reg_update( rup_status = hw_res->bottom_half_handler( hw_res, evt_payload); - if (!ife_hwr_mgr_ctx->is_rdi_only_context) + if (ife_hwr_mgr_ctx->is_rdi_only_context == 0 && + ife_hwr_mgr_ctx->is_fe_enable == false) continue; if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) @@ -4106,9 +4636,10 @@ static int cam_ife_hw_mgr_handle_epoch_for_camif_hw_res( list_for_each_entry(isp_ife_camif_res, &ife_hwr_mgr_ctx->res_list_ife_src, list) { if ((isp_ife_camif_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) - || (isp_ife_camif_res->res_id != - CAM_ISP_HW_VFE_IN_CAMIF)) + || (isp_ife_camif_res->res_id > + CAM_ISP_HW_VFE_IN_RD)) { continue; + } hw_res_l = isp_ife_camif_res->hw_res[0]; hw_res_r = isp_ife_camif_res->hw_res[1]; @@ -4341,7 +4872,8 @@ static int cam_ife_hw_mgr_handle_sof( hw_res, evt_payload); /* check if it is rdi only context */ - if (ife_hw_mgr_ctx->is_rdi_only_context) { + if (ife_hw_mgr_ctx->is_fe_enable || + ife_hw_mgr_ctx->is_rdi_only_context) { if (!sof_status && !sof_sent) { cam_ife_mgr_cmd_get_sof_timestamp( ife_hw_mgr_ctx, @@ -4352,7 +4884,7 @@ static int cam_ife_hw_mgr_handle_sof( ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); - CAM_DBG(CAM_ISP, "sof_status = %d", + CAM_DBG(CAM_ISP, "RDI sof_status = %d", sof_status); sof_sent = true; @@ -4362,6 +4894,7 @@ static int cam_ife_hw_mgr_handle_sof( break; case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: sof_status = cam_ife_hw_mgr_process_camif_sof( ife_src_res, ife_hw_mgr_ctx, evt_payload); if (!sof_status && !sof_sent) { @@ -4832,6 +5365,14 @@ static int cam_ife_hw_mgr_debug_register(void) return -ENOMEM; } + if (!debugfs_create_u32("enable_reg_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_reg_dump"); + goto err; + } + if (!debugfs_create_file("ife_csid_debug", 0644, g_ife_hw_mgr.debug_cfg.dentry, NULL, @@ -4975,6 +5516,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_cid); INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_csid); INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_src); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in_rd); ctx_pool = &g_ife_hw_mgr.ctx_pool[i]; for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) { res_list_ife_out = &ctx_pool->res_list_ife_out[j]; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index cf1e425558f3..bf5f1527caa4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,7 @@ enum cam_ife_hw_mgr_res_type { CAM_IFE_HW_MGR_RES_CID, CAM_IFE_HW_MGR_RES_CSID, CAM_IFE_HW_MGR_RES_IFE_SRC, + CAM_IFE_HW_MGR_RES_IFE_IN_RD, CAM_IFE_HW_MGR_RES_IFE_OUT, }; @@ -87,6 +88,7 @@ struct ctx_base_info { * @csid_debug: csid debug information * @enable_recovery: enable recovery * @enable_diag_sensor_status: enable sensor diagnosis status + * @enable_reg_dump: enable register dump on error * */ struct cam_ife_hw_mgr_debug { @@ -94,6 +96,7 @@ struct cam_ife_hw_mgr_debug { uint64_t csid_debug; uint32_t enable_recovery; uint32_t camif_debug; + uint32_t enable_reg_dump; }; /** @@ -108,6 +111,7 @@ struct cam_ife_hw_mgr_debug { * one. * @res_list_csid: CSID resource list * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path * @res_list_ife_out: IFE output resoruces array * @free_res_list: Free resources list for the branch node * @res_pool: memory storage for the free resource list @@ -128,6 +132,8 @@ struct cam_ife_hw_mgr_debug { * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path is enabled + * @res_bitmap fill resource bitmap for which rup to be set */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -141,6 +147,7 @@ struct cam_ife_hw_mgr_ctx { struct list_head res_list_ife_cid; struct list_head res_list_ife_csid; struct list_head res_list_ife_src; + struct list_head res_list_ife_in_rd; struct cam_ife_hw_mgr_res res_list_ife_out[ CAM_IFE_HW_OUT_RES_MAX]; @@ -162,6 +169,8 @@ struct cam_ife_hw_mgr_ctx { uint32_t is_rdi_only_context; struct completion config_done_complete; bool init_done; + bool is_fe_enable; + unsigned long res_bitmap; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index cd1d024148ff..0b3c3874a704 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -105,7 +105,7 @@ static int cam_isp_update_dual_config( struct cam_isp_hw_dual_isp_update_args dual_isp_update_args; uint32_t outport_id; uint32_t ports_plane_idx; - size_t len = 0; + size_t len = 0, remain_len = 0; uint32_t *cpu_addr; uint32_t i, j; @@ -117,9 +117,22 @@ static int cam_isp_update_dual_config( if (rc) return rc; + if ((len < sizeof(struct cam_isp_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_dual_config)))) { + CAM_ERR(CAM_UTIL, "not enough buffer provided"); + return -EINVAL; + } + remain_len = len - cmd_desc->offset; cpu_addr += (cmd_desc->offset / 4); dual_config = (struct cam_isp_dual_config *)cpu_addr; + if ((dual_config->num_ports * + sizeof(struct cam_isp_dual_stripe_config)) > + (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { + CAM_ERR(CAM_UTIL, "not enough buffer for all the dual configs"); + return -EINVAL; + } for (i = 0; i < dual_config->num_ports; i++) { if (i >= CAM_ISP_IFE_OUT_RES_MAX) { @@ -430,8 +443,11 @@ int cam_isp_add_io_buffers( uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence) + bool fill_fence, + unsigned long *res_bitmap, + cam_fill_res_bitmap fill_res_bitmap) { int rc = 0; uint64_t io_addr[CAM_PACKET_MAX_PLANES]; @@ -440,6 +456,7 @@ int cam_isp_add_io_buffers( struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_isp_hw_get_cmd_update update_buf; struct cam_isp_hw_get_wm_update wm_update; + struct cam_isp_hw_get_wm_update bus_rd_update; struct cam_hw_fence_map_entry *out_map_entries; struct cam_hw_fence_map_entry *in_map_entries; uint32_t kmd_buf_remain_size; @@ -517,6 +534,15 @@ int cam_isp_add_io_buffers( CAM_DBG(CAM_ISP, "configure input io with fill fence %d", fill_fence); + if (!list_empty(res_list_ife_in_rd)) { + hw_mgr_res = + list_first_entry(res_list_ife_in_rd, + struct cam_ife_hw_mgr_res, list); + } else { + CAM_ERR(CAM_ISP, + "No IFE in Read resource"); + return -EINVAL; + } in_map_entries = &prepare->in_map_entries[num_in_buf]; if (fill_fence) { @@ -533,7 +559,6 @@ int cam_isp_add_io_buffers( return -EINVAL; } } - continue; } else { CAM_ERR(CAM_ISP, "Invalid io config direction :%d", io_cfg[i].direction); @@ -541,7 +566,8 @@ int cam_isp_add_io_buffers( } CAM_DBG(CAM_ISP, "setup mem io"); - for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_OUTPUT; j++) { if (!hw_mgr_res->hw_res[j]) continue; @@ -656,6 +682,118 @@ int cam_isp_add_io_buffers( } io_cfg_used_bytes += update_buf.cmd.used_bytes; } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_INPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + bus_rd_update.image_buf = io_addr; + bus_rd_update.num_buf = plane_id; + bus_rd_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.rm_update = &bus_rd_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + + fill_res_bitmap(io_cfg[i].resource_type, res_bitmap); } CAM_DBG(CAM_ISP, "io_cfg_used_bytes %d, fill_fence %d", @@ -694,13 +832,16 @@ int cam_isp_add_reg_update( struct cam_hw_prepare_update_args *prepare, struct list_head *res_list_isp_src, uint32_t base_idx, - struct cam_kmd_buf_info *kmd_buf_info) + struct cam_kmd_buf_info *kmd_buf_info, + bool is_fe_en, + unsigned long res_bitmap) { int rc = -EINVAL; struct cam_isp_resource_node *res; struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_hw_update_entry *hw_entry; struct cam_isp_hw_get_cmd_update get_regup; + struct cam_isp_hw_rup_data rup_data; uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; hw_entry = prepare->hw_update_entries; @@ -746,6 +887,9 @@ int cam_isp_add_reg_update( get_regup.cmd.size = kmd_buf_remain_size; get_regup.cmd_type = CAM_ISP_HW_CMD_GET_REG_UPDATE; get_regup.res = res; + rup_data.is_fe_enable = is_fe_en; + rup_data.res_bitmap = res_bitmap; + get_regup.rup_data = &rup_data; rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index 9c1caa03e06c..806c2c657165 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -123,8 +123,11 @@ int cam_isp_add_command_buffers( * @base_idx: Base or dev index of the IFE/VFE HW instance * @kmd_buf_info: Kmd buffer to store the change base command * @res_list_isp_out: IFE /VFE out resource list + * @res_list_ife_in_rd: IFE /VFE in rd resource list * @size_isp_out: Size of the res_list_isp_out array * @fill_fence: If true, Fence map table will be filled + * @res_bitmap resource bitmap to be set for rup + * @fill_res_bitmap callback function to set resource bitmap * * @return: 0 for success * -EINVAL for Fail @@ -136,8 +139,11 @@ int cam_isp_add_io_buffers( uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence); + bool fill_fence, + unsigned long *res_bitmap, + cam_fill_res_bitmap fill_res_bitmap); /* * cam_isp_add_reg_update() @@ -150,6 +156,9 @@ int cam_isp_add_io_buffers( * @res_list_isp_src: Resource list for IFE/VFE source * @base_idx: Base or dev index of the IFE/VFE HW instance * @kmd_buf_info: Kmd buffer to store the change base command + * @is_fe_enable If fetch engine enable + * @res_bitmap resource bitmap to be set for rup + * * @return: 0 for success * -EINVAL for Fail */ @@ -157,6 +166,8 @@ int cam_isp_add_reg_update( struct cam_hw_prepare_update_args *prepare, struct list_head *res_list_isp_src, uint32_t base_idx, - struct cam_kmd_buf_info *kmd_buf_info); + struct cam_kmd_buf_info *kmd_buf_info, + bool is_fe_enable, + unsigned long res_bitmap); #endif /*_CAM_ISP_HW_PARSER_H */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index e418fa97081d..c5808d45b0b1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -617,7 +617,7 @@ static void cam_irq_controller_th_processing( evt_handler->bottom_half, &bh_cmd); if (rc || !bh_cmd) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "Can't get bh payload"); + "No payload, IRQ handling frozen"); continue; } } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 1a0f1ecab7b6..e9bcc98a8956 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,16 @@ #include <uapi/media/cam_isp.h> #include "cam_hw_mgr_intf.h" +/* + * bit position in resource bitmap + */ +#define CAM_IFE_REG_UPD_CMD_PIX_BIT 0 +#define CAM_IFE_REG_UPD_CMD_RDI0_BIT 1 +#define CAM_IFE_REG_UPD_CMD_RDI1_BIT 2 +#define CAM_IFE_REG_UPD_CMD_RDI2_BIT 3 +#define CAM_IFE_REG_UPD_CMD_RDI3_BIT 4 +#define CAM_IFE_REG_UPD_CMD_DUAL_PD_BIT 5 + /* MAX IFE instance */ #define CAM_IFE_HW_NUM_MAX 4 #define CAM_IFE_RDI_NUM_MAX 4 @@ -186,11 +196,13 @@ struct cam_isp_hw_eof_event_data { * @timestamp: Timestamp for the error event * @recovery_enabled: Identifies if the context needs to recover & reapply * this request + * @enable_reg_dump: enable register dump */ struct cam_isp_hw_error_event_data { uint32_t error_type; uint64_t timestamp; bool recovery_enabled; + bool enable_reg_dump; }; /* enum cam_isp_hw_mgr_command - Hardware manager command type */ @@ -199,20 +211,28 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_PAUSE_HW, CAM_ISP_HW_MGR_CMD_RESUME_HW, CAM_ISP_HW_MGR_CMD_SOF_DEBUG, + CAM_ISP_HW_MGR_CMD_CTX_TYPE, CAM_ISP_HW_MGR_CMD_MAX, }; +enum cam_isp_ctx_type { + CAM_ISP_CTX_FS2 = 1, + CAM_ISP_CTX_RDI, + CAM_ISP_CTX_PIX, + CAM_ISP_CTX_MAX, +}; /** * struct cam_isp_hw_cmd_args - Payload for hw manager command * * @cmd_type HW command type - * @get_context Get context type information + * @sof_irq_enable To debug if SOF irq is enabled + * @ctx_type RDI_ONLY, PIX and RDI, or FS2 */ struct cam_isp_hw_cmd_args { - uint32_t cmd_type; + uint32_t cmd_type; union { - uint32_t is_rdi_only_context; uint32_t sof_irq_enable; + uint32_t ctx_type; } u; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c deleted file mode 100644 index 70223f1427f5..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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/module.h> -#include "cam_ife_csid_core.h" -#include "cam_ife_csid170.h" -#include "cam_ife_csid_dev.h" - -#define CAM_CSID_DRV_NAME "csid_170" -#define CAM_CSID_VERSION_V170 0x10070000 - -static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { - .csid_reg = &cam_ife_csid_170_reg_offset, - .hw_dts_version = CAM_CSID_VERSION_V170, -}; - -static const struct of_device_id cam_ife_csid170_dt_match[] = { - { - .compatible = "qcom,csid170", - .data = &cam_ife_csid170_hw_info, - }, - {} -}; - -MODULE_DEVICE_TABLE(of, cam_ife_csid170_dt_match); - -static struct platform_driver cam_ife_csid170_driver = { - .probe = cam_ife_csid_probe, - .remove = cam_ife_csid_remove, - .driver = { - .name = CAM_CSID_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = cam_ife_csid170_dt_match, - .suppress_bind_attrs = true, - }, -}; - -static int __init cam_ife_csid170_init_module(void) -{ - return platform_driver_register(&cam_ife_csid170_driver); -} - -static void __exit cam_ife_csid170_exit_module(void) -{ - platform_driver_unregister(&cam_ife_csid170_driver); -} - -module_init(cam_ife_csid170_init_module); -module_exit(cam_ife_csid170_exit_module); -MODULE_DESCRIPTION("CAM IFE_CSID170 driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h index 85fec0f15dcd..576e8cb8d3b8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -222,6 +222,7 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; static struct cam_ife_csid_csi2_tpg_reg_offset @@ -273,6 +274,7 @@ static struct cam_ife_csid_common_reg_offset .num_rdis = 3, .num_pix = 1, .num_ppp = 0, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h index 4fdc518c0385..42f0f290a166 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,56 +10,93 @@ * GNU General Public License for more details. */ -#ifndef _CAM_IFE_CSID_LITE170_H_ -#define _CAM_IFE_CSID_LITE170_H_ +#ifndef _CAM_IFE_CSID_175_H_ +#define _CAM_IFE_CSID_175_H_ + #include "cam_ife_csid_core.h" -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_0_reg_offset = { +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, - .csid_rdi_irq_status_addr = 0x30, - .csid_rdi_irq_mask_addr = 0x34, - .csid_rdi_irq_clear_addr = 0x38, - .csid_rdi_irq_set_addr = 0x3c, - .csid_rdi_cfg0_addr = 0x200, - .csid_rdi_cfg1_addr = 0x204, - .csid_rdi_ctrl_addr = 0x208, - .csid_rdi_frm_drop_pattern_addr = 0x20c, - .csid_rdi_frm_drop_period_addr = 0x210, - .csid_rdi_irq_subsample_pattern_addr = 0x214, - .csid_rdi_irq_subsample_period_addr = 0x218, - .csid_rdi_rpp_hcrop_addr = 0x21c, - .csid_rdi_rpp_vcrop_addr = 0x220, - .csid_rdi_rpp_pix_drop_pattern_addr = 0x224, - .csid_rdi_rpp_pix_drop_period_addr = 0x228, - .csid_rdi_rpp_line_drop_pattern_addr = 0x22c, - .csid_rdi_rpp_line_drop_period_addr = 0x230, - .csid_rdi_rst_strobes_addr = 0x240, - .csid_rdi_status_addr = 0x250, - .csid_rdi_misr_val0_addr = 0x254, - .csid_rdi_misr_val1_addr = 0x258, - .csid_rdi_misr_val2_addr = 0x25c, - .csid_rdi_misr_val3_addr = 0x260, - .csid_rdi_format_measure_cfg0_addr = 0x270, - .csid_rdi_format_measure_cfg1_addr = 0x274, - .csid_rdi_format_measure0_addr = 0x278, - .csid_rdi_format_measure1_addr = 0x27c, - .csid_rdi_format_measure2_addr = 0x280, - .csid_rdi_timestamp_curr0_sof_addr = 0x290, - .csid_rdi_timestamp_curr1_sof_addr = 0x294, - .csid_rdi_timestamp_prev0_sof_addr = 0x298, - .csid_rdi_timestamp_prev1_sof_addr = 0x29c, - .csid_rdi_timestamp_curr0_eof_addr = 0x2a0, - .csid_rdi_timestamp_curr1_eof_addr = 0x2a4, - .csid_rdi_timestamp_prev0_eof_addr = 0x2a8, - .csid_rdi_timestamp_prev1_eof_addr = 0x2ac, - .csid_rdi_byte_cntr_ping_addr = 0x2e0, - .csid_rdi_byte_cntr_pong_addr = 0x2e4, + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_1_reg_offset = { +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_0_reg_offset = { .csid_rdi_irq_status_addr = 0x40, .csid_rdi_irq_mask_addr = 0x44, .csid_rdi_irq_clear_addr = 0x48, @@ -100,9 +137,7 @@ static struct cam_ife_csid_rdi_reg_offset .csid_rdi_byte_cntr_pong_addr = 0x3e4, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_2_reg_offset = { - +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_1_reg_offset = { .csid_rdi_irq_status_addr = 0x50, .csid_rdi_irq_mask_addr = 0x54, .csid_rdi_irq_clear_addr = 0x58, @@ -120,7 +155,6 @@ static struct cam_ife_csid_rdi_reg_offset .csid_rdi_rpp_pix_drop_period_addr = 0x428, .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, .csid_rdi_rpp_line_drop_period_addr = 0x430, - .csid_rdi_yuv_chroma_conversion_addr = 0x434, .csid_rdi_rst_strobes_addr = 0x440, .csid_rdi_status_addr = 0x450, .csid_rdi_misr_val0_addr = 0x454, @@ -144,9 +178,7 @@ static struct cam_ife_csid_rdi_reg_offset .csid_rdi_byte_cntr_pong_addr = 0x4e4, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_3_reg_offset = { - +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_2_reg_offset = { .csid_rdi_irq_status_addr = 0x60, .csid_rdi_irq_mask_addr = 0x64, .csid_rdi_irq_clear_addr = 0x68, @@ -189,8 +221,7 @@ static struct cam_ife_csid_rdi_reg_offset }; static struct cam_ife_csid_csi2_rx_reg_offset - cam_ife_csid_lite_170_csi2_reg_offset = { - + cam_ife_csid_175_csi2_reg_offset = { .csid_csi2_rx_irq_status_addr = 0x20, .csid_csi2_rx_irq_mask_addr = 0x24, .csid_csi2_rx_irq_clear_addr = 0x28, @@ -232,12 +263,11 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; - static struct cam_ife_csid_csi2_tpg_reg_offset - cam_ife_csid_lite_170_tpg_reg_offset = { - + cam_ife_csid_175_tpg_reg_offset = { /*CSID TPG control */ .csid_tpg_ctrl_addr = 0x600, .csid_tpg_vc_cfg0_addr = 0x604, @@ -257,16 +287,14 @@ static struct cam_ife_csid_csi2_tpg_reg_offset .csid_tpg_cgen_n_y1_addr = 0x664, .csid_tpg_cgen_n_y2_addr = 0x668, - /*configurations */ + /* configurations */ .tpg_dtn_cfg_offset = 0xc, .tpg_cgen_cfg_offset = 0x20, .tpg_cpas_ife_reg_offset = 0x28, }; - static struct cam_ife_csid_common_reg_offset - cam_csid_lite_170_cmn_reg_offset = { - + cam_ife_csid_175_cmn_reg_offset = { .csid_hw_version_addr = 0x0, .csid_cfg0_addr = 0x4, .csid_ctrl_addr = 0x8, @@ -284,8 +312,10 @@ static struct cam_ife_csid_common_reg_offset .major_version = 1, .minor_version = 7, .version_incr = 0, - .no_rdis = 4, - .no_pix = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, @@ -301,19 +331,23 @@ static struct cam_ife_csid_common_reg_offset .crop_shift = 16, .ipp_irq_mask_all = 0x7FFF, .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, }; -struct cam_ife_csid_reg_offset cam_ife_csid_lite_170_reg_offset = { - .cmn_reg = &cam_csid_lite_170_cmn_reg_offset, - .csi2_reg = &cam_ife_csid_lite_170_csi2_reg_offset, - .ipp_reg = NULL, +static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = { + .cmn_reg = &cam_ife_csid_175_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_ppp_reg_offset, .rdi_reg = { - &cam_ife_csid_lite_170_rdi_0_reg_offset, - &cam_ife_csid_lite_170_rdi_1_reg_offset, - &cam_ife_csid_lite_170_rdi_2_reg_offset, - &cam_ife_csid_lite_170_rdi_3_reg_offset, + &cam_ife_csid_175_rdi_0_reg_offset, + &cam_ife_csid_175_rdi_1_reg_offset, + &cam_ife_csid_175_rdi_2_reg_offset, + NULL, }, - .tpg_reg = &cam_ife_csid_lite_170_tpg_reg_offset, + .tpg_reg = &cam_ife_csid_175_tpg_reg_offset, }; -#endif /*_CAM_IFE_CSID_LITE170_H_ */ +#endif /*_CAM_IFE_CSID_175_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h new file mode 100644 index 000000000000..8a78fe0b9b0d --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -0,0 +1,369 @@ +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CAM_IFE_CSID_175_200_H_ +#define _CAM_IFE_CSID_175_200_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_200_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + .csid_csi2_rx_de_scramble_type3_cfg0_addr = 0x170, + .csid_csi2_rx_de_scramble_type3_cfg1_addr = 0x174, + .csid_csi2_rx_de_scramble_type2_cfg0_addr = 0x178, + .csid_csi2_rx_de_scramble_type2_cfg1_addr = 0x17c, + .csid_csi2_rx_de_scramble_type1_cfg0_addr = 0x180, + .csid_csi2_rx_de_scramble_type1_cfg1_addr = 0x184, + .csid_csi2_rx_de_scramble_type0_cfg0_addr = 0x188, + .csid_csi2_rx_de_scramble_type0_cfg1_addr = 0x18c, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_200_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_200_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 5, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0xFFFF, + .rdi_irq_mask_all = 0xFFFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = { + .cmn_reg = &cam_ife_csid_175_200_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_200_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_200_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_200_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_200_rdi_0_reg_offset, + &cam_ife_csid_175_200_rdi_1_reg_offset, + &cam_ife_csid_175_200_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_200_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_200_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c index f894daa846b9..80701bf6f8d0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,21 +14,42 @@ #include <linux/module.h> #include "cam_ife_csid_core.h" #include "cam_ife_csid170.h" +#include "cam_ife_csid175.h" +#include "cam_ife_csid175_200.h" #include "cam_ife_csid_dev.h" #define CAM_CSID_DRV_NAME "csid_17x" #define CAM_CSID_VERSION_V170 0x10070000 +#define CAM_CSID_VERSION_V175 0x10070050 static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { .csid_reg = &cam_ife_csid_170_reg_offset, .hw_dts_version = CAM_CSID_VERSION_V170, }; +static struct cam_ife_csid_hw_info cam_ife_csid175_hw_info = { + .csid_reg = &cam_ife_csid_175_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_200_hw_info = { + .csid_reg = &cam_ife_csid_175_200_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + static const struct of_device_id cam_ife_csid17x_dt_match[] = { { .compatible = "qcom,csid170", .data = &cam_ife_csid170_hw_info, }, + { + .compatible = "qcom,csid175", + .data = &cam_ife_csid175_hw_info, + }, + { + .compatible = "qcom,csid175_200", + .data = &cam_ife_csid175_200_hw_info, + }, {} }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index f3a15558bb1b..779d04460e2c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -67,6 +67,7 @@ static int cam_ife_csid_is_ipp_ppp_format_supported( case CAM_FORMAT_DPCM_12_8_12: case CAM_FORMAT_DPCM_14_8_14: case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_DPCM_12_10_12: rc = 0; break; default: @@ -206,6 +207,10 @@ static int cam_ife_csid_get_format_rdi( *decode_fmt = 0xC; *plain_fmt = 0x1; break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; default: rc = -EINVAL; break; @@ -280,6 +285,10 @@ static int cam_ife_csid_get_format_ipp_ppp( *decode_fmt = 0xC; *plain_fmt = 0x1; break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; default: CAM_ERR(CAM_ISP, "Unsupported format %d", in_format); @@ -309,6 +318,9 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, if (cid_data->vc == vc && cid_data->dt == dt) { cid_data->cnt++; *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); return 0; } } @@ -418,8 +430,23 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); - /* perform the top CSID HW and SW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb_sw_all, + /* perform the top CSID HW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } + + /* perform the SW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); @@ -433,6 +460,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) rc = -ETIMEDOUT; } + usleep_range(3000, 3010); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); if (val != 0) @@ -647,12 +675,12 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); goto end; } - CAM_DBG(CAM_ISP, "HW version: %d", camera_hw_version); + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); switch (camera_hw_version) { case CAM_CPAS_TITAN_NONE: case CAM_CPAS_TITAN_MAX: - CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version); + CAM_ERR(CAM_ISP, "Invalid HW version: %x", camera_hw_version); break; case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: @@ -1093,6 +1121,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) int rc = -EINVAL; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; /* Check for refcount */ if (!csid_hw->hw_info->open_count) { @@ -1127,6 +1156,9 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 0; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; @@ -1327,10 +1359,12 @@ static int cam_ife_csid_enable_csi2( return rc; /* rx cfg0 */ + val = 0; val = (csid_hw->csi2_rx_cfg.lane_num - 1) | (csid_hw->csi2_rx_cfg.lane_cfg << 4) | (csid_hw->csi2_rx_cfg.lane_type << 24); - val |= (csid_hw->csi2_rx_cfg.phy_sel & 0x3) << 20; + val |= (csid_hw->csi2_rx_cfg.phy_sel & + csid_reg->csi2_reg->csi2_rx_phy_num_mask) << 20; cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); @@ -1753,6 +1787,9 @@ static int cam_ife_csid_enable_pxl_path( /* Enable the required pxl path interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + if (pxl_reg->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) val |= CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) @@ -1775,6 +1812,7 @@ static int cam_ife_csid_disable_pxl_path( enum cam_ife_csid_halt_cmd stop_cmd) { int rc = 0; + uint32_t val = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; struct cam_ife_csid_path_cfg *path_data; @@ -1835,6 +1873,17 @@ static int cam_ife_csid_disable_pxl_path( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_irq_mask_addr); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + /* configure Halt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + return rc; } @@ -2063,6 +2112,9 @@ static int cam_ife_csid_enable_rdi_path( /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + if (csid_reg->rdi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) val |= CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) @@ -2083,7 +2135,7 @@ static int cam_ife_csid_disable_rdi_path( enum cam_ife_csid_halt_cmd stop_cmd) { int rc = 0; - uint32_t id; + uint32_t id, val = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; @@ -2128,6 +2180,62 @@ static int cam_ife_csid_disable_rdi_path( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + /* Halt the RDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + return rc; +} + +static int cam_ife_csid_poll_stop_status( + struct cam_ife_csid_hw *csid_hw, + uint32_t res_mask) +{ + int rc = 0; + uint32_t csid_status_addr = 0, val = 0, res_id = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + for (; res_id < CAM_IFE_PIX_PATH_RES_MAX; res_id++, res_mask >>= 1) { + if ((res_mask & 0x1) == 0) + continue; + val = 0; + + if (res_id == CAM_IFE_PIX_PATH_RES_IPP) { + csid_status_addr = + csid_reg->ipp_reg->csid_pxl_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { + csid_status_addr = + csid_reg->ppp_reg->csid_pxl_status_addr; + } else { + csid_status_addr = + csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + } + + CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_status_addr, val, (val & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, + CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d", + csid_hw->hw_intf->hw_idx, res_id, rc); + rc = -ETIMEDOUT; + break; + } + CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + } + return rc; } @@ -2176,10 +2284,10 @@ static int cam_ife_csid_get_hbi_vbi( rdi_reg->csid_rdi_format_measure2_addr); } - CAM_INFO_RATE_LIMIT(CAM_ISP, "Resource %u HBI: 0x%x", res->res_id, - hbi); - CAM_INFO_RATE_LIMIT(CAM_ISP, "Resource %u VBI: 0x%x", res->res_id, - vbi); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "Device %s index %u Resource %u HBI: 0x%x VBI: 0x%x", + soc_info->dev_name, soc_info->index, + res->res_id, hbi, vbi); return 0; } @@ -2506,6 +2614,7 @@ static int cam_ife_csid_init_hw(void *hw_priv, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -2573,6 +2682,10 @@ static int cam_ife_csid_init_hw(void *hw_priv, if (rc) cam_ife_csid_disable_hw(csid_hw); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; @@ -2705,6 +2818,7 @@ static int cam_ife_csid_stop(void *hw_priv, struct cam_isp_resource_node *res; struct cam_csid_hw_stop_args *csid_stop; uint32_t i; + uint32_t res_mask = 0; if (!hw_priv || !stop_args || (arg_size != sizeof(struct cam_csid_hw_stop_args))) { @@ -2736,6 +2850,7 @@ static int cam_ife_csid_stop(void *hw_priv, rc = cam_ife_csid_tpg_stop(csid_hw, res); break; case CAM_ISP_RESOURCE_PIX_PATH: + res_mask |= (1 << res->res_id); if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || res->res_id == CAM_IFE_PIX_PATH_RES_PPP) rc = cam_ife_csid_disable_pxl_path(csid_hw, @@ -2753,6 +2868,9 @@ static int cam_ife_csid_stop(void *hw_priv, } } + if (res_mask) + rc = cam_ife_csid_poll_stop_status(csid_hw, res_mask); + for (i = 0; i < csid_stop->num_res; i++) { res = csid_stop->node_res[i]; res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; @@ -2920,6 +3038,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) uint32_t val, irq_status_ppp = 0; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; + unsigned long flags; csid_hw = (struct cam_ife_csid_hw *)data; @@ -2985,65 +3104,74 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) complete(&csid_hw->csid_csi2_complete); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); - csid_hw->error_irq_count++; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); - csid_hw->error_irq_count++; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->lock_state, flags); + if (csid_hw->device_enabled == 1) { + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_EOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_SOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_STREAM_UNDERFLOW", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } } + spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { @@ -3170,6 +3298,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP CCIF violation", + csid_hw->hw_intf->hw_idx); + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP fifo over flow", @@ -3203,6 +3336,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP CCIF violation", + csid_hw->hw_intf->hw_idx); + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d PPP fifo over flow", @@ -3234,6 +3372,10 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSIDi RDI :%d CCIF violation", i); + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d RDI fifo over flow", @@ -3280,9 +3422,11 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->hw_intf->hw_type, csid_idx); + ife_csid_hw->device_enabled = 0; ife_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; mutex_init(&ife_csid_hw->hw_info->hw_mutex); spin_lock_init(&ife_csid_hw->hw_info->hw_lock); + spin_lock_init(&ife_csid_hw->lock_state); init_completion(&ife_csid_hw->hw_info->hw_complete); init_completion(&ife_csid_hw->csid_top_complete); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 43fd9b03132e..3a093d205f59 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -64,6 +64,7 @@ #define CSID_PATH_INFO_INPUT_SOF BIT(12) #define CSID_PATH_ERROR_PIX_COUNT BIT(13) #define CSID_PATH_ERROR_LINE_COUNT BIT(14) +#define CSID_PATH_ERROR_CCIF_VIOLATION BIT(15) /* * Debug values enable the corresponding interrupts and debug logs provide @@ -138,6 +139,8 @@ struct cam_ife_csid_pxl_reg_offset { /* configuration */ uint32_t pix_store_en_shift_val; uint32_t early_eof_en_shift_val; + uint32_t quad_cfa_bin_en_shift_val; + uint32_t ccif_violation_en; }; struct cam_ife_csid_rdi_reg_offset { @@ -182,6 +185,10 @@ struct cam_ife_csid_rdi_reg_offset { uint32_t csid_rdi_timestamp_prev1_eof_addr; uint32_t csid_rdi_byte_cntr_ping_addr; uint32_t csid_rdi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; }; struct cam_ife_csid_csi2_rx_reg_offset { @@ -194,7 +201,7 @@ struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_capture_ctrl_addr; uint32_t csid_csi2_rx_rst_strobes_addr; uint32_t csid_csi2_rx_de_scramble_cfg0_addr; - uint32_t csid_csi2_rx_de_scramble_cfg1_addr; /* */ + uint32_t csid_csi2_rx_de_scramble_cfg1_addr; uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr; uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr; uint32_t csid_csi2_rx_captured_short_pkt_0_addr; @@ -210,6 +217,14 @@ struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_total_pkts_rcvd_addr; uint32_t csid_csi2_rx_stats_ecc_addr; uint32_t csid_csi2_rx_total_crc_err_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg1_addr; /*configurations */ uint32_t csi2_rst_srb_all; @@ -225,6 +240,7 @@ struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csi2_capture_short_pkt_vc_shift; uint32_t csi2_capture_cphy_pkt_dt_shift; uint32_t csi2_capture_cphy_pkt_vc_shift; + uint32_t csi2_rx_phy_num_mask; }; struct cam_ife_csid_csi2_tpg_reg_offset { @@ -274,6 +290,7 @@ struct cam_ife_csid_common_reg_offset { uint32_t num_rdis; uint32_t num_pix; uint32_t num_ppp; + uint32_t csid_reg_rst_stb; uint32_t csid_rst_stb; uint32_t csid_rst_stb_sw_all; uint32_t path_rst_stb_all; @@ -477,6 +494,8 @@ struct cam_ife_csid_hw { bool sof_irq_triggered; uint32_t irq_debug_cnt; uint32_t error_irq_count; + uint32_t device_enabled; + spinlock_t lock_state; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c deleted file mode 100644 index 6c39bd84e47f..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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/module.h> -#include "cam_ife_csid_lite170.h" -#include "cam_ife_csid_core.h" -#include "cam_ife_csid_dev.h" - -#define CAM_CSID_LITE_DRV_NAME "csid_lite_170" -#define CAM_CSID_LITE_VERSION_V170 0x10070000 - -static struct cam_ife_csid_hw_info cam_ife_csid_lite170_hw_info = { - .csid_reg = &cam_ife_csid_lite_170_reg_offset, - .hw_dts_version = CAM_CSID_LITE_VERSION_V170, -}; - -static const struct of_device_id cam_ife_csid_lite170_dt_match[] = { - { - .compatible = "qcom,csid-lite170", - .data = &cam_ife_csid_lite170_hw_info, - }, - {} -}; -MODULE_DEVICE_TABLE(of, cam_ife_csid_lite170_dt_match); - -static struct platform_driver cam_ife_csid_lite170_driver = { - .probe = cam_ife_csid_probe, - .remove = cam_ife_csid_remove, - .driver = { - .name = CAM_CSID_LITE_DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = cam_ife_csid_lite170_dt_match, - .suppress_bind_attrs = true, - }, -}; - -static int __init cam_ife_csid_lite170_init_module(void) -{ - return platform_driver_register(&cam_ife_csid_lite170_driver); -} - -static void __exit cam_ife_csid_lite170_exit_module(void) -{ - platform_driver_unregister(&cam_ife_csid_lite170_driver); -} - -module_init(cam_ife_csid_lite170_init_module); -module_exit(cam_ife_csid_lite170_exit_module); -MODULE_DESCRIPTION("CAM IFE_CSID_LITE170 driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c index b05a4b533c23..11c71145ef94 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,10 @@ static const struct of_device_id cam_ife_csid_lite_dt_match[] = { .compatible = "qcom,csid-lite170", .data = &cam_ife_csid_lite_hw_info, }, + { + .compatible = "qcom,csid-lite175", + .data = &cam_ife_csid_lite_hw_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_ife_csid_lite_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h index d4e05115455a..e39666fe12b7 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -232,6 +232,7 @@ static const struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; @@ -286,6 +287,7 @@ static const struct cam_ife_csid_common_reg_offset .version_incr = 0, .num_rdis = 4, .num_pix = 0, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 940d338a9572..61542566a924 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -80,14 +80,17 @@ enum cam_isp_resource_type { CAM_ISP_RESOURCE_PIX_PATH, CAM_ISP_RESOURCE_VFE_IN, CAM_ISP_RESOURCE_VFE_OUT, + CAM_ISP_RESOURCE_VFE_BUS_RD, CAM_ISP_RESOURCE_MAX, }; enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_GET_CHANGE_BASE, CAM_ISP_HW_CMD_GET_BUF_UPDATE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, CAM_ISP_HW_CMD_GET_REG_UPDATE, CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM, CAM_ISP_HW_CMD_GET_SECURE_MODE, CAM_ISP_HW_CMD_STRIPE_UPDATE, CAM_ISP_HW_CMD_CLOCK_UPDATE, @@ -95,10 +98,12 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_GET_REG_DUMP, + CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, - CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, CAM_ISP_HW_CMD_MAX, }; @@ -186,6 +191,20 @@ struct cam_isp_hw_get_wm_update { }; /* + * struct cam_isp_hw_rup_data: + * + * @Brief: RUP for required resources. + * + * @is_fe_enable if fetch engine enabled + * @res_bitmap resource bitmap for set resources + * + */ +struct cam_isp_hw_rup_data { + bool is_fe_enable; + unsigned long res_bitmap; +}; + +/* * struct cam_isp_hw_get_cmd_update: * * @Brief: Get cmd buffer update for different CMD types @@ -202,10 +221,13 @@ struct cam_isp_hw_get_cmd_update { union { void *data; struct cam_isp_hw_get_wm_update *wm_update; + struct cam_isp_hw_get_wm_update *rm_update; struct cam_isp_port_hfr_config *hfr_update; struct cam_isp_clock_config *clock_update; struct cam_isp_bw_config *bw_update; struct cam_ubwc_plane_cfg_v1 *ubwc_update; + struct cam_fe_config *fe_update; + struct cam_isp_hw_rup_data *rup_data; }; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index b957d6913f77..f60bf6e4b3d4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,7 +28,7 @@ enum cam_isp_hw_vfe_in_mux { CAM_ISP_HW_VFE_IN_CAMIF = 0, CAM_ISP_HW_VFE_IN_TESTGEN = 1, - CAM_ISP_HW_VFE_IN_BUS_RD = 2, + CAM_ISP_HW_VFE_IN_RD = 2, CAM_ISP_HW_VFE_IN_RDI0 = 3, CAM_ISP_HW_VFE_IN_RDI1 = 4, CAM_ISP_HW_VFE_IN_RDI2 = 5, @@ -153,6 +153,7 @@ struct cam_vfe_hw_vfe_in_acquire_args { * used to schedule bottom of IRQ events associated * with this resource. * @vfe_out: Acquire args for VFE_OUT + * @vfe_bus_rd Acquire args for VFE_BUS_READ * @vfe_in: Acquire args for VFE_IN */ struct cam_vfe_acquire_args { @@ -160,6 +161,7 @@ struct cam_vfe_acquire_args { void *tasklet; union { struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + struct cam_vfe_hw_vfe_out_acquire_args vfe_bus_rd; struct cam_vfe_hw_vfe_in_acquire_args vfe_in; }; }; @@ -178,7 +180,7 @@ struct cam_vfe_clock_update_args { /* * struct cam_vfe_bw_update_args: * - * @node_res: Resource to get the time stamp + * @node_res: Resource to get the BW * @camnoc_bw_bytes: Bandwidth vote request for CAMNOC * @external_bw_bytes: Bandwidth vote request from CAMNOC * out to the rest of the path-to-DDR @@ -189,6 +191,18 @@ struct cam_vfe_bw_update_args { uint64_t external_bw_bytes; }; +/* + * struct cam_vfe_fe_update_args: + * + * @node_res: Resource to get fetch configuration + * @fe_config: fetch engine configuration + * + */ +struct cam_vfe_fe_update_args { + struct cam_isp_resource_node *node_res; + struct cam_fe_config fe_config; +}; + enum cam_vfe_bw_control_action { CAM_VFE_BW_CONTROL_EXCLUDE = 0, CAM_VFE_BW_CONTROL_INCLUDE = 1 @@ -218,6 +232,7 @@ struct cam_vfe_bw_control_args { * @irq_reg_val: IRQ and Error register values, read when IRQ was * handled * @error_type: Identify different errors + * @enable_reg_dump: enable register dump on error * @ts: Timestamp */ struct cam_vfe_top_irq_evt_payload { @@ -227,6 +242,7 @@ struct cam_vfe_top_irq_evt_payload { uint32_t evt_id; uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; uint32_t error_type; + bool enable_reg_dump; struct cam_isp_timestamp ts; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 5e6bb2012fff..2bd6db9954f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,6 +36,11 @@ static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x00000000, }; +static uint32_t camif_fe_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x10000056, + 0x00000000, +}; + static uint32_t camif_irq_err_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x0003FC00, 0xEFFF7EBC, @@ -286,6 +291,16 @@ int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) goto deinint_vfe_res; } + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.init( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus RD HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + } + vfe_hw->hw_state = CAM_HW_STATE_POWER_UP; return rc; @@ -339,6 +354,14 @@ int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) if (rc) CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.deinit( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + } + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; if (isp_res && isp_res->deinit) { rc = isp_res->deinit(isp_res, NULL, 0); @@ -485,18 +508,25 @@ int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; acquire = (struct cam_vfe_acquire_args *)reserve_args; + CAM_DBG(CAM_ISP, "acq res type: %d", acquire->rsrc_type); mutex_lock(&vfe_hw->hw_mutex); - if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN) + if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN) { rc = core_info->vfe_top->hw_ops.reserve( core_info->vfe_top->top_priv, acquire, sizeof(*acquire)); - else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT) + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.reserve( core_info->vfe_bus->bus_priv, acquire, sizeof(*acquire)); - else + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.reserve( + core_info->vfe_rd_bus->bus_priv, acquire, + sizeof(*acquire)); + } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", acquire->rsrc_type); + } mutex_unlock(&vfe_hw->hw_mutex); @@ -529,8 +559,14 @@ int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size) rc = core_info->vfe_bus->hw_ops.release( core_info->vfe_bus->bus_priv, isp_res, sizeof(*isp_res)); - else + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.release( + core_info->vfe_rd_bus->bus_priv, isp_res, + sizeof(*isp_res)); + } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } mutex_unlock(&vfe_hw->hw_mutex); @@ -570,6 +606,19 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; + } else if (isp_res->res_id == CAM_ISP_HW_VFE_IN_RD) { + isp_res->irq_handle = + cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + camif_fe_irq_reg_mask, + &core_info->irq_payload, + cam_vfe_irq_top_half, + cam_ife_mgr_do_tasklet, + isp_res->tasklet_info, + &tasklet_bh_api); + if (isp_res->irq_handle < 1) + rc = -ENOMEM; } else if (isp_res->rdi_only_ctx) { isp_res->irq_handle = cam_irq_controller_subscribe_irq( @@ -598,6 +647,10 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) } } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.start(isp_res, + NULL, 0); } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); rc = -EFAULT; @@ -653,6 +706,10 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) sizeof(struct cam_isp_resource_node)); } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.stop(isp_res, + NULL, 0); } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); } @@ -716,7 +773,26 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + } + break; default: CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type); rc = -EINVAL; @@ -766,7 +842,8 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, goto deinit_controller; } - rc = cam_vfe_bus_init(vfe_hw_info->bus_version, soc_info, hw_intf, + rc = cam_vfe_bus_init(vfe_hw_info->bus_version, BUS_TYPE_WR, + soc_info, hw_intf, vfe_hw_info->bus_hw_info, core_info->vfe_irq_controller, &core_info->vfe_bus); if (rc) { @@ -774,6 +851,19 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, goto deinit_top; } + /* Read Bus is not valid for vfe-lite */ + if ((hw_intf->hw_idx == 0) || (hw_intf->hw_idx == 1)) { + rc = cam_vfe_bus_init(vfe_hw_info->bus_rd_version, BUS_TYPE_RD, + soc_info, hw_intf, vfe_hw_info->bus_rd_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_rd_bus); + if (rc) { + CAM_ERR(CAM_ISP, "Error! RD cam_vfe_bus_init failed"); + rc = 0; + } + CAM_DBG(CAM_ISP, "vfe_bus_rd %pK hw_idx %d", + core_info->vfe_rd_bus, hw_intf->hw_idx); + } + INIT_LIST_HEAD(&core_info->free_payload_list); for (i = 0; i < CAM_VFE_EVT_MAX; i++) { INIT_LIST_HEAD(&core_info->evt_payload[i].list); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h index 9cec56a15fec..dd078f2d6ce3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,6 +25,9 @@ struct cam_vfe_hw_info { uint32_t bus_version; void *bus_hw_info; + uint32_t bus_rd_version; + void *bus_rd_hw_info; + uint32_t top_version; void *top_hw_info; uint32_t camif_version; @@ -53,6 +56,7 @@ struct cam_vfe_hw_core_info { void *vfe_irq_controller; struct cam_vfe_top *vfe_top; struct cam_vfe_bus *vfe_bus; + struct cam_vfe_bus *vfe_rd_bus; void *tasklet_info; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_EVT_MAX]; struct list_head free_payload_list; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index 12b7a03c6276..b57762644082 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,8 @@ static bool cam_vfe_cpas_cb(uint32_t client_handle, void *userdata, switch (irq_data->irq_type) { case CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR: case CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: CAM_ERR_RATE_LIMIT(CAM_ISP, "IFE UBWC Encode error type=%d status=%x", irq_data->irq_type, @@ -104,7 +106,7 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, CAM_VFE_DSP_CLK_NAME, &soc_private->dsp_clk, &soc_private->dsp_clk_index, &soc_private->dsp_clk_rate); if (rc) - CAM_WARN(CAM_ISP, "option clk get failed"); + CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc); rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler, irq_data); @@ -115,20 +117,56 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, } memset(&cpas_register_param, 0, sizeof(cpas_register_param)); - strlcpy(cpas_register_param.identifier, "ife", - CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; cpas_register_param.dev = soc_info->dev; cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb; cpas_register_param.userdata = soc_info; - rc = cam_cpas_register_client(&cpas_register_param); + + rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version); if (rc) { - CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); - goto release_soc; - } else { - soc_private->cpas_handle = cpas_register_param.client_handle; + CAM_ERR(CAM_ISP, "Error! Invalid cpas version rc=%d", rc); + goto free_soc_private; } + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_175_V120: + strlcpy(cpas_register_param.identifier, "iferdi", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "rdi CPAS registration failed rc=%d", + rc); + goto release_soc; + } else { + soc_private->cpas_handle[0] = + cpas_register_param.client_handle; + } + + strlcpy(cpas_register_param.identifier, "ifenrdi", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "nrdi CPAS registration failed rc=%d", + rc); + goto release_soc; + } else { + soc_private->cpas_handle[1] = + cpas_register_param.client_handle; + } + break; + default: + strlcpy(cpas_register_param.identifier, "ife", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle[0] = + cpas_register_param.client_handle; + } + } return rc; release_soc: @@ -154,10 +192,15 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) CAM_ERR(CAM_ISP, "Error! soc_private NULL"); return -ENODEV; } - - rc = cam_cpas_unregister_client(soc_private->cpas_handle); + rc = cam_cpas_unregister_client(soc_private->cpas_handle[0]); if (rc) - CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + CAM_ERR(CAM_ISP, "CPAS0 unregistration failed rc=%d", rc); + + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_unregister_client(soc_private->cpas_handle[1]); + if (rc) + CAM_ERR(CAM_ISP, "CPAS1 unregistration failed rc=%d", + rc); rc = cam_vfe_release_platform_resource(soc_info); if (rc < 0) @@ -194,13 +237,22 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) axi_vote.compressed_bw = 10640000000L; axi_vote.uncompressed_bw = 10640000000L; - rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + rc = cam_cpas_start(soc_private->cpas_handle[0], &ahb_vote, &axi_vote); if (rc) { - CAM_ERR(CAM_ISP, "Error! CPAS start failed rc=%d", rc); + CAM_ERR(CAM_ISP, "Error! CPAS0 start failed rc=%d", rc); rc = -EFAULT; goto end; } + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_start(soc_private->cpas_handle[1], &ahb_vote, + &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS1 start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_TURBO_VOTE, true); if (rc) { @@ -211,7 +263,9 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) return rc; stop_cpas: - cam_cpas_stop(soc_private->cpas_handle); + cam_cpas_stop(soc_private->cpas_handle[0]); + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + cam_cpas_stop(soc_private->cpas_handle[1]); end: return rc; } @@ -283,11 +337,18 @@ int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) return rc; } - rc = cam_cpas_stop(soc_private->cpas_handle); + rc = cam_cpas_stop(soc_private->cpas_handle[0]); if (rc) { CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); return rc; } + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_stop(soc_private->cpas_handle[1]); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 3f862e9249f8..780bd34ab968 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,6 +18,12 @@ #define CAM_VFE_DSP_CLK_NAME "ife_dsp_clk" +enum cam_cpas_handle_id { + CAM_CPAS_HANDLE_CAMIF, + CAM_CPAS_HANDLE_RAW, + CAM_CPAS_HANDLE_MAX, +}; + /* * struct cam_vfe_soc_private: * @@ -26,9 +32,11 @@ * @cpas_handle: Handle returned on registering with CPAS driver. * This handle is used for all further interface * with CPAS. + * @cpas_version: Has cpas version read from Hardware */ struct cam_vfe_soc_private { - uint32_t cpas_handle; + uint32_t cpas_handle[CAM_CPAS_HANDLE_MAX]; + uint32_t cpas_version; struct clk *dsp_clk; int32_t dsp_clk_index; int32_t dsp_clk_rate; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile deleted file mode 100644 index deeae35cef79..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_utils -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_core -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw - -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe170.o cam_vfe_lite170.o diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c deleted file mode 100644 index d002f84015de..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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/module.h> -#include "cam_vfe170.h" -#include "cam_vfe_hw_intf.h" -#include "cam_vfe_core.h" -#include "cam_vfe_dev.h" - -static const struct of_device_id cam_vfe170_dt_match[] = { - { - .compatible = "qcom,vfe170", - .data = &cam_vfe170_hw_info, - }, - {} -}; -MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); - -static struct platform_driver cam_vfe170_driver = { - .probe = cam_vfe_probe, - .remove = cam_vfe_remove, - .driver = { - .name = "cam_vfe170", - .owner = THIS_MODULE, - .of_match_table = cam_vfe170_dt_match, - .suppress_bind_attrs = true, - }, -}; - -static int __init cam_vfe170_init_module(void) -{ - return platform_driver_register(&cam_vfe170_driver); -} - -static void __exit cam_vfe170_exit_module(void) -{ - platform_driver_unregister(&cam_vfe170_driver); -} - -module_init(cam_vfe170_init_module); -module_exit(cam_vfe170_exit_module); -MODULE_DESCRIPTION("CAM VFE170 driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c deleted file mode 100644 index ab692cf095e4..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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/module.h> -#include "cam_vfe_lite170.h" -#include "cam_vfe_hw_intf.h" -#include "cam_vfe_core.h" -#include "cam_vfe_dev.h" - -static const struct of_device_id cam_vfe170_dt_match[] = { - { - .compatible = "qcom,vfe-lite170", - .data = &cam_vfe_lite170_hw_info, - }, - {} -}; -MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); - -static struct platform_driver cam_vfe170_driver = { - .probe = cam_vfe_probe, - .remove = cam_vfe_remove, - .driver = { - .name = "cam_vfe_lite170", - .owner = THIS_MODULE, - .of_match_table = cam_vfe170_dt_match, - .suppress_bind_attrs = true, - }, -}; - -static int __init cam_vfe170_init_module(void) -{ - return platform_driver_register(&cam_vfe170_driver); -} - -static void __exit cam_vfe170_exit_module(void) -{ - platform_driver_unregister(&cam_vfe170_driver); -} - -module_init(cam_vfe170_init_module); -module_exit(cam_vfe170_exit_module); -MODULE_DESCRIPTION("CAM VFE170 driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h deleted file mode 100644 index 4b2e0963a599..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h +++ /dev/null @@ -1,336 +0,0 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ - -#ifndef _CAM_VFE_LITE170_H_ -#define _CAM_VFE_LITE170_H_ - -#include "cam_vfe_bus_ver2.h" -#include "cam_irq_controller.h" -#include "cam_vfe_top_ver2.h" -#include "cam_vfe_core.h" - -static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { - { - .mask_reg_offset = 0x0000005C, - .clear_reg_offset = 0x00000064, - .status_reg_offset = 0x0000006C, - }, - { - .mask_reg_offset = 0x00000060, - .clear_reg_offset = 0x00000068, - .status_reg_offset = 0x00000070, - }, -}; - -static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = { - .num_registers = 2, - .irq_reg_set = vfe170_top_irq_reg_set, - .global_clear_offset = 0x00000058, - .global_clear_bitmask = 0x00000001, -}; - -static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { - .hw_version = 0x00000000, - .hw_capability = 0x00000004, - .lens_feature = 0x00000008, - .stats_feature = 0x0000000C, - .color_feature = 0x00000010, - .zoom_feature = 0x00000014, - .global_reset_cmd = 0x00000018, - .module_ctrl = { - NULL, - NULL, - NULL, - NULL, - }, - .bus_cgc_ovd = 0x0000003C, - .core_cfg = 0x00000000, - .three_D_cfg = 0x00000000, - .violation_status = 0x0000007C, - .reg_update_cmd = 0x000004AC, -}; - -static struct cam_vfe_rdi_ver2_reg vfe170_rdi_reg = { - .reg_update_cmd = 0x000004AC, -}; - -static struct cam_vfe_rdi_reg_data vfe170_rdi_0_data = { - .reg_update_cmd_data = 0x2, - .sof_irq_mask = 0x8000000, - .reg_update_irq_mask = 0x20, -}; - -static struct cam_vfe_rdi_reg_data vfe170_rdi_1_data = { - .reg_update_cmd_data = 0x4, - .sof_irq_mask = 0x10000000, - .reg_update_irq_mask = 0x40, -}; - -static struct cam_vfe_rdi_reg_data vfe170_rdi_2_data = { - .reg_update_cmd_data = 0x8, - .sof_irq_mask = 0x20000000, - .reg_update_irq_mask = 0x80, -}; - -static struct cam_vfe_rdi_reg_data vfe170_rdi_3_data = { - .reg_update_cmd_data = 0x10, - .sof_irq_mask = 0x40000000, - .reg_update_irq_mask = 0x100, -}; - -static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { - .common_reg = &vfe170_top_common_reg, - .camif_hw_info = { - .common_reg = NULL, - .camif_reg = NULL, - .reg_data = NULL, - }, - .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, - .reg_data = { - &vfe170_rdi_0_data, - &vfe170_rdi_1_data, - &vfe170_rdi_2_data, - &vfe170_rdi_3_data, - }, - }, - .mux_type = { - CAM_VFE_RDI_VER_1_0, - CAM_VFE_RDI_VER_1_0, - CAM_VFE_RDI_VER_1_0, - CAM_VFE_RDI_VER_1_0, - }, -}; - -static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { - { - .mask_reg_offset = 0x00002044, - .clear_reg_offset = 0x00002050, - .status_reg_offset = 0x0000205C, - }, - { - .mask_reg_offset = 0x00002048, - .clear_reg_offset = 0x00002054, - .status_reg_offset = 0x00002060, - }, - { - .mask_reg_offset = 0x0000204C, - .clear_reg_offset = 0x00002058, - .status_reg_offset = 0x00002064, - }, -}; - -static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { - .common_reg = { - .hw_version = 0x00002000, - .hw_capability = 0x00002004, - .sw_reset = 0x00002008, - .cgc_ovd = 0x0000200C, - .pwr_iso_cfg = 0x000020CC, - .dual_master_comp_cfg = 0x00002028, - .irq_reg_info = { - .num_registers = 3, - .irq_reg_set = vfe170_bus_irq_reg, - .global_clear_offset = 0x00002068, - .global_clear_bitmask = 0x00000001, - }, - .comp_error_status = 0x0000206C, - .comp_ovrwr_status = 0x00002070, - .dual_comp_error_status = 0x00002074, - .dual_comp_ovrwr_status = 0x00002078, - .addr_sync_cfg = 0x0000207C, - .addr_sync_frame_hdr = 0x00002080, - .addr_sync_no_sync = 0x00002084, - }, - .num_client = 4, - .bus_client_reg = { - /* BUS Client 0 */ - { - .status0 = 0x00002200, - .status1 = 0x00002204, - .cfg = 0x00002208, - .header_addr = 0x0000220C, - .header_cfg = 0x00002210, - .image_addr = 0x00002214, - .image_addr_offset = 0x00002218, - .buffer_width_cfg = 0x0000221C, - .buffer_height_cfg = 0x00002220, - .packer_cfg = 0x00002224, - .stride = 0x00002228, - .irq_subsample_period = 0x00002248, - .irq_subsample_pattern = 0x0000224C, - .framedrop_period = 0x00002250, - .framedrop_pattern = 0x00002254, - .frame_inc = 0x00002258, - .burst_limit = 0x0000225C, - .ubwc_regs = NULL, - }, - /* BUS Client 1 */ - { - .status0 = 0x00002300, - .status1 = 0x00002304, - .cfg = 0x00002308, - .header_addr = 0x0000230C, - .header_cfg = 0x00002310, - .image_addr = 0x00002314, - .image_addr_offset = 0x00002318, - .buffer_width_cfg = 0x0000231C, - .buffer_height_cfg = 0x00002320, - .packer_cfg = 0x00002324, - .stride = 0x00002328, - .irq_subsample_period = 0x00002348, - .irq_subsample_pattern = 0x0000234C, - .framedrop_period = 0x00002350, - .framedrop_pattern = 0x00002354, - .frame_inc = 0x00002358, - .burst_limit = 0x0000235C, - .ubwc_regs = NULL, - }, - /* BUS Client 2 */ - { - .status0 = 0x00002400, - .status1 = 0x00002404, - .cfg = 0x00002408, - .header_addr = 0x0000240C, - .header_cfg = 0x00002410, - .image_addr = 0x00002414, - .image_addr_offset = 0x00002418, - .buffer_width_cfg = 0x0000241C, - .buffer_height_cfg = 0x00002420, - .packer_cfg = 0x00002424, - .stride = 0x00002428, - .irq_subsample_period = 0x00002448, - .irq_subsample_pattern = 0x0000244C, - .framedrop_period = 0x00002450, - .framedrop_pattern = 0x00002454, - .frame_inc = 0x00002458, - .burst_limit = 0x0000245C, - .ubwc_regs = NULL, - }, - /* BUS Client 3 */ - { - .status0 = 0x00002500, - .status1 = 0x00002504, - .cfg = 0x00002508, - .header_addr = 0x0000250C, - .header_cfg = 0x00002510, - .image_addr = 0x00002514, - .image_addr_offset = 0x00002518, - .buffer_width_cfg = 0x0000251C, - .buffer_height_cfg = 0x00002520, - .packer_cfg = 0x00002524, - .stride = 0x00002528, - .irq_subsample_period = 0x00002548, - .irq_subsample_pattern = 0x0000254C, - .framedrop_period = 0x00002550, - .framedrop_pattern = 0x00002554, - .frame_inc = 0x00002558, - .burst_limit = 0x0000255C, - .ubwc_regs = NULL, - }, - }, - .comp_grp_reg = { - /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ - { - .comp_mask = 0x00002010, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ - { - .comp_mask = 0x00002014, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ - { - .comp_mask = 0x00002018, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ - { - .comp_mask = 0x0000201C, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ - { - .comp_mask = 0x00002020, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ - { - .comp_mask = 0x00002024, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ - { - .comp_mask = 0x0000202C, - .addr_sync_mask = 0x00002088, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ - { - .comp_mask = 0x00002030, - .addr_sync_mask = 0x0000208C, - - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ - { - .comp_mask = 0x00002034, - .addr_sync_mask = 0x00002090, - - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ - { - .comp_mask = 0x00002038, - .addr_sync_mask = 0x00002094, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ - { - .comp_mask = 0x0000203C, - .addr_sync_mask = 0x00002098, - }, - /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ - { - .comp_mask = 0x00002040, - .addr_sync_mask = 0x0000209C, - }, - }, - .num_out = 4, - .vfe_out_hw_info = { - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, - .max_width = -1, - .max_height = -1, - }, - { - .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI3, - .max_width = -1, - .max_height = -1, - }, - }, -}; - -static struct cam_vfe_hw_info cam_vfe_lite170_hw_info = { - .irq_reg_info = &vfe170_top_irq_reg_info, - - .bus_version = CAM_VFE_BUS_VER_2_0, - .bus_hw_info = &vfe170_bus_hw_info, - - .top_version = CAM_VFE_TOP_VER_2_0, - .top_hw_info = &vfe170_top_hw_info, - -}; - -#endif /* _CAM_VFE_LITE170_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index d1284d9f23d2..b47bd0d51a28 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,16 +10,17 @@ * GNU General Public License for more details. */ -#ifndef _CAM_VFE170_H_ -#define _CAM_VFE170_H_ +#ifndef _CAM_VFE175_H_ +#define _CAM_VFE175_H_ #include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" #include "cam_vfe_bus_ver2.h" #include "cam_irq_controller.h" #include "cam_vfe_top_ver2.h" #include "cam_vfe_core.h" -static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { +static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { { .mask_reg_offset = 0x0000005C, .clear_reg_offset = 0x00000064, @@ -32,14 +33,14 @@ static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { }, }; -static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = { +static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { .num_registers = 2, - .irq_reg_set = vfe170_top_irq_reg_set, + .irq_reg_set = vfe175_top_irq_reg_set, .global_clear_offset = 0x00000058, .global_clear_bitmask = 0x00000001, }; -static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { +static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { .camif_cmd = 0x00000478, .camif_config = 0x0000047C, .line_skip_pattern = 0x00000488, @@ -54,7 +55,7 @@ static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { .vfe_diag_sensor_status = 0x00000C4C, }; -static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { +static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { .raw_crop_first_pixel_shift = 16, .raw_crop_first_pixel_mask = 0xFFFF, .raw_crop_last_pixel_shift = 0x0, @@ -80,35 +81,57 @@ static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { .reg_update_irq_mask = 0x00000010, .eof_irq_mask = 0x00000002, .error_irq_mask0 = 0x0003FC00, - .error_irq_mask1 = 0x0FFF7E80, + .error_irq_mask1 = 0xEFFF7E80, .enable_diagnostic_hw = 0x1, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_reg = { +static struct cam_vfe_camif_lite_ver2_reg vfe175_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data vfe175_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_error_irq_mask0 = 0x00400000, + .lite_error_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { .reset = 0x0000001C, .cgc_ovd = 0x0000002C, .enable = 0x00000040, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { .reset = 0x00000020, .cgc_ovd = 0x00000030, .enable = 0x00000044, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { .reset = 0x00000024, .cgc_ovd = 0x00000034, .enable = 0x00000048, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { .reset = 0x00000028, .cgc_ovd = 0x00000038, .enable = 0x0000004C, }; -static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { +static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, .lens_feature = 0x00000008, @@ -117,10 +140,10 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { .zoom_feature = 0x00000014, .global_reset_cmd = 0x00000018, .module_ctrl = { - &lens_170_reg, - &stats_170_reg, - &color_170_reg, - &zoom_170_reg, + &lens_175_reg, + &stats_175_reg, + &color_175_reg, + &zoom_175_reg, }, .bus_cgc_ovd = 0x0000003C, .core_cfg = 0x00000050, @@ -129,42 +152,47 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { .reg_update_cmd = 0x000004AC, }; -static struct cam_vfe_rdi_ver2_reg vfe170_rdi_reg = { +static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { .reg_update_cmd = 0x000004AC, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_0_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { .reg_update_cmd_data = 0x2, .sof_irq_mask = 0x8000000, .reg_update_irq_mask = 0x20, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_1_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { .reg_update_cmd_data = 0x4, .sof_irq_mask = 0x10000000, .reg_update_irq_mask = 0x40, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { .reg_update_cmd_data = 0x8, .sof_irq_mask = 0x20000000, .reg_update_irq_mask = 0x80, }; -static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { - .common_reg = &vfe170_top_common_reg, +static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { + .common_reg = &vfe175_top_common_reg, .camif_hw_info = { - .common_reg = &vfe170_top_common_reg, - .camif_reg = &vfe170_camif_reg, - .reg_data = &vfe_170_camif_reg_data, + .common_reg = &vfe175_top_common_reg, + .camif_reg = &vfe175_camif_reg, + .reg_data = &vfe_175_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_lite_reg = &vfe175_camif_lite_reg, + .reg_data = &vfe175_camif_lite_reg_data, }, .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, + .common_reg = &vfe175_top_common_reg, + .rdi_reg = &vfe175_rdi_reg, .reg_data = { - &vfe_170_rdi_0_data, - &vfe_170_rdi_1_data, - &vfe_170_rdi_2_data, + &vfe_175_rdi_0_data, + &vfe_175_rdi_1_data, + &vfe_175_rdi_2_data, NULL, }, }, @@ -173,10 +201,11 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, }, }; -static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { +static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { { .mask_reg_offset = 0x00002044, .clear_reg_offset = 0x00002050, @@ -194,29 +223,59 @@ static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { }, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_3 = { .tile_cfg = 0x0000252C, .h_init = 0x00002530, .v_init = 0x00002534, .meta_addr = 0x00002538, .meta_offset = 0x0000253C, .meta_stride = 0x00002540, - .mode_cfg = 0x00002544, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, .bw_limit = 0x000025A0, }; -static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_4 = { .tile_cfg = 0x0000262C, .h_init = 0x00002630, .v_init = 0x00002634, .meta_addr = 0x00002638, .meta_offset = 0x0000263C, .meta_stride = 0x00002640, - .mode_cfg = 0x00002644, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, .bw_limit = 0x000026A0, }; -static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .common_reg = { .hw_version = 0x00002000, .hw_capability = 0x00002004, @@ -226,7 +285,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .dual_master_comp_cfg = 0x00002028, .irq_reg_info = { .num_registers = 3, - .irq_reg_set = vfe170_bus_irq_reg, + .irq_reg_set = vfe175_bus_irq_reg, .global_clear_offset = 0x00002068, .global_clear_bitmask = 0x00000001, }, @@ -240,7 +299,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .debug_status_cfg = 0x0000226C, .debug_status_0 = 0x00002270, }, - .num_client = 20, + .num_client = 24, .bus_client_reg = { /* BUS Client 0 */ { @@ -324,7 +383,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .framedrop_pattern = 0x00002554, .frame_inc = 0x00002558, .burst_limit = 0x0000255C, - .ubwc_regs = &ubwc_regs_client_3, + .ubwc_regs = &vfe175_ubwc_regs_client_3, }, /* BUS Client 4 */ { @@ -345,7 +404,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .framedrop_pattern = 0x00002654, .frame_inc = 0x00002658, .burst_limit = 0x0000265C, - .ubwc_regs = &ubwc_regs_client_4, + .ubwc_regs = &vfe175_ubwc_regs_client_4, }, /* BUS Client 5 */ { @@ -662,6 +721,90 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .burst_limit = 0x0000355C, .ubwc_regs = NULL, }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = &vfe175_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = &vfe175_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, }, .comp_grp_reg = { /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ @@ -721,7 +864,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .addr_sync_mask = 0x0000209C, }, }, - .num_out = 18, + .num_out = 22, .vfe_out_hw_info = { { .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, @@ -822,21 +965,44 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .max_width = -1, .max_height = -1, }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, }, }; -struct cam_vfe_hw_info cam_vfe170_hw_info = { - .irq_reg_info = &vfe170_top_irq_reg_info, +struct cam_vfe_hw_info cam_vfe175_hw_info = { + .irq_reg_info = &vfe175_top_irq_reg_info, .bus_version = CAM_VFE_BUS_VER_2_0, - .bus_hw_info = &vfe170_bus_hw_info, + .bus_hw_info = &vfe175_bus_hw_info, .top_version = CAM_VFE_TOP_VER_2_0, - .top_hw_info = &vfe170_top_hw_info, + .top_hw_info = &vfe175_top_hw_info, .camif_version = CAM_VFE_CAMIF_VER_2_0, - .camif_reg = &vfe170_camif_reg, + .camif_reg = &vfe175_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_camif_lite_reg, }; -#endif /* _CAM_VFE170_H_ */ +#endif /* _CAM_VFE175_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h new file mode 100644 index 000000000000..f966fe490db4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -0,0 +1,1117 @@ +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CAM_VFE175_130_H_ +#define _CAM_VFE175_130_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_130_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_130_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_130_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_fe_ver1_reg vfe175_130_fe_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, + .fe_cfg = 0x00000084, +}; + +static struct cam_vfe_fe_reg_data vfe_175_130_fe_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, + .fe_mux_data = 0x2, + .hbi_cnt_shift = 0x8, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_130_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data + vfe175_130_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_error_irq_mask0 = 0x00400000, + .lite_error_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_130_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_130_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_130_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_130_reg, + &stats_175_130_reg, + &color_175_130_reg, + &zoom_175_130_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_130_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_reg = &vfe175_130_camif_reg, + .reg_data = &vfe_175_130_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + .reg_data = &vfe175_130_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .rdi_reg = &vfe175_130_rdi_reg, + .reg_data = { + &vfe_175_130_rdi_0_data, + &vfe_175_130_rdi_1_data, + &vfe_175_130_rdi_2_data, + NULL, + }, + }, + .fe_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .fe_reg = &vfe175_130_fe_reg, + .reg_data = &vfe_175_130_fe_reg_data, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + CAM_VFE_IN_RD_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x00005010, + .clear_reg_offset = 0x00005014, + .status_reg_offset = 0x0000501C, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x00005000, + .hw_capability = 0x00005004, + .sw_reset = 0x00005008, + .cgc_ovd = 0x0000500C, + .pwr_iso_cfg = 0x000050CC, + .input_if_cmd = 0x00005020, + .test_bus_ctrl = 0x00005048, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe175_130_bus_rd_irq_reg, + .global_clear_offset = 0x00005018, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x00005050, + .image_addr = 0x00005058, + .buffer_width_cfg = 0x0000505C, + .unpacker_cfg = 0x00005064, + .stride = 0x00005060, + .burst_limit = 0x00005080, + .latency_buf_allocation = 0x00005078, + .ubwc_regs = NULL, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_130_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_130_hw_info = { + .irq_reg_info = &vfe175_130_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_130_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_VER_2_0, + .bus_rd_hw_info = &vfe175_130_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_130_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_130_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_130_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c index 6ec5ffbde4e0..2e11dc40d5a3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,6 +12,8 @@ #include <linux/module.h> #include "cam_vfe170.h" +#include "cam_vfe175.h" +#include "cam_vfe175_130.h" #include "cam_vfe_lite17x.h" #include "cam_vfe_hw_intf.h" #include "cam_vfe_core.h" @@ -23,9 +25,21 @@ static const struct of_device_id cam_vfe_dt_match[] = { .data = &cam_vfe170_hw_info, }, { + .compatible = "qcom,vfe175", + .data = &cam_vfe175_hw_info, + }, + { + .compatible = "qcom,vfe175_130", + .data = &cam_vfe175_130_hw_info, + }, + { .compatible = "qcom,vfe-lite170", .data = &cam_vfe_lite17x_hw_info, }, + { + .compatible = "qcom,vfe-lite175", + .data = &cam_vfe_lite17x_hw_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile index 1823497221ba..d8db0b56a0ee 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vf ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o cam_vfe_bus_rd_ver1.o diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c index 4c0c147f4122..b0495922a90d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,9 +13,11 @@ #include "cam_vfe_bus.h" #include "cam_vfe_bus_ver1.h" #include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" #include "cam_debug_util.h" int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, struct cam_hw_soc_info *soc_info, struct cam_hw_intf *hw_intf, void *bus_hw_info, @@ -24,10 +26,16 @@ int cam_vfe_bus_init(uint32_t bus_version, { int rc = -ENODEV; - switch (bus_version) { - case CAM_VFE_BUS_VER_2_0: - rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, bus_hw_info, - vfe_irq_controller, vfe_bus); + switch (bus_type) { + case BUS_TYPE_WR: + if (CAM_VFE_BUS_VER_2_0) + rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + case BUS_TYPE_RD: + /* Call vfe bus rd init function */ + rc = cam_vfe_bus_rd_ver1_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); break; default: CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c new file mode 100644 index 000000000000..5474ead1826e --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -0,0 +1,1239 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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/ratelimit.h> +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus_rd"; + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_vfe_bus_rd_ver1_reg_offset_bus_client)/4) + +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +enum cam_vfe_bus_rd_ver1_unpacker_format { + BUS_RD_VER1_PACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x5, + BUS_RD_VER1_PACKER_FMT_ARGB_10 = 0x6, + BUS_RD_VER1_PACKER_FMT_ARGB_12 = 0x7, + BUS_RD_VER1_PACKER_FMT_ARGB_14 = 0x8, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x9, + BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_32BPP = 0xC, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + BUS_RD_VER1_PACKER_FMT_MAX = 0xF, +}; + +struct cam_vfe_bus_rd_ver1_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; +}; + +struct cam_vfe_bus_rd_ver1_rm_resource_data { + uint32_t index; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client *hw_regs; + void *ctx; + + uint32_t irq_enabled; + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t hbi_count; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t latency_buf_allocation; + uint32_t unpacker_cfg; + uint32_t burst_len; + + uint32_t go_cmd_sel; + uint32_t fs_sync_enable; + uint32_t fs_line_sync_en; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t img_addr; + uint32_t input_if_cmd; +}; + +struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data { + uint32_t bus_rd_type; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + + uint32_t num_rm; + struct cam_isp_resource_node *rm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_bus_rd_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; +}; + +struct cam_vfe_bus_rd_ver1_priv { + struct cam_vfe_bus_rd_ver1_common_data common_data; + uint32_t num_client; + uint32_t num_bus_rd_resc; + + struct cam_isp_resource_node bus_client[ + CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + struct cam_isp_resource_node vfe_bus_rd[ + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + + uint32_t irq_handle; + uint32_t error_irq_handle; +}; + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static enum cam_vfe_bus_rd_ver1_unpacker_format + cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +{ + switch (unpack_fmt) { + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN; + default: + return BUS_RD_VER1_PACKER_FMT_MAX; + } +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return false; + + default: + return false; + } +} + +static enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type + cam_vfe_bus_get_bus_rd_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_RESOURCE_VFE_BUS_RD: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0; + default: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + } +} + +static int cam_vfe_bus_get_num_rm( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type res_type) +{ + switch (res_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported resource_type %u", + res_type); + return -EINVAL; +} + +static int cam_vfe_bus_get_rm_idx( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int rm_idx = -1; + + switch (vfe_bus_rd_res_id) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + switch (plane) { + case PLANE_Y: + rm_idx = 0; + break; + default: + break; + } + break; + default: + break; + } + + return rm_idx; +} + +static int cam_vfe_bus_acquire_rm( + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_isp_out_port_info *out_port_info, + void *tasklet, + void *ctx, + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane, + uint32_t subscribe_irq, + struct cam_isp_resource_node **rm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = NULL; + + *rm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to RM is fixed. */ + rm_idx = cam_vfe_bus_get_rm_idx(vfe_bus_rd_res_id, plane); + if (rm_idx < 0 || rm_idx >= ver1_bus_rd_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_bus_rd_res_id, plane); + return -EINVAL; + } + + rm_res_local = &ver1_bus_rd_priv->bus_client[rm_idx]; + if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "RM res not available state:%d", + rm_res_local->res_state); + return -EALREADY; + } + rm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rm_res_local->tasklet_info = tasklet; + + rsrc_data = rm_res_local->res_priv; + rsrc_data->irq_enabled = subscribe_irq; + rsrc_data->ctx = ctx; + rsrc_data->is_dual = is_dual; + /* Set RM offset value to default */ + rsrc_data->offset = 0; + + *client_done_mask = (1 << rm_idx); + *rm_res = rm_res_local; + + CAM_DBG(CAM_ISP, "RM %d: Acquired"); + return 0; +} + +static int cam_vfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + + rsrc_data->irq_enabled = 0; + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->unpacker_cfg = 0; + rsrc_data->burst_len = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rm_res->tasklet_info = NULL; + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rm_data->common_data; + uint32_t buf_size; + uint32_t val; + uint32_t offset; + + CAM_DBG(CAM_ISP, "w: 0x%x", rm_data->width); + CAM_DBG(CAM_ISP, "h: 0x%x", rm_data->height); + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", rm_data->fs_sync_enable); + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", rm_data->fs_line_sync_en); + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + + /* Write All the values*/ + offset = rm_data->hw_regs->buffer_width_cfg; + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + cam_io_w_mb(buf_size, common_data->mem_base + offset); + CAM_DBG(CAM_ISP, "buf_size: 0x%x", buf_size); + + val = rm_data->width; + offset = rm_data->hw_regs->stride; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + CAM_DBG(CAM_ISP, "rm_data->unpacker_cfg:0x%x", rm_data->unpacker_cfg); + val = cam_vfe_bus_get_unpacker_fmt(rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, " value:0x%x", val); + offset = rm_data->hw_regs->unpacker_cfg; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + val = rm_data->latency_buf_allocation; + offset = rm_data->hw_regs->latency_buf_allocation; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + cam_io_w_mb(0x1, common_data->mem_base + + rm_data->hw_regs->cfg); + return rc; +} + +static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rsrc_data->common_data; + + /* Disable RM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return rc; +} + +static int cam_vfe_bus_init_rm_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_rm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for RM res priv"); + return -ENOMEM; + } + rm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &bus_rd_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver1_bus_rd_priv->common_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = cam_vfe_bus_start_rm; + rm_res->stop = cam_vfe_bus_stop_rm; + rm_res->hw_intf = ver1_bus_rd_priv->common_data.hw_intf; + + + return 0; +} + +static int cam_vfe_bus_deinit_rm_resource( + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = NULL; + rm_res->stop = NULL; + rm_res->top_half_handler = NULL; + rm_res->bottom_half_handler = NULL; + rm_res->hw_intf = NULL; + + rsrc_data = rm_res->res_priv; + rm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type bus_rd_res_id; + int num_rm; + uint32_t subscribe_irq; + uint32_t client_done_mask; + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv = + bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *bus_rd_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + bus_rd_acquire_args = &acq_args->vfe_bus_rd; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + acq_args->rsrc_type); + + bus_rd_res_id = cam_vfe_bus_get_bus_rd_res_id( + acq_args->rsrc_type); + if (bus_rd_res_id == CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) + return -ENODEV; + + num_rm = cam_vfe_bus_get_num_rm(bus_rd_res_id); + if (num_rm < 1) + return -EINVAL; + + rsrc_node = &ver1_bus_rd_priv->vfe_bus_rd[bus_rd_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + bus_rd_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + secure_caps = cam_vfe_bus_can_be_secure( + rsrc_data->bus_rd_type); + + mode = bus_rd_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + rsrc_data->num_rm = num_rm; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; + + subscribe_irq = 1; + + for (i = 0; i < num_rm; i++) { + rc = cam_vfe_bus_acquire_rm(ver1_bus_rd_priv, + bus_rd_acquire_args->out_port_info, + acq_args->tasklet, + bus_rd_acquire_args->ctx, + bus_rd_res_id, + i, + subscribe_irq, + &rsrc_data->rm_res[i], + &client_done_mask, + bus_rd_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d RM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + bus_rd_res_id, rc); + goto release_rm; + } + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + bus_rd_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_rm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_rm(ver1_bus_rd_priv, rsrc_data->rm_res[i]); + return rc; +} + +static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_bus_rd = release_args; + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_bus_rd->res_state); + } + + for (i = 0; i < rsrc_data->num_rm; i++) + cam_vfe_bus_release_rm(bus_priv, rsrc_data->rm_res[i]); + rsrc_data->num_rm = 0; + + vfe_bus_rd->tasklet_info = NULL; + vfe_bus_rd->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->bus_rd_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_bus_rd( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource type: %x", rsrc_data->bus_rd_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_start_rm(rsrc_data->rm_res[i]); + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_bus_rd( + struct cam_isp_resource_node *vfe_bus_rd) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + CAM_DBG(CAM_ISP, "E:Stop rd Res"); + if (!vfe_bus_rd) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", + vfe_bus_rd->res_state); + return rc; + } + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_stop_rm(rsrc_data->rm_res[i]); + + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info) +{ + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_bus_rd_resc_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + + if (vfe_bus_rd_resc_type < 0 || + vfe_bus_rd_resc_type > CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_bus_rd_resc_type); + return -EINVAL; + } + + vfe_bus_rd = &bus_rd_priv->vfe_bus_rd[vfe_bus_rd_resc_type]; + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_bus_rd->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_bus_rd->res_priv = rsrc_data; + + vfe_bus_rd->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd->list); + + rsrc_data->bus_rd_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + rsrc_data->common_data = &bus_rd_priv->common_data; + rsrc_data->max_width = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_width; + rsrc_data->max_height = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_bus_rd->start = cam_vfe_bus_start_vfe_bus_rd; + vfe_bus_rd->stop = cam_vfe_bus_stop_vfe_bus_rd; + vfe_bus_rd->process_cmd = cam_vfe_bus_process_cmd; + vfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_bus_rd_resource( + struct cam_isp_resource_node *vfe_bus_rd_res) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + vfe_bus_rd_res->res_priv; + + if (vfe_bus_rd_res->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_bus_rd_res->start = NULL; + vfe_bus_rd_res->stop = NULL; + vfe_bus_rd_res->top_half_handler = NULL; + vfe_bus_rd_res->bottom_half_handler = NULL; + vfe_bus_rd_res->hw_intf = NULL; + + vfe_bus_rd_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd_res->list); + vfe_bus_rd_res->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_ver1_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "BUS READ IRQ Received"); + return 0; +} + +static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t val; + uint32_t buf_size = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "#of RM: %d", vfe_bus_rd_data->num_rm); + if (update_buf->rm_update->num_buf != vfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + vfe_bus_rd_data->num_rm); + return -EINVAL; + } + + reg_val_pair = &vfe_bus_rd_data->common_data->io_buf_update[0]; + io_cfg = update_buf->rm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_bus_rd_data->num_rm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + + /* update size register */ + rm_data->width = io_cfg->planes[i].width; + rm_data->height = io_cfg->planes[i].height; + CAM_DBG(CAM_ISP, "RM %d image w 0x%x h 0x%x image size 0x%x", + rm_data->index, rm_data->width, rm_data->height, + buf_size); + + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + + CAM_DBG(CAM_ISP, "size offset 0x%x buf_size 0x%x", + rm_data->hw_regs->buf_size, buf_size); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buffer_width_cfg, + buf_size); + CAM_DBG(CAM_ISP, "RM %d image size 0x%x", + rm_data->index, reg_val_pair[j-1]); + + val = rm_data->width; + CAM_DBG(CAM_ISP, "io_cfg stride 0x%x", val); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->stride, + val); + rm_data->stride = val; + CAM_DBG(CAM_ISP, "RM %d image stride 0x%x", + rm_data->index, reg_val_pair[j-1]); + + /* RM Image address */ + CAM_DBG(CAM_ISP, "image_addr offset %x", + rm_data->hw_regs->image_addr); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->image_addr, + update_buf->rm_update->image_buf[i] + + rm_data->offset); + CAM_DBG(CAM_ISP, "RM %d image address 0x%x", + rm_data->index, reg_val_pair[j-1]); + rm_data->img_addr = reg_val_pair[j-1]; + + } + + size = vfe_bus_rd_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_bus_rd_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_rd_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + struct cam_vfe_fe_update_args *fe_upd_args; + struct cam_fe_config *fe_cfg; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + int i = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + fe_upd_args = (struct cam_vfe_fe_update_args *)cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + fe_upd_args->node_res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + fe_cfg = &fe_upd_args->fe_config; + + for (i = 0; i < vfe_bus_rd_data->num_rm; i++) { + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + common_data = rm_data->common_data; + + rm_data->format = fe_cfg->format; + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + + rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + + rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + + rm_data->stride = fe_cfg->stride; + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + + rm_data->go_cmd_sel = fe_cfg->go_cmd_sel; + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + + rm_data->fs_sync_enable = fe_cfg->fs_sync_enable; + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", + rm_data->fs_sync_enable); + + rm_data->hbi_count = fe_cfg->hbi_count; + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + + rm_data->fs_line_sync_en = fe_cfg->fs_line_sync_en; + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", + rm_data->fs_line_sync_en); + + rm_data->fs_mode = fe_cfg->fs_mode; + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + + rm_data->min_vbi = fe_cfg->min_vbi; + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + } + bus_priv->common_data.fs_sync_enable = fe_cfg->fs_sync_enable; + bus_priv->common_data.go_cmd_sel = fe_cfg->go_cmd_sel; + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[2] = {0}; + uint32_t offset = 0, val = 0; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + common_reg = bus_priv->common_data.common_reg; + top_irq_reg_mask[0] = (1 << 23); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_rd_ver1_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + return -EFAULT; + } + /* no clock gating at bus input */ + offset = common_reg->cgc_ovd; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* BUS_RD_TEST_BUS_CTRL */ + offset = common_reg->test_bus_ctrl; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* Read irq mask */ + offset = common_reg->irq_reg_info.irq_reg_set->mask_reg_offset; + cam_io_w_mb(0x5, bus_priv->common_data.mem_base + offset); + + /* INPUT_IF_CMD */ + val = (bus_priv->common_data.fs_sync_enable << 5) | + (bus_priv->common_data.go_cmd_sel << 4); + offset = common_reg->input_if_cmd; + cam_io_w_mb(val, bus_priv->common_data.mem_base + offset); + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to unsubscribe error irq rc=%d", rc); + + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to unsubscribe irq rc=%d", rc); + + bus_priv->irq_handle = 0; + } + + return rc; +} + +static int __cam_vfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + rc = cam_vfe_bus_rd_update_rm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + rc = cam_vfe_bus_rd_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = cam_vfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_rd_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = bus_rd_hw_info->num_client; + bus_priv->num_bus_rd_resc = + bus_rd_hw_info->num_bus_rd_resc; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &bus_rd_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_rm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init RM failed rc=%d", rc); + goto deinit_rm; + } + } + + for (i = 0; i < bus_priv->num_bus_rd_resc; i++) { + rc = cam_vfe_bus_init_vfe_bus_read_resource(i, bus_priv, + bus_rd_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_bus_rd; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_bus_rd; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_bus_rd; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_rd_ver1_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + return rc; + +deinit_vfe_bus_rd: + if (i < 0) + i = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); +deinit_rm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_rd_bus_ver1_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit RM failed rc=%d", rc); + } + for (i = 0; i < CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h new file mode 100644 index 000000000000..9ab2911d6472 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h @@ -0,0 +1,143 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CAM_VFE_BUS_R_VER1_H_ +#define _CAM_VFE_BUS_R_VER1_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_RD_VER1_MAX_CLIENTS 1 + +enum cam_vfe_bus_rd_ver1_vfe_core_id { + CAM_VFE_BUS_RD_VER1_VFE_CORE_0, + CAM_VFE_BUS_RD_VER1_VFE_CORE_1, + CAM_VFE_BUS_RD_VER1_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_rd_ver1_comp_grp_type { + CAM_VFE_BUS_RD_VER1_COMP_GRP_0, + CAM_VFE_BUS_RD_VER1_COMP_GRP_MAX, +}; + + +enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type { + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX, +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t input_if_cmd; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_bus_client { + uint32_t status0; + uint32_t status1; + uint32_t cfg; + uint32_t header_addr; + uint32_t header_cfg; + uint32_t image_addr; + uint32_t image_addr_offset; + uint32_t buffer_width_cfg; + uint32_t buffer_height_cfg; + uint32_t unpacker_cfg; + uint32_t stride; + void *ubwc_regs; + uint32_t burst_limit; + uint32_t latency_buf_allocation; + uint32_t buf_size; +}; + +/* + * struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info { + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_rd_ver1_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_rd_ver1_hw_info { + struct cam_vfe_bus_rd_ver1_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + uint32_t num_bus_rd_resc; + struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info + vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; +}; + +/* + * cam_vfe_bus_rd_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_rd_bus_ver1_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_bus_ver1_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_R_VER1_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 7ee9f000a8c0..71285997fb4d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3268,24 +3268,27 @@ static int cam_vfe_bus_init_hw(void *hw_priv, NULL, NULL); - if (bus_priv->irq_handle <= 0) { + if ((int)bus_priv->irq_handle <= 0) { CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); return -EFAULT; } - bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( - bus_priv->common_data.bus_irq_controller, - CAM_IRQ_PRIORITY_0, - bus_error_irq_mask, - bus_priv, - cam_vfe_bus_error_irq_top_half, - cam_vfe_bus_err_bottom_half, - bus_priv->tasklet_info, - &tasklet_bh_api); - - if (bus_priv->irq_handle <= 0) { - CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); - return -EFAULT; + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_error_irq_top_half, + cam_vfe_bus_err_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if ((int)bus_priv->error_irq_handle <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS error IRQ %d", + bus_priv->error_irq_handle); + return -EFAULT; + } } /*Set Debug Registers*/ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h index 6f88bc7f5a99..4cdb28a0cb67 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #define CAM_VFE_BUS_VER_1_0 0x1000 #define CAM_VFE_BUS_VER_2_0 0x2000 +#define CAM_VFE_BUS_RD_VER_4_0 0x4000 enum cam_vfe_bus_plane_type { PLANE_Y, @@ -26,6 +27,12 @@ enum cam_vfe_bus_plane_type { PLANE_MAX, }; +enum cam_vfe_bus_type { + BUS_TYPE_WR, + BUS_TYPE_RD, + BUS_TYPE_MAX, +}; + /* * struct cam_vfe_bus: * @@ -50,6 +57,7 @@ struct cam_vfe_bus { * @Brief: Initialize Bus layer * * @bus_version: Version of BUS to initialize + * @bus_type: Bus Type RD/WR * @soc_info: Soc Information for the associated HW * @hw_intf: HW Interface of HW to which this resource belongs * @bus_hw_info: BUS HW info that contains details of BUS registers @@ -62,6 +70,7 @@ struct cam_vfe_bus { * Non-zero: Failure */ int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, struct cam_hw_soc_info *soc_info, struct cam_hw_intf *hw_intf, void *bus_hw_info, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile index cdb6b2867433..eb867630d88e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -11,3 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vf obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_fe_ver1.o diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index 64b77eb7ccb8..b3c795417171 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -166,10 +166,7 @@ static int cam_vfe_camif_lite_resource_start( static int cam_vfe_camif_lite_resource_stop( struct cam_isp_resource_node *camif_lite_res) { - struct cam_vfe_mux_camif_lite_data *camif_lite_priv; - struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; int rc = 0; - uint32_t val = 0; if (!camif_lite_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -180,16 +177,6 @@ static int cam_vfe_camif_lite_resource_stop( (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) return 0; - camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *) - camif_lite_res->res_priv; - camif_lite_reg = camif_lite_priv->camif_lite_reg; - - val = cam_io_r_mb(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->core_cfg); - val &= (~(1 << camif_lite_priv->reg_data->dual_pd_path_sel_shift)); - cam_io_w_mb(val, camif_lite_priv->mem_base + - camif_lite_priv->common_reg->core_cfg); - if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 95bed8d9d23c..c40936525c73 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -212,8 +212,7 @@ static int cam_vfe_camif_resource_start( uint32_t epoch0_irq_mask; uint32_t epoch1_irq_mask; uint32_t computed_epoch_line_cfg; - uint32_t camera_hw_version = 0; - int rc = 0; + struct cam_vfe_soc_private *soc_private; if (!camif_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -228,6 +227,13 @@ static int cam_vfe_camif_resource_start( rsrc_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + /*config vfe core*/ val = (rsrc_data->pix_pattern << rsrc_data->reg_data->pixel_pattern_shift); @@ -253,26 +259,14 @@ static int cam_vfe_camif_resource_start( rsrc_data->common_reg->module_ctrl[ CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); - /* get the HW version */ - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - - if (rc) { - CAM_ERR(CAM_ISP, "Couldn't find HW version. rc: %d", rc); - return rc; - } - /* epoch config */ - switch (camera_hw_version) { + switch (soc_private->cpas_version) { case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: - cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, - rsrc_data->mem_base + - rsrc_data->camif_reg->epoch_irq); - break; default: - epoch0_irq_mask = ((rsrc_data->last_line - - rsrc_data->first_line) / 2) + + epoch0_irq_mask = (((rsrc_data->last_line - + rsrc_data->first_line) * 2) / 3) + rsrc_data->first_line; epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; @@ -316,27 +310,16 @@ static int cam_vfe_camif_resource_start( } static int cam_vfe_camif_reg_dump( - struct cam_isp_resource_node *camif_res) + struct cam_vfe_mux_camif_data *camif_priv) { - struct cam_vfe_mux_camif_data *camif_priv; - struct cam_vfe_soc_private *soc_private; - int rc = 0, i; - uint32_t val = 0; + uint32_t val = 0, wm_idx, offset; + int i = 0; - if (!camif_res) { - CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); - return -EINVAL; - } - - if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || - (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) - return 0; - - camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; - soc_private = camif_priv->soc_info->soc_private; - for (i = 0xA3C; i <= 0xA90; i += 4) { - val = cam_io_r_mb(camif_priv->mem_base + i); - CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + for (i = 0xA3C; i <= 0xA90; i += 8) { + CAM_INFO(CAM_ISP, + "SCALING offset 0x%x val 0x%x offset 0x%x val 0x%x", + i, cam_io_r_mb(camif_priv->mem_base + i), i + 4, + cam_io_r_mb(camif_priv->mem_base + i + 4)); } for (i = 0xE0C; i <= 0xE3C; i += 4) { @@ -344,64 +327,96 @@ static int cam_vfe_camif_reg_dump( CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); } - for (i = 0x2000; i <= 0x20B8; i += 4) { - val = cam_io_r_mb(camif_priv->mem_base + i); - CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); - } - - for (i = 0x2500; i <= 0x255C; i += 4) { - val = cam_io_r_mb(camif_priv->mem_base + i); - CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); - } - - for (i = 0x2600; i <= 0x265C; i += 4) { - val = cam_io_r_mb(camif_priv->mem_base + i); - CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + for (wm_idx = 0; wm_idx <= 23; wm_idx++) { + offset = 0x2214 + 0x100 * wm_idx; + CAM_INFO(CAM_ISP, + "BUS_WM%u offset 0x%x val 0x%x offset 0x%x val 0x%x", + wm_idx, offset, + cam_io_r_mb(camif_priv->mem_base + offset), + offset + 4, cam_io_r_mb(camif_priv->mem_base + + offset + 4)); + CAM_INFO(CAM_ISP, + "offset+8 0x%x val+8 0x%x offset+12 0x%x val+12 0x%x", + offset + 8, + cam_io_r_mb(camif_priv->mem_base + offset + 8), + offset + 12, cam_io_r_mb(camif_priv->mem_base + + offset + 12)); } - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x420, true, &val); - CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + offset = 0x420; + val = cam_soc_util_r(camif_priv->soc_info, 1, offset); + CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x", + offset, val); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x820, true, &val); - CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + offset = 0x820; + val = cam_soc_util_r(camif_priv->soc_info, 1, offset); + CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x", + offset, val); - return rc; + return 0; } -static int cam_vfe_camif_reg_dump_bh(struct cam_vfe_mux_camif_data *camif_priv) +static int cam_vfe_camif_reg_dump_bh( + struct cam_isp_resource_node *camif_res) { + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; uint32_t offset, val, wm_idx; + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; for (offset = 0x0; offset < 0x1000; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } for (offset = 0x2000; offset <= 0x20B8; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } for (wm_idx = 0; wm_idx <= 23; wm_idx++) { for (offset = 0x2200 + 0x100 * wm_idx; offset < 0x2278 + 0x100 * wm_idx; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } } - offset = 0x420; - val = cam_soc_util_r(camif_priv->soc_info, 1, offset); - CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x", - offset, val); - - offset = 0x820; - val = cam_soc_util_r(camif_priv->soc_info, 1, offset); - CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x", - offset, val); + soc_private = camif_priv->soc_info->soc_private; + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_DBG(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_DBG(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle[1], + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_DBG(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + } else { + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_DBG(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_DBG(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } return 0; } @@ -483,7 +498,7 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, arg_size); break; case CAM_ISP_HW_CMD_GET_REG_DUMP: - rc = cam_vfe_camif_reg_dump(rsrc_node); + rc = cam_vfe_camif_reg_dump_bh(rsrc_node); break; case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); @@ -573,11 +588,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, } break; case CAM_ISP_HW_EVENT_ERROR: - if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { + if (irq_status1 & camif_priv->reg_data->error_irq_mask1 && + payload->enable_reg_dump) { CAM_DBG(CAM_ISP, "Received ERROR\n"); ret = CAM_ISP_HW_ERROR_OVERFLOW; - cam_vfe_camif_reg_dump(camif_node); - cam_vfe_camif_reg_dump_bh(camif_node->res_priv); + cam_vfe_camif_reg_dump(camif_node->res_priv); } else { ret = CAM_ISP_HW_ERROR_NONE; } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c new file mode 100644 index 000000000000..2432d7a5044b --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c @@ -0,0 +1,638 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_fe_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t fe_cfg_data; + uint32_t hbi_count; +}; + +static int cam_vfe_fe_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_fe_update( + struct cam_isp_resource_node *fe_res, + void *cmd_data, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + struct cam_vfe_fe_update_args *args = cmd_data; + uint32_t fe_cfg_data; + + if (arg_size != sizeof(struct cam_vfe_fe_update_args)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "fe_update->min_vbi = 0x%x", args->fe_config.min_vbi); + CAM_DBG(CAM_ISP, "fe_update->hbi_count = 0x%x", + args->fe_config.hbi_count); + CAM_DBG(CAM_ISP, "fe_update->fs_mode = 0x%x", args->fe_config.fs_mode); + CAM_DBG(CAM_ISP, "fe_update->fs_line_sync_en = 0x%x", + args->fe_config.fs_line_sync_en); + + fe_cfg_data = args->fe_config.min_vbi | + args->fe_config.fs_mode << 8 | + args->fe_config.fs_line_sync_en; + + rsrc_data = fe_res->res_priv; + rsrc_data->fe_cfg_data = fe_cfg_data; + rsrc_data->hbi_count = args->fe_config.hbi_count; + + CAM_DBG(CAM_ISP, "fe_cfg_data = 0x%x", fe_cfg_data); + return 0; +} + +static int cam_vfe_fe_get_reg_update( + struct cam_isp_resource_node *fe_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + if (cdm_args->rup_data->is_fe_enable && + (cdm_args->rup_data->res_bitmap & + (1 << CAM_IFE_REG_UPD_CMD_RDI1_BIT))) { + CAM_DBG(CAM_ISP, "Avoiding rup_upd for fe"); + cdm_args->cmd.used_bytes = 0; + return 0; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = fe_res->res_priv; + reg_val_pair[0] = rsrc_data->fe_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF res_id %d reg_update_cmd 0x%x offset 0x%x", + fe_res->res_id, reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *fe_res, + void *acquire_param) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_fe_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) { + CAM_ERR(CAM_ISP, "pix validation failed: id:%d pix_pattern %d", + fe_res->hw_intf->hw_idx, + acquire_data->vfe_in.in_port->test_pattern); + return rc; + } + + fe_data->sync_mode = acquire_data->vfe_in.sync_mode; + fe_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + fe_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + fe_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + fe_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + fe_data->first_line = acquire_data->vfe_in.in_port->line_start; + fe_data->last_line = acquire_data->vfe_in.in_port->line_stop; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + fe_res->hw_intf->hw_idx, + fe_data->pix_pattern, fe_data->dsp_mode); + return rc; +} + +static int cam_vfe_fe_resource_init( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_fe_resource_deinit( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; + +} + +static int cam_vfe_fe_resource_start( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid fe res res_state:%d", + fe_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + /* config vfe core */ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->fe_cfg_data) { + /*set Mux mode value to EXT_RD_PATH */ + val |= (rsrc_data->reg_data->fe_mux_data << + rsrc_data->reg_data->input_mux_sel_shift); + } + + if (rsrc_data->hbi_count) { + /*set hbi count*/ + val |= (rsrc_data->hbi_count << + rsrc_data->reg_data->hbi_cnt_shift); + } + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->common_reg->core_cfg, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - rsrc_data->first_line) / 2) + + rsrc_data->first_line; + + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + rsrc_data->fe_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line:0x%x last_line:0x%x epoch_line_cfg: 0x%x", + rsrc_data->first_line, rsrc_data->last_line, + computed_epoch_line_cfg); + + fe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Read Back cfg */ + cam_io_w_mb(rsrc_data->fe_cfg_data, + rsrc_data->mem_base + rsrc_data->fe_reg->fe_cfg); + CAM_DBG(CAM_ISP, "hw id:%d fe_cfg_data(off:0x%x val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->fe_cfg, + rsrc_data->fe_cfg_data); + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->fe_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->reg_update_cmd, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", fe_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_fe_reg_dump( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0, i; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + soc_private = fe_priv->soc_info->soc_private; + for (i = 0xA3C; i <= 0xA90; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0xE0C; i <= 0xE3C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2000; i <= 0x20B8; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2500; i <= 0x255C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2600; i <= 0x265C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + cam_cpas_reg_read((uint32_t)soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read((uint32_t)soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + + return rc; +} + +static int cam_vfe_fe_resource_stop( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_fe_ver1_reg *fe_reg; + int rc = 0; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + fe_reg = fe_priv->fe_reg; + + if ((fe_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + val &= (~(1 << fe_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + fe_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_fe_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_fe_data *fe_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + fe_priv = + (struct cam_vfe_mux_fe_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + fe_priv->enable_sof_irq_debug = true; + else + fe_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_fe_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_fe_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_DUMP: + rc = cam_vfe_fe_reg_dump(rsrc_node); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_fe_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_fe_update(rsrc_node, cmd_args, arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_fe_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_fe_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *fe_node; + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_top_irq_evt_payload *payload; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + fe_node = handler_priv; + fe_priv = fe_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + CAM_DBG(CAM_ISP, "event ID:%d, irq_status_0 = 0x%x", + payload->evt_id, irq_status0); + + switch (payload->evt_id) { + case CAM_ISP_HW_EVENT_SOF: + if (irq_status0 & fe_priv->reg_data->sof_irq_mask) { + if ((fe_priv->enable_sof_irq_debug) && + (fe_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + fe_priv->irq_debug_cnt++; + if (fe_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + fe_priv->enable_sof_irq_debug = + false; + fe_priv->irq_debug_cnt = 0; + } + } else { + CAM_DBG(CAM_ISP, "Received SOF"); + } + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_EPOCH: + if (irq_status0 & fe_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_REG_UPDATE: + if (irq_status0 & fe_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_EOF: + if (irq_status0 & fe_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF\n"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_ERROR: + if (irq_status1 & fe_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR\n"); + ret = CAM_ISP_HW_ERROR_OVERFLOW; + cam_vfe_fe_reg_dump(fe_node); + } else { + ret = CAM_ISP_HW_ERROR_NONE; + } + break; + default: + break; + } + + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *fe_hw_info, + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = NULL; + struct cam_vfe_fe_ver1_hw_info *fe_info = fe_hw_info; + + fe_priv = kzalloc(sizeof(struct cam_vfe_mux_fe_data), + GFP_KERNEL); + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! Failed to alloc for fe_priv"); + return -ENOMEM; + } + + fe_node->res_priv = fe_priv; + + fe_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + fe_priv->fe_reg = fe_info->fe_reg; + fe_priv->common_reg = fe_info->common_reg; + fe_priv->reg_data = fe_info->reg_data; + fe_priv->hw_intf = hw_intf; + fe_priv->soc_info = soc_info; + + fe_node->init = cam_vfe_fe_resource_init; + fe_node->deinit = cam_vfe_fe_resource_deinit; + fe_node->start = cam_vfe_fe_resource_start; + fe_node->stop = cam_vfe_fe_resource_stop; + fe_node->process_cmd = cam_vfe_fe_process_cmd; + fe_node->top_half_handler = cam_vfe_fe_handle_irq_top_half; + fe_node->bottom_half_handler = cam_vfe_fe_handle_irq_bottom_half; + + return 0; +} + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = fe_node->res_priv; + + fe_node->start = NULL; + fe_node->stop = NULL; + fe_node->process_cmd = NULL; + fe_node->top_half_handler = NULL; + fe_node->bottom_half_handler = NULL; + + fe_node->res_priv = NULL; + + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! fe_priv is NULL"); + return -ENODEV; + } + + kfree(fe_priv); + + return 0; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h new file mode 100644 index 000000000000..0f8d2f18d1ec --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#ifndef _CAM_VFE_FE_VER1_H_ +#define _CAM_VFE_FE_VER1_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_fe_ver1_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; + uint32_t fe_cfg; +}; + +struct cam_vfe_fe_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t fe_mux_data; + uint32_t hbi_cnt_shift; +}; + +struct cam_vfe_fe_ver1_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_fe_reg_data *reg_data; +}; + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node); + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_FE_VER1_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 230698f7f890..c2c1bc20463b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -64,6 +64,14 @@ static int cam_vfe_rdi_get_reg_update( return -EINVAL; } + if (cdm_args->rup_data->is_fe_enable && + (cdm_args->rup_data->res_bitmap & + (1 << CAM_IFE_REG_UPD_CMD_PIX_BIT))) { + cdm_args->cmd.used_bytes = 0; + CAM_DBG(CAM_ISP, "Avoiding reg_upd for fe for rdi"); + return 0; + } + rsrc_data = rdi_res->res_priv; reg_val_pair[0] = rsrc_data->rdi_reg->reg_update_cmd; reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index f54f52af5334..569bbb6b2ce0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,11 +37,13 @@ struct cam_vfe_top_ver2_priv { struct cam_axi_vote applied_axi_vote; struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; - struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX * + struct cam_axi_vote last_vote[CAM_CPAS_HANDLE_MAX] + [CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; - uint32_t last_counter; + uint32_t last_counter[CAM_CPAS_HANDLE_MAX]; enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; + enum cam_cpas_handle_id cpashdl_type[CAM_VFE_TOP_VER2_MUX_MAX]; }; static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, @@ -133,99 +135,131 @@ static int cam_vfe_top_set_axi_bw_vote( struct cam_vfe_soc_private *soc_private = soc_info->soc_private; bool apply_bw_update = false; + enum cam_cpas_handle_id cpashdl_type; + struct cam_axi_vote *last_vote = NULL; if (!soc_private) { CAM_ERR(CAM_ISP, "Error soc_private NULL"); return -EINVAL; } - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->axi_vote_control[i] == - CAM_VFE_BW_CONTROL_INCLUDE) { - sum.uncompressed_bw += + for (cpashdl_type = 0; cpashdl_type < CAM_CPAS_HANDLE_MAX; + cpashdl_type++) { + + if ((soc_private->cpas_version != CAM_CPAS_TITAN_175_V120) + && cpashdl_type) + continue; + + sum.uncompressed_bw = sum.compressed_bw = 0; + to_be_applied_axi_vote.uncompressed_bw = 0; + to_be_applied_axi_vote.compressed_bw = 0; + apply_bw_update = false; + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE && + top_priv->cpashdl_type[i] == + cpashdl_type) { + sum.uncompressed_bw += top_priv->req_axi_vote[i].uncompressed_bw; - sum.compressed_bw += + sum.compressed_bw += top_priv->req_axi_vote[i].compressed_bw; + } } - } - - CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)", - top_priv->applied_axi_vote.uncompressed_bw, - top_priv->applied_axi_vote.compressed_bw, - sum.uncompressed_bw, - sum.compressed_bw); - top_priv->last_vote[top_priv->last_counter] = sum; - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - - if ((top_priv->applied_axi_vote.uncompressed_bw == - sum.uncompressed_bw) && - (top_priv->applied_axi_vote.compressed_bw == - sum.compressed_bw)) { - CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu", + CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)", top_priv->applied_axi_vote.uncompressed_bw, - top_priv->applied_axi_vote.compressed_bw); - return 0; - } + top_priv->applied_axi_vote.compressed_bw, + sum.uncompressed_bw, + sum.compressed_bw); - if (start_stop == true) { - /* need to vote current request immediately */ - to_be_applied_axi_vote = sum; - /* Reset everything, we can start afresh */ - memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; - top_priv->last_vote[top_priv->last_counter] = sum; - top_priv->last_counter = (top_priv->last_counter + 1) % + last_vote = top_priv->last_vote[cpashdl_type]; + + last_vote[top_priv->last_counter[cpashdl_type]] = sum; + top_priv->last_counter[cpashdl_type] = + (top_priv->last_counter[cpashdl_type] + 1) % (CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - } else { + + if ((top_priv->applied_axi_vote.uncompressed_bw == + sum.uncompressed_bw) && + (top_priv->applied_axi_vote.compressed_bw == + sum.compressed_bw)) { + CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu", + top_priv->applied_axi_vote.uncompressed_bw, + top_priv->applied_axi_vote.compressed_bw); + return 0; + } + + if (start_stop == true) { + rc = cam_cpas_update_axi_vote( + soc_private->cpas_handle[cpashdl_type], + &to_be_applied_axi_vote); + if (!rc) { + top_priv->applied_axi_vote.uncompressed_bw = + to_be_applied_axi_vote.uncompressed_bw; + top_priv->applied_axi_vote.compressed_bw = + to_be_applied_axi_vote.compressed_bw; + } + return rc; + } + /* - * Find max bw request in last few frames. This will the bw - *that we want to vote to CPAS now. + * Find max bw request in last few frames. This is the bw + * that we want to vote to CPAS now. */ for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { if (to_be_applied_axi_vote.compressed_bw < - top_priv->last_vote[i].compressed_bw) + last_vote[i].compressed_bw) to_be_applied_axi_vote.compressed_bw = - top_priv->last_vote[i].compressed_bw; + last_vote[i].compressed_bw; if (to_be_applied_axi_vote.uncompressed_bw < - top_priv->last_vote[i].uncompressed_bw) + last_vote[i].uncompressed_bw) to_be_applied_axi_vote.uncompressed_bw = - top_priv->last_vote[i].uncompressed_bw; + last_vote[i].uncompressed_bw; } - } - if ((to_be_applied_axi_vote.uncompressed_bw != - top_priv->applied_axi_vote.uncompressed_bw) || - (to_be_applied_axi_vote.compressed_bw != - top_priv->applied_axi_vote.compressed_bw)) - apply_bw_update = true; + if ((to_be_applied_axi_vote.uncompressed_bw != + top_priv->applied_axi_vote.uncompressed_bw) || + (to_be_applied_axi_vote.compressed_bw != + top_priv->applied_axi_vote.compressed_bw)) + apply_bw_update = true; - CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); + CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); - if (apply_bw_update == true) { - rc = cam_cpas_update_axi_vote( - soc_private->cpas_handle, - &to_be_applied_axi_vote); - if (!rc) { - top_priv->applied_axi_vote.uncompressed_bw = + if (apply_bw_update == true) { + rc = cam_cpas_update_axi_vote( + soc_private->cpas_handle[cpashdl_type], + &to_be_applied_axi_vote); + if (!rc) { + top_priv->applied_axi_vote.uncompressed_bw = to_be_applied_axi_vote.uncompressed_bw; - top_priv->applied_axi_vote.compressed_bw = - to_be_applied_axi_vote.compressed_bw; - } else { - CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + top_priv->applied_axi_vote.compressed_bw = + to_be_applied_axi_vote.compressed_bw; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", + rc); + } } } - return rc; } +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + static int cam_vfe_top_clock_update( struct cam_vfe_top_ver2_priv *top_priv, void *cmd_args, uint32_t arg_size) @@ -476,6 +510,14 @@ int cam_vfe_top_reserve(void *device_priv, break; } + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; top_priv->mux_rsrc[i].tasklet_info = args->tasklet; top_priv->mux_rsrc[i].res_state = @@ -583,6 +625,7 @@ int cam_vfe_top_stop(void *device_priv, if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF_LITE) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_RD) || ((mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && (mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3))) { rc = mux_res->stop(mux_res); @@ -643,6 +686,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_BW_UPDATE: rc = cam_vfe_top_bw_update(top_priv, cmd_args, arg_size); @@ -669,6 +716,7 @@ int cam_vfe_top_ver2_init( struct cam_vfe_top_ver2_priv *top_priv = NULL; struct cam_vfe_top_ver2_hw_info *ver2_hw_info = top_hw_info; struct cam_vfe_top *vfe_top; + struct cam_vfe_soc_private *soc_private = NULL; vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); if (!vfe_top) { @@ -684,14 +732,22 @@ int cam_vfe_top_ver2_init( rc = -ENOMEM; goto free_vfe_top; } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + rc = -ENODEV; + goto free_vfe_top_priv; + } vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; top_priv->applied_axi_vote.compressed_bw = 0; top_priv->applied_axi_vote.uncompressed_bw = 0; memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER2_MUX_MAX * + (CAM_VFE_TOP_VER2_MUX_MAX * CAM_CPAS_HANDLE_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; + top_priv->last_counter[0] = 0; + top_priv->last_counter[1] = 0; for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; @@ -707,6 +763,7 @@ int cam_vfe_top_ver2_init( if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { top_priv->mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_CAMIF; + top_priv->cpashdl_type[i] = CAM_CPAS_HANDLE_CAMIF; rc = cam_vfe_camif_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_hw_info, @@ -717,6 +774,13 @@ int cam_vfe_top_ver2_init( CAM_VFE_CAMIF_LITE_VER_2_0) { top_priv->mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_CAMIF_LITE; + if (soc_private->cpas_version == + CAM_CPAS_TITAN_175_V120) + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_RAW; + else + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_CAMIF; rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_lite_hw_info, @@ -729,12 +793,30 @@ int cam_vfe_top_ver2_init( /* set the RDI resource id */ top_priv->mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RDI0 + j++; + if (soc_private->cpas_version == + CAM_CPAS_TITAN_175_V120) + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_RAW; + else + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_CAMIF; rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info, &ver2_hw_info->rdi_hw_info, &top_priv->mux_rsrc[i]); if (rc) goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver2_hw_info->fe_hw_info, + &top_priv->mux_rsrc[i]); + if (rc) + goto deinit_resources; } else { CAM_WARN(CAM_ISP, "Invalid mux type: %u", ver2_hw_info->mux_type[i]); @@ -769,6 +851,12 @@ deinit_resources: if (cam_vfe_camif_lite_ver2_deinit( &top_priv->mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif lite deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_ISP_HW_VFE_IN_RDI0) { + if (cam_vfe_rdi_ver2_init(hw_intf, soc_info, + &ver2_hw_info->rdi_hw_info, + &top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "RDI deinit failed"); } else { if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i])) CAM_ERR(CAM_ISP, "RDI Deinit failed"); @@ -776,7 +864,7 @@ deinit_resources: top_priv->mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; } - +free_vfe_top_priv: kfree(vfe_top->top_priv); free_vfe_top: kfree(vfe_top); @@ -829,6 +917,12 @@ int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr) rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "RDI deinit failed rc=%d", rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); } } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 11ca78cd8a2e..33435df476d1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,8 +16,9 @@ #include "cam_vfe_camif_ver2.h" #include "cam_vfe_camif_lite_ver2.h" #include "cam_vfe_rdi.h" +#include "cam_vfe_fe_ver1.h" -#define CAM_VFE_TOP_VER2_MUX_MAX 5 +#define CAM_VFE_TOP_VER2_MUX_MAX 6 enum cam_vfe_top_ver2_module_type { CAM_VFE_TOP_VER2_MODULE_LENS, @@ -55,6 +56,7 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_ver2_hw_info camif_hw_info; struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX]; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h index 90c75291bd73..cee2b4a96cb4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,7 +24,8 @@ #define CAM_VFE_CAMIF_LITE_VER_2_0 0x02 -#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_IN_RD_VER_1_0 0x2000 struct cam_vfe_top { void *top_priv; diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 24bb154f922c..f27b54a81e4a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -258,7 +258,7 @@ static int cam_jpeg_insert_cdm_change_base( struct cam_jpeg_hw_ctx_data *ctx_data, struct cam_jpeg_hw_mgr *hw_mgr) { - int rc; + int rc = 0; uint32_t dev_type; struct cam_cdm_bl_request *cdm_cmd; uint32_t size; @@ -275,6 +275,12 @@ static int cam_jpeg_insert_cdm_change_base( "unable to get src buf info for cmd buf: %d", rc); return rc; } + + if (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset >= + ch_base_len) { + CAM_ERR(CAM_JPEG, "Not enough buf"); + return -EINVAL; + } CAM_DBG(CAM_JPEG, "iova %pK len %zu offset %d", (void *)iova_addr, ch_base_len, config_args->hw_update_entries[CAM_JPEG_CHBASE].offset); @@ -713,7 +719,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return -EINVAL; } - rc = cam_packet_util_validate_packet(packet); + rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); if (rc) { CAM_ERR(CAM_JPEG, "invalid packet %d", rc); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile b/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile index 5e46bf2531f8..83a580c23bc2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include/ obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/ diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h index dc1c8f4c10aa..b8d0357f6f3d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,7 +19,7 @@ #include "cam_req_mgr_interface.h" #include "cam_sync_api.h" -#define CAM_LRME_CTX_INDEX_SHIFT 16 +#define CAM_LRME_CTX_INDEX_SHIFT 32 /** * struct cam_lrme_context diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile index a048afece9db..2a4fba727773 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/ diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 0c236462b7f5..47bf68c16c03 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -83,7 +83,8 @@ static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr, return 0; } -static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -105,7 +106,7 @@ static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -186,6 +187,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, return -ENOMEM; } + if ((size_t)io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_LRME, "Invalid plane offset: %zu", + (size_t)io_cfg[i].offsets[plane]); + return -EINVAL; + } + io_addr[plane] += io_cfg[i].offsets[plane]; CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu", @@ -841,7 +848,7 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_lrme_mgr_util_packet_validate(args->packet); + rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len); if (rc) { CAM_ERR(CAM_LRME, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 8cb1c9c28e7a..4220e5993dd5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,7 +42,10 @@ static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf, uint32_t reg_val; /* 1. config buffer size */ - reg_val = io_buf->io_cfg->planes[0].width; + if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + reg_val = io_buf->io_cfg->planes[0].width * 2; + else + reg_val = io_buf->io_cfg->planes[0].width; reg_val |= (io_buf->io_cfg->planes[0].height << 16); cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size, @@ -736,6 +739,11 @@ int cam_lrme_hw_process_irq(void *priv, void *data) mutex_lock(&lrme_hw->hw_mutex); + if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_LRME, "LRME HW is in off state"); + goto end; + } + if (top_irq_status & (1 << 3)) { CAM_DBG(CAM_LRME, "Error"); rc = cam_lrme_hw_util_process_err(lrme_hw); @@ -895,7 +903,7 @@ int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size) lrme_core->state = CAM_LRME_CORE_STATE_INIT; } else { CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state); - return -EINVAL; + rc = -EINVAL; } unlock: diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c index 2d17f7b51cd7..cff48e599f04 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -241,6 +241,13 @@ exit_func: } EXPORT_SYMBOL(cam_mem_get_cpu_buf); +int cam_mem_put_cpu_buf(int32_t buf_handle) +{ + int rc = 0; + return rc; +} +EXPORT_SYMBOL(cam_mem_put_cpu_buf); + int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) { int rc = 0, idx; @@ -409,11 +416,6 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) { - if (!cmd->flags) { - CAM_ERR(CAM_MEM, "Invalid flags"); - return -EINVAL; - } - if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h index 64258e8fb5ee..79945cff1dd2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -95,6 +95,15 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len); +/** + * @brief: This indicates end of CPU access + * + * @buf_handle: Handle for the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_put_cpu_buf(int32_t buf_handle); + static inline bool cam_mem_is_secure_buf(int32_t buf_handle) { return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c index 275940f839e3..3e3be4f6281e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,31 @@ #include "cam_req_mgr_dev.h" static struct cam_req_mgr_core_device *g_crm_core_dev; +static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; + +void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) +{ + link->link_hdl = 0; + link->num_devs = 0; + link->max_delay = CAM_PIPELINE_DELAY_0; + link->workq = NULL; + link->pd_mask = 0; + link->l_dev = NULL; + link->req.in_q = NULL; + link->req.l_tbl = NULL; + link->req.num_tbl = 0; + link->watchdog = NULL; + link->state = CAM_CRM_LINK_STATE_AVAILABLE; + link->parent = NULL; + link->subscribe_event = 0; + link->trigger_mask = 0; + link->sync_link = 0; + link->sync_link_sof_skip = false; + link->open_req_cnt = 0; + link->last_flush_id = 0; + link->initial_sync_req = -1; + link->in_msync_mode = false; +} void cam_req_mgr_handle_core_shutdown(void) { @@ -117,31 +142,35 @@ static void __cam_req_mgr_dec_idx(int32_t *val, int32_t step, int32_t max_val) } /** - * __cam_req_mgr_validate_inject_delay() + * __cam_req_mgr_inject_delay() * - * @brief : Check if any pd device is introducing inject delay + * @brief : Check if any pd device is injecting delay * @tbl : cam_req_mgr_req_tbl * @curr_idx : slot idx * * @return : 0 for success, negative for failure */ -static int __cam_req_mgr_validate_inject_delay( +static int __cam_req_mgr_inject_delay( struct cam_req_mgr_req_tbl *tbl, int32_t curr_idx) { struct cam_req_mgr_tbl_slot *slot = NULL; + int rc = 0; while (tbl) { slot = &tbl->slot[curr_idx]; if (slot->inject_delay > 0) { slot->inject_delay--; - return -EAGAIN; + CAM_DBG(CAM_CRM, + "Delay injected by pd %d device", + tbl->pd); + rc = -EAGAIN; } __cam_req_mgr_dec_idx(&curr_idx, tbl->pd_delta, tbl->num_slots); tbl = tbl->next; } - return 0; + return rc; } /** @@ -183,19 +212,6 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, traverse_data->in_q->slot[curr_idx].skip_idx); - if ((traverse_data->self_link == true) && - (!traverse_data->inject_delay_chk)) { - rc = __cam_req_mgr_validate_inject_delay(tbl, curr_idx); - if (rc) { - CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); - apply_data[tbl->pd].req_id = -1; - /* This pd tbl not ready to proceed with asked idx */ - SET_FAILURE_BIT(traverse_data->result, tbl->pd); - return -EAGAIN; - } - traverse_data->inject_delay_chk = true; - } - /* Check if req is ready or in skip mode or pd tbl is in skip mode */ if (tbl->slot[curr_idx].state == CRM_REQ_STATE_READY || traverse_data->in_q->slot[curr_idx].skip_idx == 1 || @@ -356,6 +372,30 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, } /** + * __cam_req_mgr_check_for_lower_pd_devices() + * + * @brief : Checks if there are any devices on the link having a lesser + * pd than the max pd of the link + * @link : Pointer to link which needs to be checked + * + * @return : 0 if a lower pd device is found negative otherwise + */ +static int __cam_req_mgr_check_for_lower_pd_devices( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay < link->max_delay) + return 0; + } + + return -EAGAIN; +} + +/** * __cam_req_mgr_check_next_req_slot() * * @brief : While streaming if input queue does not contain any pending @@ -363,11 +403,14 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, * devices with lower pipeline delay value. * @in_q : Pointer to input queue where req mgr wil peep into * + * @return : 0 for success, negative for failure */ -static void __cam_req_mgr_check_next_req_slot( - struct cam_req_mgr_req_queue *in_q) +static int __cam_req_mgr_check_next_req_slot( + struct cam_req_mgr_core_link *link) { - int32_t idx = in_q->rd_idx; + int rc = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + int32_t idx = in_q->rd_idx; struct cam_req_mgr_slot *slot; __cam_req_mgr_inc_idx(&idx, 1, in_q->num_slots); @@ -377,12 +420,20 @@ static void __cam_req_mgr_check_next_req_slot( /* Check if there is new req from CSL, if not complete req */ if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + rc = __cam_req_mgr_check_for_lower_pd_devices(link); + if (rc) { + CAM_DBG(CAM_CRM, "No lower pd devices on link 0x%x", + link->link_hdl); + return rc; + } __cam_req_mgr_in_q_skip_idx(in_q, idx); if (in_q->wr_idx != idx) CAM_WARN(CAM_CRM, "CHECK here wr %d, rd %d", in_q->wr_idx, idx); __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); } + + return rc; } /** @@ -483,8 +534,6 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, continue; } - trace_cam_req_mgr_apply_request(link, &apply_req, dev); - apply_req.trigger_point = trigger; CAM_DBG(CAM_REQ, "SEND: link_hdl: %x pd %d req_id %lld", @@ -497,6 +546,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, if (pd == link->max_delay) link->open_req_cnt--; } + trace_cam_req_mgr_apply_request(link, &apply_req, dev); } } if (rc < 0) { @@ -526,14 +576,12 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, * traversed through * @idx : index within input request queue * @validate_only : Whether to validate only and/or update settings - * @self_link : To indicate whether the validation is for the given link or - * other sync link * * @return : 0 for success, negative for failure * */ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, - int32_t idx, bool validate_only, bool self_link) + int32_t idx, bool validate_only) { int rc; struct cam_req_mgr_traverse traverse_data; @@ -555,19 +603,16 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.in_q = in_q; traverse_data.result = 0; traverse_data.validate_only = validate_only; - traverse_data.self_link = self_link; - traverse_data.inject_delay_chk = false; traverse_data.open_req_cnt = link->open_req_cnt; + /* * Traverse through all pd tables, if result is success, * apply the settings */ - rc = __cam_req_mgr_traverse(&traverse_data); CAM_DBG(CAM_CRM, - "SOF: idx %d self_link %d validate %d result %x pd_mask %x rc %d", - idx, traverse_data.self_link, traverse_data.validate_only, - traverse_data.result, link->pd_mask, rc); + "SOF: idx %d result %x pd_mask %x rc %d", + idx, traverse_data.result, link->pd_mask, rc); if (!rc && traverse_data.result == link->pd_mask) { CAM_DBG(CAM_CRM, @@ -616,113 +661,218 @@ static int32_t __cam_req_mgr_find_slot_for_req( } /** - * __cam_req_mgr_reset_sof_cnt() + * __cam_req_mgr_check_sync_for_mslave() * - * @brief : the sof_count for both the links are reset - * @link : pointer to link whose input queue and req tbl are + * @brief : Processes requests during sync mode [master-slave] + * Here master corresponds to the link having a higher + * max_delay (pd) compared to the slave link. + * @link : Pointer to link whose input queue and req tbl are * traversed through + * @slot : Pointer to the current slot being processed + * @return : 0 for success, negative for failure * */ -static void __cam_req_mgr_reset_sof_cnt( - struct cam_req_mgr_core_link *link) +static int __cam_req_mgr_check_sync_for_mslave( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) { - link->sof_counter = -1; - link->sync_link->sof_counter = -1; - link->frame_skip_flag = false; + struct cam_req_mgr_core_link *sync_link = NULL; + struct cam_req_mgr_slot *sync_slot = NULL; + int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; + int64_t req_id = 0, sync_req_id = 0; - CAM_DBG(CAM_CRM, - "link_hdl %x self_counter %lld other_counter %lld frame_skip_lag %d", - link->link_hdl, link->sof_counter, - link->sync_link->sof_counter, link->frame_skip_flag); -} + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } -/** - * __cam_req_mgr_sof_cnt_initialize() - * - * @brief : when the sof count is intially -1 it increments count - * and computes the sync_self_ref for this link - * the count needs to be wrapped back starting from 0 - * @link : pointer to link whose input queue and req tbl are - * traversed through - * - */ -static void __cam_req_mgr_sof_cnt_initialize( - struct cam_req_mgr_core_link *link) -{ - link->sof_counter++; - link->sync_self_ref = link->sof_counter - - link->sync_link->sof_counter; + sync_link = link->sync_link; + req_id = slot->req_id; + sync_rd_idx = sync_link->req.in_q->rd_idx; CAM_DBG(CAM_CRM, - "link_hdl %x self_counter %lld other_counter %lld", - link->link_hdl, link->sof_counter, - link->sync_link->sof_counter); -} + "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", + link->link_hdl, req_id, link->sync_link_sof_skip, + link->open_req_cnt, link->initial_sync_req, + sync_link->initial_sync_req, link->is_master); -/** - * __cam_req_mgr_wrap_sof_cnt() - * - * @brief : once the sof count reaches a predefined maximum - * the count needs to be wrapped back starting from 0 - * @link : pointer to link whose input queue and req tbl are - * traversed through - * - */ -static void __cam_req_mgr_wrap_sof_cnt( - struct cam_req_mgr_core_link *link) -{ - link->sof_counter = (MAX_SYNC_COUNT - - (link->sync_link->sof_counter)); - link->sync_link->sof_counter = 0; + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_CRM, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } - CAM_DBG(CAM_CRM, - "link_hdl %x self_counter %lld sync_link_hdl %x other_counter %lld", - link->link_hdl, link->sof_counter, - link->sync_link->link_hdl, link->sync_link->sof_counter); -} + if (link->in_msync_mode && + sync_link->in_msync_mode && + (req_id - sync_link->req.in_q->slot[sync_rd_idx].req_id > + link->max_delay - sync_link->max_delay)) { + CAM_DBG(CAM_CRM, + "Req: %lld on link:%x need to hold for link: %x req:%d", + req_id, + link->link_hdl, + sync_link->link_hdl, + sync_link->req.in_q->slot[sync_rd_idx].req_id); + return -EINVAL; + } -/** - * __cam_req_mgr_validate_sof_cnt() - * - * @brief : validates sof count difference for a given link - * @link : pointer to link whose input queue and req tbl are - * traversed through - * @sync_link : pointer to the sync link - * @return : 0 for success, negative for failure - * - */ -static int __cam_req_mgr_validate_sof_cnt( - struct cam_req_mgr_core_link *link, - struct cam_req_mgr_core_link *sync_link) -{ - int64_t sync_diff = 0; - int rc = 0; + if (link->is_master) { + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } - if (link->sof_counter == MAX_SYNC_COUNT) - __cam_req_mgr_wrap_sof_cnt(link); + if (sync_link->initial_skip) { + CAM_DBG(CAM_CRM, "Link 0x%x [slave] not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } - sync_diff = link->sof_counter - sync_link->sof_counter; + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [master] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } - CAM_DBG(CAM_CRM, - "link[%x] self_counter=%lld other_counter=%lld diff=%lld sync_self_ref=%lld", - link->link_hdl, link->sof_counter, - sync_link->sof_counter, sync_diff, link->sync_self_ref); - - if (sync_diff > SYNC_LINK_SOF_CNT_MAX_LMT) { - link->sync_link->frame_skip_flag = true; - CAM_WARN(CAM_CRM, - "Detected anomaly, skip link_hdl %x self_counter=%lld other_counter=%lld sync_self_ref=%lld", - link->link_hdl, link->sof_counter, - sync_link->sof_counter, link->sync_self_ref); - rc = -EPERM; + prev_idx = slot->idx; + __cam_req_mgr_dec_idx(&prev_idx, + (link->max_delay - sync_link->max_delay), + link->req.in_q->num_slots); + + rd_idx = sync_link->req.in_q->rd_idx; + sync_req_id = link->req.in_q->slot[prev_idx].req_id; + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not found on link: %x [slave]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - rd_idx) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not next on link: %x [slave]", + sync_req_id, + sync_link->link_hdl); + return -EINVAL; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && + (sync_link->req.in_q->slot[sync_slot_idx].status + != CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [slave] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } else { + if (link->initial_skip) + link->initial_skip = false; + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [slave] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + next_idx = link->req.in_q->rd_idx; + rd_idx = sync_link->req.in_q->rd_idx; + __cam_req_mgr_inc_idx(&next_idx, + (sync_link->max_delay - link->max_delay), + link->req.in_q->num_slots); + + sync_req_id = link->req.in_q->slot[next_idx].req_id; + + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not found on link: %x [master]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - rd_idx) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not next on link: %x [master]", + sync_req_id, sync_link->link_hdl); + return -EINVAL; + } + + sync_slot = &sync_link->req.in_q->slot[sync_slot_idx]; + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && (sync_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not ready on [master] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } } - return rc; + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; } /** - * __cam_req_mgr_process_sync_req() + * __cam_req_mgr_check_sync_request_is_ready() * * @brief : processes requests during sync mode * @link : pointer to link whose input queue and req tbl are @@ -731,13 +881,13 @@ static int __cam_req_mgr_validate_sof_cnt( * @return : 0 for success, negative for failure * */ -static int __cam_req_mgr_process_sync_req( +static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_core_link *link, struct cam_req_mgr_slot *slot) { struct cam_req_mgr_core_link *sync_link = NULL; int64_t req_id = 0; - int sync_slot_idx = 0, rc = 0; + int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -748,94 +898,81 @@ static int __cam_req_mgr_process_sync_req( req_id = slot->req_id; CAM_DBG(CAM_REQ, - "link_hdl %x req %lld sync_self_ref %lld sof_counter %lld frame_skip_flag %d sync_link_self_ref %lld", - link->link_hdl, req_id, link->sync_self_ref, link->sof_counter, - link->frame_skip_flag, link->sync_link->sync_self_ref); + "link_hdl %x req %lld frame_skip_flag %d ", + link->link_hdl, req_id, link->sync_link_sof_skip); if (sync_link->sync_link_sof_skip) { CAM_DBG(CAM_REQ, "No req applied on corresponding SOF on sync link: %x", sync_link->link_hdl); sync_link->sync_link_sof_skip = false; - /*It is to manage compensate inject delay for each pd*/ - __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); - return -EINVAL; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; } - if (link->sof_counter == -1) { - __cam_req_mgr_sof_cnt_initialize(link); - } else if ((link->frame_skip_flag) && - (sync_link->sync_self_ref != -1)) { - CAM_DBG(CAM_REQ, "Link[%x] Req[%lld] Resetting values ", - link->link_hdl, req_id); - __cam_req_mgr_reset_sof_cnt(link); - __cam_req_mgr_sof_cnt_initialize(link); - } else { - link->sof_counter++; + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; } - rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); if (rc) { - CAM_DBG(CAM_REQ, + CAM_DBG(CAM_CRM, "Req: %lld [My link] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); link->sync_link_sof_skip = true; - goto failure; + return rc; } sync_slot_idx = __cam_req_mgr_find_slot_for_req( sync_link->req.in_q, req_id); - - if (sync_slot_idx != -1) { - rc = __cam_req_mgr_check_link_is_ready( - sync_link, sync_slot_idx, true, false); - CAM_DBG(CAM_CRM, "sync_slot_idx=%d, status=%d, rc=%d", - sync_slot_idx, - sync_link->req.in_q->slot[sync_slot_idx].status, - rc); - } else { - CAM_DBG(CAM_CRM, "sync_slot_idx=%d, rc=%d", - sync_slot_idx, rc); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", + req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; } - if ((sync_slot_idx != -1) && - ((sync_link->req.in_q->slot[sync_slot_idx].status == - CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) { - rc = __cam_req_mgr_validate_sof_cnt(link, sync_link); - if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld validate failed: %x", - req_id, sync_link->link_hdl); - goto failure; - } - - CAM_DBG(CAM_REQ, - "Req: %lld ready to apply on link: %x [validation successful]", - req_id, link->link_hdl); - /* - * At this point all validation is successfully done - * and we can proceed to apply the given request. - * Ideally the next call should return success. - */ - rc = __cam_req_mgr_check_link_is_ready(link, - slot->idx, false, true); - - if (rc) - CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); - } else { - CAM_DBG(CAM_REQ, - "Req: %lld [Other link] not ready to apply on link: %x", + sync_rd_idx = sync_link->req.in_q->rd_idx; + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - sync_rd_idx) >= 1) && + (sync_link->req.in_q->slot[sync_rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld [other link] not next req to be applied on link: %x", req_id, sync_link->link_hdl); - rc = -EPERM; + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); + if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [other link] link: %x, rc=%d", + req_id, sync_link->link_hdl, rc); link->sync_link_sof_skip = true; - goto failure; + return rc; } - return rc; + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); -failure: - link->sof_counter--; - return rc; + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; } /** @@ -896,11 +1033,41 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, goto error; } - if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) - rc = __cam_req_mgr_process_sync_req(link, slot); - else - rc = __cam_req_mgr_check_link_is_ready(link, - slot->idx, false, true); + if ((slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && + (link->sync_link)) { + if (link->is_master || link->sync_link->is_master) { + if (!link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = true; + } + + rc = __cam_req_mgr_check_sync_for_mslave( + link, slot); + } else { + rc = __cam_req_mgr_check_sync_req_is_ready( + link, slot); + } + } else { + if (link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave non sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = false; + link->initial_sync_req = -1; + if (link->sync_link) { + link->sync_link->initial_sync_req = -1; + link->sync_link->in_msync_mode = false; + } + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, + slot->idx); + if (!rc) + rc = __cam_req_mgr_check_link_is_ready(link, + slot->idx, false); + } if (rc < 0) { /* @@ -1344,25 +1511,25 @@ static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( session->num_links, MAXIMUM_LINKS_PER_SESSION); return NULL; } - - link = (struct cam_req_mgr_core_link *) - kzalloc(sizeof(struct cam_req_mgr_core_link), GFP_KERNEL); - if (!link) { - CAM_ERR(CAM_CRM, "failed to create link, no mem"); - return NULL; + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!atomic_cmpxchg(&g_links[i].is_used, 0, 1)) { + link = &g_links[i]; + CAM_DBG(CAM_CRM, "alloc link index %d", i); + cam_req_mgr_core_link_reset(link); + break; + } } + if (i == MAXIMUM_LINKS_PER_SESSION) + return NULL; + in_q = (struct cam_req_mgr_req_queue *) kzalloc(sizeof(struct cam_req_mgr_req_queue), GFP_KERNEL); if (!in_q) { CAM_ERR(CAM_CRM, "failed to create input queue, no mem"); - kfree(link); return NULL; } - mutex_init(&link->lock); - spin_lock_init(&link->link_state_spin_lock); mutex_lock(&link->lock); - link->state = CAM_CRM_LINK_STATE_AVAILABLE; link->num_devs = 0; link->max_delay = 0; memset(in_q->slot, 0, @@ -1399,7 +1566,6 @@ static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( return link; error: mutex_unlock(&session->lock); - kfree(link); kfree(in_q); return NULL; } @@ -1414,9 +1580,12 @@ error: */ static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link) { + ptrdiff_t i; kfree(link->req.in_q); link->req.in_q = NULL; - kfree(link); + i = link - g_links; + CAM_DBG(CAM_CRM, "free link index %d", i); + atomic_set(&g_links[i].is_used, 0); } /** @@ -1450,21 +1619,14 @@ static void __cam_req_mgr_unreserve_link( for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { if (session->links[i] == link) session->links[i] = NULL; - } - if ((session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) && - (link->sync_link)) { - /* - * make sure to unlink sync setup under the assumption - * of only having 2 links in a given session - */ - session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; - for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { - if (session->links[i]) + if (link->sync_link) { + if (link->sync_link == session->links[i]) session->links[i]->sync_link = NULL; } } + link->sync_link = NULL; session->num_links--; CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links); mutex_unlock(&session->lock); @@ -1544,6 +1706,9 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) mutex_lock(&link->req.lock); if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + link->last_flush_id = flush_info->req_id; + CAM_INFO(CAM_CRM, "Last request id to flush is %lld", + flush_info->req_id); for (i = 0; i < in_q->num_slots; i++) { slot = &in_q->slot[i]; slot->req_id = -1; @@ -1559,21 +1724,20 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) if (idx < 0) { CAM_ERR(CAM_CRM, "req_id %lld not found in input queue", flush_info->req_id); - mutex_unlock(&link->req.lock); - return -EINVAL; - } - CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", - flush_info->req_id, idx); - slot = &in_q->slot[idx]; - if (slot->status == CRM_SLOT_STATUS_REQ_PENDING || - slot->status == CRM_SLOT_STATUS_REQ_APPLIED) { - CAM_WARN(CAM_CRM, - "req_id %lld can not be cancelled", - flush_info->req_id); - mutex_unlock(&link->req.lock); - return -EINVAL; + } else { + CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", + flush_info->req_id, idx); + slot = &in_q->slot[idx]; + if (slot->status == CRM_SLOT_STATUS_REQ_PENDING || + slot->status == CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_WARN(CAM_CRM, + "req_id %lld can not be cancelled", + flush_info->req_id); + mutex_unlock(&link->req.lock); + return -EINVAL; + } + __cam_req_mgr_in_q_skip_idx(in_q, idx); } - __cam_req_mgr_in_q_skip_idx(in_q, idx); } for (i = 0; i < link->num_devs; i++) { @@ -1622,9 +1786,11 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) sched_req = (struct cam_req_mgr_sched_request *)&task_data->u; in_q = link->req.in_q; - CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld at slot %d sync_mode %d", + CAM_DBG(CAM_CRM, + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master:%d", sched_req->link_hdl, sched_req->req_id, - in_q->wr_idx, sched_req->sync_mode); + in_q->wr_idx, sched_req->sync_mode, + link->is_master); mutex_lock(&link->req.lock); slot = &in_q->slot[in_q->wr_idx]; @@ -1640,6 +1806,16 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) slot->recover = sched_req->bubble_enable; link->open_req_cnt++; __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + + if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + if (link->initial_sync_req == -1) + link->initial_sync_req = slot->req_id; + } else { + link->initial_sync_req = -1; + if (link->sync_link) + link->sync_link->initial_sync_req = -1; + } + mutex_unlock(&link->req.lock); end: @@ -1736,8 +1912,9 @@ int cam_req_mgr_process_add_req(void *priv, void *data) trace_cam_req_mgr_add_req(link, idx, add_req, tbl, device); if (slot->req_ready_map == tbl->dev_mask) { - CAM_DBG(CAM_REQ, "idx %d req_id %lld pd %d SLOT READY", - idx, add_req->req_id, tbl->pd); + CAM_DBG(CAM_REQ, + "link 0x%x idx %d req_id %lld pd %d SLOT READY", + link->link_hdl, idx, add_req->req_id, tbl->pd); slot->state = CRM_REQ_STATE_READY; } mutex_unlock(&link->req.lock); @@ -1895,14 +2072,22 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) * Check if any new req is pending in slot, if not finish the * lower pipeline delay device with available req ids. */ - CAM_DBG(CAM_CRM, "link[%x] Req[%lld] invalidating slot", + CAM_DBG(CAM_CRM, "link[%x] Req[%lld] invalidating slot", link->link_hdl, in_q->slot[in_q->rd_idx].req_id); - __cam_req_mgr_check_next_req_slot(in_q); + rc = __cam_req_mgr_check_next_req_slot(link); + if (rc) { + CAM_DBG(CAM_REQ, + "No pending req to apply to lower pd devices"); + rc = 0; + goto release_lock; + } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); } + rc = __cam_req_mgr_process_req(link, trigger_data->trigger); - mutex_unlock(&link->req.lock); +release_lock: + mutex_unlock(&link->req.lock); end: return rc; } @@ -2368,7 +2553,8 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) if (rc < 0) { CAM_ERR(CAM_CRM, "error destroying link hdl %x rc %d", link->link_hdl, rc); - } + } else + link->link_hdl = -1; mutex_unlock(&link->lock); return rc; @@ -2445,16 +2631,17 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) return -EINVAL; } + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } - mutex_lock(&g_crm_core_dev->crm_lock); - /* Allocate link struct and map it with session's request queue */ link = __cam_req_mgr_reserve_link(cam_session); if (!link) { @@ -2478,6 +2665,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) goto link_hdl_fail; } link_info->link_hdl = link->link_hdl; + link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, @@ -2524,7 +2712,7 @@ setup_failed: __cam_req_mgr_destroy_subdev(link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); - link_info->link_hdl = 0; + link_info->link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2603,6 +2791,17 @@ int cam_req_mgr_schedule_request( goto end; } + if (sched_req->req_id <= link->last_flush_id) { + CAM_INFO(CAM_CRM, + "request %lld is flushed, last_flush_id to flush %d", + sched_req->req_id, link->last_flush_id); + rc = -EINVAL; + goto end; + } + + if (sched_req->req_id > link->last_flush_id) + link->last_flush_id = 0; + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); @@ -2627,6 +2826,33 @@ end: return rc; } +/** + * __cam_req_mgr_set_master_link() + * + * @brief : Each links sets its max pd delay based on the devices on the + * link. The link with higher pd is assigned master. + * @link1 : One of the sync links + * @link2 : The other sync link + */ +static void __cam_req_mgr_set_master_link( + struct cam_req_mgr_core_link *link1, + struct cam_req_mgr_core_link *link2) +{ + + if (link1->max_delay > link2->max_delay) { + link1->is_master = true; + link2->initial_skip = true; + } else if (link2->max_delay > link1->max_delay) { + link2->is_master = true; + link1->initial_skip = true; + } + + CAM_DBG(CAM_CRM, + "link_hdl1[0x%x] is_master [%u] link_hdl2[0x%x] is_master[%u]", + link1->link_hdl, link1->is_master, + link2->link_hdl, link2->is_master); +} + int cam_req_mgr_sync_config( struct cam_req_mgr_sync_mode *sync_info) { @@ -2647,6 +2873,12 @@ int cam_req_mgr_sync_config( return -EINVAL; } + if ((sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_SYNC) && + (sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC)) { + CAM_ERR(CAM_CRM, "Invalid sync mode %d", sync_info->sync_mode); + return -EINVAL; + } + if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) { CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x", sync_info->link_hdls[0], sync_info->link_hdls[1]); @@ -2683,17 +2915,27 @@ int cam_req_mgr_sync_config( goto done; } - link1->sof_counter = -1; - link1->sync_self_ref = -1; - link1->frame_skip_flag = false; link1->sync_link_sof_skip = false; - link1->sync_link = link2; + link1->sync_link = NULL; - link2->sof_counter = -1; - link2->sync_self_ref = -1; - link2->frame_skip_flag = false; link2->sync_link_sof_skip = false; - link2->sync_link = link1; + link2->sync_link = NULL; + + link1->is_master = false; + link2->is_master = false; + link1->initial_skip = false; + link2->initial_skip = false; + + link1->in_msync_mode = false; + link2->in_msync_mode = false; + link1->initial_sync_req = -1; + link2->initial_sync_req = -1; + + if (sync_info->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + link1->sync_link = link2; + link2->sync_link = link1; + __cam_req_mgr_set_master_link(link1, link2); + } cam_session->sync_mode = sync_info->sync_mode; CAM_DBG(CAM_REQ, @@ -2791,7 +3033,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) goto end; } - if (control->num_links > MAX_LINKS_PER_SESSION) { + if ((control->num_links <= 0) || + (control->num_links > MAX_LINKS_PER_SESSION)) { CAM_ERR(CAM_CRM, "Invalid number of links %d", control->num_links); rc = -EINVAL; @@ -2860,6 +3103,7 @@ end: int cam_req_mgr_core_device_init(void) { + int i; CAM_DBG(CAM_CRM, "Enter g_crm_core_dev %pK", g_crm_core_dev); if (g_crm_core_dev) { @@ -2876,6 +3120,12 @@ int cam_req_mgr_core_device_init(void) mutex_init(&g_crm_core_dev->crm_lock); cam_req_mgr_debug_register(g_crm_core_dev); + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + mutex_init(&g_links[i].lock); + spin_lock_init(&g_links[i].link_state_spin_lock); + atomic_set(&g_links[i].is_used, 0); + cam_req_mgr_core_link_reset(&g_links[i]); + } return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h index b7222237473b..9bff66b36ebb 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -135,9 +135,6 @@ enum cam_req_mgr_link_state { * @apply_data : pointer which various tables will update during traverse * @in_q : input request queue pointer * @validate_only : Whether to validate only and/or update settings - * @self_link : To indicate whether the check is for the given link or - * the other sync link - * @inject_delay_chk : if inject delay has been validated for all pd devices * @open_req_cnt : Count of open requests yet to be serviced in the kernel. */ struct cam_req_mgr_traverse { @@ -147,8 +144,6 @@ struct cam_req_mgr_traverse { struct cam_req_mgr_apply *apply_data; struct cam_req_mgr_req_queue *in_q; bool validate_only; - bool self_link; - bool inject_delay_chk; int32_t open_req_cnt; }; @@ -308,15 +303,20 @@ struct cam_req_mgr_connected_device { * notification to CRM at those hw events. * @trigger_mask : mask on which irq the req is already applied * @sync_link : pointer to the sync link for synchronization - * @sof_counter : sof counter during sync_mode - * @sync_self_ref : reference sync count against which the difference - * between sync_counts for a given link is checked - * @frame_skip_flag : flag that determines if a frame needs to be skipped * @sync_link_sof_skip : flag determines if a pkt is not available for a given * frame in a particular link skip corresponding * frame in sync link as well. * @open_req_cnt : Counter to keep track of open requests that are yet * to be serviced in the kernel. + * @last_flush_id : Last request to flush + * @is_used : 1 if link is in use else 0 + * @is_master : Based on pd among links, the link with the highest pd + * is assigned as master + * @initial_skip : Flag to determine if slave has started streaming in + * master-slave sync + * @in_msync_mode : Flag to determine if a link is in master-slave mode + * @initial_sync_req : The initial req which is required to sync with the + * other link * */ struct cam_req_mgr_core_link { @@ -336,11 +336,14 @@ struct cam_req_mgr_core_link { uint32_t subscribe_event; uint32_t trigger_mask; struct cam_req_mgr_core_link *sync_link; - int64_t sof_counter; - int64_t sync_self_ref; - bool frame_skip_flag; bool sync_link_sof_skip; int32_t open_req_cnt; + uint32_t last_flush_id; + atomic_t is_used; + bool is_master; + bool initial_skip; + bool in_msync_mode; + int64_t initial_sync_req; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h index 1df3122109e6..1d1df45c6ea5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -50,7 +50,7 @@ typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); * @cam_req_mgr_link_setup : to establish link with device for a session * @cam_req_mgr_notify_err : to broadcast error happened on link for request id * @cam_req_mgr_apply_req : CRM asks device to apply certain request id. - * @cam_req_mgr_flush_req : Flush or cancle request + * @cam_req_mgr_flush_req : Flush or cancel request * cam_req_mgr_process_evt : generic events */ typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c index 12bc3ac47a8e..de6a2dc519df 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -224,8 +224,8 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, crm_workq->in_irq = in_irq; crm_workq->task.num_task = num_tasks; crm_workq->task.pool = (struct crm_workq_task *) - kzalloc(sizeof(struct crm_workq_task) * - crm_workq->task.num_task, + kcalloc(crm_workq->task.num_task, + sizeof(struct crm_workq_task), GFP_KERNEL); if (!crm_workq->task.pool) { CAM_WARN(CAM_CRM, "Insufficient memory %zu", diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h index af76ae467346..c24ee31959d6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,7 +26,8 @@ /* Flag to create a high priority workq */ #define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) -/* This flag ensures only one task from a given +/* + * This flag ensures only one task from a given * workq will execute at any given point on any * given CPU. */ diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c index b2a7dc0784f4..1262db7646dc 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include "cam_trace.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_actuator_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -214,12 +215,12 @@ static int32_t cam_actuator_i2c_modes_util( } int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info; - if (!a_ctrl || !cmd_buf) { + if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) { CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; } @@ -413,9 +414,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, int32_t i = 0; uint32_t total_cmd_buf_in_bytes = 0; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; uint32_t *cmd_buf = NULL; uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; struct common_header *cmm_hdr = NULL; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; @@ -442,23 +445,36 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, sizeof(config))) return -EFAULT; rc = cam_mem_get_cpu_buf(config.packet_handle, - &generic_ptr, &len_of_buff); + &generic_pkt_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d", rc); return rc; } - if (config.offset > len_of_buff) { + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { CAM_ERR(CAM_ACTUATOR, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buff); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto rel_pkt_buf; } - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_ACTUATOR, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); if ((csl_packet->header.op_code & 0xFFFFFF) != CAM_ACTUATOR_PACKET_OPCODE_INIT && @@ -467,7 +483,8 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "reject request %lld, last request to flush %lld", csl_packet->header.request_id, a_ctrl->last_flush_req); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } if (csl_packet->header.request_id > a_ctrl->last_flush_req) @@ -488,13 +505,22 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, &generic_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); - return rc; + goto rel_pkt_buf; } cmd_buf = (uint32_t *)generic_ptr; if (!cmd_buf) { CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); - return -EINVAL; + goto rel_cmd_buf; + } + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_ACTUATOR, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto rel_cmd_buf; } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; @@ -503,11 +529,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "Received slave info buffer"); rc = cam_actuator_slaveInfo_pkt_parser( - a_ctrl, cmd_buf); + a_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to parse slave info: %d", rc); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_PWR_UP: @@ -517,12 +543,12 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_ACTUATOR, "Failed:parse power settings: %d", rc); - return rc; + goto rel_cmd_buf; } break; default: @@ -542,10 +568,14 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, "Failed:parse init settings: %d", rc); - return rc; + goto rel_cmd_buf; } break; } + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_ACTUATOR, + "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { @@ -553,7 +583,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, " Actuator Power up failed"); - return rc; + goto rel_pkt_buf; } a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; } @@ -562,7 +592,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, &a_ctrl->i2c_data.init_settings); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); - return rc; + goto rel_pkt_buf; } /* Delete the request even if the apply is failed */ @@ -579,7 +609,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Not in right state to move lens: %d", a_ctrl->cam_act_state); - return rc; + goto rel_pkt_buf; } a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_NOW; @@ -599,7 +629,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Auto move lens parsing failed: %d", rc); - return rc; + goto rel_pkt_buf; } cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; @@ -609,7 +639,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Not in right state to move lens: %d", a_ctrl->cam_act_state); - return rc; + goto rel_pkt_buf; } a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; @@ -630,7 +660,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Manual move lens parsing failed: %d", rc); - return rc; + goto rel_pkt_buf; } cam_actuator_update_req_mgr(a_ctrl, csl_packet); @@ -640,13 +670,32 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Received NOP packets in invalid state: %d", a_ctrl->cam_act_state); - return -EINVAL; + goto rel_pkt_buf; } - cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; + default: + CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + goto rel_pkt_buf; } + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %llu", + config.packet_handle); + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %d", + cmd_desc[i].mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %llu", + config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 26d73a446a5b..228ccb8a39b3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -216,9 +216,7 @@ static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client, cam_actuator_establish_link; a_ctrl->bridge_intf.ops.apply_req = cam_actuator_apply_request; - - v4l2_set_subdevdata(&(a_ctrl->v4l2_dev_str.sd), a_ctrl); - + a_ctrl->last_flush_req = 0; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; return rc; @@ -245,19 +243,24 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) return 0; } + CAM_INFO(CAM_ACTUATOR, "platform remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + soc_private = (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; kfree(a_ctrl->io_master_info.cci_client); a_ctrl->io_master_info.cci_client = NULL; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(a_ctrl->soc_info.soc_private); + a_ctrl->soc_info.soc_private = NULL; kfree(a_ctrl->i2c_data.per_frame); a_ctrl->i2c_data.per_frame = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + platform_set_drvdata(pdev, NULL); devm_kfree(&pdev->dev, a_ctrl); return rc; @@ -265,7 +268,6 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) { - int32_t rc = 0; struct cam_actuator_ctrl_t *a_ctrl = i2c_get_clientdata(client); struct cam_actuator_soc_private *soc_private; @@ -277,6 +279,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_ACTUATOR, "i2c remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); soc_private = (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; @@ -284,14 +291,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) /*Free Allocated Mem */ kfree(a_ctrl->i2c_data.per_frame); a_ctrl->i2c_data.per_frame = NULL; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - kfree(a_ctrl->soc_info.soc_private); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; a_ctrl->soc_info.soc_private = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); kfree(a_ctrl); - return rc; + + return 0; } static const struct of_device_id cam_actuator_driver_dt_match[] = { @@ -376,7 +380,6 @@ static int32_t cam_actuator_driver_platform_probe( a_ctrl->last_flush_req = 0; platform_set_drvdata(pdev, a_ctrl); - v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, a_ctrl); a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c index b0e810711c5d..f41cb4753f39 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -892,20 +892,39 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, soc_info = &cci_dev->soc_info; base = soc_info->reg_map[0].mem_base; - mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); - /* - * Todo: If there is a change in frequency of operation - * Wait for previos transaction to complete - */ + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - goto rel_mutex; + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto rel_master; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -916,24 +935,24 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, master, queue); if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->data == NULL) { CAM_ERR(CAM_CCI, "Data ptr is NULL"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", read_cfg->addr_type); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", @@ -945,14 +964,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_LOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); @@ -964,21 +983,21 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_UNLOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR @@ -1009,7 +1028,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, cam_cci_dump_registers(cci_dev, master, queue); #endif cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } read_words = cam_io_r_mb(base + @@ -1090,7 +1109,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, master, queue); #endif cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } break; } @@ -1099,8 +1118,15 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, CAM_DBG(CAM_CCI, "Burst read successful words_read %d", total_read_words); -rel_mutex: +rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } @@ -1132,20 +1158,38 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, soc_info = &cci_dev->soc_info; base = soc_info->reg_map[0].mem_base; - mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); - - /* - * Todo: If there is a change in frequency of operation - * Wait for previos transaction to complete - */ + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { + mutex_unlock(&cci_dev->cci_master_info[master].mutex); CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - goto rel_mutex; + goto rel_master; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1156,17 +1200,17 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, master, queue); if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->data == NULL) { CAM_ERR(CAM_CCI, "Data ptr is NULL"); - goto rel_mutex; + goto rel_mutex_q; } CAM_DBG(CAM_CCI, "master %d, queue %d", master, queue); @@ -1179,21 +1223,21 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_LOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", read_cfg->addr_type); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); @@ -1205,21 +1249,21 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_UNLOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR @@ -1247,7 +1291,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, "wait_for_completion_timeout rc = %d FIFO buf_lvl: 0x%x", rc, val); cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } else { rc = 0; } @@ -1260,7 +1304,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, read_words, exp_words); memset(read_cfg->data, 0, read_cfg->num_byte); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } index = 0; CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); @@ -1284,8 +1328,15 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } read_words--; } -rel_mutex: +rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } @@ -1309,12 +1360,36 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, c_ctrl->cci_info->id_map); + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - return rc; + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto ERROR; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_write call. This is to @@ -1326,18 +1401,25 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - return rc; + goto ERROR; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - return rc; + goto ERROR; } rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); if (rc < 0) { CAM_ERR(CAM_CCI, "failed rc: %d", rc); - return rc; + goto ERROR; } +ERROR: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c index 5e522a8a5959..7934aa50767c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -151,7 +151,6 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) complete(&cci_dev->cci_master_info[MASTER_1].th_complete); complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); } - rd_done_th_assert = false; if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && (!rd_done_th_assert)) { cci_dev->cci_master_info[MASTER_1].status = 0; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h index 12abeabe0a38..349effcc057b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,7 @@ #include <linux/timer.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/semaphore.h> #include <media/cam_sensor.h> #include <media/v4l2-event.h> #include <media/v4l2-ioctl.h> @@ -144,6 +145,10 @@ struct cam_cci_master_info { struct completion report_q[NUM_QUEUES]; atomic_t done_pending[NUM_QUEUES]; spinlock_t lock_q[NUM_QUEUES]; + spinlock_t freq_cnt; + struct semaphore master_sem; + bool is_first_req; + uint16_t freq_ref_cnt; }; struct cam_cci_clk_params_t { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c index da714af3fde2..7d71cd57573e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -196,7 +196,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) for (i = 0; i < NUM_MASTERS; i++) { new_cci_dev->cci_master_info[i].status = 0; + new_cci_dev->cci_master_info[i].is_first_req = true; mutex_init(&new_cci_dev->cci_master_info[i].mutex); + sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); + spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); init_completion( &new_cci_dev->cci_master_info[i].reset_complete); init_completion( diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 9894b217ac2c..17499489184b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,8 @@ #include "cam_csiphy_dev.h" #include "cam_csiphy_soc.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + #include <soc/qcom/scm.h> #include <cam_mem_mgr.h> @@ -159,11 +161,13 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, { int32_t rc = 0; uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; uint32_t *cmd_buf = NULL; struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; size_t len; + size_t remain_len; if (!cfg_dev || !csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); @@ -171,21 +175,32 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, } rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle, - &generic_ptr, &len); + &generic_pkt_ptr, &len); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); return rc; } - if (cfg_dev->offset > len) { + remain_len = len; + if ((sizeof(struct cam_packet) > len) || + ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) { CAM_ERR(CAM_CSIPHY, - "offset is out of bounds: offset: %lld len: %zu", - cfg_dev->offset, len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len); + rc = -EINVAL; + goto rel_pkt_buf; } + remain_len -= (size_t)cfg_dev->offset; csl_packet = (struct cam_packet *) - (generic_ptr + (uint32_t)cfg_dev->offset); + (generic_pkt_ptr + (uint32_t)cfg_dev->offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_CSIPHY, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&csl_packet->payload + @@ -196,7 +211,15 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get cmd buf Mem address : %d", rc); - return rc; + goto rel_pkt_buf; + } + + if ((len < sizeof(struct cam_csiphy_info)) || + (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) { + CAM_ERR(CAM_CSIPHY, + "Not enough buffer provided for cam_cisphy_info"); + rc = -EINVAL; + goto rel_pkt_buf; } cmd_buf = (uint32_t *)generic_ptr; @@ -221,6 +244,15 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, cam_csiphy_update_secure_info(csiphy_dev, cam_cmd_csiphy_info, cfg_dev); + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_CSIPHY, "Failed to put cmd buffer: %d", + cmd_desc->mem_handle); + +rel_pkt_buf: + if (cam_mem_put_cpu_buf((int32_t) cfg_dev->packet_handle)) + CAM_WARN(CAM_CSIPHY, "Failed to put packet Mem address: %llu", + cfg_dev->packet_handle); + return rc; } @@ -567,6 +599,14 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_create_dev_hdl bridge_params; + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + CAM_ERR(CAM_CSIPHY, + "Not in right state to acquire : %d", + csiphy_dev->csiphy_state); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&csiphy_acq_dev, u64_to_user_ptr(cmd->handle), sizeof(csiphy_acq_dev)); @@ -826,6 +866,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (rc < 0) { csiphy_dev->csiphy_info.secure_mode[offset] = CAM_SECURE_MODE_NON_SECURE; + cam_cpas_stop(csiphy_dev->cpas_handle); goto release_mutex; } } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 32bb34bb257b..972b0a549f30 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -165,7 +165,6 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd)); - v4l2_set_subdevdata(&(new_csiphy_dev->v4l2_dev_str.sd), new_csiphy_dev); new_csiphy_dev->bridge_intf.device_hdl[0] = -1; new_csiphy_dev->bridge_intf.device_hdl[1] = -1; @@ -211,9 +210,17 @@ static int32_t cam_csiphy_device_remove(struct platform_device *pdev) struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(subdev); + CAM_INFO(CAM_CSIPHY, "device remove invoked"); cam_cpas_unregister_client(csiphy_dev->cpas_handle); cam_csiphy_soc_release(csiphy_dev); + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + cam_unregister_subdev(&(csiphy_dev->v4l2_dev_str)); kfree(csiphy_dev->ctrl_reg); + csiphy_dev->ctrl_reg = NULL; + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(csiphy_dev->v4l2_dev_str.sd), NULL); devm_kfree(&pdev->dev, csiphy_dev); return 0; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index a16fb888edc6..945910e96a55 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,7 +20,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 4, - .csiphy_reset_array_size = 4, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 21, .csiphy_3ph_config_array_size = 31, .csiphy_2ph_clock_lane = 0x1, @@ -38,6 +38,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index 8d7a5b58215a..b7345d4abeeb 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,8 +19,8 @@ struct csiphy_reg_parms_t csiphy_v2_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 3, + .csiphy_common_array_size = 8, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 15, .csiphy_3ph_config_array_size = 17, .csiphy_2ph_clock_lane = 0x1, @@ -31,6 +31,8 @@ struct csiphy_reg_t csiphy_common_reg_2_0[] = { {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, @@ -40,6 +42,8 @@ struct csiphy_reg_t csiphy_reset_reg_2_0[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; struct csiphy_reg_t csiphy_irq_reg_2_0[] = { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 7d7c1a2977e5..220cd1598922 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,6 +18,7 @@ #include "cam_eeprom_soc.h" #include "cam_debug_util.h" #include "cam_common_util.h" +#include "cam_packet_util.h" /** * cam_eeprom_read_memory() - read map data into buffer @@ -413,7 +414,7 @@ static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, static int32_t cam_eeprom_parse_memory_map( struct cam_eeprom_memory_block_t *data, void *cmd_buf, int cmd_length, uint16_t *cmd_length_bytes, - int *num_map) + int *num_map, size_t remain_buf_len) { int32_t rc = 0; int32_t cnt = 0; @@ -427,8 +428,21 @@ static int32_t cam_eeprom_parse_memory_map( struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; struct cam_cmd_conditional_wait *i2c_poll = NULL; struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL; + size_t validate_size = 0; generic_op_code = cmm_hdr->third_byte; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR) + validate_size = sizeof(struct cam_cmd_i2c_random_wr); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD) + validate_size = sizeof(struct cam_cmd_i2c_continuous_rd); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf_len < validate_size) { + CAM_ERR(CAM_EEPROM, "not enough buffer"); + return -EINVAL; + } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; @@ -535,6 +549,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, uint32_t *cmd_buf = NULL; uintptr_t generic_pkt_addr; size_t pkt_len = 0; + size_t remain_len = 0; uint32_t total_cmd_buf_in_bytes = 0; uint32_t processed_cmd_buf_in_bytes = 0; struct common_header *cmm_hdr = NULL; @@ -575,15 +590,43 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, cmd_buf = (uint32_t *)generic_pkt_addr; if (!cmd_buf) { CAM_ERR(CAM_EEPROM, "invalid cmd buf"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + + if ((pkt_len < sizeof(struct common_header)) || + (cmd_desc[i].offset > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + remain_len = pkt_len - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto rel_cmd_buf; + } /* Loop through multiple cmd formats in one cmd buffer */ while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto rel_cmd_buf; + } cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto rel_cmd_buf; + } /* Configure the following map slave address */ map[num_map + 1].saddr = i2c_info->slave_addr; rc = cam_eeprom_update_slaveInfo(e_ctrl, @@ -599,14 +642,16 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: cmd_length_in_bytes = total_cmd_buf_in_bytes; rc = cam_sensor_update_power_settings(cmd_buf, - cmd_length_in_bytes, power_info); + cmd_length_in_bytes, power_info, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ sizeof(uint32_t); if (rc) { CAM_ERR(CAM_EEPROM, "Failed"); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: @@ -616,7 +661,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, rc = cam_eeprom_parse_memory_map( &e_ctrl->cal_data, cmd_buf, total_cmd_buf_in_bytes, - &cmd_length_in_bytes, &num_map); + &cmd_length_in_bytes, &num_map, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); @@ -626,7 +673,18 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, } } e_ctrl->cal_data.num_map = num_map + 1; + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_EEPROM, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_EEPROM, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); + return rc; } @@ -647,6 +705,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, uintptr_t buf_addr; size_t buf_size; uint8_t *read_buffer; + size_t remain_len = 0; io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) &csl_packet->payload + @@ -660,6 +719,18 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, if (io_cfg->direction == CAM_BUF_OUTPUT) { rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], &buf_addr, &buf_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d", + rc); + return rc; + } + if (buf_size <= io_cfg->offsets[0]) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + + remain_len = buf_size - io_cfg->offsets[0]; CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", (void *)buf_addr, buf_size); @@ -667,26 +738,38 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, if (!read_buffer) { CAM_ERR(CAM_EEPROM, "invalid buffer to copy data"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } read_buffer += io_cfg->offsets[0]; - if (buf_size < e_ctrl->cal_data.num_data) { + if (remain_len < e_ctrl->cal_data.num_data) { CAM_ERR(CAM_EEPROM, "failed to copy, Invalid size"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } CAM_DBG(CAM_EEPROM, "copy the data, len:%d", e_ctrl->cal_data.num_data); memcpy(read_buffer, e_ctrl->cal_data.mapdata, e_ctrl->cal_data.num_data); - + if (cam_mem_put_cpu_buf(io_cfg->mem_handle[0])) + CAM_WARN(CAM_EEPROM, "Fail in put buffer: 0x%x", + io_cfg->mem_handle[0]); } else { CAM_ERR(CAM_EEPROM, "Invalid direction"); rc = -EINVAL; } } + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(io_cfg->mem_handle[0])) + CAM_WARN(CAM_EEPROM, "Fail in put buffer : %d", + io_cfg->mem_handle[0]); + return rc; } @@ -704,6 +787,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) struct cam_config_dev_cmd dev_config; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; struct cam_eeprom_soc_private *soc_private = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; @@ -723,15 +807,28 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_EEPROM, - "Offset is out of bound: off: %lld, %zu", - dev_config.offset, pkt_len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + goto release_buf; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) - (generic_pkt_addr + (uint32_t)dev_config.offset); + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_EEPROM, "Invalid packet params"); + rc = -EINVAL; + goto release_buf; + } + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_EEPROM_PACKET_OPCODE_INIT: if (e_ctrl->userspace_probe == false) { @@ -739,7 +836,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) e_ctrl->soc_info.dev->of_node, e_ctrl); if (rc < 0) { CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); - return rc; + goto release_buf; } rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); vfree(e_ctrl->cal_data.mapdata); @@ -754,7 +851,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) if (rc) { CAM_ERR(CAM_EEPROM, "Failed in parsing the pkt"); - return rc; + goto release_buf; } e_ctrl->cal_data.mapdata = @@ -797,7 +894,13 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) default: break; } + + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : %llu", + dev_config.packet_handle); + return rc; + power_down: cam_eeprom_power_down(e_ctrl); memdata_free: @@ -811,6 +914,11 @@ error: e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; +release_buf: + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : %llu", + dev_config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index 6d8820abb7d7..cf6854c7a527 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -219,7 +219,6 @@ static int cam_eeprom_i2c_driver_probe(struct i2c_client *client, e_ctrl->bridge_intf.ops.get_dev_info = NULL; e_ctrl->bridge_intf.ops.link_setup = NULL; e_ctrl->bridge_intf.ops.apply_req = NULL; - v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; return rc; @@ -257,13 +256,17 @@ static int cam_eeprom_i2c_driver_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_EEPROM, "i2c driver remove invoked"); soc_info = &e_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(soc_private); - kfree(e_ctrl->io_master_info.cci_client); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); @@ -388,14 +391,21 @@ static int cam_eeprom_spi_driver_remove(struct spi_device *sdev) for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(e_ctrl->io_master_info.spi_client); + e_ctrl->io_master_info.spi_client = NULL; soc_private = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; if (soc_private) { kfree(soc_private->power_info.gpio_num_info); + soc_private->power_info.gpio_num_info = NULL; kfree(soc_private); + soc_private = NULL; } - mutex_destroy(&(e_ctrl->eeprom_mutex)); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); @@ -459,10 +469,7 @@ static int32_t cam_eeprom_platform_driver_probe( e_ctrl->bridge_intf.ops.get_dev_info = NULL; e_ctrl->bridge_intf.ops.link_setup = NULL; e_ctrl->bridge_intf.ops.apply_req = NULL; - platform_set_drvdata(pdev, e_ctrl); - v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); - e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; return rc; @@ -472,6 +479,7 @@ free_cci_client: kfree(e_ctrl->io_master_info.cci_client); free_e_ctrl: kfree(e_ctrl); + return rc; } @@ -487,17 +495,23 @@ static int cam_eeprom_platform_driver_remove(struct platform_device *pdev) return -EINVAL; } + CAM_INFO(CAM_EEPROM, "Platform driver remove invoked"); soc_info = &e_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(soc_info->soc_private); kfree(e_ctrl->io_master_info.cci_client); platform_set_drvdata(pdev, NULL); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); + return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c index 5c9df8ac7abf..4302d4897ea9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,43 +16,78 @@ #include "cam_flash_core.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, bool regulator_enable) { int rc = 0; + struct cam_flash_private_soc *soc_private = + (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; if (!(flash_ctrl->switch_trigger)) { CAM_ERR(CAM_FLASH, "Invalid argument"); return -EINVAL; } - if (regulator_enable && - (flash_ctrl->is_regulator_enabled == false)) { - rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, - ENABLE_REGULATOR, NULL); - if (rc) { - CAM_ERR(CAM_FLASH, "regulator enable failed rc = %d", - rc); - return rc; - } - flash_ctrl->is_regulator_enabled = true; - } else if ((!regulator_enable) && - (flash_ctrl->is_regulator_enabled == true)) { - rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, - DISABLE_REGULATOR, NULL); - if (rc) { - CAM_ERR(CAM_FLASH, "regulator disable failed rc = %d", - rc); - return rc; + if (soc_private->is_wled_flash) { + if (regulator_enable && + flash_ctrl->is_regulator_enabled == false) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "enable reg failed: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if (!regulator_enable && + flash_ctrl->is_regulator_enabled == true) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "disalbe reg fail: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Wled flash state: %d", + flash_ctrl->flash_state); + rc = -EINVAL; } - flash_ctrl->is_regulator_enabled = false; } else { - CAM_ERR(CAM_FLASH, "Wrong Flash State : %d", - flash_ctrl->flash_state); - rc = -EINVAL; - } + if (regulator_enable && + (flash_ctrl->is_regulator_enabled == false)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator enable failed rc = %d", rc); + return rc; + } + flash_ctrl->is_regulator_enabled = true; + } else if ((!regulator_enable) && + (flash_ctrl->is_regulator_enabled == true)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator disable failed rc = %d", rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Flash State : %d", + flash_ctrl->flash_state); + rc = -EINVAL; + } + } return rc; } @@ -171,6 +206,7 @@ int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, "Enable Regulator Failed rc = %d", rc); return rc; } + fctrl->last_flush_req = 0; } if (!regulator_enable) { @@ -267,7 +303,6 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, } if (type == FLUSH_ALL) { - cam_flash_off(fctrl); /* flush all requests*/ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { fctrl->per_frame[i].cmn_attr.request_id = 0; @@ -360,7 +395,13 @@ int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush) } mutex_lock(&fctrl->flash_mutex); + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + goto end; + if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + fctrl->last_flush_req = flush->req_id; + CAM_DBG(CAM_FLASH, "last reqest to flush is %lld", + flush->req_id); rc = fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); if (rc) { CAM_ERR(CAM_FLASH, "FLUSH_TYPE_ALL failed rc: %d", rc); @@ -398,37 +439,31 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, for (i = 0; i < flash_ctrl->torch_num_sources; i++) { if (flash_ctrl->torch_trigger[i]) { max_current = soc_private->torch_max_current[i]; - if (flash_data->led_current_ma[i] <= max_current) curr = flash_data->led_current_ma[i]; else - curr = soc_private->torch_op_current[i]; - - CAM_DBG(CAM_PERF, - "Led_Current[%d] = %d", i, curr); - cam_res_mgr_led_trigger_event( - flash_ctrl->torch_trigger[i], - curr); + curr = max_current; } + CAM_DBG(CAM_FLASH, "Led_Torch[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], curr); } } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { for (i = 0; i < flash_ctrl->flash_num_sources; i++) { if (flash_ctrl->flash_trigger[i]) { max_current = soc_private->flash_max_current[i]; - if (flash_data->led_current_ma[i] <= max_current) curr = flash_data->led_current_ma[i]; else - curr = soc_private->flash_op_current[i]; - - CAM_DBG(CAM_PERF, "LED flash_current[%d]: %d", - i, curr); - cam_res_mgr_led_trigger_event( - flash_ctrl->flash_trigger[i], - curr); + curr = max_current; } + CAM_DBG(CAM_FLASH, "LED_Flash[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], curr); } } else { CAM_ERR(CAM_FLASH, "Wrong Operation: %d", op); @@ -438,7 +473,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event( flash_ctrl->switch_trigger, - LED_SWITCH_ON); + (enum led_brightness)LED_SWITCH_ON); return 0; } @@ -452,7 +487,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, - LED_SWITCH_OFF); + (enum led_brightness)LED_SWITCH_OFF); flash_ctrl->flash_state = CAM_FLASH_STATE_START; return 0; @@ -591,11 +626,15 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, } static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if (len < sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } if (fctrl->io_master_info.master_type == CCI_MASTER) { fctrl->io_master_info.cci_client->cci_i2c_master = fctrl->cci_i2c_master; @@ -870,6 +909,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_flash_init *flash_init = NULL; struct common_header *cmn_hdr = NULL; struct cam_control *ioctl_ctrl = NULL; @@ -897,19 +937,42 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_mem_get_cpu_buf(config.packet_handle, &generic_ptr, &len_of_buffer); if (rc) { - CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); + CAM_ERR(CAM_FLASH, "Failed in getting the packet : %d", rc); return rc; } - - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buffer); + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); return -EINVAL; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_DBG(CAM_FLASH, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, fctrl->last_flush_req); + return -EINVAL; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { /* INIT packet*/ @@ -934,6 +997,15 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_ERR(CAM_FLASH, "invalid cmd buf"); return -EINVAL; } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buffer - + sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "invalid cmd buf length"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmn_hdr = (struct common_header *)cmd_buf; @@ -944,6 +1016,12 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) total_cmd_buf_in_bytes); switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: + if (len_of_buffer < + sizeof(struct cam_flash_init)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + flash_init = (struct cam_flash_init *)cmd_buf; fctrl->flash_type = flash_init->flash_type; cmd_length_in_bytes = @@ -955,7 +1033,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) break; case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_flash_slaveInfo_pkt_parser( - fctrl, cmd_buf); + fctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_FLASH, "Failed parsing slave info: rc: %d", @@ -978,7 +1056,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - &fctrl->power_info); + &fctrl->power_info, remain_len); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ @@ -1171,11 +1249,12 @@ update_req_mgr: int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) { int rc = 0, i = 0; - uintptr_t generic_ptr; + uintptr_t generic_ptr, cmd_buf_ptr; uint32_t *cmd_buf = NULL; uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -1187,11 +1266,16 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) struct cam_flash_set_on_off *flash_operation_info = NULL; struct cam_flash_query_curr *flash_query_info = NULL; struct cam_flash_frame_setting *flash_data = NULL; + struct cam_flash_private_soc *soc_private = NULL; if (!fctrl || !arg) { CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); return -EINVAL; } + + soc_private = (struct cam_flash_private_soc *) + fctrl->soc_info.soc_private; + /* getting CSL Packet */ ioctl_ctrl = (struct cam_control *)arg; @@ -1206,20 +1290,45 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_mem_get_cpu_buf(config.packet_handle, &generic_ptr, &len_of_buffer); if (rc) { - CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); + CAM_ERR(CAM_FLASH, "Failed in getting the packet: %d", rc); return rc; } - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buffer); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + rc = -EINVAL; + goto rel_pkt_buf; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_WARN(CAM_FLASH, + "reject request %lld, last request to flush %u", + csl_packet->header.request_id, fctrl->last_flush_req); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { @@ -1228,8 +1337,20 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) csl_packet->cmd_buf_offset); cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + goto rel_pkt_buf; + } + if ((len_of_buffer < sizeof(struct cam_flash_init)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct cam_flash_init)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + cmd_desc->offset); cam_flash_info = (struct cam_flash_init *)cmd_buf; @@ -1248,7 +1369,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (rc) { CAM_ERR(CAM_FLASH, "Enable Regulator Failed rc = %d", rc); - return rc; + goto rel_cmd_buf; } fctrl->flash_state = @@ -1258,8 +1379,26 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: { CAM_DBG(CAM_FLASH, "INIT_FIRE Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + flash_operation_info = (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1284,8 +1423,13 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) default: CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", cam_flash_info->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: %d", + cmd_desc->mem_handle); break; } case CAM_FLASH_PACKET_OPCODE_SET_OPS: { @@ -1306,13 +1450,28 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) flash_data->cmn_attr.is_settings_valid = true; cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + - cmd_desc->offset); + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x", + cmd_desc->mem_handle); + goto rel_pkt_buf; + } - if (!cmd_buf) - return -EINVAL; + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + if (!cmd_buf) { + rc = -EINVAL; + goto rel_cmd_buf; + } cmn_hdr = (struct common_header *)cmd_buf; switch (cmn_hdr->cmd_type) { @@ -1325,7 +1484,12 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_WARN(CAM_FLASH, "Rxed Flash fire ops without linking"); flash_data->cmn_attr.is_settings_valid = false; - return 0; + goto rel_cmd_buf; + } + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; } flash_operation_info = @@ -1333,7 +1497,14 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (!flash_operation_info) { CAM_ERR(CAM_FLASH, "flash_operation_info Null"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; } flash_data->opcode = flash_operation_info->opcode; @@ -1350,8 +1521,12 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) default: CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", cmn_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: 0x%x", + cmd_desc->mem_handle); break; } case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { @@ -1360,16 +1535,47 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->nrt_info.cmn_attr.is_settings_valid = true; cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + goto rel_pkt_buf; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + cmd_desc->offset); cmn_hdr = (struct common_header *)cmd_buf; switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: { CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } flash_operation_info = (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } + fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1386,29 +1592,61 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (rc) CAM_ERR(CAM_FLASH, "Apply setting failed: %d", rc); - return rc; + goto rel_cmd_buf; } case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { int query_curr_ma = 0; + if (remain_len < sizeof(struct cam_flash_query_curr)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } flash_query_info = (struct cam_flash_query_curr *)cmd_buf; - rc = qpnp_flash_led_prepare(fctrl->switch_trigger, - QUERY_MAX_CURRENT, &query_curr_ma); + if (soc_private->is_wled_flash) + rc = wled_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + else + rc = qpnp_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + CAM_DBG(CAM_FLASH, "query_curr_ma = %d", query_curr_ma); if (rc) { CAM_ERR(CAM_FLASH, "Query current failed with rc=%d", rc); - return rc; + goto rel_cmd_buf; } flash_query_info->query_current_ma = query_curr_ma; break; } case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: { rc = 0; + if (remain_len < sizeof(struct cam_flash_set_rer)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + if (!flash_rer_info) { + CAM_ERR(CAM_FLASH, + "flash_rer_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_rer_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } + fctrl->nrt_info.cmn_attr.cmd_type = CAMERA_SENSOR_FLASH_CMD_TYPE_RER; fctrl->nrt_info.opcode = flash_rer_info->opcode; @@ -1425,18 +1663,21 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->nrt_info.led_current_ma[i] = flash_rer_info->led_current_ma[i]; - rc = fctrl->func_tbl.apply_setting(fctrl, 0); if (rc) CAM_ERR(CAM_FLASH, "apply_setting failed: %d", rc); - return rc; + goto rel_cmd_buf; } default: CAM_ERR(CAM_FLASH, "Wrong cmd_type : %d", cmn_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: 0x%x", + cmd_desc->mem_handle); break; } case CAM_PKT_NOP_OPCODE: { @@ -1448,7 +1689,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) "Rxed NOP packets without linking"); fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; - return 0; + goto rel_pkt_buf; } fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; @@ -1456,14 +1697,15 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %llu", csl_packet->header.request_id); - goto update_req_mgr; + break; } default: CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", (csl_packet->header.op_code & 0xFFFFFF)); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } -update_req_mgr: + if (((csl_packet->header.op_code & 0xFFFFF) == CAM_PKT_NOP_OPCODE) || ((csl_packet->header.op_code & 0xFFFFF) == @@ -1484,6 +1726,21 @@ update_req_mgr: CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); } + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_FLASH, "Failed in put the buffer: %llu ", + config.packet_handle); + + return 0; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: %d", + cmd_desc->mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_FLASH, "Failed in put the buffer: %llu ", + config.packet_handle); + return rc; } @@ -1534,6 +1791,7 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) fctrl->bridge_intf.device_hdl = -1; fctrl->bridge_intf.link_hdl = -1; fctrl->bridge_intf.session_hdl = -1; + fctrl->last_flush_req = 0; } return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h index 1bd3b31c1668..875d13c51ee0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,15 +13,20 @@ #ifndef _CAM_FLASH_CORE_H_ #define _CAM_FLASH_CORE_H_ -#include <linux/leds-qpnp-flash.h> #include <media/cam_sensor.h> #include "cam_flash_dev.h" +#define QUERY_MAX_AVAIL_CURRENT BIT(2) + int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info); int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link); int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply); int cam_flash_process_evt(struct cam_req_mgr_link_evt_data *event_data); int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush); - +static inline int wled_flash_led_prepare(struct led_trigger *trig, int options, + int *max_current) +{ + return -EINVAL; +} #endif /*_CAM_FLASH_CORE_H_*/ diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c index f5177d6796b5..948fc9a9c990 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -181,7 +181,9 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, goto release_mutex; } + cam_flash_off(fctrl); fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + fctrl->last_flush_req = 0; fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; break; } @@ -318,7 +320,14 @@ static int cam_flash_platform_remove(struct platform_device *pdev) return 0; } - devm_kfree(&pdev->dev, fctrl); + CAM_INFO(CAM_FLASH, "Platform remove invoked"); + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL); + kfree(fctrl); return 0; } @@ -332,6 +341,8 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) CAM_ERR(CAM_FLASH, "Flash device is NULL"); return -EINVAL; } + + CAM_INFO(CAM_FLASH, "i2c driver remove invoked"); /*Free Allocated Mem */ kfree(fctrl->i2c_data.per_frame); fctrl->i2c_data.per_frame = NULL; @@ -483,6 +494,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; mutex_init(&(fctrl->flash_mutex)); @@ -569,6 +581,7 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; mutex_init(&(fctrl->flash_mutex)); fctrl->flash_state = CAM_FLASH_STATE_INIT; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h index 8e5deef871e5..ea5ea3c9997b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/leds-qpnp-flash.h> #include <media/v4l2-subdev.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> @@ -135,6 +136,7 @@ struct cam_flash_frame_setting { * @torch_trigger_name : Torch trigger name array * @torch_op_current : Torch operational current * @torch_max_current : Max supported current for LED in torch mode + * @is_wled_flash : Detection between WLED/LED flash */ struct cam_flash_private_soc { @@ -146,6 +148,7 @@ struct cam_flash_private_soc { const char *torch_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + bool is_wled_flash; }; struct cam_flash_func_tbl { @@ -180,6 +183,7 @@ struct cam_flash_func_tbl { * @cci_i2c_master : I2C structure * @io_master_info : Information about the communication master * @i2c_data : I2C register settings + * @last_flush_req : last request to flush */ struct cam_flash_ctrl { struct cam_hw_soc_info soc_info; @@ -205,6 +209,7 @@ struct cam_flash_ctrl { enum cci_i2c_master_t cci_i2c_master; struct camera_io_master io_master_info; struct i2c_data_settings i2c_data; + uint32_t last_flush_req; }; int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c index 22a124d86f93..9195c8143d3c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,9 +26,12 @@ static int32_t cam_get_source_node_info( struct device_node *torch_src_node = NULL; struct device_node *switch_src_node = NULL; + soc_private->is_wled_flash = + of_property_read_bool(of_node, "wled-flash-support"); + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); if (!switch_src_node) { - CAM_DBG(CAM_FLASH, "switch_src_node NULL"); + CAM_WARN(CAM_FLASH, "switch_src_node NULL"); } else { rc = of_property_read_string(switch_src_node, "qcom,default-led-trigger", @@ -75,46 +78,61 @@ static int32_t cam_get_source_node_info( continue; } - CAM_DBG(CAM_FLASH, "default trigger %s", + CAM_DBG(CAM_FLASH, "Flash default trigger %s", soc_private->flash_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->flash_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->flash_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED FLASH max_current read fail: %d", + rc); + of_node_put(flash_src_node); + rc = 0; + continue; + } + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &soc_private->flash_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED FLASH max-current read fail: %d", + rc); + of_node_put(flash_src_node); + continue; + } + } /* Read operational-current */ rc = of_property_read_u32(flash_src_node, "qcom,current-ma", &soc_private->flash_op_current[i]); if (rc) { - CAM_WARN(CAM_FLASH, "op-current: read failed"); - of_node_put(flash_src_node); - continue; - } - - /* Read max-current */ - rc = of_property_read_u32(flash_src_node, - "qcom,max-current", - &soc_private->flash_max_current[i]); - if (rc) { - CAM_WARN(CAM_FLASH, - "max-current: read failed"); - of_node_put(flash_src_node); - continue; + CAM_INFO(CAM_FLASH, "op-current: read failed"); + rc = 0; } /* Read max-duration */ rc = of_property_read_u32(flash_src_node, "qcom,duration-ms", &soc_private->flash_max_duration[i]); - if (rc) - CAM_WARN(CAM_FLASH, - "max-duration: read failed"); - + if (rc) { + CAM_INFO(CAM_FLASH, + "max-duration prop unavailable: %d", + rc); + rc = 0; + } of_node_put(flash_src_node); - CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + CAM_DBG(CAM_FLASH, "MainFlashMaxCurrent[%d]: %d", i, soc_private->flash_max_current[i]); - - cam_res_mgr_led_trigger_register( - soc_private->flash_trigger_name[i], - &fctrl->flash_trigger[i]); } } @@ -147,35 +165,51 @@ static int32_t cam_get_source_node_info( continue; } + CAM_DBG(CAM_FLASH, "Torch default trigger %s", + soc_private->torch_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->torch_trigger_name[i], + &fctrl->torch_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->torch_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->torch_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED TORCH max_current read fail: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } else { + rc = of_property_read_u32(torch_src_node, + "qcom,max-current", + &soc_private->torch_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED-TORCH max-current read failed: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } + /* Read operational-current */ rc = of_property_read_u32(torch_src_node, "qcom,current-ma", &soc_private->torch_op_current[i]); if (rc < 0) { - CAM_WARN(CAM_FLASH, "current: read failed"); - of_node_put(torch_src_node); - continue; - } - - /* Read max-current */ - rc = of_property_read_u32(torch_src_node, - "qcom,max-current", - &soc_private->torch_max_current[i]); - if (rc < 0) { CAM_WARN(CAM_FLASH, - "max-current: read failed"); - of_node_put(torch_src_node); - continue; + "op-current prop unavailable: %d", rc); + rc = 0; } of_node_put(torch_src_node); - CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + CAM_DBG(CAM_FLASH, "TorchMaxCurrent[%d]: %d", i, soc_private->torch_max_current[i]); - - cam_res_mgr_led_trigger_register( - soc_private->torch_trigger_name[i], - &fctrl->torch_trigger[i]); } } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c index b8ebc15e7fd5..a5c7039cc2da 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #include "cam_debug_util.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -256,12 +257,12 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, } static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_ois_info *ois_info; - if (!o_ctrl || !cmd_buf) { + if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) { CAM_ERR(CAM_OIS, "Invalid Args"); return -EINVAL; } @@ -274,7 +275,8 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, ois_info->slave_addr >> 1; o_ctrl->ois_fw_flag = ois_info->ois_fw_flag; o_ctrl->is_ois_calib = ois_info->is_ois_calib; - memcpy(o_ctrl->ois_name, ois_info->ois_name, 32); + memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); + o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; o_ctrl->io_master_info.cci_client->retries = 3; o_ctrl->io_master_info.cci_client->id_map = 0; memcpy(&(o_ctrl->opcode), &(ois_info->opcode), @@ -433,6 +435,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; size_t len_of_buff = 0; uint32_t *offset = NULL, *cmd_buf; @@ -453,15 +456,29 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_OIS, - "offset is out of bound: off: %lld len: %zu", - dev_config.offset, pkt_len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + goto rel_pkt; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_OIS, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt; + } + + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_OIS_PACKET_OPCODE_INIT: offset = (uint32_t *)&csl_packet->payload; @@ -477,25 +494,37 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, &generic_ptr, &len_of_buff); if (rc < 0) { - CAM_ERR(CAM_OIS, "Failed to get cpu buf"); - return rc; + CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x", + cmd_desc[i].mem_handle); + goto rel_pkt; } cmd_buf = (uint32_t *)generic_ptr; if (!cmd_buf) { CAM_ERR(CAM_OIS, "invalid cmd buf"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; + } + + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_OIS, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto rel_cmd_buf; } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_ois_slaveInfo_pkt_parser( - o_ctrl, cmd_buf); + o_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in parsing slave info"); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_PWR_UP: @@ -505,11 +534,11 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_OIS, "Failed: parse power settings"); - return rc; + goto rel_cmd_buf; } break; default: @@ -527,7 +556,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "init parsing failed: %d", rc); - return rc; + goto rel_cmd_buf; } } else if ((o_ctrl->is_ois_calib != 0) && (o_ctrl->i2c_calib_data.is_settings_valid == @@ -544,18 +573,21 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Calib parsing failed: %d", rc); - return rc; + goto rel_cmd_buf; } } break; } + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_OIS, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { rc = cam_ois_power_up(o_ctrl); if (rc) { CAM_ERR(CAM_OIS, " OIS Power up failed"); - return rc; + goto rel_pkt; } o_ctrl->cam_ois_state = CAM_OIS_CONFIG; } @@ -602,7 +634,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_WARN(CAM_OIS, "Not in right state to control OIS: %d", o_ctrl->cam_ois_state); - return rc; + goto rel_pkt; } offset = (uint32_t *)&csl_packet->payload; offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); @@ -615,26 +647,43 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) cmd_desc, 1); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); - return rc; + goto rel_pkt; } rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Cannot apply mode settings"); - return rc; + goto rel_pkt; } rc = delete_request(i2c_reg_settings); - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_OIS, "Fail deleting Mode data: rc: %d", rc); + goto rel_pkt; + } break; default: - break; + CAM_ERR(CAM_OIS, "Invalid Opcode: %d", + (csl_packet->header.op_code & 0xFFFFFF)); + rc = -EINVAL; + goto rel_pkt; } - return rc; + + if (!rc) + goto rel_pkt; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_OIS, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); pwr_dwn: cam_ois_power_down(o_ctrl); +rel_pkt: + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_OIS, "Fail in put buffer: %llu", + dev_config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h index d6f0ec564508..06022ababf4e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,6 +16,8 @@ #include <linux/dma-contiguous.h> #include "cam_ois_dev.h" +#define OIS_NAME_LEN 32 + /** * @power_info: power setting info to control the power * diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c index 5d16a4e54d04..db583340dad4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -229,20 +229,23 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_OIS, "i2c driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + soc_private = (struct cam_ois_soc_private *)soc_info->soc_private; power_info = &soc_private->power_info; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); kfree(o_ctrl); return 0; @@ -303,8 +306,6 @@ static int32_t cam_ois_platform_driver_probe( o_ctrl->bridge_intf.device_hdl = -1; platform_set_drvdata(pdev, o_ctrl); - v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl); - o_ctrl->cam_ois_state = CAM_OIS_INIT; return rc; @@ -333,21 +334,26 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) return -EINVAL; } + CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); kfree(o_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); kfree(o_ctrl); + return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index d03faef4d3a6..ed2f9ad945a5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -178,8 +178,10 @@ int cam_res_mgr_shared_pinctrl_init(void) return 0; } + mutex_lock(&cam_res->gpio_res_lock); if (cam_res->pstatus != PINCTRL_STATUS_PUT) { CAM_DBG(CAM_RES, "The shared pinctrl already been got."); + mutex_unlock(&cam_res->gpio_res_lock); return 0; } @@ -190,6 +192,7 @@ int cam_res_mgr_shared_pinctrl_init(void) if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) { CAM_ERR(CAM_RES, "Pinctrl not available"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } @@ -200,6 +203,7 @@ int cam_res_mgr_shared_pinctrl_init(void) CAM_ERR(CAM_RES, "Failed to get the active state pinctrl handle"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } @@ -210,10 +214,10 @@ int cam_res_mgr_shared_pinctrl_init(void) CAM_ERR(CAM_RES, "Failed to get the active state pinctrl handle"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } - mutex_lock(&cam_res->gpio_res_lock); cam_res->pstatus = PINCTRL_STATUS_GOT; mutex_unlock(&cam_res->gpio_res_lock); @@ -313,6 +317,7 @@ int cam_res_mgr_shared_pinctrl_select_state(bool active) pinctrl_info->gpio_state_suspend); cam_res->pstatus = PINCTRL_STATUS_SUSPEND; } + mutex_unlock(&cam_res->gpio_res_lock); return rc; @@ -379,12 +384,14 @@ static bool cam_res_mgr_gpio_is_shared(uint gpio) bool found = false; struct cam_res_mgr_dt *dt = &cam_res->dt; + mutex_lock(&cam_res->gpio_res_lock); for (; index < dt->num_shared_gpio; index++) { if (gpio == dt->shared_gpio[index]) { found = true; break; } } + mutex_unlock(&cam_res->gpio_res_lock); return found; } @@ -441,13 +448,14 @@ int cam_res_mgr_gpio_request(struct device *dev, uint gpio, INIT_LIST_HEAD(&gpio_res->list); INIT_LIST_HEAD(&gpio_res->dev_list); + mutex_lock(&cam_res->gpio_res_lock); rc = cam_res_mgr_add_device(dev, gpio_res); if (rc) { kfree(gpio_res); + mutex_unlock(&cam_res->gpio_res_lock); return rc; } - mutex_lock(&cam_res->gpio_res_lock); list_add_tail(&gpio_res->list, &cam_res->gpio_res_list); mutex_unlock(&cam_res->gpio_res_lock); } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c index 2117cc1f9587..5f77ca0a5293 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,8 @@ #include "cam_soc_util.h" #include "cam_trace.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, @@ -94,6 +96,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, struct cam_cmd_buf_desc *cmd_desc = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; struct cam_config_dev_cmd config; struct i2c_data_settings *i2c_data = NULL; @@ -115,27 +118,42 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, &generic_ptr, &len_of_buff); if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Failed in getting the buffer: %d", rc); + CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc); return rc; } + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto rel_pkt_buf; + } + + remain_len -= (size_t)config.offset; csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - if (config.offset > len_of_buff) { - CAM_ERR(CAM_SENSOR, - "offset is out of bounds: off: %lld len: %zu", - config.offset, len_of_buff); - return -EINVAL; + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } if ((csl_packet->header.op_code & 0xFFFFFF) != CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG && csl_packet->header.request_id <= s_ctrl->last_flush_req && s_ctrl->last_flush_req != 0) { - CAM_DBG(CAM_SENSOR, - "reject request %lld, last request to flush %lld", + CAM_ERR(CAM_SENSOR, + "reject request %lld, last request to flush %u", csl_packet->header.request_id, s_ctrl->last_flush_req); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } if (csl_packet->header.request_id > s_ctrl->last_flush_req) @@ -158,7 +176,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, } case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { if (s_ctrl->streamon_count > 0) - return 0; + goto rel_pkt_buf; s_ctrl->streamon_count = s_ctrl->streamon_count + 1; i2c_reg_settings = &i2c_data->streamon_settings; @@ -168,7 +186,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, } case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { if (s_ctrl->streamoff_count > 0) - return 0; + goto rel_pkt_buf; s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1; i2c_reg_settings = &i2c_data->streamoff_settings; @@ -182,7 +200,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { CAM_WARN(CAM_SENSOR, "Rxed Update packets without linking"); - return 0; + goto rel_pkt_buf; } i2c_reg_settings = @@ -202,7 +220,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, * fix it. */ cam_sensor_update_req_mgr(s_ctrl, csl_packet); - return 0; + goto rel_pkt_buf; } break; } @@ -211,15 +229,16 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { CAM_WARN(CAM_SENSOR, "Rxed NOP packets without linking"); - return 0; + goto rel_pkt_buf; } cam_sensor_update_req_mgr(s_ctrl, csl_packet); - return 0; + goto rel_pkt_buf; } default: CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } offset = (uint32_t *)&csl_packet->payload; @@ -230,7 +249,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, i2c_reg_settings, cmd_desc, 1); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); - return rc; + goto rel_pkt_buf; } if ((csl_packet->header.op_code & 0xFFFFFF) == @@ -240,6 +259,11 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, cam_sensor_update_req_mgr(s_ctrl, csl_packet); } +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_SENSOR, "Failed in put the buffer: %llu", + config.packet_handle); + return rc; } @@ -359,7 +383,7 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_sensor_ctrl_t *s_ctrl, - int32_t cmd_buf_num, int cmd_buf_length) + int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) { int32_t rc = 0; @@ -368,6 +392,13 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_cmd_i2c_info *i2c_info = NULL; struct cam_cmd_probe *probe_info; + if (remain_len < + (sizeof(struct cam_cmd_i2c_info) + + sizeof(struct cam_cmd_probe))) { + CAM_ERR(CAM_SENSOR, + "not enough buffer for cam_cmd_i2c_info"); + return -EINVAL; + } i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); if (rc < 0) { @@ -386,7 +417,8 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, break; case 1: { rc = cam_sensor_update_power_settings(cmd_buf, - cmd_buf_length, &s_ctrl->sensordata->power_info); + cmd_buf_length, &s_ctrl->sensordata->power_info, + remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in updating power settings"); @@ -407,10 +439,11 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) uint32_t *cmd_buf; void *ptr; size_t len; - struct cam_packet *pkt; - struct cam_cmd_buf_desc *cmd_desc; + struct cam_packet *pkt = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t cmd_buf1 = 0; uintptr_t packet = 0; + size_t remain_len = 0; rc = cam_mem_get_cpu_buf(handle, &packet, &len); @@ -418,18 +451,35 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); return -EINVAL; } + pkt = (struct cam_packet *)packet; + if (pkt == NULL) { + CAM_ERR(CAM_SENSOR, "packet pos is invalid"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if ((len < sizeof(struct cam_packet)) || + (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_SENSOR, "Not enough buf provided"); + rc = -EINVAL; + goto rel_pkt_buf; + } + cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4); if (cmd_desc == NULL) { CAM_ERR(CAM_SENSOR, "command descriptor pos is invalid"); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } if (pkt->num_cmd_buf != 2) { CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", pkt->num_cmd_buf); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } + for (i = 0; i < pkt->num_cmd_buf; i++) { if (!(cmd_desc[i].length)) continue; @@ -438,20 +488,54 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); - return -EINVAL; + goto rel_pkt_buf; + } + if (cmd_desc[i].offset >= len) { + CAM_ERR(CAM_SENSOR, + "offset past length of buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len - cmd_desc[i].offset; + if (cmd_desc[i].length > remain_len) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided for cmd"); + rc = -EINVAL; + goto rel_pkt_buf; } cmd_buf = (uint32_t *)cmd_buf1; cmd_buf += cmd_desc[i].offset/4; ptr = (void *) cmd_buf; rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl, - i, cmd_desc[i].length); + i, cmd_desc[i].length, remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); - return -EINVAL; + goto rel_cmd_buf; } + + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, + "Failed to put command Buffer : %d", + cmd_desc[i].mem_handle); } + + if (cam_mem_put_cpu_buf(handle)) + CAM_WARN(CAM_SENSOR, "Failed to put the command Buffer: %llu", + handle); + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "Failed to put command Buffer : 0x%x", + cmd_desc[i].mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(handle)) + CAM_WARN(CAM_SENSOR, "Failed to put the command Buffer: %llu", + handle); + return rc; } @@ -507,11 +591,13 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) cam_sensor_release_stream_rsc(s_ctrl); cam_sensor_release_per_frame_resource(s_ctrl); - cam_sensor_power_down(s_ctrl); + + if (s_ctrl->sensor_state != CAM_SENSOR_INIT) + cam_sensor_power_down(s_ctrl); rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); if (rc < 0) - CAM_ERR(CAM_SENSOR, " failed destroying dhdl"); + CAM_ERR(CAM_SENSOR, "dhdl already destroyed: rc = %d", rc); s_ctrl->bridge_intf.device_hdl = -1; s_ctrl->bridge_intf.link_hdl = -1; s_ctrl->bridge_intf.session_hdl = -1; @@ -843,7 +929,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, case CAM_CONFIG_DEV: { rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Failed CCI Config: %d", rc); + CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); goto release_mutex; } if (s_ctrl->i2c_data.init_settings.is_settings_valid && @@ -1210,12 +1296,19 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (s_ctrl->sensor_state != CAM_SENSOR_START || + s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + } + if (s_ctrl->i2c_data.per_frame == NULL) { CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return -EINVAL; } - mutex_lock(&(s_ctrl->cam_sensor_mutex)); if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { s_ctrl->last_flush_req = flush_req->req_id; CAM_DBG(CAM_SENSOR, "last reqest to flush is %lld", diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 8dcb6c73312f..5c5c97099d43 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -199,7 +199,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; s_ctrl->sensordata->power_info.dev = soc_info->dev; - v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl); + return rc; unreg_subdev: cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); @@ -220,11 +220,18 @@ static int cam_sensor_platform_remove(struct platform_device *pdev) return 0; } + CAM_INFO(CAM_SENSOR, "platform remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); soc_info = &s_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); kfree(s_ctrl->i2c_data.per_frame); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); devm_kfree(&pdev->dev, s_ctrl); return 0; @@ -241,11 +248,17 @@ static int cam_sensor_driver_i2c_remove(struct i2c_client *client) return 0; } + CAM_INFO(CAM_SENSOR, "i2c remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); soc_info = &s_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); kfree(s_ctrl->i2c_data.per_frame); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); kfree(s_ctrl); return 0; @@ -323,8 +336,6 @@ static int32_t cam_sensor_driver_platform_probe( s_ctrl->sensordata->power_info.dev = &pdev->dev; platform_set_drvdata(pdev, s_ctrl); - v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl); - s_ctrl->sensor_state = CAM_SENSOR_INIT; return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 1e9ec3db054a..7a2c56e3b686 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -325,6 +325,9 @@ enum msm_sensor_camera_id_t { CAMERA_1, CAMERA_2, CAMERA_3, + CAMERA_4, + CAMERA_5, + CAMERA_6, MAX_CAMERAS, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 713bcaa8643a..7f6f3aa40998 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -298,6 +298,8 @@ int cam_sensor_i2c_command_parser( size_t len_of_buff = 0; uintptr_t generic_ptr; uint16_t cmd_length_in_bytes = 0; + size_t remain_len = 0; + size_t tot_size = 0; for (i = 0; i < num_cmd_buffers; i++) { uint32_t *cmd_buf = NULL; @@ -319,16 +321,35 @@ int cam_sensor_i2c_command_parser( rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, &generic_ptr, &len_of_buff); - cmd_buf = (uint32_t *)generic_ptr; if (rc < 0) { CAM_ERR(CAM_SENSOR, "cmd hdl failed:%d, Err: %d, Buffer_len: %zd", cmd_desc[i].mem_handle, rc, len_of_buff); return rc; } + + remain_len = len_of_buff; + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buff - sizeof(struct common_header)))) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + if (remain_len < cmd_desc[i].length) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + while (byte_cnt < cmd_desc[i].length) { + if ((remain_len - byte_cnt) < + sizeof(struct common_header)) { + CAM_ERR(CAM_SENSOR, "Not enough buffer"); + rc = -EINVAL; + goto rel_buf; + } cmm_hdr = (struct common_header *)cmd_buf; generic_op_code = cmm_hdr->third_byte; switch (cmm_hdr->cmd_type) { @@ -338,6 +359,24 @@ int cam_sensor_i2c_command_parser( *cam_cmd_i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_random_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto rel_buf; + } + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct i2c_random_wr_payload) * + cam_cmd_i2c_random_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto rel_buf; + } + rc = cam_sensor_handle_random_write( cam_cmd_i2c_random_wr, i2c_reg_settings, @@ -345,7 +384,7 @@ int cam_sensor_i2c_command_parser( if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in random write %d", rc); - return rc; + return -EINVAL; } cmd_buf += cmd_length_in_bytes / @@ -360,6 +399,24 @@ int cam_sensor_i2c_command_parser( (struct cam_cmd_i2c_continuous_wr *) cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + (sizeof(struct cam_cmd_read) * + cam_cmd_i2c_continuous_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + rc = cam_sensor_handle_continuous_write( cam_cmd_i2c_continuous_wr, i2c_reg_settings, @@ -376,11 +433,16 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_WAIT: { + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_unconditional_wait)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + return -EINVAL; + } if (generic_op_code == CAMERA_SENSOR_WAIT_OP_HW_UCND || generic_op_code == CAMERA_SENSOR_WAIT_OP_SW_UCND) { - rc = cam_sensor_handle_delay( &cmd_buf, generic_op_code, i2c_reg_settings, j, &byte_cnt, @@ -412,13 +474,20 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto rel_buf; + } rc = cam_sensor_handle_slave_info( io_master, cmd_buf); if (rc) { CAM_ERR(CAM_SENSOR, - "Handle slave info failed with rc: %d", - rc); - return rc; + "Handle slave info failed with rc: %d", + rc); + goto rel_buf; } cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_info); @@ -430,13 +499,23 @@ int cam_sensor_i2c_command_parser( default: CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", cmm_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_buf; } } i2c_reg_settings->is_settings_valid = 1; + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "put failed for buffer :%d", + cmd_desc[i].mem_handle); } return rc; + +rel_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "put failed for buffer :%d", + cmd_desc[i].mem_handle); + return rc; } int cam_sensor_util_i2c_apply_setting( @@ -750,8 +829,32 @@ int cam_sensor_util_request_gpio_table( return rc; } + +static int32_t cam_sensor_validate(void *ptr, size_t remain_buf) +{ + struct common_header *cmm_hdr = (struct common_header *)ptr; + size_t validate_size = 0; + + if (remain_buf < sizeof(struct common_header)) + return -EINVAL; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP || + cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) + validate_size = sizeof(struct cam_cmd_power); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf < validate_size) { + CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu", + remain_buf, validate_size); + return -EINVAL; + } + return 0; +} + int32_t cam_sensor_update_power_settings(void *cmd_buf, - int cmd_length, struct cam_sensor_power_ctrl_t *power_info) + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len) { int32_t rc = 0, tot_size = 0, last_cmd_type = 0; int32_t i = 0, pwr_up = 0, pwr_down = 0; @@ -760,7 +863,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; struct common_header *cmm_hdr = (struct common_header *)cmd_buf; - if (!pwr_cmd || !cmd_length) { + if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || + cam_sensor_validate(cmd_buf, cmd_buf_len)) { CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", pwr_cmd, cmd_length); return -EINVAL; @@ -787,16 +891,29 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } while (tot_size < cmd_length) { + if (cam_sensor_validate(ptr, (cmd_length - tot_size))) { + rc = -EINVAL; + goto free_power_settings; + } if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP) { struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)ptr; + if ((U16_MAX - power_info->power_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow occurs"); + rc = -EINVAL; + goto free_power_settings; + } + power_info->power_setting_size += pwr_cmd->count; - if (power_info->power_setting_size > MAX_POWER_CONFIG) { + if ((power_info->power_setting_size > MAX_POWER_CONFIG) + || (pwr_cmd->count >= SENSOR_SEQ_TYPE_MAX)) { CAM_ERR(CAM_SENSOR, - "Invalid: power up setting size %d", - power_info->power_setting_size); + "pwr_up setting size %d, pwr_cmd->count: %d", + power_info->power_setting_size, + pwr_cmd->count); rc = -EINVAL; goto free_power_settings; } @@ -891,12 +1008,21 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, scr = ptr + sizeof(struct cam_cmd_power); tot_size = tot_size + sizeof(struct cam_cmd_power); + if ((U16_MAX - power_info->power_down_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow"); + rc = -EINVAL; + goto free_power_settings; + } + power_info->power_down_setting_size += pwr_cmd->count; - if (power_info->power_down_setting_size > - MAX_POWER_CONFIG) { + if ((power_info->power_down_setting_size > + MAX_POWER_CONFIG) || (pwr_cmd->count >= + SENSOR_SEQ_TYPE_MAX)) { CAM_ERR(CAM_SENSOR, - "Invalid: power down setting size %d", - power_info->power_down_setting_size); + "pwr_down_setting_size %d, pwr_cmd->count: %d", + power_info->power_down_setting_size, + pwr_cmd->count); rc = -EINVAL; goto free_power_settings; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index 583ddb14243b..85497fda011c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -60,7 +60,8 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, uint16_t power_setting_size); int32_t cam_sensor_update_power_settings(void *cmd_buf, - int cmd_length, struct cam_sensor_power_ctrl_t *power_info); + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len); int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, int bob_reg_idx, bool flag); diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c index 7a772f1c4269..1be244bb7c3a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -196,8 +196,8 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) if (row->state != CAM_SYNC_STATE_ACTIVE) { spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); CAM_ERR(CAM_SYNC, - "Error: Sync object already signaled sync_obj = %d", - sync_obj); + "Sync object already signaled sync_obj = %d state = %d", + sync_obj, row->state); return -EALREADY; } @@ -323,8 +323,8 @@ int cam_sync_get_obj_ref(int32_t sync_obj) if (row->state != CAM_SYNC_STATE_ACTIVE) { spin_unlock(&sync_dev->row_spinlocks[sync_obj]); CAM_ERR(CAM_SYNC, - "Error: accessing an uninitialized sync obj = %d", - sync_obj); + "accessing an uninitialized sync obj = %d state = %d", + sync_obj, row->state); return -EINVAL; } @@ -433,6 +433,7 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) { + int rc = 0; struct cam_sync_signal sync_signal; if (k_ioctl->size != sizeof(struct cam_sync_signal)) @@ -447,7 +448,14 @@ static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) return -EFAULT; /* need to get ref for UMD signaled fences */ - cam_sync_get_obj_ref(sync_signal.sync_obj); + rc = cam_sync_get_obj_ref(sync_signal.sync_obj); + if (rc) { + CAM_DBG(CAM_SYNC, + "Error: cannot signal an uninitialized sync obj = %d", + sync_signal.sync_obj); + return rc; + } + return cam_sync_signal(sync_signal.sync_obj, sync_signal.sync_state); } diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/Makefile b/drivers/media/platform/msm/camera_v3/cam_utils/Makefile index 7e1ebd3b7c64..9b14dfb9f6a4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_utils/Makefile @@ -3,3 +3,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_req_mgr/ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_smmu/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o cam_debug_util.o cam_trace.o cam_common_util.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cx_ipeak.o diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c new file mode 100644 index 000000000000..99de0cba82ad --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2018, 2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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/of.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <soc/qcom/cx_ipeak.h> +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static struct cx_ipeak_client *cam_cx_ipeak; +static int cx_ipeak_level = CAM_NOMINAL_VOTE; +static int cx_default_ipeak_mask; +static int cx_current_ipeak_mask; +static int cam_cx_client_cnt; + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + soc_info->cam_cx_ipeak_enable = true; + soc_info->cam_cx_ipeak_bit = 1 << cam_cx_client_cnt++; + cx_default_ipeak_mask |= soc_info->cam_cx_ipeak_bit; + + if (cam_cx_ipeak) + goto exit; + + cam_cx_ipeak = cx_ipeak_register(soc_info->dev->of_node, + "qcom,cam-cx-ipeak"); + + if (cam_cx_ipeak) { + goto exit; + } else { + rc = -EINVAL; + goto exit; + } + +exit: + CAM_DBG(CAM_UTIL, "cam_cx_ipeak is enabled for %s\n" + "mask = %x cx_default_ipeak_mask = %x", + soc_info->dev_name, soc_info->cam_cx_ipeak_bit, + cx_default_ipeak_mask); + return rc; +} + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + int ret = 0; + + CAM_DBG(CAM_UTIL, "E: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + + if (apply_level < cx_ipeak_level && + (cx_current_ipeak_mask & soc_cx_ipeak_bit)) { + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, false); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s UNVOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s DISABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + goto exit; + } else if (apply_level < cx_ipeak_level) { + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x NO AI", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + goto exit; + } + + cx_current_ipeak_mask |= soc_cx_ipeak_bit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s ENABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, true); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s VOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + +exit: + return ret; +} + +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + + CAM_DBG(CAM_UTIL, "E:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + if (cam_cx_ipeak) + cx_ipeak_update(cam_cx_ipeak, false); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x UNVOTE", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + + return 0; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_log.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.h index 321248a3e0eb..f811ac549429 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_log.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,17 +10,17 @@ * GNU General Public License for more details. */ -#ifndef _CAM_ISP_LOG_H_ -#define _CAM_ISP_LOG_H_ +#ifndef _CAM_CX_IPEAK_H_ +#define _CAM_CX_IPEAK_H_ -#include <linux/kernel.h> +#include <linux/clk/qcom.h> +#include <soc/qcom/cx_ipeak.h> +#include "cam_io_util.h" -#define ISP_TRACE_ENABLE 1 +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info); -#if (ISP_TRACE_ENABLE == 1) - #define ISP_TRACE(args...) trace_printk(args) -#else - #define ISP_TRACE(arg...) -#endif +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level); +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info); -#endif /* __CAM_ISP_LOG_H__ */ +#endif /* _CAM_CX_IPEAK_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c index acfae3622130..f623369dd857 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -50,23 +50,44 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) return 0; } -int cam_packet_util_validate_packet(struct cam_packet *packet) +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len) { + size_t sum_cmd_desc = 0; + size_t sum_io_cfgs = 0; + size_t sum_patch_desc = 0; + size_t pkt_wo_payload = 0; + if (!packet) return -EINVAL; + if ((size_t)packet->header.size > remain_len) { + CAM_ERR(CAM_UTIL, + "Invalid packet size: %zu, CPU buf length: %zu", + (size_t)packet->header.size, remain_len); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d", packet->num_cmd_buf, packet->num_io_configs, packet->kmd_cmd_buf_index); - if ((packet->kmd_cmd_buf_index >= packet->num_cmd_buf) || - (!packet->header.size) || - (packet->cmd_buf_offset > packet->header.size) || - (packet->io_configs_offset > packet->header.size)) { - CAM_ERR(CAM_UTIL, "invalid packet:%d %d %d %d %d", - packet->kmd_cmd_buf_index, - packet->num_cmd_buf, packet->cmd_buf_offset, - packet->io_configs_offset, packet->header.size); + sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc); + sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg); + sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc); + pkt_wo_payload = offsetof(struct cam_packet, payload); + + if ((!packet->header.size) || + ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + + sum_cmd_desc) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->io_configs_offset + + sum_io_cfgs) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->patch_offset + + sum_patch_desc) > (size_t)packet->header.size)) { + CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu", + (size_t)packet->header.size, sum_cmd_desc, + sum_io_cfgs, sum_patch_desc); return -EINVAL; } @@ -78,6 +99,7 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, { int rc = 0; size_t len = 0; + size_t remain_len = 0; struct cam_cmd_buf_desc *cmd_desc; uint32_t *cpu_addr; @@ -86,6 +108,13 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return -EINVAL; } + if ((packet->kmd_cmd_buf_index < 0) || + (packet->kmd_cmd_buf_index > packet->num_cmd_buf)) { + CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", + packet->kmd_cmd_buf_index); + return -EINVAL; + } + /* Take first command descriptor and add offset to it for kmd*/ cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *) &packet->payload + packet->cmd_buf_offset); @@ -100,12 +129,21 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, if (rc) return rc; - if (len < cmd_desc->size) { + remain_len = len; + if (((size_t)cmd_desc->offset >= len) || + ((size_t)cmd_desc->size >= (len - (size_t)cmd_desc->offset))) { CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d", len, cmd_desc->size); return -EINVAL; } + remain_len -= (size_t)cmd_desc->offset; + if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) { + CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu", + (size_t)packet->kmd_cmd_buf_offset); + return -EINVAL; + } + cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4); CAM_DBG(CAM_UTIL, "total size %d, cmd size: %d, KMD buffer size: %d", cmd_desc->size, cmd_desc->length, @@ -128,7 +166,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet, { struct cam_patch_desc *patch_desc = NULL; dma_addr_t iova_addr; - uintptr_t cpu_addr; + uintptr_t cpu_addr = 0; uint32_t temp; uint32_t *dst_cpu_addr; uint32_t *src_buf_iova_addr; @@ -147,7 +185,6 @@ int cam_packet_util_process_patches(struct cam_packet *packet, sizeof(struct cam_patch_desc)); for (i = 0; i < packet->num_patches; i++) { - hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? sec_mmu_hdl : iommu_hdl; rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, @@ -161,7 +198,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet, rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, &cpu_addr, &dst_buf_len); - if (rc < 0) { + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { CAM_ERR(CAM_UTIL, "unable to get dst buf address"); return rc; } @@ -171,6 +208,20 @@ int cam_packet_util_process_patches(struct cam_packet *packet, patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); + if ((size_t)patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR(CAM_UTIL, + "Invalid src buf patch offset"); + return -EINVAL; + } + + if ((dst_buf_len < sizeof(void *)) || + ((dst_buf_len - sizeof(void *)) < + (size_t)patch_desc[i].dst_offset)) { + CAM_ERR(CAM_UTIL, + "Invalid dst buf patch offset"); + return -EINVAL; + } + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + patch_desc[i].dst_offset); temp += patch_desc[i].src_offset; @@ -191,8 +242,9 @@ int cam_packet_util_process_generic_cmd_buffer( cam_packet_generic_blob_handler blob_handler_cb, void *user_data) { int rc; - uintptr_t cpu_addr; + uintptr_t cpu_addr = 0; size_t buf_size; + size_t remain_len = 0; uint32_t *blob_ptr; uint32_t blob_type, blob_size, blob_block_size, len_read; @@ -215,6 +267,21 @@ int cam_packet_util_process_generic_cmd_buffer( return rc; } + remain_len = buf_size; + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_buf->offset); + return -EINVAL; + } + + remain_len -= (size_t)cmd_buf->offset; + if (remain_len < (size_t)cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_buf->length); + return -EINVAL; + } + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + cmd_buf->offset); diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h index b2315232262d..412eba52b05a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,9 @@ struct cam_kmd_buf_info { typedef int (*cam_packet_generic_blob_handler)(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data); +/* set resource bitmap callback function type */ +typedef void (*cam_fill_res_bitmap)(uint32_t res_type, unsigned long *bitmap); + /** * cam_packet_util_get_cmd_mem_addr() * @@ -59,10 +62,13 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, * * @packet: Packet to be validated * + * @remain_len: CPU buff length after config offset + * * @return: 0 for success * -EINVAL for Fail */ -int cam_packet_util_validate_packet(struct cam_packet *packet); +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len); /** * cam_packet_util_validate_cmd_desc() diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c index 4972a2a8cd08..59a33889c013 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,6 +18,7 @@ #include <soc/qcom/socinfo.h> #include "cam_soc_util.h" #include "cam_debug_util.h" +#include "cam_cx_ipeak.h" #include <linux/nvmem-consumer.h> uint32_t cam_soc_util_get_soc_id(void) @@ -75,6 +76,33 @@ uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info) static char supported_clk_info[256]; static char debugfs_dir_name[64]; +static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int32_t src_clk_idx, int32_t clk_rate) +{ + int i; + long clk_rate_round; + + clk_rate_round = clk_round_rate(soc_info->clk[src_clk_idx], clk_rate); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed rc = %ld", + clk_rate_round); + return -EINVAL; + } + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { + CAM_DBG(CAM_UTIL, + "soc = %d round rate = %ld actual = %d", + soc_info->clk_rate[i][src_clk_idx], + clk_rate_round, clk_rate); + return i; + } + } + + CAM_WARN(CAM_UTIL, "Invalid clock rate %ld", clk_rate_round); + return -EINVAL; +} + /** * cam_soc_util_get_string_from_level() * @@ -461,6 +489,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, { int32_t src_clk_idx; struct clk *clk = NULL; + int32_t apply_level; if (!soc_info || (soc_info->src_clk_idx < 0)) return -EINVAL; @@ -471,6 +500,17 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, src_clk_idx = soc_info->src_clk_idx; clk = soc_info->clk[src_clk_idx]; + if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { + apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, + clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + "apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + if (apply_level >= 0) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, + apply_level); + } return cam_soc_util_set_clk_rate(clk, soc_info->clk_name[src_clk_idx], clk_rate); @@ -623,17 +663,29 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, if (rc) return rc; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_clk_enable(soc_info->clk[i], soc_info->clk_name[i], soc_info->clk_rate[apply_level][i]); if (rc) goto clk_disable; + if (soc_info->cam_cx_ipeak_enable) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk name = %s idx = %d\n" + "apply_level = %d clc idx = %d", + soc_info->dev_name, soc_info->clk_name[i], i, + apply_level, i); + } } return rc; clk_disable: + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); for (i--; i >= 0; i--) { cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); @@ -659,6 +711,8 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) if (soc_info->num_clk == 0) return; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_unvote_cx_ipeak(soc_info); for (i = soc_info->num_clk - 1; i >= 0; i--) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); @@ -700,7 +754,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) count = of_property_count_strings(of_node, "clock-names"); - CAM_DBG(CAM_UTIL, "count = %d", count); + CAM_DBG(CAM_UTIL, "E: dev_name = %s count = %d", + soc_info->dev_name, count); if (count > CAM_SOC_MAX_CLK) { CAM_ERR(CAM_UTIL, "invalid count of clocks, count=%d", count); rc = -EINVAL; @@ -819,6 +874,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) if (strcmp("true", clk_control_debugfs) == 0) soc_info->clk_control_enable = true; + CAM_DBG(CAM_UTIL, "X: dev_name = %s count = %d", + soc_info->dev_name, count); end: return rc; } @@ -841,12 +898,23 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, if (rc) return rc; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_set_clk_rate(soc_info->clk[i], soc_info->clk_name[i], soc_info->clk_rate[apply_level][i]); - if (rc) + if (rc < 0) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk_name = %s idx = %d\n" + "apply_level = %d", + soc_info->dev_name, soc_info->clk_name[i], + i, apply_level); + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); break; + } } return rc; @@ -1214,6 +1282,9 @@ int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info) if (rc) return rc; + if (of_find_property(of_node, "qcom,cam-cx-ipeak", NULL)) + rc = cam_cx_ipeak_register_cx_ipeak(soc_info); + return rc; } @@ -1322,7 +1393,8 @@ int cam_soc_util_regulator_enable(struct regulator *rgltr, } static int cam_soc_util_request_pinctrl( - struct cam_hw_soc_info *soc_info) { + struct cam_hw_soc_info *soc_info) +{ struct cam_soc_pinctrl_info *device_pctrl = &soc_info->pinctrl_info; struct device *dev = soc_info->dev; diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h index 91cc50daea83..80faed3edae2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -156,6 +156,7 @@ struct cam_soc_gpio_data { * @clk: Array of associated clock resources * @clk_rate: 2D array of clock rates representing clock rate * values at different vote levels + * @prev_clk_level Last vote level * @src_clk_idx: Source clock index that is rate-controllable * @clk_level_valid: Indicates whether corresponding level is valid * @gpio_data: Pointer to gpio info @@ -163,6 +164,8 @@ struct cam_soc_gpio_data { * @dentry: Debugfs entry * @clk_level_override: Clk level set from debugfs * @clk_control: Enable/disable clk rate control through debugfs + * @cam_cx_ipeak_enable cx-ipeak enable/disable flag + * @cam_cx_ipeak_bit cx-ipeak mask for driver * @soc_private: Soc private data */ struct cam_hw_soc_info { @@ -198,6 +201,7 @@ struct cam_hw_soc_info { const char *clk_name[CAM_SOC_MAX_CLK]; struct clk *clk[CAM_SOC_MAX_CLK]; int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK]; + int32_t prev_clk_level; int32_t src_clk_idx; bool clk_level_valid[CAM_MAX_VOTE]; @@ -207,6 +211,8 @@ struct cam_hw_soc_info { struct dentry *dentry; uint32_t clk_level_override; bool clk_control_enable; + bool cam_cx_ipeak_enable; + int32_t cam_cx_ipeak_bit; void *soc_private; }; diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index eed2fa473014..225bd239d9c8 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -384,9 +384,10 @@ static int hfi_process_session_error(u32 device_id, } static int hfi_process_event_notify(u32 device_id, - struct hfi_msg_event_notify_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_event_notify_packet *pkt = _pkt; dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n"); if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { @@ -425,9 +426,10 @@ static int hfi_process_event_notify(u32 device_id, } static int hfi_process_sys_init_done(u32 device_id, - struct hfi_msg_sys_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; @@ -464,9 +466,10 @@ err_no_prop: } static int hfi_process_sys_rel_resource_done(u32 device_id, - struct hfi_msg_sys_release_resource_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_release_resource_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; u32 pkt_size; @@ -1274,9 +1277,10 @@ static void hfi_process_sess_get_prop_buf_req( } static int hfi_process_session_prop_info(u32 device_id, - struct hfi_msg_session_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_property_info_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct buffer_requirements buff_req = { { {0} } }; @@ -1315,9 +1319,10 @@ static int hfi_process_session_prop_info(u32 device_id, } static int hfi_process_session_init_done(u32 device_id, - struct hfi_msg_sys_session_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct vidc_hal_session_init_done session_init_done = { {0} }; @@ -1342,9 +1347,10 @@ static int hfi_process_session_init_done(u32 device_id, } static int hfi_process_session_load_res_done(u32 device_id, - struct hfi_msg_session_load_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_load_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n", @@ -1370,9 +1376,10 @@ static int hfi_process_session_load_res_done(u32 device_id, } static int hfi_process_session_flush_done(u32 device_id, - struct hfi_msg_session_flush_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_flush_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", @@ -1413,9 +1420,10 @@ static int hfi_process_session_flush_done(u32 device_id, } static int hfi_process_session_etb_done(u32 device_id, - struct hfi_msg_session_empty_buffer_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; struct msm_vidc_cb_data_done data_done = {0}; struct hfi_picture_type *hfi_picture_type = NULL; @@ -1467,9 +1475,10 @@ static int hfi_process_session_etb_done(u32 device_id, } static int hfi_process_session_ftb_done( - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + u32 device_id, void *_pkt, struct msm_vidc_cb_info *info) { + struct vidc_hal_msg_pkt_hdr *msg_hdr = _pkt; struct msm_vidc_cb_data_done data_done = {0}; bool is_decoder = false, is_encoder = false; @@ -1595,9 +1604,10 @@ static int hfi_process_session_ftb_done( } static int hfi_process_session_start_done(u32 device_id, - struct hfi_msg_session_start_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_start_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n", @@ -1621,9 +1631,10 @@ static int hfi_process_session_start_done(u32 device_id, } static int hfi_process_session_stop_done(u32 device_id, - struct hfi_msg_session_stop_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_stop_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n", @@ -1648,9 +1659,10 @@ static int hfi_process_session_stop_done(u32 device_id, } static int hfi_process_session_rel_res_done(u32 device_id, - struct hfi_msg_session_release_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n", @@ -1675,9 +1687,10 @@ static int hfi_process_session_rel_res_done(u32 device_id, } static int hfi_process_session_rel_buf_done(u32 device_id, - struct hfi_msg_session_release_buffers_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_buffers_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; if (!pkt || pkt->size < @@ -1708,9 +1721,10 @@ static int hfi_process_session_rel_buf_done(u32 device_id, } static int hfi_process_session_end_done(u32 device_id, - struct hfi_msg_sys_session_end_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_end_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); @@ -1733,9 +1747,10 @@ static int hfi_process_session_end_done(u32 device_id, } static int hfi_process_session_abort_done(u32 device_id, - struct hfi_msg_sys_session_abort_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_abort_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", @@ -1803,9 +1818,10 @@ static void hfi_process_sys_get_prop_image_version( } static int hfi_process_sys_property_info(u32 device_id, - struct hfi_msg_sys_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_property_info_packet *pkt = _pkt; if (!pkt) { dprintk(VIDC_ERR, "%s: invalid param\n", __func__); return -EINVAL; @@ -1837,7 +1853,7 @@ static int hfi_process_sys_property_info(u32 device_id, } static int hfi_process_ignore(u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr, + void *_pkt, struct msm_vidc_cb_info *info) { *info = (struct msm_vidc_cb_info) { @@ -1918,5 +1934,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, break; } - return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; } diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c index 8eaf1fd192af..9f85f5d8b0f0 100644 --- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c @@ -322,9 +322,10 @@ static int hfi_process_session_error(u32 device_id, } static int hfi_process_event_notify(u32 device_id, - struct hfi_msg_event_notify_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_event_notify_packet *pkt = _pkt; dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n"); if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { @@ -363,9 +364,10 @@ static int hfi_process_event_notify(u32 device_id, } static int hfi_process_sys_init_done(u32 device_id, - struct hfi_msg_sys_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; @@ -402,9 +404,10 @@ err_no_prop: } static int hfi_process_sys_rel_resource_done(u32 device_id, - struct hfi_msg_sys_release_resource_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_release_resource_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; enum vidc_status status = VIDC_ERR_NONE; u32 pkt_size; @@ -1228,9 +1231,10 @@ static void hfi_process_sess_get_prop_buf_req( } static int hfi_process_session_prop_info(u32 device_id, - struct hfi_msg_session_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_property_info_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct hfi_profile_level profile_level = {0}; enum hal_h264_entropy entropy = HAL_UNUSED_ENTROPY; @@ -1303,9 +1307,10 @@ static int hfi_process_session_prop_info(u32 device_id, } static int hfi_process_session_init_done(u32 device_id, - struct hfi_msg_sys_session_init_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_init_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; struct vidc_hal_session_init_done session_init_done = { {0} }; @@ -1337,9 +1342,10 @@ static int hfi_process_session_init_done(u32 device_id, } static int hfi_process_session_load_res_done(u32 device_id, - struct hfi_msg_session_load_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_load_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n", @@ -1367,9 +1373,10 @@ static int hfi_process_session_load_res_done(u32 device_id, } static int hfi_process_session_flush_done(u32 device_id, - struct hfi_msg_session_flush_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_flush_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", @@ -1412,9 +1419,10 @@ static int hfi_process_session_flush_done(u32 device_id, } static int hfi_process_session_etb_done(u32 device_id, - struct hfi_msg_session_empty_buffer_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; struct msm_vidc_cb_data_done data_done = {0}; struct hfi_picture_type *hfi_picture_type = NULL; @@ -1463,9 +1471,10 @@ static int hfi_process_session_etb_done(u32 device_id, } static int hfi_process_session_ftb_done( - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + u32 device_id, void *_pkt, struct msm_vidc_cb_info *info) { + struct vidc_hal_msg_pkt_hdr *msg_hdr = _pkt; struct msm_vidc_cb_data_done data_done = {0}; bool is_decoder = false, is_encoder = false; @@ -1590,9 +1599,10 @@ static int hfi_process_session_ftb_done( } static int hfi_process_session_start_done(u32 device_id, - struct hfi_msg_session_start_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_start_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n", @@ -1618,9 +1628,10 @@ static int hfi_process_session_start_done(u32 device_id, } static int hfi_process_session_stop_done(u32 device_id, - struct hfi_msg_session_stop_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_stop_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n", @@ -1647,9 +1658,10 @@ static int hfi_process_session_stop_done(u32 device_id, } static int hfi_process_session_rel_res_done(u32 device_id, - struct hfi_msg_session_release_resources_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_resources_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n", @@ -1676,9 +1688,10 @@ static int hfi_process_session_rel_res_done(u32 device_id, } static int hfi_process_session_rel_buf_done(u32 device_id, - struct hfi_msg_session_release_buffers_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_session_release_buffers_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; if (!pkt || pkt->size < @@ -1711,9 +1724,10 @@ static int hfi_process_session_rel_buf_done(u32 device_id, } static int hfi_process_session_end_done(u32 device_id, - struct hfi_msg_sys_session_end_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_end_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); @@ -1738,9 +1752,10 @@ static int hfi_process_session_end_done(u32 device_id, } static int hfi_process_session_abort_done(u32 device_id, - struct hfi_msg_sys_session_abort_done_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_session_abort_done_packet *pkt = _pkt; struct msm_vidc_cb_cmd_done cmd_done = {0}; dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", @@ -1846,9 +1861,10 @@ static void hfi_process_sys_get_prop_image_version( } static int hfi_process_sys_property_info(u32 device_id, - struct hfi_msg_sys_property_info_packet *pkt, + void *_pkt, struct msm_vidc_cb_info *info) { + struct hfi_msg_sys_property_info_packet *pkt = _pkt; if (!pkt) { dprintk(VIDC_ERR, "%s: invalid param\n", __func__); return -EINVAL; @@ -1880,7 +1896,7 @@ static int hfi_process_sys_property_info(u32 device_id, } static int hfi_process_ignore(u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr, + void *_pkt, struct msm_vidc_cb_info *info) { *info = (struct msm_vidc_cb_info) { @@ -1964,5 +1980,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, break; } - return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; } diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c index 983e600c6480..0a2d380dbbd7 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1278,13 +1278,12 @@ void *msm_vidc_open(int core_id, int session_type) return inst; fail_init: + mutex_lock(&core->lock); v4l2_fh_del(&inst->event_handler); v4l2_fh_exit(&inst->event_handler); - vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); - - mutex_lock(&core->lock); list_del(&inst->list); mutex_unlock(&core->lock); + vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); fail_bufq_output: vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq); diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c index 22f49ce02e47..af2514c60065 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1638,11 +1638,11 @@ static void msm_comm_clean_notify_client(struct msm_vidc_core *core) list_for_each_entry(inst, &core->instances, list) { mutex_lock(&inst->lock); inst->state = MSM_VIDC_CORE_INVALID; - mutex_unlock(&inst->lock); dprintk(VIDC_WARN, "%s Send sys error for inst %pK\n", __func__, inst); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); + mutex_unlock(&inst->lock); } mutex_unlock(&core->lock); } diff --git a/drivers/misc/hdcp_qseecom.c b/drivers/misc/hdcp_qseecom.c index 6ce377667623..13175d041833 100644 --- a/drivers/misc/hdcp_qseecom.c +++ b/drivers/misc/hdcp_qseecom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2037,6 +2037,30 @@ bool hdcp1_check_if_supported_load_app(void) return hdcp1_supported; } +void hdcp1_unload_app(void) +{ + int rc = 0; + + if (!hdcp1_supported) { + pr_debug("hdcp1 is not supported\n"); + return; + } + + if (!hdcp1_handle) { + pr_debug("invalid hdcp1 handle\n"); + return; + } + + rc = qseecom_shutdown_app(&hdcp1_handle); + if (rc) { + pr_debug("qseecom_shutdown_app failed with ERR = %d\n", rc); + return; + } + + hdcp1_handle = NULL; + pr_debug("hdcp1 app unloaded\n"); +} + /* APIs exposed to all clients */ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb) { diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 87fc883e8a73..a4d35d94de0c 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -911,11 +911,13 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) cmdq_runtime_pm_put(cq_host); - if (cq_host->ops->crypto_cfg_end) { - err = cq_host->ops->crypto_cfg_end(mmc, mrq); - if (err) { - pr_err("%s: failed to end ice config: err %d tag %d\n", - mmc_hostname(mmc), err, tag); + if (!(mrq->cmdq_req->cmdq_req_flags & DCMD)) { + if (cq_host->ops->crypto_cfg_end) { + err = cq_host->ops->crypto_cfg_end(mmc, mrq); + if (err) { + pr_err("%s: failed to end ice config: err %d tag %d\n", + mmc_hostname(mmc), err, tag); + } } } if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 37df1bf277ca..09e8d38f57ae 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -752,11 +752,7 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) if (!event) continue; - /* - * Check if an attempt was made to free this event during - * the CPU went offline. - */ - if (event->state == PERF_EVENT_STATE_ZOMBIE) + if (event->state != PERF_EVENT_STATE_ACTIVE) continue; switch (cmd) { @@ -882,10 +878,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_EXIT; - cpu_pm_pmu_common(&data); - if (data.ret == NOTIFY_DONE) - return 0; + if (pmu->reset) + pmu->reset(pmu); if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF && data.armpmu->plat_device) { @@ -911,8 +905,6 @@ static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_ENTER; - cpu_pm_pmu_common(&data); /* Disarm the PMU IRQ before disappearing. */ if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING && data.armpmu->plat_device) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index f1f6b900d474..b3c38b9d7f86 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -737,8 +737,14 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, IPADBG("msg=%pK\n", msg); locked = 0; mutex_unlock(&ipa_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, - sizeof(struct ipa_msg_meta))) { + sizeof(struct ipa_msg_meta))) { kfree(msg); msg = NULL; ret = -EFAULT; @@ -747,8 +753,15 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } + } else { kfree(msg); msg = NULL; ret = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index c348e26b6b69..d41cdb7c2f90 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -745,6 +745,12 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, if (msg) { locked = 0; mutex_unlock(&ipa3_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { ret = -EFAULT; @@ -755,8 +761,15 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + ret = -EFAULT; + kfree(msg); + msg = NULL; + break; + } + } else { ret = -EFAULT; kfree(msg); msg = NULL; diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index bc1855ea5d48..f56b9837f259 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1115,10 +1115,14 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_VOLTAGE_NOW: - case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_TEMP: rc = smblib_get_prop_from_bms(chg, psp, val); break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rc = smblib_get_prop_from_bms(chg, psp, val); + if (!rc) + val->intval *= (-1); + break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 7994741ccb1c..a4410734f6c5 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1367,6 +1367,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CURRENT_NOW, val); + if (!rc) + val->intval *= (-1); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 896509dac561..523fe47a4d54 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -308,6 +308,7 @@ enum pmic_subtype { PMI8950 = 17, PMI8996 = 19, PMI8937 = 55, + PMI8940 = 64, }; enum smbchg_wa { @@ -1133,6 +1134,28 @@ static int get_prop_batt_voltage_max_design(struct smbchg_chip *chip) return uv; } +static int get_prop_batt_charge_counter(struct smbchg_chip *chip) +{ + int bcc = 0, rc; + + rc = get_property_from_fg(chip, + POWER_SUPPLY_PROP_CHARGE_COUNTER, &bcc); + if (rc) + pr_smb(PR_STATUS, "Couldn't get charge_counter rc = %d\n", rc); + return bcc; +} + +static int get_prop_batt_cycle_count(struct smbchg_chip *chip) +{ + int bcc = 0, rc; + + rc = get_property_from_fg(chip, + POWER_SUPPLY_PROP_CYCLE_COUNT, &bcc); + if (rc) + pr_smb(PR_STATUS, "Couldn't get cycle_count rc = %d\n", rc); + return bcc; +} + static int get_prop_batt_health(struct smbchg_chip *chip) { if (chip->batt_hot) @@ -5899,6 +5922,8 @@ static enum power_supply_property smbchg_battery_properties[] = { POWER_SUPPLY_PROP_RESTRICTED_CHARGING, POWER_SUPPLY_PROP_ALLOW_HVDCP3, POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CYCLE_COUNT, }; static int smbchg_battery_set_property(struct power_supply *psy, @@ -6118,6 +6143,12 @@ static int smbchg_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED: val->intval = chip->max_pulse_allowed; break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = get_prop_batt_charge_counter(chip); + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + val->intval = get_prop_batt_cycle_count(chip); + break; default: return -EINVAL; } @@ -8096,6 +8127,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) case PMI8950: chip->wa_flags |= SMBCHG_RESTART_WA; case PMI8937: + /* fall through */ + case PMI8940: chip->wa_flags |= SMBCHG_BATT_OV_WA; if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; @@ -8110,7 +8143,9 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) ARRAY_SIZE(aicl_rerun_period_schg_lite); chip->schg_version = QPNP_SCHG_LITE; - if (pmic_rev_id->pmic_subtype == PMI8937) + /* PMI8937/PMI8940 doesn't support HVDCP */ + if ((pmic_rev_id->pmic_subtype == PMI8937) + || (pmic_rev_id->pmic_subtype == PMI8940)) chip->hvdcp_not_supported = true; break; case PMI8996: diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index e23f13e2236f..9b0ec47df85a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2888,6 +2888,7 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) chg->pd_active = pd_active; if (chg->pd_active) { + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; vote(chg->apsd_disable_votable, PD_VOTER, true, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); diff --git a/drivers/power/supply/qcom/smb1360-charger-fg.c b/drivers/power/supply/qcom/smb1360-charger-fg.c index 4e98ec752fa7..41dcf1dca25d 100644 --- a/drivers/power/supply/qcom/smb1360-charger-fg.c +++ b/drivers/power/supply/qcom/smb1360-charger-fg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2018-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,7 @@ #include <linux/qpnp/qpnp-adc.h> #include <linux/completion.h> #include <linux/pm_wakeup.h> +#include <linux/of_irq.h> #define _SMB1360_MASK(BITS, POS) \ ((unsigned char)(((1 << (BITS)) - 1) << (POS))) @@ -405,6 +406,7 @@ struct smb1360_chip { bool otg_fet_present; bool fet_gain_enabled; int otg_fet_enable_gpio; + int usb_id_gpio; /* status tracking */ int voltage_now; @@ -466,6 +468,7 @@ struct smb1360_chip { int cold_hysteresis; int hot_hysteresis; struct extcon_dev *extcon; + int usb_id_irq; }; static int chg_time[] = { @@ -2885,6 +2888,28 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t smb1360_usb_id_irq_handler(int irq, void *dev_id) +{ + struct smb1360_chip *chip = dev_id; + int rc = 0; + bool id_state; + + id_state = gpio_get_value(chip->usb_id_gpio); + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, + !id_state ? CMD_OTG_EN_BIT : 0); + if (rc) { + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + return IRQ_HANDLED; + } + extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, + !id_state ? true : false); + + pr_debug("usb_id_irq triggered, id_state = %d\n", id_state); + + return IRQ_HANDLED; +} + static int show_irq_count(struct seq_file *m, void *data) { int i, j, total = 0; @@ -3421,6 +3446,10 @@ static int smb1360_regulator_init(struct smb1360_chip *chip) int rc = 0; struct regulator_config cfg = {}; + /* OTG is enabled by SMB1360 if usb-id config is defined */ + if (chip->usb_id_gpio > 0 && chip->usb_id_irq > 0) + return 0; + chip->otg_vreg.rdesc.owner = THIS_MODULE; chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE; chip->otg_vreg.rdesc.ops = &smb1360_otg_reg_ops; @@ -3557,6 +3586,7 @@ static int determine_initial_status(struct smb1360_chip *chip) { int rc; u8 reg = 0; + bool id_state; /* * It is okay to read the IRQ status as the irq's are @@ -3621,6 +3651,25 @@ static int determine_initial_status(struct smb1360_chip *chip) else extcon_set_cable_state_(chip->extcon, EXTCON_USB, true); + pr_debug("usb %s at boot\n", chip->usb_present ? "present" : "absent"); + + /*check otg presence and notify*/ + if (chip->usb_id_gpio != -EINVAL) { + id_state = gpio_get_value(chip->usb_id_gpio); + /* usb-id is low, enable OTG */ + if (!id_state) { + rc = smb1360_masked_write(chip, CMD_CHG_REG, + CMD_OTG_EN_BIT, CMD_OTG_EN_BIT); + if (rc) { + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + return rc; + } + extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, + true); + pr_debug("OTG enabled at boot\n"); + } + } + power_supply_changed(chip->usb_psy); return 0; } @@ -4752,6 +4801,11 @@ static int smb_parse_dt(struct smb1360_chip *chip) return rc; } } + chip->usb_id_gpio = -EINVAL; + if (of_find_property(node, "qcom,usb-id-gpio", NULL)) { + chip->usb_id_gpio = of_get_named_gpio(node, + "qcom,usb-id-gpio", 0); + } chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); @@ -5073,6 +5127,28 @@ static int smb1360_probe(struct i2c_client *client, enable_irq_wake(client->irq); } + chip->usb_id_irq = of_irq_get_byname(chip->dev->of_node, + "smb1360_usb_id_irq"); + if (chip->usb_id_irq > 0) { + if (chip->usb_id_gpio == -EINVAL) { + pr_err("usb-id gpio not defined\n"); + } else { + rc = devm_request_threaded_irq(&client->dev, + chip->usb_id_irq, NULL, + smb1360_usb_id_irq_handler, + IRQF_ONESHOT + | IRQF_TRIGGER_FALLING + | IRQF_TRIGGER_RISING, + "smb1360_usb_id_irq", chip); + if (rc < 0) { + dev_err(&client->dev, + "usb-id request_irq for irq=%d failed rc = %d\n", + chip->usb_id_irq, rc); + goto unregister_batt_psy; + } + enable_irq_wake(chip->usb_id_irq); + } + } chip->debug_root = debugfs_create_dir("smb1360", NULL); if (!chip->debug_root) dev_err(chip->dev, "Couldn't create debug dir\n"); @@ -5201,7 +5277,8 @@ static int smb1360_probe(struct i2c_client *client, unregister_batt_psy: power_supply_unregister(chip->batt_psy); fail_hw_init: - regulator_unregister(chip->otg_vreg.rdev); + if (chip->otg_vreg.rdev) + regulator_unregister(chip->otg_vreg.rdev); destroy_mutex: power_supply_unregister(chip->usb_psy); wakeup_source_trash(&chip->smb1360_ws.source); @@ -5218,8 +5295,9 @@ destroy_mutex: static int smb1360_remove(struct i2c_client *client) { struct smb1360_chip *chip = i2c_get_clientdata(client); + if (chip->otg_vreg.rdev) + regulator_unregister(chip->otg_vreg.rdev); - regulator_unregister(chip->otg_vreg.rdev); power_supply_unregister(chip->usb_psy); power_supply_unregister(chip->batt_psy); wakeup_source_trash(&chip->smb1360_ws.source); diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index d4fe6eede3b4..a2b725706667 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -226,14 +226,17 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) } qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN; - ice_workqueue = alloc_workqueue("ice-set-key", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); if (!ice_workqueue) { - dev_err(ufs_dev, "%s: workqueue allocation failed.\n", + ice_workqueue = alloc_workqueue("ice-set-key", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!ice_workqueue) { + dev_err(ufs_dev, "%s: workqueue allocation failed.\n", __func__); - goto out; + err = -ENOMEM; + goto out; + } + INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); } - INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); out: return err; @@ -286,6 +289,17 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, * propagate so it will be re-queued. */ if (err == -EAGAIN) { + if (!ice_workqueue) { + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + dev_err(qcom_host->hba->dev, + "%s: error %d workqueue NULL\n", + __func__, err); + return -EINVAL; + } + dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); @@ -405,6 +419,16 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * propagate so it will be re-queued. */ if (err == -EAGAIN) { + if (!ice_workqueue) { + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + dev_err(qcom_host->hba->dev, + "%s: error %d workqueue NULL\n", + __func__, err); + return -EINVAL; + } dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d70fc6bb9d72..3ae576655f8b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3445,18 +3445,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, int tag; struct completion wait; unsigned long flags; - bool has_read_lock = false; - - /* - * May get invoked from shutdown and IOCTL contexts. - * In shutdown context, it comes in with lock acquired. - * In error recovery context, it may come with lock acquired. - */ - - if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { - down_read(&hba->lock); - has_read_lock = true; - } /* * Get free slot, sleep if slots are unavailable. @@ -3489,8 +3477,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, out_put_tag: ufshcd_put_dev_cmd_tag(hba, tag); wake_up(&hba->dev_cmd.tag_wq); - if (has_read_lock) - up_read(&hba->lock); return err; } @@ -3565,10 +3551,15 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, struct ufs_query_res *response = NULL; int err, index = 0, selector = 0; int timeout = QUERY_REQ_TIMEOUT; + bool has_read_lock = false; BUG_ON(!hba); ufshcd_hold_all(hba); + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3612,6 +3603,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); ufshcd_release_all(hba); return err; } @@ -3634,6 +3627,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; int err; + bool has_read_lock = false; BUG_ON(!hba); @@ -3645,6 +3639,16 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, goto out; } + /* + * May get invoked from shutdown and IOCTL contexts. + * In shutdown context, it comes in with lock acquired. + * In error recovery context, it may come with lock acquired. + */ + + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3677,6 +3681,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); out: ufshcd_release_all(hba); return err; @@ -3727,6 +3733,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; int err; + bool has_read_lock = false; BUG_ON(!hba); @@ -3745,6 +3752,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out; } + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3780,6 +3791,9 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); + out: ufshcd_release_all(hba); return err; @@ -5301,8 +5315,13 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba) { int err = 0; int retries; + bool has_read_lock = false; ufshcd_hold_all(hba); + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); for (retries = NOP_OUT_RETRIES; retries > 0; retries--) { err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP, @@ -5314,6 +5333,8 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); } mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); ufshcd_release_all(hba); if (err) @@ -10252,12 +10273,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) * e.g. link_recovery. Hence, release the rw_sem * before hibern8. */ - up_write(&hba->lock); ret = ufshcd_uic_hibern8_enter(hba); - down_write(&hba->lock); if (ret) - /* link will be bad state so no need to scale_up_gear */ - return ret; + goto scale_up_gear; ufshcd_custom_cmd_log(hba, "Hibern8-entered"); } @@ -10269,8 +10287,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) if (ufshcd_is_auto_hibern8_supported(hba)) { ret = ufshcd_uic_hibern8_exit(hba); if (ret) - /* link will be bad state so no need to scale_up_gear */ - return ret; + goto scale_up_gear; ufshcd_custom_cmd_log(hba, "Hibern8-Exited"); } diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index 34be2301be20..44f34cf4227e 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -2083,7 +2083,7 @@ static int ngd_slim_runtime_suspend(struct device *device) #ifdef CONFIG_PM_SLEEP static int ngd_slim_suspend(struct device *dev) { - int ret = -EBUSY; + int ret = 0; struct platform_device *pdev = to_platform_device(dev); struct msm_slim_ctrl *cdev; @@ -2092,6 +2092,13 @@ static int ngd_slim_suspend(struct device *dev) return 0; cdev = platform_get_drvdata(pdev); + + if (cdev->state == MSM_CTRL_AWAKE) { + ret = -EBUSY; + SLIM_INFO(cdev, "system suspend: %d\n", ret); + return ret; + + } if (!pm_runtime_enabled(dev) || (!pm_runtime_suspended(dev) && cdev->state == MSM_CTRL_IDLE)) { @@ -2109,17 +2116,6 @@ static int ngd_slim_suspend(struct device *dev) cdev->qmi.deferred_resp = false; } } - if (ret == -EBUSY) { - /* - * There is a possibility that some audio stream is active - * during suspend. We dont want to return suspend failure in - * that case so that display and relevant components can still - * go to suspend. - * If there is some other error, then it should be passed-on - * to system level suspend - */ - ret = 0; - } SLIM_INFO(cdev, "system suspend\n"); return ret; } diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c index a08c4bfde4a2..efcd94cdda01 100644 --- a/drivers/soc/qcom/glink_spi_xprt.c +++ b/drivers/soc/qcom/glink_spi_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -484,6 +484,13 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst, int ret; read_id = einfo->rx_fifo_read; + if ((read_id > (einfo->rx_fifo_start + einfo->fifo_size)) || + (read_id < einfo->rx_fifo_start)) { + pr_err("%s: Invalid rx_fifo_read: %d, start: %d, size: %d\n", + __func__, read_id, einfo->rx_fifo_start, + einfo->fifo_size); + return -EINVAL; + } do { if ((read_id + size_to_read) >= (einfo->rx_fifo_start + einfo->fifo_size)) @@ -722,11 +729,11 @@ static void process_rx_cmd(struct edge_info *einfo, struct rx_short_data_desc { unsigned char data[SHORT_PKT_SIZE]; }; - struct command *cmd; + struct command *cmd = NULL; struct intent_desc *intents; struct rx_desc *rx_descp; struct rx_short_data_desc *rx_sd_descp; - int offset = 0; + uint64_t offset = 0; int rcu_id; uint16_t rcid; uint16_t name_len; @@ -742,6 +749,8 @@ static void process_rx_cmd(struct edge_info *einfo, } while (offset < rx_size) { + if (offset + sizeof(*cmd) > rx_size) + goto err; cmd = (struct command *)(rx_data + offset); offset += sizeof(*cmd); switch (cmd->id) { @@ -760,7 +769,12 @@ static void process_rx_cmd(struct edge_info *einfo, case OPEN_CMD: rcid = cmd->param1; name_len = (uint16_t)(cmd->param2 & 0xFFFF); + if (name_len > GLINK_NAME_SIZE) + goto err; prio = (uint16_t)((cmd->param2 & 0xFFFF0000) >> 16); + if (offset + ALIGN(name_len, FIFO_ALIGNMENT) > + rx_size) + goto err; name = (char *)(rx_data + offset); offset += ALIGN(name_len, FIFO_ALIGNMENT); einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_remote_open( @@ -786,6 +800,8 @@ static void process_rx_cmd(struct edge_info *einfo, case RX_INTENT_CMD: for (i = 0; i < cmd->param2; i++) { + if (offset + sizeof(*intents) > rx_size) + goto err; intents = (struct intent_desc *) (rx_data + offset); offset += sizeof(*intents); @@ -821,6 +837,8 @@ static void process_rx_cmd(struct edge_info *einfo, case TX_DATA_CONT_CMD: case TRACER_PKT_CMD: case TRACER_PKT_CONT_CMD: + if (offset + sizeof(*rx_descp) > rx_size) + goto err; rx_descp = (struct rx_desc *)(rx_data + offset); offset += sizeof(*rx_descp); process_rx_data(einfo, cmd->id, cmd->param1, @@ -830,6 +848,8 @@ static void process_rx_cmd(struct edge_info *einfo, break; case TX_SHORT_DATA_CMD: + if (offset + sizeof(*rx_sd_descp) > rx_size) + goto err; rx_sd_descp = (struct rx_short_data_desc *) (rx_data + offset); offset += sizeof(*rx_sd_descp); @@ -858,6 +878,13 @@ static void process_rx_cmd(struct edge_info *einfo, } } srcu_read_unlock(&einfo->use_ref, rcu_id); + return; +err: + srcu_read_unlock(&einfo->use_ref, rcu_id); + if (cmd) + pr_err("%s: invalid size of rx_data: %d, cmd : %d\n", + __func__, rx_size, cmd->id); + return; } /** diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 84ad1e74f73c..f3acd4113b06 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -76,6 +76,8 @@ module_param(qmi_timeout, ulong, 0600); #define ICNSS_MAX_PROBE_CNT 2 +#define PROBE_TIMEOUT 5000 + #define icnss_ipc_log_string(_x...) do { \ if (icnss_ipc_log_context) \ ipc_log_string(icnss_ipc_log_context, _x); \ @@ -286,6 +288,7 @@ enum icnss_driver_state { ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, ICNSS_MODE_ON, + ICNSS_BLOCK_SHUTDOWN, }; struct ce_irq_list { @@ -475,6 +478,7 @@ static struct icnss_priv { struct mutex dev_lock; uint32_t fw_error_fatal_irq; uint32_t fw_early_crash_irq; + struct completion unblock_shutdown; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -1164,6 +1168,21 @@ bool icnss_is_fw_ready(void) } EXPORT_SYMBOL(icnss_is_fw_ready); +void icnss_block_shutdown(bool status) +{ + if (!penv) + return; + + if (status) { + set_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + reinit_completion(&penv->unblock_shutdown); + } else { + clear_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + complete(&penv->unblock_shutdown); + } +} +EXPORT_SYMBOL(icnss_block_shutdown); + bool icnss_is_fw_down(void) { if (!penv) @@ -2256,6 +2275,7 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) icnss_hw_power_on(priv); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2265,9 +2285,11 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, priv->state, probe_cnt); + icnss_block_shutdown(false); goto out; } + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2406,6 +2428,7 @@ static int icnss_driver_event_register_driver(void *data) if (ret) goto out; + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2415,9 +2438,11 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, penv->state, probe_cnt); + icnss_block_shutdown(false); goto power_off; } + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2436,9 +2461,14 @@ static int icnss_driver_event_unregister_driver(void *data) } set_bit(ICNSS_DRIVER_UNLOADING, &penv->state); + + icnss_block_shutdown(true); + if (penv->ops) penv->ops->remove(&penv->pdev->dev); + icnss_block_shutdown(false); + clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state); clear_bit(ICNSS_DRIVER_PROBED, &penv->state); @@ -2685,6 +2715,13 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && + test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { + if (!wait_for_completion_timeout(&priv->unblock_shutdown, + PROBE_TIMEOUT)) + icnss_pr_err("wlan driver probe timeout\n"); + } + if (test_bit(ICNSS_PDR_REGISTERED, &priv->state)) { set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_qmi_timeout(true); @@ -4050,6 +4087,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_MODE_ON: seq_puts(s, "MODE ON DONE"); + continue; + case ICNSS_BLOCK_SHUTDOWN: + seq_puts(s, "BLOCK SHUTDOWN"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4721,6 +4761,8 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; + init_completion(&priv->unblock_shutdown); + icnss_pr_info("Platform driver probed successfully\n"); return 0; @@ -4743,6 +4785,8 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); + complete_all(&penv->unblock_shutdown); + icnss_modem_ssr_unregister_notifier(penv); destroy_ramdump_device(penv->msa0_dump_dev); diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c index 2c90bef1224f..48fe4e985ff5 100644 --- a/drivers/spmi/spmi-pmic-arb-debug.c +++ b/drivers/spmi/spmi-pmic-arb-debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -365,17 +365,7 @@ static struct platform_driver spmi_pmic_arb_debug_driver = { }, }; -int __init spmi_pmic_arb_debug_init(void) -{ - return platform_driver_register(&spmi_pmic_arb_debug_driver); -} -arch_initcall(spmi_pmic_arb_debug_init); - -static void __exit spmi_pmic_arb_debug_exit(void) -{ - platform_driver_unregister(&spmi_pmic_arb_debug_driver); -} -module_exit(spmi_pmic_arb_debug_exit); +module_platform_driver(spmi_pmic_arb_debug_driver); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spmi_pmic_arb_debug"); diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index ff7d7126df85..1f588a3aca20 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -261,7 +261,8 @@ static void mdp3_vsync_retire_handle_vsync(void *arg) return; } - schedule_work(&mdp3_session->retire_work); + kthread_queue_work(&mdp3_session->retire_worker, + &mdp3_session->retire_work); } void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val) @@ -282,7 +283,7 @@ void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val) mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex); } -static void mdp3_vsync_retire_work_handler(struct work_struct *work) +static void mdp3_vsync_retire_work_handler(struct kthread_work *work) { struct mdp3_session_data *mdp3_session = container_of(work, struct mdp3_session_data, retire_work); @@ -2981,6 +2982,7 @@ static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd) struct mdp3_session_data *mdp3_session; struct mdp3_notification retire_client; char name[24]; + struct sched_param param = { .sched_priority = 16 }; mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; @@ -2998,7 +3000,20 @@ static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd) if (mdp3_session->dma) mdp3_session->dma->retire_client = retire_client; - INIT_WORK(&mdp3_session->retire_work, mdp3_vsync_retire_work_handler); + kthread_init_worker(&mdp3_session->retire_worker); + kthread_init_work(&mdp3_session->retire_work, + mdp3_vsync_retire_work_handler); + + mdp3_session->retire_thread = kthread_run(kthread_worker_fn, + &mdp3_session->retire_worker, + "vsync_retire_work"); + if (IS_ERR(mdp3_session->retire_thread)) { + pr_err("unable to start vsync thread\n"); + mdp3_session->retire_thread = NULL; + return -ENOMEM; + } + + sched_setscheduler(mdp3_session->retire_thread, SCHED_FIFO, ¶m); return 0; } diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h index 032debe1aa85..07377a92981e 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.h +++ b/drivers/video/fbdev/msm/mdp3_ctrl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -61,6 +61,10 @@ struct mdp3_session_data { struct kthread_worker worker; struct task_struct *thread; + struct kthread_work retire_work; + struct kthread_worker retire_worker; + struct task_struct *retire_thread; + atomic_t dma_done_cnt; int histo_status; struct mutex histo_lock; @@ -84,7 +88,6 @@ struct mdp3_session_data { /* For retire fence */ struct mdss_timeline *vsync_timeline; int retire_cnt; - struct work_struct retire_work; }; void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq, int client); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e69ebe648a34..be3e1db832b5 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -456,17 +456,12 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) return inode; } -int proc_fill_super(struct super_block *s, void *data, int silent) +int proc_fill_super(struct super_block *s) { - struct pid_namespace *ns = get_pid_ns(s->s_fs_info); struct inode *root_inode; int ret; - if (!proc_parse_options(data, ns)) - return -EINVAL; - - /* User space would break if executables or devices appear on proc */ - s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; + s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NODEV; s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index d8105cd8b01c..d8edf39e0c1d 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -213,7 +213,7 @@ extern const struct file_operations proc_reclaim_operations; extern void proc_init_inodecache(void); extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); -extern int proc_fill_super(struct super_block *, void *data, int flags); +extern int proc_fill_super(struct super_block *); extern void proc_entry_rundown(struct proc_dir_entry *); /* @@ -278,7 +278,6 @@ static inline void proc_tty_init(void) {} * root.c */ extern struct proc_dir_entry proc_root; -extern int proc_parse_options(char *options, struct pid_namespace *pid); extern void proc_self_init(void); extern int proc_remount(struct super_block *, int *, char *); diff --git a/fs/proc/root.c b/fs/proc/root.c index c2f5014d642d..1d68fcd9313f 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -23,6 +23,21 @@ #include "internal.h" +static int proc_test_super(struct super_block *sb, void *data) +{ + return sb->s_fs_info == data; +} + +static int proc_set_super(struct super_block *sb, void *data) +{ + int err = set_anon_super(sb, NULL); + if (!err) { + struct pid_namespace *ns = (struct pid_namespace *)data; + sb->s_fs_info = get_pid_ns(ns); + } + return err; +} + enum { Opt_gid, Opt_hidepid, Opt_err, }; @@ -33,7 +48,7 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; -int proc_parse_options(char *options, struct pid_namespace *pid) +static int proc_parse_options(char *options, struct pid_namespace *pid) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -85,16 +100,45 @@ int proc_remount(struct super_block *sb, int *flags, char *data) static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { + int err; + struct super_block *sb; struct pid_namespace *ns; + char *options; if (flags & MS_KERNMOUNT) { - ns = data; - data = NULL; + ns = (struct pid_namespace *)data; + options = NULL; } else { ns = task_active_pid_ns(current); + options = data; + + /* Does the mounter have privilege over the pid namespace? */ + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + } + + sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); + if (IS_ERR(sb)) + return ERR_CAST(sb); + + if (!proc_parse_options(options, ns)) { + deactivate_locked_super(sb); + return ERR_PTR(-EINVAL); + } + + if (!sb->s_root) { + err = proc_fill_super(sb); + if (err) { + deactivate_locked_super(sb); + return ERR_PTR(err); + } + + sb->s_flags |= MS_ACTIVE; + /* User space would break if executables appear on proc */ + sb->s_iflags |= SB_I_NOEXEC; } - return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super); + return dget(sb->s_root); } static void proc_kill_sb(struct super_block *sb) diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index 08f30a46726f..9d13f24a33d4 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -215,6 +215,7 @@ struct hdcp_register_data { int hdcp_library_register(struct hdcp_register_data *data); void hdcp_library_deregister(void *phdcpcontext); bool hdcp1_check_if_supported_load_app(void); +void hdcp1_unload_app(void); int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb); int hdcp1_set_enc(bool enable); #endif /* __HDCP_QSEECOM_H */ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index d32e7b8c0b87..29dedd4eb1b1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -497,8 +497,8 @@ struct perf_addr_filters_head { * enum perf_event_active_state - the states of a event */ enum perf_event_active_state { - PERF_EVENT_STATE_DEAD = -5, - PERF_EVENT_STATE_ZOMBIE = -4, + PERF_EVENT_STATE_DORMANT = -5, + PERF_EVENT_STATE_DEAD = -4, PERF_EVENT_STATE_EXIT = -3, PERF_EVENT_STATE_ERROR = -2, PERF_EVENT_STATE_OFF = -1, @@ -721,7 +721,13 @@ struct perf_event { /* Is this event shared with other events */ bool shared; - struct list_head zombie_entry; + + /* + * Entry into the list that holds the events whose CPUs + * are offline. These events will be installed once the + * CPU wakes up and will be removed from the list after that + */ + struct list_head dormant_event_entry; #endif /* CONFIG_PERF_EVENTS */ }; @@ -1401,9 +1407,11 @@ static struct device_attribute format_attr_##_name = __ATTR_RO(_name) #ifdef CONFIG_PERF_EVENTS int perf_event_init_cpu(unsigned int cpu); int perf_event_exit_cpu(unsigned int cpu); +int perf_event_restart_events(unsigned int cpu); #else #define perf_event_init_cpu NULL #define perf_event_exit_cpu NULL +#define perf_event_restart_events NULL #endif #endif /* _LINUX_PERF_EVENT_H */ diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 7ef3db418100..0732a6fd33d1 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -144,4 +144,5 @@ extern bool icnss_is_fw_ready(void); extern bool icnss_is_fw_down(void); extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); +extern void icnss_block_shutdown(bool status); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index db433542860b..e69fe7ab5f96 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -163,7 +163,8 @@ struct cam_iommu_handle { #define CAM_FORMAT_PLAIN8_10_SWAP 43 #define CAM_FORMAT_YV12 44 #define CAM_FORMAT_Y_ONLY 45 -#define CAM_FORMAT_MAX 46 +#define CAM_FORMAT_DPCM_12_10_12 46 +#define CAM_FORMAT_MAX 47 /* camera rotaion */ #define CAM_ROTATE_CW_0_DEGREE 0 diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 2344b223ec0d..91360e240b49 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -89,6 +89,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 #define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 #define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 +#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 /* Query devices */ /** @@ -386,6 +387,44 @@ struct cam_isp_bw_config { struct cam_isp_bw_vote rdi_vote[1]; } __attribute__((packed)); +/** + * struct cam_fe_config - Fetch Engine configuration + * + * @version: fetch engine veriosn + * @min_vbi: require min vbi + * @fs_mode: indicates if fs mode enabled + * @fs_line_sync_en: frame level sync or line level + * sync for fetch engine + * @hbi_count: hbi count + * @fs_sync_enable: indicates if fetch engine working + * wokring in sync with write engine + * @go_cmd_sel: softwrae go_cmd or hw go_cmd + * @client_enable: enable read engine + * @source_addr: adrress of buffer to read from + * @width: buffer width + * @height: buffer height + * @stride: buffer stride (here equal to width) + * @format: format of image in buffer + * @unpacker_cfg: unpacker config type + * @latency_buf_size: latency buffer for read engine + */ +struct cam_fe_config { + uint64_t version; + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t fs_line_sync_en; + uint32_t hbi_count; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; + uint32_t client_enable; + uint32_t source_addr; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t unpacker_cfg; + uint32_t latency_buf_size; +} __attribute__((packed)); /* Acquire Device/HW v2 */ diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h index b806befa2bed..7e9ba62c507f 100644 --- a/include/uapi/media/cam_isp_ife.h +++ b/include/uapi/media/cam_isp_ife.h @@ -27,7 +27,8 @@ #define CAM_ISP_IFE_OUT_RES_DS4_DISP (CAM_ISP_IFE_OUT_RES_BASE + 20) #define CAM_ISP_IFE_OUT_RES_DS16_DISP (CAM_ISP_IFE_OUT_RES_BASE + 21) #define CAM_ISP_IFE_OUT_RES_2PD (CAM_ISP_IFE_OUT_RES_BASE + 22) -#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 23) +#define CAM_ISP_IFE_OUT_RES_RDI_RD (CAM_ISP_IFE_OUT_RES_BASE + 23) +#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 24) /*IFE input port resource type (global unique) */ #define CAM_ISP_IFE_IN_RES_BASE 0x4000 @@ -37,6 +38,7 @@ #define CAM_ISP_IFE_IN_RES_PHY_1 (CAM_ISP_IFE_IN_RES_BASE + 2) #define CAM_ISP_IFE_IN_RES_PHY_2 (CAM_ISP_IFE_IN_RES_BASE + 3) #define CAM_ISP_IFE_IN_RES_PHY_3 (CAM_ISP_IFE_IN_RES_BASE + 4) -#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_RD (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 6) #endif /* __UAPI_CAM_ISP_IFE_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 0b4f1cc40df3..b903078dccbd 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -383,10 +383,12 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_DEVICE: Device error message, fatal to session * @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal + * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 +#define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 /** * struct cam_req_mgr_error_msg diff --git a/kernel/cpu.c b/kernel/cpu.c index aa035154bb72..df007c474778 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1463,7 +1463,7 @@ static struct cpuhp_step cpuhp_ap_states[] = { }, [CPUHP_AP_PERF_ONLINE] = { .name = "perf:online", - .startup.single = perf_event_init_cpu, + .startup.single = perf_event_restart_events, .teardown.single = perf_event_exit_cpu, }, [CPUHP_AP_WORKQUEUE_ONLINE] = { diff --git a/kernel/events/core.c b/kernel/events/core.c index 6be8ea2fb116..8dd675001654 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2315,6 +2315,23 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, perf_pmu_enable(cpuctx->ctx.pmu); } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static LIST_HEAD(dormant_event_list); +static DEFINE_SPINLOCK(dormant_event_list_lock); + +static void perf_prepare_install_in_context(struct perf_event *event) +{ + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) + goto out; + + event->state = PERF_EVENT_STATE_DORMANT; + list_add_tail(&event->dormant_event_entry, &dormant_event_list); +out: + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Cross CPU call to install and enable a performance event * @@ -2460,6 +2477,34 @@ again: raw_spin_unlock_irq(&ctx->lock); } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static void perf_deferred_install_in_context(int cpu) +{ + struct perf_event *event, *tmp; + struct perf_event_context *ctx; + + spin_lock(&dormant_event_list_lock); + list_for_each_entry_safe(event, tmp, &dormant_event_list, + dormant_event_entry) { + if (cpu != event->cpu) + continue; + + list_del(&event->dormant_event_entry); + event->state = PERF_EVENT_STATE_INACTIVE; + spin_unlock(&dormant_event_list_lock); + + ctx = event->ctx; + + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, event, cpu); + mutex_unlock(&ctx->mutex); + + spin_lock(&dormant_event_list_lock); + } + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Put a event into inactive state and update time fields. * Enabling the leader of a group effectively enables all @@ -4277,14 +4322,6 @@ static void put_event(struct perf_event *event) } /* - * Maintain a zombie list to collect all the zombie events - */ -#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE -static LIST_HEAD(zombie_list); -static DEFINE_SPINLOCK(zombie_list_lock); -#endif - -/* * Kill an event dead; while event:refcount will preserve the event * object, it will not preserve its functionality. Once the last 'user' * gives up the object, we'll destroy the thing. @@ -4294,23 +4331,12 @@ static int __perf_event_release_kernel(struct perf_event *event) struct perf_event_context *ctx = event->ctx; struct perf_event *child, *tmp; - /* - * If the cpu associated to this event is offline, set the event as a - * zombie event. The cleanup of the cpu would be done if the CPU is - * back online. - */ #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE - if (event->cpu != -1 && per_cpu(is_hotplugging, event->cpu)) { - if (event->state == PERF_EVENT_STATE_ZOMBIE) - return 0; - - event->state = PERF_EVENT_STATE_ZOMBIE; - - spin_lock(&zombie_list_lock); - list_add_tail(&event->zombie_entry, &zombie_list); - spin_unlock(&zombie_list_lock); - - return 0; + if (event->cpu != -1) { + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) + list_del(&event->dormant_event_entry); + spin_unlock(&dormant_event_list_lock); } #endif @@ -4627,6 +4653,15 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct perf_event_context *ctx; int ret; +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) { + spin_unlock(&dormant_event_list_lock); + return 0; + } + spin_unlock(&dormant_event_list_lock); +#endif + ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -9455,13 +9490,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, mutex_init(&event->child_mutex); INIT_LIST_HEAD(&event->child_list); + INIT_LIST_HEAD(&event->dormant_event_entry); INIT_LIST_HEAD(&event->group_entry); INIT_LIST_HEAD(&event->event_entry); INIT_LIST_HEAD(&event->sibling_list); INIT_LIST_HEAD(&event->rb_entry); INIT_LIST_HEAD(&event->active_entry); INIT_LIST_HEAD(&event->addr_filters.list); - INIT_LIST_HEAD(&event->zombie_entry); INIT_HLIST_NODE(&event->hlist_entry); @@ -11114,111 +11149,27 @@ int perf_event_init_cpu(unsigned int cpu) } #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE -static void -check_hotplug_start_event(struct perf_event *event) -{ - if (event->pmu->events_across_hotplug && - event->attr.type == PERF_TYPE_SOFTWARE && - event->pmu->start) - event->pmu->start(event, 0); -} - -static void perf_event_zombie_cleanup(unsigned int cpu) +int perf_event_restart_events(unsigned int cpu) { - struct perf_event *event, *tmp; - - spin_lock(&zombie_list_lock); - - list_for_each_entry_safe(event, tmp, &zombie_list, zombie_entry) { - if (event->cpu != cpu) - continue; - - list_del(&event->zombie_entry); - spin_unlock(&zombie_list_lock); - - /* - * The detachment of the event with the - * PMU expects it to be in an active state - */ - event->state = PERF_EVENT_STATE_ACTIVE; - __perf_event_release_kernel(event); - - spin_lock(&zombie_list_lock); - } - - spin_unlock(&zombie_list_lock); -} - -static int perf_event_start_swevents(unsigned int cpu) -{ - struct perf_event_context *ctx; - struct pmu *pmu; - struct perf_event *event; - int idx; - mutex_lock(&pmus_lock); - perf_event_zombie_cleanup(cpu); - - idx = srcu_read_lock(&pmus_srcu); - list_for_each_entry_rcu(pmu, &pmus, entry) { - ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; - mutex_lock(&ctx->mutex); - raw_spin_lock(&ctx->lock); - list_for_each_entry(event, &ctx->event_list, event_entry) - check_hotplug_start_event(event); - raw_spin_unlock(&ctx->lock); - mutex_unlock(&ctx->mutex); - } - srcu_read_unlock(&pmus_srcu, idx); per_cpu(is_hotplugging, cpu) = false; + perf_deferred_install_in_context(cpu); mutex_unlock(&pmus_lock); return 0; } -/* - * If keeping events across hotplugging is supported, do not - * remove the event list so event lives beyond CPU hotplug. - * The context is exited via an fd close path when userspace - * is done and the target CPU is online. If software clock - * event is active, then stop hrtimer associated with it. - * Start the timer when the CPU comes back online. - */ -static void -check_hotplug_remove_from_context(struct perf_event *event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - if (event->pmu->events_across_hotplug && - event->attr.type == PERF_TYPE_SOFTWARE && - event->pmu->stop) - event->pmu->stop(event, PERF_EF_UPDATE); - else if (!event->pmu->events_across_hotplug) - __perf_remove_from_context(event, cpuctx, - ctx, (void *)DETACH_GROUP); -} - -static void __perf_event_exit_context(void *__info) -{ - struct perf_event_context *ctx = __info; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - struct perf_event *event; - - raw_spin_lock(&ctx->lock); - list_for_each_entry(event, &ctx->event_list, event_entry) - check_hotplug_remove_from_context(event, cpuctx, ctx); - raw_spin_unlock(&ctx->lock); -} - static void perf_event_exit_cpu_context(int cpu) { struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; unsigned long flags; + struct perf_event *event, *event_tmp; struct pmu *pmu; int idx; idx = srcu_read_lock(&pmus_srcu); + per_cpu(is_hotplugging, cpu) = true; list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; @@ -11233,7 +11184,12 @@ static void perf_event_exit_cpu_context(int cpu) } mutex_lock(&ctx->mutex); - smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1); + list_for_each_entry_safe(event, event_tmp, &ctx->event_list, + event_entry) { + perf_remove_from_context(event, DETACH_GROUP); + if (event->pmu->events_across_hotplug) + perf_prepare_install_in_context(event); + } mutex_unlock(&ctx->mutex); } srcu_read_unlock(&pmus_srcu, idx); @@ -11246,8 +11202,8 @@ static void perf_event_exit_cpu_context(int cpu) { } int perf_event_exit_cpu(unsigned int cpu) { + mutex_lock(&pmus_lock); - per_cpu(is_hotplugging, cpu) = true; perf_event_exit_cpu_context(cpu); mutex_unlock(&pmus_lock); return 0; @@ -11292,25 +11248,6 @@ static struct notifier_block perf_event_idle_nb = { .notifier_call = event_idle_notif, }; -#ifdef CONFIG_HOTPLUG_CPU -static int perf_cpu_hp_init(void) -{ - int ret; - - ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, - "PERF/CORE/CPUHP_AP_PERF_ONLINE", - perf_event_start_swevents, - perf_event_exit_cpu); - if (ret) - pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", - ret); - - return ret; -} -#else -static int perf_cpu_hp_init(void) { return 0; } -#endif - void __init perf_event_init(void) { int ret, cpu; @@ -11337,8 +11274,6 @@ void __init perf_event_init(void) perf_event_init_cpu(smp_processor_id()); idle_notifier_register(&perf_event_idle_nb); register_reboot_notifier(&perf_reboot_notifier); - ret = perf_cpu_hp_init(); - WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret); ret = init_hw_breakpoint(); WARN(ret, "hw_breakpoint initialization failed with: %d", ret); diff --git a/mm/memory.c b/mm/memory.c index ccf1a6b9f7e1..b8f1279e3728 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1971,7 +1971,7 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr, unsigned long end = addr + size; int err; - if (WARN_ON(addr >= end)) + if (WARN_ON(addr >= end - 1)) return -EINVAL; pgd = pgd_offset(mm, addr); diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 7c1b14868313..8e471bec64c8 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -25,20 +25,20 @@ country AE: DFS-ETSI country AF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -49,8 +49,8 @@ country AM: DFS-ETSI country AN: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -73,8 +73,8 @@ country AS: DFS-FCC country AT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -92,8 +92,8 @@ country AU: DFS-FCC country AW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AZ: DFS-ETSI @@ -103,8 +103,8 @@ country AZ: DFS-ETSI country BA: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -120,8 +120,8 @@ country BD: country BE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -136,8 +136,8 @@ country BF: DFS-FCC country BG: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -150,8 +150,8 @@ country BH: country BL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BM: DFS-FCC @@ -192,14 +192,14 @@ country BS: DFS-FCC country BT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BY: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BZ: @@ -226,8 +226,8 @@ country CF: DFS-FCC country CH: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -280,8 +280,8 @@ country CX: DFS-FCC country CY: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -291,8 +291,8 @@ country CY: DFS-ETSI # and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf country CZ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -306,8 +306,8 @@ country CZ: DFS-ETSI country DE: DFS-ETSI # entries 279004 and 280006 (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -315,8 +315,8 @@ country DE: DFS-ETSI country DK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -351,8 +351,8 @@ country EC: DFS-FCC country EE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -365,8 +365,8 @@ country EG: DFS-ETSI country ES: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -374,14 +374,14 @@ country ES: DFS-ETSI country ET: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country FI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -396,8 +396,8 @@ country FM: DFS-FCC country FR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -405,8 +405,8 @@ country FR: DFS-ETSI country GB: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -426,8 +426,8 @@ country GE: DFS-ETSI country GF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -440,26 +440,26 @@ country GH: DFS-FCC country GI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GP: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -467,8 +467,8 @@ country GR: DFS-ETSI country GT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GU: DFS-FCC @@ -503,8 +503,8 @@ country HN: country HR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -519,8 +519,8 @@ country HT: DFS-FCC country HU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -533,8 +533,8 @@ country ID: country IE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -547,21 +547,23 @@ country IL: DFS-ETSI # 60 gHz band channels 1-4, base on Etsi En 302 567 (57000 - 66000 @ 2160), (40) -country IN: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (23) - (5735 - 5835 @ 80), (33) +country IN: DFS-ETSI + (2402 - 2482 @ 40), (30) + (5170 - 5250 @ 80), (30), AUTO-BW + (5250 - 5330 @ 80), (24), DFS, AUTO-BW + (5490 - 5730 @ 160), (24), DFS + (5735 - 5875 @ 80), (30) country IQ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country IS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -569,8 +571,8 @@ country IS: DFS-ETSI country IT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -593,10 +595,10 @@ country JO: (57000 - 66000 @ 2160), (40) country JP: DFS-JP - (2402 - 2482 @ 40), (20) + (2402 - 2482 @ 40), (23) (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR - (5250 - 5330 @ 80), (26), DFS, AUTO-BW, NO-OUTDOOR - (5490 - 5710 @ 160), (26), DFS + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR + (5490 - 5710 @ 160), (23), DFS # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -608,8 +610,8 @@ country KE: DFS-ETSI country KH: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country KN: DFS-FCC @@ -660,8 +662,8 @@ country LC: DFS-FCC country LI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -676,14 +678,14 @@ country LK: DFS-FCC country LS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country LT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -691,8 +693,8 @@ country LT: DFS-ETSI country LU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -700,8 +702,8 @@ country LU: DFS-ETSI country LV: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -716,29 +718,29 @@ country MA: DFS-ETSI country MC: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MD: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country ME: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MH: DFS-FCC @@ -750,8 +752,8 @@ country MH: DFS-FCC country MK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -778,21 +780,21 @@ country MP: DFS-FCC country MQ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -800,8 +802,8 @@ country MT: DFS-ETSI country MU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -813,8 +815,8 @@ country MV: DFS-ETSI country MW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MX: DFS-FCC @@ -858,8 +860,8 @@ country NI: DFS-FCC country NL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -867,8 +869,8 @@ country NL: DFS-ETSI country NO: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -890,8 +892,8 @@ country NZ: DFS-FCC country OM: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country PA: @@ -910,8 +912,8 @@ country PE: DFS-FCC country PF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -937,8 +939,8 @@ country PK: country PL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -946,8 +948,8 @@ country PL: DFS-ETSI country PM: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -967,8 +969,8 @@ country PS: DFS-FCC country PT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -999,14 +1001,14 @@ country QA: DFS-ETSI country RE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country RO: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1016,8 +1018,8 @@ country RO: DFS-ETSI # http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf country RS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1047,8 +1049,8 @@ country SA: DFS-ETSI country SE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1065,8 +1067,8 @@ country SG: DFS-FCC country SI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1074,8 +1076,8 @@ country SI: DFS-ETSI country SK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1089,8 +1091,8 @@ country SN: country SR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country SV: DFS-FCC @@ -1108,14 +1110,14 @@ country TC: DFS-FCC country TD: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country TG: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS + (5170 - 5250 @ 40), (23), NO-OUTDOOR + (5250 - 5330 @ 40), (23), DFS, NO-OUTDOOR (5490 - 5710 @ 40), (30), DFS country TH: DFS-FCC @@ -1134,8 +1136,8 @@ country TN: DFS-ETSI country TR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -1210,8 +1212,8 @@ country UZ: DFS-ETSI country VC: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -1246,14 +1248,14 @@ country VU: DFS-FCC country WF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country WS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS + (5170 - 5250 @ 40), (23), NO-OUTDOOR + (5250 - 5330 @ 40), (23), DFS, NO-OUTDOOR (5490 - 5710 @ 40), (30), DFS country XA: DFS-JP @@ -1268,8 +1270,8 @@ country YE: country YT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country ZA: DFS-FCC @@ -1283,6 +1285,6 @@ country ZA: DFS-FCC country ZW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS |