mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
Merge f627bf94a3 on remote branch
Change-Id: I2ab85c61ae88c640e8dce588ae234c707580b89e
This commit is contained in:
commit
3a6bc9783a
99 changed files with 3078 additions and 860 deletions
|
|
@ -1 +1 @@
|
|||
LTS_5.4.86_7d99cf8c84a7
|
||||
LTS_5.4.86_fe9e8630bfaf
|
||||
|
|
|
|||
|
|
@ -3967,6 +3967,7 @@
|
|||
<elf-symbol name='spi_bus_lock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x1001acda'/>
|
||||
<elf-symbol name='spi_bus_unlock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x4861f1cc'/>
|
||||
<elf-symbol name='spi_busnum_to_master' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x40920415'/>
|
||||
<elf-symbol name='spi_set_cs_timing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0xe80f6172'/>
|
||||
<elf-symbol name='spi_controller_resume' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x3b6b9b70'/>
|
||||
<elf-symbol name='spi_controller_suspend' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x9e6ee413'/>
|
||||
<elf-symbol name='spi_finalize_current_message' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes' crc='0x71c101fd'/>
|
||||
|
|
@ -128457,6 +128458,13 @@
|
|||
<parameter type-id='f22e4524' name='ctlr' filepath='drivers/spi/spi.c' line='2705' column='1'/>
|
||||
<return type-id='95e97e5e'/>
|
||||
</function-decl>
|
||||
<function-decl name='spi_set_cs_timing' mangled-name='spi_set_cs_timing' filepath='drivers/spi/spi.c' line='3225' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='spi_set_cs_timing'>
|
||||
<parameter type-id='e90f4666' name='spi' filepath='drivers/spi/spi.c' line='3225' column='1'/>
|
||||
<parameter type-id='f9b06939' name='setup' filepath='drivers/spi/spi.c' line='3225' column='1'/>
|
||||
<parameter type-id='f9b06939' name='hold' filepath='drivers/spi/spi.c' line='3225' column='1'/>
|
||||
<parameter type-id='f9b06939' name='inactive_dly' filepath='drivers/spi/spi.c' line='3226' column='1'/>
|
||||
<return type-id='48b5725f'/>
|
||||
</function-decl>
|
||||
<function-decl name='spi_busnum_to_master' mangled-name='spi_busnum_to_master' filepath='drivers/spi/spi.c' line='2741' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='spi_busnum_to_master'>
|
||||
<parameter type-id='1dc6a898' name='bus_num' filepath='drivers/spi/spi.c' line='2741' column='1'/>
|
||||
<return type-id='f22e4524'/>
|
||||
|
|
|
|||
|
|
@ -94598,6 +94598,12 @@
|
|||
<parameter type-id='fa0b179b'/>
|
||||
<return type-id='48b5725f'/>
|
||||
</function-decl>
|
||||
<function-decl name='strscpy' mangled-name='strscpy' filepath='include/linux/string.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='strscpy'>
|
||||
<parameter type-id='26a90f95'/>
|
||||
<parameter type-id='80f4b756'/>
|
||||
<parameter type-id='7359adad'/>
|
||||
<return type-id='bd54fe1a'/>
|
||||
</function-decl>
|
||||
<function-decl name='msleep' mangled-name='msleep' filepath='include/linux/delay.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='msleep'>
|
||||
<parameter type-id='f0981eeb'/>
|
||||
<return type-id='48b5725f'/>
|
||||
|
|
@ -128690,15 +128696,15 @@
|
|||
<parameter type-id='1ce53783'/>
|
||||
<return type-id='c894953d'/>
|
||||
</function-decl>
|
||||
<function-decl name='sched_setscheduler' mangled-name='sched_setscheduler' filepath='kernel/sched/core.c' line='5319' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sched_setscheduler'>
|
||||
<parameter type-id='f23e2572' name='p' filepath='kernel/sched/core.c' line='5319' column='1'/>
|
||||
<parameter type-id='95e97e5e' name='policy' filepath='kernel/sched/core.c' line='5319' column='1'/>
|
||||
<parameter type-id='36fca399' name='param' filepath='kernel/sched/core.c' line='5320' column='1'/>
|
||||
<function-decl name='sched_setscheduler' mangled-name='sched_setscheduler' filepath='kernel/sched/core.c' line='5322' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sched_setscheduler'>
|
||||
<parameter type-id='f23e2572' name='p' filepath='kernel/sched/core.c' line='5322' column='1'/>
|
||||
<parameter type-id='95e97e5e' name='policy' filepath='kernel/sched/core.c' line='5322' column='1'/>
|
||||
<parameter type-id='36fca399' name='param' filepath='kernel/sched/core.c' line='5323' column='1'/>
|
||||
<return type-id='95e97e5e'/>
|
||||
</function-decl>
|
||||
<function-decl name='sched_setattr' mangled-name='sched_setattr' filepath='kernel/sched/core.c' line='5326' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sched_setattr'>
|
||||
<parameter type-id='f23e2572' name='p' filepath='kernel/sched/core.c' line='5326' column='1'/>
|
||||
<parameter type-id='8abbb6c3' name='attr' filepath='kernel/sched/core.c' line='5326' column='1'/>
|
||||
<function-decl name='sched_setattr' mangled-name='sched_setattr' filepath='kernel/sched/core.c' line='5329' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sched_setattr'>
|
||||
<parameter type-id='f23e2572' name='p' filepath='kernel/sched/core.c' line='5329' column='1'/>
|
||||
<parameter type-id='8abbb6c3' name='attr' filepath='kernel/sched/core.c' line='5329' column='1'/>
|
||||
<return type-id='95e97e5e'/>
|
||||
</function-decl>
|
||||
<function-decl name='strnstr' mangled-name='strnstr' filepath='include/linux/string.h' line='84' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='strnstr'>
|
||||
|
|
@ -130490,12 +130496,6 @@
|
|||
<parameter type-id='83c1bde6' name='work' filepath='kernel/workqueue.c' line='4553' column='1'/>
|
||||
<return type-id='f0981eeb'/>
|
||||
</function-decl>
|
||||
<function-decl name='strscpy' mangled-name='strscpy' filepath='include/linux/string.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='strscpy'>
|
||||
<parameter type-id='26a90f95'/>
|
||||
<parameter type-id='80f4b756'/>
|
||||
<parameter type-id='7359adad'/>
|
||||
<return type-id='bd54fe1a'/>
|
||||
</function-decl>
|
||||
<function-decl name='ida_alloc_range' mangled-name='ida_alloc_range' filepath='include/linux/idr.h' line='255' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='ida_alloc_range'>
|
||||
<parameter type-id='a9e764bb'/>
|
||||
<parameter type-id='f0981eeb'/>
|
||||
|
|
@ -1598,6 +1598,7 @@
|
|||
uart_update_timeout
|
||||
uart_write_wakeup
|
||||
__udelay
|
||||
ufshcd_config_pwr_mode
|
||||
ufshcd_dme_get_attr
|
||||
ufshcd_dme_set_attr
|
||||
ufshcd_pltfrm_init
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@
|
|||
remove_proc_subtree
|
||||
request_firmware
|
||||
rtc_time64_to_tm
|
||||
spi_set_cs_timing
|
||||
spi_sync
|
||||
strcat
|
||||
system_wq
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@
|
|||
regcache_drop_region
|
||||
snd_soc_dapm_del_routes
|
||||
|
||||
# required by us_prox.ko
|
||||
iio_device_unregister
|
||||
iio_device_free
|
||||
__iio_device_register
|
||||
__kfifo_to_user
|
||||
iio_device_alloc
|
||||
|
||||
# required by tfa98xx_dlkm.ko
|
||||
device_remove_bin_file
|
||||
snd_pcm_hw_constraint_mask64
|
||||
|
|
@ -32,15 +39,21 @@
|
|||
|
||||
# required by msm_drm.ko
|
||||
kobject_set_name
|
||||
wakeup_source_destroy
|
||||
wakeup_source_remove
|
||||
wakeup_source_add
|
||||
wakeup_source_create
|
||||
|
||||
# required by exfat.ko
|
||||
block_write_full_page
|
||||
__blockdev_direct_IO
|
||||
__bread_gfp
|
||||
__brelse
|
||||
clear_nlink
|
||||
cont_write_begin
|
||||
d_find_alias
|
||||
d_move
|
||||
d_splice_alias
|
||||
filemap_fdatawait_range
|
||||
filemap_fdatawrite_range
|
||||
full_name_hash
|
||||
|
|
@ -53,6 +66,7 @@
|
|||
generic_fillattr
|
||||
generic_write_end
|
||||
__getblk_gfp
|
||||
igrab
|
||||
ilookup
|
||||
in_group_p
|
||||
inc_nlink
|
||||
|
|
@ -76,14 +90,20 @@
|
|||
sb_min_blocksize
|
||||
sb_set_blocksize
|
||||
setattr_copy
|
||||
setattr_prepare
|
||||
set_nlink
|
||||
sync_blockdev
|
||||
sync_dirty_buffer
|
||||
sync_mapping_buffers
|
||||
__remove_inode_hash
|
||||
touch_buffer
|
||||
truncate_pagecache
|
||||
truncate_setsize
|
||||
unload_nls
|
||||
unlock_buffer
|
||||
utf16s_to_utf8s
|
||||
utf8s_to_utf16s
|
||||
write_inode_now
|
||||
|
||||
# required by incrementalfs.ko
|
||||
revert_creds
|
||||
|
|
|
|||
7
arch/arm/configs/vendor/sdxlemur.config
vendored
7
arch/arm/configs/vendor/sdxlemur.config
vendored
|
|
@ -342,6 +342,8 @@ CONFIG_QCOM_EUD=y
|
|||
CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE=y
|
||||
CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT=y
|
||||
CONFIG_POWER_RESET_QCOM_REBOOT_REASON=y
|
||||
CONFIG_POWER_RESET_MSM=y
|
||||
CONFIG_QCOM_MINIDUMP=y
|
||||
CONFIG_ENABLE_SFE=y
|
||||
# CONFIG_ENABLE_VMALLOC_SAVING is not set
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
|
|
@ -355,9 +357,6 @@ CONFIG_IOSS=m
|
|||
CONFIG_AQFWD_IOSS=m
|
||||
CONFIG_R8125=y
|
||||
CONFIG_R8125_IOSS=m
|
||||
CONFIG_IPA_ETH=y
|
||||
CONFIG_IPA_ETH_DEBUG=y
|
||||
# CONFIG_IPA_ETH_NOAUTO is not set
|
||||
CONFIG_QCOM_SHOW_RESUME_IRQ=y
|
||||
CONFIG_HARDENED_USERCOPY=y
|
||||
# CONFIG_HARDENED_USERCOPY_FALLBACK is not set
|
||||
|
|
@ -371,3 +370,5 @@ CONFIG_QPS615=m
|
|||
# CONFIG_BLK_CGROUP is not set
|
||||
# CONFIG_BLK_DEBUG_FS is not set
|
||||
# CONFIG_VT is not set
|
||||
CONFIG_DRM=y
|
||||
CONFIG_GKI_HIDDEN_DRM_CONFIGS=y
|
||||
|
|
|
|||
|
|
@ -32,12 +32,6 @@
|
|||
#endif
|
||||
#include <linux/fs.h>
|
||||
|
||||
#define PWR_SRC_STATUS_SET(index, status) do { \
|
||||
if (index >= PWR_SRC_INIT_STATE_IDX && index < BT_POWER_SRC_SIZE) { \
|
||||
bt_power_src_status[index] = (int) status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PWR_SRC_NOT_AVAILABLE -2
|
||||
#define DEFAULT_INVALID_VALUE -1
|
||||
#define PWR_SRC_INIT_STATE_IDX 0
|
||||
|
|
@ -76,9 +70,24 @@ enum power_src_pos {
|
|||
BT_VDD_RFA_0p8_CURRENT,
|
||||
BT_VDD_RFACMN_CURRENT,
|
||||
BT_VDD_IPA_2p2,
|
||||
BT_VDD_IPA_2p2_CURRENT
|
||||
BT_VDD_IPA_2p2_CURRENT,
|
||||
/* The below bucks are voted for HW WAR on some platform which supports
|
||||
* WNC39xx.
|
||||
*/
|
||||
BT_VDD_SMPS,
|
||||
BT_VDD_SMPS_CURRENT,
|
||||
/* New entries need to be added before PWR_SRC_SIZE.
|
||||
* Its hold the max size of power sources states.
|
||||
*/
|
||||
BT_POWER_SRC_SIZE,
|
||||
};
|
||||
|
||||
#define PWR_SRC_STATUS_SET(index, status) do { \
|
||||
if (index >= PWR_SRC_INIT_STATE_IDX && index < BT_POWER_SRC_SIZE) { \
|
||||
bt_power_src_status[index] = (int) status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Regulator structure for QCA6174/QCA9377/QCA9379 BT SoC series
|
||||
static struct bt_power_vreg_data bt_vregs_info_qca61x4_937x[] = {
|
||||
{NULL, "qcom,bt-vdd-aon", 928000, 928000, 0, false, false,
|
||||
|
|
@ -116,6 +125,8 @@ static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = {
|
|||
static struct bt_power bt_vreg_info_wcn399x = {
|
||||
.compatible = "qcom,wcn3990",
|
||||
.vregs = (struct bt_power_vreg_data []) {
|
||||
{NULL, "qcom,bt-vdd-smps", 984000, 984000, 0, false, false,
|
||||
{BT_VDD_SMPS, BT_VDD_SMPS_CURRENT}},
|
||||
{NULL, "qcom,bt-vdd-io", 1700000, 1900000, 0, false, false,
|
||||
{BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}},
|
||||
{NULL, "qcom,bt-vdd-core", 1304000, 1304000, 0, false, false,
|
||||
|
|
@ -125,7 +136,7 @@ static struct bt_power bt_vreg_info_wcn399x = {
|
|||
{NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false,
|
||||
{BT_VDD_XTAL_LDO, BT_VDD_XTAL_LDO_CURRENT}},
|
||||
},
|
||||
.num_vregs = 4,
|
||||
.num_vregs = 5,
|
||||
};
|
||||
|
||||
static struct bt_power bt_vreg_info_qca_auto = {
|
||||
|
|
|
|||
|
|
@ -92,9 +92,12 @@ struct mhi_controller *find_mhi_controller_by_name(const char *name)
|
|||
|
||||
const char *to_mhi_pm_state_str(enum MHI_PM_STATE state)
|
||||
{
|
||||
int index = find_last_bit((unsigned long *)&state, 32);
|
||||
int index;
|
||||
|
||||
if (index >= ARRAY_SIZE(mhi_pm_state_str))
|
||||
if (state)
|
||||
index = __fls(state);
|
||||
|
||||
if (!state || index >= ARRAY_SIZE(mhi_pm_state_str))
|
||||
return "Invalid State";
|
||||
|
||||
return mhi_pm_state_str[index];
|
||||
|
|
|
|||
|
|
@ -1063,8 +1063,8 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl)
|
|||
sfr_info->buf_addr);
|
||||
}
|
||||
|
||||
/* link is not down if device is in RDDM */
|
||||
transition_state = (mhi_cntrl->ee == MHI_EE_RDDM) ?
|
||||
/* link is not down if device supports RDDM */
|
||||
transition_state = (mhi_cntrl->rddm_supported) ?
|
||||
MHI_PM_DEVICE_ERR_DETECT : MHI_PM_LD_ERR_FATAL_DETECT;
|
||||
|
||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||
|
|
|
|||
|
|
@ -2895,7 +2895,12 @@ static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
/* Wait for 2 reference cycles before checking the ACK bit. */
|
||||
udelay(1);
|
||||
regmap_read(pll->clkr.regmap, PLL_MODE(pll), ®val);
|
||||
if (!(regval & ALPHA_PLL_ACK_LATCH)) {
|
||||
if (!(regval & PLL_UPDATE_BYPASS)) {
|
||||
ret = wait_for_pll_update(pll);
|
||||
if (ret)
|
||||
WARN_CLK(&pll->clkr.hw, 1, "PLL Update clear failed\n");
|
||||
return ret;
|
||||
} else if (!(regval & ALPHA_PLL_ACK_LATCH)) {
|
||||
WARN_CLK(&pll->clkr.hw, 1,
|
||||
"PLL latch failed. Output may be unstable!\n");
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -247,7 +247,8 @@ static void qcom_cc_set_critical(struct device *dev, struct qcom_cc *cc)
|
|||
if (i >= cc->num_rclks)
|
||||
continue;
|
||||
|
||||
cc->rclks[i]->flags |= QCOM_CLK_IS_CRITICAL;
|
||||
if (cc->rclks[i])
|
||||
cc->rclks[i]->flags |= QCOM_CLK_IS_CRITICAL;
|
||||
}
|
||||
|
||||
of_property_for_each_u32(dev->of_node, "qcom,critical-devices", prop, p, i) {
|
||||
|
|
@ -265,7 +266,8 @@ static void qcom_cc_set_critical(struct device *dev, struct qcom_cc *cc)
|
|||
if (args.np != dev->of_node || clock_idx >= cc->num_rclks)
|
||||
continue;
|
||||
|
||||
cc->rclks[clock_idx]->flags |= QCOM_CLK_IS_CRITICAL;
|
||||
if (cc->rclks[clock_idx])
|
||||
cc->rclks[clock_idx]->flags |= QCOM_CLK_IS_CRITICAL;
|
||||
of_node_put(args.np);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ static const char *const gcc_debug_mux_parent_names[] = {
|
|||
"gcc_video_xo_clk",
|
||||
"gpu_cc_debug_mux",
|
||||
"mc_cc_debug_mux",
|
||||
"measure_only_cnoc_clk",
|
||||
"measure_only_gcc_camera_ahb_clk",
|
||||
"measure_only_gcc_camera_xo_clk",
|
||||
"measure_only_gcc_cpuss_gnoc_clk",
|
||||
|
|
@ -237,6 +238,12 @@ static const char *const gcc_debug_mux_parent_names[] = {
|
|||
"measure_only_gcc_disp_xo_clk",
|
||||
"measure_only_gcc_gpu_cfg_ahb_clk",
|
||||
"measure_only_gcc_video_ahb_clk",
|
||||
"measure_only_hwkm_ahb_clk",
|
||||
"measure_only_hwkm_km_core_clk",
|
||||
"measure_only_ipa_2x_clk",
|
||||
"measure_only_pka_ahb_clk",
|
||||
"measure_only_pka_core_clk",
|
||||
"measure_only_snoc_clk",
|
||||
};
|
||||
|
||||
static int gcc_debug_mux_sels[] = {
|
||||
|
|
@ -350,6 +357,7 @@ static int gcc_debug_mux_sels[] = {
|
|||
0x3F, /* gcc_video_xo_clk */
|
||||
0xFB, /* gpu_cc_debug_mux */
|
||||
0xAE, /* mc_cc_debug_mux */
|
||||
0x1D, /* measure_only_cnoc_clk */
|
||||
0x38, /* measure_only_gcc_camera_ahb_clk */
|
||||
0x40, /* measure_only_gcc_camera_xo_clk */
|
||||
0xBA, /* measure_only_gcc_cpuss_gnoc_clk */
|
||||
|
|
@ -357,6 +365,12 @@ static int gcc_debug_mux_sels[] = {
|
|||
0x41, /* measure_only_gcc_disp_xo_clk */
|
||||
0xF9, /* measure_only_gcc_gpu_cfg_ahb_clk */
|
||||
0x37, /* measure_only_gcc_video_ahb_clk */
|
||||
0x166, /* measure_only_hwkm_ahb_clk */
|
||||
0x167, /* measure_only_hwkm_km_core_clk */
|
||||
0xD7, /* measure_only_ipa_2x_clk */
|
||||
0x162, /* measure_only_pka_ahb_clk */
|
||||
0x163, /* measure_only_pka_core_clk */
|
||||
0x7, /* measure_only_snoc_clk */
|
||||
};
|
||||
|
||||
static struct clk_debug_mux gcc_debug_mux = {
|
||||
|
|
@ -450,6 +464,14 @@ static struct mux_regmap_names mux_list[] = {
|
|||
{ .mux = &mc_cc_debug_mux, .regmap_name = "qcom,mccc" },
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_cnoc_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_cnoc_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_mccc_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
|
|
@ -530,6 +552,54 @@ static struct clk_dummy measure_only_gcc_video_ahb_clk = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_hwkm_ahb_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_hwkm_ahb_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_hwkm_km_core_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_hwkm_km_core_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_ipa_2x_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_ipa_2x_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_pka_ahb_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_pka_ahb_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_pka_core_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_pka_core_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy measure_only_snoc_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "measure_only_snoc_clk",
|
||||
.ops = &clk_dummy_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_dummy perfcl_clk = {
|
||||
.rrate = 1000,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
|
|
@ -555,6 +625,7 @@ static struct clk_dummy l3_clk = {
|
|||
};
|
||||
|
||||
static struct clk_hw *debugcc_blair_hws[] = {
|
||||
&measure_only_cnoc_clk.hw,
|
||||
&measure_only_disp_cc_sleep_clk.hw,
|
||||
&measure_only_disp_cc_xo_clk.hw,
|
||||
&measure_only_gcc_camera_ahb_clk.hw,
|
||||
|
|
@ -564,7 +635,13 @@ static struct clk_hw *debugcc_blair_hws[] = {
|
|||
&measure_only_gcc_disp_xo_clk.hw,
|
||||
&measure_only_gcc_gpu_cfg_ahb_clk.hw,
|
||||
&measure_only_gcc_video_ahb_clk.hw,
|
||||
&measure_only_ipa_2x_clk.hw,
|
||||
&measure_only_mccc_clk.hw,
|
||||
&measure_only_snoc_clk.hw,
|
||||
&measure_only_hwkm_km_core_clk.hw,
|
||||
&measure_only_hwkm_ahb_clk.hw,
|
||||
&measure_only_pka_core_clk.hw,
|
||||
&measure_only_pka_ahb_clk.hw,
|
||||
&perfcl_clk.hw,
|
||||
&pwrcl_clk.hw,
|
||||
&l3_clk.hw,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <uapi/linux/sched/types.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -933,9 +934,15 @@ static struct kgsl_process_private *kgsl_process_private_new(
|
|||
/* Search in the process list */
|
||||
list_for_each_entry(private, &kgsl_driver.process_list, list) {
|
||||
if (private->pid == cur_pid) {
|
||||
if (!kgsl_process_private_get(private)) {
|
||||
private = ERR_PTR(-EINVAL);
|
||||
}
|
||||
if (!kgsl_process_private_get(private))
|
||||
/*
|
||||
* This will happen only if refcount is zero
|
||||
* i.e. destroy is triggered but didn't complete
|
||||
* yet. Return -EEXIST to indicate caller that
|
||||
* destroy is pending to allow caller to take
|
||||
* appropriate action.
|
||||
*/
|
||||
private = ERR_PTR(-EEXIST);
|
||||
/*
|
||||
* We need to hold only one reference to the PID for
|
||||
* each process struct to avoid overflowing the
|
||||
|
|
@ -1043,8 +1050,7 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,
|
|||
kgsl_process_private_put(private);
|
||||
}
|
||||
|
||||
|
||||
static struct kgsl_process_private *kgsl_process_private_open(
|
||||
static struct kgsl_process_private *_process_private_open(
|
||||
struct kgsl_device *device)
|
||||
{
|
||||
struct kgsl_process_private *private;
|
||||
|
|
@ -1062,6 +1068,27 @@ done:
|
|||
return private;
|
||||
}
|
||||
|
||||
static struct kgsl_process_private *kgsl_process_private_open(
|
||||
struct kgsl_device *device)
|
||||
{
|
||||
struct kgsl_process_private *private;
|
||||
int i;
|
||||
|
||||
private = _process_private_open(device);
|
||||
|
||||
/*
|
||||
* If we get error and error is -EEXIST that means previous process
|
||||
* private destroy is triggered but didn't complete. Retry creating
|
||||
* process private after sometime to allow previous destroy to complete.
|
||||
*/
|
||||
for (i = 0; (PTR_ERR_OR_ZERO(private) == -EEXIST) && (i < 5); i++) {
|
||||
usleep_range(10, 100);
|
||||
private = _process_private_open(device);
|
||||
}
|
||||
|
||||
return private;
|
||||
}
|
||||
|
||||
int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count)
|
||||
{
|
||||
struct kgsl_process_private *p;
|
||||
|
|
@ -3042,11 +3069,22 @@ void kgsl_get_egl_counts(struct kgsl_mem_entry *entry,
|
|||
}
|
||||
spin_unlock(&kgsl_dmabuf_lock);
|
||||
}
|
||||
|
||||
unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry)
|
||||
{
|
||||
struct kgsl_dma_buf_meta *meta = entry->priv_data;
|
||||
|
||||
return meta ? file_inode(meta->dmabuf->file)->i_ino : 0;
|
||||
}
|
||||
#else
|
||||
void kgsl_get_egl_counts(struct kgsl_mem_entry *entry,
|
||||
int *egl_surface_count, int *egl_image_count)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
|
||||
|
|
|
|||
|
|
@ -453,6 +453,8 @@ void kgsl_mem_entry_destroy(struct kref *kref);
|
|||
void kgsl_get_egl_counts(struct kgsl_mem_entry *entry,
|
||||
int *egl_surface_count, int *egl_image_count);
|
||||
|
||||
unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry);
|
||||
|
||||
struct kgsl_mem_entry * __must_check
|
||||
kgsl_sharedmem_find(struct kgsl_process_private *private, uint64_t gpuaddr);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2002,2008-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2002,2008-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
|
@ -177,6 +177,7 @@ static int print_mem_entry(void *data, void *ptr)
|
|||
struct kgsl_memdesc *m = &entry->memdesc;
|
||||
unsigned int usermem_type = kgsl_memdesc_usermem_type(m);
|
||||
int egl_surface_count = 0, egl_image_count = 0;
|
||||
unsigned long inode_number = 0;
|
||||
|
||||
flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
|
||||
flags[1] = '-';
|
||||
|
|
@ -192,11 +193,13 @@ static int print_mem_entry(void *data, void *ptr)
|
|||
|
||||
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
|
||||
|
||||
if (usermem_type == KGSL_MEM_ENTRY_ION)
|
||||
if (usermem_type == KGSL_MEM_ENTRY_ION) {
|
||||
kgsl_get_egl_counts(entry, &egl_surface_count,
|
||||
&egl_image_count);
|
||||
inode_number = kgsl_get_dmabuf_inode_number(entry);
|
||||
}
|
||||
|
||||
seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16llu %6d %6d",
|
||||
seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16llu %6d %6d %10lu",
|
||||
(uint64_t *)(uintptr_t) m->gpuaddr,
|
||||
/*
|
||||
* Show zero for the useraddr - we can't reliably track
|
||||
|
|
@ -205,7 +208,7 @@ static int print_mem_entry(void *data, void *ptr)
|
|||
0, m->size, entry->id, flags,
|
||||
memtype_str(usermem_type),
|
||||
usage, (m->sgt ? m->sgt->nents : 0), m->size,
|
||||
egl_surface_count, egl_image_count);
|
||||
egl_surface_count, egl_image_count, inode_number);
|
||||
|
||||
if (entry->metadata[0] != 0)
|
||||
seq_printf(s, " %s", entry->metadata);
|
||||
|
|
@ -273,9 +276,9 @@ static void *process_mem_seq_next(struct seq_file *s, void *ptr,
|
|||
static int process_mem_seq_show(struct seq_file *s, void *ptr)
|
||||
{
|
||||
if (ptr == SEQ_START_TOKEN) {
|
||||
seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s\n",
|
||||
seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s %10s\n",
|
||||
"gpuaddr", "useraddr", "size", "id", "flags", "type",
|
||||
"usage", "sglen", "mapsize", "eglsrf", "eglimg");
|
||||
"usage", "sglen", "mapsize", "eglsrf", "eglimg", "inode");
|
||||
return 0;
|
||||
} else
|
||||
return print_mem_entry(s, ptr);
|
||||
|
|
|
|||
|
|
@ -674,7 +674,8 @@ static void etr_pcie_client_cb(struct mhi_dev_client_cb_data *cb_data)
|
|||
byte_cntr_data = cb_data->user_data;
|
||||
if (!byte_cntr_data)
|
||||
return;
|
||||
|
||||
if (tmcdrvdata->pcie_path != TMC_ETR_PCIE_SW_PATH)
|
||||
return;
|
||||
switch (cb_data->ctrl_info) {
|
||||
case MHI_STATE_CONNECTED:
|
||||
if (cb_data->channel == byte_cntr_data->pcie_out_chan) {
|
||||
|
|
|
|||
|
|
@ -1706,8 +1706,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|||
|
||||
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
|
||||
tmc_etr_byte_cntr_start(drvdata->byte_cntr);
|
||||
if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE)
|
||||
etr_pcie_start(drvdata->byte_cntr);
|
||||
|
||||
if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE
|
||||
&& drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -89,6 +90,24 @@
|
|||
#define ADC_APP_SID_MASK 0xf
|
||||
#define ADC7_CONV_TIMEOUT_MS 501
|
||||
|
||||
/* For ADC_PBS on PMIC7 with SW calibration */
|
||||
#define ADC7_SW_CALIB_PBS_CALREF_FLAG 0x57
|
||||
#define ADC7_SW_CALIB_PBS_CALREF_RDY BIT(7)
|
||||
|
||||
#define ADC7_SW_CALIB_PBS_GND_REF_D0 0x58
|
||||
#define ADC7_SW_CALIB_PBS_GND_REF_D1 0x59
|
||||
#define ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D0 0x5a
|
||||
#define ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D1 0x5b
|
||||
#define ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D0 0x5c
|
||||
#define ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D1 0x5d
|
||||
|
||||
/* For ADC_CMN on PMIC7 with SW calibration */
|
||||
#define ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL 0x4e
|
||||
#define ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ BIT(2)
|
||||
#define ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ_MODE BIT(1)
|
||||
#define ADC7_PBUS_WRITE_SYNC_BYPASS BIT(0)
|
||||
|
||||
|
||||
enum adc5_cal_method {
|
||||
ADC5_NO_CAL = 0,
|
||||
ADC5_RATIOMETRIC_CAL,
|
||||
|
|
@ -134,6 +153,8 @@ struct adc5_channel_prop {
|
|||
* @regmap: SPMI ADC5 peripheral register map field.
|
||||
* @dev: SPMI ADC5 device.
|
||||
* @base: base address for the ADC peripheral.
|
||||
* @cmn_base: base address for the ADC_CMN peripheral, needed
|
||||
* for SW calibrated ADC.
|
||||
* @nchannels: number of ADC channels.
|
||||
* @chan_props: array of ADC channel properties.
|
||||
* @iio_chans: array of IIO channels specification.
|
||||
|
|
@ -146,6 +167,7 @@ struct adc5_chip {
|
|||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
u16 base;
|
||||
u16 cmn_base;
|
||||
unsigned int nchannels;
|
||||
struct adc5_channel_prop *chan_props;
|
||||
struct iio_chan_spec *iio_chans;
|
||||
|
|
@ -175,17 +197,50 @@ static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
|
|||
|
||||
static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len)
|
||||
{
|
||||
return regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
|
||||
if (ret)
|
||||
pr_err("adc read to register %#x of length:%d failed, ret=%d\n",
|
||||
offset, len, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len)
|
||||
{
|
||||
return regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
|
||||
if (ret)
|
||||
pr_err("adc write to register %#x of length:%d failed, ret=%d\n",
|
||||
offset, len, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val)
|
||||
{
|
||||
return regmap_update_bits(adc->regmap, adc->base + offset, mask, val);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(adc->regmap, adc->base + offset, mask, val);
|
||||
if (ret)
|
||||
pr_err("adc masked write to register %#x with mask:0x%x failed, ret=%d\n",
|
||||
offset, mask, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc5_cmn_write(struct adc5_chip *adc, u16 offset, u8 *data, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_write(adc->regmap, adc->cmn_base + offset, data, len);
|
||||
if (ret)
|
||||
pr_err("adc_cmn write to register %#x of length:%d failed, ret=%d\n",
|
||||
offset, len, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc5_prescaling_from_dt(u32 num, u32 den)
|
||||
|
|
@ -242,11 +297,11 @@ static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data)
|
|||
int ret;
|
||||
u8 rslt_lsb, rslt_msb;
|
||||
|
||||
ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, sizeof(rslt_lsb));
|
||||
ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, sizeof(rslt_lsb));
|
||||
ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -385,6 +440,52 @@ static int adc7_configure(struct adc5_chip *adc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int adc7_sw_calib_configure(struct adc5_chip *adc,
|
||||
struct adc5_channel_prop *prop)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[5], val = 0;
|
||||
|
||||
/* Read registers 0x42 through 0x46 */
|
||||
ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Digital param selection */
|
||||
adc5_update_dig_param(adc, prop, &buf[0]);
|
||||
|
||||
/* Update fast average sample value */
|
||||
buf[1] &= (u8) ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK;
|
||||
buf[1] |= prop->avg_samples | ADC5_USR_FAST_AVG_CTL_EN;
|
||||
|
||||
/* Select ADC channel */
|
||||
buf[2] = prop->channel;
|
||||
|
||||
/* Select HW settle delay for channel */
|
||||
buf[3] &= (u8) ~ADC5_USR_HW_SETTLE_DELAY_MASK;
|
||||
buf[3] |= prop->hw_settle_time;
|
||||
|
||||
/* Select ADC enable */
|
||||
buf[4] |= ADC5_USR_EN_CTL1_ADC_EN;
|
||||
|
||||
if (!adc->poll_eoc)
|
||||
reinit_completion(&adc->complete);
|
||||
|
||||
ret = adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ | ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ_MODE;
|
||||
|
||||
ret = adc5_cmn_write(adc, ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL, &val, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Select CONV request */
|
||||
val = ADC5_USR_CONV_REQ_REQ;
|
||||
return adc5_write(adc, ADC5_USR_CONV_REQ, &val, 1);
|
||||
}
|
||||
|
||||
static int adc5_do_conversion(struct adc5_chip *adc,
|
||||
struct adc5_channel_prop *prop,
|
||||
struct iio_chan_spec const *chan,
|
||||
|
|
@ -494,6 +595,59 @@ unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define ADC7_SW_CALIB_CONV_TIMEOUT_MS 150
|
||||
static int adc7_sw_calib_do_conversion(struct adc5_chip *adc,
|
||||
struct adc5_channel_prop *prop, u16 *adc_code_volt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long rc;
|
||||
u8 status = 0, val;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
|
||||
ret = adc7_sw_calib_configure(adc, prop);
|
||||
if (ret) {
|
||||
pr_err("ADC configure failed with %d\n", ret);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* No support for polling mode at present*/
|
||||
rc = wait_for_completion_timeout(&adc->complete,
|
||||
msecs_to_jiffies(ADC7_SW_CALIB_CONV_TIMEOUT_MS));
|
||||
if (!rc) {
|
||||
pr_err("Reading ADC channel %s timed out\n",
|
||||
prop->datasheet_name);
|
||||
ret = -ETIMEDOUT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = adc5_read(adc, ADC5_USR_STATUS1, &status, 1);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
if (!(status & ADC5_USR_STATUS1_EOC)) {
|
||||
pr_err("ADC channel %s EOC bit not set, status=%#x\n",
|
||||
prop->datasheet_name, status);
|
||||
ret = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = adc5_read_voltage_data(adc, adc_code_volt);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
val = 0;
|
||||
ret = adc5_write(adc, ADC5_USR_EN_CTL1, &val, 1);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
ret = adc5_cmn_write(adc, ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL, &val, 1);
|
||||
unlock:
|
||||
mutex_unlock(&adc->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t adc5_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct adc5_chip *adc = dev_id;
|
||||
|
|
@ -503,6 +657,21 @@ static irqreturn_t adc5_isr(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct adc5_channel_prop *adc7_get_channel(struct adc5_chip *adc,
|
||||
unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < adc->nchannels; i++) {
|
||||
if (adc->chan_props[i].channel == num)
|
||||
return &adc->chan_props[i];
|
||||
}
|
||||
|
||||
pr_err("Invalid channel %02x\n", num);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int adc5_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
{
|
||||
|
|
@ -609,6 +778,118 @@ static int adc5_read_raw(struct iio_dev *indio_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adc7_calib(struct adc5_chip *adc)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 gnd, vref_1p25, vref_vdd;
|
||||
u8 buf[2];
|
||||
struct adc5_channel_prop *gnd_prop, *vref_1p25_prop, *vref_vdd_prop;
|
||||
|
||||
/* These channels are mandatory, they are used as reference points */
|
||||
gnd_prop = adc7_get_channel(adc, ADC7_REF_GND);
|
||||
if (!gnd_prop) {
|
||||
dev_err(adc->dev, "GND channel not defined for SW calibration\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vref_1p25_prop = adc7_get_channel(adc, ADC7_1P25VREF);
|
||||
if (!vref_1p25_prop) {
|
||||
dev_err(adc->dev, "1.25VREF channel not defined for SW calibration\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vref_vdd_prop = adc7_get_channel(adc, ADC7_VREF_VADC);
|
||||
if (!vref_vdd_prop) {
|
||||
dev_err(adc->dev, "VDD channel not defined for SW calibration\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = adc7_sw_calib_do_conversion(adc, gnd_prop, &gnd);
|
||||
if (ret) {
|
||||
dev_err(adc->dev, "Failed to read GND channel, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adc7_sw_calib_do_conversion(adc, vref_1p25_prop, &vref_1p25);
|
||||
if (ret) {
|
||||
dev_err(adc->dev, "Failed to read 1.25VREF channel, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adc7_sw_calib_do_conversion(adc, vref_vdd_prop, &vref_vdd);
|
||||
if (ret) {
|
||||
dev_err(adc->dev, "Failed to read VDD channel, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf[0] = gnd & 0xff;
|
||||
buf[1] = gnd >> 8;
|
||||
ret = adc5_write(adc, ADC7_SW_CALIB_PBS_GND_REF_D0, buf, sizeof(buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vref_vdd -= gnd;
|
||||
buf[0] = vref_vdd & 0xff;
|
||||
buf[1] = vref_vdd >> 8;
|
||||
ret = adc5_write(adc, ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D0, buf, sizeof(buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vref_1p25 -= gnd;
|
||||
buf[0] = vref_1p25 & 0xff;
|
||||
buf[1] = vref_1p25 >> 8;
|
||||
ret = adc5_write(adc, ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D0, buf, sizeof(buf));
|
||||
|
||||
if (!ret)
|
||||
dev_dbg(adc->dev, "SW calibration done, gnd:0x%x vref_vdd:0x%x vref_1p25:0x%x\n",
|
||||
gnd, vref_vdd, vref_1p25);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc7_sw_calib_conv(struct adc5_chip *adc, struct adc5_channel_prop *prop, int *val)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 adc_code_volt;
|
||||
|
||||
ret = adc7_calib(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adc7_sw_calib_do_conversion(adc, prop, &adc_code_volt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return qcom_adc5_hw_scale(prop->scale_fn_type,
|
||||
&adc5_prescale_ratios[prop->prescale],
|
||||
adc->data,
|
||||
adc_code_volt, val);
|
||||
}
|
||||
|
||||
static int adc7_sw_calib_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
struct adc5_channel_prop *prop;
|
||||
int ret;
|
||||
|
||||
prop = &adc->chan_props[chan->address];
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = adc7_sw_calib_conv(adc, prop, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info adc5_info = {
|
||||
.read_raw = adc5_read_raw,
|
||||
.of_xlate = adc5_of_xlate,
|
||||
|
|
@ -619,6 +900,11 @@ static const struct iio_info adc7_info = {
|
|||
.of_xlate = adc7_of_xlate,
|
||||
};
|
||||
|
||||
static const struct iio_info adc7_sw_calib_info = {
|
||||
.read_raw = adc7_sw_calib_read_raw,
|
||||
.of_xlate = adc5_of_xlate,
|
||||
};
|
||||
|
||||
struct adc5_channels {
|
||||
const char *datasheet_name;
|
||||
unsigned int prescale_index;
|
||||
|
|
@ -711,6 +997,8 @@ static const struct adc5_channels adc7_chans_pmic[ADC5_MAX_CHANNEL] = {
|
|||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC7_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC7_VREF_VADC] = ADC5_CHAN_VOLT("vref_vadc", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC7_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC7_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
|
||||
|
|
@ -904,6 +1192,8 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
|||
|
||||
if (of_property_read_bool(node, "qcom,ratiometric"))
|
||||
prop->cal_method = ADC5_RATIOMETRIC_CAL;
|
||||
else if (of_property_read_bool(node, "qcom,no-cal"))
|
||||
prop->cal_method = ADC5_NO_CAL;
|
||||
else
|
||||
prop->cal_method = ADC5_ABSOLUTE_CAL;
|
||||
|
||||
|
|
@ -980,6 +1270,10 @@ static const struct of_device_id adc5_match_table[] = {
|
|||
.compatible = "qcom,spmi-adc7",
|
||||
.data = &adc7_data_pmic,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,spmi-adc7-sw-calib",
|
||||
.data = &adc7_data_pmic,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,spmi-adc-rev2",
|
||||
.data = &adc5_data_pmic_rev2,
|
||||
|
|
@ -1062,8 +1356,10 @@ static int adc5_probe(struct platform_device *pdev)
|
|||
struct adc5_chip *adc;
|
||||
struct regmap *regmap;
|
||||
const char *irq_name;
|
||||
const __be32 *prop_addr;
|
||||
int ret, irq_eoc;
|
||||
u32 reg;
|
||||
u8 val;
|
||||
|
||||
regmap = dev_get_regmap(dev->parent, NULL);
|
||||
if (!regmap)
|
||||
|
|
@ -1080,13 +1376,32 @@ static int adc5_probe(struct platform_device *pdev)
|
|||
adc = iio_priv(indio_dev);
|
||||
adc->regmap = regmap;
|
||||
adc->dev = dev;
|
||||
adc->base = reg;
|
||||
|
||||
prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
|
||||
if (!prop_addr) {
|
||||
pr_err("invalid IO resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
adc->base = be32_to_cpu(*prop_addr);
|
||||
|
||||
prop_addr = of_get_address(dev->of_node, 1, NULL, NULL);
|
||||
if (!prop_addr)
|
||||
pr_debug("invalid cmn resource\n");
|
||||
else
|
||||
adc->cmn_base = be32_to_cpu(*prop_addr);
|
||||
|
||||
platform_set_drvdata(pdev, adc);
|
||||
|
||||
if (of_device_is_compatible(node, "qcom,spmi-adc7")) {
|
||||
indio_dev->info = &adc7_info;
|
||||
adc->is_pmic7 = true;
|
||||
} else if (of_device_is_compatible(node, "qcom,spmi-adc7-sw-calib")) {
|
||||
if (!adc->cmn_base) {
|
||||
pr_err("ADC_CMN undefined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
indio_dev->info = &adc7_sw_calib_info;
|
||||
adc->is_pmic7 = true;
|
||||
} else {
|
||||
indio_dev->info = &adc5_info;
|
||||
}
|
||||
|
|
@ -1116,6 +1431,17 @@ static int adc5_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(node, "qcom,spmi-adc7-sw-calib")) {
|
||||
ret = adc7_calib(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = ADC7_SW_CALIB_PBS_CALREF_RDY;
|
||||
ret = adc5_write(adc, ADC7_SW_CALIB_PBS_CALREF_FLAG, &val, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->dev.of_node = node;
|
||||
indio_dev->name = pdev->name;
|
||||
|
|
|
|||
|
|
@ -71,8 +71,11 @@
|
|||
#define DRV_SLEW_RATE_MASK GENMASK(2, 0)
|
||||
|
||||
#define HAP_CFG_VMAX_REG 0x48
|
||||
#define VMAX_STEP_MV 50
|
||||
#define VMAX_HV_STEP_MV 50
|
||||
#define VMAX_MV_STEP_MV 32
|
||||
#define MAX_VMAX_MV 11000
|
||||
#define MAX_HV_VMAX_MV 10000
|
||||
#define MAX_MV_VMAX_MV 6000
|
||||
#define CLAMPED_VMAX_MV 5000
|
||||
#define DEFAULT_VMAX_MV 5000
|
||||
|
||||
|
|
@ -175,6 +178,9 @@
|
|||
#define CAL_RC_CLK_MANUAL_VAL 2
|
||||
|
||||
/* These registers are only applicable for PM5100 */
|
||||
#define HAP_CFG_HW_CONFIG_REG 0x0D
|
||||
#define HV_HAP_DRIVER_BIT BIT(1)
|
||||
|
||||
#define HAP_CFG_HPWR_INTF_CTL_REG 0x80
|
||||
#define INTF_CTL_MASK GENMASK(1, 0)
|
||||
#define INTF_CTL_BOB 1
|
||||
|
|
@ -358,6 +364,10 @@ enum pmic_type {
|
|||
PM5100,
|
||||
};
|
||||
|
||||
enum wa_flags {
|
||||
TOGGLE_CAL_RC_CLK = BIT(0),
|
||||
};
|
||||
|
||||
static const char * const src_str[] = {
|
||||
"FIFO",
|
||||
"DIRECT_PLAY",
|
||||
|
|
@ -505,15 +515,18 @@ struct haptics_chip {
|
|||
u32 cfg_addr_base;
|
||||
u32 ptn_addr_base;
|
||||
u32 hbst_addr_base;
|
||||
u32 wa_flags;
|
||||
u8 cfg_revision;
|
||||
u8 ptn_revision;
|
||||
u8 hpwr_intf_ctl;
|
||||
u16 hbst_revision;
|
||||
u16 max_vmax_mv;
|
||||
enum pmic_type pmic_type;
|
||||
bool fifo_empty_irq_en;
|
||||
bool swr_slave_enabled;
|
||||
bool clamp_at_5v;
|
||||
bool hpwr_vreg_enabled;
|
||||
bool is_hv_haptics;
|
||||
};
|
||||
|
||||
struct haptics_reg_info {
|
||||
|
|
@ -1163,18 +1176,20 @@ static int haptics_get_closeloop_lra_period(struct haptics_chip *chip,
|
|||
static int haptics_set_vmax_mv(struct haptics_chip *chip, u32 vmax_mv)
|
||||
{
|
||||
int rc = 0;
|
||||
u8 val;
|
||||
u8 val, vmax_step;
|
||||
|
||||
if (vmax_mv > MAX_VMAX_MV) {
|
||||
if (vmax_mv > chip->max_vmax_mv) {
|
||||
dev_err(chip->dev, "vmax (%d) exceed the max value: %d\n",
|
||||
vmax_mv, MAX_VMAX_MV);
|
||||
vmax_mv, chip->max_vmax_mv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (chip->clamp_at_5v && (vmax_mv > CLAMPED_VMAX_MV))
|
||||
vmax_mv = CLAMPED_VMAX_MV;
|
||||
|
||||
val = vmax_mv / VMAX_STEP_MV;
|
||||
vmax_step = (chip->is_hv_haptics) ?
|
||||
VMAX_HV_STEP_MV : VMAX_MV_STEP_MV;
|
||||
val = vmax_mv / vmax_step;
|
||||
rc = haptics_write(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_VMAX_REG, &val, 1);
|
||||
if (rc < 0)
|
||||
|
|
@ -1441,8 +1456,9 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if ((val & CAL_RC_CLK_MASK) ==
|
||||
CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT) {
|
||||
if ((chip->wa_flags & TOGGLE_CAL_RC_CLK) &&
|
||||
((val & CAL_RC_CLK_MASK) ==
|
||||
CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT)) {
|
||||
val = CAL_RC_CLK_DISABLED_VAL << CAL_RC_CLK_SHIFT;
|
||||
rc = haptics_masked_write(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK,
|
||||
|
|
@ -2570,6 +2586,23 @@ static int haptics_config_openloop_lra_period(struct haptics_chip *chip,
|
|||
HAP_CFG_TLRA_OL_HIGH_REG, val, 2);
|
||||
}
|
||||
|
||||
static int haptics_config_wa(struct haptics_chip *chip)
|
||||
{
|
||||
switch (chip->pmic_type) {
|
||||
case PM8350B:
|
||||
chip->wa_flags |= TOGGLE_CAL_RC_CLK;
|
||||
break;
|
||||
case PM5100:
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->dev, "PMIC type %d does not match\n",
|
||||
chip->pmic_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int haptics_hw_init(struct haptics_chip *chip)
|
||||
{
|
||||
struct haptics_hw_config *config = &chip->config;
|
||||
|
|
@ -2578,6 +2611,10 @@ static int haptics_hw_init(struct haptics_chip *chip)
|
|||
u8 val[2];
|
||||
u32 t_lra_us;
|
||||
|
||||
rc = haptics_config_wa(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Store CL brake settings */
|
||||
rc = haptics_store_cl_brake_settings(chip);
|
||||
if (rc < 0)
|
||||
|
|
@ -2592,6 +2629,20 @@ static int haptics_hw_init(struct haptics_chip *chip)
|
|||
chip->clamp_at_5v = val[0] & CLAMP_5V_BIT;
|
||||
}
|
||||
|
||||
chip->is_hv_haptics = true;
|
||||
chip->max_vmax_mv = MAX_VMAX_MV;
|
||||
|
||||
if (chip->pmic_type == PM5100) {
|
||||
rc = haptics_read(chip, chip->cfg_addr_base,
|
||||
HAP_CFG_HW_CONFIG_REG, val, 1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
chip->is_hv_haptics = val[0] & HV_HAP_DRIVER_BIT;
|
||||
chip->max_vmax_mv = (chip->is_hv_haptics) ?
|
||||
MAX_HV_VMAX_MV : MAX_MV_VMAX_MV;
|
||||
}
|
||||
|
||||
/* Config VMAX */
|
||||
rc = haptics_set_vmax_mv(chip, config->vmax_mv);
|
||||
if (rc < 0)
|
||||
|
|
|
|||
|
|
@ -2476,6 +2476,9 @@ static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata)
|
|||
FTS_INFO("max touch number:%d, irq gpio:%d, reset gpio:%d",
|
||||
pdata->max_touch_number, pdata->irq_gpio, pdata->reset_gpio);
|
||||
|
||||
pdata->power_always_on =
|
||||
of_property_read_bool(np, "focaltech,power-always-on");
|
||||
|
||||
ret = of_property_read_u32(np, "focaltech,ic-type", &temp_val);
|
||||
if (ret < 0)
|
||||
pdata->type = _FT3518;
|
||||
|
|
@ -2903,6 +2906,7 @@ static int fts_ts_suspend(struct device *dev)
|
|||
{
|
||||
int ret = 0;
|
||||
struct fts_ts_data *ts_data = fts_data;
|
||||
struct fts_ts_platform_data *pdata = ts_data->pdata;
|
||||
|
||||
FTS_FUNC_ENTER();
|
||||
if (ts_data->suspended) {
|
||||
|
|
@ -2934,7 +2938,8 @@ static int fts_ts_suspend(struct device *dev)
|
|||
if (ret < 0)
|
||||
FTS_ERROR("set TP to sleep mode fail, ret=%d", ret);
|
||||
|
||||
if (!ts_data->ic_info.is_incell) {
|
||||
if (!ts_data->ic_info.is_incell && !pdata->power_always_on) {
|
||||
|
||||
#if FTS_POWER_SOURCE_CUST_EN
|
||||
ret = fts_power_source_suspend(ts_data);
|
||||
if (ret < 0) {
|
||||
|
|
@ -2953,6 +2958,7 @@ static int fts_ts_suspend(struct device *dev)
|
|||
static int fts_ts_resume(struct device *dev)
|
||||
{
|
||||
struct fts_ts_data *ts_data = fts_data;
|
||||
struct fts_ts_platform_data *pdata = ts_data->pdata;
|
||||
|
||||
FTS_FUNC_ENTER();
|
||||
if (!ts_data->suspended) {
|
||||
|
|
@ -2971,7 +2977,8 @@ static int fts_ts_resume(struct device *dev)
|
|||
|
||||
if (!ts_data->ic_info.is_incell) {
|
||||
#if FTS_POWER_SOURCE_CUST_EN
|
||||
fts_power_source_resume(ts_data);
|
||||
if (!pdata->power_always_on)
|
||||
fts_power_source_resume(ts_data);
|
||||
#endif
|
||||
fts_reset_proc(200);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ struct fts_ts_platform_data {
|
|||
u32 x_min;
|
||||
u32 y_min;
|
||||
u32 max_touch_number;
|
||||
bool power_always_on;
|
||||
};
|
||||
|
||||
struct ts_event {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#define pr_fmt(fmt) "synx: " fmt
|
||||
|
||||
|
|
@ -158,8 +158,8 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj)
|
|||
data = bind_desc->external_data;
|
||||
bind_ops = synx_util_get_bind_ops(type);
|
||||
if (!bind_ops) {
|
||||
pr_err("bind ops fail id: %d, type: %u, err: %d\n",
|
||||
sync_id, type, rc);
|
||||
pr_err("bind ops fail id: %d, type: %u\n",
|
||||
sync_id, type);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,40 +223,6 @@ DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
|
|||
"%llu\n");
|
||||
|
||||
#if defined(CONFIG_SDC_QTI)
|
||||
static int mmc_scale_get(void *data, u64 *val)
|
||||
{
|
||||
struct mmc_host *host = data;
|
||||
|
||||
*val = host->clk_scaling.curr_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_scale_set(void *data, u64 val)
|
||||
{
|
||||
int err = 0;
|
||||
struct mmc_host *host = data;
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
/* change frequency from sysfs manually */
|
||||
err = mmc_clk_update_freq(host, val, host->clk_scaling.state);
|
||||
if (err == -EAGAIN)
|
||||
err = 0;
|
||||
else if (err)
|
||||
pr_err("%s: clock scale to %llu failed with error %d\n",
|
||||
mmc_hostname(host), val, err);
|
||||
else
|
||||
pr_debug("%s: clock change to %llu finished successfully (%s)\n",
|
||||
mmc_hostname(host), val, current->comm);
|
||||
|
||||
mmc_release_host(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(mmc_scale_fops, mmc_scale_get, mmc_scale_set,
|
||||
"%llu\n");
|
||||
|
||||
static int mmc_max_clock_get(void *data, u64 *val)
|
||||
{
|
||||
|
|
@ -314,8 +280,6 @@ void mmc_add_host_debugfs(struct mmc_host *host)
|
|||
#if defined(CONFIG_SDC_QTI)
|
||||
debugfs_create_file("max_clock", 0600, root, host,
|
||||
&mmc_max_clock_fops);
|
||||
debugfs_create_file("scale", 0600, root, host,
|
||||
&mmc_scale_fops);
|
||||
debugfs_create_bool("skip_clk_scale_freq_update",
|
||||
0600, root,
|
||||
&host->clk_scaling.skip_clk_scale_freq_update);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020 - 2021, 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,6 +29,7 @@ static struct cqhci_host_crypto_variant_ops __maybe_unused cqhci_crypto_qti_vari
|
|||
.disable = cqhci_crypto_qti_disable,
|
||||
.resume = cqhci_crypto_qti_resume,
|
||||
.debug = cqhci_crypto_qti_debug,
|
||||
.recovery_finish = cqhci_crypto_qti_recovery_finish,
|
||||
};
|
||||
|
||||
static bool ice_cap_idx_valid(struct cqhci_host *host,
|
||||
|
|
@ -317,5 +318,11 @@ int cqhci_crypto_qti_resume(struct cqhci_host *host)
|
|||
return crypto_qti_resume(host->crypto_vops->priv);
|
||||
}
|
||||
|
||||
int cqhci_crypto_qti_recovery_finish(struct cqhci_host *host)
|
||||
{
|
||||
keyslot_manager_reprogram_all_keys(host->mmc->ksm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Vendor specific CQHCI Crypto Engine Support");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020 - 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _UFSHCD_CRYPTO_QTI_H
|
||||
|
|
@ -28,4 +28,6 @@ void cqhci_crypto_qti_set_vops(struct cqhci_host *host)
|
|||
|
||||
int cqhci_crypto_qti_resume(struct cqhci_host *host);
|
||||
|
||||
int cqhci_crypto_qti_recovery_finish(struct cqhci_host *host);
|
||||
|
||||
#endif /* _UFSHCD_ICE_QTI_H */
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/qcom-pinctrl.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
|
|
@ -164,6 +165,10 @@
|
|||
#define CQHCI_VENDOR_DIS_RST_ON_CQ_EN (0x3 << 13)
|
||||
#define RCLK_TOGGLE BIT(2)
|
||||
|
||||
/* enum for writing to TLMM_NORTH_SPARE register as defined by pinctrl API */
|
||||
#define TLMM_NORTH_SPARE 2
|
||||
#define TLMM_NORTH_SPARE_CORE_IE BIT(15)
|
||||
|
||||
struct sdhci_msm_offset {
|
||||
u32 core_hc_mode;
|
||||
u32 core_mci_data_cnt;
|
||||
|
|
@ -2226,6 +2231,7 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host,
|
|||
struct sdhci_msm_vreg_data *curr_slot;
|
||||
struct sdhci_msm_reg_data *vreg_table[2];
|
||||
struct mmc_host *mmc = msm_host->mmc;
|
||||
u32 val = 0;
|
||||
|
||||
curr_slot = msm_host->vreg_data;
|
||||
if (!curr_slot) {
|
||||
|
|
@ -2241,6 +2247,20 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host,
|
|||
if (!enable && vreg_table[1]->is_always_on && !mmc->card)
|
||||
vreg_table[1]->is_always_on = false;
|
||||
|
||||
if (!enable && !(mmc->caps & MMC_CAP_NONREMOVABLE)) {
|
||||
|
||||
/*
|
||||
* Disable Receiver of the Pad to avoid crowbar currents
|
||||
* when Pad power supplies are collapsed. Provide SW control
|
||||
* on the core_ie of SDC2 Pads. SW write 1’b0
|
||||
* into the bit 15 of register TLMM_NORTH_SPARE.
|
||||
*/
|
||||
|
||||
val = msm_spare_read(TLMM_NORTH_SPARE);
|
||||
val &= ~TLMM_NORTH_SPARE_CORE_IE;
|
||||
msm_spare_write(TLMM_NORTH_SPARE, val);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
|
||||
if (vreg_table[i]) {
|
||||
if (enable)
|
||||
|
|
@ -2251,6 +2271,20 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host,
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable && !(mmc->caps & MMC_CAP_NONREMOVABLE)) {
|
||||
|
||||
/*
|
||||
* Disable Receiver of the Pad to avoid crowbar currents
|
||||
* when Pad power supplies are collapsed. Provide SW control
|
||||
* on the core_ie of SDC2 Pads. SW write 1’b1
|
||||
* into the bit 15 of register TLMM_NORTH_SPARE.
|
||||
*/
|
||||
|
||||
val = msm_spare_read(TLMM_NORTH_SPARE);
|
||||
val |= TLMM_NORTH_SPARE_CORE_IE;
|
||||
msm_spare_write(TLMM_NORTH_SPARE, val);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1431,12 +1431,20 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
|
|||
|
||||
headroom = skb_headroom(skb) - 8;
|
||||
|
||||
#ifdef CONFIG_ENABLE_SFE
|
||||
if (((!(skb->fast_forwarded) && skb_header_cloned(skb)) ||
|
||||
headroom < 0) &&
|
||||
pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if ((skb_header_cloned(skb) || headroom < 0) &&
|
||||
pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
ptr = skb_push(skb, 8);
|
||||
put_unaligned_le32(tx_hdr1, ptr);
|
||||
put_unaligned_le32(tx_hdr2, ptr + 4);
|
||||
|
|
|
|||
|
|
@ -876,6 +876,24 @@ void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
|
|||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPC_LOGGING)
|
||||
void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
|
||||
const char *log_level, char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list va_args;
|
||||
|
||||
va_start(va_args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &va_args;
|
||||
|
||||
if (log_level)
|
||||
printk("%scnss: %pV", log_level, &vaf);
|
||||
|
||||
ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
|
||||
|
||||
va_end(va_args);
|
||||
}
|
||||
|
||||
static int cnss_ipc_logging_init(void)
|
||||
{
|
||||
cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
|
||||
|
|
@ -911,6 +929,21 @@ static void cnss_ipc_logging_deinit(void)
|
|||
#else
|
||||
static int cnss_ipc_logging_init(void) { return 0; }
|
||||
static void cnss_ipc_logging_deinit(void) {}
|
||||
void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
|
||||
const char *log_level, char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list va_args;
|
||||
|
||||
va_start(va_args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &va_args;
|
||||
|
||||
if (log_level)
|
||||
printk("%scnss: %pV", log_level, &vaf);
|
||||
|
||||
va_end(va_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
int cnss_debug_init(void)
|
||||
|
|
|
|||
|
|
@ -4,55 +4,58 @@
|
|||
#ifndef _CNSS_DEBUG_H
|
||||
#define _CNSS_DEBUG_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPC_LOGGING)
|
||||
#include <linux/ipc_logging.h>
|
||||
#endif
|
||||
#include <linux/printk.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPC_LOGGING)
|
||||
#define CNSS_IPC_LOG_PAGES 32
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <asm/current.h>
|
||||
|
||||
extern void *cnss_ipc_log_context;
|
||||
extern void *cnss_ipc_log_long_context;
|
||||
|
||||
#define cnss_ipc_log_string(_x...) \
|
||||
ipc_log_string(cnss_ipc_log_context, _x)
|
||||
|
||||
#define cnss_ipc_log_long_string(_x...) \
|
||||
ipc_log_string(cnss_ipc_log_long_context, _x)
|
||||
#ifdef CONFIG_CNSS2_DEBUG
|
||||
#define CNSS_IPC_LOG_PAGES 100
|
||||
#else
|
||||
#define cnss_ipc_log_string(_x...)
|
||||
#define cnss_ipc_log_long_string(_x...)
|
||||
#define CNSS_IPC_LOG_PAGES 50
|
||||
#endif
|
||||
#define cnss_debug_log_print(_x...) \
|
||||
cnss_debug_ipc_log_print(cnss_ipc_log_context, _x)
|
||||
|
||||
#define cnss_debug_log_long_print(_x...) \
|
||||
cnss_debug_ipc_log_print(cnss_ipc_log_long_context, _x)
|
||||
#else
|
||||
#define cnss_debug_log_print(_x...) \
|
||||
cnss_debug_ipc_log_print((void *)NULL, _x)
|
||||
#define cnss_debug_log_long_print(_x...) \
|
||||
cnss_debug_ipc_log_print((void *)NULL, _x)
|
||||
#endif
|
||||
|
||||
#define cnss_pr_err(_fmt, ...) do { \
|
||||
printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__); \
|
||||
cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
#define proc_name (in_irq() ? "irq" : \
|
||||
(in_softirq() ? "soft_irq" : current->comm))
|
||||
|
||||
#define cnss_pr_warn(_fmt, ...) do { \
|
||||
printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__); \
|
||||
cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
#define cnss_pr_err(_fmt, ...) \
|
||||
cnss_debug_log_print(proc_name, __func__, \
|
||||
KERN_ERR, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define cnss_pr_info(_fmt, ...) do { \
|
||||
printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__); \
|
||||
cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
#define cnss_pr_warn(_fmt, ...) \
|
||||
cnss_debug_log_print(proc_name, __func__, \
|
||||
KERN_WARNING, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define cnss_pr_dbg(_fmt, ...) do { \
|
||||
printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \
|
||||
cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
#define cnss_pr_info(_fmt, ...) \
|
||||
cnss_debug_log_print(proc_name, __func__, \
|
||||
KERN_INFO, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define cnss_pr_vdbg(_fmt, ...) do { \
|
||||
printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \
|
||||
cnss_ipc_log_long_string("%scnss: " _fmt, "", \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define cnss_pr_dbg(_fmt, ...) \
|
||||
cnss_debug_log_print(proc_name, __func__, \
|
||||
KERN_DEBUG, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define cnss_pr_buf(_fmt, ...) \
|
||||
cnss_ipc_log_long_string("%scnss: " _fmt, "", ##__VA_ARGS__) \
|
||||
#define cnss_pr_vdbg(_fmt, ...) \
|
||||
cnss_debug_log_long_print(proc_name, __func__, \
|
||||
KERN_DEBUG, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#define cnss_pr_buf(_fmt, ...) \
|
||||
cnss_debug_log_long_print(proc_name, __func__, \
|
||||
NULL, _fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_CNSS2_DEBUG
|
||||
#define CNSS_ASSERT(_condition) do { \
|
||||
|
|
@ -79,5 +82,6 @@ int cnss_debug_init(void);
|
|||
void cnss_debug_deinit(void);
|
||||
int cnss_debugfs_create(struct cnss_plat_data *plat_priv);
|
||||
void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv);
|
||||
|
||||
void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
|
||||
const char *log_level, char *fmt, ...);
|
||||
#endif /* _CNSS_DEBUG_H */
|
||||
|
|
|
|||
|
|
@ -685,6 +685,8 @@ int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv)
|
|||
|
||||
static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset)
|
||||
{
|
||||
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
|
||||
|
||||
u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK;
|
||||
u32 window_enable = WINDOW_ENABLE_BIT | window;
|
||||
u32 val;
|
||||
|
|
@ -703,7 +705,8 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset)
|
|||
if (val != window_enable) {
|
||||
cnss_pr_err("Failed to config window register to 0x%x, current value: 0x%x\n",
|
||||
window_enable, val);
|
||||
if (!cnss_pci_check_link_status(pci_priv))
|
||||
if (!cnss_pci_check_link_status(pci_priv) &&
|
||||
!test_bit(CNSS_IN_PANIC, &plat_priv->driver_state))
|
||||
CNSS_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1287,6 +1290,9 @@ static void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv)
|
|||
pci_priv->pci_link_down_ind = true;
|
||||
spin_unlock_irqrestore(&pci_link_down_lock, flags);
|
||||
|
||||
/* Notify MHI about link down */
|
||||
mhi_control_error(pci_priv->mhi_ctrl);
|
||||
|
||||
if (pci_dev->device == QCA6174_DEVICE_ID)
|
||||
disable_irq(pci_dev->irq);
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@
|
|||
#define PCIE20_ELBI_SYS_STTS (0x08)
|
||||
|
||||
#define PCIE20_CAP (0x70)
|
||||
#define PCIE20_CAP_DEVCAP (PCIE20_CAP + 0x04)
|
||||
#define PCIE20_CAP_DEVCTRLSTATUS (PCIE20_CAP + 0x08)
|
||||
#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
|
||||
#define PCIE_CAP_DLL_ACTIVE BIT(29)
|
||||
|
|
@ -503,7 +504,6 @@ enum msm_pcie_debugfs_option {
|
|||
MSM_PCIE_DISABLE_LINK,
|
||||
MSM_PCIE_ENABLE_LINK,
|
||||
MSM_PCIE_DISABLE_ENABLE_LINK,
|
||||
MSM_PCIE_DUMP_SHADOW_REGISTER,
|
||||
MSM_PCIE_DISABLE_L0S,
|
||||
MSM_PCIE_ENABLE_L0S,
|
||||
MSM_PCIE_DISABLE_L1,
|
||||
|
|
@ -532,7 +532,6 @@ static const char * const
|
|||
"DISABLE LINK",
|
||||
"ENABLE LINK",
|
||||
"DISABLE AND ENABLE LINK",
|
||||
"DUMP PCIE SHADOW REGISTER",
|
||||
"DISABLE L0S",
|
||||
"ENABLE L0S",
|
||||
"DISABLE L1",
|
||||
|
|
@ -640,11 +639,7 @@ struct msm_pcie_sid_info_t {
|
|||
/* PCIe device info structure */
|
||||
struct msm_pcie_device_info {
|
||||
struct list_head pcidev_node;
|
||||
u32 bdf;
|
||||
struct pci_dev *dev;
|
||||
short short_bdf;
|
||||
u32 sid;
|
||||
int domain;
|
||||
};
|
||||
|
||||
/* DRV IPC command type */
|
||||
|
|
@ -703,6 +698,11 @@ struct msm_pcie_drv_info {
|
|||
struct completion completion;
|
||||
};
|
||||
|
||||
struct pcie_i2c_reg_update {
|
||||
u32 offset;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
/* i2c control interface for a i2c client device */
|
||||
struct pcie_i2c_ctrl {
|
||||
struct i2c_client *client;
|
||||
|
|
@ -713,6 +713,8 @@ struct pcie_i2c_ctrl {
|
|||
u32 ep_reset_gpio_mask;
|
||||
u32 *dump_regs;
|
||||
u32 dump_reg_count;
|
||||
struct pcie_i2c_reg_update *reg_update;
|
||||
u32 reg_update_count;
|
||||
|
||||
/* client specific callbacks */
|
||||
int (*client_i2c_read)(struct i2c_client *client, u32 reg_addr,
|
||||
|
|
@ -721,6 +723,7 @@ struct pcie_i2c_ctrl {
|
|||
u32 val);
|
||||
int (*client_i2c_reset)(struct pcie_i2c_ctrl *i2c_ctrl, bool reset);
|
||||
void (*client_i2c_dump_regs)(struct pcie_i2c_ctrl *i2c_ctrl);
|
||||
void (*client_i2c_de_emphasis_wa)(struct pcie_i2c_ctrl *i2c_ctrl);
|
||||
};
|
||||
|
||||
enum i2c_client_id {
|
||||
|
|
@ -788,6 +791,8 @@ struct msm_pcie_dev_t {
|
|||
enum msm_pcie_link_status link_status;
|
||||
bool user_suspend;
|
||||
bool disable_pc;
|
||||
|
||||
struct pci_saved_state *default_state;
|
||||
struct pci_saved_state *saved_state;
|
||||
|
||||
struct wakeup_source *ws;
|
||||
|
|
@ -863,9 +868,6 @@ struct msm_pcie_dev_t {
|
|||
struct msm_pcie_tcsr_info_t *tcsr_config;
|
||||
u32 sid_info_len;
|
||||
struct msm_pcie_sid_info_t *sid_info;
|
||||
u32 ep_shadow[MAX_DEVICE_NUM][PCIE_CONF_SPACE_DW];
|
||||
u32 rc_shadow[PCIE_CONF_SPACE_DW];
|
||||
bool shadow_en;
|
||||
bool bridge_found;
|
||||
struct list_head event_reg_list;
|
||||
spinlock_t evt_reg_list_lock;
|
||||
|
|
@ -877,7 +879,6 @@ struct msm_pcie_dev_t {
|
|||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct pinctrl_state *pins_sleep;
|
||||
struct msm_pcie_device_info pcidev_table[MAX_DEVICE_NUM];
|
||||
|
||||
struct msm_pcie_drv_info *drv_info;
|
||||
struct work_struct drv_enable_pc_work;
|
||||
|
|
@ -1524,54 +1525,6 @@ static bool msm_pcie_confirm_linkup(struct msm_pcie_dev_t *dev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void msm_pcie_cfg_recover(struct msm_pcie_dev_t *dev, bool rc)
|
||||
{
|
||||
int i, j;
|
||||
u32 val = 0;
|
||||
u32 *shadow;
|
||||
void __iomem *cfg = dev->conf;
|
||||
|
||||
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||
if (!rc && !dev->pcidev_table[i].bdf)
|
||||
break;
|
||||
if (rc) {
|
||||
cfg = dev->dm_core;
|
||||
shadow = dev->rc_shadow;
|
||||
} else {
|
||||
if (!msm_pcie_confirm_linkup(dev, false, true,
|
||||
dev->pcidev_table[i].dev))
|
||||
continue;
|
||||
|
||||
shadow = dev->ep_shadow[i];
|
||||
PCIE_DBG(dev,
|
||||
"PCIe Device: %02x:%02x.%01x\n",
|
||||
dev->pcidev_table[i].bdf >> 24,
|
||||
dev->pcidev_table[i].bdf >> 19 & 0x1f,
|
||||
dev->pcidev_table[i].bdf >> 16 & 0x07);
|
||||
}
|
||||
for (j = PCIE_CONF_SPACE_DW - 1; j >= 0; j--) {
|
||||
val = shadow[j];
|
||||
if (val != PCIE_CLEAR) {
|
||||
PCIE_DBG3(dev,
|
||||
"PCIe: before recovery:cfg 0x%x:0x%x\n",
|
||||
j * 4, readl_relaxed(cfg + j * 4));
|
||||
PCIE_DBG3(dev,
|
||||
"PCIe: shadow_dw[%d]:cfg 0x%x:0x%x\n",
|
||||
j, j * 4, val);
|
||||
msm_pcie_write_reg(cfg, j * 4, val);
|
||||
PCIE_DBG3(dev,
|
||||
"PCIe: after recovery:cfg 0x%x:0x%x\n\n",
|
||||
j * 4, readl_relaxed(cfg + j * 4));
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
pci_save_state(dev->pcidev_table[i].dev);
|
||||
cfg += SZ_4K;
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_pcie_write_mask(void __iomem *addr,
|
||||
uint32_t clear_mask, uint32_t set_mask)
|
||||
{
|
||||
|
|
@ -1701,8 +1654,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
|
|||
dev->linkdown_panic);
|
||||
PCIE_DBG_FS(dev, "the link is %s suspending\n",
|
||||
dev->suspending ? "" : "not");
|
||||
PCIE_DBG_FS(dev, "shadow is %s enabled\n",
|
||||
dev->shadow_en ? "" : "not");
|
||||
PCIE_DBG_FS(dev, "the power of RC is %s on\n",
|
||||
dev->power_on ? "" : "not");
|
||||
PCIE_DBG_FS(dev, "smmu_sid_base: 0x%x\n",
|
||||
|
|
@ -1771,37 +1722,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
|
|||
dev->l23_rdy_poll_timeout);
|
||||
}
|
||||
|
||||
static void msm_pcie_shadow_dump(struct msm_pcie_dev_t *dev, bool rc)
|
||||
{
|
||||
int i, j;
|
||||
u32 val = 0;
|
||||
u32 *shadow;
|
||||
|
||||
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||
if (!rc && !dev->pcidev_table[i].bdf)
|
||||
break;
|
||||
if (rc) {
|
||||
shadow = dev->rc_shadow;
|
||||
} else {
|
||||
shadow = dev->ep_shadow[i];
|
||||
PCIE_DBG_FS(dev, "PCIe Device: %02x:%02x.%01x\n",
|
||||
dev->pcidev_table[i].bdf >> 24,
|
||||
dev->pcidev_table[i].bdf >> 19 & 0x1f,
|
||||
dev->pcidev_table[i].bdf >> 16 & 0x07);
|
||||
}
|
||||
for (j = 0; j < PCIE_CONF_SPACE_DW; j++) {
|
||||
val = shadow[j];
|
||||
if (val != PCIE_CLEAR) {
|
||||
PCIE_DBG_FS(dev,
|
||||
"PCIe: shadow_dw[%d]:cfg 0x%x:0x%x\n",
|
||||
j, j * 4, val);
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
|
||||
u32 testcase)
|
||||
{
|
||||
|
|
@ -1818,9 +1738,8 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
|
|||
case MSM_PCIE_DISABLE_LINK:
|
||||
PCIE_DBG_FS(dev,
|
||||
"\n\nPCIe: RC%d: disable link\n\n", dev->rc_idx);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0,
|
||||
dev->dev, NULL,
|
||||
MSM_PCIE_CONFIG_NO_CFG_RESTORE);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, dev->dev, NULL,
|
||||
0);
|
||||
if (ret)
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:failed to disable link\n",
|
||||
__func__);
|
||||
|
|
@ -1832,50 +1751,28 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
|
|||
PCIE_DBG_FS(dev,
|
||||
"\n\nPCIe: RC%d: enable link and recover config space\n\n",
|
||||
dev->rc_idx);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0,
|
||||
dev->dev, NULL,
|
||||
MSM_PCIE_CONFIG_NO_CFG_RESTORE);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, dev->dev, NULL,
|
||||
0);
|
||||
if (ret)
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:failed to enable link\n",
|
||||
__func__);
|
||||
else {
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:enabled link\n", __func__);
|
||||
msm_pcie_recover_config(dev->dev);
|
||||
}
|
||||
break;
|
||||
case MSM_PCIE_DISABLE_ENABLE_LINK:
|
||||
PCIE_DBG_FS(dev,
|
||||
"\n\nPCIe: RC%d: disable and enable link then recover config space\n\n",
|
||||
dev->rc_idx);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0,
|
||||
dev->dev, NULL,
|
||||
MSM_PCIE_CONFIG_NO_CFG_RESTORE);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, dev->dev, NULL,
|
||||
0);
|
||||
if (ret)
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:failed to disable link\n",
|
||||
__func__);
|
||||
else
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:disabled link\n", __func__);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0,
|
||||
dev->dev, NULL,
|
||||
MSM_PCIE_CONFIG_NO_CFG_RESTORE);
|
||||
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, dev->dev, NULL,
|
||||
0);
|
||||
if (ret)
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:failed to enable link\n",
|
||||
__func__);
|
||||
else {
|
||||
PCIE_DBG_FS(dev, "PCIe:%s:enabled link\n", __func__);
|
||||
msm_pcie_recover_config(dev->dev);
|
||||
}
|
||||
break;
|
||||
case MSM_PCIE_DUMP_SHADOW_REGISTER:
|
||||
PCIE_DBG_FS(dev,
|
||||
"\n\nPCIe: RC%d: dumping RC shadow registers\n",
|
||||
dev->rc_idx);
|
||||
msm_pcie_shadow_dump(dev, true);
|
||||
|
||||
PCIE_DBG_FS(dev,
|
||||
"\n\nPCIe: RC%d: dumping EP shadow registers\n",
|
||||
dev->rc_idx);
|
||||
msm_pcie_shadow_dump(dev, false);
|
||||
break;
|
||||
case MSM_PCIE_DISABLE_L0S:
|
||||
PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n",
|
||||
|
|
@ -2965,29 +2862,6 @@ static void msm_pcie_cfg_bdf(struct msm_pcie_dev_t *dev, u8 bus, u8 devfn)
|
|||
dev->current_bdf = bdf;
|
||||
}
|
||||
|
||||
static void msm_pcie_save_shadow(struct msm_pcie_dev_t *dev,
|
||||
u32 word_offset, u32 wr_val,
|
||||
u32 bdf, bool rc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (rc) {
|
||||
dev->rc_shadow[word_offset / 4] = wr_val;
|
||||
} else {
|
||||
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||
if (!dev->pcidev_table[i].bdf) {
|
||||
dev->pcidev_table[i].bdf = bdf;
|
||||
if ((!dev->bridge_found) && (i > 0))
|
||||
dev->bridge_found = true;
|
||||
}
|
||||
if (dev->pcidev_table[i].bdf == bdf) {
|
||||
dev->ep_shadow[i][word_offset / 4] = wr_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
|
|
@ -3089,18 +2963,6 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
|
|||
|
||||
msm_pcie_write_reg(config_base, word_offset, wr_val);
|
||||
|
||||
if (dev->shadow_en) {
|
||||
if (rd_val == PCIE_LINK_DOWN &&
|
||||
(readl_relaxed(config_base) == PCIE_LINK_DOWN))
|
||||
PCIE_ERR(dev,
|
||||
"Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n",
|
||||
rc_idx, bus->number, devfn,
|
||||
where, size);
|
||||
else
|
||||
msm_pcie_save_shadow(dev, word_offset, wr_val,
|
||||
bdf, rc);
|
||||
}
|
||||
|
||||
PCIE_DBG3(dev,
|
||||
"RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n",
|
||||
rc_idx, bus->number, devfn, where, size,
|
||||
|
|
@ -3793,6 +3655,8 @@ done:
|
|||
|
||||
static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
PCIE_DBG(dev, "RC%d\n", dev->rc_idx);
|
||||
|
||||
/*
|
||||
|
|
@ -3815,11 +3679,6 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
|||
PCIE20_ACK_N_FTS,
|
||||
dev->n_fts << 8);
|
||||
|
||||
if (dev->shadow_en)
|
||||
dev->rc_shadow[PCIE20_ACK_F_ASPM_CTRL_REG / 4] =
|
||||
readl_relaxed(dev->dm_core +
|
||||
PCIE20_ACK_F_ASPM_CTRL_REG);
|
||||
|
||||
PCIE_DBG2(dev, "Updated PCIE20_ACK_F_ASPM_CTRL_REG:0x%x\n",
|
||||
readl_relaxed(dev->dm_core + PCIE20_ACK_F_ASPM_CTRL_REG));
|
||||
|
||||
|
|
@ -3833,6 +3692,13 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
|||
PCIE20_DEVICE_CONTROL2_STATUS2,
|
||||
0xf, dev->cpl_timeout);
|
||||
|
||||
/* update RC Max Payload Size based on Max Payload Size Supported */
|
||||
val = readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCAP) &
|
||||
PCI_EXP_DEVCAP_PAYLOAD;
|
||||
msm_pcie_write_reg_field(dev->dm_core,
|
||||
PCIE20_CAP_DEVCTRLSTATUS,
|
||||
PCI_EXP_DEVCTL_PAYLOAD, val);
|
||||
|
||||
/* Enable AER on RC */
|
||||
if (dev->aer_enable) {
|
||||
msm_pcie_write_mask(dev->dm_core + PCIE20_BRIDGE_CTRL, 0,
|
||||
|
|
@ -4638,6 +4504,28 @@ static void ntn3_dump_regs(struct pcie_i2c_ctrl *i2c_ctrl)
|
|||
}
|
||||
}
|
||||
|
||||
static void ntn3_de_emphasis_wa(struct pcie_i2c_ctrl *i2c_ctrl)
|
||||
{
|
||||
int i, val;
|
||||
struct msm_pcie_dev_t *pcie_dev = container_of(i2c_ctrl,
|
||||
struct msm_pcie_dev_t,
|
||||
i2c_ctrl);
|
||||
|
||||
PCIE_DBG(pcie_dev, "PCIe: RC%d: NTN3 reg update\n", pcie_dev->rc_idx);
|
||||
|
||||
for (i = 0; i < i2c_ctrl->reg_update_count; i++) {
|
||||
i2c_ctrl->client_i2c_write(i2c_ctrl->client, i2c_ctrl->reg_update[i].offset,
|
||||
i2c_ctrl->reg_update[i].val);
|
||||
/*Read to make sure writes are completed*/
|
||||
i2c_ctrl->client_i2c_read(i2c_ctrl->client, i2c_ctrl->reg_update[i].offset,
|
||||
&val);
|
||||
PCIE_DBG(pcie_dev, "PCIe: RC%d: NTN3 reg off:0x%x wr_val:0x%x rd_val:0x%x\n",
|
||||
pcie_dev->rc_idx, i2c_ctrl->reg_update[i].offset,
|
||||
i2c_ctrl->reg_update[i].val, val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int msm_pcie_enable(struct msm_pcie_dev_t *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
@ -4751,6 +4639,9 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev)
|
|||
|
||||
ep_up_timeout = jiffies + usecs_to_jiffies(EP_UP_TIMEOUT_US);
|
||||
|
||||
if (dev->i2c_ctrl.client && dev->i2c_ctrl.client_i2c_de_emphasis_wa)
|
||||
dev->i2c_ctrl.client_i2c_de_emphasis_wa(&dev->i2c_ctrl);
|
||||
|
||||
msm_pcie_config_sid(dev);
|
||||
msm_pcie_config_controller(dev);
|
||||
|
||||
|
|
@ -4876,7 +4767,7 @@ static void msm_pcie_disable(struct msm_pcie_dev_t *dev)
|
|||
PCIE_DBG(dev, "RC%d: exit\n", dev->rc_idx);
|
||||
}
|
||||
|
||||
static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev)
|
||||
static int msm_pcie_config_device_info(struct pci_dev *pcidev, void *pdev)
|
||||
{
|
||||
struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *) pdev;
|
||||
struct msm_pcie_device_info *dev_info;
|
||||
|
|
@ -5000,7 +4891,7 @@ int msm_pcie_enumerate(u32 rc_idx)
|
|||
struct pci_dev *pcidev = NULL;
|
||||
struct pci_host_bridge *bridge;
|
||||
bool found = false;
|
||||
struct pci_bus *bus;
|
||||
struct pci_bus *bus, *child;
|
||||
resource_size_t iobase = 0;
|
||||
u32 ids, vendor_id, device_id;
|
||||
LIST_HEAD(res);
|
||||
|
|
@ -5082,6 +4973,9 @@ int msm_pcie_enumerate(u32 rc_idx)
|
|||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
dev->enumerated = true;
|
||||
|
|
@ -5094,13 +4988,6 @@ int msm_pcie_enumerate(u32 rc_idx)
|
|||
msm_pcie_write_reg_field(dev->dm_core,
|
||||
PCIE20_DEVICE_CONTROL2_STATUS2, 0xf, dev->cpl_timeout);
|
||||
|
||||
if (dev->shadow_en) {
|
||||
u32 val = readl_relaxed(dev->dm_core + PCIE20_COMMAND_STATUS);
|
||||
|
||||
PCIE_DBG(dev, "PCIE20_COMMAND_STATUS:0x%x\n", val);
|
||||
dev->rc_shadow[PCIE20_COMMAND_STATUS / 4] = val;
|
||||
}
|
||||
|
||||
do {
|
||||
pcidev = pci_get_device(vendor_id, device_id, pcidev);
|
||||
if (pcidev && (dev == (struct msm_pcie_dev_t *)
|
||||
|
|
@ -5117,8 +5004,10 @@ int msm_pcie_enumerate(u32 rc_idx)
|
|||
goto out;
|
||||
}
|
||||
|
||||
pci_walk_bus(dev->dev->bus, msm_pcie_config_device_table, dev);
|
||||
pci_walk_bus(dev->dev->bus, msm_pcie_config_device_info, dev);
|
||||
|
||||
pci_save_state(pcidev);
|
||||
dev->default_state = pci_store_saved_state(pcidev);
|
||||
out:
|
||||
mutex_unlock(&dev->enumerate_lock);
|
||||
|
||||
|
|
@ -5387,7 +5276,6 @@ static void msm_pcie_handle_linkdown(struct msm_pcie_dev_t *dev)
|
|||
return;
|
||||
|
||||
dev->link_status = MSM_PCIE_LINK_DOWN;
|
||||
dev->shadow_en = false;
|
||||
|
||||
if (!dev->suspending) {
|
||||
/* PCIe registers dump on link down */
|
||||
|
|
@ -6054,6 +5942,23 @@ static int msm_pcie_i2c_ctrl_init(struct msm_pcie_dev_t *pcie_dev)
|
|||
i2c_ctrl->dump_reg_count = 0;
|
||||
}
|
||||
|
||||
of_get_property(i2c_client_node, "reg_update", &size);
|
||||
|
||||
if (size) {
|
||||
i2c_ctrl->reg_update = devm_kzalloc(dev, size, GFP_KERNEL);
|
||||
if (!i2c_ctrl->reg_update)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_ctrl->reg_update_count = size / sizeof(*i2c_ctrl->reg_update);
|
||||
|
||||
ret = of_property_read_u32_array(i2c_client_node,
|
||||
"reg_update",
|
||||
(unsigned int *)i2c_ctrl->reg_update,
|
||||
size/sizeof(i2c_ctrl->reg_update->offset));
|
||||
if (ret)
|
||||
i2c_ctrl->reg_update_count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -6061,7 +5966,7 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
int ret = 0;
|
||||
int rc_idx = -1;
|
||||
int i, j, size;
|
||||
int size;
|
||||
struct msm_pcie_dev_t *pcie_dev;
|
||||
struct device_node *of_node;
|
||||
|
||||
|
|
@ -6274,7 +6179,6 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
|||
PCIE_DBG(pcie_dev, "RC%d: clkreq gpio no:%u\n",
|
||||
pcie_dev->rc_idx, pcie_dev->clkreq_gpio);
|
||||
|
||||
pcie_dev->shadow_en = true;
|
||||
pcie_dev->aer_enable = true;
|
||||
|
||||
memcpy(pcie_dev->vreg, msm_pcie_vreg_info, sizeof(msm_pcie_vreg_info));
|
||||
|
|
@ -6290,18 +6194,6 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
|||
memcpy(pcie_dev->pipe_reset, msm_pcie_pipe_reset_info[rc_idx],
|
||||
sizeof(msm_pcie_pipe_reset_info[rc_idx]));
|
||||
|
||||
for (i = 0; i < PCIE_CONF_SPACE_DW; i++)
|
||||
pcie_dev->rc_shadow[i] = PCIE_CLEAR;
|
||||
for (i = 0; i < MAX_DEVICE_NUM; i++)
|
||||
for (j = 0; j < PCIE_CONF_SPACE_DW; j++)
|
||||
pcie_dev->ep_shadow[i][j] = PCIE_CLEAR;
|
||||
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||
pcie_dev->pcidev_table[i].bdf = 0;
|
||||
pcie_dev->pcidev_table[i].dev = NULL;
|
||||
pcie_dev->pcidev_table[i].short_bdf = 0;
|
||||
pcie_dev->pcidev_table[i].sid = 0;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, pcie_dev);
|
||||
|
||||
ret = msm_pcie_get_resources(pcie_dev, pcie_dev->pdev);
|
||||
|
|
@ -6438,6 +6330,14 @@ static int msm_pcie_remove(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "PCIe: RC%d: being removed\n", rc_idx);
|
||||
}
|
||||
|
||||
if (msm_pcie_dev[rc_idx].saved_state)
|
||||
pci_load_and_free_saved_state(msm_pcie_dev[rc_idx].dev,
|
||||
&msm_pcie_dev[rc_idx].saved_state);
|
||||
|
||||
if (msm_pcie_dev[rc_idx].default_state)
|
||||
pci_load_and_free_saved_state(msm_pcie_dev[rc_idx].dev,
|
||||
&msm_pcie_dev[rc_idx].default_state);
|
||||
|
||||
msm_pcie_irq_deinit(&msm_pcie_dev[rc_idx]);
|
||||
msm_pcie_vreg_deinit(&msm_pcie_dev[rc_idx]);
|
||||
msm_pcie_clk_deinit(&msm_pcie_dev[rc_idx]);
|
||||
|
|
@ -7132,6 +7032,7 @@ static int pcie_i2c_ctrl_probe(struct i2c_client *client,
|
|||
i2c_ctrl->client_i2c_write = ntn3_i2c_write;
|
||||
i2c_ctrl->client_i2c_reset = ntn3_ep_reset_ctrl;
|
||||
i2c_ctrl->client_i2c_dump_regs = ntn3_dump_regs;
|
||||
i2c_ctrl->client_i2c_de_emphasis_wa = ntn3_de_emphasis_wa;
|
||||
} else {
|
||||
dev_err(&client->dev, "invalid client id %d\n", client_id);
|
||||
}
|
||||
|
|
@ -7331,16 +7232,26 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (dev && !(options & MSM_PCIE_CONFIG_NO_CFG_RESTORE)
|
||||
&& msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) {
|
||||
ret = pci_save_state(dev);
|
||||
pcie_dev->saved_state = pci_store_saved_state(dev);
|
||||
}
|
||||
if (ret) {
|
||||
PCIE_ERR(pcie_dev, "PCIe: fail to save state of RC%d:%d.\n",
|
||||
pcie_dev->rc_idx, ret);
|
||||
pcie_dev->suspending = false;
|
||||
return ret;
|
||||
if (dev) {
|
||||
if (msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) {
|
||||
ret = pci_save_state(dev);
|
||||
if (ret) {
|
||||
PCIE_ERR(pcie_dev,
|
||||
"PCIe: RC%d: fail to save state of RC%d:%d.\n",
|
||||
pcie_dev->rc_idx, ret);
|
||||
pcie_dev->suspending = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcie_dev->saved_state = pci_store_saved_state(dev);
|
||||
} else {
|
||||
pci_load_and_free_saved_state(dev,
|
||||
&pcie_dev->saved_state);
|
||||
pcie_dev->saved_state = pcie_dev->default_state;
|
||||
PCIE_DBG(pcie_dev,
|
||||
"PCIe: RC%d: saved default config space\n",
|
||||
pcie_dev->rc_idx);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pcie_dev->cfg_lock,
|
||||
|
|
@ -7451,37 +7362,11 @@ static int msm_pcie_pm_resume(struct pci_dev *dev,
|
|||
"dev->bus->number = %d dev->bus->primary = %d\n",
|
||||
dev->bus->number, dev->bus->primary);
|
||||
|
||||
if (!(options & MSM_PCIE_CONFIG_NO_CFG_RESTORE)) {
|
||||
if (pcie_dev->saved_state) {
|
||||
PCIE_DBG(pcie_dev,
|
||||
"RC%d: entry of PCI framework restore state\n",
|
||||
pcie_dev->rc_idx);
|
||||
|
||||
pci_load_and_free_saved_state(dev,
|
||||
&pcie_dev->saved_state);
|
||||
pci_restore_state(dev);
|
||||
|
||||
PCIE_DBG(pcie_dev,
|
||||
"RC%d: exit of PCI framework restore state\n",
|
||||
pcie_dev->rc_idx);
|
||||
} else {
|
||||
PCIE_DBG(pcie_dev,
|
||||
"RC%d: restore rc config space using shadow recovery\n",
|
||||
pcie_dev->rc_idx);
|
||||
msm_pcie_cfg_recover(pcie_dev, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (pcie_dev->bridge_found) {
|
||||
PCIE_DBG(pcie_dev,
|
||||
"RC%d: entry of PCIe recover config\n",
|
||||
pcie_dev->rc_idx);
|
||||
|
||||
msm_pcie_recover_config(dev);
|
||||
|
||||
PCIE_DBG(pcie_dev,
|
||||
"RC%d: exit of PCIe recover config\n",
|
||||
pcie_dev->rc_idx);
|
||||
if (dev) {
|
||||
PCIE_DBG(pcie_dev, "RC%d: restore config space\n",
|
||||
pcie_dev->rc_idx);
|
||||
pci_load_and_free_saved_state(dev, &pcie_dev->saved_state);
|
||||
pci_restore_state(dev);
|
||||
}
|
||||
|
||||
msm_msi_config_access(dev_get_msi_domain(&pcie_dev->dev->dev), true);
|
||||
|
|
@ -8205,76 +8090,5 @@ int msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
|
|||
}
|
||||
EXPORT_SYMBOL(msm_pcie_deregister_event);
|
||||
|
||||
int msm_pcie_recover_config(struct pci_dev *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct msm_pcie_dev_t *pcie_dev;
|
||||
|
||||
if (dev) {
|
||||
pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
|
||||
PCIE_DBG(pcie_dev,
|
||||
"Recovery for the link of RC%d\n", pcie_dev->rc_idx);
|
||||
} else {
|
||||
pr_err("PCIe: the input pci dev is NULL.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) {
|
||||
PCIE_DBG(pcie_dev,
|
||||
"Recover config space of RC%d and its EP\n",
|
||||
pcie_dev->rc_idx);
|
||||
pcie_dev->shadow_en = false;
|
||||
PCIE_DBG(pcie_dev, "Recover RC%d\n", pcie_dev->rc_idx);
|
||||
msm_pcie_cfg_recover(pcie_dev, true);
|
||||
PCIE_DBG(pcie_dev, "Recover EP of RC%d\n", pcie_dev->rc_idx);
|
||||
msm_pcie_cfg_recover(pcie_dev, false);
|
||||
PCIE_DBG(pcie_dev,
|
||||
"Refreshing the saved config space in PCI framework for RC%d and its EP\n",
|
||||
pcie_dev->rc_idx);
|
||||
pci_save_state(pcie_dev->dev);
|
||||
pci_save_state(dev);
|
||||
pcie_dev->shadow_en = true;
|
||||
PCIE_DBG(pcie_dev, "Turn on shadow for RC%d\n",
|
||||
pcie_dev->rc_idx);
|
||||
} else {
|
||||
PCIE_ERR(pcie_dev,
|
||||
"PCIe: the link of RC%d is not up yet; can't recover config space.\n",
|
||||
pcie_dev->rc_idx);
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_pcie_recover_config);
|
||||
|
||||
int msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
|
||||
{
|
||||
int ret = 0;
|
||||
struct msm_pcie_dev_t *pcie_dev;
|
||||
|
||||
if (dev) {
|
||||
pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
|
||||
PCIE_DBG(pcie_dev,
|
||||
"User requests to %s shadow\n",
|
||||
enable ? "enable" : "disable");
|
||||
} else {
|
||||
pr_err("PCIe: the input pci dev is NULL.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
PCIE_DBG(pcie_dev,
|
||||
"The shadowing of RC%d is %s enabled currently.\n",
|
||||
pcie_dev->rc_idx, pcie_dev->shadow_en ? "" : "not");
|
||||
|
||||
pcie_dev->shadow_en = enable;
|
||||
|
||||
PCIE_DBG(pcie_dev,
|
||||
"Shadowing of RC%d is turned %s upon user's request.\n",
|
||||
pcie_dev->rc_idx, enable ? "on" : "off");
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_pcie_shadow_control);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. PCIe RC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
@ -411,6 +411,18 @@ enum qcs404_functions {
|
|||
msm_mux_blsp_i2c_sda_b2,
|
||||
msm_mux_blsp_i2c_scl_b2,
|
||||
msm_mux_pwm_led11,
|
||||
msm_mux_i2s_1_sck,
|
||||
msm_mux_i2s_1_ws,
|
||||
msm_mux_i2s_1_data0_dsd0,
|
||||
msm_mux_i2s_1_data0,
|
||||
msm_mux_i2s_1_data1_dsd1,
|
||||
msm_mux_i2s_1_data1,
|
||||
msm_mux_i2s_1_data2_dsd2,
|
||||
msm_mux_i2s_1_data2,
|
||||
msm_mux_i2s_1_data3_dsd3,
|
||||
msm_mux_i2s_1_data3,
|
||||
msm_mux_i2s_1_data4_dsd4,
|
||||
msm_mux_i2s_1_data5_dsd5,
|
||||
msm_mux_i2s_3_data0_a,
|
||||
msm_mux_ebi2_lcd,
|
||||
msm_mux_i2s_3_data1_a,
|
||||
|
|
@ -419,14 +431,25 @@ enum qcs404_functions {
|
|||
msm_mux_pwm_led3,
|
||||
msm_mux_i2s_3_data3_a,
|
||||
msm_mux_pwm_led4,
|
||||
msm_mux_i2s_4,
|
||||
msm_mux_i2s_4_sck,
|
||||
msm_mux_ebi2_a,
|
||||
msm_mux_dsd_clk_b,
|
||||
msm_mux_pwm_led5,
|
||||
msm_mux_i2s_4_ws,
|
||||
msm_mux_i2s_4_data0_dsd0,
|
||||
msm_mux_pwm_led6,
|
||||
msm_mux_i2s_4_data0,
|
||||
msm_mux_i2s_4_data1_dsd1,
|
||||
msm_mux_pwm_led7,
|
||||
msm_mux_i2s_4_data1,
|
||||
msm_mux_i2s_4_data2_dsd2,
|
||||
msm_mux_pwm_led8,
|
||||
msm_mux_i2s_4_data2,
|
||||
msm_mux_i2s_4_data3_dsd3,
|
||||
msm_mux_pwm_led24,
|
||||
msm_mux_i2s_4_data3,
|
||||
msm_mux_i2s_4_data4_dsd4,
|
||||
msm_mux_i2s_4_data5_dsd5,
|
||||
msm_mux_spkr_dac0,
|
||||
msm_mux_blsp_i2c4,
|
||||
msm_mux_pwm_led9,
|
||||
|
|
@ -547,25 +570,21 @@ static const char * const gpio_groups[] = {
|
|||
"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
|
||||
"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
|
||||
"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
|
||||
"gpio21", "gpio21", "gpio22", "gpio22", "gpio23", "gpio23", "gpio24",
|
||||
"gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
|
||||
"gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio36", "gpio36",
|
||||
"gpio36", "gpio37", "gpio37", "gpio37", "gpio38", "gpio38", "gpio38",
|
||||
"gpio39", "gpio39", "gpio40", "gpio40", "gpio41", "gpio41", "gpio41",
|
||||
"gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48",
|
||||
"gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55",
|
||||
"gpio56", "gpio57", "gpio58", "gpio59", "gpio59", "gpio60", "gpio61",
|
||||
"gpio62", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68",
|
||||
"gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75",
|
||||
"gpio76", "gpio77", "gpio77", "gpio78", "gpio78", "gpio78", "gpio79",
|
||||
"gpio79", "gpio79", "gpio80", "gpio81", "gpio81", "gpio82", "gpio83",
|
||||
"gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
|
||||
"gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97",
|
||||
"gpio98", "gpio99", "gpio100", "gpio101", "gpio102", "gpio103",
|
||||
"gpio104", "gpio105", "gpio106", "gpio107", "gpio108", "gpio108",
|
||||
"gpio108", "gpio109", "gpio109", "gpio110", "gpio111", "gpio112",
|
||||
"gpio113", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118",
|
||||
"gpio119",
|
||||
"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
|
||||
"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
|
||||
"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
|
||||
"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
|
||||
"gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
|
||||
"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
|
||||
"gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
|
||||
"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
|
||||
"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
|
||||
"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
|
||||
"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
|
||||
"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
|
||||
"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
|
||||
"gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
|
||||
"gpio117", "gpio118", "gpio119",
|
||||
};
|
||||
|
||||
static const char * const hdmi_tx_groups[] = {
|
||||
|
|
@ -816,9 +835,56 @@ static const char * const pwm_led4_groups[] = {
|
|||
"gpio109",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_groups[] = {
|
||||
"gpio110", "gpio111", "gpio111", "gpio112", "gpio112", "gpio113",
|
||||
"gpio113", "gpio114", "gpio114", "gpio115", "gpio115", "gpio116",
|
||||
static const char * const i2s_1_sck_groups[] = {
|
||||
"gpio87",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_ws_groups[] = {
|
||||
"gpio88",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data0_dsd0_groups[] = {
|
||||
"gpio88",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data0_groups[] = {
|
||||
"gpio89",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data1_dsd1_groups[] = {
|
||||
"gpio89",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data1_groups[] = {
|
||||
"gpio90",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data2_dsd2_groups[] = {
|
||||
"gpio90",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data2_groups[] = {
|
||||
"gpio91",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data3_dsd3_groups[] = {
|
||||
"gpio91",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data3_groups[] = {
|
||||
"gpio92",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data4_dsd4_groups[] = {
|
||||
"gpio92",
|
||||
};
|
||||
|
||||
static const char * const i2s_1_data5_dsd5_groups[] = {
|
||||
"gpio93",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_sck_groups[] = {
|
||||
"gpio110",
|
||||
};
|
||||
|
||||
static const char * const ebi2_a_groups[] = {
|
||||
|
|
@ -833,22 +899,66 @@ static const char * const pwm_led5_groups[] = {
|
|||
"gpio110",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_ws_groups[] = {
|
||||
"gpio111",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data0_dsd0_groups[] = {
|
||||
"gpio111",
|
||||
};
|
||||
|
||||
static const char * const pwm_led6_groups[] = {
|
||||
"gpio111",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data0_groups[] = {
|
||||
"gpio112",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data1_dsd1_groups[] = {
|
||||
"gpio112",
|
||||
};
|
||||
|
||||
static const char * const pwm_led7_groups[] = {
|
||||
"gpio112",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data1_groups[] = {
|
||||
"gpio113",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data2_dsd2_groups[] = {
|
||||
"gpio113",
|
||||
};
|
||||
|
||||
static const char * const pwm_led8_groups[] = {
|
||||
"gpio113",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data2_groups[] = {
|
||||
"gpio114",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data3_dsd3_groups[] = {
|
||||
"gpio114",
|
||||
};
|
||||
|
||||
static const char * const pwm_led24_groups[] = {
|
||||
"gpio114",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data3_groups[] = {
|
||||
"gpio115",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data4_dsd4_groups[] = {
|
||||
"gpio115",
|
||||
};
|
||||
|
||||
static const char * const i2s_4_data5_dsd5_groups[] = {
|
||||
"gpio116",
|
||||
};
|
||||
|
||||
static const char * const spkr_dac0_groups[] = {
|
||||
"gpio116",
|
||||
};
|
||||
|
|
@ -1366,14 +1476,37 @@ static const struct msm_function qcs404_functions[] = {
|
|||
FUNCTION(pwm_led3),
|
||||
FUNCTION(i2s_3_data3_a),
|
||||
FUNCTION(pwm_led4),
|
||||
FUNCTION(i2s_4),
|
||||
FUNCTION(i2s_1_sck),
|
||||
FUNCTION(i2s_4_sck),
|
||||
FUNCTION(ebi2_a),
|
||||
FUNCTION(dsd_clk_b),
|
||||
FUNCTION(pwm_led5),
|
||||
FUNCTION(i2s_1_ws),
|
||||
FUNCTION(i2s_1_data0_dsd0),
|
||||
FUNCTION(i2s_4_ws),
|
||||
FUNCTION(i2s_4_data0_dsd0),
|
||||
FUNCTION(pwm_led6),
|
||||
FUNCTION(i2s_1_data0),
|
||||
FUNCTION(i2s_1_data1_dsd1),
|
||||
FUNCTION(i2s_4_data0),
|
||||
FUNCTION(i2s_4_data1_dsd1),
|
||||
FUNCTION(pwm_led7),
|
||||
FUNCTION(i2s_1_data1),
|
||||
FUNCTION(i2s_1_data2_dsd2),
|
||||
FUNCTION(i2s_4_data1),
|
||||
FUNCTION(i2s_4_data2_dsd2),
|
||||
FUNCTION(pwm_led8),
|
||||
FUNCTION(i2s_1_data2),
|
||||
FUNCTION(i2s_1_data3_dsd3),
|
||||
FUNCTION(i2s_4_data2),
|
||||
FUNCTION(i2s_4_data3_dsd3),
|
||||
FUNCTION(pwm_led24),
|
||||
FUNCTION(i2s_1_data3),
|
||||
FUNCTION(i2s_1_data4_dsd4),
|
||||
FUNCTION(i2s_1_data5_dsd5),
|
||||
FUNCTION(i2s_4_data3),
|
||||
FUNCTION(i2s_4_data4_dsd4),
|
||||
FUNCTION(i2s_4_data5_dsd5),
|
||||
FUNCTION(spkr_dac0),
|
||||
FUNCTION(blsp_i2c4),
|
||||
FUNCTION(pwm_led9),
|
||||
|
|
@ -1582,13 +1715,16 @@ static const struct msm_pingroup qcs404_groups[] = {
|
|||
[84] = PINGROUP(84, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp1_clk_a, qdss_cti_trig_in_b1, _, _, _, _),
|
||||
[85] = PINGROUP(85, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp2_clk_a, qdss_tracedata_b, _, _, _, _),
|
||||
[86] = PINGROUP(86, EAST, ext_mclk0, mclk_in1, _, _, _, _, _, _, _),
|
||||
[87] = PINGROUP(87, EAST, i2s_1, dsd_clk_a, _, _, _, _, _, _, _),
|
||||
[88] = PINGROUP(88, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
|
||||
[89] = PINGROUP(89, EAST, i2s_1, i2s_1, _, _, _, _, _, _, qdss_tracedata_b),
|
||||
[90] = PINGROUP(90, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
|
||||
[91] = PINGROUP(91, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
|
||||
[92] = PINGROUP(92, EAST, i2s_1, i2s_1, _, _, _, _, _, qdss_cti_trig_in_a1, _),
|
||||
[93] = PINGROUP(93, EAST, i2s_1, pwm_led22, i2s_1, _, _, _, _, _, qdss_tracedata_b),
|
||||
[87] = PINGROUP(87, EAST, i2s_1_sck, dsd_clk_a, _, _, _, _, _, _, _),
|
||||
[88] = PINGROUP(88, EAST, i2s_1_ws, i2s_1_data0_dsd0, _, _, _, _, _, _, _),
|
||||
[89] = PINGROUP(89, EAST, i2s_1_data0, i2s_1_data1_dsd1, _, _, _, _, _, _,
|
||||
qdss_tracedata_b),
|
||||
[90] = PINGROUP(90, EAST, i2s_1_data1, i2s_1_data2_dsd2, _, _, _, _, _, _, _),
|
||||
[91] = PINGROUP(91, EAST, i2s_1_data2, i2s_1_data3_dsd3, _, _, _, _, _, _, _),
|
||||
[92] = PINGROUP(92, EAST, i2s_1_data3, i2s_1_data4_dsd4, _, _, _, _, _,
|
||||
qdss_cti_trig_in_a1, _),
|
||||
[93] = PINGROUP(93, EAST, i2s_1_data5_dsd5, pwm_led22, i2s_1, _, _, _, _, _,
|
||||
qdss_tracedata_b),
|
||||
[94] = PINGROUP(94, EAST, i2s_1, pwm_led23, i2s_1, _, qdss_cti_trig_out_a0, _, rgmi_dll2, _, _),
|
||||
[95] = PINGROUP(95, EAST, i2s_1, pwm_led1, i2s_1, _, qdss_cti_trig_out_a1, _, _, _, _),
|
||||
[96] = PINGROUP(96, EAST, i2s_1, pwm_led2, _, _, _, _, _, _, _),
|
||||
|
|
@ -1605,13 +1741,13 @@ static const struct msm_pingroup qcs404_groups[] = {
|
|||
[107] = PINGROUP(107, EAST, i2s_3_data1_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _),
|
||||
[108] = PINGROUP(108, EAST, i2s_3_data2_a, ebi2_lcd, atest_char, pwm_led3, ebi_cdc, _, _, _, _),
|
||||
[109] = PINGROUP(109, EAST, i2s_3_data3_a, ebi2_lcd, pwm_led4, bimc_dte1, _, _, _, _, _),
|
||||
[110] = PINGROUP(110, EAST, i2s_4, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _),
|
||||
[111] = PINGROUP(111, EAST, i2s_4, i2s_4, pwm_led6, ebi_cdc, _, _, _, _, _),
|
||||
[112] = PINGROUP(112, EAST, i2s_4, i2s_4, pwm_led7, _, _, _, _, _, _),
|
||||
[113] = PINGROUP(113, EAST, i2s_4, i2s_4, pwm_led8, _, _, _, _, _, _),
|
||||
[114] = PINGROUP(114, EAST, i2s_4, i2s_4, pwm_led24, _, _, _, _, _, _),
|
||||
[115] = PINGROUP(115, EAST, i2s_4, i2s_4, _, _, _, _, _, _, _),
|
||||
[116] = PINGROUP(116, EAST, i2s_4, spkr_dac0, _, _, _, _, _, _, _),
|
||||
[110] = PINGROUP(110, EAST, i2s_4_sck, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _),
|
||||
[111] = PINGROUP(111, EAST, i2s_4_ws, i2s_4_data0_dsd0, pwm_led6, ebi_cdc, _, _, _, _, _),
|
||||
[112] = PINGROUP(112, EAST, i2s_4_data0, i2s_4_data1_dsd1, pwm_led7, _, _, _, _, _, _),
|
||||
[113] = PINGROUP(113, EAST, i2s_4_data1, i2s_4_data2_dsd2, pwm_led8, _, _, _, _, _, _),
|
||||
[114] = PINGROUP(114, EAST, i2s_4_data2, i2s_4_data3_dsd3, pwm_led24, _, _, _, _, _, _),
|
||||
[115] = PINGROUP(115, EAST, i2s_4_data3, i2s_4_data4_dsd4, _, _, _, _, _, _, _),
|
||||
[116] = PINGROUP(116, EAST, i2s_4_data5_dsd5, spkr_dac0, _, _, _, _, _, _, _),
|
||||
[117] = PINGROUP(117, NORTH, blsp_i2c4, blsp_spi4, pwm_led9, _, _, _, _, _, _),
|
||||
[118] = PINGROUP(118, NORTH, blsp_i2c4, blsp_spi4, pwm_led10, _, _, _, _, _, _),
|
||||
[119] = PINGROUP(119, EAST, spdifrx_opt, _, _, _, _, _, _, _, _),
|
||||
|
|
|
|||
|
|
@ -1044,12 +1044,13 @@ static const struct msm_gpio_wakeirq_map sdxlemur_pdc_map[] = {
|
|||
{1, 20}, {2, 21}, {5, 22}, {6, 23}, {9, 24}, {10, 25},
|
||||
{11, 26}, {12, 27}, {13, 28}, {14, 29}, {15, 30}, {16, 31},
|
||||
{17, 32}, {18, 33}, {19, 34}, {21, 35}, {22, 36}, {23, 70},
|
||||
{24, 37}, {25, 38}, {35, 40}, {43, 41}, {46, 44}, {48, 45},
|
||||
{49, 57}, {50, 46}, {52, 47}, {54, 49}, {55, 50}, {60, 53},
|
||||
{24, 37}, {25, 38}, {32, 39}, {35, 40}, {43, 41}, {44, 42},
|
||||
{45, 43}, {46, 44}, {48, 45}, {49, 57}, {50, 46}, {52, 47},
|
||||
{53, 48}, {54, 49}, {55, 50}, {56, 51}, {57, 52}, {60, 53},
|
||||
{61, 54}, {64, 55}, {65, 81}, {68, 56}, {71, 58}, {73, 59},
|
||||
{77, 77}, {81, 65}, {83, 63}, {84, 64}, {86, 66}, {88, 67},
|
||||
{89, 68}, {90, 69}, {93, 71}, {94, 72}, {95, 73}, {96, 74},
|
||||
{99, 75}, {103, 78}, {104, 79}
|
||||
{76, 60}, {77, 77}, {78, 61}, {79, 62}, {81, 65}, {83, 63},
|
||||
{84, 64}, {86, 66}, {88, 67}, {89, 68}, {90, 69}, {93, 71},
|
||||
{94, 72}, {95, 73}, {96, 74}, {99, 75}, {103, 78}, {104, 79},
|
||||
};
|
||||
|
||||
static const struct msm_pinctrl_soc_data sdxlemur_pinctrl = {
|
||||
|
|
|
|||
|
|
@ -251,6 +251,9 @@ struct ipa_fmwk_contex {
|
|||
int (*ipa_usb_xdci_resume)(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
||||
enum ipa_usb_teth_prot teth_prot);
|
||||
|
||||
bool (*ipa_usb_is_teth_prot_connected)(
|
||||
enum ipa_usb_teth_prot usb_teth_prot);
|
||||
|
||||
/* ipa_wdi3 APIs */
|
||||
int (*ipa_wdi_init)(struct ipa_wdi_init_in_params *in,
|
||||
struct ipa_wdi_init_out_params *out);
|
||||
|
|
@ -309,6 +312,8 @@ struct ipa_fmwk_contex {
|
|||
|
||||
int (*ipa_dereg_uc_rdyCB)(void);
|
||||
|
||||
bool (*ipa_wdi_is_tx1_used)(void);
|
||||
|
||||
/* ipa_gsb APIs*/
|
||||
int (*ipa_bridge_init)(struct ipa_bridge_init_params *params, u32 *hdl);
|
||||
|
||||
|
|
@ -425,8 +430,15 @@ struct ipa_fmwk_contex {
|
|||
int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg);
|
||||
|
||||
int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg);
|
||||
|
||||
int (*ipa_get_default_aggr_time_limit)(enum ipa_client_type client,
|
||||
u32 *default_aggr_time_limit);
|
||||
|
||||
enum ipa_client_type (*ipa_eth_get_ipa_client_type_from_eth_type)(
|
||||
enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir);
|
||||
|
||||
bool (*ipa_eth_client_exist)(
|
||||
enum ipa_eth_client_type eth_client_type, int inst_id);
|
||||
};
|
||||
|
||||
static struct ipa_fmwk_contex *ipa_fmwk_ctx;
|
||||
|
|
@ -1056,7 +1068,8 @@ int ipa_fmwk_register_ipa_usb(const struct ipa_usb_data *in)
|
|||
ipa_fmwk_ctx->ipa_usb_xdci_disconnect ||
|
||||
ipa_fmwk_ctx->ipa_usb_deinit_teth_prot ||
|
||||
ipa_fmwk_ctx->ipa_usb_xdci_suspend ||
|
||||
ipa_fmwk_ctx->ipa_usb_xdci_resume) {
|
||||
ipa_fmwk_ctx->ipa_usb_xdci_resume ||
|
||||
ipa_fmwk_ctx->ipa_usb_is_teth_prot_connected) {
|
||||
pr_err("ipa_usb APIs were already initialized\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
|
@ -1066,6 +1079,8 @@ int ipa_fmwk_register_ipa_usb(const struct ipa_usb_data *in)
|
|||
ipa_fmwk_ctx->ipa_usb_deinit_teth_prot = in->ipa_usb_deinit_teth_prot;
|
||||
ipa_fmwk_ctx->ipa_usb_xdci_suspend = in->ipa_usb_xdci_suspend;
|
||||
ipa_fmwk_ctx->ipa_usb_xdci_resume = in->ipa_usb_xdci_resume;
|
||||
ipa_fmwk_ctx->ipa_usb_is_teth_prot_connected =
|
||||
in->ipa_usb_is_teth_prot_connected;
|
||||
|
||||
pr_info("ipa_usb registered successfully\n");
|
||||
|
||||
|
|
@ -1153,6 +1168,17 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
|||
}
|
||||
EXPORT_SYMBOL(ipa_usb_xdci_resume);
|
||||
|
||||
bool ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPA_FMWK_DISPATCH_RETURN(ipa_usb_is_teth_prot_connected,
|
||||
usb_teth_prot);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_usb_is_teth_prot_connected);
|
||||
|
||||
/* registration API for IPA wdi3 module */
|
||||
int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in)
|
||||
{
|
||||
|
|
@ -1175,7 +1201,8 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in)
|
|||
|| ipa_fmwk_ctx->ipa_wdi_release_smmu_mapping
|
||||
|| ipa_fmwk_ctx->ipa_wdi_get_stats
|
||||
|| ipa_fmwk_ctx->ipa_get_wdi_version
|
||||
|| ipa_fmwk_ctx->ipa_wdi_sw_stats) {
|
||||
|| ipa_fmwk_ctx->ipa_wdi_sw_stats
|
||||
|| ipa_fmwk_ctx->ipa_wdi_is_tx1_used) {
|
||||
pr_err("ipa_wdi3 APIs were already initialized\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
|
@ -1197,6 +1224,7 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in)
|
|||
ipa_fmwk_ctx->ipa_wdi_get_stats = in->ipa_wdi_get_stats;
|
||||
ipa_fmwk_ctx->ipa_wdi_sw_stats = in->ipa_wdi_sw_stats;
|
||||
ipa_fmwk_ctx->ipa_get_wdi_version = in->ipa_get_wdi_version;
|
||||
ipa_fmwk_ctx->ipa_wdi_is_tx1_used = in->ipa_wdi_is_tx1_used;
|
||||
|
||||
pr_info("ipa_wdi3 registered successfully\n");
|
||||
|
||||
|
|
@ -1217,6 +1245,16 @@ int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
|
|||
}
|
||||
EXPORT_SYMBOL(ipa_wdi_init);
|
||||
|
||||
bool ipa_wdi_is_tx1_used(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_is_tx1_used);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_wdi_is_tx1_used);
|
||||
|
||||
int ipa_wdi_cleanup(void)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -2125,7 +2163,9 @@ int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in)
|
|||
|| ipa_fmwk_ctx->ipa_eth_client_unreg_intf
|
||||
|| ipa_fmwk_ctx->ipa_eth_client_set_perf_profile
|
||||
|| ipa_fmwk_ctx->ipa_eth_client_conn_evt
|
||||
|| ipa_fmwk_ctx->ipa_eth_client_disconn_evt) {
|
||||
|| ipa_fmwk_ctx->ipa_eth_client_disconn_evt
|
||||
|| ipa_fmwk_ctx->ipa_eth_get_ipa_client_type_from_eth_type
|
||||
|| ipa_fmwk_ctx->ipa_eth_client_exist) {
|
||||
pr_err("ipa_eth APIs were already initialized\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
|
@ -2143,6 +2183,10 @@ int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in)
|
|||
ipa_fmwk_ctx->ipa_eth_client_conn_evt = in->ipa_eth_client_conn_evt;
|
||||
ipa_fmwk_ctx->ipa_eth_client_disconn_evt =
|
||||
in->ipa_eth_client_disconn_evt;
|
||||
ipa_fmwk_ctx->ipa_eth_get_ipa_client_type_from_eth_type =
|
||||
in->ipa_eth_get_ipa_client_type_from_eth_type;
|
||||
ipa_fmwk_ctx->ipa_eth_client_exist =
|
||||
in->ipa_eth_client_exist;
|
||||
|
||||
pr_info("ipa_eth registered successfully\n");
|
||||
|
||||
|
|
@ -2275,6 +2319,30 @@ int ipa_get_default_aggr_time_limit(enum ipa_client_type client,
|
|||
}
|
||||
EXPORT_SYMBOL(ipa_get_default_aggr_time_limit);
|
||||
|
||||
enum ipa_client_type ipa_eth_get_ipa_client_type_from_eth_type(
|
||||
enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_get_ipa_client_type_from_eth_type,
|
||||
eth_client_type, dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_eth_get_ipa_client_type_from_eth_type);
|
||||
|
||||
bool ipa_eth_client_exist(
|
||||
enum ipa_eth_client_type eth_client_type, int inst_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_exist,
|
||||
eth_client_type, inst_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipa_eth_client_exist);
|
||||
|
||||
/* module functions */
|
||||
static int __init ipa_fmwk_init(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ static void mhi_dev_cmd_event_msi_cb(void *req);
|
|||
|
||||
static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi);
|
||||
|
||||
static int mhi_dev_ring_init(struct mhi_dev *dev);
|
||||
|
||||
static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
|
||||
static DECLARE_COMPLETION(read_from_host);
|
||||
|
|
@ -476,6 +477,22 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
|
||||
if (!ereq->is_cmd_cpl) {
|
||||
ch = ereq->context;
|
||||
/*
|
||||
* Take Channel ring event lock to prevent sending
|
||||
* completion command while the channel is getting
|
||||
* reset/stopped.
|
||||
* Abort sending completion event if channel has moved to
|
||||
* stopped state.
|
||||
*/
|
||||
mutex_lock(&ch->ring->event_lock);
|
||||
if (ch->state == MHI_DEV_CH_STOPPED ||
|
||||
ch->state == MHI_DEV_CH_PENDING_STOP) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Ch:%d is in %d state, abort sending completion evnt\n"
|
||||
, ch->ch_id, ch->state);
|
||||
rc = -ENXIO;
|
||||
goto exit;
|
||||
}
|
||||
mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
|
||||
ereq->num_events, ch->ch_id);
|
||||
} else {
|
||||
|
|
@ -487,8 +504,7 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
|
||||
if (rc) {
|
||||
pr_err("%s(): error in adding element rc %d\n", __func__, rc);
|
||||
mutex_unlock(&ring->event_lock);
|
||||
return rc;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
|
||||
|
|
@ -537,6 +553,9 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
pr_err("%s: error sending in msi\n", __func__);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (!ereq->is_cmd_cpl)
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ring->event_lock);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -597,18 +616,21 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
|
|||
unsigned long flags;
|
||||
struct event_req *flush_ereq;
|
||||
|
||||
/*
|
||||
* Channel got stopped or closed with transfers pending
|
||||
* Do not send completion events to host
|
||||
*/
|
||||
if (ch->state == MHI_DEV_CH_CLOSED ||
|
||||
ch->state == MHI_DEV_CH_STOPPED) {
|
||||
mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n",
|
||||
ch->ch_id, ch->pend_wr_count + 1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
/*
|
||||
* Channel got stopped or closed with transfers pending
|
||||
* Do not send completion events to host
|
||||
*/
|
||||
if (ch->state == MHI_DEV_CH_CLOSED ||
|
||||
ch->state == MHI_DEV_CH_STOPPED) {
|
||||
mhi_log(MHI_MSG_DBG,
|
||||
"Ch %d closed with %d writes pending\n",
|
||||
ch->ch_id, ch->pend_wr_count + 1);
|
||||
rc = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mhi->lock, flags);
|
||||
if (list_empty(&ch->flush_event_req_buffers)) {
|
||||
spin_unlock_irqrestore(&mhi->lock, flags);
|
||||
|
|
@ -634,7 +656,8 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
|
|||
"Invalid cmpl evt buf - start %pK, end %pK\n",
|
||||
flush_ereq->tr_events,
|
||||
flush_ereq->tr_events + flush_ereq->num_events);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
rc = mhi_dev_send_multiple_tr_events(mhi,
|
||||
mhi->ch_ctx_cache[ch->ch_id].err_indx,
|
||||
|
|
@ -1326,13 +1349,7 @@ static int mhi_enable_int(void)
|
|||
int rc = 0;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Enable chdb, ctrl and cmdb interrupts\n");
|
||||
|
||||
rc = mhi_dev_mmio_enable_chdb_interrupts(mhi_ctx);
|
||||
if (rc) {
|
||||
pr_err("Failed to enable channel db: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
"Enable ctrl and cmdb interrupts\n");
|
||||
|
||||
rc = mhi_dev_mmio_enable_ctrl_interrupt(mhi_ctx);
|
||||
if (rc) {
|
||||
|
|
@ -1599,7 +1616,7 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,
|
|||
}
|
||||
}
|
||||
|
||||
mutex_lock(&mhi->mhi_event_lock);
|
||||
mutex_lock(&ring->event_lock);
|
||||
/* add the ring element */
|
||||
mhi_dev_add_element(ring, el, NULL, 0);
|
||||
|
||||
|
|
@ -1632,7 +1649,6 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,
|
|||
*/
|
||||
wmb();
|
||||
|
||||
mutex_unlock(&mhi->mhi_event_lock);
|
||||
mhi_log(MHI_MSG_VERBOSE, "event sent:\n");
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr);
|
||||
mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n", el->evt_tr_comp.len);
|
||||
|
|
@ -1645,6 +1661,7 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,
|
|||
else
|
||||
rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
|
||||
|
||||
mutex_unlock(&ring->event_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1811,7 +1828,57 @@ static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
|
|||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
}
|
||||
|
||||
static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
||||
static void mhi_dev_process_reset_cmd(struct mhi_dev *mhi, int ch_id)
|
||||
{
|
||||
int rc = 0;
|
||||
struct mhi_dev_channel *ch;
|
||||
struct mhi_addr host_addr;
|
||||
|
||||
rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_id);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Failed to disable chdb for ch %d\n", ch_id);
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED);
|
||||
if (rc)
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Error with compl event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ch = &mhi->ch[ch_id];
|
||||
/* hard stop and set the channel to stop */
|
||||
mhi->ch_ctx_cache[ch_id].ch_state =
|
||||
MHI_DEV_CH_STATE_DISABLED;
|
||||
mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
|
||||
|
||||
if (mhi->use_ipa)
|
||||
host_addr.host_pa =
|
||||
mhi->ch_ctx_shadow.host_pa +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
else
|
||||
host_addr.device_va =
|
||||
mhi->ch_ctx_shadow.device_va +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
|
||||
host_addr.virt_addr =
|
||||
&mhi->ch_ctx_cache[ch_id].ch_state;
|
||||
host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
|
||||
|
||||
/* update the channel state in the host */
|
||||
mhi_ctx->write_to_host(mhi, &host_addr, NULL,
|
||||
MHI_DEV_DMA_SYNC);
|
||||
|
||||
/* send the completion event to the host */
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
if (rc)
|
||||
pr_err("Error sending command completion event\n");
|
||||
|
||||
ch->reset_pending = false;
|
||||
}
|
||||
|
||||
static int mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
||||
union mhi_dev_ring_element_type *el, void *ctx)
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
@ -1828,7 +1895,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
|||
|
||||
switch (el->generic.type) {
|
||||
case MHI_DEV_RING_EL_START:
|
||||
mhi_log(MHI_MSG_VERBOSE, "recived start cmd for channel %d\n",
|
||||
mhi_log(MHI_MSG_VERBOSE, "received start cmd for channel %d\n",
|
||||
ch_id);
|
||||
if (ch_id >= (HW_CHANNEL_BASE)) {
|
||||
rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type);
|
||||
|
|
@ -1836,13 +1903,26 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
|||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error with HW channel cmd %d\n", rc);
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED);
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED);
|
||||
if (rc)
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error with compl event\n");
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
goto send_start_completion_event;
|
||||
} else {
|
||||
rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch_id);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Failed to enable chdb for ch %d\n",
|
||||
ch_id);
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED);
|
||||
if (rc)
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Error with compl event\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* fetch the channel context from host */
|
||||
|
|
@ -1860,7 +1940,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
|||
if (rc)
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error with compl event\n");
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
|
||||
mhi->ring[mhi->ch_ring_start + ch_id].state =
|
||||
|
|
@ -1873,18 +1953,6 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
|||
mhi->ch[ch_id].ring = &mhi->ring[mhi->ch_ring_start + ch_id];
|
||||
mhi->ch[ch_id].ch_type = mhi->ch_ctx_cache[ch_id].ch_type;
|
||||
|
||||
/* enable DB for event ring */
|
||||
rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch_id);
|
||||
if (rc) {
|
||||
pr_err("Failed to enable channel db\n");
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED);
|
||||
if (rc)
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error with compl event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mhi->use_edma || mhi->use_ipa) {
|
||||
uint32_t evnt_ring_idx = mhi->ev_ring_start +
|
||||
mhi->ch_ctx_cache[ch_id].err_indx;
|
||||
|
|
@ -1898,7 +1966,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
|||
mhi_log(MHI_MSG_ERROR,
|
||||
"error starting event ring %d\n",
|
||||
mhi->ch_ctx_cache[ch_id].err_indx);
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
mutex_lock(&mhi->ch[ch_id].ch_lock);
|
||||
|
|
@ -1953,7 +2021,7 @@ send_start_completion_event:
|
|||
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
if (rc) {
|
||||
pr_err("stop event send failed\n");
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -1966,12 +2034,13 @@ send_start_completion_event:
|
|||
ring = &mhi->ring[ch_id + mhi->ch_ring_start];
|
||||
if (ring->state == RING_STATE_UINT) {
|
||||
pr_err("Channel not opened for %d\n", ch_id);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch = &mhi->ch[ch_id];
|
||||
|
||||
mutex_lock(&ch->ch_lock);
|
||||
mutex_lock(&ch->ring->event_lock);
|
||||
|
||||
mhi->ch[ch_id].state = MHI_DEV_CH_PENDING_STOP;
|
||||
rc = mhi_dev_process_stop_cmd(
|
||||
|
|
@ -1980,6 +2049,7 @@ send_start_completion_event:
|
|||
if (rc)
|
||||
pr_err("stop event send failed\n");
|
||||
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED);
|
||||
/* Trigger callback to clients */
|
||||
|
|
@ -2013,7 +2083,7 @@ send_start_completion_event:
|
|||
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
if (rc) {
|
||||
pr_err("stop event send failed\n");
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
@ -2024,39 +2094,23 @@ send_start_completion_event:
|
|||
ring = &mhi->ring[ch_id + mhi->ch_ring_start];
|
||||
if (ring->state == RING_STATE_UINT) {
|
||||
pr_err("Channel not opened for %d\n", ch_id);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch = &mhi->ch[ch_id];
|
||||
|
||||
mutex_lock(&ch->ch_lock);
|
||||
|
||||
/* hard stop and set the channel to stop */
|
||||
mhi->ch_ctx_cache[ch_id].ch_state =
|
||||
MHI_DEV_CH_STATE_DISABLED;
|
||||
mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
|
||||
if (MHI_USE_DMA(mhi))
|
||||
host_addr.host_pa =
|
||||
mhi->ch_ctx_shadow.host_pa +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
else
|
||||
host_addr.device_va =
|
||||
mhi->ch_ctx_shadow.device_va +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
|
||||
host_addr.virt_addr =
|
||||
&mhi->ch_ctx_cache[ch_id].ch_state;
|
||||
host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
|
||||
|
||||
/* update the channel state in the host */
|
||||
mhi_ctx->write_to_host(mhi, &host_addr, NULL,
|
||||
MHI_DEV_DMA_SYNC);
|
||||
|
||||
/* send the completion event to the host */
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
if (rc)
|
||||
pr_err("Error sending command completion event\n");
|
||||
mutex_lock(&ch->ring->event_lock);
|
||||
if (ch->db_pending) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"skipping reset cmd ack for channel %d\n",
|
||||
ch_id);
|
||||
ch->reset_pending = true;
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
rc = -EBUSY;
|
||||
return rc;
|
||||
}
|
||||
mhi_dev_process_reset_cmd(mhi, ch_id);
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED);
|
||||
mhi_dev_trigger_cb(ch_id);
|
||||
|
|
@ -2068,9 +2122,10 @@ send_start_completion_event:
|
|||
pr_err("%s: Invalid command:%d\n", __func__, el->generic.type);
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void mhi_dev_process_tre_ring(struct mhi_dev *mhi,
|
||||
static int mhi_dev_process_tre_ring(struct mhi_dev *mhi,
|
||||
union mhi_dev_ring_element_type *el, void *ctx)
|
||||
{
|
||||
struct mhi_dev_ring *ring = (struct mhi_dev_ring *)ctx;
|
||||
|
|
@ -2081,7 +2136,7 @@ static void mhi_dev_process_tre_ring(struct mhi_dev *mhi,
|
|||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"invalid channel ring id (%d), should be < %lu\n",
|
||||
ring->id, mhi->ch_ring_start);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch = &mhi->ch[ring->id - mhi->ch_ring_start];
|
||||
|
|
@ -2095,6 +2150,7 @@ static void mhi_dev_process_tre_ring(struct mhi_dev *mhi,
|
|||
*/
|
||||
if (ch->active_client && ch->active_client->event_trigger != NULL)
|
||||
ch->active_client->event_trigger(&reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mhi_dev_process_ring_pending(struct work_struct *work)
|
||||
|
|
@ -2104,11 +2160,12 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
struct list_head *cp, *q;
|
||||
struct mhi_dev_ring *ring;
|
||||
struct mhi_dev_channel *ch;
|
||||
int rc = 0;
|
||||
int rc = 0, ch_id;
|
||||
|
||||
mutex_lock(&mhi_ctx->mhi_lock);
|
||||
|
||||
rc = mhi_dev_process_ring(&mhi->ring[mhi->cmd_ring_idx]);
|
||||
if (rc) {
|
||||
if (rc && rc != -EBUSY) {
|
||||
mhi_log(MHI_MSG_ERROR, "error processing command ring\n");
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -2117,12 +2174,6 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
ring = list_entry(cp, struct mhi_dev_ring, list);
|
||||
list_del(cp);
|
||||
mhi_log(MHI_MSG_VERBOSE, "processing ring %d\n", ring->id);
|
||||
rc = mhi_dev_process_ring(ring);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error processing ring %d\n", ring->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ring->id < mhi->ch_ring_start) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
|
|
@ -2131,10 +2182,40 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
}
|
||||
|
||||
ch = &mhi->ch[ring->id - mhi->ch_ring_start];
|
||||
|
||||
rc = mhi_dev_process_ring(ring);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error processing ring %d\n", ring->id);
|
||||
goto exit;
|
||||
}
|
||||
mutex_lock(&ch->ch_lock);
|
||||
ch->db_pending = false;
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
|
||||
if (ch->reset_pending) {
|
||||
/*
|
||||
* The channel might be reset asynchronously by the
|
||||
* host, below reset ack is in case the channel
|
||||
* was stopped/reset with pending DB.
|
||||
*/
|
||||
ch_id = ch->ch_id;
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"processing pending ch:%d reset\n", ch_id);
|
||||
rc = mhi_dev_process_ring(
|
||||
&mhi->ring[mhi->cmd_ring_idx]);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error processing command ring\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch->ch_id);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error enabling chdb interrupt for %d\n", ch->ch_id);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
|
@ -2169,10 +2250,12 @@ static int mhi_dev_get_event_notify(enum mhi_dev_state state,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void mhi_dev_queue_channel_db(struct mhi_dev *mhi,
|
||||
static bool mhi_dev_queue_channel_db(struct mhi_dev *mhi,
|
||||
uint32_t chintr_value, uint32_t ch_num)
|
||||
{
|
||||
struct mhi_dev_ring *ring;
|
||||
struct mhi_dev_channel *ch;
|
||||
bool work_pending = false;
|
||||
int rc = 0;
|
||||
|
||||
for (; chintr_value; ch_num++, chintr_value >>= 1) {
|
||||
|
|
@ -2184,25 +2267,40 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi,
|
|||
}
|
||||
mhi_ring_set_state(ring, RING_STATE_PENDING);
|
||||
list_add(&ring->list, &mhi->process_ring_list);
|
||||
ch = &mhi->ch[ch_num];
|
||||
mutex_lock(&ch->ch_lock);
|
||||
ch->db_pending = true;
|
||||
work_pending = true;
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_num);
|
||||
if (rc) {
|
||||
pr_err("Error disabling chdb\n");
|
||||
return;
|
||||
return work_pending;
|
||||
}
|
||||
queue_work(mhi->pending_ring_wq, &mhi->pending_work);
|
||||
}
|
||||
}
|
||||
return work_pending;
|
||||
}
|
||||
|
||||
static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi)
|
||||
/*
|
||||
* mhi_dev_check_channel_interrupt () - function called
|
||||
* to check if CH DB interrupts are present to process.
|
||||
*
|
||||
* Return : true if valid interrupts are present
|
||||
* to process, false if not.
|
||||
*/
|
||||
|
||||
static bool mhi_dev_check_channel_interrupt(struct mhi_dev *mhi)
|
||||
{
|
||||
int i, rc = 0;
|
||||
bool pending_work = false;
|
||||
uint32_t chintr_value = 0, ch_num = 0;
|
||||
|
||||
rc = mhi_dev_mmio_read_chdb_status_interrupts(mhi);
|
||||
if (rc) {
|
||||
pr_err("Read channel db\n");
|
||||
return;
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error while reading CH DB\n");
|
||||
return pending_work;
|
||||
}
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) {
|
||||
|
|
@ -2213,15 +2311,18 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi)
|
|||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"processing id: %d, ch interrupt 0x%x\n",
|
||||
i, chintr_value);
|
||||
mhi_dev_queue_channel_db(mhi, chintr_value, ch_num);
|
||||
pending_work |= mhi_dev_queue_channel_db(mhi,
|
||||
chintr_value, ch_num);
|
||||
rc = mhi_dev_mmio_write(mhi, MHI_CHDB_INT_CLEAR_A7_n(i),
|
||||
mhi->chdb[i].status);
|
||||
if (rc) {
|
||||
pr_err("Error writing interrupt clear for A7\n");
|
||||
return;
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Error writing interrupt clear for A7\n");
|
||||
return pending_work;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pending_work;
|
||||
}
|
||||
|
||||
static void mhi_update_state_info_all(enum mhi_ctrl_info info)
|
||||
|
|
@ -2361,6 +2462,7 @@ static void mhi_dev_transfer_completion_cb(void *mreq)
|
|||
/* Trigger client call back */
|
||||
req->client_cb(req);
|
||||
|
||||
mutex_lock(&ch->ch_lock);
|
||||
/* Flush read completions to host */
|
||||
if (snd_cmpl && mhi_ctx->ch_ctx_cache[ch->ch_id].ch_type ==
|
||||
MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL) {
|
||||
|
|
@ -2371,7 +2473,7 @@ static void mhi_dev_transfer_completion_cb(void *mreq)
|
|||
"Failed to flush read completions to host\n");
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
if (ch->state == MHI_DEV_CH_PENDING_STOP) {
|
||||
ch->state = MHI_DEV_CH_STOPPED;
|
||||
rc = mhi_dev_process_stop_cmd(ch->ring, ch->ch_id, mhi_ctx);
|
||||
|
|
@ -2386,6 +2488,7 @@ static void mhi_dev_scheduler(struct work_struct *work)
|
|||
struct mhi_dev *mhi = container_of(work,
|
||||
struct mhi_dev, chdb_ctrl_work);
|
||||
int rc = 0;
|
||||
bool work_pending = false;
|
||||
uint32_t int_value = 0;
|
||||
struct mhi_dev_ring *ring;
|
||||
enum mhi_dev_state state;
|
||||
|
|
@ -2439,11 +2542,13 @@ static void mhi_dev_scheduler(struct work_struct *work)
|
|||
"processing cmd db interrupt with %d\n", int_value);
|
||||
ring = &mhi->ring[MHI_RING_CMD_ID];
|
||||
ring->state = RING_STATE_PENDING;
|
||||
queue_work(mhi->pending_ring_wq, &mhi->pending_work);
|
||||
work_pending = true;
|
||||
}
|
||||
|
||||
/* get the specific channel interrupts */
|
||||
mhi_dev_check_channel_interrupt(mhi);
|
||||
work_pending |= mhi_dev_check_channel_interrupt(mhi);
|
||||
if (work_pending)
|
||||
queue_work(mhi->pending_ring_wq, &mhi->pending_work);
|
||||
|
||||
fail:
|
||||
mutex_unlock(&mhi_ctx->mhi_lock);
|
||||
|
|
@ -2598,6 +2703,25 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi)
|
|||
mhi->cfg.event_rings;
|
||||
mhi->ch_ctx_shadow.size = sizeof(struct mhi_dev_ch_ctx) *
|
||||
mhi->cfg.channels;
|
||||
|
||||
/* Allocate ring elements, during M0 when host
|
||||
* would have updated MHICFG register
|
||||
*/
|
||||
|
||||
if (!mhi->ring) {
|
||||
mhi->ring = devm_kcalloc(&pdev->dev,
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings+1),
|
||||
sizeof(struct mhi_dev_ring),
|
||||
GFP_KERNEL);
|
||||
if (!mhi->ring) {
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_ALLOC: size:%d RING_ALLOC\n",
|
||||
(sizeof(struct mhi_dev_ring) *
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings + 1)));
|
||||
}
|
||||
/*
|
||||
* This func mhi_dev_cache_host_cfg will be called when
|
||||
* processing mhi device reset as well, do not allocate
|
||||
|
|
@ -2644,6 +2768,13 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi)
|
|||
}
|
||||
memset(mhi->ch_ctx_cache, 0, sizeof(struct mhi_dev_ch_ctx) *
|
||||
mhi->cfg.channels);
|
||||
|
||||
rc = mhi_dev_ring_init(mhi);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_VERBOSE, "MHI dev ring init failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (MHI_USE_DMA(mhi)) {
|
||||
data_transfer.phy_addr = mhi->cmd_ctx_cache_dma_handle;
|
||||
data_transfer.host_pa = mhi->cmd_ctx_shadow.host_pa;
|
||||
|
|
@ -2674,21 +2805,43 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi)
|
|||
mhi->ev_ctx_cache->rp,
|
||||
mhi->ev_ctx_cache->wp);
|
||||
|
||||
return mhi_ring_start(&mhi->ring[0],
|
||||
rc = mhi_ring_start(&mhi->ring[0],
|
||||
(union mhi_dev_ring_ctx *)mhi->cmd_ctx_cache, mhi);
|
||||
if (rc) {
|
||||
pr_err("MHI ring start failed:%d\n", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
if (mhi->cmd_ctx_cache)
|
||||
if (mhi->ring) {
|
||||
devm_kfree(&pdev->dev, mhi->ring);
|
||||
mhi->ring = NULL;
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC: size:%d RING_ALLOC\n",
|
||||
(sizeof(struct mhi_dev_ring) *
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings + 1)));
|
||||
}
|
||||
if (mhi->cmd_ctx_cache) {
|
||||
dma_free_coherent(&pdev->dev,
|
||||
sizeof(struct mhi_dev_cmd_ctx),
|
||||
mhi->cmd_ctx_cache,
|
||||
mhi->cmd_ctx_cache_dma_handle);
|
||||
if (mhi->ev_ctx_cache)
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC: size:%d CMD_CTX_CACHE\n",
|
||||
sizeof(struct mhi_dev_cmd_ctx));
|
||||
}
|
||||
if (mhi->ev_ctx_cache) {
|
||||
dma_free_coherent(&pdev->dev,
|
||||
sizeof(struct mhi_dev_ev_ctx) *
|
||||
mhi->cfg.event_rings,
|
||||
mhi->ev_ctx_cache,
|
||||
mhi->ev_ctx_cache_dma_handle);
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC: size:%d EV_CTX_CACHE\n",
|
||||
sizeof(struct mhi_dev_ev_ctx) *
|
||||
mhi->cfg.event_rings);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -2839,8 +2992,8 @@ static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi)
|
|||
sizeof(*cmd_ctx->ereqs),
|
||||
GFP_KERNEL);
|
||||
if (!cmd_ctx->ereqs) {
|
||||
rc = -ENOMEM;
|
||||
goto free_ereqs;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate buffers to queue transfer completion events */
|
||||
|
|
@ -2869,9 +3022,13 @@ static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi)
|
|||
|
||||
return 0;
|
||||
free_ereqs:
|
||||
kfree(mhi->cmd_ctx);
|
||||
kfree(cmd_ctx->ereqs);
|
||||
cmd_ctx->ereqs = NULL;
|
||||
|
||||
kfree(mhi->cmd_ctx);
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC: size:%d CMD_CTX\n",
|
||||
sizeof(struct mhi_cmd_cmpl_ctx));
|
||||
mhi->cmd_ctx = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -3066,7 +3223,8 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
|
|||
ch = handle->channel;
|
||||
|
||||
do {
|
||||
if (ch->pend_wr_count) {
|
||||
if (ch->pend_wr_count &&
|
||||
!list_empty(&ch->event_req_buffers)) {
|
||||
usleep_range(MHI_DEV_CH_CLOSE_TIMEOUT_MIN,
|
||||
MHI_DEV_CH_CLOSE_TIMEOUT_MAX);
|
||||
} else
|
||||
|
|
@ -3078,6 +3236,9 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
|
|||
if (ch->pend_wr_count)
|
||||
mhi_log(MHI_MSG_ERROR, "%d writes pending for channel %d\n",
|
||||
ch->pend_wr_count, ch->ch_id);
|
||||
if (!list_empty(&ch->event_req_buffers))
|
||||
mhi_log(MHI_MSG_ERROR, "%d pending flush for channel %d\n",
|
||||
ch->pend_wr_count, ch->ch_id);
|
||||
|
||||
if (ch->state != MHI_DEV_CH_PENDING_START)
|
||||
if ((ch->ch_type == MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL &&
|
||||
|
|
@ -3089,14 +3250,24 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
|
|||
ch->state = MHI_DEV_CH_CLOSED;
|
||||
ch->active_client = NULL;
|
||||
kfree(ch->ereqs);
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC:ch:%d size:%d EREQ\n",
|
||||
ch->ch_id, ch->evt_req_size);
|
||||
kfree(ch->tr_events);
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_DEALLOC:ch:%d size:%d TR_EVENTS\n",
|
||||
ch->ch_id, ch->evt_buf_size);
|
||||
ch->evt_buf_size = 0;
|
||||
ch->evt_req_size = 0;
|
||||
ch->ereqs = NULL;
|
||||
ch->tr_events = NULL;
|
||||
kfree(handle);
|
||||
mhi_log(MHI_MSG_INFO,
|
||||
"MEM_ALLOC:ch:%d size:%d CLNT_HANDLE\n",
|
||||
ch->ch_id, sizeof(struct mhi_dev_client));
|
||||
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_dev_close_channel);
|
||||
|
||||
|
|
@ -3175,9 +3346,9 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
|
|||
mutex_lock(&ch->ch_lock);
|
||||
|
||||
do {
|
||||
if (ch->state == MHI_DEV_CH_STOPPED) {
|
||||
if (ch->state == MHI_DEV_CH_STOPPED || ch->reset_pending) {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"channel (%d) already stopped\n",
|
||||
"channel (%d) already stopped or RST pending\n",
|
||||
mreq->chan);
|
||||
bytes_read = -1;
|
||||
goto exit;
|
||||
|
|
@ -3358,9 +3529,10 @@ int mhi_dev_write_channel(struct mhi_req *wreq)
|
|||
}
|
||||
|
||||
ch->pend_wr_count++;
|
||||
if (ch->state == MHI_DEV_CH_STOPPED) {
|
||||
if (ch->state == MHI_DEV_CH_STOPPED || ch->reset_pending) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"channel %d already stopped\n", wreq->chan);
|
||||
"channel %d already stopped or RST pending\n",
|
||||
wreq->chan);
|
||||
bytes_written = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -3573,13 +3745,6 @@ static void mhi_dev_enable(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
rc = mhi_dev_ring_init(mhi);
|
||||
if (rc) {
|
||||
pr_err("MHI dev ring init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset);
|
||||
if (rc) {
|
||||
pr_err("%s: get mhi state failed\n", __func__);
|
||||
|
|
@ -3893,14 +4058,6 @@ static int mhi_init(struct mhi_dev *mhi)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (!mhi->ring)
|
||||
mhi->ring = devm_kzalloc(&pdev->dev,
|
||||
(sizeof(struct mhi_dev_ring) *
|
||||
(mhi->cfg.channels + mhi->cfg.event_rings + 1)),
|
||||
GFP_KERNEL);
|
||||
if (!mhi->ring)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* mhi_init is also called during device reset, in
|
||||
* which case channel mem will already be allocated.
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ struct mhi_dev_ring {
|
|||
/* ring_ctx_shadow -> tracking ring_ctx in the host */
|
||||
union mhi_dev_ring_ctx *ring_ctx_shadow;
|
||||
struct msi_buf_cb_data msi_buffer;
|
||||
void (*ring_cb)(struct mhi_dev *dev,
|
||||
int (*ring_cb)(struct mhi_dev *dev,
|
||||
union mhi_dev_ring_element_type *el,
|
||||
void *ctx);
|
||||
};
|
||||
|
|
@ -509,6 +509,8 @@ struct mhi_dev_channel {
|
|||
uint32_t msi_cnt;
|
||||
uint32_t flush_req_cnt;
|
||||
bool skip_td;
|
||||
bool db_pending;
|
||||
bool reset_pending;
|
||||
};
|
||||
|
||||
/* Structure device for mhi dev */
|
||||
|
|
@ -773,7 +775,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring,
|
|||
* @ring_cb: callback function.
|
||||
*/
|
||||
void mhi_ring_set_cb(struct mhi_dev_ring *ring,
|
||||
void (*ring_cb)(struct mhi_dev *dev,
|
||||
int (*ring_cb)(struct mhi_dev *dev,
|
||||
union mhi_dev_ring_element_type *el, void *ctx));
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -601,13 +601,18 @@ EXPORT_SYMBOL(mhi_dev_mmio_reset);
|
|||
|
||||
int mhi_dev_restore_mmio(struct mhi_dev *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t i, reg_cntl_value;
|
||||
void *reg_cntl_addr;
|
||||
|
||||
if (WARN_ON(!dev))
|
||||
return -EINVAL;
|
||||
|
||||
mhi_dev_mmio_mask_interrupts(dev);
|
||||
mhi_dev_mmio_disable_ctrl_interrupt(dev);
|
||||
|
||||
mhi_dev_mmio_disable_cmdb_interrupt(dev);
|
||||
|
||||
mhi_dev_mmio_mask_erdb_interrupts(dev);
|
||||
|
||||
for (i = 0; i < (MHI_DEV_MMIO_RANGE/4); i++) {
|
||||
reg_cntl_addr = dev->mmio_base_addr +
|
||||
|
|
@ -618,12 +623,26 @@ int mhi_dev_restore_mmio(struct mhi_dev *dev)
|
|||
|
||||
mhi_dev_mmio_clear_interrupts(dev);
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) {
|
||||
/* Enable channel interrupt whose mask is enabled */
|
||||
if (dev->chdb[i].mask) {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Enabling id: %d, chdb mask 0x%x\n",
|
||||
i, dev->chdb[i].mask);
|
||||
|
||||
rc = mhi_dev_mmio_write(dev, MHI_CHDB_INT_MASK_A7_n(i),
|
||||
dev->chdb[i].mask);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Error writing enable for A7\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mask and enable control interrupt */
|
||||
mhi_dev_mmio_enable_ctrl_interrupt(dev);
|
||||
|
||||
/*Enable chdb interrupt*/
|
||||
mhi_dev_mmio_enable_chdb_interrupts(dev);
|
||||
|
||||
/*Enable cmdb interrupt*/
|
||||
mhi_dev_mmio_enable_cmdb_interrupt(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, size_t offset)
|
|||
el->tre.len, offset);
|
||||
|
||||
if (ring->ring_cb)
|
||||
ring->ring_cb(ring->mhi_dev, el, (void *)ring);
|
||||
return ring->ring_cb(ring->mhi_dev, el, (void *)ring);
|
||||
else
|
||||
mhi_log(MHI_MSG_ERROR, "No callback registered for ring %d\n",
|
||||
ring->id);
|
||||
|
|
@ -557,7 +557,7 @@ void mhi_ring_init(struct mhi_dev_ring *ring, enum mhi_dev_ring_type type,
|
|||
EXPORT_SYMBOL(mhi_ring_init);
|
||||
|
||||
void mhi_ring_set_cb(struct mhi_dev_ring *ring,
|
||||
void (*ring_cb)(struct mhi_dev *dev,
|
||||
int (*ring_cb)(struct mhi_dev *dev,
|
||||
union mhi_dev_ring_element_type *el, void *ctx))
|
||||
{
|
||||
if (WARN_ON(!ring || !ring_cb))
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ struct uci_client {
|
|||
struct mhi_uci_ctxt_t *uci_ctxt;
|
||||
struct mutex in_chan_lock;
|
||||
struct mutex out_chan_lock;
|
||||
struct mutex client_lock;
|
||||
spinlock_t req_lock;
|
||||
unsigned int f_flags;
|
||||
/* Pointer to dynamically allocated mhi_req structs */
|
||||
|
|
@ -557,15 +558,25 @@ static struct mhi_req *mhi_uci_get_req(struct uci_client *uci_handle)
|
|||
return req;
|
||||
}
|
||||
|
||||
static void mhi_uci_put_req(struct uci_client *uci_handle, struct mhi_req *req)
|
||||
static int mhi_uci_put_req(struct uci_client *uci_handle, struct mhi_req *req)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&uci_handle->req_lock, flags);
|
||||
if (req->is_stale) {
|
||||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Got stale completion for ch %d, ignoring\n",
|
||||
req->chan);
|
||||
spin_unlock_irqrestore(&uci_handle->req_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Remove from in-use list and add back to free list */
|
||||
list_del_init(&req->list);
|
||||
list_add_tail(&req->list, &uci_handle->req_list);
|
||||
spin_unlock_irqrestore(&uci_handle->req_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mhi_uci_write_completion_cb(void *req)
|
||||
|
|
@ -581,17 +592,12 @@ static void mhi_uci_write_completion_cb(void *req)
|
|||
* the stale flag and return. The ureq was added to
|
||||
* the free list when client called release function.
|
||||
*/
|
||||
if (ureq->is_stale) {
|
||||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Got stale completion for ch %d\n", ureq->chan);
|
||||
ureq->is_stale = false;
|
||||
if (mhi_uci_put_req(uci_handle, ureq))
|
||||
return;
|
||||
}
|
||||
|
||||
if (uci_handle->write_done)
|
||||
complete(uci_handle->write_done);
|
||||
|
||||
mhi_uci_put_req(uci_handle, ureq);
|
||||
/* Write queue may be waiting for write request structs */
|
||||
wake_up(&uci_handle->write_wq);
|
||||
}
|
||||
|
|
@ -601,19 +607,19 @@ static void mhi_uci_read_completion_cb(void *req)
|
|||
struct mhi_req *ureq = req;
|
||||
struct uci_client *uci_handle;
|
||||
|
||||
if (ureq->is_stale) {
|
||||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Got stale completion for ch %d, ignoring\n",
|
||||
ureq->chan);
|
||||
return;
|
||||
}
|
||||
|
||||
uci_handle = (struct uci_client *)ureq->context;
|
||||
|
||||
uci_handle->pkt_loc = (void *)ureq->buf;
|
||||
uci_handle->pkt_size = ureq->transfer_len;
|
||||
|
||||
mhi_uci_put_req(uci_handle, ureq);
|
||||
/*
|
||||
* If this is a delayed read completion, just clear
|
||||
* the stale flag and return. The ureq was added to
|
||||
* the free list when client called release function.
|
||||
*/
|
||||
if (mhi_uci_put_req(uci_handle, ureq))
|
||||
return;
|
||||
|
||||
complete(&uci_handle->read_done);
|
||||
}
|
||||
|
||||
|
|
@ -782,6 +788,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
|
|||
if (!uci_handle)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&uci_handle->client_lock);
|
||||
|
||||
poll_wait(file, &uci_handle->read_wq, wait);
|
||||
poll_wait(file, &uci_handle->write_wq, wait);
|
||||
/*
|
||||
|
|
@ -789,8 +797,10 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
|
|||
* to poll are in connected state and return with the
|
||||
* appropriate mask if channels are disconnected.
|
||||
*/
|
||||
if (!mhi_uci_are_channels_connected(uci_handle)) {
|
||||
if (!atomic_read(&uci_handle->mhi_chans_open) ||
|
||||
!mhi_uci_are_channels_connected(uci_handle)) {
|
||||
mask = POLLHUP;
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
return mask;
|
||||
}
|
||||
mask = uci_handle->at_ctrl_mask;
|
||||
|
|
@ -810,6 +820,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
|
|||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Client attempted to poll chan %d, returning mask 0x%x\n",
|
||||
uci_handle->in_chan, mask);
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
|
@ -1069,6 +1081,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&uci_handle->client_lock);
|
||||
uci_log(UCI_DBG_DBG,
|
||||
"Client opened struct device node 0x%x, ref count 0x%x\n",
|
||||
iminor(mhi_inode), atomic_read(&uci_handle->ref_count));
|
||||
|
|
@ -1076,6 +1089,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode,
|
|||
if (!uci_handle) {
|
||||
atomic_dec(&uci_handle->ref_count);
|
||||
uci_log(UCI_DBG_DBG, "No memory, returning failure\n");
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
uci_handle->uci_ctxt = &uci_ctxt;
|
||||
|
|
@ -1093,11 +1107,13 @@ static int mhi_uci_client_open(struct inode *mhi_inode,
|
|||
uci_log(UCI_DBG_INFO,
|
||||
"Closing failed channel\n");
|
||||
}
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
file_handle->private_data = uci_handle;
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1110,14 +1126,17 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
|
|||
const struct chan_attr *in_chan_attr;
|
||||
int count = 0, i;
|
||||
struct mhi_req *ureq;
|
||||
unsigned long flags;
|
||||
|
||||
if (!uci_handle)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&uci_handle->client_lock);
|
||||
in_chan_attr = uci_handle->in_chan_attr;
|
||||
if (!in_chan_attr) {
|
||||
uci_log(UCI_DBG_ERROR, "Null channel attributes for chan %d\n",
|
||||
uci_handle->in_chan);
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1125,6 +1144,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
|
|||
uci_log(UCI_DBG_DBG, "Client close chan %d, ref count 0x%x\n",
|
||||
iminor(mhi_inode),
|
||||
atomic_read(&uci_handle->ref_count));
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1162,17 +1182,23 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
|
|||
* to client if the transfer completes later.
|
||||
*/
|
||||
count = 0;
|
||||
while (!(list_empty(&uci_handle->in_use_list))) {
|
||||
ureq = container_of(uci_handle->in_use_list.next,
|
||||
|
||||
spin_lock_irqsave(&uci_handle->req_lock, flags);
|
||||
if (!(uci_handle->f_flags & O_SYNC)) {
|
||||
while (!(list_empty(&uci_handle->in_use_list))) {
|
||||
ureq = container_of(
|
||||
uci_handle->in_use_list.next,
|
||||
struct mhi_req, list);
|
||||
list_del_init(&ureq->list);
|
||||
ureq->is_stale = true;
|
||||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Adding back req for chan %d to free list\n",
|
||||
ureq->chan);
|
||||
list_add_tail(&ureq->list, &uci_handle->req_list);
|
||||
count++;
|
||||
list_del_init(&ureq->list);
|
||||
ureq->is_stale = true;
|
||||
uci_log(UCI_DBG_VERBOSE,
|
||||
"Adding back req for chan %d to free list\n",
|
||||
ureq->chan);
|
||||
list_add_tail(&ureq->list, &uci_handle->req_list);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&uci_handle->req_lock, flags);
|
||||
if (count)
|
||||
uci_log(UCI_DBG_DBG,
|
||||
"Client %d closed with %d transfers pending\n",
|
||||
|
|
@ -1188,6 +1214,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
|
|||
atomic_set(&uci_handle->read_data_ready, 0);
|
||||
atomic_set(&uci_handle->write_data_ready, 0);
|
||||
file_handle->private_data = NULL;
|
||||
mutex_unlock(&uci_handle->client_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1670,6 +1697,7 @@ static int mhi_register_client(struct uci_client *mhi_client, int index)
|
|||
|
||||
mutex_init(&mhi_client->in_chan_lock);
|
||||
mutex_init(&mhi_client->out_chan_lock);
|
||||
mutex_init(&mhi_client->client_lock);
|
||||
spin_lock_init(&mhi_client->req_lock);
|
||||
/* Init the completion event for AT ctrl read */
|
||||
init_completion(&mhi_client->at_ctrl_read_done);
|
||||
|
|
@ -2069,13 +2097,15 @@ static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data)
|
|||
mhi_dev_close_channel(client->out_handle);
|
||||
mhi_dev_close_channel(client->in_handle);
|
||||
|
||||
/* Add back reqs for in-use list, if any, to free list */
|
||||
while (!(list_empty(&client->in_use_list))) {
|
||||
ureq = container_of(client->in_use_list.next,
|
||||
struct mhi_req, list);
|
||||
list_del_init(&ureq->list);
|
||||
/* Add to in-use list */
|
||||
list_add_tail(&ureq->list, &client->req_list);
|
||||
/* Add back reqs from in-use list, if any, to free list */
|
||||
if (!(client->f_flags & O_SYNC)) {
|
||||
while (!(list_empty(&client->in_use_list))) {
|
||||
ureq = container_of(client->in_use_list.next,
|
||||
struct mhi_req, list);
|
||||
list_del_init(&ureq->list);
|
||||
/* Add to in-use list */
|
||||
list_add_tail(&ureq->list, &client->req_list);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (client->in_chan_attr->nr_trbs); i++) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
/* Bus-Access-Manager (BAM) Hardware manager. */
|
||||
|
||||
|
|
@ -2140,13 +2140,16 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option)
|
|||
u32 pipe = pipe_index;
|
||||
u32 desc_fifo_addr;
|
||||
u32 desc_fifo_size;
|
||||
u32 *desc_fifo;
|
||||
u32 __iomem *desc_fifo;
|
||||
int i;
|
||||
char desc_info[MAX_MSG_LEN];
|
||||
struct sps_bam *dev;
|
||||
|
||||
if (base == NULL)
|
||||
return;
|
||||
|
||||
dev = to_sps_bam_dev(virt_addr);
|
||||
|
||||
desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR, pipe);
|
||||
desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES, pipe,
|
||||
P_DESC_FIFO_SIZE);
|
||||
|
|
@ -2167,7 +2170,14 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option)
|
|||
"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n",
|
||||
desc_fifo_addr, desc_fifo_size, desc_fifo_size);
|
||||
|
||||
desc_fifo = (u32 *) phys_to_virt(desc_fifo_addr);
|
||||
if (dev->props.options & SPS_BAM_SMMU_EN) {
|
||||
struct sps_pipe *pipe_indx = dev->pipes[pipe_index];
|
||||
|
||||
SPS_DUMP("%s", "SMMU is enabled\n");
|
||||
desc_fifo = pipe_indx->map->desc.base;
|
||||
} else {
|
||||
desc_fifo = (u32 __iomem *) phys_to_virt(desc_fifo_addr);
|
||||
}
|
||||
|
||||
if (option == 100) {
|
||||
SPS_DUMP("%s",
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ int qbg_batterydata_init(struct device_node *profile_node,
|
|||
rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qbg_battery");
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to allocate chrdev, rc=%d\n", rc);
|
||||
goto free_battery;
|
||||
return rc;
|
||||
}
|
||||
|
||||
cdev_init(&battery->battery_cdev, &qbg_battery_data_fops);
|
||||
|
|
@ -534,8 +534,6 @@ delete_cdev:
|
|||
cdev_del(&battery->battery_cdev);
|
||||
unregister_chrdev:
|
||||
unregister_chrdev_region(battery->dev_no, 1);
|
||||
free_battery:
|
||||
kfree(battery);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
|| ((left) <= (right) && (left) <= (value) \
|
||||
&& (value) <= (right)))
|
||||
|
||||
enum ttf_calc_mode {
|
||||
TTF_MODE_VBAT_STEP_CHG = 0,
|
||||
TTF_MODE_OCV_STEP_CHG,
|
||||
TTF_MODE_SOC_STEP_CHG,
|
||||
};
|
||||
|
||||
struct battery_data_table0 {
|
||||
int soc_length;
|
||||
int ocv_length;
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@
|
|||
enum debug_mask {
|
||||
QBG_DEBUG_BUS_READ = BIT(0),
|
||||
QBG_DEBUG_BUS_WRITE = BIT(1),
|
||||
QBG_DEBUG_FIFO = BIT(2),
|
||||
QBG_DEBUG_SDAM = BIT(2),
|
||||
QBG_DEBUG_IRQ = BIT(3),
|
||||
QBG_DEBUG_DEVICE = BIT(4),
|
||||
QBG_DEBUG_PROFILE = BIT(5),
|
||||
QBG_DEBUG_SOC = BIT(6),
|
||||
QBG_DEBUG_SDAM = BIT(7),
|
||||
QBG_DEBUG_STATUS = BIT(8),
|
||||
QBG_DEBUG_PON = BIT(9),
|
||||
QBG_DEBUG_STATUS = BIT(7),
|
||||
QBG_DEBUG_PON = BIT(8),
|
||||
};
|
||||
|
||||
enum qbg_sdam {
|
||||
|
|
@ -37,6 +36,32 @@ enum qbg_sdam {
|
|||
SDAM_DATA4,
|
||||
};
|
||||
|
||||
enum qbg_data_tag {
|
||||
QBG_DATA_TAG_FAST_CHAR,
|
||||
};
|
||||
|
||||
enum QBG_SAMPLE_NUM_TYPE {
|
||||
SAMPLE_NUM_1,
|
||||
SAMPLE_NUM_2,
|
||||
SAMPLE_NUM_4,
|
||||
SAMPLE_NUM_8,
|
||||
SAMPLE_NUM_16,
|
||||
SAMPLE_NUM_32,
|
||||
QBG_SAMPLE_NUM_INVALID,
|
||||
};
|
||||
|
||||
enum QBG_ACCUM_INTERVAL_TYPE {
|
||||
ACCUM_INTERVAL_100MS,
|
||||
ACCUM_INTERVAL_200MS,
|
||||
ACCUM_INTERVAL_500MS,
|
||||
ACCUM_INTERVAL_1000MS,
|
||||
ACCUM_INTERVAL_2000MS,
|
||||
ACCUM_INTERVAL_5000MS,
|
||||
ACCUM_INTERVAL_10000MS,
|
||||
ACCUM_INTERVAL_100000MS,
|
||||
ACCUM_INTERVAL_INVALID,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qti_qbg - Structure for QTI QBG device
|
||||
* @dev: Pointer to QBG device structure
|
||||
|
|
@ -59,6 +84,7 @@ enum qbg_sdam {
|
|||
* @kdata: QBG Kernel space data structure
|
||||
* @udata: QBG user space data structure
|
||||
* @battery: Pointer to QBG battery data structure
|
||||
* @step_chg_jeita_params: Jeita step charge parameters structure
|
||||
* @fifo_lock: Lock for reading FIFO data
|
||||
* @data_lock: Lock for reading kdata from QBG char device
|
||||
* @batt_id_chan: IIO channel to read battery ID
|
||||
|
|
@ -70,8 +96,11 @@ enum qbg_sdam {
|
|||
* @batt_type_str: String array denoting battery type
|
||||
* @irq: QBG irq number
|
||||
* @base: Base address of QBG HW
|
||||
* @num_sdams: Number of sdams used for QBG
|
||||
* @num_data_sdams: Number of data sdams used for QBG
|
||||
* @batt_id_ohm: Battery resistance in ohms
|
||||
* @sdam_batt_id: Battery ID stored and retrieved from SDAM
|
||||
* @essential_param_revid: QBG essential parameters revision ID
|
||||
* @sample_time_us: Array of accumulator sample time in each QBG HW state
|
||||
* @debug_mask: Debug mask to enable/disable debug prints
|
||||
* @pon_ocv: Power-on OCV of QBG device
|
||||
* @pon_ibat: Power-on current of QBG device
|
||||
|
|
@ -126,6 +155,7 @@ struct qti_qbg {
|
|||
struct qbg_kernel_data kdata;
|
||||
struct qbg_user_data udata;
|
||||
struct qbg_battery_data *battery;
|
||||
struct qbg_step_chg_jeita_params *step_chg_jeita_params;
|
||||
struct mutex fifo_lock;
|
||||
struct mutex data_lock;
|
||||
struct iio_channel *batt_id_chan;
|
||||
|
|
@ -138,9 +168,11 @@ struct qti_qbg {
|
|||
int irq;
|
||||
u32 base;
|
||||
u32 sdam_base;
|
||||
u32 num_sdams;
|
||||
u32 num_data_sdams;
|
||||
u32 batt_id_ohm;
|
||||
u32 sdam_batt_id;
|
||||
u32 essential_param_revid;
|
||||
u32 sample_time_us[QBG_STATE_MAX];
|
||||
u32 *debug_mask;
|
||||
int pon_ocv;
|
||||
int pon_ibat;
|
||||
|
|
|
|||
|
|
@ -49,22 +49,18 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo,
|
|||
fifo_data_length = fifo_count * QBG_ONE_FIFO_LENGTH;
|
||||
num_sdams = fifo_data_length / QBG_SDAM_ONE_FIFO_REGION_SIZE;
|
||||
|
||||
if (num_sdams > chip->num_sdams) {
|
||||
if (num_sdams > chip->num_data_sdams) {
|
||||
pr_err("Fifo count exceeds QBG SDAMs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "Completely filled sdams=%d\n",
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Completely filled sdams=%d\n",
|
||||
num_sdams);
|
||||
|
||||
/* First read SDAMs that are completely filled */
|
||||
for (i = 0; i < num_sdams; i++) {
|
||||
if (!chip->sdam[i]) {
|
||||
pr_err("Number of SDAMs not sufficient to read FIFOs\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
rc = qbg_sdam_read(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i),
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)),
|
||||
(((u8 *)fifo) + bytes_read),
|
||||
QBG_SDAM_ONE_FIFO_REGION_SIZE);
|
||||
if (rc < 0) {
|
||||
|
|
@ -77,12 +73,12 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo,
|
|||
|
||||
/* Next read SDAM that is partially filled */
|
||||
bytes_remaining = fifo_data_length - bytes_read;
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "Valid data in partially filled sdam:%d bytes\n",
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Valid data in partially filled sdam:%d bytes\n",
|
||||
bytes_remaining);
|
||||
|
||||
if (bytes_remaining) {
|
||||
rc = qbg_sdam_read(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i),
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)),
|
||||
(((u8 *)fifo) + bytes_read),
|
||||
bytes_remaining);
|
||||
if (rc < 0) {
|
||||
|
|
@ -93,7 +89,7 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo,
|
|||
bytes_read += bytes_remaining;
|
||||
}
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "Total bytes read=%d\n", bytes_read);
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Total bytes read=%d\n", bytes_read);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -106,13 +102,13 @@ int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params)
|
|||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_read(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * 0x100) +
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_START_OFFSET,
|
||||
(u8 *)params, sizeof(struct qbg_essential_params));
|
||||
if (rc < 0)
|
||||
pr_err("Failed to read QBG essential params, rc=%d\n", rc);
|
||||
else
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "Read QBG essential params\n");
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -125,13 +121,94 @@ int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params)
|
|||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_write(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * 0x100) +
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_START_OFFSET,
|
||||
(u8 *)params, sizeof(struct qbg_essential_params));
|
||||
if (rc < 0)
|
||||
pr_err("Failed to write QBG essential params, rc=%d\n", rc);
|
||||
else
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "Written QBG essential params\n");
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Written QBG essential params\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!chip || !revid)
|
||||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_read(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_REVID_OFFSET,
|
||||
revid, 1);
|
||||
if (rc < 0)
|
||||
pr_err("Failed to read QBG essential params revid, rc=%d\n", rc);
|
||||
else
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params revid:%u\n", *revid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_write(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_REVID_OFFSET,
|
||||
&revid, 1);
|
||||
if (rc < 0)
|
||||
pr_err("Failed to write QBG essential params revid, rc=%d\n", rc);
|
||||
else
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG essential params revid:%u\n",
|
||||
revid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid)
|
||||
{
|
||||
int rc;
|
||||
u8 buf[2];
|
||||
|
||||
if (!chip || !battid)
|
||||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_read(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_BATTID_OFFSET,
|
||||
buf, 2);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read QBG battery ID, rc=%d\n", rc);
|
||||
} else {
|
||||
*battid = buf[0] | (buf[1] << 8);
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG battery ID:%u\n",
|
||||
*battid);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
rc = qbg_sdam_write(chip,
|
||||
chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) +
|
||||
QBG_ESSENTIAL_PARAMS_BATTID_OFFSET,
|
||||
(u8 *)&battid, 2);
|
||||
if (rc < 0)
|
||||
pr_err("Failed to write QBG battery ID, rc=%d\n", rc);
|
||||
else
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG battery ID:%u\n", battid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#define QBG_SDAM_FIFO_COUNT_OFFSET 0x46
|
||||
#define QBG_ESSENTIAL_PARAMS_START_OFFSET 0x47
|
||||
#define QBG_SDAM_START_OFFSET 0x4b
|
||||
#define QBG_ESSENTIAL_PARAMS_BATTID_OFFSET 0x45
|
||||
#define QBG_SDAM_BHARGER_OCV_HDRM_OFFSET 0x5b
|
||||
#define QBG_ESSENTIAL_PARAMS_REVID_OFFSET 0xbb
|
||||
#define QBG_SDAM_INT_TEST1 0xe0
|
||||
#define QBG_SDAM_INT_TEST_VAL 0xe1
|
||||
#define QBG_SDAM_DATA_PUSH_COUNTER_OFFSET 0x46
|
||||
|
|
@ -19,14 +21,23 @@
|
|||
#define QBG_SDAM_ONE_FIFO_REGION_SIZE 117 /* 117 bytes for FIFO starting from 0x4B */
|
||||
#define QBG_SDAM_ESR_PULSE_FIFO_INDEX 11
|
||||
|
||||
#define QBG_SDAM_DATA_START_OFFSET(chip, index) \
|
||||
(chip->sdam_base + (index * 0x100) + QBG_SDAM_START_OFFSET)
|
||||
#define QBG_SINGLE_SDAM_SIZE 0x100
|
||||
#define QBG_SDAM_BASE(chip, index) (chip->sdam_base + (index * QBG_SINGLE_SDAM_SIZE))
|
||||
|
||||
int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data, int length);
|
||||
int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data, int length);
|
||||
#define QBG_SDAM_DATA_START_OFFSET(chip, index) \
|
||||
(QBG_SDAM_BASE(chip, index) + QBG_SDAM_START_OFFSET)
|
||||
|
||||
int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data,
|
||||
int length);
|
||||
int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data,
|
||||
int length);
|
||||
int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo,
|
||||
u32 fifo_count);
|
||||
int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params);
|
||||
int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params);
|
||||
|
||||
int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid);
|
||||
int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid);
|
||||
int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid);
|
||||
int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid);
|
||||
#endif /* __QBG_SDAM_H__ */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __QG_CORE_H__
|
||||
|
|
@ -154,6 +154,7 @@ struct qpnp_qg {
|
|||
bool fvss_active;
|
||||
bool tcss_active;
|
||||
bool bass_active;
|
||||
bool first_profile_load;
|
||||
int charge_status;
|
||||
int charge_type;
|
||||
int chg_iterm_ma;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __QG_IIO_H
|
||||
|
|
@ -91,6 +91,7 @@ static const struct qg_iio_channels qg_iio_psy_channels[] = {
|
|||
QG_CHAN_RES("esr_actual", PSY_IIO_ESR_ACTUAL)
|
||||
QG_CHAN_RES("esr_nominal", PSY_IIO_ESR_NOMINAL)
|
||||
QG_CHAN_INDEX("soh", PSY_IIO_SOH)
|
||||
QG_CHAN_INDEX("clear_soh", PSY_IIO_CLEAR_SOH)
|
||||
QG_CHAN_ENERGY("cc_soc", PSY_IIO_CC_SOC)
|
||||
QG_CHAN_ACT("fg_reset", PSY_IIO_FG_RESET)
|
||||
QG_CHAN_VOLT("voltage_avg", PSY_IIO_VOLTAGE_AVG)
|
||||
|
|
|
|||
|
|
@ -2135,6 +2135,9 @@ static int qg_iio_write_raw(struct iio_dev *indio_dev,
|
|||
if (chip->sp)
|
||||
soh_profile_update(chip->sp, chip->soh);
|
||||
break;
|
||||
case PSY_IIO_CLEAR_SOH:
|
||||
chip->first_profile_load = val1;
|
||||
break;
|
||||
case PSY_IIO_ESR_ACTUAL:
|
||||
chip->esr_actual = val1;
|
||||
break;
|
||||
|
|
@ -2260,6 +2263,9 @@ static int qg_iio_read_raw(struct iio_dev *indio_dev,
|
|||
case PSY_IIO_SOH:
|
||||
*val1 = chip->soh;
|
||||
break;
|
||||
case PSY_IIO_CLEAR_SOH:
|
||||
*val1 = chip->first_profile_load;
|
||||
break;
|
||||
case PSY_IIO_CC_SOC:
|
||||
rc = qg_get_cc_soc(chip, val1);
|
||||
break;
|
||||
|
|
@ -3470,6 +3476,7 @@ static int qg_sanitize_sdam(struct qpnp_qg *chip)
|
|||
rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
|
||||
if (!rc)
|
||||
qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n");
|
||||
chip->first_profile_load = true;
|
||||
} else {
|
||||
/* SDAM has invalid value */
|
||||
rc = qg_sdam_clear();
|
||||
|
|
@ -3477,6 +3484,7 @@ static int qg_sanitize_sdam(struct qpnp_qg *chip)
|
|||
pr_err("SDAM uninitialized, SDAM reset\n");
|
||||
rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
|
||||
}
|
||||
chip->first_profile_load = true;
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
|
|
|
|||
|
|
@ -67,15 +67,28 @@
|
|||
|
||||
#define QBG_MAIN_VBAT_EMPTY_THRESH 0x56
|
||||
|
||||
#define QBG_MAIN_HPM_MEAS_CTL2 0x5d
|
||||
|
||||
#define QBG_MAIN_MPM_MEAS_CTL2 0x61
|
||||
|
||||
#define QBG_MAIN_LPM_MEAS_CTL2 0x65
|
||||
#define QBG_NUM_OF_ACCUM_MASK GENMASK(7, 5)
|
||||
#define QBG_NUM_OF_ACCUM_SHIFT 5
|
||||
#define QBG_ACCUM_INTERVAL_MASK GENMASK(2, 0)
|
||||
|
||||
#define QBG_MAIN_FAST_CHAR_MEAS_CTL2 0x69
|
||||
|
||||
#define QBG_MAIN_PON_OCV_ACC0_DATA0 0x70
|
||||
|
||||
#define QBG_MAIN_LAST_ADC_ACC0_DATA0 0x9A
|
||||
|
||||
#define QBG_MAIN_LAST_BURST_AVG_ACC0_DATA0 0xA0
|
||||
|
||||
#define QBG_MAIN_LAST_BURST_AVG_ACC2_DATA0 0xA4
|
||||
|
||||
#define QBG_FAST_CHAR_DELTA_MS 100000
|
||||
#define VBATT_1S_LSB 19463
|
||||
#define IBATT_10A_LSB 30518
|
||||
#define IBATT_10A_LSB 6103
|
||||
#define VBAT_0PCT_OCV 300000000ULL
|
||||
#define ICHG_FS_10A 1
|
||||
#define TBAT_LSB 7500
|
||||
|
|
@ -86,12 +99,21 @@
|
|||
#define OCV_BOOST_MAX_UV 5600000
|
||||
#define OCV_BOOST_STEP_UV 100000
|
||||
|
||||
enum qbg_data_tag {
|
||||
QBG_DATA_TAG_FAST_CHAR,
|
||||
};
|
||||
#define BATT_HOT_DECIDEGREE_MAX 600
|
||||
|
||||
#define MILLI_TO_10NANO 100000
|
||||
#define MICRO_TO_10NANO 100
|
||||
#define MILLI_TO_MICRO 1000
|
||||
|
||||
static int qbg_debug_mask;
|
||||
|
||||
static const unsigned int qbg_accum_interval[8] = {
|
||||
10000, 20000, 50000, 100000, 150000, 200000, 500000, 1000000};
|
||||
static const unsigned int qbg_lpm_accum_interval[8] = {
|
||||
100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000};
|
||||
static const unsigned int qbg_fast_char_avg_interval[8] = {
|
||||
6250, 12500, 25000, 50000, 100000, 200000, 400000, 800000};
|
||||
|
||||
static const struct qbg_iio_channels qbg_iio_psy_channels[] = {
|
||||
QBG_CHAN_INDEX("debug_battery", PSY_IIO_DEBUG_BATTERY)
|
||||
QBG_CHAN_ENERGY("capacity", PSY_IIO_CAPACITY)
|
||||
|
|
@ -100,6 +122,7 @@ static const struct qbg_iio_channels qbg_iio_psy_channels[] = {
|
|||
QBG_CHAN_VOLT("voltage_max", PSY_IIO_VOLTAGE_MAX)
|
||||
QBG_CHAN_VOLT("voltage_now", PSY_IIO_VOLTAGE_NOW)
|
||||
QBG_CHAN_VOLT("voltage_ocv", PSY_IIO_VOLTAGE_OCV)
|
||||
QBG_CHAN_VOLT("voltage_avg", PSY_IIO_VOLTAGE_AVG)
|
||||
QBG_CHAN_CUR("current_now", PSY_IIO_CURRENT_NOW)
|
||||
QBG_CHAN_RES("resistance_id", PSY_IIO_RESISTANCE_ID)
|
||||
QBG_CHAN_TSTAMP("time_to_full_avg", PSY_IIO_TIME_TO_FULL_AVG)
|
||||
|
|
@ -215,7 +238,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count)
|
|||
u8 val[2];
|
||||
|
||||
rc = qbg_sdam_read(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET,
|
||||
val, 2);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read QBG SDAM, rc=%d\n", rc);
|
||||
|
|
@ -223,7 +246,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count)
|
|||
}
|
||||
|
||||
*fifo_count = (val[1] << 8) | val[0];
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "FIFO count=%d\n", *fifo_count);
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "FIFO count=%d\n", *fifo_count);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -248,13 +271,14 @@ static void update_ocv_for_boost(struct qti_qbg *chip)
|
|||
|
||||
qbg_dbg(chip, QBG_DEBUG_STATUS, "Boost OCV value written =%d\n", ocv_for_boost);
|
||||
qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET,
|
||||
(u8 *)&ocv_for_boost, 1);
|
||||
}
|
||||
|
||||
static void process_udata_work(struct work_struct *work)
|
||||
{
|
||||
struct qti_qbg *chip = container_of(work, struct qti_qbg, udata_work);
|
||||
int rc;
|
||||
|
||||
if (chip->udata.param[QBG_PARAM_BATT_SOC].valid)
|
||||
chip->batt_soc = chip->udata.param[QBG_PARAM_BATT_SOC].data;
|
||||
|
|
@ -306,6 +330,20 @@ static void process_udata_work(struct work_struct *work)
|
|||
if (chip->udata.param[QBG_PARAM_TBAT].valid)
|
||||
chip->tbat = chip->udata.param[QBG_PARAM_TBAT].data;
|
||||
|
||||
if (chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].valid) {
|
||||
chip->essential_param_revid =
|
||||
chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].data;
|
||||
|
||||
rc = qbg_sdam_set_essential_param_revid(chip, chip->essential_param_revid);
|
||||
if (rc < 0)
|
||||
pr_err("Failed to set essential param revid in sdam, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
rc = qbg_sdam_set_battery_id(chip, chip->batt_id_ohm / 1000);
|
||||
if (rc < 0)
|
||||
pr_err("Failed to set battid in sdam, rc=%d\n", rc);
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_STATUS, "udata update: batt_soc=%d sys_soc=%d soc=%d qbg_esr=%d\n",
|
||||
(chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL,
|
||||
(chip->sys_soc != INT_MIN) ? chip->sys_soc : -EINVAL,
|
||||
|
|
@ -382,7 +420,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count)
|
|||
unsigned long timestamp;
|
||||
|
||||
if (!fifo_count) {
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "No FIFO data\n");
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "No FIFO data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +477,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count)
|
|||
esr = (vbat1 - vbat1_esr) / ((ibat_esr - ibat) * 10000);
|
||||
esr *= 10000;
|
||||
chip->esr = esr;
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n",
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n",
|
||||
esr, ibat, ibat_esr, vbat1, vbat1_esr);
|
||||
} else {
|
||||
pr_err("Couldn't calculate ESR, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n",
|
||||
|
|
@ -456,7 +494,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count)
|
|||
goto ret;
|
||||
}
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_FIFO, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n",
|
||||
qbg_dbg(chip, QBG_DEBUG_SDAM, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n",
|
||||
vbat1, ibat, tbat, ibat_t);
|
||||
|
||||
chip->kdata.fifo[i].v1 = vbat1;
|
||||
|
|
@ -464,6 +502,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count)
|
|||
chip->kdata.fifo[i].i = ibat;
|
||||
chip->kdata.fifo[i].tbat = tbat;
|
||||
chip->kdata.fifo[i].ibat = ibat_t;
|
||||
chip->kdata.fifo[i].data_tag = fifo[i].data_tag;
|
||||
}
|
||||
|
||||
ret:
|
||||
|
|
@ -477,7 +516,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip)
|
|||
u8 val[2] = {0, 0};
|
||||
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET,
|
||||
val, 2);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to clear QBG FIFO Count, rc=%d\n", rc);
|
||||
|
|
@ -487,7 +526,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip)
|
|||
for (i = 0; i < 10; i++) {
|
||||
val[0] = 0;
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to SDAM0 test val to 0, rc=%d\n", rc);
|
||||
|
|
@ -496,7 +535,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip)
|
|||
|
||||
/* Handshake with PBS to access FIFO data */
|
||||
rc = qbg_sdam_read(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read QBG SDAM, rc=%d\n", rc);
|
||||
|
|
@ -512,7 +551,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip)
|
|||
val[0] = QBG_SDAM_START_OFFSET;
|
||||
val[1] = 0x0;
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET,
|
||||
QBG_SDAM_BASE(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET,
|
||||
val, 2);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to configure QBG data push counter, rc=%d\n", rc);
|
||||
|
|
@ -520,7 +559,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip)
|
|||
}
|
||||
val[0] = 0x0;
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET,
|
||||
val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to set QBG PBS status, rc=%d\n", rc);
|
||||
|
|
@ -537,7 +576,7 @@ static int qbg_init_sdam(struct qti_qbg *chip)
|
|||
|
||||
val[0] = 0x80;
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1);
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to write QBG SDAM, rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -545,7 +584,7 @@ static int qbg_init_sdam(struct qti_qbg *chip)
|
|||
|
||||
val[0] = 0;
|
||||
rc = qbg_sdam_read(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL,
|
||||
val, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Faiiled to read QBG SDAM, rc=%d\n", rc);
|
||||
|
|
@ -673,6 +712,211 @@ static int qbg_notifier_cb(struct notifier_block *nb,
|
|||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int qbg_read_range_data_from_node(struct device_node *node,
|
||||
const char *prop_str, struct ranges *ranges,
|
||||
int max_threshold, u32 max_value)
|
||||
{
|
||||
int rc = 0, i, length, per_tuple_length, tuples;
|
||||
|
||||
if (!node || !prop_str || !ranges) {
|
||||
pr_err("Invalid parameters passed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32));
|
||||
if (rc < 0) {
|
||||
pr_err("Count %s failed, rc=%d\n", prop_str, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
length = rc;
|
||||
per_tuple_length = sizeof(struct range_data) / sizeof(u32);
|
||||
if (length % per_tuple_length) {
|
||||
pr_err("%s length (%d) should be multiple of %d\n",
|
||||
prop_str, length, per_tuple_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tuples = length / per_tuple_length;
|
||||
if (tuples > QBG_MAX_STEP_CHG_ENTRIES) {
|
||||
pr_err("too many entries(%d), only %d allowed\n",
|
||||
tuples, QBG_MAX_STEP_CHG_ENTRIES);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(node, prop_str, (u32 *)ranges->data, length);
|
||||
if (rc < 0) {
|
||||
pr_err("Read %s failed, rc=%d\n", prop_str, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < tuples; i++) {
|
||||
if (ranges->data[i].low_threshold >
|
||||
ranges->data[i].high_threshold) {
|
||||
pr_err("%s thresholds should be in ascendant ranges data\n",
|
||||
prop_str);
|
||||
rc = -EINVAL;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
if (ranges->data[i - 1].high_threshold >
|
||||
ranges->data[i].low_threshold) {
|
||||
pr_err("%s thresholds should be in ascendant ranges data\n",
|
||||
prop_str);
|
||||
rc = -EINVAL;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
if (ranges->data[i].low_threshold > max_threshold)
|
||||
ranges->data[i].low_threshold = max_threshold;
|
||||
if (ranges->data[i].high_threshold > max_threshold)
|
||||
ranges->data[i].high_threshold = max_threshold;
|
||||
if (ranges->data[i].value > max_value)
|
||||
ranges->data[i].value = max_value;
|
||||
}
|
||||
|
||||
ranges->range_count = tuples;
|
||||
ranges->valid = true;
|
||||
return rc;
|
||||
clean:
|
||||
memset(ranges, 0, tuples * sizeof(struct range_data));
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define QBG_DEFAULT_JEITA_FULL_FV_10NV 420000000
|
||||
#define QBG_DEFAULT_BATTERY_BETA 4250
|
||||
#define QBG_DEFAULT_BATTERY_THERM_KOHM 100
|
||||
#define QBG_DEFAULT_JEITA_WARM_ADC_DATA 0x25e3 /* WARM = 40 DegC */
|
||||
#define QBG_DEFAULT_JEITA_COOL_ADC_DATA 0x5314 /* COOL = 5 DegC */
|
||||
static int parse_step_chg_jeita_params(struct qti_qbg *chip, struct device_node *profile_node)
|
||||
{
|
||||
struct qbg_step_chg_jeita_params *step_chg_jeita;
|
||||
bool soc_based_step_chg = false;
|
||||
bool ocv_based_step_chg = false;
|
||||
int rc;
|
||||
int i = 0;
|
||||
u32 temp[2];
|
||||
bool jeita_thresh_valid = true;
|
||||
|
||||
step_chg_jeita = devm_kzalloc(chip->dev, sizeof(*step_chg_jeita),
|
||||
GFP_KERNEL);
|
||||
if (!step_chg_jeita)
|
||||
return -ENOMEM;
|
||||
|
||||
/* choose the lower of the two soft threaholds as the jeita-full-fv */
|
||||
step_chg_jeita->jeita_full_fv_10nv = QBG_DEFAULT_JEITA_FULL_FV_10NV;
|
||||
rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-fv-uv",
|
||||
temp, 2);
|
||||
if (!rc)
|
||||
step_chg_jeita->jeita_full_fv_10nv = min(temp[0], temp[1]) * MICRO_TO_10NANO;
|
||||
else
|
||||
pr_debug("Failed to read jeita full fv from battery profile, rc=%d\n", rc);
|
||||
|
||||
step_chg_jeita->jeita_full_iterm_10na = chip->iterm_ma * MILLI_TO_10NANO;
|
||||
|
||||
soc_based_step_chg = of_property_read_bool(profile_node, "qcom,soc-based-step-chg");
|
||||
ocv_based_step_chg = of_property_read_bool(profile_node, "qcom,ocv-based-step-chg");
|
||||
if (soc_based_step_chg)
|
||||
step_chg_jeita->ttf_calc_mode = TTF_MODE_SOC_STEP_CHG;
|
||||
else if (ocv_based_step_chg)
|
||||
step_chg_jeita->ttf_calc_mode = TTF_MODE_OCV_STEP_CHG;
|
||||
|
||||
step_chg_jeita->battery_beta = QBG_DEFAULT_BATTERY_BETA;
|
||||
rc = of_property_read_u32(profile_node, "qcom,battery-beta",
|
||||
&step_chg_jeita->battery_beta);
|
||||
if (rc < 0)
|
||||
pr_debug("Failed to read battery beta form battery profile, rc=%d\n", rc);
|
||||
|
||||
step_chg_jeita->battery_therm_kohm = QBG_DEFAULT_BATTERY_THERM_KOHM;
|
||||
rc = of_property_read_u32(profile_node, "qcom,battery-therm-kohm",
|
||||
&step_chg_jeita->battery_therm_kohm);
|
||||
if (rc < 0)
|
||||
pr_debug("Failed to read battery therm from battery profile, rc=%d\n", rc);
|
||||
|
||||
step_chg_jeita->jeita_cool_adc_value = QBG_DEFAULT_JEITA_COOL_ADC_DATA;
|
||||
step_chg_jeita->jeita_warm_adc_value = QBG_DEFAULT_JEITA_WARM_ADC_DATA;
|
||||
rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-thresholds",
|
||||
temp, 2);
|
||||
if (!rc) {
|
||||
step_chg_jeita->jeita_cool_adc_value = temp[0];
|
||||
step_chg_jeita->jeita_warm_adc_value = temp[1];
|
||||
} else {
|
||||
jeita_thresh_valid = false;
|
||||
pr_debug("Failed to read jeita cool and warm value from battery profile, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
rc = qbg_read_range_data_from_node(profile_node,
|
||||
"qcom,jeita-fcc-ranges",
|
||||
&step_chg_jeita->jeita_fcc_cfg,
|
||||
BATT_HOT_DECIDEGREE_MAX,
|
||||
chip->fastchg_curr_ma * MILLI_TO_MICRO);
|
||||
if (rc < 0)
|
||||
pr_debug("Failed to read qcom,jeita-fcc-ranges from battery profile, rc=%d\n",
|
||||
rc);
|
||||
|
||||
rc = qbg_read_range_data_from_node(profile_node,
|
||||
"qcom,jeita-fv-ranges",
|
||||
&step_chg_jeita->jeita_fv_cfg,
|
||||
BATT_HOT_DECIDEGREE_MAX, chip->float_volt_uv);
|
||||
if (rc < 0)
|
||||
pr_debug("Failed to read qcom,jeita-fv-ranges from battery profile, rc=%d\n",
|
||||
rc);
|
||||
|
||||
if ((step_chg_jeita->jeita_fcc_cfg.valid != step_chg_jeita->jeita_fv_cfg.valid)
|
||||
|| (jeita_thresh_valid != step_chg_jeita->jeita_fcc_cfg.valid)) {
|
||||
pr_err("battery JEITA configuration is not valid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = qbg_read_range_data_from_node(profile_node,
|
||||
"qcom,step-chg-ranges",
|
||||
&step_chg_jeita->step_fcc_cfg,
|
||||
soc_based_step_chg ? 100 : chip->float_volt_uv,
|
||||
chip->fastchg_curr_ma * MILLI_TO_MICRO);
|
||||
if (rc < 0)
|
||||
pr_debug("Failed to read qcom,step-chg-ranges from battery profile, rc=%d\n",
|
||||
rc);
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_PROFILE, "jeita_full_fv = %dnv, jeita_full_iterm = %dna, jeita_warm_adc = 0x%x, jeita_cool_adc = 0x%x, battery_beta = %d, battery_therm = %dkohm\n",
|
||||
step_chg_jeita->jeita_full_fv_10nv,
|
||||
step_chg_jeita->jeita_full_iterm_10na,
|
||||
step_chg_jeita->jeita_warm_adc_value,
|
||||
step_chg_jeita->jeita_cool_adc_value,
|
||||
step_chg_jeita->battery_beta,
|
||||
step_chg_jeita->battery_therm_kohm);
|
||||
|
||||
pr_debug("step-chg-ranges:\n");
|
||||
for (i = 0; i < step_chg_jeita->step_fcc_cfg.range_count; i++) {
|
||||
pr_debug("%d %d %d\n",
|
||||
step_chg_jeita->step_fcc_cfg.data[i].low_threshold,
|
||||
step_chg_jeita->step_fcc_cfg.data[i].high_threshold,
|
||||
step_chg_jeita->step_fcc_cfg.data[i].value);
|
||||
}
|
||||
|
||||
pr_debug("jeita-fcc-ranges:\n");
|
||||
for (i = 0; i < step_chg_jeita->jeita_fcc_cfg.range_count; i++) {
|
||||
pr_debug("%d %d %d\n",
|
||||
step_chg_jeita->jeita_fcc_cfg.data[i].low_threshold,
|
||||
step_chg_jeita->jeita_fcc_cfg.data[i].high_threshold,
|
||||
step_chg_jeita->jeita_fcc_cfg.data[i].value);
|
||||
}
|
||||
|
||||
pr_debug("jeita-fv-ranges:\n");
|
||||
for (i = 0; i < step_chg_jeita->jeita_fv_cfg.range_count; i++) {
|
||||
pr_debug("%d %d %d\n",
|
||||
step_chg_jeita->jeita_fv_cfg.data[i].low_threshold,
|
||||
step_chg_jeita->jeita_fv_cfg.data[i].high_threshold,
|
||||
step_chg_jeita->jeita_fv_cfg.data[i].value);
|
||||
}
|
||||
|
||||
chip->step_chg_jeita_params = step_chg_jeita;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qbg_load_battery_profile(struct qti_qbg *chip)
|
||||
{
|
||||
struct device_node *node = chip->dev->of_node;
|
||||
|
|
@ -687,7 +931,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip)
|
|||
}
|
||||
|
||||
profile_node = of_batterydata_get_best_profile(chip->batt_node,
|
||||
chip->batt_id_ohm, NULL);
|
||||
chip->batt_id_ohm / 1000, NULL);
|
||||
if (IS_ERR(profile_node)) {
|
||||
rc = PTR_ERR(profile_node);
|
||||
pr_err("Failed to detect valid QBG battery profile, rc=%d\n",
|
||||
|
|
@ -723,7 +967,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip)
|
|||
goto out;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(profile_node, "qcom,fastchg-curr-ma",
|
||||
rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
|
||||
&chip->fastchg_curr_ma);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read battery fastcharge current, rc:%d\n", rc);
|
||||
|
|
@ -738,6 +982,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip)
|
|||
}
|
||||
chip->nominal_capacity = temp[0];
|
||||
|
||||
rc = parse_step_chg_jeita_params(chip, profile_node);
|
||||
out:
|
||||
of_node_put(chip->batt_node);
|
||||
return rc;
|
||||
|
|
@ -868,42 +1113,23 @@ static bool is_battery_present(struct qti_qbg *chip)
|
|||
return present;
|
||||
}
|
||||
|
||||
#define BID_RPULL_OHM 100000
|
||||
#define BID_VREF_MV 1875
|
||||
static int get_batt_id_ohm(struct qti_qbg *chip, u32 *batt_id_ohm)
|
||||
{
|
||||
int rc, batt_id_mv;
|
||||
int64_t denom;
|
||||
int rc, batt_id;
|
||||
|
||||
if (!chip->batt_id_chan)
|
||||
return -EINVAL;
|
||||
|
||||
/* Read battery-id */
|
||||
rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv);
|
||||
rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
batt_id_mv = div_s64(batt_id_mv, 1000);
|
||||
if (batt_id_mv == 0) {
|
||||
*batt_id_ohm = 0;
|
||||
pr_debug("batt_id_mv = 0 from ADC\n");
|
||||
return 0;
|
||||
}
|
||||
*batt_id_ohm = (u32)batt_id;
|
||||
|
||||
denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000;
|
||||
if (denom <= 0) {
|
||||
/* batt id connector might be open, return 0 kohms */
|
||||
*batt_id_ohm = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom);
|
||||
chip->batt_id_ohm = *batt_id_ohm;
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n",
|
||||
batt_id_mv, *batt_id_ohm);
|
||||
qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_ohm=%u\n", *batt_id_ohm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -934,7 +1160,7 @@ static int qbg_setup_battery(struct qti_qbg *chip)
|
|||
/* Update OCV boost headroom compensation value to 4.3V in debug battery case */
|
||||
if (is_debug_batt_id(chip)) {
|
||||
rc = qbg_sdam_write(chip,
|
||||
QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) +
|
||||
QBG_SDAM_BASE(chip, SDAM_CTRL0) +
|
||||
QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, &ocv_boost_val, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1034,13 +1260,6 @@ static int qbg_determine_pon_soc(struct qti_qbg *chip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qbg_psy_set_prop(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *pval)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qbg_psy_get_prop(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *pval)
|
||||
|
|
@ -1061,7 +1280,6 @@ static struct power_supply_desc qbg_psy_desc = {
|
|||
.properties = qbg_psy_props,
|
||||
.num_properties = ARRAY_SIZE(qbg_psy_props),
|
||||
.get_property = qbg_psy_get_prop,
|
||||
.set_property = qbg_psy_set_prop,
|
||||
};
|
||||
|
||||
static int qbg_init_psy(struct qti_qbg *chip)
|
||||
|
|
@ -1121,6 +1339,9 @@ static int qbg_iio_read_raw(struct iio_dev *indio_dev,
|
|||
case PSY_IIO_VOLTAGE_OCV:
|
||||
*val1 = chip->ocv_uv;
|
||||
break;
|
||||
case PSY_IIO_VOLTAGE_AVG:
|
||||
rc = qbg_get_battery_voltage(chip, val1);
|
||||
break;
|
||||
case PSY_IIO_VOLTAGE_NOW:
|
||||
rc = qbg_get_battery_voltage(chip, val1);
|
||||
break;
|
||||
|
|
@ -1228,6 +1449,85 @@ static int qbg_init_iio(struct qti_qbg *chip,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int qbg_get_accumulator_properties(struct qti_qbg *chip,
|
||||
enum QBG_STATE state,
|
||||
enum QBG_SAMPLE_NUM_TYPE *num_of_accum,
|
||||
enum QBG_ACCUM_INTERVAL_TYPE *accum_interval)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int reg = QBG_MAIN_LPM_MEAS_CTL2;
|
||||
unsigned char data = 0;
|
||||
|
||||
if (state >= QBG_STATE_MAX || !num_of_accum || !accum_interval)
|
||||
return -EINVAL;
|
||||
|
||||
switch (state) {
|
||||
case QBG_LPM:
|
||||
reg = QBG_MAIN_LPM_MEAS_CTL2;
|
||||
break;
|
||||
case QBG_MPM:
|
||||
reg = QBG_MAIN_MPM_MEAS_CTL2;
|
||||
break;
|
||||
case QBG_HPM:
|
||||
reg = QBG_MAIN_HPM_MEAS_CTL2;
|
||||
break;
|
||||
case QBG_FAST_CHAR:
|
||||
reg = QBG_MAIN_FAST_CHAR_MEAS_CTL2;
|
||||
break;
|
||||
default:
|
||||
pr_err("Invalid QBG state requested for accumulator properties %u\n",
|
||||
state);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qbg_read(chip, reg, &data, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to MEAS_CTL2 %u, rc=%d\n", reg, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (state == QBG_FAST_CHAR)
|
||||
*num_of_accum = 0;
|
||||
else
|
||||
*num_of_accum = (data & QBG_NUM_OF_ACCUM_MASK) >> QBG_NUM_OF_ACCUM_SHIFT;
|
||||
|
||||
*accum_interval = data & QBG_ACCUM_INTERVAL_MASK;
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_DEVICE, "state:%u num_of_accum:%u accum_interval:%u\n",
|
||||
state, *num_of_accum, *accum_interval);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qbg_get_sample_time_us(struct qti_qbg *chip)
|
||||
{
|
||||
int rc = 0, index;
|
||||
unsigned int interval;
|
||||
enum QBG_ACCUM_INTERVAL_TYPE accum_interval = ACCUM_INTERVAL_100MS;
|
||||
enum QBG_SAMPLE_NUM_TYPE num_accum = SAMPLE_NUM_1;
|
||||
|
||||
for (index = 0; index < QBG_STATE_MAX; index++) {
|
||||
if (index == QBG_PON_OCV)
|
||||
continue;
|
||||
|
||||
rc = qbg_get_accumulator_properties(chip, index, &num_accum,
|
||||
&accum_interval);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (index == QBG_FAST_CHAR)
|
||||
interval = qbg_fast_char_avg_interval[accum_interval];
|
||||
else if (index == QBG_LPM)
|
||||
interval = qbg_lpm_accum_interval[accum_interval];
|
||||
else
|
||||
interval = qbg_accum_interval[accum_interval];
|
||||
|
||||
chip->sample_time_us[index] = interval;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t qbg_device_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
|
|
@ -1360,8 +1660,9 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
|
|||
struct qbg_config __user *config_user;
|
||||
struct qbg_config config;
|
||||
struct qbg_essential_params __user *params_user;
|
||||
struct qbg_step_chg_jeita_params __user *step_chg_params_user;
|
||||
unsigned long rtc_sec;
|
||||
int rc = 0;
|
||||
int rc = 0, i;
|
||||
|
||||
if (!chip) {
|
||||
pr_err("Device private data not set!\n");
|
||||
|
|
@ -1383,28 +1684,59 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
|
|||
switch (cmd) {
|
||||
case QBGIOCXCFG:
|
||||
config_user = (struct qbg_config __user *)arg;
|
||||
|
||||
rc = qbg_get_sample_time_us(chip);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to calculate sample time us, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qbg_sdam_get_battery_id(chip, &chip->sdam_batt_id);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to get battid from sdam, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qbg_sdam_get_essential_param_revid(chip,
|
||||
(u8 *)&chip->essential_param_revid);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to get essential param revid, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
config.current_time = rtc_sec;
|
||||
config.batt_id = chip->batt_id_ohm;
|
||||
config.batt_id = chip->batt_id_ohm / 1000;
|
||||
config.pon_ocv = chip->pon_ocv;
|
||||
config.pon_ibat = chip->pon_ibat;
|
||||
config.pon_tbat = chip->pon_tbat;
|
||||
config.pon_soc = chip->pon_soc;
|
||||
config.float_volt_uv = chip->float_volt_uv;
|
||||
config.fastchg_curr_ma = chip->fastchg_curr_ma;
|
||||
config.vbat_cutoff_mv = chip->vbat_cutoff_mv;
|
||||
config.ibat_cutoff_ma = chip->ibat_cutoff_ma;
|
||||
config.vph_min_mv = chip->vph_min_mv;
|
||||
config.iterm_ma = chip->iterm_ma;
|
||||
config.rconn_mohm = chip->rconn_mohm;
|
||||
config.sdam_batt_id = chip->sdam_batt_id;
|
||||
config.essential_param_revid = chip->essential_param_revid;
|
||||
for (i = 0; i < QBG_STATE_MAX; i++) {
|
||||
config.sample_time_us[i] = chip->sample_time_us[i];
|
||||
qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sample_time_us[%d]:%u\n",
|
||||
i, config.sample_time_us[i]);
|
||||
}
|
||||
|
||||
if (copy_to_user(config_user, (void *)&config, sizeof(config))) {
|
||||
pr_err("Failed to copy QBG config to user\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n",
|
||||
qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sdam_battid:%u essential param revid:%u battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n",
|
||||
config.sdam_batt_id, config.essential_param_revid,
|
||||
config.batt_id, config.pon_ocv,
|
||||
config.pon_ibat, config.pon_soc,
|
||||
config.vbat_cutoff_mv, config.iterm_ma);
|
||||
|
||||
break;
|
||||
case QBGIOCXEPR:
|
||||
params_user = (struct qbg_essential_params __user *)arg;
|
||||
|
|
@ -1441,6 +1773,21 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd,
|
|||
qbg_dbg(chip, QBG_DEBUG_SDAM, "Essential params written, time:%lu secs\n",
|
||||
rtc_sec);
|
||||
|
||||
break;
|
||||
case QBGIOCXSTEPCHGCFG:
|
||||
step_chg_params_user = (struct qbg_step_chg_jeita_params __user *)arg;
|
||||
|
||||
if (copy_to_user(step_chg_params_user, (void *)chip->step_chg_jeita_params,
|
||||
sizeof(struct qbg_step_chg_jeita_params))) {
|
||||
pr_err("Failed to copy QBG step and jeita charge params to user\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXSTEPCHGCFG: jeita_full_fv_10nv:%d jeita_warm_adc_value:0x%x jeita_cool_adc_value:0x%x ttf_calc_mode:%u\n",
|
||||
chip->step_chg_jeita_params->jeita_full_fv_10nv,
|
||||
chip->step_chg_jeita_params->jeita_warm_adc_value,
|
||||
chip->step_chg_jeita_params->jeita_cool_adc_value,
|
||||
chip->step_chg_jeita_params->ttf_calc_mode);
|
||||
|
||||
break;
|
||||
default:
|
||||
pr_err("IOCTL %d not supported\n", cmd);
|
||||
|
|
@ -1538,7 +1885,7 @@ static int qbg_parse_sdam_dt(struct qti_qbg *chip, struct device_node *node)
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(node, "sdam-base", &chip->sdam_base);
|
||||
rc = of_property_read_u32(node, "qcom,sdam-base", &chip->sdam_base);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed to read SDAM base address, rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -65,6 +65,7 @@ struct eud_chip {
|
|||
int eud_irq;
|
||||
unsigned int extcon_id;
|
||||
unsigned int int_status;
|
||||
unsigned int int_mask;
|
||||
bool usb_attach;
|
||||
bool chgr_enable;
|
||||
void __iomem *eud_reg_base;
|
||||
|
|
@ -92,7 +93,7 @@ static inline void msm_eud_enable_irqs(struct eud_chip *chip)
|
|||
{
|
||||
/* Enable vbus, chgr & safe mode warning interrupts */
|
||||
writel_relaxed(EUD_INT_VBUS | EUD_INT_CHGR | EUD_INT_SAFE_MODE,
|
||||
chip->eud_reg_base + EUD_REG_INT1_EN_MASK);
|
||||
chip->eud_reg_base + chip->int_mask);
|
||||
}
|
||||
|
||||
static int msm_eud_hw_is_enabled(struct platform_device *pdev)
|
||||
|
|
@ -506,7 +507,7 @@ static irqreturn_t handle_eud_irq(int irq, void *data)
|
|||
struct eud_chip *chip = data;
|
||||
u8 reg;
|
||||
u32 int_mask_en1 = readl_relaxed(chip->eud_reg_base +
|
||||
EUD_REG_INT1_EN_MASK);
|
||||
chip->int_mask);
|
||||
|
||||
/* read status register and find out which interrupt triggered */
|
||||
reg = readb_relaxed(chip->eud_reg_base + EUD_REG_INT_STATUS_1);
|
||||
|
|
@ -705,6 +706,11 @@ static int msm_eud_probe(struct platform_device *pdev)
|
|||
if (chip->secure_eud_en && check_eud_mode_mgr2(chip))
|
||||
enable = 1;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "interrupt-mask",
|
||||
&chip->int_mask);
|
||||
if (ret)
|
||||
chip->int_mask = EUD_REG_INT1_EN_MASK;
|
||||
|
||||
ret = uart_add_one_port(&eud_uart_driver, port);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to add uart port!\n");
|
||||
|
|
|
|||
|
|
@ -2713,11 +2713,18 @@ EXPORT_SYMBOL(icnss_get_mhi_state);
|
|||
int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode)
|
||||
{
|
||||
int ret;
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
struct icnss_priv *priv;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv) {
|
||||
icnss_pr_err("Platform driver not initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (test_bit(ICNSS_FW_DOWN, &penv->state) ||
|
||||
!test_bit(ICNSS_FW_READY, &penv->state)) {
|
||||
icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n",
|
||||
|
|
@ -2737,11 +2744,13 @@ EXPORT_SYMBOL(icnss_set_fw_log_mode);
|
|||
|
||||
int icnss_force_wake_request(struct device *dev)
|
||||
{
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
struct icnss_priv *priv;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv) {
|
||||
icnss_pr_err("Platform driver not initialized\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -2764,11 +2773,13 @@ EXPORT_SYMBOL(icnss_force_wake_request);
|
|||
|
||||
int icnss_force_wake_release(struct device *dev)
|
||||
{
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
struct icnss_priv *priv;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv) {
|
||||
icnss_pr_err("Platform driver not initialized\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -3336,7 +3347,7 @@ static void icnss_wpss_load(struct work_struct *wpss_load_work)
|
|||
struct icnss_priv *priv = icnss_get_plat_priv();
|
||||
|
||||
priv->subsys = subsystem_get("wpss");
|
||||
if (IS_ERR(priv->subsys))
|
||||
if (IS_ERR_OR_NULL(priv->subsys))
|
||||
icnss_pr_err("Failed to load wpss subsys");
|
||||
}
|
||||
|
||||
|
|
@ -3689,6 +3700,8 @@ static int icnss_smmu_fault_handler(struct iommu_domain *domain,
|
|||
|
||||
if (test_bit(ICNSS_FW_READY, &priv->state)) {
|
||||
fw_down_data.crashed = true;
|
||||
icnss_call_driver_uevent(priv, ICNSS_UEVENT_SMMU_FAULT,
|
||||
&fw_down_data);
|
||||
icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN,
|
||||
&fw_down_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2078,6 +2078,14 @@ int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv)
|
|||
}
|
||||
|
||||
req->mem_seg_len = priv->qdss_mem_seg_len;
|
||||
|
||||
if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) {
|
||||
icnss_pr_err("Invalid seg len %u\n",
|
||||
priv->qdss_mem_seg_len);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < req->mem_seg_len; i++) {
|
||||
icnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
|
||||
qdss_mem[i].va, &qdss_mem[i].pa,
|
||||
|
|
@ -2469,6 +2477,13 @@ static void wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi,
|
|||
}
|
||||
|
||||
priv->qdss_mem_seg_len = ind_msg->mem_seg_len;
|
||||
|
||||
if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) {
|
||||
icnss_pr_err("Invalid seg len %u\n",
|
||||
priv->qdss_mem_seg_len);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->qdss_mem_seg_len; i++) {
|
||||
icnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n",
|
||||
ind_msg->mem_seg[i].size,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/cache.h>
|
||||
|
|
@ -191,9 +191,11 @@ static void __init register_kernel_sections(void)
|
|||
struct md_region ksec_entry;
|
||||
char *data_name = "KDATABSS";
|
||||
char *rodata_name = "KROAIDATA";
|
||||
#ifdef CONFIG_SMP
|
||||
const size_t static_size = __per_cpu_end - __per_cpu_start;
|
||||
void __percpu *base = (void __percpu *)__per_cpu_start;
|
||||
unsigned int cpu;
|
||||
#endif
|
||||
|
||||
strlcpy(ksec_entry.name, data_name, sizeof(ksec_entry.name));
|
||||
ksec_entry.virt_addr = (uintptr_t)_sdata;
|
||||
|
|
@ -209,6 +211,7 @@ static void __init register_kernel_sections(void)
|
|||
if (msm_minidump_add_region(&ksec_entry) < 0)
|
||||
pr_err("Failed to add rodata section in Minidump\n");
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Add percpu static sections */
|
||||
for_each_possible_cpu(cpu) {
|
||||
void *start = per_cpu_ptr(base, cpu);
|
||||
|
|
@ -222,6 +225,7 @@ static void __init register_kernel_sections(void)
|
|||
if (msm_minidump_add_region(&ksec_entry) < 0)
|
||||
pr_err("Failed to add percpu sections in Minidump\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool in_stack_range(
|
||||
|
|
@ -264,7 +268,7 @@ void dump_stack_minidump(u64 sp)
|
|||
|
||||
is_vmap_stack = IS_ENABLED(CONFIG_VMAP_STACK);
|
||||
|
||||
if (sp < KIMAGE_VADDR || sp > -256UL)
|
||||
if (sp < MODULES_END || sp > -256UL)
|
||||
sp = current_stack_pointer;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ static int modem_ramdump(int enable, const struct subsys_desc *subsys)
|
|||
|
||||
static irqreturn_t modem_wdog_bite_intr_handler(int irq, void *dev_data)
|
||||
{
|
||||
struct modem_data *drv = subsys_to_drv(dev_data);
|
||||
struct modem_data *drv = dev_data;
|
||||
|
||||
if (drv->ignore_errors)
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
|||
|
|
@ -371,6 +371,8 @@ int qcom_wdt_pet_suspend(struct device *dev)
|
|||
wdog_dd->freeze_in_progress = true;
|
||||
spin_unlock(&wdog_dd->freeze_lock);
|
||||
del_timer_sync(&wdog_dd->pet_timer);
|
||||
if (wdog_dd->user_pet_enabled)
|
||||
del_timer_sync(&wdog_dd->user_pet_timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_wdt_pet_suspend);
|
||||
|
|
@ -390,6 +392,11 @@ int qcom_wdt_pet_resume(struct device *dev)
|
|||
spin_lock(&wdog_dd->freeze_lock);
|
||||
wdog_dd->pet_timer.expires = jiffies + delay_time;
|
||||
add_timer(&wdog_dd->pet_timer);
|
||||
if (wdog_dd->user_pet_enabled) {
|
||||
delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000);
|
||||
wdog_dd->user_pet_timer.expires = jiffies + delay_time;
|
||||
add_timer(&wdog_dd->user_pet_timer);
|
||||
}
|
||||
wdog_dd->freeze_in_progress = false;
|
||||
spin_unlock(&wdog_dd->freeze_lock);
|
||||
return 0;
|
||||
|
|
@ -480,6 +487,8 @@ static void qcom_wdt_disable(struct msm_watchdog_data *wdog_dd)
|
|||
qcom_wdt_unregister_die_notifier(wdog_dd);
|
||||
unregister_restart_handler(&wdog_dd->restart_blk);
|
||||
del_timer_sync(&wdog_dd->pet_timer);
|
||||
if (wdog_dd->user_pet_enabled)
|
||||
del_timer_sync(&wdog_dd->user_pet_timer);
|
||||
wdog_dd->ops->disable_wdt(wdog_dd);
|
||||
dev_err(wdog_dd->dev, "QCOM Apps Watchdog deactivated\n");
|
||||
}
|
||||
|
|
@ -583,6 +592,8 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev,
|
|||
{
|
||||
struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
unsigned long delay_time = 0;
|
||||
bool already_enabled = wdog_dd->user_pet_enabled;
|
||||
|
||||
ret = strtobool(buf, &wdog_dd->user_pet_enabled);
|
||||
if (ret) {
|
||||
|
|
@ -590,6 +601,12 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000);
|
||||
if (wdog_dd->user_pet_enabled)
|
||||
mod_timer(&wdog_dd->user_pet_timer, jiffies + delay_time);
|
||||
else if (already_enabled)
|
||||
del_timer_sync(&wdog_dd->user_pet_timer);
|
||||
|
||||
__qcom_wdt_user_pet(wdog_dd);
|
||||
|
||||
return count;
|
||||
|
|
@ -650,6 +667,15 @@ static void qcom_wdt_pet_task_wakeup(struct timer_list *t)
|
|||
wdog_dd->timer_fired = sched_clock();
|
||||
wake_up(&wdog_dd->pet_complete);
|
||||
}
|
||||
static void qcom_wdt_user_pet_bite(struct timer_list *t)
|
||||
{
|
||||
struct msm_watchdog_data *wdog_dd =
|
||||
from_timer(wdog_dd, t, user_pet_timer);
|
||||
if (!wdog_dd->user_pet_complete) {
|
||||
dev_info(wdog_dd->dev, "QCOM Apps Watchdog user pet timeout!\n");
|
||||
qcom_wdt_trigger_bite();
|
||||
}
|
||||
}
|
||||
|
||||
static __ref int qcom_wdt_kthread(void *arg)
|
||||
{
|
||||
|
|
@ -751,6 +777,8 @@ int qcom_wdt_remove(struct platform_device *pdev)
|
|||
irq_dispose_mapping(wdog_dd->bark_irq);
|
||||
dev_info(wdog_dd->dev, "QCOM Apps Watchdog Exit - Deactivated\n");
|
||||
del_timer_sync(&wdog_dd->pet_timer);
|
||||
if (wdog_dd->user_pet_enabled)
|
||||
del_timer_sync(&wdog_dd->user_pet_timer);
|
||||
wdog_dd->timer_expired = true;
|
||||
wdog_dd->user_pet_complete = true;
|
||||
kthread_stop(wdog_dd->watchdog_task);
|
||||
|
|
@ -895,6 +923,7 @@ static int qcom_wdt_init(struct msm_watchdog_data *wdog_dd,
|
|||
timer_setup(&wdog_dd->pet_timer, qcom_wdt_pet_task_wakeup, 0);
|
||||
wdog_dd->pet_timer.expires = jiffies + delay_time;
|
||||
add_timer(&wdog_dd->pet_timer);
|
||||
timer_setup(&wdog_dd->user_pet_timer, qcom_wdt_user_pet_bite, 0);
|
||||
val = BIT(EN);
|
||||
if (wdog_dd->wakeup_irq_enable)
|
||||
val |= BIT(UNMASKED_INT_EN);
|
||||
|
|
|
|||
|
|
@ -2002,6 +2002,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "LA-VM usecase\n");
|
||||
}
|
||||
|
||||
geni_mas->spi_rsc.wrapper_dev = &wrapper_pdev->dev;
|
||||
/*
|
||||
* For LE, clocks, gpio and icb voting will be provided by
|
||||
* by LA. The SPI operates in GSI mode only for LE usecase,
|
||||
|
|
@ -2009,7 +2010,6 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||
* in SPI LE dt.
|
||||
*/
|
||||
if (!geni_mas->is_le_vm) {
|
||||
geni_mas->spi_rsc.wrapper_dev = &wrapper_pdev->dev;
|
||||
ret = geni_se_resources_init(rsc, SPI_CORE2X_VOTE,
|
||||
(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ struct msm_geni_serial_port {
|
|||
struct completion s_cmd_timeout;
|
||||
spinlock_t rx_lock;
|
||||
bool pm_auto_suspend_disable;
|
||||
bool is_clock_off;
|
||||
atomic_t is_clock_off;
|
||||
enum uart_error_code uart_error;
|
||||
};
|
||||
|
||||
|
|
@ -1268,7 +1268,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport)
|
|||
static unsigned int ios_log_limit;
|
||||
|
||||
/* when start_tx is called with UART clocks OFF return. */
|
||||
if (uart_console(uport) && msm_port->is_clock_off) {
|
||||
if (uart_console(uport) && (uport->suspended || atomic_read(&msm_port->is_clock_off))) {
|
||||
IPC_LOG_MSG(msm_port->console_log,
|
||||
"%s. Console in suspend state\n", __func__);
|
||||
return;
|
||||
|
|
@ -2166,7 +2166,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
|
|||
bool s_cmd_done = false;
|
||||
bool m_cmd_done = false;
|
||||
|
||||
if (uart_console(uport) && msm_port->is_clock_off) {
|
||||
if (uart_console(uport) && atomic_read(&msm_port->is_clock_off)) {
|
||||
IPC_LOG_MSG(msm_port->console_log,
|
||||
"%s. Console in suspend state\n", __func__);
|
||||
goto exit_geni_serial_isr;
|
||||
|
|
@ -2380,6 +2380,8 @@ static void msm_geni_serial_shutdown(struct uart_port *uport)
|
|||
IPC_LOG_MSG(msm_port->ipc_log_misc,
|
||||
"%s: Error %d pinctrl_select_state\n", __func__, ret);
|
||||
}
|
||||
/* Reset UART error to default during port_close() */
|
||||
msm_port->uart_error = UART_ERROR_DEFAULT;
|
||||
}
|
||||
IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: End\n", __func__);
|
||||
}
|
||||
|
|
@ -2991,11 +2993,11 @@ static void msm_geni_serial_cons_pm(struct uart_port *uport,
|
|||
|
||||
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) {
|
||||
se_geni_resources_on(&msm_port->serial_rsc);
|
||||
msm_port->is_clock_off = false;
|
||||
atomic_set(&msm_port->is_clock_off, 0);
|
||||
} else if (new_state == UART_PM_STATE_OFF &&
|
||||
old_state == UART_PM_STATE_ON) {
|
||||
atomic_set(&msm_port->is_clock_off, 1);
|
||||
se_geni_resources_off(&msm_port->serial_rsc);
|
||||
msm_port->is_clock_off = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3620,6 +3622,7 @@ static int msm_geni_serial_sys_suspend(struct device *dev)
|
|||
struct uart_port *uport = &port->uport;
|
||||
|
||||
if (uart_console(uport) || port->pm_auto_suspend_disable) {
|
||||
IPC_LOG_MSG(port->console_log, "%s start\n", __func__);
|
||||
uart_suspend_port((struct uart_driver *)uport->private_data,
|
||||
uport);
|
||||
IPC_LOG_MSG(port->console_log, "%s\n", __func__);
|
||||
|
|
@ -3652,6 +3655,7 @@ static int msm_geni_serial_sys_resume(struct device *dev)
|
|||
if ((uart_console(uport) &&
|
||||
console_suspend_enabled && uport->suspended) ||
|
||||
port->pm_auto_suspend_disable) {
|
||||
IPC_LOG_MSG(port->console_log, "%s start\n", __func__);
|
||||
uart_resume_port((struct uart_driver *)uport->private_data,
|
||||
uport);
|
||||
IPC_LOG_MSG(port->console_log, "%s\n", __func__);
|
||||
|
|
|
|||
|
|
@ -1485,6 +1485,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
|||
"snps,dis-tx-ipgap-linecheck-quirk");
|
||||
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
|
||||
"snps,parkmode-disable-ss-quirk");
|
||||
dwc->usb2_l1_disable = device_property_read_bool(dev,
|
||||
"snps,usb2-l1-disable");
|
||||
|
||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||
"snps,tx_de_emphasis_quirk");
|
||||
|
|
|
|||
|
|
@ -1363,6 +1363,7 @@ struct dwc3 {
|
|||
unsigned tx_de_emphasis:2;
|
||||
unsigned err_evt_seen:1;
|
||||
unsigned enable_bus_suspend:1;
|
||||
unsigned usb2_l1_disable:1;
|
||||
|
||||
atomic_t in_lpm;
|
||||
bool b_suspend;
|
||||
|
|
|
|||
|
|
@ -4070,6 +4070,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
|
|||
struct dwc3_msm *mdwc = enb->mdwc;
|
||||
char *eud_str;
|
||||
const char *edev_name;
|
||||
bool is_cdp;
|
||||
|
||||
if (!edev || !mdwc)
|
||||
return NOTIFY_DONE;
|
||||
|
|
@ -4094,12 +4095,21 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
|
|||
mdwc->vbus_active = event;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of ADSP based charger detection driving a pulse on
|
||||
* DP to ensure proper CDP detection will be taken care by
|
||||
* ADSP.
|
||||
*/
|
||||
is_cdp = ((mdwc->apsd_source == IIO) &&
|
||||
(get_chg_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP)) ||
|
||||
((mdwc->apsd_source == PSY) &&
|
||||
(get_chg_type(mdwc) == POWER_SUPPLY_USB_TYPE_CDP));
|
||||
|
||||
/*
|
||||
* Drive a pulse on DP to ensure proper CDP detection
|
||||
* and only when the vbus connect event is a valid one.
|
||||
*/
|
||||
if (get_chg_type(mdwc) == POWER_SUPPLY_USB_TYPE_CDP &&
|
||||
mdwc->vbus_active && !mdwc->check_eud_state) {
|
||||
if (is_cdp && mdwc->vbus_active && !mdwc->check_eud_state) {
|
||||
dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n");
|
||||
mdwc->hs_phy->charger_detect(mdwc->hs_phy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -971,7 +971,7 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
|
|||
dbg_event(dep->number, "DISABLE", ret);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
pm_runtime_mark_last_busy(dwc->sysdev);
|
||||
pm_runtime_put_sync_autosuspend(dwc->sysdev);
|
||||
pm_runtime_put_autosuspend(dwc->sysdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -4369,7 +4369,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
dwc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
dwc->gadget.sg_supported = true;
|
||||
dwc->gadget.name = "dwc3-gadget";
|
||||
dwc->gadget.lpm_capable = true;
|
||||
dwc->gadget.lpm_capable = !dwc->usb2_l1_disable;
|
||||
|
||||
/*
|
||||
* FIXME We might be setting max_speed to <SUPER, however versions
|
||||
|
|
|
|||
|
|
@ -1726,11 +1726,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
count_configs(cdev, USB_DT_DEVICE);
|
||||
cdev->desc.bMaxPacketSize0 =
|
||||
cdev->gadget->ep0->maxpacket;
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0200);
|
||||
if (gadget_is_superspeed(gadget)) {
|
||||
if (gadget->speed >= USB_SPEED_SUPER) {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0320);
|
||||
cdev->desc.bMaxPacketSize0 = 9;
|
||||
} else {
|
||||
} else if (gadget->lpm_capable) {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -164,6 +164,14 @@ int usb_assign_descriptors(struct usb_function *f,
|
|||
{
|
||||
struct usb_gadget *g = f->config->cdev->gadget;
|
||||
|
||||
/* super-speed-plus descriptor falls back to super-speed one,
|
||||
* if such a descriptor was provided, thus avoiding a NULL
|
||||
* pointer dereference if a 5gbps capable gadget is used with
|
||||
* a 10gbps capable config (device port + cable + host port)
|
||||
*/
|
||||
if (!ssp)
|
||||
ssp = ss;
|
||||
|
||||
if (fs) {
|
||||
f->fs_descriptors = usb_copy_descriptors(fs);
|
||||
if (!f->fs_descriptors)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <asm/ioctls.h>
|
||||
#include <asm-generic/termios.h>
|
||||
#include <linux/usb/dwc3-msm.h>
|
||||
|
||||
#define DEVICE_NAME "at_usb"
|
||||
#define MODULE_NAME "msm_usb_bridge"
|
||||
|
|
@ -99,6 +100,7 @@ struct f_cdev {
|
|||
struct list_head read_pool;
|
||||
struct list_head read_queued;
|
||||
struct list_head write_pool;
|
||||
struct list_head write_pending;
|
||||
|
||||
/* current active USB RX request */
|
||||
struct usb_request *current_rx_req;
|
||||
|
|
@ -127,6 +129,8 @@ struct f_cdev {
|
|||
struct workqueue_struct *fcdev_wq;
|
||||
bool is_connected;
|
||||
bool port_open;
|
||||
bool is_suspended;
|
||||
bool pending_state_notify;
|
||||
|
||||
unsigned long nbytes_from_host;
|
||||
unsigned long nbytes_to_host;
|
||||
|
|
@ -536,19 +540,56 @@ static int usb_cser_set_alt(struct usb_function *f, unsigned int intf,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int port_notify_serial_state(struct cserial *cser);
|
||||
|
||||
static void usb_cser_resume(struct usb_function *f)
|
||||
{
|
||||
struct f_cdev *port = func_to_port(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (cdev->gadget->speed >= USB_SPEED_SUPER && port->func_is_suspended) {
|
||||
if (port->func_wakeup_pending) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"func_wakeup for port:%s\n", port->name);
|
||||
usb_func_wakeup(&port->port_usb.func);
|
||||
port->func_wakeup_pending = false;
|
||||
struct usb_request *req, *t;
|
||||
struct usb_ep *in;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
port->is_suspended = false;
|
||||
|
||||
/* process pending state notifications */
|
||||
if (port->pending_state_notify)
|
||||
port_notify_serial_state(&port->port_usb);
|
||||
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
in = port->port_usb.in;
|
||||
/* process any pending requests */
|
||||
list_for_each_entry_safe(req, t, &port->write_pending, list) {
|
||||
list_del_init(&req->list);
|
||||
if (!port->is_connected) {
|
||||
pr_err("%s: cable is disconnected.\n", __func__);
|
||||
list_add(&req->list, &port->write_pool);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
ret = usb_ep_queue(in, req, GFP_KERNEL);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (ret) {
|
||||
pr_err("EP QUEUE failed:%d\n", ret);
|
||||
list_add(&req->list, &port->write_pool);
|
||||
} else {
|
||||
port->nbytes_from_port_bridge += req->length;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
}
|
||||
|
||||
static void usb_cser_suspend(struct usb_function *f)
|
||||
{
|
||||
struct f_cdev *port = func_to_port(f);
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
port->is_suspended = true;
|
||||
}
|
||||
|
||||
static int usb_cser_func_suspend(struct usb_function *f, u8 options)
|
||||
|
|
@ -557,11 +598,31 @@ static int usb_cser_func_suspend(struct usb_function *f, u8 options)
|
|||
|
||||
port->func_wakeup_allowed =
|
||||
!!(options & (USB_INTRF_FUNC_SUSPEND_RW >> 8));
|
||||
port->func_is_suspended = options & (USB_INTRF_FUNC_SUSPEND_LP >> 8);
|
||||
|
||||
if (options & (USB_INTRF_FUNC_SUSPEND_LP >> 8)) {
|
||||
if (!port->func_is_suspended) {
|
||||
usb_cser_suspend(f);
|
||||
port->func_is_suspended = true;
|
||||
} else {
|
||||
if (port->func_is_suspended) {
|
||||
port->func_is_suspended = false;
|
||||
usb_cser_resume(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_cser_get_remote_wakeup_capable(struct usb_function *f,
|
||||
struct usb_gadget *g)
|
||||
{
|
||||
struct f_cdev *port = func_to_port(f);
|
||||
|
||||
return ((g->speed >= USB_SPEED_SUPER && port->func_wakeup_allowed) ||
|
||||
(g->speed < USB_SPEED_SUPER && usb_get_remote_wakeup_status(g)));
|
||||
|
||||
}
|
||||
|
||||
static int usb_cser_get_status(struct usb_function *f)
|
||||
{
|
||||
#ifdef CONFIG_USB_FUNC_WAKEUP_SUPPORTED
|
||||
|
|
@ -643,7 +704,16 @@ static int port_notify_serial_state(struct cserial *cser)
|
|||
unsigned long flags;
|
||||
struct usb_composite_dev *cdev = port->port_usb.func.config->cdev;
|
||||
|
||||
if (port->is_suspended) {
|
||||
port->pending_state_notify = true;
|
||||
pr_debug("%s: port is suspended\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (port->pending_state_notify)
|
||||
port->pending_state_notify = false;
|
||||
|
||||
if (!port->port_usb.pending) {
|
||||
port->port_usb.pending = true;
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
|
@ -1133,6 +1203,7 @@ static void usb_cser_stop_io(struct f_cdev *port)
|
|||
usb_cser_free_requests(out, &port->read_queued);
|
||||
usb_cser_free_requests(out, &port->read_pool);
|
||||
usb_cser_free_requests(in, &port->write_pool);
|
||||
usb_cser_free_requests(in, &port->write_pending);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -1298,6 +1369,9 @@ ssize_t f_cdev_write(struct file *file,
|
|||
struct list_head *pool;
|
||||
unsigned int xfer_size;
|
||||
struct usb_ep *in;
|
||||
struct cserial *cser;
|
||||
struct usb_function *func;
|
||||
struct usb_gadget *gadget;
|
||||
|
||||
port = file->private_data;
|
||||
if (!port) {
|
||||
|
|
@ -1305,6 +1379,9 @@ ssize_t f_cdev_write(struct file *file,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cser = &port->port_usb;
|
||||
func = &cser->func;
|
||||
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
pr_debug("write on port(%s)(%pK)\n", port->name, port);
|
||||
|
||||
|
|
@ -1336,9 +1413,40 @@ ssize_t f_cdev_write(struct file *file,
|
|||
if (ret) {
|
||||
pr_err("copy_from_user failed: err %d\n", ret);
|
||||
ret = -EFAULT;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
req->length = xfer_size;
|
||||
req->zero = 1;
|
||||
if (port->is_suspended) {
|
||||
gadget = cser->func.config->cdev->gadget;
|
||||
if (!usb_cser_get_remote_wakeup_capable(func, gadget)) {
|
||||
pr_debug("%s remote-wakeup not capable\n",
|
||||
__func__);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
list_add(&req->list, &port->write_pending);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
if (gadget->speed >= USB_SPEED_SUPER
|
||||
&& port->func_is_suspended)
|
||||
ret = usb_func_wakeup(func);
|
||||
else
|
||||
ret = usb_gadget_wakeup(gadget);
|
||||
|
||||
if (ret < 0 && ret != -EACCES && ret != -EAGAIN) {
|
||||
pr_err("Remote wakeup failed:%d\n", ret);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
req = list_first_entry(&port->write_pending,
|
||||
struct usb_request, list);
|
||||
list_del(&req->list);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
goto err_exit;
|
||||
}
|
||||
} else {
|
||||
req->length = xfer_size;
|
||||
req->zero = 1;
|
||||
ret = usb_ep_queue(in, req, GFP_KERNEL);
|
||||
if (ret) {
|
||||
pr_err("EP QUEUE failed:%d\n", ret);
|
||||
|
|
@ -1350,19 +1458,18 @@ ssize_t f_cdev_write(struct file *file,
|
|||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
}
|
||||
|
||||
err_exit:
|
||||
if (ret) {
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
/* USB cable is connected, add it back otherwise free request */
|
||||
if (port->is_connected)
|
||||
list_add(&req->list, &port->write_pool);
|
||||
else
|
||||
usb_cser_free_req(in, req);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return xfer_size;
|
||||
|
||||
err_exit:
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
/* USB cable is connected, add it back otherwise free request */
|
||||
if (port->is_connected)
|
||||
list_add(&req->list, &port->write_pool);
|
||||
else
|
||||
usb_cser_free_req(in, req);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int f_cdev_poll(struct file *file, poll_table *wait)
|
||||
|
|
@ -1598,6 +1705,8 @@ int usb_cser_connect(struct f_cdev *port)
|
|||
cser->pending = false;
|
||||
cser->q_again = false;
|
||||
port->is_connected = true;
|
||||
port->pending_state_notify = false;
|
||||
port->is_suspended = false;
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
usb_cser_start_io(port);
|
||||
|
|
@ -1799,6 +1908,7 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno)
|
|||
INIT_LIST_HEAD(&port->read_pool);
|
||||
INIT_LIST_HEAD(&port->read_queued);
|
||||
INIT_LIST_HEAD(&port->write_pool);
|
||||
INIT_LIST_HEAD(&port->write_pending);
|
||||
|
||||
port->fcdev_wq = create_singlethread_workqueue(port->name);
|
||||
if (!port->fcdev_wq) {
|
||||
|
|
@ -2089,6 +2199,7 @@ static struct usb_function *cser_alloc(struct usb_function_instance *fi)
|
|||
port->port_usb.func.setup = usb_cser_setup;
|
||||
port->port_usb.func.func_suspend = usb_cser_func_suspend;
|
||||
port->port_usb.func.resume = usb_cser_resume;
|
||||
port->port_usb.func.suspend = usb_cser_suspend;
|
||||
port->port_usb.func.get_status = usb_cser_get_status;
|
||||
port->port_usb.func.free_func = usb_cser_free_func;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,13 +28,43 @@ struct f_gser {
|
|||
struct gserial port;
|
||||
u8 data_id;
|
||||
u8 port_num;
|
||||
spinlock_t lock;
|
||||
|
||||
struct usb_ep *notify;
|
||||
struct usb_request *notify_req;
|
||||
|
||||
u8 online;
|
||||
u8 pending;
|
||||
struct usb_cdc_line_coding port_line_coding;
|
||||
|
||||
/* SetControlLineState request */
|
||||
u16 port_handshake_bits;
|
||||
#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
|
||||
#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
|
||||
|
||||
/* SerialState notification */
|
||||
u16 serial_state;
|
||||
#define ACM_CTRL_OVERRUN (1 << 6)
|
||||
#define ACM_CTRL_PARITY (1 << 5)
|
||||
#define ACM_CTRL_FRAMING (1 << 4)
|
||||
#define ACM_CTRL_RI (1 << 3)
|
||||
#define ACM_CTRL_BRK (1 << 2)
|
||||
#define ACM_CTRL_DSR (1 << 1)
|
||||
#define ACM_CTRL_DCD (1 << 0)
|
||||
};
|
||||
|
||||
static inline struct f_gser *port_to_gser(struct gserial *p)
|
||||
{
|
||||
return container_of(p, struct f_gser, port);
|
||||
}
|
||||
|
||||
static inline struct f_gser *func_to_gser(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct f_gser, port.func);
|
||||
}
|
||||
|
||||
#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
|
||||
#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* interface descriptor: */
|
||||
|
|
@ -43,15 +73,55 @@ static struct usb_interface_descriptor gser_interface_desc = {
|
|||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
.bNumEndpoints = 2,
|
||||
.bNumEndpoints = 3,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0x40,
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc gser_header_desc = {
|
||||
.bLength = sizeof(gser_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor
|
||||
gser_call_mgmt_descriptor = {
|
||||
.bLength = sizeof(gser_call_mgmt_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
|
||||
.bmCapabilities = 0,
|
||||
/* .bDataInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_acm_descriptor gser_descriptor = {
|
||||
.bLength = sizeof(gser_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
.bmCapabilities = USB_CDC_CAP_LINE,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc gser_union_desc = {
|
||||
.bLength = sizeof(gser_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
/* .bMasterInterface0 = DYNAMIC */
|
||||
/* .bSlaveInterface0 = DYNAMIC */
|
||||
};
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
|
@ -68,12 +138,25 @@ static struct usb_endpoint_descriptor gser_fs_out_desc = {
|
|||
|
||||
static struct usb_descriptor_header *gser_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_header_desc,
|
||||
(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_union_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_notify_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_out_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* high speed support: */
|
||||
static struct usb_endpoint_descriptor gser_hs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
|
|
@ -91,6 +174,11 @@ static struct usb_endpoint_descriptor gser_hs_out_desc = {
|
|||
|
||||
static struct usb_descriptor_header *gser_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_header_desc,
|
||||
(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_union_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_notify_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_out_desc,
|
||||
NULL,
|
||||
|
|
@ -115,8 +203,33 @@ static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
|
|||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_ss_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor gser_ss_notify_comp_desc = {
|
||||
.bLength = sizeof(gser_ss_notify_comp_desc),
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
/* the following 2 values can be tweaked if necessary */
|
||||
/* .bMaxBurst = 0, */
|
||||
/* .bmAttributes = 0, */
|
||||
.wBytesPerInterval = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_ss_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_header_desc,
|
||||
(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_union_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_notify_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_notify_comp_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_out_desc,
|
||||
|
|
@ -127,7 +240,7 @@ static struct usb_descriptor_header *gser_ss_function[] = {
|
|||
/* string descriptors: */
|
||||
|
||||
static struct usb_string gser_string_defs[] = {
|
||||
[0].s = "Generic Serial",
|
||||
[0].s = "DUN over Serial",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
|
|
@ -142,13 +255,131 @@ static struct usb_gadget_strings *gser_strings[] = {
|
|||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void gser_complete_set_line_coding(struct usb_ep *ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
struct f_gser *gser = ep->driver_data;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
|
||||
if (req->status != 0) {
|
||||
dev_dbg(&cdev->gadget->dev, "gser ttyGS%d completion, err %d\n",
|
||||
gser->port_num, req->status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* normal completion */
|
||||
if (req->actual != sizeof(gser->port_line_coding)) {
|
||||
dev_dbg(&cdev->gadget->dev, "gser ttyGS%d short resp, len %d\n",
|
||||
gser->port_num, req->actual);
|
||||
usb_ep_set_halt(ep);
|
||||
} else {
|
||||
struct usb_cdc_line_coding *value = req->buf;
|
||||
|
||||
gser->port_line_coding = *value;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct usb_request *req = cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
|
||||
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
|
||||
/* SET_LINE_CODING ... just read and save what the host sends */
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_SET_LINE_CODING:
|
||||
if (w_length != sizeof(struct usb_cdc_line_coding))
|
||||
goto invalid;
|
||||
|
||||
value = w_length;
|
||||
cdev->gadget->ep0->driver_data = gser;
|
||||
req->complete = gser_complete_set_line_coding;
|
||||
break;
|
||||
|
||||
/* GET_LINE_CODING ... return what host sent, or initial value */
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_GET_LINE_CODING:
|
||||
value = min_t(unsigned int, w_length,
|
||||
sizeof(struct usb_cdc_line_coding));
|
||||
memcpy(req->buf, &gser->port_line_coding, value);
|
||||
break;
|
||||
|
||||
/* SET_CONTROL_LINE_STATE ... save what the host sent */
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
||||
|
||||
value = 0;
|
||||
gser->port_handshake_bits = w_value;
|
||||
pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d RST:%d\n",
|
||||
__func__, w_value & ACM_CTRL_DTR ? 1 : 0,
|
||||
w_value & ACM_CTRL_RTS ? 1 : 0);
|
||||
|
||||
if (gser->port.notify_modem)
|
||||
gser->port.notify_modem(&gser->port, 0, w_value);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid:
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"invalid control req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
}
|
||||
|
||||
/* respond with data transfer or status phase? */
|
||||
if (value >= 0) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
|
||||
gser->port_num, ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
req->zero = 0;
|
||||
req->length = value;
|
||||
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0)
|
||||
ERROR(cdev, "gser response on ttyGS%d, err %d\n",
|
||||
gser->port_num, value);
|
||||
}
|
||||
|
||||
/* device either stalls (value < 0) or reports success */
|
||||
return value;
|
||||
}
|
||||
|
||||
static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
int rc = 0;
|
||||
|
||||
/* we know alt == 0, so this is an activation or a reset */
|
||||
if (gser->notify->driver_data) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"reset generic ctl ttyGS%d\n", gser->port_num);
|
||||
usb_ep_disable(gser->notify);
|
||||
}
|
||||
|
||||
if (!gser->notify->desc) {
|
||||
if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
|
||||
gser->notify->desc = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
rc = usb_ep_enable(gser->notify);
|
||||
if (rc) {
|
||||
ERROR(cdev, "can't enable %s, result %d\n",
|
||||
gser->notify->name, rc);
|
||||
return rc;
|
||||
}
|
||||
gser->notify->driver_data = gser;
|
||||
|
||||
if (gser->port.in->enabled) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
|
|
@ -166,7 +397,9 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
}
|
||||
}
|
||||
gserial_connect(&gser->port, gser->port_num);
|
||||
return 0;
|
||||
gser->online = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void gser_disable(struct usb_function *f)
|
||||
|
|
@ -177,6 +410,178 @@ static void gser_disable(struct usb_function *f)
|
|||
dev_dbg(&cdev->gadget->dev,
|
||||
"generic ttyGS%d deactivated\n", gser->port_num);
|
||||
gserial_disconnect(&gser->port);
|
||||
usb_ep_disable(gser->notify);
|
||||
gser->notify->driver_data = NULL;
|
||||
gser->online = 0;
|
||||
}
|
||||
|
||||
static int gser_notify(struct f_gser *gser, u8 type, u16 value,
|
||||
void *data, unsigned int length)
|
||||
{
|
||||
struct usb_ep *ep = gser->notify;
|
||||
struct usb_request *req;
|
||||
struct usb_cdc_notification *notify;
|
||||
const unsigned int len = sizeof(*notify) + length;
|
||||
void *buf;
|
||||
int status;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
|
||||
req = gser->notify_req;
|
||||
gser->notify_req = NULL;
|
||||
gser->pending = false;
|
||||
|
||||
req->length = len;
|
||||
notify = req->buf;
|
||||
buf = notify + 1;
|
||||
|
||||
notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
|
||||
| USB_RECIP_INTERFACE;
|
||||
notify->bNotificationType = type;
|
||||
notify->wValue = cpu_to_le16(value);
|
||||
notify->wIndex = cpu_to_le16(gser->data_id);
|
||||
notify->wLength = cpu_to_le16(length);
|
||||
memcpy(buf, data, length);
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
|
||||
gser->port_num, status);
|
||||
gser->notify_req = req;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int gser_notify_serial_state(struct f_gser *gser)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
|
||||
spin_lock_irqsave(&gser->lock, flags);
|
||||
if (gser->notify_req) {
|
||||
DBG(cdev, "gser ttyGS%d serial state %04x\n",
|
||||
gser->port_num, gser->serial_state);
|
||||
status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
|
||||
0, &gser->serial_state,
|
||||
sizeof(gser->serial_state));
|
||||
} else {
|
||||
gser->pending = true;
|
||||
status = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&gser->lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_gser *gser = req->context;
|
||||
u8 doit = false;
|
||||
unsigned long flags;
|
||||
|
||||
/* on this call path we do NOT hold the port spinlock,
|
||||
* which is why ACM needs its own spinlock
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&gser->lock, flags);
|
||||
if (req->status != -ESHUTDOWN)
|
||||
doit = gser->pending;
|
||||
|
||||
gser->notify_req = req;
|
||||
spin_unlock_irqrestore(&gser->lock, flags);
|
||||
|
||||
if (doit && gser->online)
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static void gser_connect(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static unsigned int gser_get_dtr(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
if (gser->port_handshake_bits & ACM_CTRL_DTR)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int gser_get_rts(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
if (gser->port_handshake_bits & ACM_CTRL_RTS)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int gser_send_carrier_detect(struct gserial *port,
|
||||
unsigned int yes)
|
||||
{
|
||||
u16 state;
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_DCD;
|
||||
if (yes)
|
||||
state |= ACM_CTRL_DCD;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static unsigned int gser_send_ring_indicator(struct gserial *port,
|
||||
unsigned int yes)
|
||||
{
|
||||
u16 state;
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_RI;
|
||||
if (yes)
|
||||
state |= ACM_CTRL_RI;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static void gser_disconnect(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static int gser_send_break(struct gserial *port, int duration)
|
||||
{
|
||||
u16 state;
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_BRK;
|
||||
if (duration)
|
||||
state |= ACM_CTRL_BRK;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static int gser_send_modem_ctrl_bits(struct gserial *port, int ctrl_bits)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
gser->serial_state = ctrl_bits;
|
||||
|
||||
return gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -222,6 +627,21 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
goto fail;
|
||||
gser->port.out = ep;
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
gser->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
/* allocate notification */
|
||||
gser->notify_req = gs_alloc_req(ep,
|
||||
sizeof(struct usb_cdc_notification) + 2,
|
||||
GFP_KERNEL);
|
||||
if (!gser->notify_req)
|
||||
goto fail;
|
||||
|
||||
gser->notify_req->complete = gser_notify_complete;
|
||||
gser->notify_req->context = gser;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
|
|
@ -232,6 +652,15 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
|
||||
gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
gser_hs_notify_desc.bEndpointAddress =
|
||||
gser_fs_notify_desc.bEndpointAddress;
|
||||
}
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
gser_ss_notify_desc.bEndpointAddress =
|
||||
gser_fs_notify_desc.bEndpointAddress;
|
||||
}
|
||||
|
||||
status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
|
||||
gser_ss_function, NULL);
|
||||
if (status)
|
||||
|
|
@ -244,6 +673,18 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (gser->notify_req)
|
||||
gs_free_req(gser->notify, gser->notify_req);
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (gser->notify)
|
||||
gser->notify->driver_data = NULL;
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (gser->port.out)
|
||||
gser->port.out->driver_data = NULL;
|
||||
if (gser->port.in)
|
||||
gser->port.in->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
@ -324,7 +765,10 @@ static void gser_free(struct usb_function *f)
|
|||
|
||||
static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
gs_free_req(gser->notify, gser->notify_req);
|
||||
}
|
||||
|
||||
static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
||||
|
|
@ -339,6 +783,7 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
|||
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
|
||||
spin_lock_init(&gser->lock);
|
||||
gser->port_num = opts->port_num;
|
||||
|
||||
gser->port.func.name = "gser";
|
||||
|
|
@ -348,6 +793,15 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
|||
gser->port.func.set_alt = gser_set_alt;
|
||||
gser->port.func.disable = gser_disable;
|
||||
gser->port.func.free_func = gser_free;
|
||||
gser->port.func.setup = gser_setup;
|
||||
gser->port.connect = gser_connect;
|
||||
gser->port.get_dtr = gser_get_dtr;
|
||||
gser->port.get_rts = gser_get_rts;
|
||||
gser->port.send_carrier_detect = gser_send_carrier_detect;
|
||||
gser->port.send_ring_indicator = gser_send_ring_indicator;
|
||||
gser->port.send_modem_ctrl_bits = gser_send_modem_ctrl_bits;
|
||||
gser->port.disconnect = gser_disconnect;
|
||||
gser->port.send_break = gser_send_break;
|
||||
|
||||
return &gser->port.func;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,23 @@ struct gserial {
|
|||
|
||||
/* REVISIT avoid this CDC-ACM support harder ... */
|
||||
struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
|
||||
u16 serial_state;
|
||||
|
||||
/* control signal callbacks*/
|
||||
unsigned int (*get_dtr)(struct gserial *p);
|
||||
unsigned int (*get_rts)(struct gserial *p);
|
||||
|
||||
/* notification callbacks */
|
||||
void (*connect)(struct gserial *p);
|
||||
void (*disconnect)(struct gserial *p);
|
||||
int (*send_break)(struct gserial *p, int duration);
|
||||
unsigned int (*send_carrier_detect)(struct gserial *p,
|
||||
unsigned int yes);
|
||||
unsigned int (*send_ring_indicator)(struct gserial *p,
|
||||
unsigned int yes);
|
||||
int (*send_modem_ctrl_bits)(struct gserial *p, int ctrl_bits);
|
||||
/* notification changes to modem */
|
||||
void (*notify_modem)(void *gser, u8 portno, int ctrl_bits);
|
||||
};
|
||||
|
||||
/* utilities to allocate/free request and buffer */
|
||||
|
|
|
|||
|
|
@ -204,10 +204,13 @@ static unsigned int fuse_req_hash(u64 unique)
|
|||
/**
|
||||
* A new request is available, wake fiq->waitq
|
||||
*/
|
||||
static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq)
|
||||
static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync)
|
||||
__releases(fiq->lock)
|
||||
{
|
||||
wake_up(&fiq->waitq);
|
||||
if (sync)
|
||||
wake_up_sync(&fiq->waitq);
|
||||
else
|
||||
wake_up(&fiq->waitq);
|
||||
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
|
||||
spin_unlock(&fiq->lock);
|
||||
}
|
||||
|
|
@ -220,14 +223,14 @@ const struct fuse_iqueue_ops fuse_dev_fiq_ops = {
|
|||
EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops);
|
||||
|
||||
static void queue_request_and_unlock(struct fuse_iqueue *fiq,
|
||||
struct fuse_req *req)
|
||||
struct fuse_req *req, bool sync)
|
||||
__releases(fiq->lock)
|
||||
{
|
||||
req->in.h.len = sizeof(struct fuse_in_header) +
|
||||
fuse_len_args(req->args->in_numargs,
|
||||
(struct fuse_arg *) req->args->in_args);
|
||||
list_add_tail(&req->list, &fiq->pending);
|
||||
fiq->ops->wake_pending_and_unlock(fiq);
|
||||
fiq->ops->wake_pending_and_unlock(fiq, sync);
|
||||
}
|
||||
|
||||
void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
|
||||
|
|
@ -242,7 +245,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
|
|||
if (fiq->connected) {
|
||||
fiq->forget_list_tail->next = forget;
|
||||
fiq->forget_list_tail = forget;
|
||||
fiq->ops->wake_forget_and_unlock(fiq);
|
||||
fiq->ops->wake_forget_and_unlock(fiq, 0);
|
||||
} else {
|
||||
kfree(forget);
|
||||
spin_unlock(&fiq->lock);
|
||||
|
|
@ -262,7 +265,7 @@ static void flush_bg_queue(struct fuse_conn *fc)
|
|||
fc->active_background++;
|
||||
spin_lock(&fiq->lock);
|
||||
req->in.h.unique = fuse_get_unique(fiq);
|
||||
queue_request_and_unlock(fiq, req);
|
||||
queue_request_and_unlock(fiq, req, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +354,7 @@ static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
|
|||
spin_unlock(&fiq->lock);
|
||||
return 0;
|
||||
}
|
||||
fiq->ops->wake_interrupt_and_unlock(fiq);
|
||||
fiq->ops->wake_interrupt_and_unlock(fiq, 0);
|
||||
} else {
|
||||
spin_unlock(&fiq->lock);
|
||||
}
|
||||
|
|
@ -417,7 +420,7 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
|
|||
/* acquire extra reference, since request is still needed
|
||||
after fuse_request_end() */
|
||||
__fuse_get_request(req);
|
||||
queue_request_and_unlock(fiq, req);
|
||||
queue_request_and_unlock(fiq, req, 1);
|
||||
|
||||
request_wait_answer(fc, req);
|
||||
/* Pairs with smp_wmb() in fuse_request_end() */
|
||||
|
|
@ -588,7 +591,7 @@ static int fuse_simple_notify_reply(struct fuse_conn *fc,
|
|||
|
||||
spin_lock(&fiq->lock);
|
||||
if (fiq->connected) {
|
||||
queue_request_and_unlock(fiq, req);
|
||||
queue_request_and_unlock(fiq, req, 0);
|
||||
} else {
|
||||
err = -ENODEV;
|
||||
spin_unlock(&fiq->lock);
|
||||
|
|
|
|||
|
|
@ -379,19 +379,19 @@ struct fuse_iqueue_ops {
|
|||
/**
|
||||
* Signal that a forget has been queued
|
||||
*/
|
||||
void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq)
|
||||
void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq, bool sync)
|
||||
__releases(fiq->lock);
|
||||
|
||||
/**
|
||||
* Signal that an INTERRUPT request has been queued
|
||||
*/
|
||||
void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq)
|
||||
void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq, bool sync)
|
||||
__releases(fiq->lock);
|
||||
|
||||
/**
|
||||
* Signal that a request has been queued
|
||||
*/
|
||||
void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq)
|
||||
void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq, bool sync)
|
||||
__releases(fiq->lock);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -474,6 +474,8 @@ gen_headers_out_arm = [
|
|||
"linux/qemu_fw_cfg.h",
|
||||
"linux/qg.h",
|
||||
"linux/qg-profile.h",
|
||||
"linux/qbg.h",
|
||||
"linux/qbg-profile.h",
|
||||
"linux/qnx4_fs.h",
|
||||
"linux/qnxtypes.h",
|
||||
"linux/qrng.h",
|
||||
|
|
|
|||
|
|
@ -469,6 +469,8 @@ gen_headers_out_arm64 = [
|
|||
"linux/qemu_fw_cfg.h",
|
||||
"linux/qg.h",
|
||||
"linux/qg-profile.h",
|
||||
"linux/qbg.h",
|
||||
"linux/qbg-profile.h",
|
||||
"linux/qnx4_fs.h",
|
||||
"linux/qnxtypes.h",
|
||||
"linux/qrng.h",
|
||||
|
|
|
|||
|
|
@ -151,4 +151,7 @@
|
|||
|
||||
/* USB */
|
||||
#define PSY_IIO_MOISTURE_DETECTION_EN 0x7b
|
||||
|
||||
/* BMS */
|
||||
#define PSY_IIO_CLEAR_SOH 0x7c
|
||||
#endif /* __QTI_POWER_SUPPLY_IIO_H__ */
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@
|
|||
#define CAM_CPAS_FUSE_FEATURE_MAX 10
|
||||
|
||||
/* Flash type*/
|
||||
#define CAM_FLASH_TYPE_GPIO 0
|
||||
#define CAM_FLASH_TYPE_PMIC 0
|
||||
#define CAM_FLASH_TYPE_I2C 1
|
||||
#define CAM_FLASH_TYPE_PMIC 2
|
||||
#define CAM_FLASH_TYPE_GPIO 2
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -89,7 +89,4 @@ int btpower_get_chipset_version(void);
|
|||
|
||||
#define TCS_CMD_IO_ADDR_OFFSET 0x4
|
||||
|
||||
/* total number of power src */
|
||||
#define BT_POWER_SRC_SIZE 30
|
||||
|
||||
#endif /* __LINUX_BLUETOOTH_POWER_H */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _IPA_ETH_H_
|
||||
|
|
@ -1094,5 +1094,9 @@ int ipa_eth_client_set_perf_profile(struct ipa_eth_client *client,
|
|||
struct ipa_eth_perf_profile *profile);
|
||||
int ipa_eth_client_conn_evt(struct ipa_ecm_msg *msg);
|
||||
int ipa_eth_client_disconn_evt(struct ipa_ecm_msg *msg);
|
||||
enum ipa_client_type ipa_eth_get_ipa_client_type_from_eth_type(
|
||||
enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir);
|
||||
bool ipa_eth_client_exist(
|
||||
enum ipa_eth_client_type eth_client_type, int inst_id);
|
||||
|
||||
#endif // _IPA_ETH_H_
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ struct ipa_usb_data {
|
|||
|
||||
int (*ipa_usb_xdci_resume)(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
||||
enum ipa_usb_teth_prot teth_prot);
|
||||
|
||||
bool (*ipa_usb_is_teth_prot_connected)(enum ipa_usb_teth_prot usb_teth_prot);
|
||||
};
|
||||
|
||||
struct ipa_wdi3_data {
|
||||
|
|
@ -199,6 +201,8 @@ struct ipa_wdi3_data {
|
|||
int (*ipa_wdi_sw_stats)(struct ipa_wdi_tx_info *info);
|
||||
|
||||
int (*ipa_get_wdi_version)(void);
|
||||
|
||||
bool (*ipa_wdi_is_tx1_used)(void);
|
||||
};
|
||||
|
||||
struct ipa_qdss_data {
|
||||
|
|
@ -327,6 +331,13 @@ struct ipa_eth_data {
|
|||
int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg);
|
||||
|
||||
int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg);
|
||||
|
||||
enum ipa_client_type (*ipa_eth_get_ipa_client_type_from_eth_type)(
|
||||
enum ipa_eth_client_type eth_client_type,
|
||||
enum ipa_eth_pipe_direction dir);
|
||||
|
||||
bool (*ipa_eth_client_exist)(
|
||||
enum ipa_eth_client_type eth_client_type, int inst_id);
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPA3)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _IPA_UC_OFFLOAD_H_
|
||||
|
|
@ -19,6 +19,7 @@ enum ipa_uc_offload_proto {
|
|||
IPA_UC_INVALID = 0,
|
||||
IPA_UC_WDI = 1,
|
||||
IPA_UC_NTN = 2,
|
||||
IPA_UC_NTN_V2X = 3,
|
||||
IPA_UC_MAX_PROT_SIZE
|
||||
};
|
||||
|
||||
|
|
@ -89,6 +90,7 @@ struct ntn_buff_smmu_map {
|
|||
* @num_buffers: Rx/Tx buffer pool size (in terms of elements)
|
||||
* @data_buff_size: size of the each data buffer allocated in DDR
|
||||
* @ntn_reg_base_ptr_pa: physical address of the Tx/Rx NTN Ring's
|
||||
* @u8 db_mode: 0 means irq mode, 1 means db mode
|
||||
* tail pointer
|
||||
*/
|
||||
struct ipa_ntn_setup_info {
|
||||
|
|
@ -111,6 +113,8 @@ struct ipa_ntn_setup_info {
|
|||
u32 data_buff_size;
|
||||
|
||||
phys_addr_t ntn_reg_base_ptr_pa;
|
||||
|
||||
u8 db_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -139,10 +143,14 @@ struct ipa_ntn_conn_in_params {
|
|||
* @ul_uc_db_pa: physical address of IPA uc doorbell for UL
|
||||
* @dl_uc_db_pa: physical address of IPA uc doorbell for DL
|
||||
* @clnt_hdl: opaque handle assigned to offload client
|
||||
* @ul_uc_db_iomem: iomem address of IPA uc doorbell for UL
|
||||
* @dl_uc_db_iomem: iomem address of IPA uc doorbell for DL
|
||||
*/
|
||||
struct ipa_ntn_conn_out_params {
|
||||
phys_addr_t ul_uc_db_pa;
|
||||
phys_addr_t dl_uc_db_pa;
|
||||
void __iomem *ul_uc_db_iomem;
|
||||
void __iomem *dl_uc_db_iomem;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -176,10 +184,12 @@ struct ipa_uc_offload_conn_out_params {
|
|||
* struct ipa_perf_profile - To set BandWidth profile
|
||||
*
|
||||
* @client: type of "client" (IPA_CLIENT_ODU#_PROD/CONS)
|
||||
* @proto: uC offload protocol type
|
||||
* @max_supported_bw_mbps: maximum bandwidth needed (in Mbps)
|
||||
*/
|
||||
struct ipa_perf_profile {
|
||||
enum ipa_client_type client;
|
||||
enum ipa_uc_offload_proto proto;
|
||||
u32 max_supported_bw_mbps;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _IPA_USB_H_
|
||||
|
|
@ -292,6 +292,15 @@ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
|||
int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
||||
enum ipa_usb_teth_prot teth_prot);
|
||||
|
||||
/**
|
||||
* ipa_usb_is_teth_prot_connected - Internal API for checking USB
|
||||
* protocol is connected
|
||||
*
|
||||
* @usb_teth_prot: USB tethering protocol
|
||||
* @Return true if connected, false if not
|
||||
*/
|
||||
bool ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot);
|
||||
|
||||
#else /* IS_ENABLED(CONFIG_IPA3) */
|
||||
|
||||
static inline int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
|
||||
|
|
@ -337,6 +346,11 @@ static inline int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline int ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_IPA3) */
|
||||
|
||||
|
|
|
|||
|
|
@ -250,6 +250,12 @@ struct ipa_wdi_perf_profile {
|
|||
int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
|
||||
struct ipa_wdi_init_out_params *out);
|
||||
|
||||
/** ipa_wdi_is_tx1_used - return if DBS mode is active
|
||||
*
|
||||
* @Return bool
|
||||
*/
|
||||
bool ipa_wdi_is_tx1_used(void);
|
||||
|
||||
/**
|
||||
* ipa_wdi_cleanup - Client should call this function to
|
||||
* clean up WDI IPA offload data path
|
||||
|
|
@ -399,6 +405,11 @@ static inline int ipa_get_wdi_version(void)
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline int ipa_wdi_is_tx1_used(void)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline int ipa_wdi_cleanup(void)
|
||||
{
|
||||
return -EPERM;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
/* Smart-Peripheral-Switch (SPS) API. */
|
||||
|
||||
|
|
@ -485,7 +485,7 @@ struct sps_bam_props {
|
|||
*
|
||||
*/
|
||||
struct sps_mem_buffer {
|
||||
void *base;
|
||||
void __iomem *base;
|
||||
phys_addr_t phys_base;
|
||||
unsigned long iova;
|
||||
u32 size;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
|
||||
enum msm_pcie_config {
|
||||
MSM_PCIE_CONFIG_INVALID = 0,
|
||||
MSM_PCIE_CONFIG_NO_CFG_RESTORE = 0x1,
|
||||
MSM_PCIE_CONFIG_LINKDOWN = 0x2,
|
||||
MSM_PCIE_CONFIG_NO_RECOVERY = 0x4,
|
||||
MSM_PCIE_CONFIG_NO_L1SS_TO = 0x8,
|
||||
MSM_PCIE_CONFIG_NO_DRV_PC = 0x10,
|
||||
MSM_PCIE_CONFIG_LINKDOWN = BIT(0),
|
||||
MSM_PCIE_CONFIG_NO_RECOVERY = BIT(1),
|
||||
MSM_PCIE_CONFIG_NO_L1SS_TO = BIT(2),
|
||||
MSM_PCIE_CONFIG_NO_DRV_PC = BIT(3),
|
||||
};
|
||||
|
||||
enum msm_pcie_pm_opt {
|
||||
|
|
@ -174,16 +173,6 @@ int msm_pcie_register_event(struct msm_pcie_register_event *reg);
|
|||
*/
|
||||
int msm_pcie_deregister_event(struct msm_pcie_register_event *reg);
|
||||
|
||||
/**
|
||||
* msm_pcie_recover_config - recover config space.
|
||||
* @dev: pci device structure
|
||||
*
|
||||
* This function recovers the config space of both RC and Endpoint.
|
||||
*
|
||||
* Return: 0 on success, negative value on error
|
||||
*/
|
||||
int msm_pcie_recover_config(struct pci_dev *dev);
|
||||
|
||||
/**
|
||||
* msm_pcie_enumerate - enumerate Endpoints.
|
||||
* @rc_idx: RC that Endpoints connect to.
|
||||
|
|
@ -194,28 +183,6 @@ int msm_pcie_recover_config(struct pci_dev *dev);
|
|||
*/
|
||||
int msm_pcie_enumerate(u32 rc_idx);
|
||||
|
||||
/**
|
||||
* msm_pcie_recover_config - recover config space.
|
||||
* @dev: pci device structure
|
||||
*
|
||||
* This function recovers the config space of both RC and Endpoint.
|
||||
*
|
||||
* Return: 0 on success, negative value on error
|
||||
*/
|
||||
int msm_pcie_recover_config(struct pci_dev *dev);
|
||||
|
||||
/**
|
||||
* msm_pcie_shadow_control - control the shadowing of PCIe config space.
|
||||
* @dev: pci device structure
|
||||
* @enable: shadowing should be enabled or disabled
|
||||
*
|
||||
* This function gives PCIe endpoint device drivers the control to enable
|
||||
* or disable the shadowing of PCIe config space.
|
||||
*
|
||||
* Return: 0 on success, negative value on error
|
||||
*/
|
||||
int msm_pcie_shadow_control(struct pci_dev *dev, bool enable);
|
||||
|
||||
/*
|
||||
* msm_pcie_debug_info - run a PCIe specific debug testcase.
|
||||
* @dev: pci device structure
|
||||
|
|
@ -286,21 +253,11 @@ static inline int msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_pcie_recover_config(struct pci_dev *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_pcie_enumerate(u32 rc_idx)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base,
|
||||
u32 offset, u32 mask, u32 value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ extern unsigned int sysctl_sched_prefer_spread;
|
|||
extern unsigned int sysctl_walt_rtg_cfs_boost_prio;
|
||||
extern unsigned int sysctl_walt_low_latency_task_threshold;
|
||||
extern unsigned int sysctl_sched_sync_hint_enable;
|
||||
extern unsigned int sysctl_walt_cpu_high_irqload;
|
||||
|
||||
extern int
|
||||
walt_proc_group_thresholds_handler(struct ctl_table *table, int write,
|
||||
|
|
@ -87,6 +88,10 @@ extern int sched_boost_handler(struct ctl_table *table, int write,
|
|||
|
||||
extern int sched_busy_hyst_handler(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos);
|
||||
|
||||
extern int walt_high_irqload_handler(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos);
|
||||
|
||||
#endif
|
||||
|
||||
enum sched_tunable_scaling {
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode, int nr);
|
|||
#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
|
||||
#define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
|
||||
#define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
|
||||
#define wake_up_sync(x) __wake_up_sync(x, TASK_NORMAL, 1)
|
||||
|
||||
/*
|
||||
* Wakeup macros to be used to report events to the targets.
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ struct msm_watchdog_data {
|
|||
struct qcom_irq_info ipi_counts[NR_IPI];
|
||||
unsigned int tot_irq_count[NR_CPUS];
|
||||
atomic_t irq_counts_running;
|
||||
struct timer_list user_pet_timer;
|
||||
};
|
||||
|
||||
extern void qcom_wdt_trigger_bite(void);
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@
|
|||
#define IPA_IOCTL_SET_PKT_THRESHOLD 87
|
||||
#define IPA_IOCTL_ADD_EoGRE_MAPPING 88
|
||||
#define IPA_IOCTL_DEL_EoGRE_MAPPING 89
|
||||
#define IPA_IOCTL_SET_IPPT_SW_FLT 90
|
||||
|
||||
/**
|
||||
* max size of the header to be inserted
|
||||
|
|
@ -200,6 +201,12 @@
|
|||
(IPA_MAX_FLT_RT_CNT_INDEX - IPA_FLT_RT_HW_COUNTER)
|
||||
#define IPA_MAX_FLT_RT_CLIENTS 60
|
||||
|
||||
/**
|
||||
* Max number of ports/IPs IPPT exception
|
||||
*/
|
||||
|
||||
#define IPA_MAX_IPPT_NUM_PORT_FLT 5
|
||||
|
||||
/**
|
||||
* New feature flag for CV2X config.
|
||||
*/
|
||||
|
|
@ -256,6 +263,47 @@
|
|||
#define IPA_MAX_PDN_NUM 16
|
||||
#define IPA_MAX_PDN_NUM_v4 5
|
||||
|
||||
/**
|
||||
* Macros duplicated from ipa_lnx_spearhead_stats.h and
|
||||
* ipa_lnx_stats.h. All three macros should match.
|
||||
* This needs to be updated whenever the header file structure
|
||||
* and structure length macros are updated to match exactly
|
||||
* the same. This is done to overcome backward and forward
|
||||
* compatibility between userspace and driver spearhead structures.
|
||||
*/
|
||||
/* IPA Linux basic stats structure macros */
|
||||
#define IPA_LNX_PG_RECYCLE_STATS_STRUCT_LEN 32
|
||||
#define IPA_LNX_EXCEPTION_STATS_STRUCT_LEN 40
|
||||
#define IPA_LNX_ODL_EP_STATS_STRUCT_LEN 16
|
||||
#define IPA_LNX_HOLB_DISCARD_STATS_STRUCT_LEN 16
|
||||
#define IPA_LNX_HOLB_MONITOR_STATS_STRUCT_LEN 16
|
||||
#define IPA_LNX_HOLB_DROP_AND_MON_STATS_STRUCT_LEN (8 + 16 + 16)
|
||||
#define IPA_LNX_GENERIC_STATS_STRUCT_LEN (40 + 32 + 40 + 16 + 40)
|
||||
/* IPA Linux clock stats structures */
|
||||
#define IPA_LNX_PM_CLIENT_STATS_STRUCT_LEN 24
|
||||
#define IPA_LNX_CLOCK_STATS_STRUCT_LEN (24 + 24)
|
||||
/* Generic instance structures */
|
||||
#define IPA_LNX_GSI_RX_DEBUG_STATS_STRUCT_LEN 48
|
||||
#define IPA_LNX_GSI_TX_DEBUG_STATS_STRUCT_LEN 56
|
||||
#define IPA_LNX_GSI_DEBUG_STATS_STRUCT_LEN (8 + 48 + 56)
|
||||
#define IPA_LNX_PIPE_INFO_STATS_STRUCT_LEN 120
|
||||
/* IPA Linux wlan instance stats structures */
|
||||
#define IPA_LNX_WLAN_INSTANCE_INFO_STRUCT_LEN (32 + 112 + 120)
|
||||
#define IPA_LNX_WLAN_INST_STATS_STRUCT_LEN (8 + 264)
|
||||
/* IPA Linux eth instance stats structures */
|
||||
#define IPA_LNX_ETH_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120)
|
||||
#define IPA_LNX_ETH_INST_STATS_STRUCT_LEN (8 + 248)
|
||||
/* IPA Linux usb instance stats structures */
|
||||
#define IPA_LNX_USB_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120)
|
||||
#define IPA_LNX_USB_INST_STATS_STRUCT_LEN (8 + 248)
|
||||
/* IPA Linux mhip instance stats structures */
|
||||
#define IPA_LNX_MHIP_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120)
|
||||
#define IPA_LNX_MHIP_INST_STATS_STRUCT_LEN (8 + 248)
|
||||
/* IPA Linux Instance allocation info structures */
|
||||
#define IPA_LNX_EACH_INST_ALLOC_INFO_STRUCT_LEN (24 + 12 + 12 + 16)
|
||||
#define IPA_LNX_STATS_ALL_INFO_STRUCT_LEN (32 + 128 + 128 + 128)
|
||||
#define IPA_LNX_STATS_SPEARHEAD_CTX_STRUCT_LEN (8 + 4 + 416)
|
||||
|
||||
/**
|
||||
* enum ipa_client_type - names for the various IPA "clients"
|
||||
* these are from the perspective of the clients, for e.g.
|
||||
|
|
@ -846,7 +894,13 @@ enum ipa_eogre_event {
|
|||
#define IPA_EoGRE_EVENT_MAX IPA_EoGRE_EVENT_MAX
|
||||
};
|
||||
|
||||
#define IPA_EVENT_MAX_NUM (IPA_EoGRE_EVENT_MAX)
|
||||
enum ipa_ippt_sw_flt_event {
|
||||
IPA_IPPT_SW_FLT_EVENT = IPA_EoGRE_EVENT_MAX,
|
||||
IPA_IPPT_SW_FLT_EVENT_MAX
|
||||
#define IPA_IPPT_SW_FLT_EVENT_MAX IPA_IPPT_SW_FLT_EVENT_MAX
|
||||
};
|
||||
|
||||
#define IPA_EVENT_MAX_NUM (IPA_IPPT_SW_FLT_EVENT_MAX)
|
||||
#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
|
||||
|
||||
/**
|
||||
|
|
@ -3225,11 +3279,33 @@ struct ipa_sw_flt_list_type {
|
|||
char iface[IPA_MAX_NUM_IFACE_FLT][IPA_RESOURCE_NAME_MAX];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ipa_ippt_sw_flt_list_type- exception list
|
||||
* @ipv4_enable: true to block ipv4 addrs given below and false to clean
|
||||
* up all previous ipv4 addrs
|
||||
* @num_of_ipv4: holds num of ipv4 to SW-exception
|
||||
* @ipv4: an array to hold ipv4 addrs to SW-exception
|
||||
* @port_enable: true to block current ports and false to clean
|
||||
* up all previous ports
|
||||
* @num_of_port: holds num of ports to SW-exception
|
||||
* @port: an array to hold connection ports to SW-exception
|
||||
*/
|
||||
|
||||
struct ipa_ippt_sw_flt_list_type {
|
||||
uint8_t ipv4_enable;
|
||||
int num_of_ipv4;
|
||||
uint32_t ipv4[IPA_MAX_PDN_NUM];
|
||||
uint8_t port_enable;
|
||||
int num_of_port;
|
||||
uint16_t port[IPA_MAX_IPPT_NUM_PORT_FLT];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ipa_ioc_sw_flt_list_type
|
||||
* @ioctl_ptr: has to be typecasted to (__u64)(uintptr_t)
|
||||
* @ioctl_data_size:
|
||||
* Eg: For ipa_sw_flt_list_type = sizeof(ipa_sw_flt_list_type)
|
||||
* Eg: For ipa_ippt_sw_flt_list_type = sizeof(ipa_ippt_sw_flt_list_type)
|
||||
*/
|
||||
struct ipa_ioc_sw_flt_list_type {
|
||||
__u64 ioctl_ptr;
|
||||
|
|
@ -3536,6 +3612,10 @@ struct ipa_ioc_sw_flt_list_type {
|
|||
#define IPA_IOC_DEL_EoGRE_MAPPING _IOWR(IPA_IOC_MAGIC, \
|
||||
IPA_IOCTL_DEL_EoGRE_MAPPING, \
|
||||
struct ipa_ioc_eogre_info)
|
||||
|
||||
#define IPA_IOC_SET_IPPT_SW_FLT _IOWR(IPA_IOC_MAGIC, \
|
||||
IPA_IOCTL_SET_IPPT_SW_FLT, \
|
||||
struct ipa_ioc_sw_flt_list_type)
|
||||
/*
|
||||
* unique magic number of the Tethering bridge ioctls
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@
|
|||
#define __QBG_H__
|
||||
|
||||
#define MAX_FIFO_COUNT 36
|
||||
#define QBG_MAX_STEP_CHG_ENTRIES 6
|
||||
|
||||
enum QBG_STATE {
|
||||
QBG_LPM,
|
||||
QBG_MPM,
|
||||
QBG_HPM,
|
||||
QBG_FAST_CHAR,
|
||||
QBG_PON_OCV,
|
||||
QBG_STATE_MAX,
|
||||
};
|
||||
|
||||
enum QBG_SDAM_DATA_OFFSET {
|
||||
QBG_ACC0_OFFSET = 0,
|
||||
|
|
@ -41,10 +51,7 @@ enum qbg {
|
|||
QBG_PARAM_SYS_SOC_HOLD_100PCT,
|
||||
QBG_PARAM_JEITA_COOL_THRESHOLD,
|
||||
QBG_PARAM_TOTAL_IMPEDANCE,
|
||||
QBG_PARAM_PON_OCV,
|
||||
QBG_PARAM_PON_IBAT,
|
||||
QBG_PARAM_PON_SOC,
|
||||
QBG_PARAM_BATT_ID,
|
||||
QBG_PARAM_ESSENTIAL_PARAM_REVID,
|
||||
QBG_PARAM_FIFO_TIMESTAMP,
|
||||
QBG_PARAM_MAX,
|
||||
};
|
||||
|
|
@ -115,6 +122,9 @@ struct qbg_config {
|
|||
unsigned int iterm_ma;
|
||||
unsigned int rconn_mohm;
|
||||
unsigned long current_time;
|
||||
unsigned int sdam_batt_id;
|
||||
unsigned int essential_param_revid;
|
||||
unsigned long sample_time_us[QBG_STATE_MAX];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct qbg_param {
|
||||
|
|
@ -134,9 +144,35 @@ struct qbg_user_data {
|
|||
struct qbg_param param[QBG_PARAM_MAX];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct range_data {
|
||||
int low_threshold;
|
||||
int high_threshold;
|
||||
unsigned int value;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct ranges {
|
||||
struct range_data data[QBG_MAX_STEP_CHG_ENTRIES];
|
||||
unsigned char range_count;
|
||||
_Bool valid;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct qbg_step_chg_jeita_params {
|
||||
int jeita_full_fv_10nv;
|
||||
int jeita_full_iterm_10na;
|
||||
int jeita_warm_adc_value;
|
||||
int jeita_cool_adc_value;
|
||||
int battery_beta;
|
||||
int battery_therm_kohm;
|
||||
struct ranges step_fcc_cfg;
|
||||
struct ranges jeita_fcc_cfg;
|
||||
struct ranges jeita_fv_cfg;
|
||||
unsigned char ttf_calc_mode;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* IOCTLs to read & write QBG config and essential params */
|
||||
#define QBGIOCXCFG _IOR('B', 0x01, struct qbg_config)
|
||||
#define QBGIOCXEPR _IOR('B', 0x02, struct qbg_essential_params)
|
||||
#define QBGIOCXEPW _IOWR('B', 0x03, struct qbg_essential_params)
|
||||
#define QBGIOCXSTEPCHGCFG _IOWR('B', 0x04, struct qbg_step_chg_jeita_params)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ unsigned int sysctl_sched_capacity_margin_up[MAX_MARGIN_LEVELS] = {
|
|||
[0 ... MAX_MARGIN_LEVELS-1] = 1078}; /* ~5% margin */
|
||||
unsigned int sysctl_sched_capacity_margin_down[MAX_MARGIN_LEVELS] = {
|
||||
[0 ... MAX_MARGIN_LEVELS-1] = 1205}; /* ~15% margin */
|
||||
|
||||
unsigned int sysctl_walt_cpu_high_irqload = 95;
|
||||
static unsigned int walt_cpu_high_irqload;
|
||||
|
||||
unsigned int sysctl_sched_walt_rotate_big_tasks;
|
||||
|
|
@ -3666,6 +3668,26 @@ int walt_proc_group_thresholds_handler(struct ctl_table *table, int write,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int walt_high_irqload_handler(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int ret;
|
||||
static DEFINE_MUTEX(mutex);
|
||||
|
||||
mutex_lock(&mutex);
|
||||
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
||||
|
||||
if (ret || !write) {
|
||||
mutex_unlock(&mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
walt_cpu_high_irqload = div64_u64((u64)sched_ravg_window *
|
||||
sysctl_walt_cpu_high_irqload, (u64) 100);
|
||||
mutex_unlock(&mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void walt_init_window_dep(void)
|
||||
{
|
||||
walt_cpu_util_freq_divisor =
|
||||
|
|
@ -3678,7 +3700,8 @@ static void walt_init_window_dep(void)
|
|||
sched_init_task_load_windows_scaled =
|
||||
scale_demand(sched_init_task_load_windows);
|
||||
|
||||
walt_cpu_high_irqload = div64_u64((u64)sched_ravg_window * 95, (u64) 100);
|
||||
walt_cpu_high_irqload = mult_frac((u64)sched_ravg_window,
|
||||
sysctl_walt_cpu_high_irqload, (u64) 100);
|
||||
}
|
||||
|
||||
static void walt_init_once(void)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ static int __maybe_unused max_kswapd_threads = MAX_KSWAPD_THREADS;
|
|||
#ifdef CONFIG_SCHED_WALT
|
||||
static int neg_three = -3;
|
||||
static int three = 3;
|
||||
static int fifty = 50;
|
||||
static int two_hundred_fifty_five = 255;
|
||||
const int sched_user_hint_max = 1000;
|
||||
static unsigned int ns_per_sec = NSEC_PER_SEC;
|
||||
|
|
@ -594,6 +595,16 @@ static struct ctl_table kern_table[] = {
|
|||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "sched_cpu_high_irqload",
|
||||
.data = &sysctl_walt_cpu_high_irqload,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = walt_high_irqload_handler,
|
||||
.extra1 = &fifty,
|
||||
.extra2 = &one_hundred,
|
||||
},
|
||||
|
||||
#endif
|
||||
{
|
||||
.procname = "sched_force_lb_enable",
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ static void sysstats_build(struct sys_memstats *stats)
|
|||
stats->version = SYSSTATS_VERSION;
|
||||
stats->memtotal = K(i.totalram);
|
||||
stats->reclaimable =
|
||||
global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE) >> 10;
|
||||
K(global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE));
|
||||
stats->swap_used = K(i.totalswap - i.freeswap);
|
||||
stats->swap_total = K(i.totalswap);
|
||||
stats->vmalloc_total = K(vmalloc_nr_pages());
|
||||
|
|
|
|||
|
|
@ -2861,8 +2861,6 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
|
|||
shinfo->gso_type |= SKB_GSO_TCPV6;
|
||||
}
|
||||
|
||||
/* Due to IPv6 header, MSS needs to be downgraded. */
|
||||
skb_decrease_gso_size(shinfo, len_diff);
|
||||
/* Header must be checked, and gso_segs recomputed. */
|
||||
shinfo->gso_type |= SKB_GSO_DODGY;
|
||||
shinfo->gso_segs = 0;
|
||||
|
|
@ -2902,8 +2900,6 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
|
|||
shinfo->gso_type |= SKB_GSO_TCPV4;
|
||||
}
|
||||
|
||||
/* Due to IPv4 header, MSS can be upgraded. */
|
||||
skb_increase_gso_size(shinfo, len_diff);
|
||||
/* Header must be checked, and gso_segs recomputed. */
|
||||
shinfo->gso_type |= SKB_GSO_DODGY;
|
||||
shinfo->gso_segs = 0;
|
||||
|
|
|
|||
|
|
@ -2071,6 +2071,9 @@ static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len)
|
|||
struct sk_buff *skb, *next;
|
||||
|
||||
skb = tcp_send_head(sk);
|
||||
if (!skb)
|
||||
return false;
|
||||
|
||||
tcp_for_write_queue_from_safe(skb, next, sk) {
|
||||
if (len <= skb->len)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -2510,6 +2510,9 @@ void udp_destroy_sock(struct sock *sk)
|
|||
{
|
||||
struct udp_sock *up = udp_sk(sk);
|
||||
bool slow = lock_sock_fast(sk);
|
||||
|
||||
/* protects from races with udp_abort() */
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
udp_flush_pending_frames(sk);
|
||||
unlock_sock_fast(sk, slow);
|
||||
if (static_branch_unlikely(&udp_encap_needed_key)) {
|
||||
|
|
@ -2765,10 +2768,17 @@ int udp_abort(struct sock *sk, int err)
|
|||
{
|
||||
lock_sock(sk);
|
||||
|
||||
/* udp{v6}_destroy_sock() sets it under the sk lock, avoid racing
|
||||
* with close()
|
||||
*/
|
||||
if (sock_flag(sk, SOCK_DEAD))
|
||||
goto out;
|
||||
|
||||
sk->sk_err = err;
|
||||
sk->sk_error_report(sk);
|
||||
__udp_disconnect(sk, 0);
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1539,6 +1539,9 @@ void udpv6_destroy_sock(struct sock *sk)
|
|||
{
|
||||
struct udp_sock *up = udp_sk(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
/* protects from races with udp_abort() */
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
udp_v6_flush_pending_frames(sk);
|
||||
release_sock(sk);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ struct security_class_mapping secclass_map[] = {
|
|||
{ COMMON_IPC_PERMS, NULL } },
|
||||
{ "netlink_route_socket",
|
||||
{ COMMON_SOCK_PERMS,
|
||||
"nlmsg_read", "nlmsg_write", "nlmsg_readpriv", NULL } },
|
||||
"nlmsg_read", "nlmsg_write", "nlmsg_readpriv", "nlmsg_getneigh",
|
||||
NULL } },
|
||||
{ "netlink_tcpdiag_socket",
|
||||
{ COMMON_SOCK_PERMS,
|
||||
"nlmsg_read", "nlmsg_write", NULL } },
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ struct selinux_state {
|
|||
bool initialized;
|
||||
bool policycap[__POLICYDB_CAPABILITY_MAX];
|
||||
bool android_netlink_route;
|
||||
bool android_netlink_getneigh;
|
||||
|
||||
struct selinux_avc *avc;
|
||||
struct selinux_ss *ss;
|
||||
};
|
||||
|
|
@ -185,6 +187,13 @@ static inline bool selinux_android_nlroute_getlink(void)
|
|||
return state->android_netlink_route;
|
||||
}
|
||||
|
||||
static inline bool selinux_android_nlroute_getneigh(void)
|
||||
{
|
||||
struct selinux_state *state = &selinux_state;
|
||||
|
||||
return state->android_netlink_getneigh;
|
||||
}
|
||||
|
||||
int security_mls_enabled(struct selinux_state *state);
|
||||
int security_load_policy(struct selinux_state *state,
|
||||
void *data, size_t len);
|
||||
|
|
|
|||
|
|
@ -207,12 +207,12 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void nlmsg_set_getlink_perm(u32 perm)
|
||||
static void nlmsg_set_perm_for_type(u32 perm, u16 type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nlmsg_route_perms); i++) {
|
||||
if (nlmsg_route_perms[i].nlmsg_type == RTM_GETLINK) {
|
||||
if (nlmsg_route_perms[i].nlmsg_type == type) {
|
||||
nlmsg_route_perms[i].perm = perm;
|
||||
break;
|
||||
}
|
||||
|
|
@ -222,11 +222,27 @@ static void nlmsg_set_getlink_perm(u32 perm)
|
|||
/**
|
||||
* Use nlmsg_readpriv as the permission for RTM_GETLINK messages if the
|
||||
* netlink_route_getlink policy capability is set. Otherwise use nlmsg_read.
|
||||
* Similarly, use nlmsg_getneigh for RTM_GETNEIGH and RTM_GETNEIGHTBL if the
|
||||
* netlink_route_getneigh policy capability is set. Otherwise use nlmsg_read.
|
||||
*/
|
||||
void selinux_nlmsg_init(void)
|
||||
{
|
||||
if (selinux_android_nlroute_getlink())
|
||||
nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV);
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV,
|
||||
RTM_GETLINK);
|
||||
else
|
||||
nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ);
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ,
|
||||
RTM_GETLINK);
|
||||
|
||||
if (selinux_android_nlroute_getneigh()) {
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_GETNEIGH,
|
||||
RTM_GETNEIGH);
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_GETNEIGH,
|
||||
RTM_GETNEIGHTBL);
|
||||
} else {
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ,
|
||||
RTM_GETNEIGH);
|
||||
nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ,
|
||||
RTM_GETNEIGHTBL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2353,6 +2353,10 @@ int policydb_read(struct policydb *p, void *fp)
|
|||
p->android_netlink_route = 1;
|
||||
}
|
||||
|
||||
if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH)) {
|
||||
p->android_netlink_getneigh = 1;
|
||||
}
|
||||
|
||||
if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
|
||||
rc = ebitmap_read(&p->policycaps, fp);
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ struct genfs {
|
|||
struct policydb {
|
||||
int mls_enabled;
|
||||
int android_netlink_route;
|
||||
int android_netlink_getneigh;
|
||||
|
||||
/* symbol tables */
|
||||
struct symtab symtab[SYM_NUM];
|
||||
|
|
@ -322,6 +323,7 @@ extern int policydb_write(struct policydb *p, void *fp);
|
|||
|
||||
#define POLICYDB_CONFIG_MLS 1
|
||||
#define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE (1 << 31)
|
||||
#define POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH (1 << 30)
|
||||
|
||||
/* the config flags related to unknown classes/perms are bits 2 and 3 */
|
||||
#define REJECT_UNKNOWN 0x00000002
|
||||
|
|
|
|||
|
|
@ -2127,6 +2127,7 @@ static void security_load_policycaps(struct selinux_state *state)
|
|||
}
|
||||
|
||||
state->android_netlink_route = p->android_netlink_route;
|
||||
state->android_netlink_getneigh = p->android_netlink_getneigh;
|
||||
selinux_nlmsg_init();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue