summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/regmap/regmap-swr.c23
-rw-r--r--drivers/clk/msm/clock-gpu-cobalt.c80
-rw-r--r--drivers/clk/msm/clock-mmss-cobalt.c73
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c119
-rw-r--r--drivers/clk/msm/reset.c6
-rw-r--r--drivers/firmware/qcom/tz_log.c117
-rw-r--r--drivers/gpio/gpio-msm-smp2p-test.c10
-rw-r--r--drivers/gpu/msm/a5xx_reg.h1
-rw-r--r--drivers/gpu/msm/adreno.c2
-rw-r--r--drivers/gpu/msm/adreno.h2
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c7
-rw-r--r--drivers/gpu/msm/adreno_perfcounter.c8
-rw-r--r--drivers/gpu/msm/adreno_ringbuffer.c17
-rw-r--r--drivers/gpu/msm/kgsl.c602
-rw-r--r--drivers/gpu/msm/kgsl.h37
-rw-r--r--drivers/gpu/msm/kgsl_compat.c12
-rw-r--r--drivers/gpu/msm/kgsl_debugfs.c81
-rw-r--r--drivers/gpu/msm/kgsl_ioctl.c12
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c165
-rw-r--r--drivers/gpu/msm/kgsl_mmu.c93
-rw-r--r--drivers/gpu/msm/kgsl_mmu.h6
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.h34
-rw-r--r--drivers/gpu/msm/kgsl_snapshot.c7
-rw-r--r--drivers/gpu/msm/kgsl_trace.h94
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.c49
-rw-r--r--drivers/input/touchscreen/ft5x06_ts.c801
-rw-r--r--drivers/input/touchscreen/gt9xx/goodix_tool.c1166
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx_firmware.h12
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx_update.c3308
-rw-r--r--drivers/input/touchscreen/it7258_ts_i2c.c73
-rw-r--r--drivers/input/touchscreen/msg21xx_ts.c1455
-rw-r--r--drivers/iommu/dma-mapping-fast.c29
-rw-r--r--drivers/iommu/msm_dma_iommu_mapping.c4
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c492
-rw-r--r--drivers/leds/leds-qpnp-flash.c28
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_soc_api.c12
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_soc_api.h13
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c15
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp48.c13
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c3
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c14
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c15
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c45
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c26
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c20
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h2
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c7
-rw-r--r--drivers/media/platform/msm/vidc/Kconfig2
-rw-r--r--drivers/media/platform/msm/vidc/Makefile32
-rw-r--r--drivers/media/platform/msm/vidc/governors/Kconfig2
-rw-r--r--drivers/media/platform/msm/vidc/governors/Makefile10
-rw-r--r--drivers/media/platform/msm/vidc/msm_v4l2_vidc.c2
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c128
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c2
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c6
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c4
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c7
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_resources.h1
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c31
-rw-r--r--drivers/media/platform/msm/vidc/vmem/Kconfig2
-rw-r--r--drivers/media/platform/msm/vidc/vmem/Makefile9
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem.c40
-rw-r--r--drivers/media/platform/msm/vidc/vmem/vmem.h4
-rw-r--r--drivers/mfd/wcd9xxx-irq.c1
-rw-r--r--drivers/mfd/wcd9xxx-slimslave.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c11
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c7
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h1
-rw-r--r--drivers/nfc/nq-nci.c46
-rw-r--r--drivers/of/fdt.c14
-rw-r--r--drivers/perf/arm_pmu.c128
-rw-r--r--drivers/platform/msm/gsi/gsi.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c21
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_dp.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_i.h2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c21
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h2
-rw-r--r--drivers/platform/msm/sps/sps.c7
-rw-r--r--drivers/platform/msm/sps/spsi.h4
-rw-r--r--drivers/regulator/cpr3-regulator.c121
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c48
-rw-r--r--drivers/scsi/ufs/ufshcd.c27
-rw-r--r--drivers/slimbus/slim-msm.c8
-rw-r--r--drivers/soc/qcom/Kconfig11
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/icnss.c171
-rw-r--r--drivers/soc/qcom/irq-helper.c2
-rw-r--r--drivers/soc/qcom/secure_buffer.c182
-rw-r--r--drivers/soc/qcom/service-locator.c4
-rw-r--r--drivers/soc/qcom/smp2p.c6
-rw-r--r--drivers/soc/qcom/smp2p_private_api.h4
-rw-r--r--drivers/soc/qcom/smp2p_sleepstate.c3
-rw-r--r--drivers/soc/qcom/smp2p_spinlock_test.c14
-rw-r--r--drivers/soc/qcom/spcom.c12
-rw-r--r--drivers/soc/qcom/wcd-dsp-glink.c948
-rw-r--r--drivers/soc/qcom/wlan_firmware_service_v01.c186
-rw-r--r--drivers/soc/qcom/wlan_firmware_service_v01.h50
-rw-r--r--drivers/soundwire/swr-wcd-ctrl.c5
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c60
-rw-r--r--drivers/staging/android/ion/ion_priv.h7
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c148
-rw-r--r--drivers/staging/android/ion/ion_system_secure_heap.c141
-rw-r--r--drivers/staging/android/ion/msm/msm_ion.c8
-rw-r--r--drivers/staging/android/ion/msm_ion_priv.h1
-rw-r--r--drivers/staging/android/uapi/msm_ion.h3
-rw-r--r--drivers/tty/serial/amba-pl011.c1
-rw-r--r--drivers/tty/serial/arc_uart.c1
-rw-r--r--drivers/tty/serial/earlycon.c10
-rw-r--r--drivers/tty/serial/msm_serial.c300
-rw-r--r--drivers/tty/serial/msm_serial.h184
-rw-r--r--drivers/tty/serial/samsung.c6
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/usb/pd/policy_engine.c170
-rw-r--r--drivers/usb/pd/qpnp-pdphy.c62
-rw-r--r--drivers/usb/phy/phy-msm-ssusb-qmp.c7
-rw-r--r--drivers/video/fbdev/msm/mdss.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c69
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h13
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c92
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.h39
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_hdcp.c1006
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_hdcp.h10
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c62
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c16
-rw-r--r--drivers/video/fbdev/msm/msm_ext_display.c24
129 files changed, 9064 insertions, 4962 deletions
diff --git a/drivers/base/regmap/regmap-swr.c b/drivers/base/regmap/regmap-swr.c
index 5ea67421ed85..027cbfc505ab 100644
--- a/drivers/base/regmap/regmap-swr.c
+++ b/drivers/base/regmap/regmap-swr.c
@@ -23,15 +23,15 @@
static int regmap_swr_gather_write(void *context,
const void *reg, size_t reg_size,
- const void *val, size_t val_size)
+ const void *val, size_t val_len)
{
struct device *dev = context;
struct swr_device *swr = to_swr_device(dev);
struct regmap *map = dev_get_regmap(dev, NULL);
size_t addr_bytes = map->format.reg_bytes;
- int ret = 0;
- int i;
- u32 reg_addr = 0;
+ size_t val_bytes;
+ int i, ret = 0;
+ u16 reg_addr = 0;
if (swr == NULL) {
dev_err(dev, "%s: swr device is NULL\n", __func__);
@@ -43,12 +43,15 @@ static int regmap_swr_gather_write(void *context,
return -EINVAL;
}
reg_addr = *(u16 *)reg;
- for (i = 0; i < val_size; i++) {
- ret = swr_write(swr, swr->dev_num, (reg_addr+i),
- (u32 *)(val+i));
+ val_bytes = map->format.val_bytes;
+ /* val_len = val_bytes * val_count */
+ for (i = 0; i < (val_len / val_bytes); i++) {
+ reg_addr = reg_addr + i;
+ val = (u8 *)val + (val_bytes * i);
+ ret = swr_write(swr, swr->dev_num, reg_addr, val);
if (ret < 0) {
dev_err(dev, "%s: write reg 0x%x failed, err %d\n",
- __func__, (reg_addr+i), ret);
+ __func__, reg_addr, ret);
break;
}
}
@@ -153,7 +156,7 @@ static int regmap_swr_read(void *context,
struct regmap *map = dev_get_regmap(dev, NULL);
size_t addr_bytes = map->format.reg_bytes;
int ret = 0;
- u32 reg_addr = 0;
+ u16 reg_addr = 0;
if (swr == NULL) {
dev_err(dev, "%s: swr is NULL\n", __func__);
@@ -164,7 +167,7 @@ static int regmap_swr_read(void *context,
__func__, reg_size);
return -EINVAL;
}
- reg_addr = *(u32 *)reg;
+ reg_addr = *(u16 *)reg;
ret = swr_read(swr, swr->dev_num, reg_addr, val, val_size);
if (ret < 0)
dev_err(dev, "%s: codec reg 0x%x read failed %d\n",
diff --git a/drivers/clk/msm/clock-gpu-cobalt.c b/drivers/clk/msm/clock-gpu-cobalt.c
index 7230c7a2bc04..7cec9be1f42c 100644
--- a/drivers/clk/msm/clock-gpu-cobalt.c
+++ b/drivers/clk/msm/clock-gpu-cobalt.c
@@ -39,8 +39,6 @@ static void __iomem *virt_base_gfx;
#define gpucc_gpll0_source_val 5
#define gpu_pll0_pll_out_even_source_val 1
#define gpu_pll0_pll_out_odd_source_val 2
-#define gpu_pll1_pll_out_even_source_val 3
-#define gpu_pll1_pll_out_odd_source_val 4
#define SW_COLLAPSE_MASK BIT(0)
#define GPU_CX_GDSCR_OFFSET 0x1004
@@ -157,65 +155,6 @@ static struct div_clk gpu_pll0_pll_out_odd = {
},
};
-static struct alpha_pll_clk gpu_pll1_pll = {
- .masks = &pll_masks_p,
- .base = &virt_base_gfx,
- .offset = GPUCC_GPU_PLL1_PLL_MODE,
- .enable_config = 0x1,
- .is_fabia = true,
- .c = {
- .rate = 0,
- .parent = &gpucc_xo.c,
- .dbg_name = "gpu_pll1_pll",
- .ops = &clk_ops_fabia_alpha_pll,
- VDD_GPU_PLL_FMAX_MAP1(MIN, 1300000500),
- CLK_INIT(gpu_pll1_pll.c),
- },
-};
-
-static struct div_clk gpu_pll1_pll_out_even = {
- .base = &virt_base_gfx,
- .offset = GPUCC_GPU_PLL1_USER_CTL_MODE,
- .mask = 0xf,
- .shift = 8,
- .data = {
- .max_div = 8,
- .min_div = 1,
- .skip_odd_div = true,
- .allow_div_one = true,
- .rate_margin = 500,
- },
- .ops = &postdiv_reg_ops,
- .c = {
- .parent = &gpu_pll1_pll.c,
- .dbg_name = "gpu_pll1_pll_out_even",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(gpu_pll1_pll_out_even.c),
- },
-};
-
-static struct div_clk gpu_pll1_pll_out_odd = {
- .base = &virt_base_gfx,
- .offset = GPUCC_GPU_PLL0_USER_CTL_MODE,
- .mask = 0xf,
- .shift = 12,
- .data = {
- .max_div = 7,
- .min_div = 3,
- .skip_even_div = true,
- .rate_margin = 500,
- },
- .ops = &postdiv_reg_ops,
- .c = {
- .parent = &gpu_pll1_pll.c,
- .dbg_name = "gpu_pll1_pll_out_odd",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(gpu_pll1_pll_out_odd.c),
- },
-};
-
static struct clk_freq_tbl ftbl_gfx3d_clk_src[] = {
F_SLEW( 171000000, 342000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 251000000, 502000000, gpu_pll0_pll_out_even, 1, 0, 0),
@@ -227,11 +166,11 @@ static struct clk_freq_tbl ftbl_gfx3d_clk_src[] = {
};
static struct clk_freq_tbl ftbl_gfx3d_clk_src_v2[] = {
- F_SLEW( 189000000, 378000000, gpu_pll0_pll_out_even, 1, 0, 0),
- F_SLEW( 264000000, 528000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 180000000, 360000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 257000000, 514000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 342000000, 684000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 414000000, 828000000, gpu_pll0_pll_out_even, 1, 0, 0),
- F_SLEW( 520000000, 1040000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 515000000, 1030000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 596000000, 1192000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 670000000, 1340000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 710000000, 1420000000, gpu_pll0_pll_out_even, 1, 0, 0),
@@ -239,14 +178,14 @@ static struct clk_freq_tbl ftbl_gfx3d_clk_src_v2[] = {
};
static struct clk_freq_tbl ftbl_gfx3d_clk_src_vq[] = {
- F_SLEW( 185000000, 370000000, gpu_pll0_pll_out_even, 1, 0, 0),
- F_SLEW( 285000000, 570000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 180000000, 360000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 265000000, 530000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 358000000, 716000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 434000000, 868000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 542000000, 1084000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_SLEW( 630000000, 1260000000, gpu_pll0_pll_out_even, 1, 0, 0),
- F_SLEW( 670000000, 1340000000, gpu_pll1_pll_out_even, 1, 0, 0),
- F_SLEW( 710000000, 1420000000, gpu_pll1_pll_out_even, 1, 0, 0),
+ F_SLEW( 700000000, 1400000000, gpu_pll0_pll_out_even, 1, 0, 0),
+ F_SLEW( 750000000, 1500000000, gpu_pll0_pll_out_even, 1, 0, 0),
F_END
};
@@ -659,9 +598,6 @@ static struct clk_lookup msm_clocks_gfxcc_cobalt[] = {
CLK_LIST(gpu_pll0_pll),
CLK_LIST(gpu_pll0_pll_out_even),
CLK_LIST(gpu_pll0_pll_out_odd),
- CLK_LIST(gpu_pll1_pll),
- CLK_LIST(gpu_pll1_pll_out_even),
- CLK_LIST(gpu_pll1_pll_out_odd),
CLK_LIST(gfx3d_clk_src),
CLK_LIST(gpucc_gfx3d_clk),
CLK_LIST(gpucc_mx_clk),
@@ -671,14 +607,12 @@ static struct clk_lookup msm_clocks_gfxcc_cobalt[] = {
static void msm_gfxcc_hamster_fixup(void)
{
gpu_pll0_pll.c.fmax[VDD_DIG_MIN] = 1420000500;
- gpu_pll1_pll.c.fmax[VDD_DIG_MIN] = 1420000500;
gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_vq;
}
static void msm_gfxcc_cobalt_v2_fixup(void)
{
gpu_pll0_pll.c.fmax[VDD_DIG_MIN] = 1420000500;
- gpu_pll1_pll.c.fmax[VDD_DIG_MIN] = 1420000500;
gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_v2;
}
diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c
index 288abb133743..2da10a2e4780 100644
--- a/drivers/clk/msm/clock-mmss-cobalt.c
+++ b/drivers/clk/msm/clock-mmss-cobalt.c
@@ -274,7 +274,7 @@ static struct rcg_clk csi0_clk_src = {
.c = {
.dbg_name = "csi0_clk_src",
.ops = &clk_ops_rcg,
- VDD_DIG_FMAX_MAP4(LOWER, 164570000, LOW, 256000000,
+ VDD_DIG_FMAX_MAP4(LOWER, 164571429, LOW, 256000000,
NOMINAL, 384000000, HIGH, 576000000),
CLK_INIT(csi0_clk_src.c),
},
@@ -292,6 +292,9 @@ static struct clk_freq_tbl ftbl_vfe_clk_src[] = {
static struct clk_freq_tbl ftbl_vfe_clk_src_vq[] = {
F_MM( 200000000, mmsscc_gpll0, 3, 0, 0),
+ F_MM( 300000000, mmsscc_gpll0, 2, 0, 0),
+ F_MM( 320000000, mmpll7_pll_out, 3, 0, 0),
+ F_MM( 384000000, mmpll4_pll_out, 2, 0, 0),
F_MM( 404000000, mmpll0_pll_out, 2, 0, 0),
F_MM( 480000000, mmpll7_pll_out, 2, 0, 0),
F_MM( 576000000, mmpll10_pll_out, 1, 0, 0),
@@ -367,16 +370,6 @@ static struct clk_freq_tbl ftbl_maxi_clk_src[] = {
F_END
};
-static struct clk_freq_tbl ftbl_maxi_clk_src_vq[] = {
- F_MM( 19200000, mmsscc_xo, 1, 0, 0),
- F_MM( 75000000, mmsscc_gpll0_div, 4, 0, 0),
- F_MM( 171428571, mmsscc_gpll0, 3.5, 0, 0),
- F_MM( 240000000, mmsscc_gpll0, 2.5, 0, 0),
- F_MM( 323200000, mmpll0_pll_out, 2.5, 0, 0),
- F_MM( 406000000, mmpll1_pll_out, 2, 0, 0),
- F_END
-};
-
static struct rcg_clk maxi_clk_src = {
.cmd_rcgr_reg = MMSS_MAXI_CMD_RCGR,
.set_rate = set_rate_hid,
@@ -592,18 +585,11 @@ static struct clk_freq_tbl ftbl_fd_core_clk_src[] = {
F_END
};
-static struct clk_freq_tbl ftbl_fd_core_clk_src_v2[] = {
- F_MM( 100000000, mmsscc_gpll0, 6, 0, 0),
- F_MM( 404000000, mmpll0_pll_out, 2, 0, 0),
- F_MM( 480000000, mmpll7_pll_out, 2, 0, 0),
- F_MM( 576000000, mmpll10_pll_out, 1, 0, 0),
- F_END
-};
-
static struct clk_freq_tbl ftbl_fd_core_clk_src_vq[] = {
F_MM( 100000000, mmsscc_gpll0, 6, 0, 0),
F_MM( 200000000, mmsscc_gpll0, 3, 0, 0),
- F_MM( 400000000, mmsscc_gpll0, 1.5, 0, 0),
+ F_MM( 404000000, mmpll0_pll_out, 2, 0, 0),
+ F_MM( 480000000, mmpll7_pll_out, 2, 0, 0),
F_MM( 576000000, mmpll10_pll_out, 1, 0, 0),
F_END
};
@@ -2677,60 +2663,81 @@ static void msm_mmsscc_hamster_fixup(void)
vfe1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000;
csi0_clk_src.freq_tbl = ftbl_csi_clk_src_vq;
- csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi0_clk_src.c.fmax[VDD_DIG_LOW] = 274290000;
+ csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000;
csi1_clk_src.freq_tbl = ftbl_csi_clk_src_vq;
- csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi1_clk_src.c.fmax[VDD_DIG_LOW] = 274290000;
+ csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000;
csi2_clk_src.freq_tbl = ftbl_csi_clk_src_vq;
- csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi2_clk_src.c.fmax[VDD_DIG_LOW] = 274290000;
+ csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000;
csi3_clk_src.freq_tbl = ftbl_csi_clk_src_vq;
- csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi3_clk_src.c.fmax[VDD_DIG_LOW] = 274290000;
+ csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000;
cpp_clk_src.freq_tbl = ftbl_cpp_clk_src_vq;
- cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000;
+ cpp_clk_src.c.fmax[VDD_DIG_LOW] = 384000000;
+ cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000;
jpeg0_clk_src.freq_tbl = ftbl_jpeg0_clk_src_vq;
jpeg0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000;
csiphy_clk_src.freq_tbl = ftbl_csiphy_clk_src_vq;
+ csiphy_clk_src.c.fmax[VDD_DIG_LOW] = 274290000;
csiphy_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
fd_core_clk_src.freq_tbl = ftbl_fd_core_clk_src_vq;
- fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 400000000;
+ fd_core_clk_src.c.fmax[VDD_DIG_LOW] = 404000000;
+ fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000;
csi0phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333;
csi1phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333;
csi2phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333;
mdp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000;
+ dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 154000000;
extpclk_clk_src.c.fmax[VDD_DIG_LOW] = 312500000;
extpclk_clk_src.c.fmax[VDD_DIG_LOW_L1] = 375000000;
rot_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000;
- maxi_clk_src.freq_tbl = ftbl_maxi_clk_src_vq;
video_core_clk_src.freq_tbl = ftbl_video_core_clk_src_vq;
video_core_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000;
video_core_clk_src.c.fmax[VDD_DIG_LOW] = 269330000;
- video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000;
+ video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
video_core_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000;
video_core_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000;
video_subcore0_clk_src.freq_tbl = ftbl_video_subcore_clk_src_vq;
video_subcore0_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000;
video_subcore0_clk_src.c.fmax[VDD_DIG_LOW] = 269330000;
- video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000;
+ video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
video_subcore0_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000;
video_subcore0_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000;
video_subcore1_clk_src.freq_tbl = ftbl_video_subcore_clk_src_vq;
video_subcore1_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000;
video_subcore1_clk_src.c.fmax[VDD_DIG_LOW] = 269330000;
- video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000;
+ video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
video_subcore1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000;
video_subcore1_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000;
};
static void msm_mmsscc_v2_fixup(void)
{
- fd_core_clk_src.freq_tbl = ftbl_fd_core_clk_src_v2;
- fd_core_clk_src.c.fmax[VDD_DIG_LOW] = 404000000;
- fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000;
+ cpp_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
+ cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000;
+ csi0_clk_src.c.fmax[VDD_DIG_LOW] = 256000000;
+ csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi1_clk_src.c.fmax[VDD_DIG_LOW] = 256000000;
+ csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi2_clk_src.c.fmax[VDD_DIG_LOW] = 256000000;
+ csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csi3_clk_src.c.fmax[VDD_DIG_LOW] = 256000000;
+ csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000;
+ csiphy_clk_src.c.fmax[VDD_DIG_LOW] = 256000000;
+
+ dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 148380000;
+
+ video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
+ video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
+ video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000;
}
int msm_mmsscc_cobalt_probe(struct platform_device *pdev)
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
index 1751f49b798c..19e813fd5a54 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
@@ -53,6 +53,13 @@
#define PLL_FRAC_DIV_START_LOW_1 0x0d0
#define PLL_FRAC_DIV_START_MID_1 0x0d4
#define PLL_FRAC_DIV_START_HIGH_1 0x0d8
+#define PLL_SSC_STEPSIZE_LOW_1 0x10c
+#define PLL_SSC_STEPSIZE_HIGH_1 0x110
+#define PLL_SSC_DIV_PER_LOW_1 0x114
+#define PLL_SSC_DIV_PER_HIGH_1 0x118
+#define PLL_SSC_DIV_ADJPER_LOW_1 0x11c
+#define PLL_SSC_DIV_ADJPER_HIGH_1 0x120
+#define PLL_SSC_CONTROL 0x13c
#define PLL_PLL_OUTDIV_RATE 0x140
#define PLL_PLL_LOCKDET_RATE_1 0x144
#define PLL_PLL_PROP_GAIN_RATE_1 0x14c
@@ -70,6 +77,16 @@
#define PHY_CMN_PLL_CNTRL 0x038
#define PHY_CMN_CTRL_0 0x024
+/* Bit definition of SSC control registers */
+#define SSC_CENTER BIT(0)
+#define SSC_EN BIT(1)
+#define SSC_FREQ_UPDATE BIT(2)
+#define SSC_FREQ_UPDATE_MUX BIT(3)
+#define SSC_UPDATE_SSC BIT(4)
+#define SSC_UPDATE_SSC_MUX BIT(5)
+#define SSC_START BIT(6)
+#define SSC_START_MUX BIT(7)
+
enum {
DSI_PLL_0,
DSI_PLL_1,
@@ -84,6 +101,13 @@ struct dsi_pll_regs {
u32 frac_div_start_low;
u32 frac_div_start_mid;
u32 frac_div_start_high;
+ u32 ssc_stepsize_low;
+ u32 ssc_stepsize_high;
+ u32 ssc_div_per_low;
+ u32 ssc_div_per_high;
+ u32 ssc_adjper_low;
+ u32 ssc_adjper_high;
+ u32 ssc_control;
};
struct dsi_pll_config {
@@ -92,6 +116,8 @@ struct dsi_pll_config {
u32 output_div;
bool ignore_frac;
bool disable_prescaler;
+ bool enable_ssc;
+ bool ssc_center;
u32 dec_bits;
u32 frac_bits;
u32 lock_timer;
@@ -151,7 +177,7 @@ static void dsi_pll_setup_config(struct dsi_pll_cobalt *pll,
config->frac_bits = 18;
config->lock_timer = 64;
config->ssc_freq = 31500;
- config->ssc_offset = 4800;
+ config->ssc_offset = 5000;
config->ssc_adj_per = 2;
config->thresh_cycles = 32;
config->refclk_cycles = 256;
@@ -159,6 +185,15 @@ static void dsi_pll_setup_config(struct dsi_pll_cobalt *pll,
config->div_override = false;
config->ignore_frac = false;
config->disable_prescaler = false;
+ config->enable_ssc = rsc->ssc_en;
+ config->ssc_center = rsc->ssc_center;
+
+ if (config->enable_ssc) {
+ if (rsc->ssc_freq)
+ config->ssc_freq = rsc->ssc_freq;
+ if (rsc->ssc_ppm)
+ config->ssc_offset = rsc->ssc_ppm;
+ }
dsi_pll_config_slave(rsc);
}
@@ -227,6 +262,77 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_cobalt *pll,
regs->frac_div_start_high = (frac & 0x30000) >> 16;
}
+static void dsi_pll_calc_ssc(struct dsi_pll_cobalt *pll,
+ struct mdss_pll_resources *rsc)
+{
+ struct dsi_pll_config *config = &pll->pll_configuration;
+ struct dsi_pll_regs *regs = &pll->reg_setup;
+ u32 ssc_per;
+ u32 ssc_mod;
+ u64 ssc_step_size;
+ u64 frac;
+
+ if (!config->enable_ssc) {
+ pr_debug("SSC not enabled\n");
+ return;
+ }
+
+ ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
+ ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
+ ssc_per -= ssc_mod;
+
+ frac = regs->frac_div_start_low |
+ (regs->frac_div_start_mid << 8) |
+ (regs->frac_div_start_high << 16);
+ ssc_step_size = regs->decimal_div_start;
+ ssc_step_size *= (1 << config->frac_bits);
+ ssc_step_size += frac;
+ ssc_step_size *= config->ssc_offset;
+ ssc_step_size *= (config->ssc_adj_per + 1);
+ ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
+ ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
+
+ regs->ssc_div_per_low = ssc_per & 0xFF;
+ regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
+ regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
+ regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
+ regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
+ regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
+
+ regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
+
+ pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
+ regs->decimal_div_start, frac, config->frac_bits);
+ pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
+ ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
+}
+
+static void dsi_pll_ssc_commit(struct dsi_pll_cobalt *pll,
+ struct mdss_pll_resources *rsc)
+{
+ void __iomem *pll_base = rsc->pll_base;
+ struct dsi_pll_regs *regs = &pll->reg_setup;
+
+ if (pll->pll_configuration.enable_ssc) {
+ pr_debug("SSC is enabled\n");
+
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1,
+ regs->ssc_stepsize_low);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1,
+ regs->ssc_stepsize_high);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1,
+ regs->ssc_div_per_low);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1,
+ regs->ssc_div_per_high);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_LOW_1,
+ regs->ssc_adjper_low);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_HIGH_1,
+ regs->ssc_adjper_high);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL,
+ SSC_EN | regs->ssc_control);
+ }
+}
+
static void dsi_pll_config_hzindep_reg(struct dsi_pll_cobalt *pll,
struct mdss_pll_resources *rsc)
{
@@ -270,8 +376,6 @@ static void dsi_pll_commit(struct dsi_pll_cobalt *pll,
MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x0a);
- /* flush, ensure all register writes are done*/
- wmb();
}
static int vco_cobalt_set_rate(struct clk *c, unsigned long rate)
@@ -311,11 +415,16 @@ static int vco_cobalt_set_rate(struct clk *c, unsigned long rate)
dsi_pll_calc_dec_frac(pll, rsc);
+ dsi_pll_calc_ssc(pll, rsc);
+
+ dsi_pll_commit(pll, rsc);
+
dsi_pll_config_hzindep_reg(pll, rsc);
- /* todo: ssc configuration */
+ dsi_pll_ssc_commit(pll, rsc);
- dsi_pll_commit(pll, rsc);
+ /* flush, ensure all register writes are done*/
+ wmb();
mdss_pll_resource_enable(rsc, false);
diff --git a/drivers/clk/msm/reset.c b/drivers/clk/msm/reset.c
index 41e0357aea3e..087e245e18f4 100644
--- a/drivers/clk/msm/reset.c
+++ b/drivers/clk/msm/reset.c
@@ -40,6 +40,9 @@ msm_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
regval |= BIT(map->bit);
writel_relaxed(regval, rst->base + map->reg);
+ /* Make sure the reset is asserted */
+ mb();
+
return 0;
}
@@ -57,6 +60,9 @@ msm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
regval &= ~BIT(map->bit);
writel_relaxed(regval, rst->base + map->reg);
+ /* Make sure the reset is de-asserted */
+ mb();
+
return 0;
}
diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c
index 7a45142a66c1..bf3a24b3eb01 100644
--- a/drivers/firmware/qcom/tz_log.c
+++ b/drivers/firmware/qcom/tz_log.c
@@ -54,6 +54,10 @@
*/
#define TZBSP_MAX_INT_DESC 16
/*
+ * TZ 3.X version info
+ */
+#define QSEE_VERSION_TZ_3_X 0x800000
+/*
* VMID Table
*/
struct tzdbg_vmid_t {
@@ -72,6 +76,19 @@ struct tzdbg_boot_info_t {
uint32_t spare; /* Reserved for future use. */
};
/*
+ * Boot Info Table for 64-bit
+ */
+struct tzdbg_boot_info64_t {
+ uint32_t wb_entry_cnt; /* Warmboot entry CPU Counter */
+ uint32_t wb_exit_cnt; /* Warmboot exit CPU Counter */
+ uint32_t pc_entry_cnt; /* Power Collapse entry CPU Counter */
+ uint32_t pc_exit_cnt; /* Power Collapse exit CPU counter */
+ uint32_t psci_entry_cnt;/* PSCI syscall entry CPU Counter */
+ uint32_t psci_exit_cnt; /* PSCI syscall exit CPU Counter */
+ uint64_t warm_jmp_addr; /* Last Warmboot Jump Address */
+ uint32_t warm_jmp_instr; /* Last Warmboot Jump Address Instruction */
+};
+/*
* Reset Info Table
*/
struct tzdbg_reset_info_t {
@@ -318,30 +335,90 @@ static int _disp_tz_boot_stats(void)
{
int i;
int len = 0;
- struct tzdbg_boot_info_t *ptr;
+ struct tzdbg_boot_info_t *ptr = NULL;
+ struct tzdbg_boot_info64_t *ptr_64 = NULL;
+ int ret = 0;
+ uint32_t smc_id = 0;
+ uint32_t feature = 10;
+ struct qseecom_command_scm_resp resp = {};
+ struct scm_desc desc = {0};
- ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf +
- tzdbg.diag_buf->boot_info_off);
+ if (!is_scm_armv8()) {
+ ret = scm_call(SCM_SVC_INFO, SCM_SVC_UTIL, &feature,
+ sizeof(feature), &resp, sizeof(resp));
+ } else {
+ smc_id = TZ_INFO_GET_FEATURE_VERSION_ID;
+ desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID;
+ desc.args[0] = feature;
+ ret = scm_call2(smc_id, &desc);
+ resp.result = desc.ret[0];
+ }
- for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
- len += snprintf(tzdbg.disp_buf + len,
- (debug_rw_buf_size - 1) - len,
- " CPU #: %d\n"
- " Warmboot jump address : 0x%x\n"
- " Warmboot entry CPU counter: 0x%x\n"
- " Warmboot exit CPU counter : 0x%x\n"
- " Power Collapse entry CPU counter: 0x%x\n"
- " Power Collapse exit CPU counter : 0x%x\n",
- i, ptr->warm_jmp_addr, ptr->wb_entry_cnt,
- ptr->wb_exit_cnt, ptr->pc_entry_cnt,
- ptr->pc_exit_cnt);
+ if (ret) {
+ pr_err("%s: scm_call to register log buffer failed\n",
+ __func__);
+ return 0;
+ }
+ pr_info("qsee_version = 0x%x\n", resp.result);
- if (len > (debug_rw_buf_size - 1)) {
- pr_warn("%s: Cannot fit all info into the buffer\n",
- __func__);
- break;
+ if (resp.result >= QSEE_VERSION_TZ_3_X) {
+ ptr_64 = (struct tzdbg_boot_info64_t *)((unsigned char *)
+ tzdbg.diag_buf + tzdbg.diag_buf->boot_info_off);
+ } else {
+ ptr = (struct tzdbg_boot_info_t *)((unsigned char *)
+ tzdbg.diag_buf + tzdbg.diag_buf->boot_info_off);
+ }
+
+ for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
+ if (resp.result >= QSEE_VERSION_TZ_3_X) {
+ len += snprintf(tzdbg.disp_buf + len,
+ (debug_rw_buf_size - 1) - len,
+ " CPU #: %d\n"
+ " Warmboot jump address : 0x%llx\n"
+ " Warmboot entry CPU counter : 0x%x\n"
+ " Warmboot exit CPU counter : 0x%x\n"
+ " Power Collapse entry CPU counter : 0x%x\n"
+ " Power Collapse exit CPU counter : 0x%x\n"
+ " Psci entry CPU counter : 0x%x\n"
+ " Psci exit CPU counter : 0x%x\n"
+ " Warmboot Jump Address Instruction : 0x%x\n",
+ i, (uint64_t)ptr_64->warm_jmp_addr,
+ ptr_64->wb_entry_cnt,
+ ptr_64->wb_exit_cnt,
+ ptr_64->pc_entry_cnt,
+ ptr_64->pc_exit_cnt,
+ ptr_64->psci_entry_cnt,
+ ptr_64->psci_exit_cnt,
+ ptr_64->warm_jmp_instr);
+
+ if (len > (debug_rw_buf_size - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+ ptr_64++;
+ } else {
+ len += snprintf(tzdbg.disp_buf + len,
+ (debug_rw_buf_size - 1) - len,
+ " CPU #: %d\n"
+ " Warmboot jump address : 0x%x\n"
+ " Warmboot entry CPU counter: 0x%x\n"
+ " Warmboot exit CPU counter : 0x%x\n"
+ " Power Collapse entry CPU counter: 0x%x\n"
+ " Power Collapse exit CPU counter : 0x%x\n",
+ i, ptr->warm_jmp_addr,
+ ptr->wb_entry_cnt,
+ ptr->wb_exit_cnt,
+ ptr->pc_entry_cnt,
+ ptr->pc_exit_cnt);
+
+ if (len > (debug_rw_buf_size - 1)) {
+ pr_warn("%s: Cannot fit all info into the buffer\n",
+ __func__);
+ break;
+ }
+ ptr++;
}
- ptr++;
}
tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf;
return len;
diff --git a/drivers/gpio/gpio-msm-smp2p-test.c b/drivers/gpio/gpio-msm-smp2p-test.c
index 067735b3026f..5907513b43c0 100644
--- a/drivers/gpio/gpio-msm-smp2p-test.c
+++ b/drivers/gpio/gpio-msm-smp2p-test.c
@@ -1,6 +1,6 @@
/* drivers/gpio/gpio-msm-smp2p-test.c
*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,6 +95,10 @@ static int smp2p_gpio_test_probe(struct platform_device *pdev)
gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].in;
} else if (strcmp("qcom,smp2pgpio_test_smp2p_4_out", node->name) == 0) {
gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].out;
+ } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_in", node->name) == 0) {
+ gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].in;
+ } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_out", node->name) == 0) {
+ gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].out;
} else if (strcmp("qcom,smp2pgpio_test_smp2p_7_in", node->name) == 0) {
gpio_info_ptr = &gpio_info[SMP2P_TZ_PROC].in;
} else if (strcmp("qcom,smp2pgpio_test_smp2p_7_out", node->name) == 0) {
@@ -148,6 +152,10 @@ static struct of_device_id msm_smp2p_match_table[] = {
{.compatible = "qcom,smp2pgpio_test_smp2p_4_out", },
{.compatible = "qcom,smp2pgpio_test_smp2p_4_in", },
+ /* CDSP */
+ {.compatible = "qcom,smp2pgpio_test_smp2p_5_out", },
+ {.compatible = "qcom,smp2pgpio_test_smp2p_5_in", },
+
/* TZ */
{.compatible = "qcom,smp2pgpio_test_smp2p_7_out", },
{.compatible = "qcom,smp2pgpio_test_smp2p_7_in", },
diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h
index 207588844931..c6dc9032c0bc 100644
--- a/drivers/gpu/msm/a5xx_reg.h
+++ b/drivers/gpu/msm/a5xx_reg.h
@@ -561,6 +561,7 @@
/* RB registers */
+#define A5XX_RB_DBG_ECO_CNT 0xCC4
#define A5XX_RB_ADDR_MODE_CNTL 0xCC5
#define A5XX_RB_MODE_CNTL 0xCC6
#define A5XX_RB_PERFCTR_RB_SEL_0 0xCD0
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b57fe05b21d5..cbeb1a924cc9 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -825,6 +825,8 @@ static struct {
{ ADRENO_QUIRK_IOMMU_SYNC, "qcom,gpu-quirk-iommu-sync" },
{ ADRENO_QUIRK_CRITICAL_PACKETS, "qcom,gpu-quirk-critical-packets" },
{ ADRENO_QUIRK_FAULT_DETECT_MASK, "qcom,gpu-quirk-fault-detect-mask" },
+ { ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING,
+ "qcom,gpu-quirk-dp2clockgating-disable" },
};
static int adreno_of_get_power(struct adreno_device *adreno_dev,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index f5fb4e48c3ee..cbbfc57e27f4 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -121,6 +121,8 @@
#define ADRENO_QUIRK_CRITICAL_PACKETS BIT(2)
/* Mask out RB1-3 activity signals from HW hang detection logic */
#define ADRENO_QUIRK_FAULT_DETECT_MASK BIT(3)
+/* Disable RB sampler datapath clock gating optimization */
+#define ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING BIT(4)
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 467b385f6d56..61d27ac8061f 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -1836,6 +1836,13 @@ static void a5xx_start(struct adreno_device *adreno_dev)
kgsl_regrmw(device, A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8));
}
+ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING)) {
+ /*
+ * Disable RB sampler datapath DP2 clock gating
+ * optimization for 1-SP GPU's, by default it is enabled.
+ */
+ kgsl_regrmw(device, A5XX_RB_DBG_ECO_CNT, 0, (1 << 9));
+ }
/* Set the USE_RETENTION_FLOPS chicken bit */
kgsl_regwrite(device, A5XX_CP_CHICKEN_DBG, 0x02000000);
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index 96922972200f..10f4577c1103 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -665,6 +665,7 @@ static void _power_counter_enable_gpmu(struct adreno_device *adreno_dev,
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_perfcount_register *reg;
+ unsigned int shift = counter << 3;
if (adreno_is_a530(adreno_dev)) {
if (countable > 43)
@@ -677,12 +678,7 @@ static void _power_counter_enable_gpmu(struct adreno_device *adreno_dev,
return;
reg = &counters->groups[group].regs[counter];
-
- /* Move the countable to the correct byte offset */
- countable = countable << ((counter % 4) * 8);
-
- kgsl_regwrite(device, reg->select, countable);
-
+ kgsl_regrmw(device, reg->select, 0xff << shift, countable << shift);
kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
reg->value = 0;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 0160939e97f9..5ffb0b2513f3 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -158,11 +158,18 @@ unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
return RB_HOSTPTR(rb, ret);
}
- cmds = RB_HOSTPTR(rb, rb->_wptr);
- *cmds = cp_packet(adreno_dev, CP_NOP,
- KGSL_RB_DWORDS - rb->_wptr - 1);
-
- rb->_wptr = 0;
+ /*
+ * There isn't enough space toward the end of ringbuffer. So
+ * look for space from the beginning of ringbuffer upto the
+ * read pointer.
+ */
+ if (dwords < rptr) {
+ cmds = RB_HOSTPTR(rb, rb->_wptr);
+ *cmds = cp_packet(adreno_dev, CP_NOP,
+ KGSL_RB_DWORDS - rb->_wptr - 1);
+ rb->_wptr = dwords;
+ return RB_HOSTPTR(rb, 0);
+ }
}
if (rb->_wptr + dwords < rptr) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c203ac7bfe8c..24005a1fda72 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -78,6 +78,16 @@ struct kgsl_dma_buf_meta {
struct sg_table *table;
};
+static inline struct kgsl_pagetable *_get_memdesc_pagetable(
+ struct kgsl_pagetable *pt, struct kgsl_mem_entry *entry)
+{
+ /* if a secured buffer, map it to secure global pagetable */
+ if (kgsl_memdesc_is_secured(&entry->memdesc))
+ return pt->mmu->securepagetable;
+
+ return pt;
+}
+
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
static const struct file_operations kgsl_fops;
@@ -445,14 +455,17 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
/* map the memory after unlocking if gpuaddr has been assigned */
if (entry->memdesc.gpuaddr) {
- /* if a secured buffer map it to secure global pagetable */
+ pagetable = process->pagetable;
if (kgsl_memdesc_is_secured(&entry->memdesc))
- pagetable = process->pagetable->mmu->securepagetable;
- else
- pagetable = process->pagetable;
+ pagetable = pagetable->mmu->securepagetable;
entry->memdesc.pagetable = pagetable;
- ret = kgsl_mmu_map(pagetable, &entry->memdesc);
+
+ if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_VIRT)
+ ret = kgsl_mmu_sparse_dummy_map(pagetable,
+ &entry->memdesc, 0, entry->memdesc.size);
+ else if (entry->memdesc.gpuaddr)
+ ret = kgsl_mmu_map(pagetable, &entry->memdesc);
if (ret)
kgsl_mem_entry_detach_process(entry);
}
@@ -1270,6 +1283,24 @@ kgsl_sharedmem_find(struct kgsl_process_private *private, uint64_t gpuaddr)
}
EXPORT_SYMBOL(kgsl_sharedmem_find);
+struct kgsl_mem_entry * __must_check
+kgsl_sharedmem_find_id_flags(struct kgsl_process_private *process,
+ unsigned int id, uint64_t flags)
+{
+ int count = 0;
+ struct kgsl_mem_entry *entry;
+
+ spin_lock(&process->mem_lock);
+ entry = idr_find(&process->mem_idr, id);
+ if (entry)
+ if (!entry->pending_free &&
+ (flags & entry->memdesc.flags) == flags)
+ count = kgsl_mem_entry_get(entry);
+ spin_unlock(&process->mem_lock);
+
+ return (count == 0) ? NULL : entry;
+}
+
/**
* kgsl_sharedmem_find_id() - find a memory entry by id
* @process: the owning process
@@ -1283,19 +1314,7 @@ EXPORT_SYMBOL(kgsl_sharedmem_find);
struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
{
- int result;
- struct kgsl_mem_entry *entry;
-
- drain_workqueue(kgsl_driver.mem_workqueue);
-
- spin_lock(&process->mem_lock);
- entry = idr_find(&process->mem_idr, id);
- result = kgsl_mem_entry_get(entry);
- spin_unlock(&process->mem_lock);
-
- if (result == 0)
- return NULL;
- return entry;
+ return kgsl_sharedmem_find_id_flags(process, id, 0);
}
/**
@@ -3121,6 +3140,546 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
return result;
}
+static inline int _sparse_alloc_param_sanity_check(uint64_t size,
+ uint64_t pagesize)
+{
+ if (size == 0 || pagesize == 0)
+ return -EINVAL;
+
+ if (pagesize != PAGE_SIZE && pagesize != SZ_64K)
+ return -EINVAL;
+
+ if (pagesize > size || !IS_ALIGNED(size, pagesize))
+ return -EINVAL;
+
+ return 0;
+}
+
+long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *process = dev_priv->process_priv;
+ struct kgsl_sparse_phys_alloc *param = data;
+ struct kgsl_mem_entry *entry;
+ int ret;
+ int id;
+
+ ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize);
+ if (ret)
+ return ret;
+
+ entry = kgsl_mem_entry_create();
+ if (entry == NULL)
+ return -ENOMEM;
+
+ ret = kgsl_process_private_get(process);
+ if (!ret) {
+ ret = -EBADF;
+ goto err_free_entry;
+ }
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&process->mem_lock);
+ /* Allocate the ID but don't attach the pointer just yet */
+ id = idr_alloc(&process->mem_idr, NULL, 1, 0, GFP_NOWAIT);
+ spin_unlock(&process->mem_lock);
+ idr_preload_end();
+
+ if (id < 0) {
+ ret = id;
+ goto err_put_proc_priv;
+ }
+
+ entry->id = id;
+ entry->priv = process;
+
+ entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_PHYS;
+ kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize));
+
+ ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc,
+ process->pagetable, param->size, entry->memdesc.flags);
+ if (ret)
+ goto err_remove_idr;
+
+ /* Sanity check to verify we got correct pagesize */
+ if (param->pagesize != PAGE_SIZE && entry->memdesc.sgt != NULL) {
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(entry->memdesc.sgt->sgl, s,
+ entry->memdesc.sgt->nents, i) {
+ if (!IS_ALIGNED(s->length, param->pagesize))
+ goto err_invalid_pages;
+ }
+ }
+
+ param->id = entry->id;
+ param->flags = entry->memdesc.flags;
+
+ trace_sparse_phys_alloc(entry->id, param->size, param->pagesize);
+ kgsl_mem_entry_commit_process(entry);
+
+ return 0;
+
+err_invalid_pages:
+ kgsl_sharedmem_free(&entry->memdesc);
+err_remove_idr:
+ spin_lock(&process->mem_lock);
+ idr_remove(&process->mem_idr, entry->id);
+ spin_unlock(&process->mem_lock);
+err_put_proc_priv:
+ kgsl_process_private_put(process);
+err_free_entry:
+ kfree(entry);
+
+ return ret;
+}
+
+long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *process = dev_priv->process_priv;
+ struct kgsl_sparse_phys_free *param = data;
+ struct kgsl_mem_entry *entry;
+
+ entry = kgsl_sharedmem_find_id_flags(process, param->id,
+ KGSL_MEMFLAGS_SPARSE_PHYS);
+ if (entry == NULL)
+ return -EINVAL;
+
+ if (entry->memdesc.cur_bindings != 0) {
+ kgsl_mem_entry_put(entry);
+ return -EINVAL;
+ }
+
+ trace_sparse_phys_free(entry->id);
+
+ /* One put for find_id(), one put for the kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+ kgsl_mem_entry_put(entry);
+
+ return 0;
+}
+
+long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_sparse_virt_alloc *param = data;
+ struct kgsl_mem_entry *entry;
+ int ret;
+
+ ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize);
+ if (ret)
+ return ret;
+
+ entry = kgsl_mem_entry_create();
+ if (entry == NULL)
+ return -ENOMEM;
+
+ entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT;
+ entry->memdesc.size = param->size;
+ entry->memdesc.cur_bindings = 0;
+ kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize));
+
+ spin_lock_init(&entry->bind_lock);
+ entry->bind_tree = RB_ROOT;
+
+ ret = kgsl_mem_entry_attach_process(entry, dev_priv);
+ if (ret) {
+ kfree(entry);
+ return ret;
+ }
+
+ param->id = entry->id;
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ param->flags = entry->memdesc.flags;
+
+ trace_sparse_virt_alloc(entry->id, param->size, param->pagesize);
+ kgsl_mem_entry_commit_process(entry);
+
+ return 0;
+}
+
+long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *process = dev_priv->process_priv;
+ struct kgsl_sparse_virt_free *param = data;
+ struct kgsl_mem_entry *entry = NULL;
+
+ entry = kgsl_sharedmem_find_id_flags(process, param->id,
+ KGSL_MEMFLAGS_SPARSE_VIRT);
+ if (entry == NULL)
+ return -EINVAL;
+
+ if (entry->bind_tree.rb_node != NULL) {
+ kgsl_mem_entry_put(entry);
+ return -EINVAL;
+ }
+
+ trace_sparse_virt_free(entry->id);
+
+ /* One put for find_id(), one put for the kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+ kgsl_mem_entry_put(entry);
+
+ return 0;
+}
+
+static int _sparse_add_to_bind_tree(struct kgsl_mem_entry *entry,
+ uint64_t v_offset,
+ struct kgsl_memdesc *memdesc,
+ uint64_t p_offset,
+ uint64_t size,
+ uint64_t flags)
+{
+ struct sparse_bind_object *new;
+ struct rb_node **node, *parent = NULL;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (new == NULL)
+ return -ENOMEM;
+
+ new->v_off = v_offset;
+ new->p_off = p_offset;
+ new->p_memdesc = memdesc;
+ new->size = size;
+ new->flags = flags;
+
+ node = &entry->bind_tree.rb_node;
+
+ while (*node != NULL) {
+ struct sparse_bind_object *this;
+
+ parent = *node;
+ this = rb_entry(parent, struct sparse_bind_object, node);
+
+ if (new->v_off < this->v_off)
+ node = &parent->rb_left;
+ else if (new->v_off > this->v_off)
+ node = &parent->rb_right;
+ }
+
+ rb_link_node(&new->node, parent, node);
+ rb_insert_color(&new->node, &entry->bind_tree);
+
+ return 0;
+}
+
+static int _sparse_rm_from_bind_tree(struct kgsl_mem_entry *entry,
+ struct sparse_bind_object *obj,
+ uint64_t v_offset, uint64_t size)
+{
+ spin_lock(&entry->bind_lock);
+ if (v_offset == obj->v_off && size >= obj->size) {
+ /*
+ * We are all encompassing, remove the entry and free
+ * things up
+ */
+ rb_erase(&obj->node, &entry->bind_tree);
+ kfree(obj);
+ } else if (v_offset == obj->v_off) {
+ /*
+ * We are the front of the node, adjust the front of
+ * the node
+ */
+ obj->v_off += size;
+ obj->p_off += size;
+ obj->size -= size;
+ } else if ((v_offset + size) == (obj->v_off + obj->size)) {
+ /*
+ * We are at the end of the obj, adjust the beginning
+ * points
+ */
+ obj->size -= size;
+ } else {
+ /*
+ * We are in the middle of a node, split it up and
+ * create a new mini node. Adjust this node's bounds
+ * and add the new node to the list.
+ */
+ uint64_t tmp_size = obj->size;
+ int ret;
+
+ obj->size = v_offset - obj->v_off;
+
+ spin_unlock(&entry->bind_lock);
+ ret = _sparse_add_to_bind_tree(entry, v_offset + size,
+ obj->p_memdesc,
+ obj->p_off + (v_offset - obj->v_off) + size,
+ tmp_size - (v_offset - obj->v_off) - size,
+ obj->flags);
+
+ return ret;
+ }
+
+ spin_unlock(&entry->bind_lock);
+
+ return 0;
+}
+
+static struct sparse_bind_object *_find_containing_bind_obj(
+ struct kgsl_mem_entry *entry,
+ uint64_t offset, uint64_t size)
+{
+ struct sparse_bind_object *obj = NULL;
+ struct rb_node *node = entry->bind_tree.rb_node;
+
+ spin_lock(&entry->bind_lock);
+
+ while (node != NULL) {
+ obj = rb_entry(node, struct sparse_bind_object, node);
+
+ if (offset == obj->v_off) {
+ break;
+ } else if (offset < obj->v_off) {
+ if (offset + size > obj->v_off)
+ break;
+ node = node->rb_left;
+ obj = NULL;
+ } else if (offset > obj->v_off) {
+ if (offset < obj->v_off + obj->size)
+ break;
+ node = node->rb_right;
+ obj = NULL;
+ }
+ }
+
+ spin_unlock(&entry->bind_lock);
+
+ return obj;
+}
+
+static int _sparse_unbind(struct kgsl_mem_entry *entry,
+ struct sparse_bind_object *bind_obj,
+ uint64_t offset, uint64_t size)
+{
+ struct kgsl_memdesc *memdesc = bind_obj->p_memdesc;
+ struct kgsl_pagetable *pt = memdesc->pagetable;
+ int ret;
+
+ if (memdesc->cur_bindings < (size / PAGE_SIZE))
+ return -EINVAL;
+
+ memdesc->cur_bindings -= size / PAGE_SIZE;
+
+ ret = kgsl_mmu_unmap_offset(pt, memdesc,
+ entry->memdesc.gpuaddr, offset, size);
+ if (ret)
+ return ret;
+
+ ret = kgsl_mmu_sparse_dummy_map(pt, &entry->memdesc, offset, size);
+ if (ret)
+ return ret;
+
+ ret = _sparse_rm_from_bind_tree(entry, bind_obj, offset, size);
+ if (ret == 0) {
+ atomic_long_sub(size, &kgsl_driver.stats.mapped);
+ trace_sparse_unbind(entry->id, offset, size);
+ }
+
+ return ret;
+}
+
+static long sparse_unbind_range(struct kgsl_sparse_binding_object *obj,
+ struct kgsl_mem_entry *virt_entry)
+{
+ struct sparse_bind_object *bind_obj;
+ int ret = 0;
+ uint64_t size = obj->size;
+ uint64_t tmp_size = obj->size;
+ uint64_t offset = obj->virtoffset;
+
+ while (size > 0 && ret == 0) {
+ tmp_size = size;
+ bind_obj = _find_containing_bind_obj(virt_entry, offset, size);
+ if (bind_obj == NULL)
+ return 0;
+
+ if (bind_obj->v_off > offset) {
+ tmp_size = size - bind_obj->v_off - offset;
+ if (tmp_size > bind_obj->size)
+ tmp_size = bind_obj->size;
+ offset = bind_obj->v_off;
+ } else if (bind_obj->v_off < offset) {
+ uint64_t diff = offset - bind_obj->v_off;
+
+ if (diff + size > bind_obj->size)
+ tmp_size = bind_obj->size - diff;
+ } else {
+ if (tmp_size > bind_obj->size)
+ tmp_size = bind_obj->size;
+ }
+
+ ret = _sparse_unbind(virt_entry, bind_obj, offset, tmp_size);
+ if (ret == 0) {
+ offset += tmp_size;
+ size -= tmp_size;
+ }
+ }
+
+ return ret;
+}
+
+static inline bool _is_phys_bindable(struct kgsl_mem_entry *phys_entry,
+ uint64_t offset, uint64_t size, uint64_t flags)
+{
+ struct kgsl_memdesc *memdesc = &phys_entry->memdesc;
+
+ if (!IS_ALIGNED(offset | size, kgsl_memdesc_get_pagesize(memdesc)))
+ return false;
+
+ if (!(flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) &&
+ offset + size > memdesc->size)
+ return false;
+
+ return true;
+}
+
+static int _sparse_bind(struct kgsl_process_private *process,
+ struct kgsl_mem_entry *virt_entry, uint64_t v_offset,
+ struct kgsl_mem_entry *phys_entry, uint64_t p_offset,
+ uint64_t size, uint64_t flags)
+{
+ int ret;
+ struct kgsl_pagetable *pagetable;
+ struct kgsl_memdesc *memdesc = &phys_entry->memdesc;
+
+ /* map the memory after unlocking if gpuaddr has been assigned */
+ if (memdesc->gpuaddr)
+ return -EINVAL;
+
+ if (memdesc->useraddr != 0)
+ return -EINVAL;
+
+ pagetable = memdesc->pagetable;
+
+ /* Clear out any mappings */
+ ret = kgsl_mmu_unmap_offset(pagetable, &virt_entry->memdesc,
+ virt_entry->memdesc.gpuaddr, v_offset, size);
+ if (ret)
+ return ret;
+
+ ret = kgsl_mmu_map_offset(pagetable, virt_entry->memdesc.gpuaddr,
+ v_offset, memdesc, p_offset, size, flags);
+ if (ret) {
+ /* Try to clean up, but not the end of the world */
+ kgsl_mmu_sparse_dummy_map(pagetable, &virt_entry->memdesc,
+ v_offset, size);
+ return ret;
+ }
+
+ ret = _sparse_add_to_bind_tree(virt_entry, v_offset, memdesc,
+ p_offset, size, flags);
+ if (ret == 0)
+ memdesc->cur_bindings += size / PAGE_SIZE;
+
+ return ret;
+}
+
+static long sparse_bind_range(struct kgsl_process_private *private,
+ struct kgsl_sparse_binding_object *obj,
+ struct kgsl_mem_entry *virt_entry)
+{
+ struct kgsl_mem_entry *phys_entry;
+ int ret;
+
+ phys_entry = kgsl_sharedmem_find_id_flags(private, obj->id,
+ KGSL_MEMFLAGS_SPARSE_PHYS);
+ if (phys_entry == NULL)
+ return -EINVAL;
+
+ if (!_is_phys_bindable(phys_entry, obj->physoffset, obj->size,
+ obj->flags)) {
+ kgsl_mem_entry_put(phys_entry);
+ return -EINVAL;
+ }
+
+ if (kgsl_memdesc_get_align(&virt_entry->memdesc) !=
+ kgsl_memdesc_get_align(&phys_entry->memdesc)) {
+ kgsl_mem_entry_put(phys_entry);
+ return -EINVAL;
+ }
+
+ ret = sparse_unbind_range(obj, virt_entry);
+ if (ret) {
+ kgsl_mem_entry_put(phys_entry);
+ return -EINVAL;
+ }
+
+ ret = _sparse_bind(private, virt_entry, obj->virtoffset,
+ phys_entry, obj->physoffset, obj->size,
+ obj->flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS);
+ if (ret == 0) {
+ KGSL_STATS_ADD(obj->size, &kgsl_driver.stats.mapped,
+ &kgsl_driver.stats.mapped_max);
+
+ trace_sparse_bind(virt_entry->id, obj->virtoffset,
+ phys_entry->id, obj->physoffset,
+ obj->size, obj->flags);
+ }
+
+ kgsl_mem_entry_put(phys_entry);
+
+ return ret;
+}
+
+long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_sparse_bind *param = data;
+ struct kgsl_sparse_binding_object obj;
+ struct kgsl_mem_entry *virt_entry;
+ int pg_sz;
+ void __user *ptr;
+ int ret = 0;
+ int i = 0;
+
+ ptr = (void __user *) (uintptr_t) param->list;
+
+ if (param->size > sizeof(struct kgsl_sparse_binding_object) ||
+ param->count == 0 || ptr == NULL)
+ return -EINVAL;
+
+ virt_entry = kgsl_sharedmem_find_id_flags(private, param->id,
+ KGSL_MEMFLAGS_SPARSE_VIRT);
+ if (virt_entry == NULL)
+ return -EINVAL;
+
+ pg_sz = kgsl_memdesc_get_pagesize(&virt_entry->memdesc);
+
+ for (i = 0; i < param->count; i++) {
+ memset(&obj, 0, sizeof(obj));
+ ret = _copy_from_user(&obj, ptr, sizeof(obj), param->size);
+ if (ret)
+ break;
+
+ /* Sanity check initial range */
+ if (obj.size == 0 ||
+ obj.virtoffset + obj.size > virt_entry->memdesc.size ||
+ !(IS_ALIGNED(obj.virtoffset | obj.size, pg_sz))) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (obj.flags & KGSL_SPARSE_BIND)
+ ret = sparse_bind_range(private, &obj, virt_entry);
+ else if (obj.flags & KGSL_SPARSE_UNBIND)
+ ret = sparse_unbind_range(&obj, virt_entry);
+ else
+ ret = -EINVAL;
+ if (ret)
+ break;
+
+ ptr += sizeof(obj);
+ }
+
+ kgsl_mem_entry_put(virt_entry);
+
+ return ret;
+}
+
long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -3356,6 +3915,13 @@ get_mmap_entry(struct kgsl_process_private *private,
goto err_put;
}
+ if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_PHYS) {
+ if (len != entry->memdesc.size) {
+ ret = -EINVAL;
+ goto err_put;
+ }
+ }
+
if (entry->memdesc.useraddr != 0) {
ret = -EBUSY;
goto err_put;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ee7149e1fd41..25f5de6ce645 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -184,6 +184,7 @@ struct kgsl_memdesc_ops {
* @attrs: dma attributes for this memory
* @pages: An array of pointers to allocated pages
* @page_count: Total number of pages allocated
+ * @cur_bindings: Number of sparse pages actively bound
*/
struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
@@ -202,6 +203,7 @@ struct kgsl_memdesc {
struct dma_attrs attrs;
struct page **pages;
unsigned int page_count;
+ unsigned int cur_bindings;
};
/*
@@ -235,6 +237,8 @@ struct kgsl_memdesc {
* @dev_priv: back pointer to the device file that created this entry.
* @metadata: String containing user specified metadata for the entry
* @work: Work struct used to schedule a kgsl_mem_entry_put in atomic contexts
+ * @bind_lock: Lock for sparse memory bindings
+ * @bind_tree: RB Tree for sparse memory bindings
*/
struct kgsl_mem_entry {
struct kref refcount;
@@ -246,6 +250,8 @@ struct kgsl_mem_entry {
int pending_free;
char metadata[KGSL_GPUOBJ_ALLOC_METADATA_MAX + 1];
struct work_struct work;
+ spinlock_t bind_lock;
+ struct rb_root bind_tree;
};
struct kgsl_device_private;
@@ -315,6 +321,24 @@ struct kgsl_protected_registers {
int range;
};
+/**
+ * struct sparse_bind_object - Bind metadata
+ * @node: Node for the rb tree
+ * @p_memdesc: Physical memdesc bound to
+ * @v_off: Offset of bind in the virtual entry
+ * @p_off: Offset of bind in the physical memdesc
+ * @size: Size of the bind
+ * @flags: Flags for the bind
+ */
+struct sparse_bind_object {
+ struct rb_node node;
+ struct kgsl_memdesc *p_memdesc;
+ uint64_t v_off;
+ uint64_t p_off;
+ uint64_t size;
+ uint64_t flags;
+};
+
long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
@@ -377,6 +401,19 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+long kgsl_ioctl_sparse_unbind(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
+
void kgsl_mem_entry_destroy(struct kref *kref);
struct kgsl_mem_entry * __must_check
diff --git a/drivers/gpu/msm/kgsl_compat.c b/drivers/gpu/msm/kgsl_compat.c
index 248c78b7e5c4..028a9566fa14 100644
--- a/drivers/gpu/msm/kgsl_compat.c
+++ b/drivers/gpu/msm/kgsl_compat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -372,6 +372,16 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
kgsl_ioctl_gpu_command),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SET_INFO,
kgsl_ioctl_gpuobj_set_info),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_ALLOC,
+ kgsl_ioctl_sparse_phys_alloc),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_FREE,
+ kgsl_ioctl_sparse_phys_free),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_ALLOC,
+ kgsl_ioctl_sparse_virt_alloc),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_FREE,
+ kgsl_ioctl_sparse_virt_free),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
+ kgsl_ioctl_sparse_bind),
};
long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 93ac790f3a55..df9eb9ebd779 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -129,10 +129,13 @@ static int print_mem_entry(int id, void *ptr, void *data)
{
struct seq_file *s = data;
struct kgsl_mem_entry *entry = ptr;
- char flags[9];
+ char flags[10];
char usage[16];
struct kgsl_memdesc *m = &entry->memdesc;
+ if (m->flags & KGSL_MEMFLAGS_SPARSE_VIRT)
+ return 0;
+
flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
flags[1] = '-';
flags[2] = !(m->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-';
@@ -141,7 +144,8 @@ static int print_mem_entry(int id, void *ptr, void *data)
flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
flags[6] = (m->useraddr) ? 'Y' : 'N';
flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-';
- flags[8] = '\0';
+ flags[8] = m->flags & KGSL_MEMFLAGS_SPARSE_PHYS ? 'P' : '-';
+ flags[9] = '\0';
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
@@ -211,6 +215,70 @@ static const struct file_operations process_mem_fops = {
.release = process_mem_release,
};
+static int print_sparse_mem_entry(int id, void *ptr, void *data)
+{
+ struct seq_file *s = data;
+ struct kgsl_mem_entry *entry = ptr;
+ struct kgsl_memdesc *m = &entry->memdesc;
+ struct rb_node *node;
+
+ if (!(m->flags & KGSL_MEMFLAGS_SPARSE_VIRT))
+ return 0;
+
+ node = rb_first(&entry->bind_tree);
+
+ while (node != NULL) {
+ struct sparse_bind_object *obj = rb_entry(node,
+ struct sparse_bind_object, node);
+ seq_printf(s, "%5d %16llx %16llx %16llx %16llx\n",
+ entry->id, entry->memdesc.gpuaddr,
+ obj->v_off, obj->size, obj->p_off);
+ node = rb_next(node);
+ }
+
+ seq_putc(s, '\n');
+
+ return 0;
+}
+
+static int process_sparse_mem_print(struct seq_file *s, void *unused)
+{
+ struct kgsl_process_private *private = s->private;
+
+ seq_printf(s, "%5s %16s %16s %16s %16s\n",
+ "v_id", "gpuaddr", "v_offset", "v_size", "p_offset");
+
+ spin_lock(&private->mem_lock);
+ idr_for_each(&private->mem_idr, print_sparse_mem_entry, s);
+ spin_unlock(&private->mem_lock);
+
+ return 0;
+}
+
+static int process_sparse_mem_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ pid_t pid = (pid_t) (unsigned long) inode->i_private;
+ struct kgsl_process_private *private = NULL;
+
+ private = kgsl_process_private_find(pid);
+
+ if (!private)
+ return -ENODEV;
+
+ ret = single_open(file, process_sparse_mem_print, private);
+ if (ret)
+ kgsl_process_private_put(private);
+
+ return ret;
+}
+
+static const struct file_operations process_sparse_mem_fops = {
+ .open = process_sparse_mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = process_mem_release,
+};
/**
* kgsl_process_init_debugfs() - Initialize debugfs for a process
@@ -251,6 +319,15 @@ void kgsl_process_init_debugfs(struct kgsl_process_private *private)
if (IS_ERR_OR_NULL(dentry))
WARN((dentry == NULL),
"Unable to create 'mem' file for %s\n", name);
+
+ dentry = debugfs_create_file("sparse_mem", 0444, private->debug_root,
+ (void *) ((unsigned long) private->pid),
+ &process_sparse_mem_fops);
+
+ if (IS_ERR_OR_NULL(dentry))
+ WARN((dentry == NULL),
+ "Unable to create 'sparse_mem' file for %s\n", name);
+
}
void kgsl_core_debugfs_init(void)
diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c
index 0802e94f56ad..894e6a4a146b 100644
--- a/drivers/gpu/msm/kgsl_ioctl.c
+++ b/drivers/gpu/msm/kgsl_ioctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -90,6 +90,16 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = {
kgsl_ioctl_gpu_command),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SET_INFO,
kgsl_ioctl_gpuobj_set_info),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_ALLOC,
+ kgsl_ioctl_sparse_phys_alloc),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_FREE,
+ kgsl_ioctl_sparse_phys_free),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_ALLOC,
+ kgsl_ioctl_sparse_virt_alloc),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_FREE,
+ kgsl_ioctl_sparse_virt_free),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
+ kgsl_ioctl_sparse_bind),
};
long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index b467ef81d257..166bb68e64a1 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -323,8 +323,8 @@ static int _iommu_map_sync_pc(struct kgsl_pagetable *pt,
_unlock_if_secure_mmu(memdesc, pt->mmu);
if (ret) {
- KGSL_CORE_ERR("map err: %p, 0x%016llX, 0x%llx, 0x%x, %d\n",
- iommu_pt->domain, gpuaddr, size, flags, ret);
+ KGSL_CORE_ERR("map err: 0x%016llX, 0x%llx, 0x%x, %d\n",
+ gpuaddr, size, flags, ret);
return -ENODEV;
}
@@ -351,8 +351,8 @@ static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt,
_unlock_if_secure_mmu(memdesc, pt->mmu);
if (unmapped != size) {
- KGSL_CORE_ERR("unmap err: %p, 0x%016llx, 0x%llx, %zd\n",
- iommu_pt->domain, addr, size, unmapped);
+ KGSL_CORE_ERR("unmap err: 0x%016llx, 0x%llx, %zd\n",
+ addr, size, unmapped);
return -ENODEV;
}
@@ -421,8 +421,9 @@ static int _iommu_map_sg_offset_sync_pc(struct kgsl_pagetable *pt,
if (size != 0) {
/* Cleanup on error */
_iommu_unmap_sync_pc(pt, memdesc, addr, mapped);
- KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n",
- iommu_pt->domain, addr, nents, flags, mapped);
+ KGSL_CORE_ERR(
+ "map sg offset err: 0x%016llX, %d, %x, %zd\n",
+ addr, nents, flags, mapped);
return -ENODEV;
}
@@ -451,8 +452,8 @@ static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt,
_unlock_if_secure_mmu(memdesc, pt->mmu);
if (mapped == 0) {
- KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n",
- iommu_pt->domain, addr, nents, flags, mapped);
+ KGSL_CORE_ERR("map sg err: 0x%016llX, %d, %x, %zd\n",
+ addr, nents, flags, mapped);
return -ENODEV;
}
@@ -467,6 +468,13 @@ static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt,
static struct page *kgsl_guard_page;
static struct kgsl_memdesc kgsl_secure_guard_page_memdesc;
+/*
+ * The dummy page is a placeholder/extra page to be used for sparse mappings.
+ * This page will be mapped to all virtual sparse bindings that are not
+ * physically backed.
+ */
+static struct page *kgsl_dummy_page;
+
/* These functions help find the nearest allocated memory entries on either side
* of a faulting address. If we know the nearby allocations memory we can
* get a better determination of what we think should have been located in the
@@ -1309,6 +1317,11 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu)
kgsl_guard_page = NULL;
}
+ if (kgsl_dummy_page != NULL) {
+ __free_page(kgsl_dummy_page);
+ kgsl_dummy_page = NULL;
+ }
+
kgsl_iommu_remove_global(mmu, &iommu->setstate);
kgsl_sharedmem_free(&iommu->setstate);
kgsl_cleanup_qdss_desc(mmu);
@@ -1523,6 +1536,8 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc, uint64_t addr,
uint64_t offset, uint64_t size)
{
+ if (size == 0 || (size + offset) > kgsl_memdesc_footprint(memdesc))
+ return -EINVAL;
/*
* All GPU addresses as assigned are page aligned, but some
* functions perturb the gpuaddr with an offset, so apply the
@@ -1530,9 +1545,8 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt,
*/
addr = PAGE_ALIGN(addr);
-
- if (size == 0 || addr == 0)
- return 0;
+ if (addr == 0)
+ return -EINVAL;
return _iommu_unmap_sync_pc(pt, memdesc, addr + offset, size);
}
@@ -1540,13 +1554,11 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt,
static int
kgsl_iommu_unmap(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc)
{
- uint64_t size = memdesc->size;
-
- if (kgsl_memdesc_has_guard_page(memdesc))
- size += kgsl_memdesc_guard_page_size(pt->mmu, memdesc);
+ if (memdesc->size == 0 || memdesc->gpuaddr == 0)
+ return -EINVAL;
return kgsl_iommu_unmap_offset(pt, memdesc, memdesc->gpuaddr, 0,
- size);
+ kgsl_memdesc_footprint(memdesc));
}
/**
@@ -1593,7 +1605,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt,
} else {
if (kgsl_guard_page == NULL) {
kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
- __GFP_HIGHMEM);
+ __GFP_NORETRY | __GFP_HIGHMEM);
if (kgsl_guard_page == NULL)
return -ENOMEM;
}
@@ -1602,7 +1614,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt,
}
return _iommu_map_sync_pc(pt, memdesc, gpuaddr, physaddr,
- kgsl_memdesc_guard_page_size(pt->mmu, memdesc),
+ kgsl_memdesc_guard_page_size(memdesc),
protflags & ~IOMMU_WRITE);
}
@@ -1658,6 +1670,100 @@ done:
return ret;
}
+static int kgsl_iommu_sparse_dummy_map(struct kgsl_pagetable *pt,
+ struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size)
+{
+ int ret = 0, i;
+ struct page **pages = NULL;
+ struct sg_table sgt;
+ int count = size >> PAGE_SHIFT;
+
+ /* verify the offset is within our range */
+ if (size + offset > memdesc->size)
+ return -EINVAL;
+
+ if (kgsl_dummy_page == NULL) {
+ kgsl_dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_HIGHMEM);
+ if (kgsl_dummy_page == NULL)
+ return -ENOMEM;
+ }
+
+ pages = kcalloc(count, sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++)
+ pages[i] = kgsl_dummy_page;
+
+ ret = sg_alloc_table_from_pages(&sgt, pages, count,
+ 0, size, GFP_KERNEL);
+ if (ret == 0) {
+ ret = _iommu_map_sg_sync_pc(pt, memdesc->gpuaddr + offset,
+ memdesc, sgt.sgl, sgt.nents,
+ IOMMU_READ | IOMMU_NOEXEC);
+ sg_free_table(&sgt);
+ }
+
+ kfree(pages);
+
+ return ret;
+}
+
+static int _map_to_one_page(struct kgsl_pagetable *pt, uint64_t addr,
+ struct kgsl_memdesc *memdesc, uint64_t physoffset,
+ uint64_t size, unsigned int map_flags)
+{
+ int ret = 0, i;
+ int pg_sz = kgsl_memdesc_get_pagesize(memdesc);
+ int count = size >> PAGE_SHIFT;
+ struct page *page = NULL;
+ struct page **pages = NULL;
+ struct sg_page_iter sg_iter;
+ struct sg_table sgt;
+
+ /* Find our physaddr offset addr */
+ if (memdesc->pages != NULL)
+ page = memdesc->pages[physoffset >> PAGE_SHIFT];
+ else {
+ for_each_sg_page(memdesc->sgt->sgl, &sg_iter,
+ memdesc->sgt->nents, physoffset >> PAGE_SHIFT) {
+ page = sg_page_iter_page(&sg_iter);
+ break;
+ }
+ }
+
+ if (page == NULL)
+ return -EINVAL;
+
+ pages = kcalloc(count, sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ if (pg_sz != PAGE_SIZE) {
+ struct page *tmp_page = page;
+ int j;
+
+ for (j = 0; j < 16; j++, tmp_page += PAGE_SIZE)
+ pages[i++] = tmp_page;
+ } else
+ pages[i] = page;
+ }
+
+ ret = sg_alloc_table_from_pages(&sgt, pages, count,
+ 0, size, GFP_KERNEL);
+ if (ret == 0) {
+ ret = _iommu_map_sg_sync_pc(pt, addr, memdesc, sgt.sgl,
+ sgt.nents, map_flags);
+ sg_free_table(&sgt);
+ }
+
+ kfree(pages);
+
+ return ret;
+}
+
static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt,
uint64_t virtaddr, uint64_t virtoffset,
struct kgsl_memdesc *memdesc, uint64_t physoffset,
@@ -1668,13 +1774,17 @@ static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt,
int ret;
struct sg_table *sgt = NULL;
- pg_sz = (1 << kgsl_memdesc_get_align(memdesc));
+ pg_sz = kgsl_memdesc_get_pagesize(memdesc);
if (!IS_ALIGNED(virtaddr | virtoffset | physoffset | size, pg_sz))
return -EINVAL;
if (size == 0)
return -EINVAL;
+ if (!(feature_flag & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) &&
+ size + physoffset > kgsl_memdesc_footprint(memdesc))
+ return -EINVAL;
+
/*
* For paged memory allocated through kgsl, memdesc->pages is not NULL.
* Allocate sgt here just for its map operation. Contiguous memory
@@ -1688,9 +1798,13 @@ static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt,
if (IS_ERR(sgt))
return PTR_ERR(sgt);
- ret = _iommu_map_sg_offset_sync_pc(pt, virtaddr + virtoffset,
- memdesc, sgt->sgl, sgt->nents,
- physoffset, size, protflags);
+ if (feature_flag & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS)
+ ret = _map_to_one_page(pt, virtaddr + virtoffset,
+ memdesc, physoffset, size, protflags);
+ else
+ ret = _iommu_map_sg_offset_sync_pc(pt, virtaddr + virtoffset,
+ memdesc, sgt->sgl, sgt->nents,
+ physoffset, size, protflags);
if (memdesc->pages != NULL)
kgsl_free_sgt(sgt);
@@ -2152,8 +2266,7 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
{
struct kgsl_iommu_pt *pt = pagetable->priv;
int ret = 0;
- uint64_t addr, start, end;
- uint64_t size = memdesc->size;
+ uint64_t addr, start, end, size;
unsigned int align;
BUG_ON(kgsl_memdesc_use_cpu_map(memdesc));
@@ -2162,8 +2275,7 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
pagetable->name != KGSL_MMU_SECURE_PT)
return -EINVAL;
- if (kgsl_memdesc_has_guard_page(memdesc))
- size += kgsl_memdesc_guard_page_size(pagetable->mmu, memdesc);
+ size = kgsl_memdesc_footprint(memdesc);
align = 1 << kgsl_memdesc_get_align(memdesc);
@@ -2445,4 +2557,5 @@ static struct kgsl_mmu_pt_ops iommu_pt_ops = {
.addr_in_range = kgsl_iommu_addr_in_range,
.mmu_map_offset = kgsl_iommu_map_offset,
.mmu_unmap_offset = kgsl_iommu_unmap_offset,
+ .mmu_sparse_dummy_map = kgsl_iommu_sparse_dummy_map,
};
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 8b0d93fda32c..10f6b8049d36 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -386,29 +386,24 @@ int
kgsl_mmu_map(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc)
{
- int ret = 0;
int size;
if (!memdesc->gpuaddr)
return -EINVAL;
- /* Only global mappings should be mapped multiple times */
- if (!kgsl_memdesc_is_global(memdesc) &&
- (KGSL_MEMDESC_MAPPED & memdesc->priv))
- return -EINVAL;
size = kgsl_memdesc_footprint(memdesc);
- if (PT_OP_VALID(pagetable, mmu_map))
- ret = pagetable->pt_ops->mmu_map(pagetable, memdesc);
-
- if (ret)
- return ret;
+ if (PT_OP_VALID(pagetable, mmu_map)) {
+ int ret;
- atomic_inc(&pagetable->stats.entries);
- KGSL_STATS_ADD(size, &pagetable->stats.mapped,
- &pagetable->stats.max_mapped);
+ ret = pagetable->pt_ops->mmu_map(pagetable, memdesc);
+ if (ret)
+ return ret;
- memdesc->priv |= KGSL_MEMDESC_MAPPED;
+ atomic_inc(&pagetable->stats.entries);
+ KGSL_STATS_ADD(size, &pagetable->stats.mapped,
+ &pagetable->stats.max_mapped);
+ }
return 0;
}
@@ -455,22 +450,22 @@ int
kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc)
{
- uint64_t size;
-
- if (memdesc->size == 0 || memdesc->gpuaddr == 0 ||
- !(KGSL_MEMDESC_MAPPED & memdesc->priv))
+ if (memdesc->size == 0)
return -EINVAL;
- size = kgsl_memdesc_footprint(memdesc);
+ if (PT_OP_VALID(pagetable, mmu_unmap)) {
+ int ret;
+ uint64_t size;
- if (PT_OP_VALID(pagetable, mmu_unmap))
- pagetable->pt_ops->mmu_unmap(pagetable, memdesc);
+ size = kgsl_memdesc_footprint(memdesc);
- atomic_dec(&pagetable->stats.entries);
- atomic_long_sub(size, &pagetable->stats.mapped);
+ ret = pagetable->pt_ops->mmu_unmap(pagetable, memdesc);
+ if (ret)
+ return ret;
- if (!kgsl_memdesc_is_global(memdesc))
- memdesc->priv &= ~KGSL_MEMDESC_MAPPED;
+ atomic_dec(&pagetable->stats.entries);
+ atomic_long_sub(size, &pagetable->stats.mapped);
+ }
return 0;
}
@@ -481,11 +476,20 @@ int kgsl_mmu_map_offset(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc, uint64_t physoffset,
uint64_t size, uint64_t flags)
{
- if (PT_OP_VALID(pagetable, mmu_map_offset))
- return pagetable->pt_ops->mmu_map_offset(pagetable, virtaddr,
+ if (PT_OP_VALID(pagetable, mmu_map_offset)) {
+ int ret;
+
+ ret = pagetable->pt_ops->mmu_map_offset(pagetable, virtaddr,
virtoffset, memdesc, physoffset, size, flags);
+ if (ret)
+ return ret;
+
+ atomic_inc(&pagetable->stats.entries);
+ KGSL_STATS_ADD(size, &pagetable->stats.mapped,
+ &pagetable->stats.max_mapped);
+ }
- return -EINVAL;
+ return 0;
}
EXPORT_SYMBOL(kgsl_mmu_map_offset);
@@ -493,14 +497,41 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset,
uint64_t size)
{
- if (PT_OP_VALID(pagetable, mmu_unmap_offset))
- return pagetable->pt_ops->mmu_unmap_offset(pagetable, memdesc,
+ if (PT_OP_VALID(pagetable, mmu_unmap_offset)) {
+ int ret;
+
+ ret = pagetable->pt_ops->mmu_unmap_offset(pagetable, memdesc,
addr, offset, size);
+ if (ret)
+ return ret;
+
+ atomic_dec(&pagetable->stats.entries);
+ atomic_long_sub(size, &pagetable->stats.mapped);
+ }
- return -EINVAL;
+ return 0;
}
EXPORT_SYMBOL(kgsl_mmu_unmap_offset);
+int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable,
+ struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size)
+{
+ if (PT_OP_VALID(pagetable, mmu_sparse_dummy_map)) {
+ int ret;
+
+ ret = pagetable->pt_ops->mmu_sparse_dummy_map(pagetable,
+ memdesc, offset, size);
+ if (ret)
+ return ret;
+
+ atomic_dec(&pagetable->stats.entries);
+ atomic_long_sub(size, &pagetable->stats.mapped);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_mmu_sparse_dummy_map);
+
void kgsl_mmu_remove_global(struct kgsl_device *device,
struct kgsl_memdesc *memdesc)
{
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 588777af353f..53645cc1741c 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -106,6 +106,9 @@ struct kgsl_mmu_pt_ops {
int (*mmu_unmap_offset)(struct kgsl_pagetable *pt,
struct kgsl_memdesc *memdesc, uint64_t addr,
uint64_t offset, uint64_t size);
+ int (*mmu_sparse_dummy_map)(struct kgsl_pagetable *pt,
+ struct kgsl_memdesc *memdesc, uint64_t offset,
+ uint64_t size);
};
/*
@@ -230,6 +233,9 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device);
+int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable,
+ struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size);
+
/*
* Static inline functions of MMU that simply call the SMMU specific
* function using a function pointer. These functions can be thought
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index c05aaecb5284..565ae4c39fdd 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -92,6 +92,18 @@ kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc)
}
/*
+ * kgsl_memdesc_get_pagesize - Get pagesize based on alignment
+ * @memdesc - the memdesc
+ *
+ * Returns the pagesize based on memdesc alignment
+ */
+static inline int
+kgsl_memdesc_get_pagesize(const struct kgsl_memdesc *memdesc)
+{
+ return (1 << kgsl_memdesc_get_align(memdesc));
+}
+
+/*
* kgsl_memdesc_get_cachemode - Get cache mode of a memdesc
* @memdesc: the memdesc
*
@@ -211,12 +223,19 @@ kgsl_memdesc_has_guard_page(const struct kgsl_memdesc *memdesc)
*
* Returns guard page size
*/
-static inline int
-kgsl_memdesc_guard_page_size(const struct kgsl_mmu *mmu,
- const struct kgsl_memdesc *memdesc)
+static inline uint64_t
+kgsl_memdesc_guard_page_size(const struct kgsl_memdesc *memdesc)
{
- return kgsl_memdesc_is_secured(memdesc) ? mmu->secure_align_mask + 1 :
- PAGE_SIZE;
+ if (!kgsl_memdesc_has_guard_page(memdesc))
+ return 0;
+
+ if (kgsl_memdesc_is_secured(memdesc)) {
+ if (memdesc->pagetable != NULL &&
+ memdesc->pagetable->mmu != NULL)
+ return memdesc->pagetable->mmu->secure_align_mask + 1;
+ }
+
+ return PAGE_SIZE;
}
/*
@@ -241,10 +260,7 @@ kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc)
static inline uint64_t
kgsl_memdesc_footprint(const struct kgsl_memdesc *memdesc)
{
- uint64_t size = memdesc->size;
- if (kgsl_memdesc_has_guard_page(memdesc))
- size += SZ_4K;
- return size;
+ return memdesc->size + kgsl_memdesc_guard_page_size(memdesc);
}
/*
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 69ae2e3fd2d7..f9d3ede718ab 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -313,6 +313,13 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot,
goto err_put;
}
+ /* Do not save sparse memory */
+ if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_VIRT ||
+ entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_PHYS) {
+ ret = 0;
+ goto err_put;
+ }
+
/*
* size indicates the number of bytes in the region to save. This might
* not always be the entire size of the region because some buffers are
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 8988dc12839f..bac09175cf12 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -1102,6 +1102,100 @@ TRACE_EVENT(kgsl_msg,
)
);
+DECLARE_EVENT_CLASS(sparse_alloc_template,
+ TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize),
+ TP_ARGS(id, size, pagesize),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(uint64_t, size)
+ __field(unsigned int, pagesize)
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->size = size;
+ __entry->pagesize = pagesize;
+ ),
+ TP_printk("id=%d size=0x%llX pagesize=0x%X",
+ __entry->id, __entry->size, __entry->pagesize)
+);
+
+DEFINE_EVENT(sparse_alloc_template, sparse_phys_alloc,
+ TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize),
+ TP_ARGS(id, size, pagesize)
+);
+
+DEFINE_EVENT(sparse_alloc_template, sparse_virt_alloc,
+ TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize),
+ TP_ARGS(id, size, pagesize)
+);
+
+DECLARE_EVENT_CLASS(sparse_free_template,
+ TP_PROTO(unsigned int id),
+ TP_ARGS(id),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ ),
+ TP_printk("id=%d", __entry->id)
+);
+
+DEFINE_EVENT(sparse_free_template, sparse_phys_free,
+ TP_PROTO(unsigned int id),
+ TP_ARGS(id)
+);
+
+DEFINE_EVENT(sparse_free_template, sparse_virt_free,
+ TP_PROTO(unsigned int id),
+ TP_ARGS(id)
+);
+
+TRACE_EVENT(sparse_bind,
+ TP_PROTO(unsigned int v_id, uint64_t v_off,
+ unsigned int p_id, uint64_t p_off,
+ uint64_t size, uint64_t flags),
+ TP_ARGS(v_id, v_off, p_id, p_off, size, flags),
+ TP_STRUCT__entry(
+ __field(unsigned int, v_id)
+ __field(uint64_t, v_off)
+ __field(unsigned int, p_id)
+ __field(uint64_t, p_off)
+ __field(uint64_t, size)
+ __field(uint64_t, flags)
+ ),
+ TP_fast_assign(
+ __entry->v_id = v_id;
+ __entry->v_off = v_off;
+ __entry->p_id = p_id;
+ __entry->p_off = p_off;
+ __entry->size = size;
+ __entry->flags = flags;
+ ),
+ TP_printk(
+ "v_id=%d v_off=0x%llX p_id=%d p_off=0x%llX size=0x%llX flags=0x%llX",
+ __entry->v_id, __entry->v_off,
+ __entry->p_id, __entry->p_off,
+ __entry->size, __entry->flags)
+);
+
+TRACE_EVENT(sparse_unbind,
+ TP_PROTO(unsigned int v_id, uint64_t v_off, uint64_t size),
+ TP_ARGS(v_id, v_off, size),
+ TP_STRUCT__entry(
+ __field(unsigned int, v_id)
+ __field(uint64_t, v_off)
+ __field(uint64_t, size)
+ ),
+ TP_fast_assign(
+ __entry->v_id = v_id;
+ __entry->v_off = v_off;
+ __entry->size = size;
+ ),
+ TP_printk("v_id=%d v_off=0x%llX size=0x%llX",
+ __entry->v_id, __entry->v_off, __entry->size)
+);
+
#endif /* _KGSL_TRACE_H */
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 617c766f032e..5697ad3b1d13 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -42,6 +42,7 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
static int etm4_count;
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
static struct notifier_block etm4_cpu_notifier;
+static struct notifier_block etm4_cpu_dying_notifier;
static void etm4_os_unlock(void *info)
{
@@ -2682,20 +2683,15 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
clk_disable[cpu] = false;
}
break;
-
- case CPU_DYING:
- spin_lock(&etmdrvdata[cpu]->spinlock);
- if (etmdrvdata[cpu]->enable)
- etm4_disable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- break;
}
out:
return NOTIFY_OK;
err_init:
- if (--etm4_count == 0)
+ if (--etm4_count == 0) {
unregister_hotcpu_notifier(&etm4_cpu_notifier);
+ unregister_hotcpu_notifier(&etm4_cpu_dying_notifier);
+ }
if (clk_disable[cpu]) {
pm_runtime_put(etmdrvdata[cpu]->dev);
@@ -2715,6 +2711,31 @@ static struct notifier_block etm4_cpu_notifier = {
.notifier_call = etm4_cpu_callback,
};
+static int etm4_cpu_dying_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ if (!etmdrvdata[cpu])
+ goto out;
+
+ switch (action & (~CPU_TASKS_FROZEN)) {
+ case CPU_DYING:
+ spin_lock(&etmdrvdata[cpu]->spinlock);
+ if (etmdrvdata[cpu]->enable)
+ etm4_disable_hw(etmdrvdata[cpu]);
+ spin_unlock(&etmdrvdata[cpu]->spinlock);
+ break;
+ }
+out:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block etm4_cpu_dying_notifier = {
+ .notifier_call = etm4_cpu_dying_callback,
+ .priority = 1,
+};
+
static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
@@ -2773,8 +2794,10 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
etmdrvdata[drvdata->cpu] = drvdata;
- if (!etm4_count++)
+ if (!etm4_count++) {
register_hotcpu_notifier(&etm4_cpu_notifier);
+ register_hotcpu_notifier(&etm4_cpu_dying_notifier);
+ }
put_online_cpus();
@@ -2793,8 +2816,10 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
err_late_init:
- if (--etm4_count == 0)
+ if (--etm4_count == 0) {
unregister_hotcpu_notifier(&etm4_cpu_notifier);
+ unregister_hotcpu_notifier(&etm4_cpu_dying_notifier);
+ }
return ret;
}
@@ -2803,8 +2828,10 @@ static int etm4_remove(struct amba_device *adev)
struct etmv4_drvdata *drvdata = amba_get_drvdata(adev);
coresight_unregister(drvdata->csdev);
- if (--etm4_count == 0)
+ if (--etm4_count == 0) {
unregister_hotcpu_notifier(&etm4_cpu_notifier);
+ unregister_hotcpu_notifier(&etm4_cpu_dying_notifier);
+ }
return 0;
}
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 45ce036b1693..eac9067822a3 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -27,6 +28,7 @@
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
+#include <linux/debugfs.h>
#include <linux/input/ft5x06_ts.h>
#if defined(CONFIG_FB)
@@ -39,22 +41,23 @@
#define FT_SUSPEND_LEVEL 1
#endif
-#define CFG_MAX_TOUCH_POINTS 5
+#define FT_DRIVER_VERSION 0x02
-#define FT_STARTUP_DLY 150
-#define FT_RESET_DLY 20
+#define FT_META_REGS 3
+#define FT_ONE_TCH_LEN 6
+#define FT_TCH_LEN(x) (FT_META_REGS + FT_ONE_TCH_LEN * x)
#define FT_PRESS 0x7F
#define FT_MAX_ID 0x0F
-#define FT_TOUCH_STEP 6
#define FT_TOUCH_X_H_POS 3
#define FT_TOUCH_X_L_POS 4
#define FT_TOUCH_Y_H_POS 5
#define FT_TOUCH_Y_L_POS 6
+#define FT_TD_STATUS 2
#define FT_TOUCH_EVENT_POS 3
#define FT_TOUCH_ID_POS 5
-
-#define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
+#define FT_TOUCH_DOWN 0
+#define FT_TOUCH_CONTACT 2
/* register address*/
#define FT_REG_DEV_MODE 0x00
@@ -66,6 +69,9 @@
#define FT_REG_THGROUP 0x80
#define FT_REG_ECC 0xCC
#define FT_REG_RESET_FW 0x07
+#define FT_REG_FW_MAJ_VER 0xB1
+#define FT_REG_FW_MIN_VER 0xB2
+#define FT_REG_FW_SUB_MIN_VER 0xB3
/* power register bits */
#define FT_PMODE_ACTIVE 0x00
@@ -74,12 +80,14 @@
#define FT_PMODE_HIBERNATE 0x03
#define FT_FACTORYMODE_VALUE 0x40
#define FT_WORKMODE_VALUE 0x00
-#define FT_RST_CMD_REG 0xFC
+#define FT_RST_CMD_REG1 0xFC
+#define FT_RST_CMD_REG2 0xBC
#define FT_READ_ID_REG 0x90
#define FT_ERASE_APP_REG 0x61
#define FT_ERASE_PANEL_REG 0x63
#define FT_FW_START_REG 0xBF
+#define FT_STATUS_NUM_TP_MASK 0x0F
#define FT_VTG_MIN_UV 2600000
#define FT_VTG_MAX_UV 3300000
@@ -95,54 +103,19 @@
#define FT5316_ID 0x0A
#define FT5306I_ID 0x55
+#define FT6X06_ID 0x06
#define FT_UPGRADE_AA 0xAA
#define FT_UPGRADE_55 0x55
-/* upgrade config of FT5606 */
-#define FT5606_UPGRADE_AA_DELAY 50
-#define FT5606_UPGRADE_55_DELAY 10
-#define FT5606_UPGRADE_ID_1 0x79
-#define FT5606_UPGRADE_ID_2 0x06
-#define FT5606_UPGRADE_READID_DELAY 100
-#define FT5606_UPGRADE_EARSE_DELAY 2000
-
-/* upgrade config of FT5316 */
-#define FT5316_UPGRADE_AA_DELAY 50
-#define FT5316_UPGRADE_55_DELAY 30
-#define FT5316_UPGRADE_ID_1 0x79
-#define FT5316_UPGRADE_ID_2 0x07
-#define FT5316_UPGRADE_READID_DELAY 1
-#define FT5316_UPGRADE_EARSE_DELAY 1500
-
-/* upgrade config of FT5x06(x=2,3,4) */
-#define FT5X06_UPGRADE_AA_DELAY 50
-#define FT5X06_UPGRADE_55_DELAY 30
-#define FT5X06_UPGRADE_ID_1 0x79
-#define FT5X06_UPGRADE_ID_2 0x03
-#define FT5X06_UPGRADE_READID_DELAY 1
-#define FT5X06_UPGRADE_EARSE_DELAY 2000
-
-/* upgrade config of FT6208 */
-#define FT6208_UPGRADE_AA_DELAY 60
-#define FT6208_UPGRADE_55_DELAY 10
-#define FT6208_UPGRADE_ID_1 0x79
-#define FT6208_UPGRADE_ID_2 0x05
-#define FT6208_UPGRADE_READID_DELAY 10
-#define FT6208_UPGRADE_EARSE_DELAY 2000
-
-#define FT_UPGRADE_INFO(x, y) do { \
- x->delay_55 = y##_UPGRADE_55_DELAY; \
- x->delay_aa = y##_UPGRADE_AA_DELAY; \
- x->upgrade_id_1 = y##_UPGRADE_ID_1; \
- x->upgrade_id_2 = y##_UPGRADE_ID_2; \
- x->delay_readid = y##_UPGRADE_READID_DELAY; \
- x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
- } while (0)
-
#define FT_FW_MIN_SIZE 8
#define FT_FW_MAX_SIZE 32768
-#define FT_FW_FILE_VER(x) ((x)->data[(x)->size - 2])
+
+/* Firmware file is not supporting minor and sub minor so use 0 */
+#define FT_FW_FILE_MAJ_VER(x) ((x)->data[(x)->size - 2])
+#define FT_FW_FILE_MIN_VER(x) 0
+#define FT_FW_FILE_SUB_MIN_VER(x) 0
+
#define FT_FW_CHECK(x) \
(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
&& (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
@@ -159,7 +132,7 @@
#define FT_FW_LAST_PKT 0x6ffa
#define FT_EARSE_DLY_MS 100
-#define FT_UPGRADE_LOOP 3
+#define FT_UPGRADE_LOOP 10
#define FT_CAL_START 0x04
#define FT_CAL_FIN 0x00
#define FT_CAL_STORE 0x05
@@ -167,35 +140,42 @@
#define FT_REG_CAL 0x00
#define FT_CAL_MASK 0x70
-struct ts_event {
- u16 x[CFG_MAX_TOUCH_POINTS]; /* x coordinate */
- u16 y[CFG_MAX_TOUCH_POINTS]; /* y coordinate */
- /* touch event: 0 -- down; 1-- contact; 2 -- contact */
- u8 touch_event[CFG_MAX_TOUCH_POINTS];
- u8 finger_id[CFG_MAX_TOUCH_POINTS]; /* touch ID */
- u16 pressure;
- u8 touch_point;
-};
-
-struct upgrade_info {
- u16 delay_aa; /* delay of write FT_UPGRADE_AA */
- u16 delay_55; /* delay of write FT_UPGRADE_55 */
- u8 upgrade_id_1; /* upgrade id 1 */
- u8 upgrade_id_2; /* upgrade id 2 */
- u16 delay_readid; /* delay of read id */
- u16 delay_earse_flash; /* delay of earse flash */
-};
+#define FT_INFO_MAX_LEN 512
+
+#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
+ fw_name, fw_maj, fw_min, fw_sub_min) \
+ snprintf(buf, FT_INFO_MAX_LEN, \
+ "controller\t= focaltech\n" \
+ "model\t\t= 0x%x\n" \
+ "name\t\t= %s\n" \
+ "max_touches\t= %d\n" \
+ "drv_ver\t\t= 0x%x\n" \
+ "group_id\t= 0x%x\n" \
+ "fw_vkey_support\t= %s\n" \
+ "fw_name\t\t= %s\n" \
+ "fw_ver\t\t= %d.%d.%d\n", id, name, \
+ max_tch, FT_DRIVER_VERSION, group_id, \
+ fw_vkey_support, fw_name, fw_maj, fw_min, \
+ fw_sub_min)
+
+#define FT_DEBUG_DIR_NAME "ts_debug"
struct ft5x06_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
- struct ts_event event;
const struct ft5x06_ts_platform_data *pdata;
struct regulator *vdd;
struct regulator *vcc_i2c;
char fw_name[FT_FW_NAME_MAX_LEN];
bool loading_fw;
u8 family_id;
+ struct dentry *dir;
+ u16 addr;
+ bool suspended;
+ char *ts_info;
+ u8 *tch_data;
+ u32 tch_data_len;
+ u8 fw_ver[3];
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
#elif defined(CONFIG_HAS_EARLYSUSPEND)
@@ -278,85 +258,91 @@ static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
return ft5x06_i2c_read(client, &addr, 1, val, 1);
}
-static void ft5x06_report_value(struct ft5x06_ts_data *data)
+static void ft5x06_update_fw_ver(struct ft5x06_ts_data *data)
{
- struct ts_event *event = &data->event;
- int i;
- int fingerdown = 0;
-
- for (i = 0; i < event->touch_point; i++) {
- if (event->touch_event[i] == 0 || event->touch_event[i] == 2) {
- event->pressure = FT_PRESS;
- fingerdown++;
- } else {
- event->pressure = 0;
- }
+ struct i2c_client *client = data->client;
+ u8 reg_addr;
+ int err;
- input_report_abs(data->input_dev, ABS_MT_POSITION_X,
- event->x[i]);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
- event->y[i]);
- input_report_abs(data->input_dev, ABS_MT_PRESSURE,
- event->pressure);
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
- event->finger_id[i]);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
- event->pressure);
- input_mt_sync(data->input_dev);
- }
+ reg_addr = FT_REG_FW_MAJ_VER;
+ err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[0], 1);
+ if (err < 0)
+ dev_err(&client->dev, "fw major version read failed");
- input_report_key(data->input_dev, BTN_TOUCH, !!fingerdown);
- input_sync(data->input_dev);
+ reg_addr = FT_REG_FW_MIN_VER;
+ err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[1], 1);
+ if (err < 0)
+ dev_err(&client->dev, "fw minor version read failed");
+
+ reg_addr = FT_REG_FW_SUB_MIN_VER;
+ err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[2], 1);
+ if (err < 0)
+ dev_err(&client->dev, "fw sub minor version read failed");
+
+ dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
+ data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]);
}
-static int ft5x06_handle_touchdata(struct ft5x06_ts_data *data)
+static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
{
- struct ts_event *event = &data->event;
- int ret, i;
- u8 buf[POINT_READ_BUF] = { 0 };
- u8 pointid = FT_MAX_ID;
-
- ret = ft5x06_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
- if (ret < 0) {
- dev_err(&data->client->dev, "%s read touchdata failed.\n",
- __func__);
- return ret;
- }
- memset(event, 0, sizeof(struct ts_event));
-
- event->touch_point = 0;
- for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
- pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
- if (pointid >= FT_MAX_ID)
- break;
+ struct ft5x06_ts_data *data = dev_id;
+ struct input_dev *ip_dev;
+ int rc, i;
+ u32 id, x, y, pressure, status, num_touches;
+ u8 reg = 0x00, *buf;
+ bool update_input = false;
+
+ if (!data) {
+ pr_err("%s: Invalid data\n", __func__);
+ return IRQ_HANDLED;
+ }
- event->touch_point++;
+ ip_dev = data->input_dev;
+ buf = data->tch_data;
- event->x[i] =
- (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
- 8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i];
- event->y[i] =
- (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
- 8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i];
- event->touch_event[i] =
- buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6;
- event->finger_id[i] =
- (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
+ rc = ft5x06_i2c_read(data->client, &reg, 1,
+ buf, data->tch_data_len);
+ if (rc < 0) {
+ dev_err(&data->client->dev, "%s: read data fail\n", __func__);
+ return IRQ_HANDLED;
}
- ft5x06_report_value(data);
+ for (i = 0; i < data->pdata->num_max_touches; i++) {
+ id = (buf[FT_TOUCH_ID_POS + FT_ONE_TCH_LEN * i]) >> 4;
+ if (id >= FT_MAX_ID)
+ break;
- return 0;
-}
+ update_input = true;
-static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
-{
- struct ft5x06_ts_data *data = dev_id;
- int rc;
+ x = (buf[FT_TOUCH_X_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+ (buf[FT_TOUCH_X_L_POS + FT_ONE_TCH_LEN * i]);
+ y = (buf[FT_TOUCH_Y_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+ (buf[FT_TOUCH_Y_L_POS + FT_ONE_TCH_LEN * i]);
- rc = ft5x06_handle_touchdata(data);
- if (rc)
- pr_err("%s: handling touchdata failed\n", __func__);
+ status = buf[FT_TOUCH_EVENT_POS + FT_ONE_TCH_LEN * i] >> 6;
+
+ num_touches = buf[FT_TD_STATUS] & FT_STATUS_NUM_TP_MASK;
+
+ /* invalid combination */
+ if (!num_touches && !status && !id)
+ break;
+
+ input_mt_slot(ip_dev, id);
+ if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) {
+ pressure = FT_PRESS;
+ input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1);
+ input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
+ } else {
+ input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
+ }
+ }
+
+ if (update_input) {
+ input_mt_report_pointer_emulation(ip_dev, false);
+ input_sync(ip_dev);
+ }
return IRQ_HANDLED;
}
@@ -473,30 +459,99 @@ pwr_deinit:
static int ft5x06_ts_suspend(struct device *dev)
{
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
- char txbuf[2];
+ char txbuf[2], i;
+ int err;
+
+ if (data->loading_fw) {
+ dev_info(dev, "Firmware loading in process...\n");
+ return 0;
+ }
+
+ if (data->suspended) {
+ dev_info(dev, "Already in suspend state\n");
+ return 0;
+ }
disable_irq(data->client->irq);
+ /* release all touches */
+ for (i = 0; i < data->pdata->num_max_touches; i++) {
+ input_mt_slot(data->input_dev, i);
+ input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
+ }
+ input_report_key(data->input_dev, BTN_TOUCH, 0);
+ input_sync(data->input_dev);
+
if (gpio_is_valid(data->pdata->reset_gpio)) {
txbuf[0] = FT_REG_PMODE;
txbuf[1] = FT_PMODE_HIBERNATE;
ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
}
+ if (data->pdata->power_on) {
+ err = data->pdata->power_on(false);
+ if (err) {
+ dev_err(dev, "power off failed");
+ goto pwr_off_fail;
+ }
+ } else {
+ err = ft5x06_power_on(data, false);
+ if (err) {
+ dev_err(dev, "power off failed");
+ goto pwr_off_fail;
+ }
+ }
+
+ data->suspended = true;
+
return 0;
+
+pwr_off_fail:
+ if (gpio_is_valid(data->pdata->reset_gpio)) {
+ gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
+ msleep(data->pdata->hard_rst_dly);
+ gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
+ }
+ enable_irq(data->client->irq);
+ return err;
}
static int ft5x06_ts_resume(struct device *dev)
{
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ int err;
+
+ if (!data->suspended) {
+ dev_dbg(dev, "Already in awake state\n");
+ return 0;
+ }
+
+ if (data->pdata->power_on) {
+ err = data->pdata->power_on(true);
+ if (err) {
+ dev_err(dev, "power on failed");
+ return err;
+ }
+ } else {
+ err = ft5x06_power_on(data, true);
+ if (err) {
+ dev_err(dev, "power on failed");
+ return err;
+ }
+ }
if (gpio_is_valid(data->pdata->reset_gpio)) {
gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
- msleep(FT_RESET_DLY);
+ msleep(data->pdata->hard_rst_dly);
gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
}
+
+ msleep(data->pdata->soft_rst_dly);
+
enable_irq(data->client->irq);
+ data->suspended = false;
+
return 0;
}
@@ -550,16 +605,17 @@ static const struct dev_pm_ops ft5x06_ts_pm_ops = {
static int ft5x06_auto_cal(struct i2c_client *client)
{
+ struct ft5x06_ts_data *data = i2c_get_clientdata(client);
u8 temp = 0, i;
/* set to factory mode */
- msleep(2 * FT_STARTUP_DLY);
+ msleep(2 * data->pdata->soft_rst_dly);
ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
- msleep(FT_STARTUP_DLY);
+ msleep(data->pdata->soft_rst_dly);
/* start calibration */
ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
- msleep(2 * FT_STARTUP_DLY);
+ msleep(2 * data->pdata->soft_rst_dly);
for (i = 0; i < FT_CAL_RETRY; i++) {
ft5x0x_read_reg(client, FT_REG_CAL, &temp);
/* return to normal mode, calibration finish */
@@ -567,34 +623,18 @@ static int ft5x06_auto_cal(struct i2c_client *client)
break;
}
- /* calibration OK */
- msleep(2 * FT_STARTUP_DLY);
+ /*calibration OK */
+ msleep(2 * data->pdata->soft_rst_dly);
ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
- msleep(FT_STARTUP_DLY);
+ msleep(data->pdata->soft_rst_dly);
/* store calibration data */
ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
- msleep(2 * FT_STARTUP_DLY);
+ msleep(2 * data->pdata->soft_rst_dly);
/* set to normal mode */
ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
- msleep(2 * FT_STARTUP_DLY);
-
- return 0;
-}
-
-static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
-{
- switch (family_id) {
- case FT5306I_ID:
- FT_UPGRADE_INFO(info, FT5X06);
- break;
- case FT5316_ID:
- FT_UPGRADE_INFO(info, FT5316);
- break;
- default:
- return -EINVAL;
- }
+ msleep(2 * data->pdata->soft_rst_dly);
return 0;
}
@@ -603,35 +643,35 @@ static int ft5x06_fw_upgrade_start(struct i2c_client *client,
const u8 *data, u32 data_len)
{
struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
- struct upgrade_info info;
+ struct fw_upgrade_info info = ts_data->pdata->info;
+ u8 reset_reg;
u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
int rc, i, j, temp;
u32 pkt_num, pkt_len;
u8 fw_ecc;
- rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
- if (rc < 0) {
- dev_err(&client->dev, "Cannot get upgrade information!\n");
- return -EINVAL;
- }
+ for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+ /* reset - write 0xaa and 0x55 to reset register */
+ if (ts_data->family_id == FT6X06_ID)
+ reset_reg = FT_RST_CMD_REG2;
+ else
+ reset_reg = FT_RST_CMD_REG1;
- for (i = 0; i < FT_UPGRADE_LOOP; i++) {
- /* reset - write 0xaa and 0x55 to register 0xfc */
- ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
+ ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_AA);
msleep(info.delay_aa);
- ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
+ ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
msleep(info.delay_55);
/* Enter upgrade mode */
w_buf[0] = FT_UPGRADE_55;
w_buf[1] = FT_UPGRADE_AA;
do {
- i++;
+ j++;
rc = ft5x06_i2c_write(client, w_buf, 2);
msleep(FT_RETRY_DLY);
- } while (rc <= 0 && i < FT_MAX_TRIES);
+ } while (rc <= 0 && j < FT_MAX_TRIES);
/* check READ_ID */
msleep(info.delay_readid);
@@ -657,7 +697,7 @@ static int ft5x06_fw_upgrade_start(struct i2c_client *client,
/* erase app and panel paramenter area */
w_buf[0] = FT_ERASE_APP_REG;
ft5x06_i2c_write(client, w_buf, 1);
- msleep(info.delay_earse_flash);
+ msleep(info.delay_erase_flash);
w_buf[0] = FT_ERASE_PANEL_REG;
ft5x06_i2c_write(client, w_buf, 1);
@@ -732,7 +772,9 @@ static int ft5x06_fw_upgrade_start(struct i2c_client *client,
/* reset */
w_buf[0] = FT_REG_RESET_FW;
ft5x06_i2c_write(client, w_buf, 1);
- msleep(FT_STARTUP_DLY);
+ msleep(ts_data->pdata->soft_rst_dly);
+
+ dev_info(&client->dev, "Firmware upgrade successful\n");
return 0;
}
@@ -742,7 +784,8 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force)
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
const struct firmware *fw = NULL;
int rc;
- u8 val = 0;
+ u8 fw_file_maj, fw_file_min, fw_file_sub_min;
+ bool fw_upgrade = false;
rc = request_firmware(&fw, data->fw_name, dev);
if (rc < 0) {
@@ -757,34 +800,52 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force)
goto rel_fw;
}
- /* check firmware version */
- rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
- if (rc < 0) {
- dev_err(dev, "Get firmware version failed\n");
- goto rel_fw;
- }
+ fw_file_maj = FT_FW_FILE_MAJ_VER(fw);
+ fw_file_min = FT_FW_FILE_MIN_VER(fw);
+ fw_file_sub_min = FT_FW_FILE_SUB_MIN_VER(fw);
+
+ dev_info(dev, "Current firmware: %d.%d.%d", data->fw_ver[0],
+ data->fw_ver[1], data->fw_ver[2]);
+ dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
+ fw_file_min, fw_file_sub_min);
+
+ if (force) {
+ fw_upgrade = true;
+ } else if (data->fw_ver[0] == fw_file_maj) {
+ if (data->fw_ver[1] < fw_file_min)
+ fw_upgrade = true;
+ else if (data->fw_ver[2] < fw_file_sub_min)
+ fw_upgrade = true;
+ else
+ dev_info(dev, "No need to upgrade\n");
+ } else
+ dev_info(dev, "Firmware versions do not match\n");
- if (val == FT_FW_FILE_VER(fw) && !force) {
- dev_err(dev, "No need to update (0x%x)\n", val);
+ if (!fw_upgrade) {
+ dev_info(dev, "Exiting fw upgrade...\n");
rc = -EFAULT;
goto rel_fw;
}
- dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
- FT_FW_FILE_VER(fw), val);
-
/* start firmware upgrade */
if (FT_FW_CHECK(fw)) {
rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
if (rc < 0)
- dev_err(dev, "update failed (%d)\n", rc);
- else
+ dev_err(dev, "update failed (%d). try later...\n", rc);
+ else if (data->pdata->info.auto_cal)
ft5x06_auto_cal(data->client);
} else {
dev_err(dev, "FW format error\n");
rc = -EIO;
}
+ ft5x06_update_fw_ver(data);
+
+ FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+ data->pdata->num_max_touches, data->pdata->group_id,
+ data->pdata->fw_vkey_support ? "yes" : "no",
+ data->pdata->fw_name, data->fw_ver[0],
+ data->fw_ver[1], data->fw_ver[2]);
rel_fw:
release_firmware(fw);
return rc;
@@ -813,6 +874,11 @@ static ssize_t ft5x06_update_fw_store(struct device *dev,
if (rc != 0)
return rc;
+ if (data->suspended) {
+ dev_info(dev, "In suspend state, try again later...\n");
+ return size;
+ }
+
mutex_lock(&data->input_dev->mutex);
if (!data->loading_fw && val) {
data->loading_fw = true;
@@ -882,6 +948,138 @@ static ssize_t ft5x06_fw_name_store(struct device *dev,
static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store);
+static bool ft5x06_debug_addr_is_valid(int addr)
+{
+ if (addr < 0 || addr > 0xFF) {
+ pr_err("FT reg address is invalid: 0x%x\n", addr);
+ return false;
+ }
+
+ return true;
+}
+
+static int ft5x06_debug_data_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr))
+ dev_info(&data->client->dev,
+ "Writing into FT registers not supported\n");
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+static int ft5x06_debug_data_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+ int rc;
+ u8 reg;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr)) {
+ rc = ft5x0x_read_reg(data->client, data->addr, &reg);
+ if (rc < 0)
+ dev_err(&data->client->dev,
+ "FT read register 0x%x failed (%d)\n",
+ data->addr, rc);
+ else
+ *val = reg;
+ }
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, ft5x06_debug_data_get,
+ ft5x06_debug_data_set, "0x%02llX\n");
+
+static int ft5x06_debug_addr_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ if (ft5x06_debug_addr_is_valid(val)) {
+ mutex_lock(&data->input_dev->mutex);
+ data->addr = val;
+ mutex_unlock(&data->input_dev->mutex);
+ }
+
+ return 0;
+}
+
+static int ft5x06_debug_addr_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr))
+ *val = data->addr;
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, ft5x06_debug_addr_get,
+ ft5x06_debug_addr_set, "0x%02llX\n");
+
+static int ft5x06_debug_suspend_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (val)
+ ft5x06_ts_suspend(&data->client->dev);
+ else
+ ft5x06_ts_resume(&data->client->dev);
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+static int ft5x06_debug_suspend_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+ *val = data->suspended;
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, ft5x06_debug_suspend_get,
+ ft5x06_debug_suspend_set, "%lld\n");
+
+static int ft5x06_debug_dump_info(struct seq_file *m, void *v)
+{
+ struct ft5x06_ts_data *data = m->private;
+
+ seq_printf(m, "%s\n", data->ts_info);
+
+ return 0;
+}
+
+static int debugfs_dump_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ft5x06_debug_dump_info, inode->i_private);
+}
+
+static const struct file_operations debug_dump_info_fops = {
+ .owner = THIS_MODULE,
+ .open = debugfs_dump_info_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
#ifdef CONFIG_OF
static int ft5x06_get_dt_coords(struct device *dev, char *name,
struct ft5x06_ts_platform_data *pdata)
@@ -936,6 +1134,13 @@ static int ft5x06_parse_dt(struct device *dev,
u32 temp_val, num_buttons;
u32 button_map[MAX_BUTTONS];
+ pdata->name = "focaltech";
+ rc = of_property_read_string(np, "focaltech,name", &pdata->name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read name\n");
+ return rc;
+ }
+
rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata);
if (rc && (rc != -EINVAL))
return rc;
@@ -960,6 +1165,89 @@ static int ft5x06_parse_dt(struct device *dev,
if (pdata->irq_gpio < 0)
return pdata->irq_gpio;
+ pdata->fw_name = "ft_fw.bin";
+ rc = of_property_read_string(np, "focaltech,fw-name", &pdata->fw_name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw name\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "focaltech,group-id", &temp_val);
+ if (!rc)
+ pdata->group_id = temp_val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(np, "focaltech,hard-reset-delay-ms",
+ &temp_val);
+ if (!rc)
+ pdata->hard_rst_dly = temp_val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(np, "focaltech,soft-reset-delay-ms",
+ &temp_val);
+ if (!rc)
+ pdata->soft_rst_dly = temp_val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(np, "focaltech,num-max-touches", &temp_val);
+ if (!rc)
+ pdata->num_max_touches = temp_val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(np, "focaltech,fw-delay-aa-ms", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw delay aa\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.delay_aa = temp_val;
+
+ rc = of_property_read_u32(np, "focaltech,fw-delay-55-ms", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw delay 55\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.delay_55 = temp_val;
+
+ rc = of_property_read_u32(np, "focaltech,fw-upgrade-id1", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw upgrade id1\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.upgrade_id_1 = temp_val;
+
+ rc = of_property_read_u32(np, "focaltech,fw-upgrade-id2", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw upgrade id2\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.upgrade_id_2 = temp_val;
+
+ rc = of_property_read_u32(np, "focaltech,fw-delay-readid-ms",
+ &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw delay read id\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.delay_readid = temp_val;
+
+ rc = of_property_read_u32(np, "focaltech,fw-delay-era-flsh-ms",
+ &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw delay erase flash\n");
+ return rc;
+ } else if (rc != -EINVAL)
+ pdata->info.delay_erase_flash = temp_val;
+
+ pdata->info.auto_cal = of_property_read_bool(np,
+ "focaltech,fw-auto-cal");
+
+ pdata->fw_vkey_support = of_property_read_bool(np,
+ "focaltech,fw-vkey-support");
+
rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
if (!rc)
pdata->family_id = temp_val;
@@ -997,9 +1285,10 @@ static int ft5x06_ts_probe(struct i2c_client *client,
struct ft5x06_ts_platform_data *pdata;
struct ft5x06_ts_data *data;
struct input_dev *input_dev;
+ struct dentry *temp;
u8 reg_value;
u8 reg_addr;
- int err;
+ int err, len;
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
@@ -1008,8 +1297,10 @@ static int ft5x06_ts_probe(struct i2c_client *client,
return -ENOMEM;
err = ft5x06_parse_dt(&client->dev, pdata);
- if (err)
+ if (err) {
+ dev_err(&client->dev, "DT parsing failed\n");
return err;
+ }
} else
pdata = client->dev.platform_data;
@@ -1023,15 +1314,31 @@ static int ft5x06_ts_probe(struct i2c_client *client,
return -ENODEV;
}
- data = kzalloc(sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+ data = devm_kzalloc(&client->dev,
+ sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (pdata->fw_name) {
+ len = strlen(pdata->fw_name);
+ if (len > FT_FW_NAME_MAX_LEN - 1) {
+ dev_err(&client->dev, "Invalid firmware name\n");
+ return -EINVAL;
+ }
+
+ strlcpy(data->fw_name, pdata->fw_name, len + 1);
+ }
+
+ data->tch_data_len = FT_TCH_LEN(pdata->num_max_touches);
+ data->tch_data = devm_kzalloc(&client->dev,
+ data->tch_data_len, GFP_KERNEL);
if (!data)
return -ENOMEM;
input_dev = input_allocate_device();
if (!input_dev) {
- err = -ENOMEM;
dev_err(&client->dev, "failed to allocate input device\n");
- goto free_mem;
+ return -ENOMEM;
}
data->input_dev = input_dev;
@@ -1050,13 +1357,11 @@ static int ft5x06_ts_probe(struct i2c_client *client,
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ input_mt_init_slots(input_dev, pdata->num_max_touches);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
pdata->y_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
- CFG_MAX_TOUCH_POINTS, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
err = input_register_device(input_dev);
@@ -1120,19 +1425,19 @@ static int ft5x06_ts_probe(struct i2c_client *client,
"set_direction for reset gpio failed\n");
goto free_reset_gpio;
}
- msleep(FT_RESET_DLY);
+ msleep(data->pdata->hard_rst_dly);
gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
}
/* make sure CTP already finish startup process */
- msleep(FT_STARTUP_DLY);
+ msleep(data->pdata->soft_rst_dly);
/* check the controller id */
reg_addr = FT_REG_ID;
err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
if (err < 0) {
dev_err(&client->dev, "version read failed");
- return err;
+ goto free_reset_gpio;
}
dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
@@ -1144,28 +1449,6 @@ static int ft5x06_ts_probe(struct i2c_client *client,
data->family_id = reg_value;
- /* get some register information */
- reg_addr = FT_REG_FW_VER;
- err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
- if (err < 0)
- dev_err(&client->dev, "version read failed");
-
- dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
-
- reg_addr = FT_REG_POINT_RATE;
- ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
- if (err < 0)
- dev_err(&client->dev, "report rate read failed");
-
- dev_dbg(&client->dev, "report rate = %dHz\n", reg_value * 10);
-
- reg_addr = FT_REG_THGROUP;
- err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
- if (err < 0)
- dev_err(&client->dev, "threshold read failed");
-
- dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
-
err = request_threaded_irq(client->irq, NULL,
ft5x06_ts_interrupt, pdata->irqflags,
client->dev.driver->name, data);
@@ -1192,6 +1475,72 @@ static int ft5x06_ts_probe(struct i2c_client *client,
goto free_update_fw_sys;
}
+ data->dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
+ if (data->dir == NULL || IS_ERR(data->dir)) {
+ pr_err("debugfs_create_dir failed(%ld)\n", PTR_ERR(data->dir));
+ err = PTR_ERR(data->dir);
+ goto free_force_update_fw_sys;
+ }
+
+ temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, data->dir, data,
+ &debug_addr_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, data->dir, data,
+ &debug_data_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, data->dir,
+ data, &debug_suspend_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR, data->dir,
+ data, &debug_dump_info_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ data->ts_info = devm_kzalloc(&client->dev,
+ FT_INFO_MAX_LEN, GFP_KERNEL);
+ if (!data->ts_info)
+ goto free_debug_dir;
+
+ /*get some register information */
+ reg_addr = FT_REG_POINT_RATE;
+ ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+ if (err < 0)
+ dev_err(&client->dev, "report rate read failed");
+
+ dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
+
+ reg_addr = FT_REG_THGROUP;
+ err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+ if (err < 0)
+ dev_err(&client->dev, "threshold read failed");
+
+ dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
+
+ ft5x06_update_fw_ver(data);
+
+ FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+ data->pdata->num_max_touches, data->pdata->group_id,
+ data->pdata->fw_vkey_support ? "yes" : "no",
+ data->pdata->fw_name, data->fw_ver[0],
+ data->fw_ver[1], data->fw_ver[2]);
#if defined(CONFIG_FB)
data->fb_notif.notifier_call = fb_notifier_callback;
@@ -1211,6 +1560,10 @@ static int ft5x06_ts_probe(struct i2c_client *client,
return 0;
+free_debug_dir:
+ debugfs_remove_recursive(data->dir);
+free_force_update_fw_sys:
+ device_remove_file(&client->dev, &dev_attr_force_update_fw);
free_update_fw_sys:
device_remove_file(&client->dev, &dev_attr_update_fw);
free_fw_name_sys:
@@ -1238,8 +1591,6 @@ unreg_inputdev:
input_dev = NULL;
free_inputdev:
input_free_device(input_dev);
-free_mem:
- kfree(data);
return err;
}
@@ -1247,6 +1598,7 @@ static int ft5x06_ts_remove(struct i2c_client *client)
{
struct ft5x06_ts_data *data = i2c_get_clientdata(client);
+ debugfs_remove_recursive(data->dir);
device_remove_file(&client->dev, &dev_attr_force_update_fw);
device_remove_file(&client->dev, &dev_attr_update_fw);
device_remove_file(&client->dev, &dev_attr_fw_name);
@@ -1276,7 +1628,6 @@ static int ft5x06_ts_remove(struct i2c_client *client)
ft5x06_power_init(data, false);
input_unregister_device(data->input_dev);
- kfree(data);
return 0;
}
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index 3dfe4e1d334e..bef080671ab0 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -1,615 +1,551 @@
-/* drivers/input/touchscreen/goodix_tool.c
- *
- * 2010 - 2012 Goodix Technology.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * Version:1.6
- * V1.0:2012/05/01,create file.
- * V1.2:2012/06/08,modify some warning.
- * V1.4:2012/08/28,modified to support GT9XX
- * V1.6:new proc name
- */
-
-#include "gt9xx.h"
-
-#define DATA_LENGTH_UINT 512
-#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*))
-static char procname[20] = {0};
-
-#define UPDATE_FUNCTIONS
-
-#ifdef UPDATE_FUNCTIONS
-extern s32 gup_enter_update_mode(struct i2c_client *client);
-extern void gup_leave_update_mode(void);
-extern s32 gup_update_proc(void *dir);
-#endif
-
-extern void gtp_irq_disable(struct goodix_ts_data *);
-extern void gtp_irq_enable(struct goodix_ts_data *);
-
-#pragma pack(1)
-typedef struct{
- u8 wr; //write read flag£¬0:R 1:W 2:PID 3:
- u8 flag; //0:no need flag/int 1: need flag 2:need int
- u8 flag_addr[2]; //flag address
- u8 flag_val; //flag val
- u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:<
- u16 circle; //polling cycle
- u8 times; //plling times
- u8 retry; //I2C retry times
- u16 delay; //delay befor read or after write
- u16 data_len; //data length
- u8 addr_len; //address length
- u8 addr[2]; //address
- u8 res[3]; //reserved
- u8* data; //data pointer
-}st_cmd_head;
-#pragma pack()
-st_cmd_head cmd_head;
-
-static struct i2c_client *gt_client = NULL;
-
-static struct proc_dir_entry *goodix_proc_entry;
-
-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);
-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );
-static s32 (*tool_i2c_read)(u8 *, u16);
-static s32 (*tool_i2c_write)(u8 *, u16);
-
-#if GTP_ESD_PROTECT
-extern void gtp_esd_switch(struct i2c_client *, s32);
-#endif
-s32 DATA_LENGTH = 0;
-s8 IC_TYPE[16] = {0};
-
-static void tool_set_proc_name(char * procname)
-{
- char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
- "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- char date[20] = {0};
- char month[4] = {0};
- int i = 0, n_month = 1, n_day = 0, n_year = 0;
-
- sprintf(date, "%s", __DATE__);
-
- //GTP_DEBUG("compile date: %s", date);
-
- sscanf(date, "%s %d %d", month, &n_day, &n_year);
-
- for (i = 0; i < 12; ++i)
- {
- if (!memcmp(months[i], month, 3))
- {
- n_month = i+1;
- break;
- }
- }
-
- sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);
-
- //GTP_DEBUG("procname = %s", procname);
-}
-
-
-static s32 tool_i2c_read_no_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- s32 i = 0;
- struct i2c_msg msgs[2];
-
- msgs[0].flags = !I2C_M_RD;
- msgs[0].addr = gt_client->addr;
- msgs[0].len = cmd_head.addr_len;
- msgs[0].buf = &buf[0];
-
- msgs[1].flags = I2C_M_RD;
- msgs[1].addr = gt_client->addr;
- msgs[1].len = len;
- msgs[1].buf = &buf[GTP_ADDR_LENGTH];
-
- for (i = 0; i < cmd_head.retry; i++)
- {
- ret=i2c_transfer(gt_client->adapter, msgs, 2);
- if (ret > 0)
- {
- break;
- }
- }
- return ret;
-}
-
-static s32 tool_i2c_write_no_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- s32 i = 0;
- struct i2c_msg msg;
-
- msg.flags = !I2C_M_RD;
- msg.addr = gt_client->addr;
- msg.len = len;
- msg.buf = buf;
-
- for (i = 0; i < cmd_head.retry; i++)
- {
- ret=i2c_transfer(gt_client->adapter, &msg, 1);
- if (ret > 0)
- {
- break;
- }
- }
- return ret;
-}
-
-static s32 tool_i2c_read_with_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- u8 pre[2] = {0x0f, 0xff};
- u8 end[2] = {0x80, 0x00};
-
- tool_i2c_write_no_extra(pre, 2);
- ret = tool_i2c_read_no_extra(buf, len);
- tool_i2c_write_no_extra(end, 2);
-
- return ret;
-}
-
-static s32 tool_i2c_write_with_extra(u8* buf, u16 len)
-{
- s32 ret = -1;
- u8 pre[2] = {0x0f, 0xff};
- u8 end[2] = {0x80, 0x00};
-
- tool_i2c_write_no_extra(pre, 2);
- ret = tool_i2c_write_no_extra(buf, len);
- tool_i2c_write_no_extra(end, 2);
-
- return ret;
-}
-
-static void register_i2c_func(void)
-{
-// if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
-// || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
-// || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
-// || !strncmp(IC_TYPE, "GT813", 5))
- if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
- && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
- && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
- && strncmp(IC_TYPE, "GTxxx", 5))
- {
- tool_i2c_read = tool_i2c_read_with_extra;
- tool_i2c_write = tool_i2c_write_with_extra;
- GTP_DEBUG("I2C function: with pre and end cmd!");
- }
- else
- {
- tool_i2c_read = tool_i2c_read_no_extra;
- tool_i2c_write = tool_i2c_write_no_extra;
- GTP_INFO("I2C function: without pre and end cmd!");
- }
-}
-
-static void unregister_i2c_func(void)
-{
- tool_i2c_read = NULL;
- tool_i2c_write = NULL;
- GTP_INFO("I2C function: unregister i2c transfer function!");
-}
-
-
-s32 init_wr_node(struct i2c_client *client)
-{
- s32 i;
-
- gt_client = client;
- memset(&cmd_head, 0, sizeof(cmd_head));
- cmd_head.data = NULL;
-
- i = 5;
- while ((!cmd_head.data) && i)
- {
- cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
- if (NULL != cmd_head.data)
- {
- break;
- }
- i--;
- }
- if (i)
- {
- DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
- GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
- }
- else
- {
- GTP_ERROR("Apply for memory failed.");
- return FAIL;
- }
-
- cmd_head.addr_len = 2;
- cmd_head.retry = 5;
-
- register_i2c_func();
-
- tool_set_proc_name(procname);
- goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
- if (goodix_proc_entry == NULL)
- {
- GTP_ERROR("Couldn't create proc entry!");
- return FAIL;
- }
- else
- {
- GTP_INFO("Create proc entry success!");
- goodix_proc_entry->write_proc = goodix_tool_write;
- goodix_proc_entry->read_proc = goodix_tool_read;
- }
-
- return SUCCESS;
-}
-
-void uninit_wr_node(void)
-{
- kfree(cmd_head.data);
- cmd_head.data = NULL;
- unregister_i2c_func();
- remove_proc_entry(procname, NULL);
-}
-
-static u8 relation(u8 src, u8 dst, u8 rlt)
-{
- u8 ret = 0;
-
- switch (rlt)
- {
- case 0:
- ret = (src != dst) ? true : false;
- break;
-
- case 1:
- ret = (src == dst) ? true : false;
- GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32)ret);
- break;
-
- case 2:
- ret = (src > dst) ? true : false;
- break;
-
- case 3:
- ret = (src < dst) ? true : false;
- break;
-
- case 4:
- ret = (src & dst) ? true : false;
- break;
-
- case 5:
- ret = (!(src | dst)) ? true : false;
- break;
-
- default:
- ret = false;
- break;
- }
-
- return ret;
-}
-
-/*******************************************************
-Function:
- Comfirm function.
-Input:
- None.
-Output:
- Return write length.
-********************************************************/
-static u8 comfirm(void)
-{
- s32 i = 0;
- u8 buf[32];
-
-// memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);
-// memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17
- memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
-
- for (i = 0; i < cmd_head.times; i++)
- {
- if (tool_i2c_read(buf, 1) <= 0)
- {
- GTP_ERROR("Read flag data failed!");
- return FAIL;
- }
- if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))
- {
- GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);
- GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
- break;
- }
-
- msleep(cmd_head.circle);
- }
-
- if (i >= cmd_head.times)
- {
- GTP_ERROR("Didn't get the flag to continue!");
- return FAIL;
- }
-
- return SUCCESS;
-}
-
-/*******************************************************
-Function:
- Goodix tool write function.
-Input:
- standard proc write function param.
-Output:
- Return write length.
-********************************************************/
-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
-{
- s32 ret = 0;
- GTP_DEBUG_FUNC();
- GTP_DEBUG_ARRAY((u8*)buff, len);
-
- ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
-
- GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
- GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
- GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
- GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
- GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
- GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
- GTP_DEBUG("times :%d.", (s32)cmd_head.times);
- GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
- GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
- GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
- GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
- GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
- GTP_DEBUG("len:%d.", (s32)len);
- GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
-
- if (1 == cmd_head.wr)
- {
- // copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
- memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);
-
- GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);
- GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-
- if (1 == cmd_head.flag)
- {
- if (FAIL == comfirm())
- {
- GTP_ERROR("[WRITE]Comfirm fail!");
- return FAIL;
- }
- }
- else if (2 == cmd_head.flag)
- {
- //Need interrupt!
- }
- if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
- cmd_head.data_len + cmd_head.addr_len) <= 0)
- {
- GTP_ERROR("[WRITE]Write data failed!");
- return FAIL;
- }
-
- GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);
- if (cmd_head.delay)
- {
- msleep(cmd_head.delay);
- }
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (3 == cmd_head.wr) //Write ic type
- {
- ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_ERROR("copy_from_user failed.");
- }
- memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
-
- register_i2c_func();
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (5 == cmd_head.wr)
- {
- //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
-
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- }
- else if (7 == cmd_head.wr)//disable irq!
- {
- gtp_irq_disable(i2c_get_clientdata(gt_client));
-
- #if GTP_ESD_PROTECT
- gtp_esd_switch(gt_client, SWITCH_OFF);
- #endif
- return CMD_HEAD_LENGTH;
- }
- else if (9 == cmd_head.wr) //enable irq!
- {
- gtp_irq_enable(i2c_get_clientdata(gt_client));
-
- #if GTP_ESD_PROTECT
- gtp_esd_switch(gt_client, SWITCH_ON);
- #endif
- return CMD_HEAD_LENGTH;
- }
- else if(17 == cmd_head.wr)
- {
- struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
- ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
- if(ret)
- {
- GTP_DEBUG("copy_from_user failed.");
- }
- if(cmd_head.data[GTP_ADDR_LENGTH])
- {
- GTP_DEBUG("gtp enter rawdiff.");
- ts->gtp_rawdiff_mode = true;
- }
- else
- {
- ts->gtp_rawdiff_mode = false;
- GTP_DEBUG("gtp leave rawdiff.");
- }
- return CMD_HEAD_LENGTH;
- }
-#ifdef UPDATE_FUNCTIONS
- else if (11 == cmd_head.wr)//Enter update mode!
- {
- if (FAIL == gup_enter_update_mode(gt_client))
- {
- return FAIL;
- }
- }
- else if (13 == cmd_head.wr)//Leave update mode!
- {
- gup_leave_update_mode();
- }
- else if (15 == cmd_head.wr) //Update firmware!
- {
- show_len = 0;
- total_len = 0;
- memset(cmd_head.data, 0, cmd_head.data_len + 1);
- memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-
- if (FAIL == gup_update_proc((void*)cmd_head.data))
- {
- return FAIL;
- }
- }
-#endif
-
- return CMD_HEAD_LENGTH;
-}
-
-/*******************************************************
-Function:
- Goodix tool read function.
-Input:
- standard proc read function param.
-Output:
- Return read length.
-********************************************************/
-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
-{
- GTP_DEBUG_FUNC();
-
- if (cmd_head.wr % 2)
- {
- return FAIL;
- }
- else if (!cmd_head.wr)
- {
- u16 len = 0;
- s16 data_len = 0;
- u16 loc = 0;
-
- if (1 == cmd_head.flag)
- {
- if (FAIL == comfirm())
- {
- GTP_ERROR("[READ]Comfirm fail!");
- return FAIL;
- }
- }
- else if (2 == cmd_head.flag)
- {
- //Need interrupt!
- }
-
- memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
-
- GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);
- GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
-
- if (cmd_head.delay)
- {
- msleep(cmd_head.delay);
- }
-
- data_len = cmd_head.data_len;
- while(data_len > 0)
- {
- if (data_len > DATA_LENGTH)
- {
- len = DATA_LENGTH;
- }
- else
- {
- len = data_len;
- }
- data_len -= DATA_LENGTH;
-
- if (tool_i2c_read(cmd_head.data, len) <= 0)
- {
- GTP_ERROR("[READ]Read data failed!");
- return FAIL;
- }
- memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);
- loc += len;
-
- GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
- GTP_DEBUG_ARRAY(page, len);
- }
- }
- else if (2 == cmd_head.wr)
- {
- // memcpy(page, "gt8", cmd_head.data_len);
- // memcpy(page, "GT818", 5);
- // page[5] = 0;
-
- GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);
- return cmd_head.data_len;
- //return sizeof(IC_TYPE_NAME);
- }
- else if (4 == cmd_head.wr)
- {
- page[0] = show_len >> 8;
- page[1] = show_len & 0xff;
- page[2] = total_len >> 8;
- page[3] = total_len & 0xff;
-
- return cmd_head.data_len;
- }
- else if (6 == cmd_head.wr)
- {
- //Read error code!
- }
- else if (8 == cmd_head.wr) //Read driver version
- {
- // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));
- s32 tmp_len;
- tmp_len = strlen(GTP_DRIVER_VERSION);
- memcpy(page, GTP_DRIVER_VERSION, tmp_len);
- page[tmp_len] = 0;
- }
-
- return cmd_head.data_len;
-}
+/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Version:1.6
+ * V1.0:2012/05/01,create file.
+ * V1.2:2012/06/08,modify some warning.
+ * V1.4:2012/08/28,modified to support GT9XX
+ * V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT 512
+#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#pragma pack(1)
+struct {
+ u8 wr; /* write read flag£¬0:R 1:W 2:PID 3: */
+ u8 flag; /* 0:no need flag/int 1: need flag 2:need int */
+ u8 flag_addr[2];/* flag address */
+ u8 flag_val; /* flag val */
+ u8 flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */
+ u16 circle; /* polling cycle */
+ u8 times; /* plling times */
+ u8 retry; /* I2C retry times */
+ u16 delay; /* delay before read or after write */
+ u16 data_len; /* data length */
+ u8 addr_len; /* address length */
+ u8 addr[2]; /* address */
+ u8 res[3]; /* reserved */
+ u8 *data; /* data pointer */
+} st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+ unsigned long len, void *data);
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data);
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+s32 DATA_LENGTH;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char *procname)
+{
+ char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ char date[20] = {0};
+ char month[4] = {0};
+ int i = 0, n_month = 1, n_day = 0, n_year = 0, ret;
+
+ ret = sscanf(date, "%s %d %d", month, &n_day, &n_year);
+ if (!ret)
+ return;
+ for (i = 0; i < 12; ++i) {
+ if (!memcmp(months[i], month, 3)) {
+ n_month = i+1;
+ break;
+ }
+ }
+
+ snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+ /* GTP_DEBUG("procname = %s", procname); */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msgs[2];
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = gt_client->addr;
+ msgs[0].len = cmd_head.addr_len;
+ msgs[0].buf = &buf[0];
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = gt_client->addr;
+ msgs[1].len = len;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = i2c_transfer(gt_client->adapter, msgs, 2);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msg;
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = gt_client->addr;
+ msg.len = len;
+ msg.buf = buf;
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = i2c_transfer(gt_client->adapter, &msg, 1);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_read_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_write_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static void register_i2c_func(void)
+{
+ if (strcmp(IC_TYPE, "GT8110") && strcmp(IC_TYPE, "GT8105")
+ && strcmp(IC_TYPE, "GT801") && strcmp(IC_TYPE, "GT800")
+ && strcmp(IC_TYPE, "GT801PLUS") && strcmp(IC_TYPE, "GT811")
+ && strcmp(IC_TYPE, "GTxxx")) {
+ tool_i2c_read = tool_i2c_read_with_extra;
+ tool_i2c_write = tool_i2c_write_with_extra;
+ GTP_DEBUG("I2C function: with pre and end cmd!");
+ } else {
+ tool_i2c_read = tool_i2c_read_no_extra;
+ tool_i2c_write = tool_i2c_write_no_extra;
+ GTP_INFO("I2C function: without pre and end cmd!");
+ }
+}
+
+static void unregister_i2c_func(void)
+{
+ tool_i2c_read = NULL;
+ tool_i2c_write = NULL;
+ GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+ s32 i;
+
+ gt_client = client;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 5;
+ while ((!cmd_head.data) && i) {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (cmd_head.data != NULL)
+ break;
+ i--;
+ }
+ if (i) {
+ DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+ GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ } else {
+ GTP_ERROR("Apply for memory failed.");
+ return FAIL;
+ }
+
+ cmd_head.addr_len = 2;
+ cmd_head.retry = 5;
+
+ register_i2c_func();
+
+ tool_set_proc_name(procname);
+ goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ if (goodix_proc_entry == NULL) {
+ GTP_ERROR("Couldn't create proc entry!");
+ return FAIL;
+ }
+ GTP_INFO("Create proc entry success!");
+ goodix_proc_entry->write_proc = goodix_tool_write;
+ dix_proc_entry->read_proc = goodix_tool_read;
+
+ return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ unregister_i2c_func();
+ remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+ u8 ret = 0;
+
+ switch (rlt) {
+
+ case 0:
+ ret = (src != dst) ? true : false;
+ break;
+
+ case 1:
+ ret = (src == dst) ? true : false;
+ GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.",
+ src, dst, (s32)ret);
+ break;
+
+ case 2:
+ ret = (src > dst) ? true : false;
+ break;
+
+ case 3:
+ ret = (src < dst) ? true : false;
+ break;
+
+ case 4:
+ ret = (src & dst) ? true : false;
+ break;
+
+ case 5:
+ ret = (!(src | dst)) ? true : false;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+ * Function:
+ * Comfirm function.
+ * Input:
+ * None.
+ * Output:
+ * Return write length.
+ *******************************************************
+ */
+static u8 comfirm(void)
+{
+ s32 i = 0;
+ u8 buf[32];
+
+/* memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ * &cmd_head.flag_addr, cmd_head.addr_len);
+ * memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
+ * //Modified by Scott, 2012-02-17
+ */
+ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+ for (i = 0; i < cmd_head.times; i++) {
+ if (tool_i2c_read(buf, 1) <= 0) {
+ GTP_ERROR("Read flag data failed!");
+ return FAIL;
+ }
+ if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
+ cmd_head.flag_relation)) {
+ GTP_DEBUG("value at flag addr:0x%02x.",
+ buf[GTP_ADDR_LENGTH]);
+ GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+ break;
+ }
+
+ msleep(cmd_head.circle);
+ }
+
+ if (i >= cmd_head.times) {
+ GTP_ERROR("Didn't get the flag to continue!");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+/********************************************************
+ * Function:
+ * Goodix tool write function.
+ * Input:
+ * standard proc write function param.
+ * Output:
+ * Return write length.
+ *******************************************************
+ */
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+ unsigned long len, void *data)
+{
+ s32 ret = 0;
+
+ GTP_DEBUG_FUNC();
+ GTP_DEBUG_ARRAY((u8 *)buff, len);
+
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
+ GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+ GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0],
+ cmd_head.flag_addr[1]);
+ GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+ GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+ GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
+ GTP_DEBUG("times :%d.", (s32)cmd_head.times);
+ GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
+ GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
+ GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+ GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+ GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+ GTP_DEBUG("len:%d.", (s32)len);
+ GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+ if (cmd_head.wr == 1) {
+ /* copy_from_user(&cmd_head.data[cmd_head.addr_len],
+ * &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ */
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG_ARRAY(cmd_head.data,
+ cmd_head.data_len + cmd_head.addr_len);
+ GTP_DEBUG_ARRAY((u8 *)&buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+
+ if (cmd_head.flag == 1) {
+ if (comfirm() == FAIL) {
+ GTP_ERROR("[WRITE]Comfirm fail!");
+ return FAIL;
+ }
+ } else if (cmd_head.flag == 2) {
+ /* Need interrupt! */
+ }
+ if (tool_i2c_write(
+ &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len) <= 0) {
+ GTP_ERROR("[WRITE]Write data failed!");
+ return FAIL;
+ }
+
+ GTP_DEBUG_ARRAY(
+ &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len);
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 3) { /* Write ic type */
+
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret)
+ GTP_ERROR("copy_from_user failed.");
+
+ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ register_i2c_func();
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 3) {
+
+ /* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 7) { /* disable irq! */
+ gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_OFF);
+ #endif
+ return CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 9) { /* enable irq! */
+ gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_ON);
+ #endif
+ return CMD_HEAD_LENGTH;
+ } else if (cmd_head.wr == 17) {
+ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if (ret)
+ GTP_DEBUG("copy_from_user failed.");
+ if (cmd_head.data[GTP_ADDR_LENGTH]) {
+ GTP_DEBUG("gtp enter rawdiff.");
+ ts->gtp_rawdiff_mode = true;
+ } else {
+ ts->gtp_rawdiff_mode = false;
+ GTP_DEBUG("gtp leave rawdiff.");
+ }
+ return CMD_HEAD_LENGTH;
+ }
+#ifdef UPDATE_FUNCTIONS
+ else if (cmd_head.wr == 11) { /* Enter update mode! */
+ if (gup_enter_update_mode(gt_client) == FAIL)
+ return FAIL;
+ } else if (cmd_head.wr == 13) { /* Leave update mode! */
+ gup_leave_update_mode();
+ } else if (cmd_head.wr == 15) { /* Update firmware! */
+ show_len = 0;
+ total_len = 0;
+ memset(cmd_head.data, 0, cmd_head.data_len + 1);
+ memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+
+ if (gup_update_proc((void *)cmd_head.data) == FAIL)
+ return FAIL;
+ }
+#endif
+
+ return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+ * Function:
+ * Goodix tool read function.
+ * Input:
+ * standard proc read function param.
+ * Output:
+ * Return read length.
+ *******************************************************
+*/
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ GTP_DEBUG_FUNC();
+
+ if (cmd_head.wr % 2) {
+ return FAIL;
+ } else if (!cmd_head.wr) {
+ u16 len = 0;
+ s16 data_len = 0;
+ u16 loc = 0;
+
+ if (cmd_head.flag == 1) {
+ if (comfirm() == FAIL) {
+ GTP_ERROR("[READ]Comfirm fail!");
+ return FAIL;
+ }
+ } else if (cmd_head.flag == 2) {
+ /* Need interrupt! */
+ }
+
+ memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
+ cmd_head.data[1]);
+ GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
+ cmd_head.addr[1]);
+
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+
+ data_len = cmd_head.data_len;
+ while (data_len > 0) {
+ if (data_len > DATA_LENGTH)
+ len = DATA_LENGTH;
+ else
+ len = data_len;
+
+ data_len -= DATA_LENGTH;
+
+ if (tool_i2c_read(cmd_head.data, len) <= 0) {
+ GTP_ERROR("[READ]Read data failed!");
+ return FAIL;
+ }
+ memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
+ len);
+ loc += len;
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+ GTP_DEBUG_ARRAY(page, len);
+ }
+ } else if (cmd_head.wr == 2) {
+ /* memcpy(page, "gt8", cmd_head.data_len);
+ * memcpy(page, "GT818", 5);
+ * page[5] = 0;
+ */
+
+ GTP_DEBUG("Return ic type:%s len:%d.", page,
+ (s32)cmd_head.data_len);
+ return cmd_head.data_len;
+ /* return sizeof(IC_TYPE_NAME); */
+ } else if (cmd_head.wr == 4) {
+ page[0] = show_len >> 8;
+ page[1] = show_len & 0xff;
+ page[2] = total_len >> 8;
+ page[3] = total_len & 0xff;
+
+ return cmd_head.data_len;
+ } else if (cmd_head.wr == 6) {
+ /* Read error code! */
+ } else if (cmd_head.wr == 8) { /*Read driver version */
+ /* memcpy(page, GTP_DRIVER_VERSION,
+ * strlen(GTP_DRIVER_VERSION));
+ */
+ s32 tmp_len;
+
+ tmp_len = strlen(GTP_DRIVER_VERSION);
+ memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+ page[tmp_len] = 0;
+ }
+
+ return cmd_head.data_len;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
index 3998bf0023f8..81e3affe62e9 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -1,6 +1,6 @@
-// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
-// define your own firmware array here
-const unsigned char header_fw_array[] =
-{
-
-}; \ No newline at end of file
+/*
+ * make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+ * define your own firmware array here
+*/
+const unsigned char header_fw_array[] = {
+};
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index f564a6b3aaed..29459b6d9ad1 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -1,21 +1,22 @@
/* drivers/input/touchscreen/gt9xx_update.c
- *
+ *
* 2010 - 2012 Goodix Technology.
- *
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be a reference
- * to you, when you are integrating the GOODiX's CTP IC into your system,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
- *
+ *
* Latest Version:1.6
* Author: andrew@goodix.com
- * Revision Record:
+ * Revision Record:
* V1.0:
* first release. By Andrew, 2012/08/31
* V1.2:
@@ -25,7 +26,7 @@
* 2. modify enter_update_mode;
* 3. add update file cal checksum.
* By Andrew, 2012/12/12
- * V1.6:
+ * V1.6:
* 1. replace guitar_client with i2c_connect_client;
* 2. support firmware header array update.
* By Meta, 2013/03/11
@@ -47,8 +48,8 @@
#define UPDATE_FILE_PATH_2 "/data/_goodix_update_.bin"
#define UPDATE_FILE_PATH_1 "/sdcard/_goodix_update_.bin"
-#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
-#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
#define FW_HEAD_LENGTH 14
#define FW_SECTION_LENGTH 0x2000
@@ -73,39 +74,27 @@
#define SUCCESS 1
#pragma pack(1)
-typedef struct
-{
- u8 hw_info[4]; //hardware info//
- u8 pid[8]; //product id //
- u16 vid; //version id //
-}st_fw_head;
+struct {
+ u8 hw_info[4]; /* hardware info */
+ u8 pid[8]; /* product id */
+ u16 vid; /* version id */
+} st_fw_head;
#pragma pack()
-typedef struct
-{
- u8 force_update;
- u8 fw_flag;
- struct file *file;
- struct file *cfg_file;
- st_fw_head ic_fw_msg;
- mm_segment_t old_fs;
-}st_update_msg;
+struct {
+ u8 force_update;
+ u8 fw_flag;
+ struct file *file;
+ struct file *cfg_file;
+ st_fw_head ic_fw_msg;
+ mm_segment_t old_fs;
+} st_update_msg;
st_update_msg update_msg;
u16 show_len;
u16 total_len;
-u8 got_file_flag = 0;
-u8 searching_file = 0;
-extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
-extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
-extern s32 gtp_send_cfg(struct i2c_client *client);
-extern struct i2c_client * i2c_connect_client;
-extern void gtp_irq_enable(struct goodix_ts_data *ts);
-extern void gtp_irq_disable(struct goodix_ts_data *ts);
-extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
-#if GTP_ESD_PROTECT
-extern void gtp_esd_switch(struct i2c_client *, s32);
-#endif
+u8 got_file_flag;
+u8 searching_file;
/*******************************************************
Function:
Read data from the i2c slave device.
@@ -115,37 +104,37 @@ Input:
buf[2~len-1]: read data buffer.
len: GTP_ADDR_LENGTH + read bytes count
Output:
- numbers of i2c_msgs to transfer:
+ numbers of i2c_msgs to transfer:
2: succeed, otherwise: failed
*********************************************************/
s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
{
- struct i2c_msg msgs[2];
- s32 ret=-1;
- s32 retries = 0;
-
- GTP_DEBUG_FUNC();
-
- msgs[0].flags = !I2C_M_RD;
- msgs[0].addr = client->addr;
- msgs[0].len = GTP_ADDR_LENGTH;
- msgs[0].buf = &buf[0];
- //msgs[0].scl_rate = 300 * 1000; // for Rockchip
-
- msgs[1].flags = I2C_M_RD;
- msgs[1].addr = client->addr;
- msgs[1].len = len - GTP_ADDR_LENGTH;
- msgs[1].buf = &buf[GTP_ADDR_LENGTH];
- //msgs[1].scl_rate = 300 * 1000;
-
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, msgs, 2);
- if(ret == 2)break;
- retries++;
- }
-
- return ret;
+ struct i2c_msg msgs[2];
+ s32 ret = -1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = client->addr;
+ msgs[0].len = GTP_ADDR_LENGTH;
+ msgs[0].buf = &buf[0];
+ /* msgs[0].scl_rate = 300 * 1000; (for Rockchip) */
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = client->addr;
+ msgs[1].len = len - GTP_ADDR_LENGTH;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+ /* msgs[1].scl_rate = 300 * 1000; */
+
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret == 2)
+ break;
+ retries++;
+ }
+
+ return ret;
}
/*******************************************************
@@ -157,1774 +146,1643 @@ Input:
buf[2~len-1]: data buffer
len: GTP_ADDR_LENGTH + write bytes count
Output:
- numbers of i2c_msgs to transfer:
- 1: succeed, otherwise: failed
+ numbers of i2c_msgs to transfer:
+ 1: succeed, otherwise: failed
*********************************************************/
-s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len)
{
- struct i2c_msg msg;
- s32 ret=-1;
- s32 retries = 0;
-
- GTP_DEBUG_FUNC();
-
- msg.flags = !I2C_M_RD;
- msg.addr = client->addr;
- msg.len = len;
- msg.buf = buf;
- //msg.scl_rate = 300 * 1000; // for Rockchip
-
- while(retries < 5)
- {
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret == 1)break;
- retries++;
- }
-
- return ret;
+ struct i2c_msg msg;
+ s32 ret = -1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = buf;
+ /* msg.scl_rate = 300 * 1000; (for Rockchip) */
+
+ while (retries < 5) {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ break;
+ retries++;
+ }
+
+ return ret;
}
static s32 gup_init_panel(struct goodix_ts_data *ts)
{
- s32 ret = 0;
- s32 i = 0;
- u8 check_sum = 0;
- u8 opr_buf[16];
- u8 sensor_id = 0;
-
- u8 cfg_info_group1[] = CTP_CFG_GROUP1;
- u8 cfg_info_group2[] = CTP_CFG_GROUP2;
- u8 cfg_info_group3[] = CTP_CFG_GROUP3;
- u8 cfg_info_group4[] = CTP_CFG_GROUP4;
- u8 cfg_info_group5[] = CTP_CFG_GROUP5;
- u8 cfg_info_group6[] = CTP_CFG_GROUP6;
- u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
- cfg_info_group4, cfg_info_group5, cfg_info_group6};
- u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
- CFG_GROUP_LEN(cfg_info_group2),
- CFG_GROUP_LEN(cfg_info_group3),
- CFG_GROUP_LEN(cfg_info_group4),
- CFG_GROUP_LEN(cfg_info_group5),
- CFG_GROUP_LEN(cfg_info_group6)};
-
- if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
- (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
- (!cfg_info_len[5]))
- {
- sensor_id = 0;
- }
- else
- {
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
- if (SUCCESS == ret)
- {
- if (sensor_id >= 0x06)
- {
- GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
- return -1;
- }
- }
- else
- {
- GTP_ERROR("Failed to get sensor_id, No config sent!");
- return -1;
- }
- }
-
- GTP_DEBUG("Sensor_ID: %d", sensor_id);
-
- ts->gtp_cfg_len = cfg_info_len[sensor_id];
-
- if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
- {
- GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
- return -1;
- }
-
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
-
- if (ret == SUCCESS)
- {
- GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1,
- send_cfg_buf[sensor_id][0], opr_buf[0]);
-
- send_cfg_buf[sensor_id][0] = opr_buf[0];
- ts->fixed_cfg = 0;
- /*
- if (opr_buf[0] < 90)
- {
- grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version
- send_cfg_buf[sensor_id][0] = 0x00;
- ts->fixed_cfg = 0;
- }
- else // treated as fixed config, not send config
- {
- GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]);
- ts->fixed_cfg = 1;
- }*/
- }
- else
- {
- GTP_ERROR("Failed to get ic config version!No config sent!");
- return -1;
- }
-
- memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
- memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
-
- GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
- ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
-
- config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
- config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
- config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
- config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
-
- if (GTP_INT_TRIGGER == 0) //RISING
- {
- config[TRIGGER_LOC] &= 0xfe;
- }
- else if (GTP_INT_TRIGGER == 1) //FALLING
- {
- config[TRIGGER_LOC] |= 0x01;
- }
-
- check_sum = 0;
- for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
- {
- check_sum += config[i];
- }
- config[ts->gtp_cfg_len] = (~check_sum) + 1;
-
- GTP_DEBUG_FUNC();
- ret = gtp_send_cfg(ts->client);
- if (ret < 0)
- {
- GTP_ERROR("Send config error.");
- }
-
- msleep(10);
- return 0;
+ s32 ret = 0;
+ s32 i = 0;
+ u8 check_sum = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
+
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+ u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+ u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+ cfg_info_group4, cfg_info_group5, cfg_info_group6};
+ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5),
+ CFG_GROUP_LEN(cfg_info_group6)};
+
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+ (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+ (!cfg_info_len[5])) {
+ sensor_id = 0;
+ } else {
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+ &sensor_id, 1);
+ if (ret == SUCCESS) {
+ if (sensor_id >= 0x06) {
+ GTP_ERROR(
+ "Invalid sensor_id(0x%02X), No Config Sent!",
+ sensor_id);
+ return -EINVAL;
+ }
+ } else {
+ GTP_ERROR("Failed to get sensor_id, No config sent!");
+ return -EINVAL;
+ }
+ }
+
+ GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+ ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+ if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+ GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG",
+ " GROUP! NO Config Sent! You need to check you header",
+ " file CFG_GROUP section!", sensor_id);
+ return -EINVAL;
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+
+ if (ret == SUCCESS) {
+ GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version:",
+ " %d", sensor_id+1, send_cfg_buf[sensor_id][0], opr_buf[0]);
+
+ send_cfg_buf[sensor_id][0] = opr_buf[0];
+ ts->fixed_cfg = 0;
+ /*
+ * if (opr_buf[0] < 90) {
+ * grp_cfg_version = send_cfg_buf[sensor_id][0];
+ * *** backup group config version ***
+ * send_cfg_buf[sensor_id][0] = 0x00;
+ * ts->fixed_cfg = 0;
+ * } else { *** treated as fixed config, not send config ***
+ * GTP_INFO("Ic fixed config with config version(%d)",
+ * opr_buf[0]);
+ * ts->fixed_cfg = 1;
+ * }
+ */
+ } else {
+ GTP_ERROR("Failed to get ic config version!No config sent!");
+ return -EINVAL;
+ }
+
+ memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+ ts->gtp_cfg_len);
+
+ GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+ ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+ config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
+ config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+ config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+ config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+ if (GTP_INT_TRIGGER == 0) /* RISING */
+ config[TRIGGER_LOC] &= 0xfe;
+ else if (GTP_INT_TRIGGER == 1) /* FALLING */
+ config[TRIGGER_LOC] |= 0x01;
+
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ check_sum += config[i];
+
+ config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+ GTP_DEBUG_FUNC();
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ GTP_ERROR("Send config error.");
+
+ msleep(20);
+ return 0;
}
-static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
{
- s32 i = 0;
-
- msg[0] = (addr >> 8) & 0xff;
- msg[1] = addr & 0xff;
-
- for (i = 0; i < 5; i++)
- {
- if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
- {
- break;
- }
- }
-
- if (i >= 5)
- {
- GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
- return FAIL;
- }
-
- return SUCCESS;
+ s32 i = 0;
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+
+ for (i = 0; i < 5; i++)
+ if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+ break;
+
+ if (i >= 5) {
+ GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
}
static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
{
- s32 i = 0;
- u8 msg[3];
-
- msg[0] = (addr >> 8) & 0xff;
- msg[1] = addr & 0xff;
- msg[2] = val;
-
- for (i = 0; i < 5; i++)
- {
- if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
- {
- break;
- }
- }
-
- if (i >= 5)
- {
- GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
- return FAIL;
- }
-
- return SUCCESS;
+ s32 i = 0;
+ u8 msg[3];
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+ msg[2] = val;
+
+ for (i = 0; i < 5; i++)
+ if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+ break;
+
+ if (i >= 5) {
+ GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
}
static u8 gup_get_ic_fw_msg(struct i2c_client *client)
{
- s32 ret = -1;
- u8 retry = 0;
- u8 buf[16];
- u8 i;
-
- // step1:get hardware info
- ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4);
- if (FAIL == ret)
- {
- GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
- return FAIL;
- }
-
- // buf[2~5]: 00 06 90 00
- // hw_info: 00 90 06 00
- for(i=0; i<4; i++)
- {
- update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
- }
- GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
- update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
- // step2:get firmware message
- for(retry=0; retry<2; retry++)
- {
- ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
- if(FAIL == ret)
- {
- GTP_ERROR("Read firmware message fail.");
- return ret;
- }
-
- update_msg.force_update = buf[GTP_ADDR_LENGTH];
- if((0xBE != update_msg.force_update)&&(!retry))
- {
- GTP_INFO("The check sum in ic is error.");
- GTP_INFO("The IC will be updated by force.");
- continue;
- }
- break;
- }
- GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
-
- // step3:get pid & vid
- ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6);
- if (FAIL == ret)
- {
- GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
- return FAIL;
- }
-
- memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
- memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
- GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
-
- //GT9XX PID MAPPING
- /*|-----FLASH-----RAM-----|
- |------918------918-----|
- |------968------968-----|
- |------913------913-----|
- |------913P-----913P----|
- |------927------927-----|
- |------927P-----927P----|
- |------9110-----9110----|
- |------9110P----9111----|*/
- if(update_msg.ic_fw_msg.pid[0] != 0)
- {
- if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4))
- {
- GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid);
- memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
- }
- }
-
- update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8);
- GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
-
- return SUCCESS;
+ s32 ret = -1;
+ u8 retry = 0;
+ u8 buf[16];
+ u8 i;
+
+ /* step1:get hardware info */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+ &buf[GTP_ADDR_LENGTH], 4);
+ if (ret == FAIL) {
+ GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+ return FAIL;
+ }
+
+ /* buf[2~5]: 00 06 90 00 */
+ /* hw_info: 00 90 06 00 */
+ for (i = 0; i < 4; i++)
+ update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+
+ GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x",
+ update_msg.ic_fw_msg.hw_info[0],
+ update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2],
+ update_msg.ic_fw_msg.hw_info[3]);
+
+ /* step2:get firmware message */
+ for (retry = 0; retry < 2; retry++) {
+ ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+ if (ret == FAIL) {
+ GTP_ERROR("Read firmware message fail.");
+ return ret;
+ }
+
+ update_msg.force_update = buf[GTP_ADDR_LENGTH];
+ if ((update_msg.force_update != 0xBE) && (!retry)) {
+ GTP_INFO("The check sum in ic is error.");
+ GTP_INFO("The IC will be updated by force.");
+ continue;
+ }
+ break;
+ }
+ GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+
+ /* step3:get pid & vid */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+ &buf[GTP_ADDR_LENGTH], 6);
+ if (ret == FAIL) {
+ GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+ return FAIL;
+ }
+
+ memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+ memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+ GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+ /* GT9XX PID MAPPING
+ * |-----FLASH-----RAM-----|
+ * |------918------918-----|
+ * |------968------968-----|
+ * |------913------913-----|
+ * |------913P-----913P----|
+ * |------927------927-----|
+ * |------927P-----927P----|
+ * |------9110-----9110----|
+ * |------9110P----9111----|
+ */
+ if (update_msg.ic_fw_msg.pid[0] != 0) {
+ if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+ GTP_DEBUG("IC Mapping Product id:%s",
+ update_msg.ic_fw_msg.pid);
+ memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+ }
+ }
+
+ update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+ (buf[GTP_ADDR_LENGTH + 5] << 8);
+ GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+ return SUCCESS;
}
s32 gup_enter_update_mode(struct i2c_client *client)
{
- s32 ret = -1;
- s32 retry = 0;
- u8 rd_buf[3];
-
- //step1:RST output low last at least 2ms
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
- msleep(2);
-
- //step2:select I2C slave addr,INT:0--0xBA;1--0x28.
- GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
- msleep(2);
-
- //step3:RST output high reset guitar
- GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
-
- //20121211 modify start
- msleep(5);
- while(retry++ < 200)
- {
- //step4:Hold ss51 & dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
- continue;
- }
-
- //step5:Confirm hold
- ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
- continue;
- }
- if(0x0C == rd_buf[GTP_ADDR_LENGTH])
- {
- GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
- break;
- }
- GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]);
- }
- if(retry >= 200)
- {
- GTP_ERROR("Enter update Hold ss51 failed.");
- return FAIL;
- }
-
- //step6:DSP_CK and DSP_ALU_CK PowerOn
- ret = gup_set_ic_msg(client, 0x4010, 0x00);
-
- //20121211 modify end
- return ret;
+ s32 ret = -1;
+ s32 retry = 0;
+ u8 rd_buf[3];
+
+ /* step1:RST output low last at least 2ms */
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+ msleep(20);
+
+ /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+ msleep(20);
+
+ /* step3:RST output high reset guitar */
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+ /* 20121211 modify start */
+ msleep(20);
+ while (retry++ < 200) {
+ /* step4:Hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+
+ /* step5:Confirm hold */
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+ if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+ GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+ break;
+ }
+ GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+ rd_buf[GTP_ADDR_LENGTH]);
+ }
+ if (retry >= 200) {
+ GTP_ERROR("Enter update Hold ss51 failed.");
+ return FAIL;
+ }
+
+ /* step6:DSP_CK and DSP_ALU_CK PowerOn */
+ ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+ /* 20121211 modify end */
+ return ret;
}
void gup_leave_update_mode(void)
{
- GTP_GPIO_AS_INT(GTP_INT_PORT);
-
- GTP_DEBUG("[leave_update_mode]reset chip.");
- gtp_reset_guitar(i2c_connect_client, 20);
+ GTP_GPIO_AS_INT(GTP_INT_PORT);
+
+ GTP_DEBUG("[leave_update_mode]reset chip.");
+ gtp_reset_guitar(i2c_connect_client, 20);
}
-// Get the correct nvram data
-// The correct conditions:
-// 1. the hardware info is the same
-// 2. the product id is the same
-// 3. the firmware version in update file is greater than the firmware version in ic
-// or the check sum in ic is wrong
-/* Update Conditions:
- 1. Same hardware info
- 2. Same PID
- 3. File PID > IC PID
- Force Update Conditions:
- 1. Wrong ic firmware checksum
- 2. INVALID IC PID or VID
- 3. IC PID == 91XX || File PID == 91XX
-*/
+/* Get the correct nvram data
+ * The correct conditions:
+ * 1. the hardware info is the same
+ * 2. the product id is the same
+ * 3. the firmware version in update file is greater than the firmware
+ * version in ic or the check sum in ic is wrong
+
+ * Update Conditions:
+ * 1. Same hardware info
+ * 2. Same PID
+ * 3. File PID > IC PID
+
+ * Force Update Conditions:
+ * 1. Wrong ic firmware checksum
+ * 2. INVALID IC PID or VID
+ * 3. IC PID == 91XX || File PID == 91XX
+ */
static u8 gup_enter_update_judge(st_fw_head *fw_head)
{
- u16 u16_tmp;
- s32 i = 0;
-
- u16_tmp = fw_head->vid;
- fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
-
- GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
- GTP_DEBUG("FILE PID:%s", fw_head->pid);
- GTP_DEBUG("FILE VID:%04x", fw_head->vid);
-
- GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
- update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
- GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
- GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
-
- //First two conditions
- if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info)))
- {
- GTP_DEBUG("Get the same hardware info.");
- if( update_msg.force_update != 0xBE )
- {
- GTP_INFO("FW chksum error,need enter update.");
- return SUCCESS;
- }
-
- // 20130523 start
- if (strlen(update_msg.ic_fw_msg.pid) < 3)
- {
- GTP_INFO("Illegal IC pid, need enter update");
- return SUCCESS;
- }
- else
- {
- for (i = 0; i < 3; i++)
- {
- if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39))
- {
- GTP_INFO("Illegal IC pid, out of bound, need enter update");
- return SUCCESS;
- }
- }
- }
- // 20130523 end
-
-
- if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))||
- (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))||
- (!memcmp(fw_head->pid, "91XX", 4)))
- {
- if(!memcmp(fw_head->pid, "91XX", 4))
- {
- GTP_DEBUG("Force none same pid update mode.");
- }
- else
- {
- GTP_DEBUG("Get the same pid.");
- }
- //The third condition
- if (fw_head->vid > update_msg.ic_fw_msg.vid)
- {
-
- GTP_INFO("Need enter update.");
- return SUCCESS;
- }
- GTP_ERROR("Don't meet the third condition.");
- GTP_ERROR("File VID <= Ic VID, update aborted!");
- }
- else
- {
- GTP_ERROR("File PID != Ic PID, update aborted!");
- }
- }
- else
- {
- GTP_ERROR("Different Hardware, update aborted!");
- }
- return FAIL;
+ u16 u16_tmp;
+ s32 i = 0;
+
+ u16_tmp = fw_head->vid;
+ fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+ GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
+ fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+ TP_DEBUG("FILE PID:%s", fw_head->pid);
+ TP_DEBUG("FILE VID:%04x", fw_head->vid);
+
+ TP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x",
+ update_msg.ic_fw_msg.hw_info[0],
+ update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2],
+ update_msg.ic_fw_msg.hw_info[3]);
+ TP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+ TP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+
+ /* First two conditions */
+ if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+ sizeof(update_msg.ic_fw_msg.hw_info))) {
+ GTP_DEBUG("Get the same hardware info.");
+ if (update_msg.force_update != 0xBE) {
+ GTP_INFO("FW chksum error,need enter update.");
+ return SUCCESS;
+ }
+
+ /* 20130523 start */
+ if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+ GTP_INFO("Illegal IC pid, need enter update");
+ return SUCCESS;
+ }
+ for (i = 0; i < 3; i++) {
+ if ((update_msg.ic_fw_msg.pid[i] < 0x30) ||
+ (update_msg.ic_fw_msg.pid[i] > 0x39)) {
+ GTP_INFO("Illegal IC pid, out of ",
+ "bound, need enter update");
+ return SUCCESS;
+ }
+ }
+ /* 20130523 end */
+
+ if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid,
+ (strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) ||
+ (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+ (!memcmp(fw_head->pid, "91XX", 4))) {
+ if (!memcmp(fw_head->pid, "91XX", 4))
+ GTP_DEBUG("Force none same pid update mode.");
+ else
+ GTP_DEBUG("Get the same pid.");
+
+ /* The third condition */
+ if (fw_head->vid > update_msg.ic_fw_msg.vid) {
+ GTP_INFO("Need enter update.");
+ return SUCCESS;
+ }
+ GTP_ERROR("Don't meet the third condition.");
+ GTP_ERROR("File VID <= Ic VID, update aborted!");
+ } else {
+ GTP_ERROR("File PID != Ic PID, update aborted!");
+ }
+ } else {
+ GTP_ERROR("Different Hardware, update aborted!");
+ }
+
+ return FAIL;
}
static u8 ascii2hex(u8 a)
{
- s8 value = 0;
-
- if(a >= '0' && a <= '9')
- {
- value = a - '0';
- }
- else if(a >= 'A' && a <= 'F')
- {
- value = a - 'A' + 0x0A;
- }
- else if(a >= 'a' && a <= 'f')
- {
- value = a - 'a' + 0x0A;
- }
- else
- {
- value = 0xff;
- }
-
- return value;
+ s8 value = 0;
+
+ if (a >= '0' && a <= '9')
+ value = a - '0';
+ else if (a >= 'A' && a <= 'F')
+ value = a - 'A' + 0x0A;
+ else if (a >= 'a' && a <= 'f')
+ value = a - 'a' + 0x0A;
+ else
+ value = 0xff;
+
+ return value;
}
static s8 gup_update_config(struct i2c_client *client)
{
- s32 file_len = 0;
- s32 ret = 0;
- s32 i = 0;
- s32 file_cfg_len = 0;
- s32 chip_cfg_len = 0;
- s32 count = 0;
- u8 *buf;
- u8 *pre_buf;
- u8 *file_config;
- //u8 checksum = 0;
- u8 pid[8];
-
- if(NULL == update_msg.cfg_file)
- {
- GTP_ERROR("[update_cfg]No need to upgrade config!");
- return FAIL;
- }
- file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END);
-
- ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_cfg]Read product id & version id fail.");
- return FAIL;
- }
- pid[5] = '\0';
- GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
-
- chip_cfg_len = 186;
- if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
- !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
- !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3))
- {
- chip_cfg_len = 228;
- }
- GTP_DEBUG("[update_cfg]config file len:%d", file_len);
- GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len);
- if((file_len+5) < chip_cfg_len*5)
- {
- GTP_ERROR("Config length error");
- return -1;
- }
-
- buf = (u8*)kzalloc(file_len, GFP_KERNEL);
- pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL);
- file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
- update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
-
- GTP_DEBUG("[update_cfg]Read config from file.");
- ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos);
- if(ret<0)
- {
- GTP_ERROR("[update_cfg]Read config file failed.");
- goto update_cfg_file_failed;
- }
-
- GTP_DEBUG("[update_cfg]Delete illgal charactor.");
- for(i=0,count=0; i<file_len; i++)
- {
- if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n')
- {
- continue;
- }
- buf[count++] = pre_buf[i];
- }
-
- GTP_DEBUG("[update_cfg]Ascii to hex.");
- file_config[0] = GTP_REG_CONFIG_DATA >> 8;
- file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
- for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5)
- {
- if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X')))
- {
- u8 high,low;
- high = ascii2hex(buf[i+2]);
- low = ascii2hex(buf[i+3]);
-
- if((high == 0xFF) || (low == 0xFF))
- {
- ret = 0;
- GTP_ERROR("[update_cfg]Illegal config file.");
- goto update_cfg_file_failed;
- }
- file_config[file_cfg_len++] = (high<<4) + low;
- }
- else
- {
- ret = 0;
- GTP_ERROR("[update_cfg]Illegal config file.");
- goto update_cfg_file_failed;
- }
- }
-
-// //cal checksum
-// for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
-// {
-// checksum += file_config[i];
-// }
-// file_config[chip_cfg_len] = (~checksum) + 1;
-// file_config[chip_cfg_len+1] = 0x01;
-
- GTP_DEBUG("config:");
- GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
-
- i = 0;
- while(i++ < 5)
- {
- ret = gup_i2c_write(client, file_config, file_cfg_len);
- if(ret > 0)
- {
- GTP_INFO("[update_cfg]Send config SUCCESS.");
- break;
- }
- GTP_ERROR("[update_cfg]Send config i2c error.");
- }
-
+ s32 file_len = 0;
+ s32 ret = 0;
+ s32 i = 0;
+ s32 file_cfg_len = 0;
+ s32 chip_cfg_len = 0;
+ s32 count = 0;
+ u8 *buf;
+ u8 *pre_buf;
+ u8 *file_config;
+ /* u8 checksum = 0; */
+ u8 pid[8];
+
+ if (update_msg.cfg_file == NULL) {
+ GTP_ERROR("[update_cfg]No need to upgrade config!");
+ return FAIL;
+ }
+ file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file,
+ 0, SEEK_END);
+
+ ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_cfg]Read product id & version id fail.");
+ return FAIL;
+ }
+ pid[5] = '\0';
+ GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+
+ chip_cfg_len = 186;
+ if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
+ chip_cfg_len = 228;
+ }
+ GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+ GTP_DEBUG("[update_cfg]need config len:%d", chip_cfg_len);
+ if ((file_len+5) < chip_cfg_len*5) {
+ GTP_ERROR("Config length error");
+ return -EINVAL;
+ }
+
+ buf = kzalloc(file_len, GFP_KERNEL);
+ pre_buf = kzalloc(file_len, GFP_KERNEL);
+ file_config = kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+ update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+
+ GTP_DEBUG("[update_cfg]Read config from file.");
+ ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file,
+ (char *)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("[update_cfg]Read config file failed.");
+ goto update_cfg_file_failed;
+ }
+
+ GTP_DEBUG("[update_cfg]Delete illegal character.");
+ for (i = 0, count = 0; i < file_len; i++) {
+ if (pre_buf[i] == ' ' || pre_buf[i] == '\r'
+ || pre_buf[i] == '\n')
+ continue;
+ buf[count++] = pre_buf[i];
+ }
+
+ GTP_DEBUG("[update_cfg]Ascii to hex.");
+ file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+ file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+ for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i + = 5) {
+ if ((buf[i] == '0') && ((buf[i+1] == 'x') ||
+ (buf[i+1] == 'X'))) {
+ u8 high, low;
+
+ high = ascii2hex(buf[i+2]);
+ low = ascii2hex(buf[i+3]);
+
+ if ((high == 0xFF) || (low == 0xFF)) {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ file_config[file_cfg_len++] = (high<<4) + low;
+ } else {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ }
+
+ /* cal checksum */
+ /* for (i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+ * checksum += file_config[i];
+ * file_config[chip_cfg_len] = (~checksum) + 1;
+ * file_config[chip_cfg_len+1] = 0x01;
+ */
+
+ GTP_DEBUG("config:");
+ GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+
+ i = 0;
+ while (i++ < 5) {
+ ret = gup_i2c_write(client, file_config, file_cfg_len);
+ if (ret > 0) {
+ GTP_INFO("[update_cfg]Send config SUCCESS.");
+ break;
+ }
+ GTP_ERROR("[update_cfg]Send config i2c error.");
+ }
+
update_cfg_file_failed:
- kfree(pre_buf);
- kfree(buf);
- kfree(file_config);
- return ret;
+ kfree(pre_buf);
+ kfree(buf);
+ kfree(file_config);
+ return ret;
}
#if GTP_HEADER_FW_UPDATE
static u8 gup_check_fs_mounted(char *path_name)
{
- struct path root_path;
- struct path path;
- int err;
- err = kern_path("/", LOOKUP_FOLLOW, &root_path);
-
- if (err)
- {
- GTP_DEBUG("\"/\" NOT Mounted: %d", err);
- return FAIL;
- }
- err = kern_path(path_name, LOOKUP_FOLLOW, &path);
-
- if (err)
- {
- GTP_DEBUG("/data/ NOT Mounted: %d", err);
- return FAIL;
- }
-
- return SUCCESS;
-
- /*
- if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
- {
- //-- not mounted
- return FAIL;
- }
- else
- {
- return SUCCESS;
- }*/
-
+ struct path root_path;
+ struct path path;
+ int err;
+
+ err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+
+ if (err) {
+ GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+ return FAIL;
+ }
+ err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+
+ if (err) {
+ GTP_DEBUG("/data/ NOT Mounted: %d", err);
+ return FAIL;
+ }
+
+ return SUCCESS;
+
+ /* if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+ * return FAIL;
+ * else
+ * return SUCCESS;
+ */
}
#endif
-static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path)
+
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head *fw_head,
+ u8 *path)
{
- s32 ret = 0;
- s32 i = 0;
- s32 fw_checksum = 0;
- u8 buf[FW_HEAD_LENGTH];
-
- if (path)
- {
- GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
- update_msg.file = filp_open(path, O_RDONLY, 0);
-
- if (IS_ERR(update_msg.file))
- {
- GTP_ERROR("Open update file(%s) error!", path);
- return FAIL;
- }
- }
- else
- {
+ s32 ret = 0;
+ s32 i = 0;
+ s32 fw_checksum = 0;
+ u8 buf[FW_HEAD_LENGTH];
+
+ if (path) {
+ GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+ update_msg.file = file_open(path, O_RDONLY, 0);
+
+ if (IS_ERR(update_msg.file)) {
+ GTP_ERROR("Open update file(%s) error!", path);
+ return FAIL;
+ }
+ } else {
#if GTP_HEADER_FW_UPDATE
- for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++)
- {
- GTP_DEBUG("Waiting for /data mounted [%d]", i);
-
- if (gup_check_fs_mounted("/data") == SUCCESS)
- {
- GTP_DEBUG("/data Mounted!");
- break;
- }
- msleep(3000);
- }
- if (i >= (GUP_SEARCH_FILE_TIMES))
- {
- GTP_ERROR("Wait for /data mounted timeout!");
- return FAIL;
- }
-
- // update config
- update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0);
- if (IS_ERR(update_msg.cfg_file))
- {
- GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
- }
- else
- {
- GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
- ret = gup_update_config(client);
- if(ret <= 0)
- {
- GTP_ERROR("Update config failed.");
- }
- filp_close(update_msg.cfg_file, NULL);
- }
-
- if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH))
- {
- GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!");
- return FAIL;
- }
- update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666);
- if ((IS_ERR(update_msg.file)))
- {
- GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2);
- return FAIL;
- }
- update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
- update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos);
- filp_close(update_msg.file, NULL);
- update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+ for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) {
+ GTP_DEBUG("Waiting for /data mounted [%d]", i);
+
+ if (gup_check_fs_mounted("/data") == SUCCESS) {
+ GTP_DEBUG("/data Mounted!");
+ break;
+ }
+ msleep(3000);
+ }
+ if (i >= (GUP_SEARCH_FILE_TIMES)) {
+ GTP_ERROR("Wait for /data mounted timeout!");
+ return FAIL;
+ }
+
+ /* update config */
+ update_msg.cfg_file = file_open(CONFIG_FILE_PATH_1,
+ O_RDONLY, 0);
+
+ if (IS_ERR(update_msg.cfg_file)) {
+ GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+ } else {
+ GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+ ret = gup_update_config(client);
+ if (ret <= 0)
+ GTP_ERROR("Update config failed.");
+ filp_close(update_msg.cfg_file, NULL);
+ }
+
+ if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH
+ *4 + FW_DSP_ISP_LENGTH+FW_DSP_LENGTH + FW_BOOT_LENGTH)) {
+ GTP_ERROR("INVALID header_fw_array, check your ",
+ "gt9xx_firmware.h file!");
+ return FAIL;
+ }
+ update_msg.file = file_open(UPDATE_FILE_PATH_2, O_CREAT |
+ O_RDWR, 0666);
+ if ((IS_ERR(update_msg.file))) {
+ GTP_ERROR("Failed to Create file: %s for fw_header!",
+ UPDATE_FILE_PATH_2);
+ return FAIL;
+ }
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ update_msg.file->f_op->write(update_msg.file,
+ (char *)header_fw_array, sizeof(header_fw_array),
+ &update_msg.file->f_pos);
+ file_close(update_msg.file, NULL);
+ update_msg.file = file_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
#else
- u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2));
- u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2));
- u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL);
- u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL);
- //Begin to search update file,the config file & firmware file must be in the same path,single or double.
- searching_file = 1;
- for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++)
- {
- if (searching_file == 0)
- {
- kfree(search_update_path);
- kfree(search_cfg_path);
- GTP_INFO(".bin/.cfg update file search forcely terminated!");
- return FAIL;
- }
- if(i%2)
- {
- memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1));
- memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1));
- }
- else
- {
- memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2));
- memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2));
- }
-
- if(!(got_file_flag&0x0F))
- {
- update_msg.file = filp_open(search_update_path, O_RDONLY, 0);
- if(!IS_ERR(update_msg.file))
- {
- GTP_DEBUG("Find the bin file");
- got_file_flag |= 0x0F;
- }
- }
- if(!(got_file_flag&0xF0))
- {
- update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0);
- if(!IS_ERR(update_msg.cfg_file))
- {
- GTP_DEBUG("Find the cfg file");
- got_file_flag |= 0xF0;
- }
- }
-
- if(got_file_flag)
- {
- if(got_file_flag == 0xFF)
- {
- break;
- }
- else
- {
- i += 4;
- }
- }
- GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg");
- msleep(3000);
- }
- searching_file = 0;
- kfree(search_update_path);
- kfree(search_cfg_path);
-
- if(!got_file_flag)
- {
- GTP_ERROR("Can't find update file.");
- goto load_failed;
- }
-
- if(got_file_flag&0xF0)
- {
- GTP_DEBUG("Got the update config file.");
- ret = gup_update_config(client);
- if(ret <= 0)
- {
- GTP_ERROR("Update config failed.");
- }
- filp_close(update_msg.cfg_file, NULL);
- msleep(500); //waiting config to be stored in FLASH.
- }
- if(got_file_flag&0x0F)
- {
- GTP_DEBUG("Got the update firmware file.");
- }
- else
- {
- GTP_ERROR("No need to upgrade firmware.");
- goto load_failed;
- }
+ u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1),
+ sizeof(UPDATE_FILE_PATH_2));
+ u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1),
+ sizeof(CONFIG_FILE_PATH_2));
+ u8 *search_update_path = kzalloc(fp_len, GFP_KERNEL);
+ u8 *search_cfg_path = kzalloc(cfp_len, GFP_KERNEL);
+ /* Begin to search update file,the config file & firmware
+ * file must be in the same path,single or double.
+ */
+ searching_file = 1;
+ for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) {
+ if (searching_file == 0) {
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+ GTP_INFO(".bin/.cfg update file search ",
+ "forcely terminated!");
+ return FAIL;
+ }
+ if (i % 2) {
+ memcpy(search_update_path, UPDATE_FILE_PATH_1,
+ sizeof(UPDATE_FILE_PATH_1));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_1,
+ sizeof(CONFIG_FILE_PATH_1));
+ } else {
+ memcpy(search_update_path, UPDATE_FILE_PATH_2,
+ sizeof(UPDATE_FILE_PATH_2));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_2,
+ sizeof(CONFIG_FILE_PATH_2));
+ }
+
+ if (!(got_file_flag&0x0F)) {
+ update_msg.file = file_open(search_update_path,
+ O_RDONLY, 0);
+ if (!IS_ERR(update_msg.file)) {
+ GTP_DEBUG("Find the bin file");
+ got_file_flag |= 0x0F;
+ }
+ }
+ if (!(got_file_flag & 0xF0)) {
+ update_msg.cfg_file = file_open(search_cfg_path,
+ O_RDONLY, 0);
+ if (!IS_ERR(update_msg.cfg_file)) {
+ GTP_DEBUG("Find the cfg file");
+ got_file_flag |= 0xF0;
+ }
+ }
+
+ if (got_file_flag) {
+ if (got_file_flag == 0xFF)
+ break;
+ i += 4;
+ }
+ GTP_DEBUG("%3d:Searching %s %s file...", i,
+ (got_file_flag & 0x0F) ? "" : "bin",
+ (got_file_flag & 0xF0) ? "" : "cfg");
+
+ msleep(3000);
+ }
+
+ searching_file = 0;
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+
+ if (!got_file_flag) {
+ GTP_ERROR("Can't find update file.");
+ goto load_failed;
+ }
+
+ if (got_file_flag & 0xF0) {
+ GTP_DEBUG("Got the update config file.");
+ ret = gup_update_config(client);
+ if (ret <= 0)
+ GTP_ERROR("Update config failed.");
+ filp_close(update_msg.cfg_file, NULL);
+ msleep(500); /* waiting config to be stored in FLASH. */
+ }
+ if (got_file_flag & 0x0F) {
+ GTP_DEBUG("Got the update firmware file.");
+ } else {
+ GTP_ERROR("No need to upgrade firmware.");
+ goto load_failed;
+ }
#endif
- }
-
- update_msg.old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
- //update_msg.file->f_pos = 0;
-
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
- if (ret < 0)
- {
- GTP_ERROR("Read firmware head in update file error.");
- goto load_failed;
- }
- memcpy(fw_head, buf, FW_HEAD_LENGTH);
-
- //check firmware legality
- fw_checksum = 0;
- for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2)
- {
- u16 temp;
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos);
- if (ret < 0)
- {
- GTP_ERROR("Read firmware file error.");
- goto load_failed;
- }
- //GTP_DEBUG("BUF[0]:%x", buf[0]);
- temp = (buf[0]<<8) + buf[1];
- fw_checksum += temp;
- }
-
- GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
- if(fw_checksum&0xFFFF)
- {
- GTP_ERROR("Illegal firmware file.");
- goto load_failed;
- }
-
- return SUCCESS;
+ }
+
+ update_msg.old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ /* update_msg.file->f_pos = 0; */
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+ FW_HEAD_LENGTH, &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read firmware head in update file error.");
+ goto load_failed;
+ }
+ memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+ /* check firmware legality */
+ fw_checksum = 0;
+ for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH; i + = 2) {
+ u16 temp;
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+ 2, &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read firmware file error.");
+ goto load_failed;
+ }
+ /* GTP_DEBUG("BUF[0]:%x", buf[0]); */
+ temp = (buf[0]<<8) + buf[1];
+ fw_checksum += temp;
+ }
+
+ GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+ if (fw_checksum & 0xFFFF) {
+ GTP_ERROR("Illegal firmware file.");
+ goto load_failed;
+ }
+
+ return SUCCESS;
load_failed:
- set_fs(update_msg.old_fs);
- return FAIL;
+ set_fs(update_msg.old_fs);
+ return FAIL;
}
#if 0
-static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head)
+static u8 gup_check_update_header(struct i2c_client *client,
+ st_fw_head *fw_head)
{
- const u8* pos;
- int i = 0;
- u8 mask_num = 0;
- s32 ret = 0;
-
- pos = HEADER_UPDATE_DATA;
-
- memcpy(fw_head, pos, FW_HEAD_LENGTH);
- pos += FW_HEAD_LENGTH;
-
- ret = gup_enter_update_judge(fw_head);
- if(SUCCESS == ret)
- {
- return SUCCESS;
- }
- return FAIL;
+ const u8 *pos;
+ int i = 0;
+ u8 mask_num = 0;
+ s32 ret = 0;
+
+ pos = HEADER_UPDATE_DATA;
+
+ memcpy(fw_head, pos, FW_HEAD_LENGTH);
+ pos += FW_HEAD_LENGTH;
+
+ ret = gup_enter_update_judge(fw_head);
+ if (ret == SUCCESS)
+ return SUCCESS;
+ return FAIL;
}
#endif
-static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length)
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr,
+ u16 total_length)
{
- s32 ret = 0;
- u16 burn_addr = start_addr;
- u16 frame_length = 0;
- u16 burn_length = 0;
- u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- u8 retry = 0;
-
- GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr);
- while(burn_length < total_length)
- {
- GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
- frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
- wr_buf[0] = (u8)(burn_addr>>8);
- rd_buf[0] = wr_buf[0];
- wr_buf[1] = (u8)burn_addr;
- rd_buf[1] = wr_buf[1];
- memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length);
-
- for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++)
- {
- ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("Write frame data i2c error.");
- continue;
- }
- ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("Read back frame data i2c error.");
- continue;
- }
-
- if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length))
- {
- GTP_ERROR("Check frame data fail,not equal.");
- GTP_DEBUG("write array:");
- GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length);
- GTP_DEBUG("read array:");
- GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
- continue;
- }
- else
- {
- //GTP_DEBUG("Check frame data success.");
- break;
- }
- }
- if(retry >= MAX_FRAME_CHECK_TIME)
- {
- GTP_ERROR("Burn frame data time out,exit.");
- return FAIL;
- }
- burn_length += frame_length;
- burn_addr += frame_length;
- }
- return SUCCESS;
+ s32 ret = 0;
+ u16 burn_addr = start_addr;
+ u16 frame_length = 0;
+ u16 burn_length = 0;
+ u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 retry = 0;
+
+ GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024),
+ start_addr);
+ while (burn_length < total_length) {
+ GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+ frame_length = ((total_length - burn_length) > PACK_SIZE)
+ ? PACK_SIZE : (total_length - burn_length);
+ wr_buf[0] = (u8)(burn_addr>>8);
+ rd_buf[0] = wr_buf[0];
+ wr_buf[1] = (u8)burn_addr;
+ rd_buf[1] = wr_buf[1];
+ memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length],
+ frame_length);
+
+ for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+ ret = gup_i2c_write(client, wr_buf,
+ GTP_ADDR_LENGTH + frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("Write frame data i2c error.");
+ continue;
+ }
+ ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH +
+ frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("Read back frame data i2c error.");
+ continue;
+ }
+
+ if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+ &rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+ GTP_ERROR("Check frame data fail,not equal.");
+ GTP_DEBUG("write array:");
+ GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ GTP_DEBUG("read array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ continue;
+ } else {
+ /* GTP_DEBUG("Check frame data success."); */
+ break;
+ }
+ }
+ if (retry >= MAX_FRAME_CHECK_TIME) {
+ GTP_ERROR("Burn frame data time out,exit.");
+ return FAIL;
+ }
+ burn_length += frame_length;
+ burn_addr += frame_length;
+ }
+ return SUCCESS;
}
-static u8 gup_load_section_file(u8* buf, u16 offset, u16 length)
+static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length)
{
- s32 ret = 0;
-
- if(update_msg.file == NULL)
- {
- GTP_ERROR("cannot find update file,load section file fail.");
- return FAIL;
- }
- update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
-
- ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos);
- if(ret < 0)
- {
- GTP_ERROR("Read update file fail.");
- return FAIL;
- }
-
- return SUCCESS;
+ s32 ret = 0;
+
+ if (update_msg.file == NULL) {
+ GTP_ERROR("cannot find update file,load section file fail.");
+ return FAIL;
+ }
+ update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char *)buf, length,
+ &update_msg.file->f_pos);
+ if (ret < 0) {
+ GTP_ERROR("Read update file fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
}
-static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length)
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+ u16 start_rd_addr, u16 chk_length)
{
- u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
- s32 ret = 0;
- u16 recall_addr = start_rd_addr;
- u16 recall_length = 0;
- u16 frame_length = 0;
-
- while(recall_length < chk_length)
- {
- frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length);
- ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
- if(ret <= 0)
- {
- GTP_ERROR("recall i2c error,exit");
- return FAIL;
- }
-
- if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length))
- {
- GTP_ERROR("Recall frame data fail,not equal.");
- GTP_DEBUG("chk_src array:");
- GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
- GTP_DEBUG("recall array:");
- GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
- return FAIL;
- }
-
- recall_length += frame_length;
- recall_addr += frame_length;
- }
- GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
-
- return SUCCESS;
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ s32 ret = 0;
+ u16 recall_addr = start_rd_addr;
+ u16 recall_length = 0;
+ u16 frame_length = 0;
+
+ while (recall_length < chk_length) {
+ frame_length = ((chk_length - recall_length) > PACK_SIZE)
+ ? PACK_SIZE : (chk_length - recall_length);
+ ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+ if (ret <= 0) {
+ GTP_ERROR("recall i2c error,exit");
+ return FAIL;
+ }
+
+ if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length],
+ frame_length)) {
+ GTP_ERROR("Recall frame data fail,not equal.");
+ GTP_DEBUG("chk_src array:");
+ GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+ GTP_DEBUG("recall array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+ return FAIL;
+ }
+
+ recall_length += frame_length;
+ recall_addr += frame_length;
+ }
+ GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+
+ return SUCCESS;
}
-static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+ u16 start_addr, u8 bank_cmdi)
{
- s32 ret = 0;
- u8 rd_buf[5];
-
- //step1:hold ss51 & dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
- return FAIL;
- }
-
- //step2:set scramble
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]set scramble fail.");
- return FAIL;
- }
-
- //step3:select bank
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
- return FAIL;
- }
-
- //step4:enable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]enable accessing code fail.");
- return FAIL;
- }
-
- //step5:burn 8k fw section
- ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_section]burn fw_section fail.");
- return FAIL;
- }
-
- //step6:hold ss51 & release dsp
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
- return FAIL;
- }
- //must delay
- msleep(1);
-
- //step7:send burn cmd to move data to flash from sram
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]send burn cmd fail.");
- return FAIL;
- }
- GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]Get burn state fail");
- return FAIL;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
-
- //step8:select bank
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
- return FAIL;
- }
-
- //step9:enable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]enable accessing code fail.");
- return FAIL;
- }
-
- //step10:recall 8k fw section
- ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
- return FAIL;
- }
-
- //step11:disable accessing code
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_section]disable accessing code fail.");
- return FAIL;
- }
-
- return SUCCESS;
+ s32 ret = 0;
+ u8 rd_buf[5];
+
+ /* step1:hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+ return FAIL;
+ }
+
+ /* step2:set scramble */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]set scramble fail.");
+ return FAIL;
+ }
+
+ /* step3:select bank */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+ (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step4:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step5:burn 8k fw section */
+ ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+ return FAIL;
+ }
+
+ /* step6:hold ss51 & release dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+ return FAIL;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step7:send burn cmd to move data to flash from sram */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+ return FAIL;
+ }
+ GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]Get burn state fail");
+ return FAIL;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_section]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:select bank */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+ (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step9:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step10:recall 8k fw section */
+ ret = gup_recall_check(client, fw_section, start_addr,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+ return FAIL;
+ }
+
+ /* step11:disable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
}
static u8 gup_burn_dsp_isp(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_dsp_isp = NULL;
- u8 retry = 0;
-
- GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
-
- //step1:alloc memory
- GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
- if(fw_dsp_isp == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load dsp isp file data
- GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
- ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
- goto exit_burn_dsp_isp;
- }
-
- //step3:disable wdt,clear cache enable
- GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
- ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step4:hold ss51 & dsp
- GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step5:set boot from sram
- GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step6:software reboot
- GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
- ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]software reboot fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step7:select bank2
- GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step8:enable accessing code
- GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
-
- //step9:burn 4k dsp_isp
- GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
- ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
- goto exit_burn_dsp_isp;
- }
-
- //step10:set scramble
- GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_dsp_isp]set scramble fail.");
- ret = FAIL;
- goto exit_burn_dsp_isp;
- }
- ret = SUCCESS;
+ s32 ret = 0;
+ u8 *fw_dsp_isp = NULL;
+ u8 retry = 0;
+
+ GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+ if (fw_dsp_isp == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.",
+ (FW_DSP_ISP_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load dsp isp file data */
+ GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+ ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step3:disable wdt,clear cache enable */
+ GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step4:hold ss51 & dsp */
+ GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step5:set boot from sram */
+ GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step6:software reboot */
+ GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+ ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step7:select bank2 */
+ GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step8:enable accessing code */
+ GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step9:burn 4k dsp_isp */
+ GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+ ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step10:set scramble */
+ GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = SUCCESS;
exit_burn_dsp_isp:
- kfree(fw_dsp_isp);
- return ret;
+ kfree(fw_dsp_isp);
+ return ret;
}
static u8 gup_burn_fw_ss51(struct i2c_client *client)
{
- u8* fw_ss51 = NULL;
- u8 retry = 0;
- s32 ret = 0;
-
- GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
-
- //step1:alloc memory
- GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
- if(fw_ss51 == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load ss51 firmware section 1 file data
- GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
- ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step3:clear control flag
- GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
- ret = FAIL;
- goto exit_burn_fw_ss51;
- }
-
- //step4:burn ss51 firmware section 1
- GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
- ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step5:load ss51 firmware section 2 file data
- GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
- ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step6:burn ss51 firmware section 2
- GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
- ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step7:load ss51 firmware section 3 file data
- GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
- ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step8:burn ss51 firmware section 3
- GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
- ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step9:load ss51 firmware section 4 file data
- GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
- ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
- goto exit_burn_fw_ss51;
- }
-
- //step10:burn ss51 firmware section 4
- GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
- ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
- goto exit_burn_fw_ss51;
- }
-
- ret = SUCCESS;
-
+ u8 *fw_ss51 = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+
+ GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_ss51 == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load ss51 firmware section 1 file data */
+ GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+ ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step3:clear control flag */
+ GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+ ret = FAIL;
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step4:burn ss51 firmware section 1 */
+ GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step5:load ss51 firmware section 2 file data */
+ GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+ ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step6:burn ss51 firmware section 2 */
+ GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step7:load ss51 firmware section 3 file data */
+ GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+ ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step8:burn ss51 firmware section 3 */
+ GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step9:load ss51 firmware section 4 file data */
+ GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+ ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step10:burn ss51 firmware section 4 */
+ GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_ss51:
- kfree(fw_ss51);
- return ret;
+ kfree(fw_ss51);
+ return ret;
}
static u8 gup_burn_fw_dsp(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_dsp = NULL;
- u8 retry = 0;
- u8 rd_buf[5];
-
- GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
- //step1:alloc memory
- GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
- while(retry++ < 5)
- {
- fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
- if(fw_dsp == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load firmware dsp
- GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
- ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
- goto exit_burn_fw_dsp;
- }
-
- //step3:select bank3
- GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step4:hold ss51 & dsp
- GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step5:set scramble
- GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]set scramble fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
-
- //step6:release ss51 & dsp
- GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_dsp;
- }
- //must delay
- msleep(1);
-
- //step7:burn 4k dsp firmware
- GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
- ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
- goto exit_burn_fw_dsp;
- }
-
- //step8:send burn cmd to move data to flash from sram
- GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
- goto exit_burn_fw_dsp;
- }
- GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_dsp]Get burn state fail");
- goto exit_burn_fw_dsp;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
-
- //step9:recall check 4k dsp firmware
- GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
- ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
- goto exit_burn_fw_dsp;
- }
-
- ret = SUCCESS;
-
+ s32 ret = 0;
+ u8 *fw_dsp = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+ /* step1:alloc memory */
+ GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+ if (fw_dsp == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware dsp */
+ GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+ ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step3:select bank3 */
+ GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* Step4:hold ss51 & dsp */
+ GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step5:set scramble */
+ GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step6:release ss51 & dsp */
+ GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step7:burn 4k dsp firmware */
+ GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+ ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step8:send burn cmd to move data to flash from sram */
+ GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash",
+ "from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+ goto exit_burn_fw_dsp;
+ }
+ GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+ goto exit_burn_fw_dsp;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step9:recall check 4k dsp firmware */
+ GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+ ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_dsp:
- kfree(fw_dsp);
- return ret;
+ kfree(fw_dsp);
+ return ret;
}
static u8 gup_burn_fw_boot(struct i2c_client *client)
{
- s32 ret = 0;
- u8* fw_boot = NULL;
- u8 retry = 0;
- u8 rd_buf[5];
-
- GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
-
- //step1:Alloc memory
- GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
- while(retry++ < 5)
- {
- fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
- if(fw_boot == NULL)
- {
- continue;
- }
- else
- {
- GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024));
- break;
- }
- }
- if(retry >= 5)
- {
- GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
- return FAIL;
- }
-
- //step2:load firmware bootloader
- GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
- ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
- goto exit_burn_fw_boot;
- }
-
- //step3:hold ss51 & dsp
- GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step4:set scramble
- GTP_DEBUG("[burn_fw_boot]step4:set scramble");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]set scramble fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step5:release ss51 & dsp
- GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
- //must delay
- msleep(1);
-
- //step6:select bank3
- GTP_DEBUG("[burn_fw_boot]step6:select bank3");
- ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]select bank3 fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step7:burn 2k bootloader firmware
- GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
- ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
- goto exit_burn_fw_boot;
- }
-
- //step7:send burn cmd to move data to flash from sram
- GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
- goto exit_burn_fw_boot;
- }
- GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
- do{
- ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]Get burn state fail");
- goto exit_burn_fw_boot;
- }
- msleep(10);
- //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
- }while(rd_buf[GTP_ADDR_LENGTH]);
-
- //step8:recall check 2k bootloader firmware
- GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
- ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
- if(FAIL == ret)
- {
- GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
- goto exit_burn_fw_boot;
- }
-
- //step9:enable download DSP code
- GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- //step10:release ss51 & hold dsp
- GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
- ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
- if(ret <= 0)
- {
- GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
- ret = FAIL;
- goto exit_burn_fw_boot;
- }
-
- ret = SUCCESS;
-
+ s32 ret = 0;
+ u8 *fw_boot = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+ /* step1:Alloc memory */
+ GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+ while (retry++ < 5) {
+ fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+ if (fw_boot == NULL) {
+ continue;
+ } else {
+ GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.",
+ (FW_BOOT_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware bootloader */
+ GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+ ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH +
+ FW_DSP_LENGTH), FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step3:hold ss51 & dsp */
+ GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step4:set scramble */
+ GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step5:release ss51 & dsp */
+ GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+ /* must delay */
+ msleep(20);
+
+ /* step6:select bank3 */
+ GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step7:burn 2k bootloader firmware */
+ GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+ ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step7:send burn cmd to move data to flash from sram */
+ GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to",
+ "flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+ goto exit_burn_fw_boot;
+ }
+ GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]Get burn state fail");
+ goto exit_burn_fw_boot;
+ }
+ msleep(20);
+ /* GTP_DEBUG("[burn_fw_boot]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:recall check 2k bootloader firmware */
+ GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+ ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step9:enable download DSP code */
+ GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step10:release ss51 & hold dsp */
+ GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+ if (ret <= 0) {
+ GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ ret = SUCCESS;
+
exit_burn_fw_boot:
- kfree(fw_boot);
- return ret;
+ kfree(fw_boot);
+ return ret;
}
s32 gup_update_proc(void *dir)
{
- s32 ret = 0;
- u8 retry = 0;
- st_fw_head fw_head;
- struct goodix_ts_data *ts = NULL;
-
- GTP_DEBUG("[update_proc]Begin update ......");
-
- show_len = 1;
- total_len = 100;
- if(dir == NULL)
- {
- msleep(3000); //wait main thread to be completed
- }
-
- ts = i2c_get_clientdata(i2c_connect_client);
-
- if (searching_file)
- {
- searching_file = 0; // exit .bin update file searching
- GTP_INFO("Exiting searching .bin update file...");
- while ((show_len != 200) && (show_len != 100)) // wait for auto update quitted completely
- {
- msleep(100);
- }
- }
-
- update_msg.file = NULL;
- ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir); //20121211
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]check update file fail.");
- goto file_fail;
- }
-
- //gtp_reset_guitar(i2c_connect_client, 20);
- ret = gup_get_ic_fw_msg(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]get ic message fail.");
- goto file_fail;
- }
-
- ret = gup_enter_update_judge(&fw_head);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]Check *.bin file fail.");
- goto file_fail;
- }
-
- ts->enter_update = 1;
- gtp_irq_disable(ts);
+ s32 ret = 0;
+ u8 retry = 0;
+ st_fw_head fw_head;
+ struct goodix_ts_data *ts = NULL;
+
+ GTP_DEBUG("[update_proc]Begin update ......");
+
+ show_len = 1;
+ total_len = 100;
+ if (dir == NULL)
+ /* wait main thread to be completed */
+ msleep(3000);
+
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ if (searching_file) {
+ /* exit .bin update file searching */
+ searching_file = 0;
+ GTP_INFO("Exiting searching .bin update file...");
+ /* wait for auto update quitted completely */
+ while ((show_len != 200) && (show_len != 100))
+ msleep(100);
+ }
+
+ update_msg.file = NULL;
+ ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]check update file fail.");
+ goto file_fail;
+ }
+
+ /* gtp_reset_guitar(i2c_connect_client, 20); */
+ ret = gup_get_ic_fw_msg(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]get ic message fail.");
+ goto file_fail;
+ }
+
+ ret = gup_enter_update_judge(&fw_head);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]Check *.bin file fail.");
+ goto file_fail;
+ }
+
+ ts->enter_update = 1;
+ gtp_irq_disable(ts);
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_OFF);
+ gtp_esd_switch(ts->client, SWITCH_OFF);
#endif
- ret = gup_enter_update_mode(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]enter update mode fail.");
- goto update_fail;
- }
-
- while(retry++ < 5)
- {
- show_len = 10;
- total_len = 100;
- ret = gup_burn_dsp_isp(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn dsp isp fail.");
- continue;
- }
-
- show_len += 10;
- ret = gup_burn_fw_ss51(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn ss51 firmware fail.");
- continue;
- }
-
- show_len += 40;
- ret = gup_burn_fw_dsp(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn dsp firmware fail.");
- continue;
- }
-
- show_len += 20;
- ret = gup_burn_fw_boot(i2c_connect_client);
- if(FAIL == ret)
- {
- GTP_ERROR("[update_proc]burn bootloader firmware fail.");
- continue;
- }
- show_len += 10;
- GTP_INFO("[update_proc]UPDATE SUCCESS.");
- break;
- }
- if(retry >= 5)
- {
- GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
- goto update_fail;
- }
-
- GTP_DEBUG("[update_proc]leave update mode.");
- gup_leave_update_mode();
-
- msleep(100);
-// GTP_DEBUG("[update_proc]send config.");
-// ret = gtp_send_cfg(i2c_connect_client);
-// if(ret < 0)
-// {
-// GTP_ERROR("[update_proc]send config fail.");
-// }
- if (ts->fw_error)
- {
- GTP_INFO("firmware error auto update, resent config!");
- gup_init_panel(ts);
- }
- show_len = 100;
- total_len = 100;
- ts->enter_update = 0;
- gtp_irq_enable(ts);
-
+ ret = gup_enter_update_mode(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]enter update mode fail.");
+ goto update_fail;
+ }
+
+ while (retry++ < 5) {
+ show_len = 10;
+ total_len = 100;
+ ret = gup_burn_dsp_isp(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn dsp isp fail.");
+ continue;
+ }
+
+ show_len += 10;
+ ret = gup_burn_fw_ss51(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+ continue;
+ }
+
+ show_len += 40;
+ ret = gup_burn_fw_dsp(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn dsp firmware fail.");
+ continue;
+ }
+
+ show_len += 20;
+ ret = gup_burn_fw_boot(i2c_connect_client);
+ if (ret == FAIL) {
+ GTP_ERROR("[update_proc]burn bootloader fw fail.");
+ continue;
+ }
+ show_len += 10;
+ GTP_INFO("[update_proc]UPDATE SUCCESS.");
+ break;
+ }
+ if (retry >= 5) {
+ GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+ goto update_fail;
+ }
+
+ GTP_DEBUG("[update_proc]leave update mode.");
+ gup_leave_update_mode();
+
+ msleep(100);
+
+ /* GTP_DEBUG("[update_proc]send config.");
+ * ret = gtp_send_cfg(i2c_connect_client);
+ * if(ret < 0) {
+ * GTP_ERROR("[update_proc]send config fail.");
+ * }
+ */
+
+ if (ts->fw_error) {
+ GTP_INFO("firmware error auto update, resent config!");
+ gup_init_panel(ts);
+ }
+ show_len = 100;
+ total_len = 100;
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_ON);
+ gtp_esd_switch(ts->client, SWITCH_ON);
#endif
- filp_close(update_msg.file, NULL);
- return SUCCESS;
-
+ filp_close(update_msg.file, NULL);
+ return SUCCESS;
+
update_fail:
- ts->enter_update = 0;
- gtp_irq_enable(ts);
-
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
#if GTP_ESD_PROTECT
- gtp_esd_switch(ts->client, SWITCH_ON);
+ gtp_esd_switch(ts->client, SWITCH_ON);
#endif
file_fail:
- if(update_msg.file && !IS_ERR(update_msg.file))
- {
- filp_close(update_msg.file, NULL);
- }
- show_len = 200;
- total_len = 100;
- return FAIL;
+ if (update_msg.file && !IS_ERR(update_msg.file))
+ filp_close(update_msg.file, NULL);
+
+ show_len = 200;
+ total_len = 100;
+ return FAIL;
}
#if GTP_AUTO_UPDATE
u8 gup_init_update_proc(struct goodix_ts_data *ts)
{
- struct task_struct *thread = NULL;
+ struct task_struct *thread = NULL;
- GTP_INFO("Ready to run update thread.");
- thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update");
- if (IS_ERR(thread))
- {
- GTP_ERROR("Failed to create update thread.\n");
- return -1;
- }
+ GTP_INFO("Ready to run update thread.");
+ thread = kthread_run(gup_update_proc, (void *)NULL, "guitar_update");
+ if (IS_ERR(thread)) {
+ GTP_ERROR("Failed to create update thread.\n");
+ return -EINVAL;
+ }
- return 0;
+ return 0;
}
-#endif \ No newline at end of file
+#endif
diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c
index 9080a13069a8..88b1d3c013c7 100644
--- a/drivers/input/touchscreen/it7258_ts_i2c.c
+++ b/drivers/input/touchscreen/it7258_ts_i2c.c
@@ -117,6 +117,7 @@
#define PD_FLAGS_DATA_TYPE_BITS 0xF0
/* other types (like chip-detected gestures) exist but we do not care */
#define PD_FLAGS_DATA_TYPE_TOUCH 0x00
+#define PD_FLAGS_IDLE_TO_ACTIVE 0x10
/* a bit for each finger data that is valid (from lsb to msb) */
#define PD_FLAGS_HAVE_FINGERS 0x07
#define PD_PALM_FLAG_BIT 0x01
@@ -137,15 +138,15 @@
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
struct finger_data {
- uint8_t xLo;
- uint8_t hi;
- uint8_t yLo;
- uint8_t pressure;
+ u8 xLo;
+ u8 hi;
+ u8 yLo;
+ u8 pressure;
} __packed;
struct point_data {
- uint8_t flags;
- uint8_t palm;
+ u8 flags;
+ u8 gesture_id;
struct finger_data fd[3];
} __packed;
@@ -179,7 +180,7 @@ struct it7260_ts_data {
const struct it7260_ts_platform_data *pdata;
struct regulator *vdd;
struct regulator *avdd;
- bool device_needs_wakeup;
+ bool in_low_power_mode;
bool suspended;
bool fw_upgrade_result;
bool cfg_upgrade_result;
@@ -743,18 +744,31 @@ out:
static int it7260_ts_chip_low_power_mode(struct it7260_ts_data *ts_data,
const u8 sleep_type)
{
- const uint8_t cmd_sleep[] = {CMD_PWR_CTL, 0x00, sleep_type};
- uint8_t dummy;
+ const u8 cmd_sleep[] = {CMD_PWR_CTL, 0x00, sleep_type};
+ u8 dummy;
+ int ret;
- if (sleep_type)
- it7260_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_sleep,
- sizeof(cmd_sleep));
- else
- it7260_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dummy,
+ if (sleep_type) {
+ ret = it7260_i2c_write_no_ready_check(ts_data, BUF_COMMAND,
+ cmd_sleep, sizeof(cmd_sleep));
+ if (ret != IT_I2C_WRITE_RET)
+ dev_err(&ts_data->client->dev,
+ "Can't go to sleep or low power mode(%d) %d\n",
+ sleep_type, ret);
+ else
+ ret = 0;
+ } else {
+ ret = it7260_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dummy,
sizeof(dummy));
+ if (ret != IT_I2C_READ_RET)
+ dev_err(&ts_data->client->dev,
+ "Can't go to active mode %d\n", ret);
+ else
+ ret = 0;
+ }
msleep(WAIT_CHANGE_MODE);
- return 0;
+ return ret;
}
static ssize_t sysfs_fw_upgrade_store(struct device *dev,
@@ -1226,18 +1240,28 @@ static irqreturn_t it7260_ts_threaded_handler(int irq, void *devid)
* schedule a work that tells the pm core to relax once the CPU
* cores are up.
*/
- if (ts_data->device_needs_wakeup) {
+ if ((pt_data.flags & PD_FLAGS_DATA_TYPE_BITS) ==
+ PD_FLAGS_IDLE_TO_ACTIVE &&
+ pt_data.gesture_id == 0) {
pm_stay_awake(&ts_data->client->dev);
input_report_key(input_dev, KEY_WAKEUP, 1);
input_sync(input_dev);
input_report_key(input_dev, KEY_WAKEUP, 0);
input_sync(input_dev);
schedule_work(&ts_data->work_pm_relax);
- return IRQ_HANDLED;
+ } else {
+ dev_dbg(&ts_data->client->dev,
+ "Ignore the touch data\n");
}
+ return IRQ_HANDLED;
}
- palm_detected = pt_data.palm & PD_PALM_FLAG_BIT;
+ /*
+ * Check if touch data also includes any palm gesture or not.
+ * If palm gesture is detected, then send the keycode parsed
+ * from the DT.
+ */
+ palm_detected = pt_data.gesture_id & PD_PALM_FLAG_BIT;
if (palm_detected && ts_data->pdata->palm_detect_en) {
input_report_key(input_dev,
ts_data->pdata->palm_detect_keycode, 1);
@@ -2084,7 +2108,7 @@ static int it7260_ts_resume(struct device *dev)
int retval;
if (device_may_wakeup(dev)) {
- if (ts_data->device_needs_wakeup) {
+ if (ts_data->in_low_power_mode) {
/* Set active current for the avdd regulator */
if (ts_data->pdata->avdd_lpm_cur) {
retval = reg_set_optimum_mode_check(
@@ -2095,7 +2119,7 @@ static int it7260_ts_resume(struct device *dev)
retval);
}
- ts_data->device_needs_wakeup = false;
+ ts_data->in_low_power_mode = false;
disable_irq_wake(ts_data->client->irq);
}
return 0;
@@ -2130,10 +2154,13 @@ static int it7260_ts_suspend(struct device *dev)
}
if (device_may_wakeup(dev)) {
- if (!ts_data->device_needs_wakeup) {
+ if (!ts_data->in_low_power_mode) {
/* put the device in low power idle mode */
- it7260_ts_chip_low_power_mode(ts_data,
+ retval = it7260_ts_chip_low_power_mode(ts_data,
PWR_CTL_LOW_POWER_MODE);
+ if (retval)
+ dev_err(dev, "Can't go to low power mode %d\n",
+ retval);
/* Set lpm current for avdd regulator */
if (ts_data->pdata->avdd_lpm_cur) {
@@ -2145,7 +2172,7 @@ static int it7260_ts_suspend(struct device *dev)
retval);
}
- ts_data->device_needs_wakeup = true;
+ ts_data->in_low_power_mode = true;
enable_irq_wake(ts_data->client->irq);
}
return 0;
diff --git a/drivers/input/touchscreen/msg21xx_ts.c b/drivers/input/touchscreen/msg21xx_ts.c
index 8f2c4da578fc..fe8c6e1647f8 100644
--- a/drivers/input/touchscreen/msg21xx_ts.c
+++ b/drivers/input/touchscreen/msg21xx_ts.c
@@ -30,10 +30,8 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/firmware.h>
-#include <linux/string.h>
-#include <linux/kthread.h>
+#include <linux/debugfs.h>
#include <linux/regulator/consumer.h>
#if defined(CONFIG_FB)
@@ -67,6 +65,13 @@
#define MSTAR_CHIPTOP_REGISTER_BANK 0x1E
#define MSTAR_CHIPTOP_REGISTER_ICTYPE 0xCC
#define MSTAR_INIT_SW_ID 0x7FF
+#define MSTAR_DEBUG_DIR_NAME "ts_debug"
+
+#define MSG_FW_FILE_MAJOR_VERSION(x) \
+ (((x)->data[0x7f4f] << 8) + ((x)->data[0x7f4e]))
+
+#define MSG_FW_FILE_MINOR_VERSION(x) \
+ (((x)->data[0x7f51] << 8) + ((x)->data[0x7f50]))
/*
* Note.
@@ -89,7 +94,6 @@ static unsigned char MSG_FIRMWARE[1][33*1024] = { {
#endif
#define CONFIG_TP_HAVE_KEY
-
#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
@@ -97,30 +101,16 @@ static unsigned char MSG_FIRMWARE[1][33*1024] = { {
#define SLAVE_I2C_ID_DBBUS (0xC4>>1)
#define DEMO_MODE_PACKET_LENGTH (8)
-#define MAX_TOUCH_NUM (2)
#define TP_PRINT
-#ifdef TP_PRINT
-static int tp_print_proc_read(void);
-static void tp_print_create_entry(void);
-#endif
static char *fw_version; /* customer firmware version */
static unsigned short fw_version_major;
static unsigned short fw_version_minor;
static unsigned char temp[94][1024];
static unsigned int crc32_table[256];
-static int FwDataCnt;
-static unsigned char bFwUpdating;
-static struct class *firmware_class;
-static struct device *firmware_cmd_dev;
-static struct i2c_client *i2c_client;
-
-static u32 button_map[MAX_BUTTONS];
-static u32 num_buttons;
-
-static unsigned short update_bin_major, update_bin_minor;
+static unsigned short fw_file_major, fw_file_minor;
static unsigned short main_sw_id = MSTAR_INIT_SW_ID;
static unsigned short info_sw_id = MSTAR_INIT_SW_ID;
static unsigned int bin_conf_crc32;
@@ -128,15 +118,12 @@ static unsigned int bin_conf_crc32;
struct msg21xx_ts_platform_data {
const char *name;
char fw_name[MSTAR_FW_NAME_MAX_LEN];
- char *fw_version;
- unsigned short fw_version_major;
- unsigned short fw_version_minor;
- u32 irqflags;
+ u8 fw_version_major;
+ u8 fw_version_minor;
u32 irq_gpio;
u32 irq_gpio_flags;
u32 reset_gpio;
u32 reset_gpio_flags;
- u32 family_id;
u32 x_max;
u32 y_max;
u32 x_min;
@@ -153,26 +140,33 @@ struct msg21xx_ts_platform_data {
int (*power_on)(bool);
int (*power_init)(bool);
int (*power_on)(bool);
+ u8 ic_type;
+ u32 button_map[MAX_BUTTONS];
+ u32 num_buttons;
+ u32 hard_reset_delay_ms;
+ u32 post_hard_reset_delay_ms;
+ bool updating_fw;
+};
+
+/* Touch Data Type Definition */
+struct touchPoint_t {
+ unsigned short x;
+ unsigned short y;
};
-static struct msg21xx_ts_platform_data *pdata;
+struct touchInfo_t {
+ struct touchPoint_t *point;
+ unsigned char count;
+ unsigned char keycode;
+};
struct msg21xx_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
- const struct msg21xx_ts_platform_data *pdata;
+ struct msg21xx_ts_platform_data *pdata;
struct regulator *vdd;
struct regulator *vcc_i2c;
- bool loading_fw;
- u8 family_id;
- struct dentry *dir;
- u16 addr;
bool suspended;
- char *ts_info;
- u8 *tch_data;
- u32 tch_data_len;
- u8 fw_ver[3];
- u8 fw_vendor_id;
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
#endif
@@ -181,10 +175,9 @@ struct msg21xx_ts_data {
struct pinctrl_state *pinctrl_state_suspend;
struct pinctrl_state *pinctrl_state_release;
struct mutex ts_mutex;
+ struct touchInfo_t info;
};
-static struct msg21xx_ts_data *ts_data;
-
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data);
@@ -195,23 +188,15 @@ static unsigned char bEnableTpProximity;
static unsigned char bFaceClosingTp;
#endif
-static struct mutex msg21xx_mutex;
-static struct input_dev *input_dev;
-
-
-/* Data Type Definition */
+#ifdef TP_PRINT
+static int tp_print_proc_read(struct msg21xx_ts_data *ts_data);
+static void tp_print_create_entry(struct msg21xx_ts_data *ts_data);
+#endif
-struct touchPoint_t {
- unsigned short x;
- unsigned short y;
-};
-
-struct touchInfo_t {
- struct touchPoint_t point[MAX_TOUCH_NUM];
- unsigned char count;
- unsigned char keycode;
-};
+static void _ReadBinConfig(struct msg21xx_ts_data *ts_data);
+static unsigned int _CalMainCRC32(struct msg21xx_ts_data *ts_data);
+static struct mutex msg21xx_mutex;
enum EMEM_TYPE_t {
EMEM_ALL = 0,
@@ -259,26 +244,25 @@ static void _CRC_initTable(void)
}
}
-static void reset_hw(void)
+static void msg21xx_reset_hw(struct msg21xx_ts_platform_data *pdata)
{
- DBG("reset_hw()\n");
-
gpio_direction_output(pdata->reset_gpio, 1);
gpio_set_value_cansleep(pdata->reset_gpio, 0);
- msleep(100); /* Note that the RST must be in LOW 10ms at least */
+ /* Note that the RST must be in LOW 10ms at least */
+ usleep(pdata->hard_reset_delay_ms * 1000);
gpio_set_value_cansleep(pdata->reset_gpio, 1);
/* Enable the interrupt service thread/routine for INT after 50ms */
- msleep(100);
+ usleep(pdata->post_hard_reset_delay_ms * 1000);
}
-static int read_i2c_seq(unsigned char addr, unsigned char *buf,
- unsigned short size)
+static int read_i2c_seq(struct msg21xx_ts_data *ts_data, unsigned char addr,
+ unsigned char *buf, unsigned short size)
{
int rc = 0;
struct i2c_msg msgs[] = {
{
.addr = addr,
- .flags = I2C_M_RD, /* read flag*/
+ .flags = I2C_M_RD, /* read flag */
.len = size,
.buf = buf,
},
@@ -287,25 +271,27 @@ static int read_i2c_seq(unsigned char addr, unsigned char *buf,
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
* transmitted, else error code.
*/
- if (i2c_client != NULL) {
- rc = i2c_transfer(i2c_client->adapter, msgs, 1);
+ if (ts_data->client != NULL) {
+ rc = i2c_transfer(ts_data->client->adapter, msgs, 1);
if (rc < 0)
- DBG("read_i2c_seq() error %d\n", rc);
+ dev_err(&ts_data->client->dev,
+ "%s error %d\n", __func__, rc);
} else {
- DBG("i2c_client is NULL\n");
+ dev_err(&ts_data->client->dev, "ts_data->client is NULL\n");
}
return rc;
}
-static int write_i2c_seq(unsigned char addr, unsigned char *buf,
- unsigned short size)
+static int write_i2c_seq(struct msg21xx_ts_data *ts_data, unsigned char addr,
+ unsigned char *buf, unsigned short size)
{
int rc = 0;
struct i2c_msg msgs[] = {
{
.addr = addr,
- /* if read flag is undefined,
+ /*
+ * if read flag is undefined,
* then it means write flag.
*/
.flags = 0,
@@ -314,48 +300,55 @@ static int write_i2c_seq(unsigned char addr, unsigned char *buf,
},
};
- /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ /*
+ * If everything went ok (i.e. 1 msg transmitted), return #bytes
* transmitted, else error code.
*/
- if (i2c_client != NULL) {
- rc = i2c_transfer(i2c_client->adapter, msgs, 1);
+ if (ts_data->client != NULL) {
+ rc = i2c_transfer(ts_data->client->adapter, msgs, 1);
if (rc < 0)
- DBG("write_i2c_seq() error %d\n", rc);
+ dev_err(&ts_data->client->dev,
+ "%s error %d\n", __func__, rc);
} else {
- DBG("i2c_client is NULL\n");
+ dev_err(&ts_data->client->dev, "ts_data->client is NULL\n");
}
return rc;
}
-static unsigned short read_reg(unsigned char bank, unsigned char addr)
+static unsigned short read_reg(struct msg21xx_ts_data *ts_data,
+ unsigned char bank, unsigned char addr)
{
unsigned char tx_data[3] = {0x10, bank, addr};
unsigned char rx_data[2] = {0};
- write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 3);
- read_i2c_seq(SLAVE_I2C_ID_DBBUS, &rx_data[0], 2);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data));
+ read_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, rx_data, sizeof(rx_data));
return rx_data[1] << 8 | rx_data[0];
}
-static void write_reg(unsigned char bank, unsigned char addr,
+static void write_reg(struct msg21xx_ts_data *ts_data, unsigned char bank,
+ unsigned char addr,
unsigned short data)
{
unsigned char tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8};
write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 5);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data));
}
-static void write_reg_8bit(unsigned char bank, unsigned char addr,
+static void write_reg_8bit(struct msg21xx_ts_data *ts_data, unsigned char bank,
+ unsigned char addr,
unsigned char data)
{
unsigned char tx_data[4] = {0x10, bank, addr, data};
write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 4);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, tx_data, sizeof(tx_data));
}
-static void dbbusDWIICEnterSerialDebugMode(void)
+static void dbbusDWIICEnterSerialDebugMode(struct msg21xx_ts_data *ts_data)
{
unsigned char data[5];
@@ -366,120 +359,109 @@ static void dbbusDWIICEnterSerialDebugMode(void)
data[3] = 0x44;
data[4] = 0x42;
- write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 5);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data));
}
-static void dbbusDWIICStopMCU(void)
+static void dbbusDWIICStopMCU(struct msg21xx_ts_data *ts_data)
{
unsigned char data[1];
/* Stop the MCU */
data[0] = 0x37;
- write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data));
}
-static void dbbusDWIICIICUseBus(void)
+static void dbbusDWIICIICUseBus(struct msg21xx_ts_data *ts_data)
{
unsigned char data[1];
/* IIC Use Bus */
data[0] = 0x35;
- write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data));
}
-static void dbbusDWIICIICReshape(void)
+static void dbbusDWIICIICReshape(struct msg21xx_ts_data *ts_data)
{
unsigned char data[1];
/* IIC Re-shape */
data[0] = 0x71;
- write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+ write_i2c_seq(ts_data, SLAVE_I2C_ID_DBBUS, data, sizeof(data));
}
-static unsigned char get_ic_type(void)
+static unsigned char msg21xx_get_ic_type(struct msg21xx_ts_data *ts_data)
{
unsigned char ic_type = 0;
unsigned char bank;
unsigned char addr;
- reset_hw();
- dbbusDWIICEnterSerialDebugMode();
- dbbusDWIICStopMCU();
- dbbusDWIICIICUseBus();
- dbbusDWIICIICReshape();
+ msg21xx_reset_hw(ts_data->pdata);
+ dbbusDWIICEnterSerialDebugMode(ts_data);
+ dbbusDWIICStopMCU(ts_data);
+ dbbusDWIICIICUseBus(ts_data);
+ dbbusDWIICIICReshape(ts_data);
msleep(300);
/* stop mcu */
- write_reg_8bit(0x0F, 0xE6, 0x01);
+ write_reg_8bit(ts_data, 0x0F, 0xE6, 0x01);
/* disable watch dog */
- write_reg(0x3C, 0x60, 0xAA55);
+ write_reg(ts_data, 0x3C, 0x60, 0xAA55);
/* get ic type */
bank = MSTAR_CHIPTOP_REGISTER_BANK;
addr = MSTAR_CHIPTOP_REGISTER_ICTYPE;
- ic_type = (0xff)&(read_reg(bank, addr));
+ ic_type = (0xff)&(read_reg(ts_data, bank, addr));
- if (ic_type != 1 /* msg2133 */
- && ic_type != 2 /* msg21xxA */
- && ic_type != 3) /* msg26xxM */ {
+ if (ic_type != ts_data->pdata->ic_type)
ic_type = 0;
- }
- reset_hw();
+ msg21xx_reset_hw(ts_data->pdata);
return ic_type;
}
-static int msg21xx_read_firmware_id(void)
+static int msg21xx_read_firmware_id(struct msg21xx_ts_data *ts_data)
{
- unsigned char dbbus_tx_data[3] = {0};
- unsigned char dbbus_rx_data[4] = {0};
- int ret = 0;
+ unsigned char command[3] = { 0x53, 0x00, 0x2A};
+ unsigned char response[4] = { 0 };
- dbbus_tx_data[0] = 0x53;
- dbbus_tx_data[1] = 0x00;
- dbbus_tx_data[2] = 0x2A;
mutex_lock(&msg21xx_mutex);
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4);
+ write_i2c_seq(ts_data, ts_data->client->addr, command, sizeof(command));
+ read_i2c_seq(ts_data, ts_data->client->addr, response,
+ sizeof(response));
mutex_unlock(&msg21xx_mutex);
- pdata->fw_version_major = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0];
- pdata->fw_version_minor = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2];
-
- dev_dbg(&i2c_client->dev, "major num = %d, minor num = %d\n",
- pdata->fw_version_major, pdata->fw_version_minor);
-
- if (pdata->fw_version == NULL)
- pdata->fw_version = kzalloc(sizeof(char), GFP_KERNEL);
+ ts_data->pdata->fw_version_major = (response[1]<<8) + response[0];
+ ts_data->pdata->fw_version_minor = (response[3]<<8) + response[2];
- snprintf(pdata->fw_version, sizeof(char) * 7, "%03d%03d",
- pdata->fw_version_major,
- pdata->fw_version_minor);
+ dev_info(&ts_data->client->dev, "major num = %d, minor num = %d\n",
+ ts_data->pdata->fw_version_major,
+ ts_data->pdata->fw_version_minor);
- return ret;
+ return 0;
}
-static int firmware_erase_c33(enum EMEM_TYPE_t emem_type)
+static int firmware_erase_c33(struct msg21xx_ts_data *ts_data,
+ enum EMEM_TYPE_t emem_type)
{
/* stop mcu */
- write_reg(0x0F, 0xE6, 0x0001);
+ write_reg(ts_data, 0x0F, 0xE6, 0x0001);
/* disable watch dog */
- write_reg_8bit(0x3C, 0x60, 0x55);
- write_reg_8bit(0x3C, 0x61, 0xAA);
+ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55);
+ write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA);
/* set PROGRAM password */
- write_reg_8bit(0x16, 0x1A, 0xBA);
- write_reg_8bit(0x16, 0x1B, 0xAB);
+ write_reg_8bit(ts_data, 0x16, 0x1A, 0xBA);
+ write_reg_8bit(ts_data, 0x16, 0x1B, 0xAB);
- write_reg_8bit(0x16, 0x18, 0x80);
+ write_reg_8bit(ts_data, 0x16, 0x18, 0x80);
if (emem_type == EMEM_ALL)
- write_reg_8bit(0x16, 0x08, 0x10);
+ write_reg_8bit(ts_data, 0x16, 0x08, 0x10);
- write_reg_8bit(0x16, 0x18, 0x40);
+ write_reg_8bit(ts_data, 0x16, 0x18, 0x40);
msleep(20);
/* clear pce */
@@ -487,7 +469,7 @@ static int firmware_erase_c33(enum EMEM_TYPE_t emem_type)
/* erase trigger */
if (emem_type == EMEM_MAIN)
- write_reg_8bit(0x16, 0x0E, 0x04); /* erase main */
+ write_reg_8bit(ts_data, 0x16, 0x0E, 0x04); /* erase main */
else
write_reg_8bit(0x16, 0x0E, 0x08); /* erase all block */
@@ -513,7 +495,9 @@ static int check_fw_update(void)
}
}
return ret;
+ write_reg_8bit(ts_data, 0x16, 0x0E, 0x08); /* erase all block */
+ return 0;
}
static ssize_t firmware_update_c33(struct device *dev,
@@ -526,71 +510,85 @@ static ssize_t firmware_update_c33(struct device *dev,
unsigned int crc_info, crc_info_tp;
unsigned short reg_data = 0;
int update_pass = 1;
+ bool fw_upgrade = false;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
crc_main = 0xffffffff;
crc_info = 0xffffffff;
- reset_hw();
+ msg21xx_reset_hw(ts_data->pdata);
- if (!check_fw_update() && !isForce) {
- DBG("****no need to update\n");
- reset_hw();
- FwDataCnt = 0;
+ msg21xx_read_firmware_id(ts_data);
+ _ReadBinConfig(ts_data);
+ if ((main_sw_id == info_sw_id) &&
+ (_CalMainCRC32(ts_data) == bin_conf_crc32) &&
+ (fw_file_major == ts_data->pdata->fw_version_major) &&
+ (fw_file_minor > ts_data->pdata->fw_version_minor)) {
+ fw_upgrade = true;
+ }
+
+ if (!fw_upgrade && !isForce) {
+ dev_dbg(dev, "no need to update\n");
+ msg21xx_reset_hw(ts_data->pdata);
return size;
}
- reset_hw();
+ msg21xx_reset_hw(ts_data->pdata);
msleep(300);
- dbbusDWIICEnterSerialDebugMode();
- dbbusDWIICStopMCU();
- dbbusDWIICIICUseBus();
- dbbusDWIICIICReshape();
+ dbbusDWIICEnterSerialDebugMode(ts_data);
+ dbbusDWIICStopMCU(ts_data);
+ dbbusDWIICIICUseBus(ts_data);
+ dbbusDWIICIICReshape(ts_data);
msleep(300);
/* erase main */
- firmware_erase_c33(EMEM_MAIN);
+ firmware_erase_c33(ts_data, EMEM_MAIN);
msleep(1000);
- reset_hw();
- dbbusDWIICEnterSerialDebugMode();
- dbbusDWIICStopMCU();
- dbbusDWIICIICUseBus();
- dbbusDWIICIICReshape();
+ msg21xx_reset_hw(ts_data->pdata);
+ dbbusDWIICEnterSerialDebugMode(ts_data);
+ dbbusDWIICStopMCU(ts_data);
+ dbbusDWIICIICUseBus(ts_data);
+ dbbusDWIICIICReshape(ts_data);
msleep(300);
-
+ /*
+ * Program
+ */
/* polling 0x3CE4 is 0x1C70 */
if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) {
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0x1C70);
}
switch (emem_type) {
case EMEM_ALL:
- write_reg(0x3C, 0xE4, 0xE38F); /* for all-blocks */
+ write_reg(ts_data, 0x3C, 0xE4, 0xE38F); /* for all-blocks */
break;
case EMEM_MAIN:
- write_reg(0x3C, 0xE4, 0x7731); /* for main block */
+ write_reg(ts_data, 0x3C, 0xE4, 0x7731); /* for main block */
break;
case EMEM_INFO:
- write_reg(0x3C, 0xE4, 0x7731); /* for info block */
+ write_reg(ts_data, 0x3C, 0xE4, 0x7731); /* for info block */
- write_reg_8bit(0x0F, 0xE6, 0x01);
+ write_reg_8bit(ts_data, 0x0F, 0xE6, 0x01);
- write_reg_8bit(0x3C, 0xE4, 0xC5);
- write_reg_8bit(0x3C, 0xE5, 0x78);
+ write_reg_8bit(ts_data, 0x3C, 0xE4, 0xC5);
+ write_reg_8bit(ts_data, 0x3C, 0xE5, 0x78);
- write_reg_8bit(MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x9F);
- write_reg_8bit(MSTAR_CHIPTOP_REGISTER_BANK, 0x05, 0x82);
+ write_reg_8bit(ts_data, MSTAR_CHIPTOP_REGISTER_BANK,
+ 0x04, 0x9F);
+ write_reg_8bit(ts_data, MSTAR_CHIPTOP_REGISTER_BANK,
+ 0x05, 0x82);
- write_reg_8bit(0x0F, 0xE6, 0x00);
+ write_reg_8bit(ts_data, 0x0F, 0xE6, 0x00);
msleep(100);
break;
}
/* polling 0x3CE4 is 0x2F43 */
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0x2F43);
/* calculate CRC 32 */
@@ -612,28 +610,28 @@ static ssize_t firmware_update_c33(struct device *dev,
}
for (j = 0; j < 8; j++)
- write_i2c_seq(ts_data->client->addr,
+ write_i2c_seq(ts_data, ts_data->client->addr,
&fw_bin_data[i][j * 128], 128);
msleep(100);
/* polling 0x3CE4 is 0xD0BC */
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0xD0BC);
- write_reg(0x3C, 0xE4, 0x2F43);
+ write_reg(ts_data, 0x3C, 0xE4, 0x2F43);
}
if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) {
/* write file done and check crc */
- write_reg(0x3C, 0xE4, 0x1380);
+ write_reg(ts_data, 0x3C, 0xE4, 0x1380);
}
msleep(20);
if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) {
/* polling 0x3CE4 is 0x9432 */
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0x9432);
}
@@ -642,12 +640,14 @@ static ssize_t firmware_update_c33(struct device *dev,
if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) {
/* CRC Main from TP */
- crc_main_tp = read_reg(0x3C, 0x80);
- crc_main_tp = (crc_main_tp << 16) | read_reg(0x3C, 0x82);
+ crc_main_tp = read_reg(ts_data, 0x3C, 0x80);
+ crc_main_tp = (crc_main_tp << 16) |
+ read_reg(ts_data, 0x3C, 0x82);
/* CRC Info from TP */
- crc_info_tp = read_reg(0x3C, 0xA0);
- crc_info_tp = (crc_info_tp << 16) | read_reg(0x3C, 0xA2);
+ crc_info_tp = read_reg(ts_data, 0x3C, 0xA0);
+ crc_info_tp = (crc_info_tp << 16) |
+ read_reg(ts_data, 0x3C, 0xA2);
}
update_pass = 1;
@@ -657,94 +657,93 @@ static ssize_t firmware_update_c33(struct device *dev,
}
if (!update_pass) {
- DBG("update_C33 failed\n");
- reset_hw();
- FwDataCnt = 0;
+ dev_err(dev, "update_C33 failed\n");
+ msg21xx_reset_hw(ts_data->pdata);
return 0;
}
- DBG("update_C33 OK\n");
- reset_hw();
- FwDataCnt = 0;
+ dev_dbg(dev, "update_C33 OK\n");
+ msg21xx_reset_hw(ts_data->pdata);
return size;
}
-static unsigned int _CalMainCRC32(void)
+static unsigned int _CalMainCRC32(struct msg21xx_ts_data *ts_data)
{
unsigned int ret = 0;
unsigned short reg_data = 0;
- reset_hw();
+ msg21xx_reset_hw(ts_data->pdata);
- dbbusDWIICEnterSerialDebugMode();
- dbbusDWIICStopMCU();
- dbbusDWIICIICUseBus();
- dbbusDWIICIICReshape();
+ dbbusDWIICEnterSerialDebugMode(ts_data);
+ dbbusDWIICStopMCU(ts_data);
+ dbbusDWIICIICUseBus(ts_data);
+ dbbusDWIICIICReshape(ts_data);
msleep(100);
/* Stop MCU */
- write_reg(0x0F, 0xE6, 0x0001);
+ write_reg(ts_data, 0x0F, 0xE6, 0x0001);
/* Stop Watchdog */
- write_reg_8bit(0x3C, 0x60, 0x55);
- write_reg_8bit(0x3C, 0x61, 0xAA);
+ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55);
+ write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA);
/* cmd */
- write_reg(0x3C, 0xE4, 0xDF4C);
- write_reg(0x1E, 0x04, 0x7d60);
+ write_reg(ts_data, 0x3C, 0xE4, 0xDF4C);
+ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60);
/* TP SW reset */
- write_reg(0x1E, 0x04, 0x829F);
+ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x829F);
/* MCU run */
- write_reg(0x0F, 0xE6, 0x0000);
+ write_reg(ts_data, 0x0F, 0xE6, 0x0000);
/* polling 0x3CE4 */
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0x9432);
/* Cal CRC Main from TP */
- ret = read_reg(0x3C, 0x80);
- ret = (ret << 16) | read_reg(0x3C, 0x82);
+ ret = read_reg(ts_data, 0x3C, 0x80);
+ ret = (ret << 16) | read_reg(ts_data, 0x3C, 0x82);
- DBG("[21xxA]:Current main crc32=0x%x\n", ret);
+ dev_dbg(&ts_data->client->dev,
+ "[21xxA]:Current main crc32=0x%x\n", ret);
return ret;
}
-static void _ReadBinConfig(void)
+static void _ReadBinConfig(struct msg21xx_ts_data *ts_data)
{
unsigned char dbbus_tx_data[5] = {0};
unsigned char dbbus_rx_data[4] = {0};
unsigned short reg_data = 0;
- reset_hw();
+ msg21xx_reset_hw(ts_data->pdata);
- dbbusDWIICEnterSerialDebugMode();
- dbbusDWIICStopMCU();
- dbbusDWIICIICUseBus();
- dbbusDWIICIICReshape();
+ dbbusDWIICEnterSerialDebugMode(ts_data);
+ dbbusDWIICStopMCU(ts_data);
+ dbbusDWIICIICUseBus(ts_data);
+ dbbusDWIICIICReshape(ts_data);
msleep(100);
/* Stop MCU */
- write_reg(0x0F, 0xE6, 0x0001);
+ write_reg(ts_data, 0x0F, 0xE6, 0x0001);
/* Stop Watchdog */
- write_reg_8bit(0x3C, 0x60, 0x55);
- write_reg_8bit(0x3C, 0x61, 0xAA);
+ write_reg_8bit(ts_data, 0x3C, 0x60, 0x55);
+ write_reg_8bit(ts_data, 0x3C, 0x61, 0xAA);
/* cmd */
- write_reg(0x3C, 0xE4, 0xA4AB);
- write_reg(MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60);
+ write_reg(ts_data, 0x3C, 0xE4, 0xA4AB);
+ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60);
+
/* TP SW reset */
- write_reg(0x1E, 0x04, 0x829F);
- /* TP SW reset*/
+ write_reg(ts_data, MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x829F);
/* MCU run */
- write_reg(0x0F, 0xE6, 0x0000);
+ write_reg(ts_data, 0x0F, 0xE6, 0x0000);
/* polling 0x3CE4 */
do {
- reg_data = read_reg(0x3C, 0xE4);
+ reg_data = read_reg(ts_data, 0x3C, 0xE4);
} while (reg_data != 0x5B58);
dbbus_tx_data[0] = 0x72;
@@ -752,8 +751,8 @@ static void _ReadBinConfig(void)
dbbus_tx_data[2] = 0x55;
dbbus_tx_data[3] = 0x00;
dbbus_tx_data[4] = 0x04;
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4);
+ write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5);
+ read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4);
if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39)
&& (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39)
&& (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) {
@@ -767,20 +766,20 @@ static void _ReadBinConfig(void)
dbbus_tx_data[2] = 0xFC;
dbbus_tx_data[3] = 0x00;
dbbus_tx_data[4] = 0x04;
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4);
- bin_conf_crc32 = dbbus_rx_data[0];
- bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[1];
- bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[2];
- bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[3];
+ write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5);
+ read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4);
+ bin_conf_crc32 = (dbbus_rx_data[0] << 24) |
+ (dbbus_rx_data[1] << 16) |
+ (dbbus_rx_data[2] << 8) |
+ (dbbus_rx_data[3]);
dbbus_tx_data[0] = 0x72;
dbbus_tx_data[1] = 0x83;
dbbus_tx_data[2] = 0x00;
dbbus_tx_data[3] = 0x00;
dbbus_tx_data[4] = 0x04;
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4);
+ write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 5);
+ read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4);
if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39)
&& (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39)
&& (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) {
@@ -789,18 +788,18 @@ static void _ReadBinConfig(void)
(dbbus_rx_data[2] - 0x30);
}
- DBG("[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32=0x%x\n",
- main_sw_id, info_sw_id, bin_conf_crc32);
+ dev_dbg(&ts_data->client->dev,
+ "[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32 = 0x%x\n",
+ main_sw_id, info_sw_id, bin_conf_crc32);
}
static ssize_t firmware_update_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- DBG("*** firmware_update_show() pdata->fw_version = %s ***\n",
- pdata->fw_version);
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- return snprintf(buf, sizeof(char) - 1, "%s\n", pdata->fw_version);
+ return snprintf(buf, 3, "%d\n", ts_data->pdata->updating_fw);
}
static ssize_t firmware_update_store(struct device *dev,
@@ -808,14 +807,15 @@ static ssize_t firmware_update_store(struct device *dev,
const char *buf,
size_t size)
{
- bFwUpdating = 1;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
+
+ ts_data->pdata->updating_fw = true;
disable_irq(ts_data->client->irq);
- DBG("*** update fw size = %d ***\n", FwDataCnt);
size = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false);
enable_irq(ts_data->client->irq);
- bFwUpdating = 0;
+ ts_data->pdata->updating_fw = false;
return size;
}
@@ -830,27 +830,24 @@ static int prepare_fw_data(struct device *dev)
int i;
int ret;
const struct firmware *fw = NULL;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- ret = request_firmware(&fw, pdata->fw_name, dev);
+ ret = request_firmware(&fw, ts_data->pdata->fw_name, dev);
if (ret < 0) {
dev_err(dev, "Request firmware failed - %s (%d)\n",
- pdata->fw_name, ret);
+ ts_data->pdata->fw_name, ret);
return ret;
}
- DBG("*** prepare_fw_data() ret = %d, size = %d***\n", ret, fw->size);
count = fw->size / 1024;
- for (i = 0; i < count; i++) {
- memcpy(fw_bin_data[FwDataCnt], fw->data + (i * 1024), 1024);
- FwDataCnt++;
- }
- update_bin_major = (fw->data[0x7f4f] << 8) + fw->data[0x7f4e];
- update_bin_minor = (fw->data[0x7f51] << 8) + fw->data[0x7f50];
- DBG("*** prepare_fw_data bin major = %d ***\n", update_bin_major);
- DBG("*** prepare_fw_data bin minor = %d ***\n", update_bin_minor);
+ for (i = 0; i < count; i++)
+ memcpy(fw_bin_data[i], fw->data + (i * 1024), 1024);
- DBG("***FwDataCnt = %d ***\n", FwDataCnt);
+ fw_file_major = MSG_FW_FILE_MAJOR_VERSION(fw);
+ fw_file_minor = MSG_FW_FILE_MINOR_VERSION(fw);
+ dev_dbg(dev, "New firmware: %d.%d",
+ fw_file_major, fw_file_minor);
return fw->size;
}
@@ -861,22 +858,22 @@ static ssize_t firmware_update_smart_store(struct device *dev,
size_t size)
{
int ret;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
ret = prepare_fw_data(dev);
if (ret < 0) {
dev_err(dev, "Request firmware failed -(%d)\n", ret);
return ret;
}
- bFwUpdating = 1;
+ ts_data->pdata->updating_fw = true;
disable_irq(ts_data->client->irq);
- DBG("*** update fw size = %d ***\n", FwDataCnt);
ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false);
if (ret == 0)
- DBG("*** firmware_update_c33 ret = %d ***\n", ret);
+ dev_err(dev, "firmware_update_c33 ret = %d\n", ret);
enable_irq(ts_data->client->irq);
- bFwUpdating = 0;
+ ts_data->pdata->updating_fw = false;
return ret;
}
@@ -887,22 +884,22 @@ static ssize_t firmware_force_update_smart_store(struct device *dev,
size_t size)
{
int ret;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
ret = prepare_fw_data(dev);
if (ret < 0) {
dev_err(dev, "Request firmware failed -(%d)\n", ret);
return ret;
}
- bFwUpdating = 1;
+ ts_data->pdata->updating_fw = true;
disable_irq(ts_data->client->irq);
- DBG("*** update fw size = %d ***\n", FwDataCnt);
ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, true);
if (ret == 0)
- DBG("*** firmware_update_c33 et = %d ***\n", ret);
+ dev_err(dev, "firmware_update_c33 et = %d\n", ret);
enable_irq(ts_data->client->irq);
- bFwUpdating = 0;
+ ts_data->pdata->updating_fw = false;
return ret;
}
@@ -919,44 +916,40 @@ static ssize_t firmware_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- msg21xx_read_firmware_id();
- return snprintf(buf, 8, "%s\n", pdata->fw_version);
-}
-
-static ssize_t firmware_version_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t size)
-{
- msg21xx_read_firmware_id();
- DBG("*** firmware_version_store() pdata->fw_version = %s ***\n",
- pdata->fw_version);
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- return size;
+ msg21xx_read_firmware_id(ts_data);
+ return snprintf(buf, sizeof(char) * 8, "%03d%03d\n",
+ ts_data->pdata->fw_version_major,
+ ts_data->pdata->fw_version_minor);
}
-static DEVICE_ATTR(version, (S_IRUGO | S_IWUSR),
+static DEVICE_ATTR(version, S_IRUGO,
firmware_version_show,
- firmware_version_store);
+ NULL);
static ssize_t msg21xx_fw_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, MSTAR_FW_NAME_MAX_LEN - 1, "%s\n", pdata->fw_name);
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, MSTAR_FW_NAME_MAX_LEN - 1,
+ "%s\n", ts_data->pdata->fw_name);
}
static ssize_t msg21xx_fw_name_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
if (size > MSTAR_FW_NAME_MAX_LEN - 1)
return -EINVAL;
- strlcpy(pdata->fw_name, buf, size);
- if (pdata->fw_name[size - 1] == '\n')
- pdata->fw_name[size - 1] = 0;
+ strlcpy(ts_data->pdata->fw_name, buf, size);
+ if (ts_data->pdata->fw_name[size - 1] == '\n')
+ ts_data->pdata->fw_name[size - 1] = 0;
return size;
}
@@ -964,15 +957,6 @@ static ssize_t msg21xx_fw_name_store(struct device *dev,
static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR),
msg21xx_fw_name_show, msg21xx_fw_name_store);
-static ssize_t firmware_data_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- DBG("*** firmware_data_show() FwDataCnt = %d ***\n", FwDataCnt);
-
- return FwDataCnt;
-}
-
static ssize_t firmware_data_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -981,31 +965,26 @@ static ssize_t firmware_data_store(struct device *dev,
int count = size / 1024;
int i;
- for (i = 0; i < count; i++) {
- memcpy(fw_bin_data[FwDataCnt], buf + (i * 1024), 1024);
-
- FwDataCnt++;
- }
-
- DBG("***FwDataCnt = %d ***\n", FwDataCnt);
+ for (i = 0; i < count; i++)
+ memcpy(fw_bin_data[i], buf + (i * 1024), 1024);
if (buf != NULL)
- DBG("*** buf[0] = %c ***\n", buf[0]);
+ dev_dbg(dev, "buf[0] = %c\n", buf[0]);
return size;
}
-static DEVICE_ATTR(data, (S_IRUGO | S_IWUSR),
- firmware_data_show, firmware_data_store);
+static DEVICE_ATTR(data, S_IWUSR, NULL, firmware_data_store);
-#ifdef TP_PRINT
static ssize_t tp_print_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- tp_print_proc_read();
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- return snprintf(buf, sizeof(char) - 1, "%d\n", ts_data->suspended);
+ tp_print_proc_read(ts_data);
+
+ return snprintf(buf, 3, "%d\n", ts_data->suspended);
}
static ssize_t tp_print_store(struct device *dev,
@@ -1013,21 +992,17 @@ static ssize_t tp_print_store(struct device *dev,
const char *buf,
size_t size)
{
- DBG("*** tp_print_store() ***\n");
-
return size;
}
static DEVICE_ATTR(tpp, (S_IRUGO | S_IWUSR),
tp_print_show, tp_print_store);
-#endif
#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
static void _msg_enable_proximity(void)
{
unsigned char tx_data[4] = {0};
- DBG("_msg_enable_proximity!");
tx_data[0] = 0x52;
tx_data[1] = 0x00;
tx_data[2] = 0x47;
@@ -1043,7 +1018,6 @@ static void _msg_disable_proximity(void)
{
unsigned char tx_data[4] = {0};
- DBG("_msg_disable_proximity!");
tx_data[0] = 0x52;
tx_data[1] = 0x00;
tx_data[2] = 0x47;
@@ -1070,15 +1044,15 @@ static int tsps_msg21xx_data(void)
}
#endif
-static int msg21xx_pinctrl_init(void)
+static int msg21xx_pinctrl_init(struct msg21xx_ts_data *ts_data)
{
int retval;
/* Get pinctrl if target uses pinctrl */
- ts_data->ts_pinctrl = devm_pinctrl_get(&(i2c_client->dev));
+ ts_data->ts_pinctrl = devm_pinctrl_get(&(ts_data->client->dev));
if (IS_ERR_OR_NULL(ts_data->ts_pinctrl)) {
retval = PTR_ERR(ts_data->ts_pinctrl);
- dev_dbg(&i2c_client->dev,
+ dev_dbg(&ts_data->client->dev,
"Target does not use pinctrl %d\n", retval);
goto err_pinctrl_get;
}
@@ -1087,7 +1061,7 @@ static int msg21xx_pinctrl_init(void)
ts_data->ts_pinctrl, PINCTRL_STATE_ACTIVE);
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_active)) {
retval = PTR_ERR(ts_data->pinctrl_state_active);
- dev_dbg(&i2c_client->dev,
+ dev_dbg(&ts_data->client->dev,
"Can't lookup %s pinstate %d\n",
PINCTRL_STATE_ACTIVE, retval);
goto err_pinctrl_lookup;
@@ -1097,7 +1071,7 @@ static int msg21xx_pinctrl_init(void)
ts_data->ts_pinctrl, PINCTRL_STATE_SUSPEND);
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_suspend)) {
retval = PTR_ERR(ts_data->pinctrl_state_suspend);
- dev_dbg(&i2c_client->dev,
+ dev_dbg(&ts_data->client->dev,
"Can't lookup %s pinstate %d\n",
PINCTRL_STATE_SUSPEND, retval);
goto err_pinctrl_lookup;
@@ -1107,7 +1081,7 @@ static int msg21xx_pinctrl_init(void)
ts_data->ts_pinctrl, PINCTRL_STATE_RELEASE);
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
retval = PTR_ERR(ts_data->pinctrl_state_release);
- dev_dbg(&i2c_client->dev,
+ dev_dbg(&ts_data->client->dev,
"Can't lookup %s pinstate %d\n",
PINCTRL_STATE_RELEASE, retval);
}
@@ -1131,7 +1105,7 @@ static unsigned char calculate_checksum(unsigned char *msg, int length)
return (unsigned char)((-checksum) & 0xFF);
}
-static int parse_info(struct touchInfo_t *info)
+static int parse_info(struct msg21xx_ts_data *ts_data)
{
unsigned char data[DEMO_MODE_PACKET_LENGTH] = {0};
unsigned char checksum = 0;
@@ -1140,33 +1114,36 @@ static int parse_info(struct touchInfo_t *info)
unsigned int delta_x = 0, delta_y = 0;
mutex_lock(&msg21xx_mutex);
- read_i2c_seq(ts_data->client->addr, &data[0], DEMO_MODE_PACKET_LENGTH);
+ read_i2c_seq(ts_data, ts_data->client->addr, &data[0],
+ DEMO_MODE_PACKET_LENGTH);
mutex_unlock(&msg21xx_mutex);
checksum = calculate_checksum(&data[0], (DEMO_MODE_PACKET_LENGTH-1));
- DBG("check sum: [%x] == [%x]?\n",
+ dev_dbg(&ts_data->client->dev, "check sum: [%x] == [%x]?\n",
data[DEMO_MODE_PACKET_LENGTH-1], checksum);
if (data[DEMO_MODE_PACKET_LENGTH-1] != checksum) {
- DBG("WRONG CHECKSUM\n");
+ dev_err(&ts_data->client->dev, "WRONG CHECKSUM\n");
return -EINVAL;
}
if (data[0] != 0x52) {
- DBG("WRONG HEADER\n");
+ dev_err(&ts_data->client->dev, "WRONG HEADER\n");
return -EINVAL;
}
- info->keycode = 0xFF;
+ ts_data->info.keycode = 0xFF;
if ((data[1] == 0xFF) && (data[2] == 0xFF) &&
(data[3] == 0xFF) && (data[4] == 0xFF) &&
(data[6] == 0xFF)) {
if ((data[5] == 0xFF) || (data[5] == 0)) {
- info->keycode = 0xFF;
+ ts_data->info.keycode = 0xFF;
} else if ((data[5] == 1) || (data[5] == 2) ||
(data[5] == 4) || (data[5] == 8)) {
- info->keycode = data[5] >> 1;
+ ts_data->info.keycode = data[5] >> 1;
- DBG("info->keycode index %d\n", info->keycode);
+ dev_dbg(&ts_data->client->dev,
+ "ts_data->info.keycode index %d\n",
+ ts_data->info.keycode);
}
#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
else if (bEnableTpProximity && ((data[5] == 0x80) ||
@@ -1180,7 +1157,7 @@ static int parse_info(struct touchInfo_t *info)
}
#endif
else {
- DBG("WRONG KEY\n");
+ dev_err(&ts_data->client->dev, "WRONG KEY\n");
return -EINVAL;
}
} else {
@@ -1190,9 +1167,11 @@ static int parse_info(struct touchInfo_t *info)
delta_y = (((data[4] & 0x0F) << 8) | data[6]);
if ((delta_x == 0) && (delta_y == 0)) {
- info->point[0].x = x * pdata->x_max / TPD_WIDTH;
- info->point[0].y = y * pdata->y_max / TPD_HEIGHT;
- info->count = 1;
+ ts_data->info.point[0].x =
+ x * ts_data->pdata->x_max / TPD_WIDTH;
+ ts_data->info.point[0].y =
+ y * ts_data->pdata->y_max / TPD_HEIGHT;
+ ts_data->info.count = 1;
} else {
if (delta_x > 2048)
delta_x -= 4096;
@@ -1204,31 +1183,34 @@ static int parse_info(struct touchInfo_t *info)
(signed short)delta_x);
y2 = (unsigned int)((signed short)y +
(signed short)delta_y);
- info->point[0].x = x * pdata->x_max / TPD_WIDTH;
- info->point[0].y = y * pdata->y_max / TPD_HEIGHT;
- info->point[1].x = x2 * pdata->x_max / TPD_WIDTH;
- info->point[1].y = y2 * pdata->y_max / TPD_HEIGHT;
- info->count = 2;
+ ts_data->info.point[0].x =
+ x * ts_data->pdata->x_max / TPD_WIDTH;
+ ts_data->info.point[0].y =
+ y * ts_data->pdata->y_max / TPD_HEIGHT;
+ ts_data->info.point[1].x =
+ x2 * ts_data->pdata->x_max / TPD_WIDTH;
+ ts_data->info.point[1].y =
+ y2 * ts_data->pdata->y_max / TPD_HEIGHT;
+ ts_data->info.count = ts_data->pdata->num_max_touches;
}
}
return 0;
}
-static void touch_driver_touch_released(void)
+static void touch_driver_touch_released(struct msg21xx_ts_data *ts_data)
{
int i;
- DBG("point touch released\n");
-
- for (i = 0; i < MAX_TOUCH_NUM; i++) {
- input_mt_slot(input_dev, i);
- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ for (i = 0; i < ts_data->pdata->num_max_touches; i++) {
+ input_mt_slot(ts_data->input_dev, i);
+ input_mt_report_slot_state(ts_data->input_dev,
+ MT_TOOL_FINGER, 0);
}
- input_report_key(input_dev, BTN_TOUCH, 0);
- input_report_key(input_dev, BTN_TOOL_FINGER, 0);
- input_sync(input_dev);
+ input_report_key(ts_data->input_dev, BTN_TOUCH, 0);
+ input_report_key(ts_data->input_dev, BTN_TOOL_FINGER, 0);
+ input_sync(ts_data->input_dev);
}
/* read data through I2C then report data to input
@@ -1236,62 +1218,62 @@ static void touch_driver_touch_released(void)
*/
static irqreturn_t msg21xx_ts_interrupt(int irq, void *dev_id)
{
- struct touchInfo_t info;
int i = 0;
static int last_keycode = 0xFF;
static int last_count;
-
- DBG("touch_driver_do_work()\n");
-
- memset(&info, 0x0, sizeof(info));
- if (parse_info(&info) == 0) {
- #ifdef CONFIG_TP_HAVE_KEY
- if (info.keycode != 0xFF) { /* key touch pressed */
- if (info.keycode < num_buttons) {
- if (info.keycode != last_keycode) {
- DBG("key touch pressed");
-
- input_report_key(input_dev,
+ struct msg21xx_ts_data *ts_data = dev_id;
+
+ ts_data->info.count = 0;
+ if (parse_info(ts_data) == 0) {
+ if (ts_data->info.keycode != 0xFF) { /* key touch pressed */
+ if (ts_data->info.keycode <
+ ts_data->pdata->num_buttons) {
+ if (ts_data->info.keycode != last_keycode) {
+ dev_dbg(&ts_data->client->dev,
+ "key touch pressed");
+
+ input_report_key(ts_data->input_dev,
BTN_TOUCH, 1);
- input_report_key(input_dev,
- button_map[info.keycode], 1);
+ input_report_key(ts_data->input_dev,
+ ts_data->pdata->button_map[
+ ts_data->info.keycode], 1);
- last_keycode = info.keycode;
+ last_keycode = ts_data->info.keycode;
} else {
/* pass duplicate key-pressing */
- DBG("REPEATED KEY\n");
+ dev_dbg(&ts_data->client->dev,
+ "REPEATED KEY\n");
}
} else {
- DBG("WRONG KEY\n");
+ dev_dbg(&ts_data->client->dev, "WRONG KEY\n");
}
} else { /* key touch released */
if (last_keycode != 0xFF) {
- DBG("key touch released");
+ dev_dbg(&ts_data->client->dev, "key touch released");
- input_report_key(input_dev,
+ input_report_key(ts_data->input_dev,
BTN_TOUCH, 0);
- input_report_key(input_dev,
- button_map[last_keycode],
- 0);
+ input_report_key(ts_data->input_dev,
+ ts_data->pdata->button_map[last_keycode],
+ 0);
last_keycode = 0xFF;
}
}
- #endif /* CONFIG_TP_HAVE_KEY */
- if (info.count > 0) { /* point touch pressed */
- for (i = 0; i < info.count; i++) {
- input_mt_slot(input_dev, i);
- input_mt_report_slot_state(input_dev,
+ if (ts_data->info.count > 0) { /* point touch pressed */
+ for (i = 0; i < ts_data->info.count; i++) {
+ input_mt_slot(ts_data->input_dev, i);
+ input_mt_report_slot_state(ts_data->input_dev,
MT_TOOL_FINGER, 1);
- input_report_abs(input_dev,
+ input_report_abs(ts_data->input_dev,
ABS_MT_TOUCH_MAJOR, 1);
- input_report_abs(input_dev,
+ input_report_abs(ts_data->input_dev,
ABS_MT_POSITION_X,
- info.point[i].x);
- input_report_abs(input_dev,
+ ts_data->info.point[i].x);
+ input_report_abs(ts_data->input_dev,
ABS_MT_POSITION_Y,
- info.point[i].y);
+ ts_data->info.point[i].y);
}
}
@@ -1299,60 +1281,87 @@ static irqreturn_t msg21xx_ts_interrupt(int irq, void *dev_id)
for (i = info.count; i < MAX_TOUCH_NUM; i++) {
input_mt_slot(input_dev, i);
input_mt_report_slot_state(input_dev,
+ }
+
+ if (last_count > ts_data->info.count) {
+ for (i = ts_data->info.count;
+ i < ts_data->pdata->num_max_touches;
+ i++) {
+ input_mt_slot(ts_data->input_dev, i);
+ input_mt_report_slot_state(ts_data->input_dev,
MT_TOOL_FINGER, 0);
}
}
- last_count = info.count;
+ last_count = ts_data->info.count;
- input_report_key(input_dev, BTN_TOUCH, info.count > 0);
- input_report_key(input_dev, BTN_TOOL_FINGER, info.count > 0);
+ input_report_key(ts_data->input_dev, BTN_TOUCH,
+ ts_data->info.count > 0);
+ input_report_key(ts_data->input_dev, BTN_TOOL_FINGER,
+ ts_data->info.count > 0);
- input_sync(input_dev);
+ input_sync(ts_data->input_dev);
}
return IRQ_HANDLED;
}
-
-static int msg21xx_ts_power_init(void)
+static int msg21xx_ts_power_init(struct msg21xx_ts_data *ts_data, bool init)
{
int rc;
- ts_data->vdd = regulator_get(&i2c_client->dev, "vdd");
- if (IS_ERR(ts_data->vdd)) {
- rc = PTR_ERR(ts_data->vdd);
- dev_err(&i2c_client->dev,
- "Regulator get failed vdd rc=%d\n", rc);
- return rc;
- }
+ if (init) {
+ ts_data->vdd = regulator_get(&ts_data->client->dev,
+ "vdd");
+ if (IS_ERR(ts_data->vdd)) {
+ rc = PTR_ERR(ts_data->vdd);
+ dev_err(&ts_data->client->dev,
+ "Regulator get failed vdd rc=%d\n", rc);
+ return rc;
+ }
- if (regulator_count_voltages(ts_data->vdd) > 0) {
- rc = regulator_set_voltage(ts_data->vdd, MSTAR_VTG_MIN_UV,
- MSTAR_VTG_MAX_UV);
- if (rc) {
- dev_err(&i2c_client->dev,
- "Regulator set_vtg failed vdd rc=%d\n", rc);
- goto reg_vdd_put;
+ if (regulator_count_voltages(ts_data->vdd) > 0) {
+ rc = regulator_set_voltage(ts_data->vdd,
+ MSTAR_VTG_MIN_UV,
+ MSTAR_VTG_MAX_UV);
+ if (rc) {
+ dev_err(&ts_data->client->dev,
+ "Regulator set_vtg failed vdd rc=%d\n",
+ rc);
+ goto reg_vdd_put;
+ }
}
- }
- ts_data->vcc_i2c = regulator_get(&i2c_client->dev, "vcc_i2c");
- if (IS_ERR(ts_data->vcc_i2c)) {
- rc = PTR_ERR(ts_data->vcc_i2c);
- dev_err(&i2c_client->dev,
- "Regulator get failed vcc_i2c rc=%d\n", rc);
- goto reg_vdd_set_vtg;
- }
+ ts_data->vcc_i2c = regulator_get(&ts_data->client->dev,
+ "vcc_i2c");
+ if (IS_ERR(ts_data->vcc_i2c)) {
+ rc = PTR_ERR(ts_data->vcc_i2c);
+ dev_err(&ts_data->client->dev,
+ "Regulator get failed vcc_i2c rc=%d\n", rc);
+ goto reg_vdd_set_vtg;
+ }
- if (regulator_count_voltages(ts_data->vcc_i2c) > 0) {
- rc = regulator_set_voltage(ts_data->vcc_i2c,
- MSTAR_I2C_VTG_MIN_UV,
- MSTAR_I2C_VTG_MAX_UV);
- if (rc) {
- dev_err(&i2c_client->dev,
- "Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
- goto reg_vcc_i2c_put;
+ if (regulator_count_voltages(ts_data->vcc_i2c) > 0) {
+ rc = regulator_set_voltage(ts_data->vcc_i2c,
+ MSTAR_I2C_VTG_MIN_UV,
+ MSTAR_I2C_VTG_MAX_UV);
+ if (rc) {
+ dev_err(&ts_data->client->dev,
+ "Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
+ goto reg_vcc_i2c_put;
+ }
}
+ } else {
+ if (regulator_count_voltages(ts_data->vdd) > 0)
+ regulator_set_voltage(ts_data->vdd, 0,
+ MSTAR_VTG_MAX_UV);
+
+ regulator_put(ts_data->vdd);
+
+ if (regulator_count_voltages(ts_data->vcc_i2c) > 0)
+ regulator_set_voltage(ts_data->vcc_i2c, 0,
+ MSTAR_I2C_VTG_MAX_UV);
+
+ regulator_put(ts_data->vcc_i2c);
}
return 0;
@@ -1367,59 +1376,42 @@ reg_vdd_put:
return rc;
}
-
-static int msg21xx_ts_power_deinit(void)
-{
- if (regulator_count_voltages(ts_data->vdd) > 0)
- regulator_set_voltage(ts_data->vdd, 0, MSTAR_VTG_MAX_UV);
-
- regulator_put(ts_data->vdd);
-
- if (regulator_count_voltages(ts_data->vcc_i2c) > 0)
- regulator_set_voltage(ts_data->vcc_i2c, 0,
- MSTAR_I2C_VTG_MAX_UV);
-
- regulator_put(ts_data->vcc_i2c);
- return 0;
-}
-
-static int msg21xx_ts_power_on(void)
+static int msg21xx_ts_power_on(struct msg21xx_ts_data *ts_data, bool on)
{
int rc;
+ if (!on)
+ goto power_off;
+
rc = regulator_enable(ts_data->vdd);
if (rc) {
- dev_err(&i2c_client->dev,
+ dev_err(&ts_data->client->dev,
"Regulator vdd enable failed rc=%d\n", rc);
return rc;
}
rc = regulator_enable(ts_data->vcc_i2c);
if (rc) {
- dev_err(&i2c_client->dev,
+ dev_err(&ts_data->client->dev,
"Regulator vcc_i2c enable failed rc=%d\n", rc);
regulator_disable(ts_data->vdd);
}
return rc;
-}
-
-static int msg21xx_ts_power_off(void)
-{
- int rc;
DBG("*** %s ***\n", __func__);
rc = regulator_disable(vdd);
+power_off:
rc = regulator_disable(ts_data->vdd);
if (rc) {
- dev_err(&i2c_client->dev,
+ dev_err(&ts_data->client->dev,
"Regulator vdd disable failed rc=%d\n", rc);
return rc;
}
rc = regulator_disable(ts_data->vcc_i2c);
if (rc) {
- dev_err(&i2c_client->dev,
+ dev_err(&ts_data->client->dev,
"Regulator vcc_i2c disable failed rc=%d\n", rc);
rc = regulator_enable(ts_data->vdd);
}
@@ -1427,57 +1419,42 @@ static int msg21xx_ts_power_off(void)
return rc;
}
-static int msg21xx_ts_gpio_configure(bool on)
+static int msg21xx_ts_gpio_configure(struct msg21xx_ts_data *ts_data, bool on)
{
int ret = 0;
- if (on) {
- if (gpio_is_valid(pdata->irq_gpio)) {
- ret = gpio_request(pdata->irq_gpio, "msg21xx_irq_gpio");
- if (ret) {
- dev_err(&i2c_client->dev,
- "Failed to request GPIO[%d], %d\n",
- pdata->irq_gpio, ret);
- goto err_irq_gpio_req;
- }
- ret = gpio_direction_input(pdata->irq_gpio);
- if (ret) {
- dev_err(&i2c_client->dev,
- "Failed to set direction for gpio[%d], %d\n",
- pdata->irq_gpio, ret);
- goto err_irq_gpio_dir;
- }
- gpio_set_value_cansleep(pdata->irq_gpio, 1);
- } else {
- dev_err(&i2c_client->dev, "irq gpio not provided\n");
+ if (!on)
+ goto pwr_deinit;
+
+ if (gpio_is_valid(ts_data->pdata->irq_gpio)) {
+ ret = gpio_request(ts_data->pdata->irq_gpio,
+ "msg21xx_irq_gpio");
+ if (ret) {
+ dev_err(&ts_data->client->dev,
+ "Failed to request GPIO[%d], %d\n",
+ ts_data->pdata->irq_gpio, ret);
goto err_irq_gpio_req;
}
+ ret = gpio_direction_input(ts_data->pdata->irq_gpio);
+ if (ret) {
+ dev_err(&ts_data->client->dev,
+ "Failed to set direction for gpio[%d], %d\n",
+ ts_data->pdata->irq_gpio, ret);
+ goto err_irq_gpio_dir;
+ }
+ gpio_set_value_cansleep(ts_data->pdata->irq_gpio, 1);
+ } else {
+ dev_err(&ts_data->client->dev, "irq gpio not provided\n");
+ goto err_irq_gpio_req;
+ }
- if (gpio_is_valid(pdata->reset_gpio)) {
- ret = gpio_request(pdata->reset_gpio,
- "msg21xx_reset_gpio");
- if (ret) {
- dev_err(&i2c_client->dev,
- "Failed to request GPIO[%d], %d\n",
- pdata->reset_gpio, ret);
- goto err_reset_gpio_req;
- }
-
- /* power on TP */
- ret = gpio_direction_output(pdata->reset_gpio, 1);
- if (ret) {
- dev_err(&i2c_client->dev,
- "Failed to set direction for GPIO[%d], %d\n",
- pdata->reset_gpio, ret);
- goto err_reset_gpio_dir;
- }
- msleep(100);
- gpio_set_value_cansleep(pdata->reset_gpio, 0);
- msleep(20);
- gpio_set_value_cansleep(pdata->reset_gpio, 1);
- msleep(200);
- } else {
- dev_err(&i2c_client->dev, "reset gpio not provided\n");
+ if (gpio_is_valid(ts_data->pdata->reset_gpio)) {
+ ret = gpio_request(ts_data->pdata->reset_gpio,
+ "msg21xx_reset_gpio");
+ if (ret) {
+ dev_err(&ts_data->client->dev,
+ "Failed to request GPIO[%d], %d\n",
+ ts_data->pdata->reset_gpio, ret);
goto err_reset_gpio_req;
}
@@ -1495,55 +1472,93 @@ static int msg21xx_ts_gpio_configure(bool on)
}
}
return 0;
+ /* power on TP */
+ ret = gpio_direction_output(
+ ts_data->pdata->reset_gpio, 1);
+ if (ret) {
+ dev_err(&ts_data->client->dev,
+ "Failed to set direction for GPIO[%d], %d\n",
+ ts_data->pdata->reset_gpio, ret);
+ goto err_reset_gpio_dir;
+ }
+ msleep(100);
+ gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 0);
+ msleep(20);
+ gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 1);
+ msleep(200);
+ } else {
+ dev_err(&ts_data->client->dev, "reset gpio not provided\n");
+ goto err_reset_gpio_req;
+ }
+
+ return 0;
+
err_reset_gpio_dir:
- if (gpio_is_valid(pdata->reset_gpio))
- gpio_free(pdata->irq_gpio);
+ if (gpio_is_valid(ts_data->pdata->reset_gpio))
+ gpio_free(ts_data->pdata->irq_gpio);
err_reset_gpio_req:
err_irq_gpio_dir:
- if (gpio_is_valid(pdata->irq_gpio))
- gpio_free(pdata->irq_gpio);
+ if (gpio_is_valid(ts_data->pdata->irq_gpio))
+ gpio_free(ts_data->pdata->irq_gpio);
err_irq_gpio_req:
return ret;
+
+pwr_deinit:
+ if (gpio_is_valid(ts_data->pdata->irq_gpio))
+ gpio_free(ts_data->pdata->irq_gpio);
+ if (gpio_is_valid(ts_data->pdata->reset_gpio)) {
+ gpio_set_value_cansleep(ts_data->pdata->reset_gpio, 0);
+ ret = gpio_direction_input(ts_data->pdata->reset_gpio);
+ if (ret)
+ dev_err(&ts_data->client->dev,
+ "Unable to set direction for gpio [%d]\n",
+ ts_data->pdata->reset_gpio);
+ gpio_free(ts_data->pdata->reset_gpio);
+ }
+ return 0;
}
#ifdef CONFIG_PM
static int msg21xx_ts_resume(struct device *dev)
{
int retval;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- mutex_lock(&ts_data->ts_mutex);
- if (ts_data->suspended) {
- if (ts_data->ts_pinctrl) {
- retval = pinctrl_select_state(ts_data->ts_pinctrl,
- ts_data->pinctrl_state_active);
- if (retval < 0) {
- dev_err(dev, "Cannot get active pinctrl state\n");
- mutex_unlock(&ts_data->ts_mutex);
- return retval;
- }
- }
+ if (!ts_data->suspended) {
+ dev_info(dev, "msg21xx_ts already in resume\n");
+ return 0;
+ }
- retval = msg21xx_ts_gpio_configure(true);
- if (retval) {
- dev_err(dev, "Failed to put gpios in active state %d",
- retval);
- mutex_unlock(&ts_data->ts_mutex);
- return retval;
- }
+ mutex_lock(&ts_data->ts_mutex);
- enable_irq(ts_data->client->irq);
+ retval = msg21xx_ts_power_on(ts_data, true);
+ if (retval) {
+ dev_err(dev, "msg21xx_ts power on failed");
+ mutex_unlock(&ts_data->ts_mutex);
+ return retval;
+ }
- retval = msg21xx_ts_power_on();
- if (retval) {
- dev_err(dev, "msg21xx_ts power on failed");
+ if (ts_data->ts_pinctrl) {
+ retval = pinctrl_select_state(ts_data->ts_pinctrl,
+ ts_data->pinctrl_state_active);
+ if (retval < 0) {
+ dev_err(dev, "Cannot get active pinctrl state\n");
mutex_unlock(&ts_data->ts_mutex);
return retval;
}
+ }
- ts_data->suspended = 0;
- } else {
- dev_info(dev, "msg21xx_ts already in resume\n");
+ retval = msg21xx_ts_gpio_configure(ts_data, true);
+ if (retval) {
+ dev_err(dev, "Failed to put gpios in active state %d",
+ retval);
+ mutex_unlock(&ts_data->ts_mutex);
+ return retval;
}
+
+ enable_irq(ts_data->client->irq);
+ ts_data->suspended = false;
+
mutex_unlock(&ts_data->ts_mutex);
return 0;
@@ -1552,56 +1567,61 @@ static int msg21xx_ts_resume(struct device *dev)
static int msg21xx_ts_suspend(struct device *dev)
{
int retval;
+ struct msg21xx_ts_data *ts_data = dev_get_drvdata(dev);
- if (bFwUpdating) {
- DBG("suspend bFwUpdating=%d\n", bFwUpdating);
+ if (ts_data->pdata->updating_fw) {
+ dev_info(dev, "Firmware loading in progress\n");
+ return 0;
+ }
+
+ if (ts_data->suspended) {
+ dev_info(dev, "msg21xx_ts already in suspend\n");
return 0;
}
#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
if (bEnableTpProximity) {
- DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity);
+ dev_dbg(dev, "suspend bEnableTpProximity=%d\n",
+ bEnableTpProximity);
return 0;
}
#endif
mutex_lock(&ts_data->ts_mutex);
- if (ts_data->suspended == 0) {
- disable_irq(ts_data->client->irq);
-
- touch_driver_touch_released();
- retval = msg21xx_ts_power_off();
- if (retval) {
- dev_err(dev, "msg21xx_ts power off failed");
- mutex_unlock(&ts_data->ts_mutex);
- return retval;
- }
+ disable_irq(ts_data->client->irq);
- if (ts_data->ts_pinctrl) {
- retval = pinctrl_select_state(ts_data->ts_pinctrl,
- ts_data->pinctrl_state_suspend);
- if (retval < 0) {
- dev_err(&i2c_client->dev, "Cannot get idle pinctrl state\n");
- mutex_unlock(&ts_data->ts_mutex);
- return retval;
- }
- }
+ touch_driver_touch_released(ts_data);
- retval = msg21xx_ts_gpio_configure(false);
- if (retval) {
- dev_err(dev, "Failed to put gpios in idle state %d",
- retval);
+ if (ts_data->ts_pinctrl) {
+ retval = pinctrl_select_state(ts_data->ts_pinctrl,
+ ts_data->pinctrl_state_suspend);
+ if (retval < 0) {
+ dev_err(dev, "Cannot get idle pinctrl state %d\n",
+ retval);
mutex_unlock(&ts_data->ts_mutex);
return retval;
}
+ }
- ts_data->suspended = 1;
- } else {
- dev_err(dev, "msg21xx_ts already in suspend\n");
+ retval = msg21xx_ts_gpio_configure(ts_data, false);
+ if (retval) {
+ dev_err(dev, "Failed to put gpios in idle state %d",
+ retval);
+ mutex_unlock(&ts_data->ts_mutex);
+ return retval;
+ }
+
+ retval = msg21xx_ts_power_on(ts_data, false);
+ if (retval) {
+ dev_err(dev, "msg21xx_ts power off failed");
+ mutex_unlock(&ts_data->ts_mutex);
+ return retval;
}
- mutex_unlock(&ts_data->ts_mutex);
+ ts_data->suspended = true;
+
+ mutex_unlock(&ts_data->ts_mutex);
return 0;
}
@@ -1616,19 +1636,52 @@ static int msg21xx_ts_suspend(struct device *dev)
}
#endif
+static int msg21xx_debug_suspend_set(void *_data, u64 val)
+{
+ struct msg21xx_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (val)
+ msg21xx_ts_suspend(&data->client->dev);
+ else
+ msg21xx_ts_resume(&data->client->dev);
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+static int msg21xx_debug_suspend_get(void *_data, u64 *val)
+{
+ struct msg21xx_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+ *val = data->suspended;
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, msg21xx_debug_suspend_get,
+ msg21xx_debug_suspend_set, "%lld\n");
+
+
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct fb_event *evdata = data;
int *blank;
+ struct msg21xx_ts_data *ts_data =
+ container_of(self, struct msg21xx_ts_data, fb_notif);
if (evdata && evdata->data && event == FB_EVENT_BLANK) {
blank = evdata->data;
if (*blank == FB_BLANK_UNBLANK)
- msg21xx_ts_resume(&i2c_client->dev);
+ msg21xx_ts_resume(&ts_data->client->dev);
else if (*blank == FB_BLANK_POWERDOWN)
- msg21xx_ts_suspend(&i2c_client->dev);
+ msg21xx_ts_suspend(&ts_data->client->dev);
}
return 0;
@@ -1695,6 +1748,20 @@ static int msg21xx_parse_dt(struct device *dev,
if (rc)
return rc;
+ rc = of_property_read_u32(np, "mstar,hard-reset-delay-ms",
+ &temp_val);
+ if (!rc)
+ pdata->hard_reset_delay_ms = temp_val;
+ else
+ return rc;
+
+ rc = of_property_read_u32(np, "mstar,post-hard-reset-delay-ms",
+ &temp_val);
+ if (!rc)
+ pdata->post_hard_reset_delay_ms = temp_val;
+ else
+ return rc;
+
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "mstar,reset-gpio",
0, &pdata->reset_gpio_flags);
@@ -1706,16 +1773,27 @@ static int msg21xx_parse_dt(struct device *dev,
if (pdata->irq_gpio < 0)
return pdata->irq_gpio;
+ rc = of_property_read_u32(np, "mstar,ic-type", &temp_val);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ pdata->ic_type = temp_val;
+
+ rc = of_property_read_u32(np, "mstar,num-max-touches", &temp_val);
+ if (!rc)
+ pdata->num_max_touches = temp_val;
+ else
+ return rc;
prop = of_find_property(np, "mstar,button-map", NULL);
if (prop) {
- num_buttons = prop->length / sizeof(temp_val);
- if (num_buttons > MAX_BUTTONS)
+ pdata->num_buttons = prop->length / sizeof(temp_val);
+ if (pdata->num_buttons > MAX_BUTTONS)
return -EINVAL;
rc = of_property_read_u32_array(np,
- "mstar,button-map", button_map,
- num_buttons);
+ "mstar,button-map", pdata->button_map,
+ pdata->num_buttons);
if (rc) {
dev_err(dev, "Unable to read key codes\n");
return rc;
@@ -1729,12 +1807,11 @@ static int msg21xx_parse_dt(struct device *dev,
static int msg21xx_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id) {
- int ret = 0;
-
- if (input_dev != NULL) {
- DBG("input device has found\n");
- return -EINVAL;
- }
+ int ret = 0, i;
+ struct dentry *temp, *dir;
+ struct input_dev *input_dev;
+ struct msg21xx_ts_data *ts_data;
+ struct msg21xx_ts_platform_data *pdata;
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
@@ -1750,43 +1827,80 @@ static int msg21xx_ts_probe(struct i2c_client *client,
} else
pdata = client->dev.platform_data;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "I2C not supported\n");
+ return -ENODEV;
+ }
+
ts_data = devm_kzalloc(&client->dev,
sizeof(struct msg21xx_ts_data), GFP_KERNEL);
if (!ts_data)
return -ENOMEM;
- DBG("*** %s ***\n", __func__);
+ ts_data->client = client;
+ ts_data->info.point = devm_kzalloc(&client->dev,
+ sizeof(struct touchPoint_t) * pdata->num_max_touches,
+ GFP_KERNEL);
+ if (!ts_data->info.point) {
+ dev_err(&client->dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
- i2c_client = client;
+ /* allocate an input device */
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "input device allocation failed\n");
+ goto err_input_allocate_dev;
+ }
- ret = msg21xx_ts_power_init();
- if (ret)
+ input_dev->name = client->name;
+ input_dev->phys = "I2C";
+ input_dev->dev.parent = &client->dev;
+ input_dev->id.bustype = BUS_I2C;
+
+ ts_data->input_dev = input_dev;
+ ts_data->client = client;
+ ts_data->pdata = pdata;
+
+ input_set_drvdata(input_dev, ts_data);
+ i2c_set_clientdata(client, ts_data);
+
+ ret = msg21xx_ts_power_init(ts_data, true);
+ if (ret) {
dev_err(&client->dev, "Mstar power init failed\n");
+ return ret;
+ }
- ret = msg21xx_ts_power_on();
+ ret = msg21xx_ts_power_on(ts_data, true);
if (ret) {
dev_err(&client->dev, "Mstar power on failed\n");
goto exit_deinit_power;
}
- ret = msg21xx_pinctrl_init();
+ ret = msg21xx_pinctrl_init(ts_data);
if (!ret && ts_data->ts_pinctrl) {
+ /*
+ * Pinctrl handle is optional. If pinctrl handle is found
+ * let pins to be configured in active state. If not
+ * found continue further without error.
+ */
ret = pinctrl_select_state(ts_data->ts_pinctrl,
ts_data->pinctrl_state_active);
if (ret < 0)
- goto exit_pinctrl_select;
- } else {
- goto exit_pinctrl_init;
+ dev_err(&client->dev,
+ "Failed to select %s pinatate %d\n",
+ PINCTRL_STATE_ACTIVE, ret);
}
- ret = msg21xx_ts_gpio_configure(true);
+ ret = msg21xx_ts_gpio_configure(ts_data, true);
if (ret) {
dev_err(&client->dev, "Failed to configure gpio %d\n", ret);
goto exit_gpio_config;
}
- if (get_ic_type() == 0) {
- pr_err("the currnet ic is not Mstar\n");
+ if (msg21xx_get_ic_type(ts_data) == 0) {
+ dev_err(&client->dev, "The current IC is not Mstar\n");
ret = -1;
goto err_wrong_ic_type;
}
@@ -1794,19 +1908,6 @@ static int msg21xx_ts_probe(struct i2c_client *client,
mutex_init(&msg21xx_mutex);
mutex_init(&ts_data->ts_mutex);
- /* allocate an input device */
- input_dev = input_allocate_device();
- if (!input_dev) {
- ret = -ENOMEM;
- pr_err("*** input device allocation failed ***\n");
- goto err_input_allocate_dev;
- }
-
- input_dev->name = client->name;
- input_dev->phys = "I2C";
- input_dev->dev.parent = &client->dev;
- input_dev->id.bustype = BUS_I2C;
-
/* set the supported event type for input device */
set_bit(EV_ABS, input_dev->evbit);
set_bit(EV_SYN, input_dev->evbit);
@@ -1815,9 +1916,8 @@ static int msg21xx_ts_probe(struct i2c_client *client,
set_bit(BTN_TOOL_FINGER, input_dev->keybit);
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
- ts_data->input_dev = input_dev;
- ts_data->client = client;
- ts_data->pdata = pdata;
+ for (i = 0; i < pdata->num_buttons; i++)
+ input_set_capability(input_dev, EV_KEY, pdata->button_map[i]);
input_set_drvdata(input_dev, ts_data);
i2c_set_clientdata(client, ts_data);
@@ -1833,64 +1933,82 @@ static int msg21xx_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 2, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 2, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, pdata->y_max, 0, 0);
- ret = input_mt_init_slots(input_dev, MAX_TOUCH_NUM, 0);
+ ret = input_mt_init_slots(input_dev, pdata->num_max_touches, 0);
if (ret) {
- pr_err("Error %d initialising slots\n", ret);
+ dev_err(&client->dev,
+ "Error %d initialising slots\n", ret);
goto err_free_mem;
}
/* register the input device to input sub-system */
ret = input_register_device(input_dev);
if (ret < 0) {
- pr_err("*** Unable to register ms-touchscreen input device ***\n");
+ dev_err(&client->dev,
+ "Unable to register ms-touchscreen input device\n");
goto err_input_reg_dev;
}
- /* set sysfs for firmware */
- firmware_class = class_create(THIS_MODULE, "ms-touchscreen-msg21xx");
- if (IS_ERR(firmware_class))
- pr_err("Failed to create class(firmware)!\n");
-
- firmware_cmd_dev = device_create(firmware_class, NULL, 0,
- NULL, "device");
- if (IS_ERR(firmware_cmd_dev))
- pr_err("Failed to create device(firmware_cmd_dev)!\n");
-
/* version */
- if (device_create_file(firmware_cmd_dev, &dev_attr_version) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_version.attr.name);
+ if (device_create_file(&client->dev, &dev_attr_version) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_version.attr.name);
+ goto err_create_fw_ver_file;
+ }
/* update */
- if (device_create_file(firmware_cmd_dev, &dev_attr_update) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_update.attr.name);
+ if (device_create_file(&client->dev, &dev_attr_update) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_update.attr.name);
+ goto err_create_fw_update_file;
+ }
/* data */
- if (device_create_file(firmware_cmd_dev, &dev_attr_data) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_data.attr.name);
- /* fw name*/
- if (device_create_file(firmware_cmd_dev, &dev_attr_fw_name) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_fw_name.attr.name);
- /* smart fw update*/
- if (device_create_file(firmware_cmd_dev, &dev_attr_update_fw) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_update_fw.attr.name);
- /* smart fw force update*/
- if (device_create_file(firmware_cmd_dev, &dev_attr_force_update_fw) < 0)
- pr_err("Failed to create device file(%s)!\n",
- dev_attr_force_update_fw.attr.name);
+ if (device_create_file(&client->dev, &dev_attr_data) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_data.attr.name);
+ goto err_create_fw_data_file;
+ }
+ /* fw name */
+ if (device_create_file(&client->dev, &dev_attr_fw_name) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_fw_name.attr.name);
+ goto err_create_fw_name_file;
+ }
+ /* smart fw update */
+ if (device_create_file(&client->dev, &dev_attr_update_fw) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_update_fw.attr.name);
+ goto err_create_update_fw_file;
+ }
+ /* smart fw force update */
+ if (device_create_file(&client->dev,
+ &dev_attr_force_update_fw) < 0) {
+ dev_err(&client->dev,
+ "Failed to create device file(%s)!\n",
+ dev_attr_force_update_fw.attr.name);
+ goto err_create_force_update_fw_file;
+ }
+ dir = debugfs_create_dir(MSTAR_DEBUG_DIR_NAME, NULL);
+ temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, dir,
+ ts_data, &debug_suspend_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ dev_err(&client->dev,
+ "debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ goto free_debug_dir;
+ }
#ifdef TP_PRINT
- tp_print_create_entry();
+ tp_print_create_entry(ts_data);
#endif
- dev_set_drvdata(firmware_cmd_dev, NULL);
-
ret = request_threaded_irq(client->irq, NULL,
msg21xx_ts_interrupt,
pdata->irq_gpio_flags | IRQF_ONESHOT,
@@ -1898,7 +2016,7 @@ static int msg21xx_ts_probe(struct i2c_client *client,
if (ret)
goto err_req_irq;
- disable_irq(ts_data->client->irq);
+ disable_irq(client->irq);
#if defined(CONFIG_FB)
ts_data->fb_notif.notifier_call = fb_notifier_callback;
@@ -1910,91 +2028,38 @@ static int msg21xx_ts_probe(struct i2c_client *client,
&tsps_msg21xx_data);
#endif
-#ifdef FIRMWARE_AUTOUPDATE
- get_customer_firmware_version();
- _ReadBinConfig();
-
- if (main_sw_id == info_sw_id) {
- if (_CalMainCRC32() == bin_conf_crc32) {
- if ((main_sw_id >= SWID_START) &&
- (main_sw_id < SWID_NULL)) {
- update_bin_major = (MSG_FIRMWARE
- [main_sw_id - SWID_START][0x7f4f] << 8)
- + MSG_FIRMWARE[main_sw_id - SWID_START][0x7f4e];
- update_bin_minor = (MSG_FIRMWARE
- [main_sw_id - SWID_START][0x7f51] << 8)
- + MSG_FIRMWARE[main_sw_id - SWID_START][0x7f50];
-
- /* check upgrading */
- if ((update_bin_major == fw_version_major) &&
- (update_bin_minor > fw_version_minor)) {
- update_flag = 1;
- }
- }
- } else {
- if ((info_sw_id >= SWID_START) &&
- (info_sw_id < SWID_NULL)) {
- update_bin_major = (MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f4f] << 8)
- + MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f4e];
- update_bin_minor = (MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f51] << 8)
- + MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f50];
- update_flag = 1;
- }
- }
- } else {
- if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL)) {
- update_bin_major = (MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f4f] << 8)
- + MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f4e];
- update_bin_minor = (MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f51] << 8)
- + MSG_FIRMWARE
- [info_sw_id - SWID_START][0x7f50];
- update_flag = 1;
- }
- }
-
- if (update_flag == 1) {
- DBG("MSG21XX_fw_auto_update begin....\n");
- /* transfer data */
- for (i = 0; i < 33; i++) {
- firmware_data_store(NULL, NULL,
- &(MSG_FIRMWARE[info_sw_id - SWID_START][i * 1024]),
- 1024);
- }
-
- kthread_run(fwAutoUpdate, 0, "MSG21XX_fw_auto_update");
- DBG("*** mstar touch screen registered ***\n");
- return 0;
- }
-
- reset_hw();
-#endif
-
- DBG("*** mstar touch screen registered ***\n");
- enable_irq(ts_data->client->irq);
+ dev_dbg(&client->dev, "mstar touch screen registered\n");
+ enable_irq(client->irq);
return 0;
err_req_irq:
- free_irq(ts_data->client->irq, ts_data);
+ free_irq(client->irq, ts_data);
+ device_remove_file(&client->dev, &dev_attr_data);
+free_debug_dir:
+ debugfs_remove_recursive(dir);
+err_create_fw_data_file:
+ device_remove_file(&client->dev, &dev_attr_update);
+err_create_fw_update_file:
+ device_remove_file(&client->dev, &dev_attr_version);
+err_create_fw_name_file:
+ device_remove_file(&client->dev, &dev_attr_fw_name);
+err_create_update_fw_file:
+ device_remove_file(&client->dev, &dev_attr_update_fw);
+err_create_force_update_fw_file:
+ device_remove_file(&client->dev, &dev_attr_force_update_fw);
+err_create_fw_ver_file:
+ input_unregister_device(input_dev);
err_input_reg_dev:
+ input_free_device(input_dev);
+ input_dev = NULL;
err_input_allocate_dev:
mutex_destroy(&msg21xx_mutex);
mutex_destroy(&ts_data->ts_mutex);
- input_unregister_device(input_dev);
- input_free_device(input_dev);
- input_dev = NULL;
err_wrong_ic_type:
- msg21xx_ts_gpio_configure(false);
+ msg21xx_ts_gpio_configure(ts_data, false);
exit_gpio_config:
-exit_pinctrl_select:
if (ts_data->ts_pinctrl) {
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
devm_pinctrl_put(ts_data->ts_pinctrl);
@@ -2003,13 +2068,13 @@ exit_pinctrl_select:
ret = pinctrl_select_state(ts_data->ts_pinctrl,
ts_data->pinctrl_state_release);
if (ret < 0)
- pr_err("Cannot get release pinctrl state\n");
+ dev_err(&ts_data->client->dev,
+ "Cannot get release pinctrl state\n");
}
}
-exit_pinctrl_init:
- msg21xx_ts_power_off();
+ msg21xx_ts_power_on(ts_data, false);
exit_deinit_power:
- msg21xx_ts_power_deinit();
+ msg21xx_ts_power_init(ts_data, false);
err_free_mem:
input_free_device(input_dev);
@@ -2022,12 +2087,11 @@ err_free_mem:
static int touch_driver_remove(struct i2c_client *client)
{
int retval = 0;
-
- DBG("touch_driver_remove()\n");
+ struct msg21xx_ts_data *ts_data = i2c_get_clientdata(client);
free_irq(ts_data->client->irq, ts_data);
- gpio_free(pdata->irq_gpio);
- gpio_free(pdata->reset_gpio);
+ gpio_free(ts_data->pdata->irq_gpio);
+ gpio_free(ts_data->pdata->reset_gpio);
if (ts_data->ts_pinctrl) {
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
@@ -2037,11 +2101,12 @@ static int touch_driver_remove(struct i2c_client *client)
retval = pinctrl_select_state(ts_data->ts_pinctrl,
ts_data->pinctrl_state_release);
if (retval < 0)
- pr_err("Cannot get release pinctrl state\n");
+ dev_err(&ts_data->client->dev,
+ "Cannot get release pinctrl state\n");
}
}
- input_unregister_device(input_dev);
+ input_unregister_device(ts_data->input_dev);
mutex_destroy(&msg21xx_mutex);
mutex_destroy(&ts_data->ts_mutex);
@@ -2082,7 +2147,7 @@ module_i2c_driver(touch_device_driver);
static unsigned short InfoAddr = 0x0F, PoolAddr = 0x10, TransLen = 256;
static unsigned char row, units, cnt;
-static int tp_print_proc_read(void)
+static int tp_print_proc_read(struct msg21xx_ts_data *ts_data)
{
unsigned short i, j;
unsigned short left, offset = 0;
@@ -2106,9 +2171,9 @@ static int tp_print_proc_read(void)
& 0xFF;
dbbus_tx_data[2] = (PoolAddr + offset) & 0xFF;
mutex_lock(&msg21xx_mutex);
- write_i2c_seq(ts_data->client->addr,
+ write_i2c_seq(ts_data, ts_data->client->addr,
&dbbus_tx_data[0], 3);
- read_i2c_seq(ts_data->client->addr,
+ read_i2c_seq(ts_data, ts_data->client->addr,
&buf[offset],
left > TransLen ? TransLen : left);
mutex_unlock(&msg21xx_mutex);
@@ -2151,7 +2216,7 @@ static int tp_print_proc_read(void)
return 0;
}
-static void tp_print_create_entry(void)
+static void tp_print_create_entry(struct msg21xx_ts_data *ts_data)
{
unsigned char dbbus_tx_data[3] = {0};
unsigned char dbbus_rx_data[8] = {0};
@@ -2160,8 +2225,8 @@ static void tp_print_create_entry(void)
dbbus_tx_data[1] = 0x00;
dbbus_tx_data[2] = 0x58;
mutex_lock(&msg21xx_mutex);
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4);
+ write_i2c_seq(ts_data, ts_data->client->addr, &dbbus_tx_data[0], 3);
+ read_i2c_seq(ts_data, ts_data->client->addr, &dbbus_rx_data[0], 4);
mutex_unlock(&msg21xx_mutex);
InfoAddr = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0];
PoolAddr = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2];
@@ -2172,8 +2237,10 @@ static void tp_print_create_entry(void)
dbbus_tx_data[1] = (InfoAddr >> 8) & 0xFF;
dbbus_tx_data[2] = InfoAddr & 0xFF;
mutex_lock(&msg21xx_mutex);
- write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3);
- read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 8);
+ write_i2c_seq(ts_data, ts_data->client->addr,
+ &dbbus_tx_data[0], 3);
+ read_i2c_seq(ts_data, ts_data->client->addr,
+ &dbbus_rx_data[0], 8);
mutex_unlock(&msg21xx_mutex);
units = dbbus_rx_data[0];
@@ -2181,10 +2248,10 @@ static void tp_print_create_entry(void)
cnt = dbbus_rx_data[2];
TransLen = (dbbus_rx_data[7]<<8) + dbbus_rx_data[6];
- if (device_create_file(firmware_cmd_dev, &dev_attr_tpp) < 0) {
- pr_err("Failed to create device file(%s)!\n",
+ if (device_create_file(&ts_data->client->dev,
+ &dev_attr_tpp) < 0)
+ dev_err(&ts_data->client->dev, "Failed to create device file(%s)!\n",
dev_attr_tpp.attr.name);
- }
}
}
#endif
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index c28b8df4194e..ea8db1a431d0 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -14,6 +14,7 @@
#include <linux/dma-mapping.h>
#include <linux/dma-mapping-fast.h>
#include <linux/io-pgtable-fast.h>
+#include <linux/vmalloc.h>
#include <asm/cacheflush.h>
#include <asm/dma-iommu.h>
@@ -512,6 +513,33 @@ static void fast_smmu_free(struct device *dev, size_t size,
__fast_smmu_free_pages(pages, count);
}
+static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr,
+ size_t size, struct dma_attrs *attrs)
+{
+ struct vm_struct *area;
+ unsigned long uaddr = vma->vm_start;
+ struct page **pages;
+ int i, nr_pages, ret = 0;
+
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ area = find_vm_area(cpu_addr);
+ if (!area)
+ return -EINVAL;
+
+ pages = area->pages;
+ nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ for (i = vma->vm_pgoff; i < nr_pages && uaddr < vma->vm_end; i++) {
+ ret = vm_insert_page(vma, uaddr, pages[i]);
+ if (ret)
+ break;
+ uaddr += PAGE_SIZE;
+ }
+
+ return ret;
+}
+
static int fast_smmu_dma_supported(struct device *dev, u64 mask)
{
return mask <= 0xffffffff;
@@ -559,6 +587,7 @@ static int fast_smmu_notify(struct notifier_block *self,
static const struct dma_map_ops fast_smmu_dma_ops = {
.alloc = fast_smmu_alloc,
.free = fast_smmu_free,
+ .mmap = fast_smmu_mmap_attrs,
.map_page = fast_smmu_map_page,
.unmap_page = fast_smmu_unmap_page,
.map_sg = fast_smmu_map_sg,
diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c
index b91c7785df0b..e26b79959b13 100644
--- a/drivers/iommu/msm_dma_iommu_mapping.c
+++ b/drivers/iommu/msm_dma_iommu_mapping.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -267,6 +267,7 @@ int msm_dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, int nents,
return ret;
}
+EXPORT_SYMBOL(msm_dma_map_sg_attrs);
static void msm_iommu_meta_destroy(struct kref *kref)
{
@@ -343,6 +344,7 @@ void msm_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nents,
out:
return;
}
+EXPORT_SYMBOL(msm_dma_unmap_sg);
/*
* Only to be called by ION code when a buffer is freed
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 291720db72ce..2f7529814cd9 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -42,8 +43,14 @@
#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
#define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
+#define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56)
+#define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57)
+#define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58)
#define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
#define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
+#define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
+#define FLASH_LED_REG_MITIGATION_SW(base) (base + 0x6F)
+#define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70)
#define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
#define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0)
@@ -55,15 +62,22 @@
#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
#define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
#define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0)
+#define FLASH_LED_LMH_MITIGATION_SEL_MASK GENMASK(1, 0)
+#define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0)
#define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
#define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
+#define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
+#define FLASH_LED_THERMAL_OTST_MASK GENMASK(2, 0)
+#define FLASH_LED_PREPARE_OPTIONS_MASK GENMASK(2, 0)
#define FLASH_LED_MOD_CTRL_MASK BIT(7)
#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2)
#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
+#define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0)
#define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
#define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
#define VPH_DROOP_THRESH_MV_TO_VAL(val_mv) ((val_mv / 100) - 25)
+#define VPH_DROOP_THRESH_VAL_TO_UV(val) ((val + 25) * 100000)
#define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
#define FLASH_LED_WARMUP_DELAY_DEFAULT 2
@@ -74,9 +88,21 @@
#define FLASH_LED_VPH_DROOP_DEBOUNCE_MAX 3
#define FLASH_LED_VPH_DROOP_HYST_MAX 3
#define FLASH_LED_VPH_DROOP_THRESH_MAX 7
+#define FLASH_LED_THERMAL_THRSH_MIN 3
+#define FLASH_LED_THERMAL_OTST_LEVELS 3
+#define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
+#define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
+#define FLASH_LED_RPARA_DEFAULT_UOHM 0
#define FLASH_LED_SAFETY_TMR_VAL_OFFSET 1
#define FLASH_LED_SAFETY_TMR_VAL_DIVISOR 10
#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
+#define FLASH_LED_LMH_LEVEL_DEFAULT 0
+#define FLASH_LED_LMH_MITIGATION_ENABLE 1
+#define FLASH_LED_LMH_MITIGATION_DISABLE 0
+#define FLASH_LED_LMH_MITIGATION_SEL_DEFAULT 2
+#define FLASH_LED_LMH_MITIGATION_SEL_MAX 2
+#define FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV 3700000
+#define FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM 400000
#define FLASH_LED_IRES_BASE 3
#define FLASH_LED_IRES_DIVISOR 2500
#define FLASH_LED_IRES_MIN_UA 5000
@@ -96,6 +122,7 @@
#define FLASH_LED_DISABLE 0x00
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
#define FLASH_LED_MIN_CURRENT_MA 25
+#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
/* notifier call chain for flash-led irqs */
static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
@@ -156,17 +183,26 @@ struct flash_switch_data {
* Flash LED configuration read from device tree
*/
struct flash_led_platform_data {
+ int *thermal_derate_current;
int all_ramp_up_done_irq;
int all_ramp_down_done_irq;
int led_fault_irq;
+ int ibatt_ocp_threshold_ua;
+ int vled_max_uv;
+ int rpara_uohm;
+ int lmh_rbatt_threshold_uohm;
+ int lmh_ocv_threshold_uv;
u8 isc_delay;
u8 warmup_delay;
u8 current_derate_en_cfg;
u8 vph_droop_threshold;
u8 vph_droop_hysteresis;
u8 vph_droop_debounce;
+ u8 lmh_mitigation_sel;
+ u8 lmh_level;
u8 hw_strobe_option;
bool hdrm_auto_mode_en;
+ bool thermal_derate_en;
};
/*
@@ -185,6 +221,7 @@ struct qpnp_flash_led {
int num_snodes;
int enable;
u16 base;
+ bool trigger_lmh;
};
static int
@@ -206,6 +243,20 @@ qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
}
static int
+qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
+ u8 *val)
+{
+ int rc;
+
+ rc = qpnp_flash_led_read(led, addr, val);
+ if (rc < 0)
+ return rc;
+
+ *val &= mask;
+ return rc;
+}
+
+static int
qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
u8 val)
{
@@ -293,6 +344,20 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (rc < 0)
return rc;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SEL(led->base),
+ FLASH_LED_LMH_MITIGATION_SEL_MASK,
+ led->pdata->lmh_mitigation_sel);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LMH_LEVEL(led->base),
+ FLASH_LED_LMH_LEVEL_MASK,
+ led->pdata->lmh_level);
+ if (rc < 0)
+ return rc;
+
return 0;
}
@@ -364,10 +429,275 @@ out:
return rc;
}
-static int qpnp_flash_led_get_max_avail_current(struct flash_switch_data *snode,
- struct qpnp_flash_led *led)
+static int get_property_from_fg(struct qpnp_flash_led *led,
+ enum power_supply_property prop, int *val)
+{
+ int rc;
+ union power_supply_propval pval = {0, };
+
+ if (!led->bms_psy) {
+ dev_err(&led->pdev->dev, "no bms psy found\n");
+ return -EINVAL;
+ }
+
+ rc = power_supply_get_property(led->bms_psy, prop, &pval);
+ if (rc) {
+ dev_err(&led->pdev->dev,
+ "bms psy doesn't support reading prop %d rc = %d\n",
+ prop, rc);
+ return rc;
+ }
+
+ *val = pval.intval;
+ return rc;
+}
+
+#define VOLTAGE_HDRM_DEFAULT_MV 350
+static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
+{
+ int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (led->fnode[i].led_on) {
+ if (led->fnode[i].id < 2) {
+ if (led->fnode[i].current_ma < 750)
+ voltage_hdrm_mv = 125;
+ else if (led->fnode[i].current_ma < 1000)
+ voltage_hdrm_mv = 175;
+ else if (led->fnode[i].current_ma < 1250)
+ voltage_hdrm_mv = 250;
+ else
+ voltage_hdrm_mv = 350;
+ } else {
+ if (led->fnode[i].current_ma < 375)
+ voltage_hdrm_mv = 125;
+ else if (led->fnode[i].current_ma < 500)
+ voltage_hdrm_mv = 175;
+ else if (led->fnode[i].current_ma < 625)
+ voltage_hdrm_mv = 250;
+ else
+ voltage_hdrm_mv = 350;
+ }
+
+ voltage_hdrm_max = max(voltage_hdrm_max,
+ voltage_hdrm_mv);
+ }
+ }
+
+ if (!voltage_hdrm_max)
+ return VOLTAGE_HDRM_DEFAULT_MV;
+
+ return voltage_hdrm_max;
+}
+
+#define UCONV 1000000LL
+#define MCONV 1000LL
+#define FLASH_VDIP_MARGIN 50000
+#define BOB_EFFICIENCY 900LL
+#define VIN_FLASH_MIN_UV 3300000LL
+static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
+{
+ int ocv_uv, rbatt_uohm, ibat_now, voltage_hdrm_mv, rc;
+ int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
+ int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
+
+ /* RESISTANCE = esr_uohm + rslow_uohm */
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_RESISTANCE,
+ &rbatt_uohm);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "bms psy does not support resistance, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* If no battery is connected, return max possible flash current */
+ if (!rbatt_uohm)
+ return FLASH_LED_MAX_TOTAL_CURRENT_MA;
+
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "bms psy does not support OCV, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = get_property_from_fg(led, POWER_SUPPLY_PROP_CURRENT_NOW,
+ &ibat_now);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "bms psy does not support current, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rbatt_uohm += led->pdata->rpara_uohm;
+ voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
+ vph_flash_vdip =
+ VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
+ + FLASH_VDIP_MARGIN;
+
+ /* Check if LMH_MITIGATION needs to be triggered */
+ if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
+ rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
+ led->trigger_lmh = true;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_ENABLE);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "trigger lmh mitigation failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* Wait for LMH mitigation to take effect */
+ udelay(100);
+
+ return qpnp_flash_led_calc_max_current(led);
+ }
+
+ /*
+ * Calculate the maximum current that can pulled out of the battery
+ * before the battery voltage dips below a safe threshold.
+ */
+ ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
+ rbatt_uohm);
+
+ if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
+ /*
+ * If the calculated current is below the OCP threshold, then
+ * use it as the possible flash current.
+ */
+ ibat_flash_ua = ibat_safe_ua - ibat_now;
+ vph_flash_uv = vph_flash_vdip;
+ } else {
+ /*
+ * If the calculated current is above the OCP threshold, then
+ * use the ocp threshold instead.
+ *
+ * Any higher current will be tripping the battery OCP.
+ */
+ ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
+ vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
+ * led->pdata->ibatt_ocp_threshold_ua, UCONV);
+ }
+ /* Calculate the input voltage of the flash module. */
+ vin_flash_uv = max((led->pdata->vled_max_uv +
+ (voltage_hdrm_mv * MCONV)), VIN_FLASH_MIN_UV);
+ /* Calculate the available power for the flash module. */
+ avail_flash_power_fw = BOB_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
+ /*
+ * Calculate the available amount of current the flash module can draw
+ * before collapsing the battery. (available power/ flash input voltage)
+ */
+ avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
+ dev_dbg(&led->pdev->dev, "avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
+ avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm,
+ led->trigger_lmh);
+ return min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
+ (int)(avail_flash_ua / MCONV));
+}
+
+static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led)
+{
+ int thermal_current_lim = 0;
+ int rc;
+ u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
+
+ /* Store THERMAL_THRSHx register values */
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh1);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh2);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_read(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ &thermal_thrsh3);
+ if (rc < 0)
+ return rc;
+
+ /* Lower THERMAL_THRSHx thresholds to minimum */
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ FLASH_LED_THERMAL_THRSH_MIN);
+ if (rc < 0)
+ return rc;
+
+ /* Check THERMAL_OTST status */
+ rc = qpnp_flash_led_read(led,
+ FLASH_LED_REG_LED_STATUS2(led->base),
+ &otst_status);
+ if (rc < 0)
+ return rc;
+
+ /* Look up current limit based on THERMAL_OTST status */
+ if (otst_status)
+ thermal_current_lim =
+ led->pdata->thermal_derate_current[otst_status >> 1];
+
+ /* Restore THERMAL_THRESHx registers to original values */
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH1(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh1);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH2(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh2);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_THERMAL_THRSH3(led->base),
+ FLASH_LED_THERMAL_THRSH_MASK,
+ thermal_thrsh3);
+ if (rc < 0)
+ return rc;
+
+ return thermal_current_lim;
+}
+
+static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
{
- return 3750;
+ int max_avail_current, thermal_current_lim = 0;
+
+ led->trigger_lmh = false;
+ max_avail_current = qpnp_flash_led_calc_max_current(led);
+ if (led->pdata->thermal_derate_en)
+ thermal_current_lim =
+ qpnp_flash_led_calc_thermal_current_lim(led);
+
+ if (thermal_current_lim)
+ max_avail_current = min(max_avail_current, thermal_current_lim);
+
+ return max_avail_current;
}
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
@@ -397,6 +727,18 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
if (rc < 0)
return rc;
+ if (led->trigger_lmh) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_DISABLE);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "disable lmh mitigation failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
led->enable--;
if (led->enable == 0) {
rc = qpnp_flash_led_masked_write(led,
@@ -442,7 +784,6 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
}
}
- qpnp_flash_led_regulator_enable(led, snode, false);
snode->enabled = false;
return 0;
}
@@ -464,10 +805,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
return rc;
}
- rc = qpnp_flash_led_regulator_enable(led, snode, true);
- if (rc < 0)
- return rc;
-
/* Iterate over all leds for this switch node */
val = 0;
for (i = 0; i < led->num_fnodes; i++)
@@ -543,6 +880,18 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
}
led->enable++;
+ if (led->trigger_lmh) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MITIGATION_SW(led->base),
+ FLASH_LED_LMH_MITIGATION_EN_MASK,
+ FLASH_LED_LMH_MITIGATION_ENABLE);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "trigger lmh mitigation failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_EN_LED_CTRL(led->base),
snode->led_mask, val);
@@ -553,12 +902,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
return 0;
}
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current)
{
struct led_classdev *led_cdev = trigger_to_lcdev(trig);
struct flash_switch_data *snode;
struct qpnp_flash_led *led;
- int rc, val = 0;
+ int rc;
if (!led_cdev) {
pr_err("Invalid led_trigger provided\n");
@@ -568,7 +918,7 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
snode = container_of(led_cdev, struct flash_switch_data, cdev);
led = dev_get_drvdata(&snode->pdev->dev);
- if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
+ if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
dev_err(&led->pdev->dev, "Invalid options %d\n", options);
return -EINVAL;
}
@@ -582,16 +932,26 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
}
}
+ if (options & DISABLE_REGULATOR) {
+ rc = qpnp_flash_led_regulator_enable(led, snode, false);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "disable regulator failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
if (options & QUERY_MAX_CURRENT) {
- val = qpnp_flash_led_get_max_avail_current(snode, led);
- if (val < 0) {
+ rc = qpnp_flash_led_get_max_avail_current(led);
+ if (rc < 0) {
dev_err(&led->pdev->dev,
- "query max current failed, rc=%d\n", val);
- return val;
+ "query max current failed, rc=%d\n", rc);
+ return rc;
}
+ *max_current = rc;
}
- return val;
+ return 0;
}
static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
@@ -1143,6 +1503,28 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
(open_circuit_det << 1) | short_circuit_det;
+ led->pdata->thermal_derate_en =
+ of_property_read_bool(node, "qcom,thermal-derate-en");
+
+ if (led->pdata->thermal_derate_en) {
+ led->pdata->thermal_derate_current =
+ devm_kcalloc(&led->pdev->dev,
+ FLASH_LED_THERMAL_OTST_LEVELS,
+ sizeof(int), GFP_KERNEL);
+ if (!led->pdata->thermal_derate_current)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(node,
+ "qcom,thermal-derate-current",
+ led->pdata->thermal_derate_current,
+ FLASH_LED_THERMAL_OTST_LEVELS);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "Unable to read thermal current limits, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
if (!rc) {
@@ -1204,6 +1586,84 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return rc;
}
+ led->pdata->vled_max_uv = FLASH_LED_VLED_MAX_DEFAULT_UV;
+ rc = of_property_read_u32(node, "qcom,vled-max-uv", &val);
+ if (!rc) {
+ led->pdata->vled_max_uv = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse vled_max voltage, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->ibatt_ocp_threshold_ua =
+ FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA;
+ rc = of_property_read_u32(node, "qcom,ibatt-ocp-threshold-ua", &val);
+ if (!rc) {
+ led->pdata->ibatt_ocp_threshold_ua = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse ibatt_ocp threshold, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->rpara_uohm = FLASH_LED_RPARA_DEFAULT_UOHM;
+ rc = of_property_read_u32(node, "qcom,rparasitic-uohm", &val);
+ if (!rc) {
+ led->pdata->rpara_uohm = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse rparasitic, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->lmh_ocv_threshold_uv =
+ FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV;
+ rc = of_property_read_u32(node, "qcom,lmh-ocv-threshold-uv", &val);
+ if (!rc) {
+ led->pdata->lmh_ocv_threshold_uv = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse lmh ocv threshold, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->lmh_rbatt_threshold_uohm =
+ FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM;
+ rc = of_property_read_u32(node, "qcom,lmh-rbatt-threshold-uohm", &val);
+ if (!rc) {
+ led->pdata->lmh_rbatt_threshold_uohm = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse lmh rbatt threshold, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->lmh_level = FLASH_LED_LMH_LEVEL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,lmh-level", &val);
+ if (!rc) {
+ led->pdata->lmh_level = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse lmh_level, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
+ if (!rc) {
+ led->pdata->lmh_mitigation_sel = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse lmh_mitigation_sel, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (led->pdata->lmh_mitigation_sel > FLASH_LED_LMH_MITIGATION_SEL_MAX) {
+ dev_err(&led->pdev->dev, "Invalid lmh_mitigation_sel specified\n");
+ return -EINVAL;
+ }
+
led->pdata->all_ramp_up_done_irq =
of_irq_get_byname(node, "all-ramp-up-done-irq");
if (led->pdata->all_ramp_up_done_irq < 0)
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index 3e19cf6796a3..95b4c42a5adb 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -82,6 +82,7 @@
#define FLASH_LED_HDRM_SNS_ENABLE_MASK 0x81
#define FLASH_MASK_MODULE_CONTRL_MASK 0xE0
#define FLASH_FOLLOW_OTST2_RB_MASK 0x08
+#define FLASH_PREPARE_OPTIONS_MASK 0x08
#define FLASH_LED_TRIGGER_DEFAULT "none"
#define FLASH_LED_HEADROOM_DEFAULT_MV 500
@@ -1155,12 +1156,13 @@ error_regulator_enable:
return rc;
}
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
+int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+ int *max_current)
{
struct led_classdev *led_cdev = trigger_to_lcdev(trig);
struct flash_node_data *flash_node;
struct qpnp_flash_led *led;
- int rc, val = 0;
+ int rc;
if (!led_cdev) {
pr_err("Invalid led_trigger provided\n");
@@ -1170,7 +1172,7 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
flash_node = container_of(led_cdev, struct flash_node_data, cdev);
led = dev_get_drvdata(&flash_node->pdev->dev);
- if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
+ if (!(options & FLASH_PREPARE_OPTIONS_MASK)) {
dev_err(&led->pdev->dev, "Invalid options %d\n", options);
return -EINVAL;
}
@@ -1184,16 +1186,26 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options)
}
}
+ if (options & DISABLE_REGULATOR) {
+ rc = flash_regulator_enable(led, flash_node, false);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "disable regulator failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
if (options & QUERY_MAX_CURRENT) {
- val = qpnp_flash_led_get_max_avail_current(flash_node, led);
- if (val < 0) {
+ rc = qpnp_flash_led_get_max_avail_current(flash_node, led);
+ if (rc < 0) {
dev_err(&led->pdev->dev,
- "query max current failed, rc=%d\n", val);
- return val;
+ "query max current failed, rc=%d\n", rc);
+ return rc;
}
+ *max_current = rc;
}
- return val;
+ return 0;
}
static void qpnp_flash_led_work(struct work_struct *work)
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
index 7f5e49809a26..8da079d9d0c8 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/msm-bus.h>
+#include <linux/clk/msm-clk.h>
#include "cam_soc_api.h"
struct msm_cam_bus_pscale_data {
@@ -454,6 +455,17 @@ long msm_camera_clk_set_rate(struct device *dev,
}
EXPORT_SYMBOL(msm_camera_clk_set_rate);
+int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags)
+{
+ if (!clk)
+ return -EINVAL;
+
+ CDBG("clk : %p, flags : %ld\n", clk, flags);
+
+ return clk_set_flags(clk, flags);
+}
+EXPORT_SYMBOL(msm_camera_set_clk_flags);
+
/* release memory allocated for clocks */
static int msm_camera_put_clk_info_internal(struct device *dev,
struct msm_cam_clk_info **clk_info,
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h
index d1eeab92773f..b4494d4d6bab 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h
@@ -188,6 +188,18 @@ long msm_camera_clk_set_rate(struct device *dev,
struct clk *clk,
long clk_rate);
/**
+ * @brief : Sets flags of a clock
+ *
+ * This function will set the flags for a specified clock
+ *
+ * @param clk : Pointer to clock to set flags for
+ * @param flags : The flags to set
+ *
+ * @return Status of operation.
+ */
+
+int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags);
+/**
* @brief : Gets regulator info
*
* This function extracts the regulator information for a specific
@@ -200,6 +212,7 @@ long msm_camera_clk_set_rate(struct device *dev,
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
+
int msm_camera_get_regulator_info(struct platform_device *pdev,
struct msm_cam_regulator **vdd_info, int *num_reg);
/**
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
index 98afe4cd3074..a56e42dc1c6f 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
@@ -22,6 +22,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-v4l2.h>
+#include <linux/clk/msm-clk.h>
#include "msm_fd_dev.h"
#include "msm_fd_hw.h"
@@ -1203,6 +1204,7 @@ static int fd_probe(struct platform_device *pdev)
{
struct msm_fd_device *fd;
int ret;
+ int i;
/* Face detection device struct */
fd = kzalloc(sizeof(struct msm_fd_device), GFP_KERNEL);
@@ -1237,6 +1239,19 @@ static int fd_probe(struct platform_device *pdev)
goto error_get_clocks;
}
+ /*set memcore and mem periphery logic flags to 0*/
+ for (i = 0; i < fd->clk_num; i++) {
+ if ((strcmp(fd->clk_info[i].clk_name,
+ "mmss_fd_core_clk") == 0) ||
+ (strcmp(fd->clk_info[i].clk_name,
+ "mmss_fd_core_uar_clk") == 0)) {
+ msm_camera_set_clk_flags(fd->clk[i],
+ CLKFLAG_NORETAIN_MEM);
+ msm_camera_set_clk_flags(fd->clk[i],
+ CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
ret = msm_camera_register_bus_client(pdev, CAM_BUS_CLIENT_FD);
if (ret < 0) {
dev_err(&pdev->dev, "Fail to get bus\n");
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
index ffcd88dc44f3..a792404c243c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/ratelimit.h>
+#include <linux/clk/msm-clk.h>
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
@@ -198,6 +199,18 @@ static int msm_vfe48_get_clks(struct vfe_device *vfe_dev)
if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
"mnoc_maxi_clk") == 0)
vfe_dev->vfe_clk_info[i].clk_rate = INIT_RATE;
+ /* set no memory retention */
+ if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+ "camss_vfe_clk") == 0 ||
+ strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+ "camss_csi_vfe_clk") == 0 ||
+ strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+ "camss_vfe_vbif_axi_clk") == 0) {
+ msm_camera_set_clk_flags(vfe_dev->vfe_clk[i],
+ CLKFLAG_NORETAIN_MEM);
+ msm_camera_set_clk_flags(vfe_dev->vfe_clk[i],
+ CLKFLAG_NORETAIN_PERIPH);
+ }
}
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 8721fc18eaa8..ac2d508269a4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -184,6 +184,7 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data,
case V4L2_PIX_FMT_P16RGGB10:
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_META:
+ case V4L2_PIX_FMT_META10:
case V4L2_PIX_FMT_GREY:
stream_info->num_planes = 1;
stream_info->format_factor = ISP_Q2;
@@ -288,6 +289,7 @@ static uint32_t msm_isp_axi_get_plane_size(
case V4L2_PIX_FMT_QGBRG10:
case V4L2_PIX_FMT_QGRBG10:
case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_META10:
/* TODO: fix me */
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 5e24b146619d..e47a8de30aa9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -1396,6 +1396,7 @@ int msm_isp_cal_word_per_line(uint32_t output_format,
case V4L2_PIX_FMT_SGBRG10DPCM8:
case V4L2_PIX_FMT_SGRBG10DPCM8:
case V4L2_PIX_FMT_SRGGB10DPCM8:
+ case V4L2_PIX_FMT_META10:
val = CAL_WORD(pixel_per_line, 5, 32);
break;
case V4L2_PIX_FMT_SBGGR12:
@@ -1581,6 +1582,8 @@ int msm_isp_get_bit_per_pixel(uint32_t output_format)
case V4L2_PIX_FMT_P16GBRG10:
case V4L2_PIX_FMT_P16GRBG10:
case V4L2_PIX_FMT_P16RGGB10:
+ case V4L2_PIX_FMT_META10:
+ case MSM_V4L2_PIX_FMT_META10:
return 10;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 266a5a6be2a2..d56d246b3c91 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -319,6 +319,7 @@ err_reg_enable:
int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev)
{
int rc = -1;
+ int i;
struct resource *jpeg_irq_res;
void *jpeg_base, *vbif_base;
struct platform_device *pdev = pgmn_dev->pdev;
@@ -356,6 +357,19 @@ int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev)
goto err_jpeg_clk;
}
+ /*set memcore and mem periphery logic flags to 0*/
+ for (i = 0; i < pgmn_dev->num_clk; i++) {
+ if ((strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
+ "core_clk") == 0) ||
+ (strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
+ "mmss_camss_jpeg_axi_clk") == 0)) {
+ msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
+ CLKFLAG_NORETAIN_MEM);
+ msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
+ CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
/* get all the regulators information */
rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd,
&pgmn_dev->num_reg);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
index b8840115b674..63d7e715162b 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
@@ -24,6 +24,7 @@
#include <media/videobuf2-core.h>
#include <media/v4l2-mem2mem.h>
#include <media/msm_jpeg_dma.h>
+#include <linux/clk/msm-clk.h>
#include "msm_jpeg_dma_dev.h"
#include "msm_jpeg_dma_hw.h"
@@ -1258,6 +1259,7 @@ static int jpegdma_probe(struct platform_device *pdev)
{
struct msm_jpegdma_device *jpegdma;
int ret;
+ int i;
dev_dbg(&pdev->dev, "jpeg v4l2 DMA probed\n");
/* Jpeg dma device struct */
@@ -1293,6 +1295,19 @@ static int jpegdma_probe(struct platform_device *pdev)
if (ret < 0)
goto error_get_clocks;
+ /*set memcore and mem periphery logic flags to 0*/
+ for (i = 0; i < jpegdma->num_clk; i++) {
+ if ((strcmp(jpegdma->jpeg_clk_info[i].clk_name,
+ "core_clk") == 0) ||
+ (strcmp(jpegdma->jpeg_clk_info[i].clk_name,
+ "mmss_camss_jpeg_axi_clk") == 0)) {
+ msm_camera_set_clk_flags(jpegdma->clk[i],
+ CLKFLAG_NORETAIN_MEM);
+ msm_camera_set_clk_flags(jpegdma->clk[i],
+ CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
ret = msm_jpegdma_hw_get_qos(jpegdma);
if (ret < 0)
goto error_qos_get;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 5a1e99adc7f3..f4add41c85c9 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -25,6 +25,7 @@
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
+#include <linux/clk/msm-clk.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/msmb_camera.h>
@@ -788,13 +789,6 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
int rc = 0;
uint32_t vbif_version;
- rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
- CAM_AHB_SVS_VOTE);
- if (rc < 0) {
- pr_err("%s: failed to vote for AHB\n", __func__);
- goto ahb_vote_fail;
- }
-
rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd,
cpp_dev->num_reg, true);
if (rc < 0) {
@@ -817,6 +811,13 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
goto clk_failed;
}
+ rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+ CAM_AHB_SVS_VOTE);
+ if (rc < 0) {
+ pr_err("%s: failed to vote for AHB\n", __func__);
+ goto ahb_vote_fail;
+ }
+
if (cpp_dev->state != CPP_STATE_BOOT) {
rc = msm_camera_register_irq(cpp_dev->pdev, cpp_dev->irq,
msm_cpp_irq, IRQF_TRIGGER_RISING, "cpp", cpp_dev);
@@ -880,16 +881,16 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
pwr_collapse_reset:
msm_cpp_update_gdscr_status(cpp_dev, false);
req_irq_fail:
+ if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+ CAM_AHB_SUSPEND_VOTE) < 0)
+ pr_err("%s: failed to remove vote for AHB\n", __func__);
+ahb_vote_fail:
msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info,
cpp_dev->cpp_clk, cpp_dev->num_clks, false);
clk_failed:
msm_camera_regulator_enable(cpp_dev->cpp_vdd,
cpp_dev->num_reg, false);
reg_enable_failed:
- if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
- CAM_AHB_SUSPEND_VOTE) < 0)
- pr_err("%s: failed to remove vote for AHB\n", __func__);
-ahb_vote_fail:
return rc;
}
@@ -903,6 +904,9 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev)
}
msm_cpp_delete_buff_queue(cpp_dev);
msm_cpp_update_gdscr_status(cpp_dev, false);
+ if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+ CAM_AHB_SUSPEND_VOTE) < 0)
+ pr_err("%s: failed to remove vote for AHB\n", __func__);
msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info,
cpp_dev->cpp_clk, cpp_dev->num_clks, false);
msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, false);
@@ -912,9 +916,6 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev)
}
cpp_dev->stream_cnt = 0;
- if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
- CAM_AHB_SUSPEND_VOTE) < 0)
- pr_err("%s: failed to remove vote for AHB\n", __func__);
}
static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
@@ -3932,6 +3933,7 @@ static int cpp_probe(struct platform_device *pdev)
{
struct cpp_device *cpp_dev;
int rc = 0;
+ int i = 0;
CPP_DBG("E");
cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL);
@@ -4000,6 +4002,21 @@ static int cpp_probe(struct platform_device *pdev)
goto mem_err;
}
+ /* set memcore and mem periphery logic flags to 0 */
+ for (i = 0; i < cpp_dev->num_clks; i++) {
+ if ((strcmp(cpp_dev->clk_info[i].clk_name,
+ "cpp_core_clk") == 0) ||
+ (strcmp(cpp_dev->clk_info[i].clk_name,
+ "camss_cpp_axi_clk") == 0) ||
+ (strcmp(cpp_dev->clk_info[i].clk_name,
+ "micro_iface_clk") == 0)) {
+ msm_camera_set_clk_flags(cpp_dev->cpp_clk[i],
+ CLKFLAG_NORETAIN_MEM);
+ msm_camera_set_clk_flags(cpp_dev->cpp_clk[i],
+ CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
rc = msm_camera_get_regulator_info(pdev, &cpp_dev->cpp_vdd,
&cpp_dev->num_reg);
if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index c12e95d3310a..d0ce1de1162a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -846,9 +846,14 @@ static int32_t msm_flash_get_pmic_source_info(
"qcom,current",
&fctrl->torch_op_current[i]);
if (rc < 0) {
- pr_err("current: read failed\n");
- of_node_put(torch_src_node);
- continue;
+ rc = of_property_read_u32(torch_src_node,
+ "qcom,current-ma",
+ &fctrl->torch_op_current[i]);
+ if (rc < 0) {
+ pr_err("current: read failed\n");
+ of_node_put(torch_src_node);
+ continue;
+ }
}
/* Read max-current */
@@ -915,6 +920,14 @@ static int32_t msm_flash_get_dt_data(struct device_node *of_node,
fctrl->flash_driver_type = FLASH_DRIVER_I2C;
}
+ /* Read the flash and torch source info from device tree node */
+ rc = msm_flash_get_pmic_source_info(of_node, fctrl);
+ if (rc < 0) {
+ pr_err("%s:%d msm_flash_get_pmic_source_info failed rc %d\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+
/* Read the gpio information from device tree */
rc = msm_sensor_driver_get_gpio_data(
&(fctrl->power_info.gpio_conf), of_node);
@@ -929,13 +942,6 @@ static int32_t msm_flash_get_dt_data(struct device_node *of_node,
CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__,
fctrl->flash_driver_type);
- /* Read the flash and torch source info from device tree node */
- rc = msm_flash_get_pmic_source_info(of_node, fctrl);
- if (rc < 0) {
- pr_err("%s:%d msm_flash_get_pmic_source_info failed rc %d\n",
- __func__, __LINE__, rc);
- return rc;
- }
return rc;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 9ce02d21704a..dae1b51bfaa8 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -35,10 +35,14 @@ static int sde_rotator_stat_show(struct seq_file *s, void *data)
u64 count = stats->count;
int num_events;
s64 proc_max, proc_min, proc_avg;
+ s64 swoh_max, swoh_min, swoh_avg;
proc_max = 0;
proc_min = S64_MAX;
proc_avg = 0;
+ swoh_max = 0;
+ swoh_min = S64_MAX;
+ swoh_avg = 0;
if (count > SDE_ROTATOR_NUM_EVENTS) {
num_events = SDE_ROTATOR_NUM_EVENTS;
@@ -59,9 +63,12 @@ static int sde_rotator_stat_show(struct seq_file *s, void *data)
s64 proc_time =
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
start_time));
+ s64 sw_overhead_time =
+ ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
+ start_time));
seq_printf(s,
- "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld\n",
+ "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
i,
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
ts[SDE_ROTATOR_TS_SRCQB])),
@@ -81,21 +88,30 @@ static int sde_rotator_stat_show(struct seq_file *s, void *data)
ts[SDE_ROTATOR_TS_RETIRE])),
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DSTDQB],
ts[SDE_ROTATOR_TS_RETIRE])),
- proc_time);
+ proc_time, sw_overhead_time);
proc_max = max(proc_max, proc_time);
proc_min = min(proc_min, proc_time);
proc_avg += proc_time;
+
+ swoh_max = max(swoh_max, sw_overhead_time);
+ swoh_min = min(swoh_min, sw_overhead_time);
+ swoh_avg += sw_overhead_time;
}
proc_avg = (num_events) ?
DIV_ROUND_CLOSEST_ULL(proc_avg, num_events) : 0;
+ swoh_avg = (num_events) ?
+ DIV_ROUND_CLOSEST_ULL(swoh_avg, num_events) : 0;
seq_printf(s, "count:%llu\n", count);
seq_printf(s, "fai1:%llu\n", stats->fail_count);
seq_printf(s, "t_max:%lld\n", proc_max);
seq_printf(s, "t_min:%lld\n", proc_min);
seq_printf(s, "t_avg:%lld\n", proc_avg);
+ seq_printf(s, "swoh_max:%lld\n", swoh_max);
+ seq_printf(s, "swoh_min:%lld\n", swoh_min);
+ seq_printf(s, "swoh_avg:%lld\n", swoh_avg);
return 0;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
index 8a1da4e6d632..fd247d10128c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
@@ -33,7 +33,7 @@
#define SDE_ROTATOR_DRV_NAME "sde_rotator"
/* Event logging constants */
-#define SDE_ROTATOR_NUM_EVENTS 256
+#define SDE_ROTATOR_NUM_EVENTS 4096
#define SDE_ROTATOR_NUM_TIMESTAMPS SDE_ROTATOR_TS_MAX
struct sde_rotator_device;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index c8d14a6d253b..8d5e3b649271 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/dma-buf.h>
#include <linux/msm_ion.h>
+#include <linux/clk/msm-clk.h>
#include "sde_rotator_core.h"
#include "sde_rotator_util.h"
@@ -1963,6 +1964,12 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
if (ret)
goto error_hw_rev_init;
+ /* set rotator CBCR to shutoff memory/periphery on clock off.*/
+ clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
+ CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
+ CLKFLAG_NORETAIN_PERIPH);
+
return 0;
error_hw_rev_init:
if (rot->irq_num >= 0)
diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig
index c9773555165e..ae451ff60c54 100644
--- a/drivers/media/platform/msm/vidc/Kconfig
+++ b/drivers/media/platform/msm/vidc/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig MSM_VIDC_V4L2
- bool "Qualcomm MSM V4L2 based video driver"
+ tristate "Qualcomm MSM V4L2 based video driver"
depends on ARCH_QCOM && VIDEO_V4L2
select VIDEOBUF2_CORE
diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile
index ff355611c0d0..55c2d2e8d30b 100644
--- a/drivers/media/platform/msm/vidc/Makefile
+++ b/drivers/media/platform/msm/vidc/Makefile
@@ -1,17 +1,21 @@
-obj-$(CONFIG_MSM_VIDC_V4L2) := msm_v4l2_vidc.o \
- msm_vidc_common.o \
- msm_vidc.o \
- msm_vdec.o \
- msm_venc.o \
- msm_smem.o \
- msm_vidc_debug.o \
- msm_vidc_res_parse.o \
- venus_hfi.o \
- hfi_response_handler.o \
- hfi_packetization.o \
- vidc_hfi.o \
- venus_boot.o \
- msm_vidc_dcvs.o
+ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/
+
+msm-vidc-objs := msm_v4l2_vidc.o \
+ msm_vidc_common.o \
+ msm_vidc.o \
+ msm_vdec.o \
+ msm_venc.o \
+ msm_smem.o \
+ msm_vidc_debug.o \
+ msm_vidc_res_parse.o \
+ venus_hfi.o \
+ hfi_response_handler.o \
+ hfi_packetization.o \
+ vidc_hfi.o \
+ venus_boot.o \
+ msm_vidc_dcvs.o
+
+obj-$(CONFIG_MSM_VIDC_V4L2) := msm-vidc.o
obj-$(CONFIG_MSM_VIDC_V4L2) += governors/
diff --git a/drivers/media/platform/msm/vidc/governors/Kconfig b/drivers/media/platform/msm/vidc/governors/Kconfig
index 32362217e0b9..d667d65d5338 100644
--- a/drivers/media/platform/msm/vidc/governors/Kconfig
+++ b/drivers/media/platform/msm/vidc/governors/Kconfig
@@ -1,5 +1,5 @@
menuconfig MSM_VIDC_GOVERNORS
- bool "Clock and bandwidth governors for QTI MSM V4L2 based video driver"
+ tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver"
depends on MSM_VIDC_V4L2 && PM_DEVFREQ
help
Chooses a set of devfreq governors aimed at providing accurate bandwidth
diff --git a/drivers/media/platform/msm/vidc/governors/Makefile b/drivers/media/platform/msm/vidc/governors/Makefile
index e5b2f9d7a049..06a4d3452f14 100644
--- a/drivers/media/platform/msm/vidc/governors/Makefile
+++ b/drivers/media/platform/msm/vidc/governors/Makefile
@@ -1,5 +1,9 @@
ccflags-y := -I$(srctree)/drivers/devfreq/ \
- -I$(srctree)/drivers/media/platform/msm/vidc/
+ -I$(srctree)/drivers/media/platform/msm/vidc/ \
+ -I$(srctree)/drivers/media/platform/msm/vidc/governors/
-obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_dyn_gov.o \
- msm_vidc_table_gov.o
+msm-vidc-dyn-gov-objs := msm_vidc_dyn_gov.o
+
+msm-vidc-table-gov-objs := msm_vidc_table_gov.o
+
+obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm-vidc-dyn-gov.o msm-vidc-table-gov.o
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 0d6a0caa86c8..58a7d0d0577a 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -781,3 +781,5 @@ static void __exit msm_vidc_exit(void)
module_init(msm_vidc_init);
module_exit(msm_vidc_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 96fefea39241..ee3df23115a5 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -601,10 +601,6 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
-static int set_buffer_size(struct msm_vidc_inst *inst,
- u32 buffer_size, enum hal_buffer buffer_type);
-static int update_output_buffer_size(struct msm_vidc_inst *inst,
- struct v4l2_format *f, int num_planes);
static int vdec_hal_to_v4l2(int id, int value);
static u32 get_frame_size_nv12(int plane,
@@ -1181,13 +1177,6 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
for (i = 0; i < fmt->num_planes; ++i)
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
- rc = update_output_buffer_size(inst, f, fmt->num_planes);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s - failed to update buffer size: %d\n",
- __func__, rc);
- goto exit;
- }
}
if (stride && scanlines) {
@@ -1220,95 +1209,6 @@ exit:
return rc;
}
-static int set_buffer_size(struct msm_vidc_inst *inst,
- u32 buffer_size, enum hal_buffer buffer_type)
-{
- int rc = 0;
- struct hfi_device *hdev;
- struct hal_buffer_size_minimum b;
-
- if (!inst || !inst->core || !inst->core->device) {
- dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- hdev = inst->core->device;
-
- dprintk(VIDC_DBG,
- "Set minimum buffer size = %d for buffer type %d to fw\n",
- buffer_size, buffer_type);
-
- b.buffer_type = buffer_type;
- b.buffer_size = buffer_size;
- rc = call_hfi_op(hdev, session_set_property,
- inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
- &b);
- if (rc)
- dprintk(VIDC_ERR,
- "%s - failed to set actual buffer size %u on firmware\n",
- __func__, buffer_size);
- return rc;
-}
-
-static int update_output_buffer_size(struct msm_vidc_inst *inst,
- struct v4l2_format *f, int num_planes)
-{
- int rc = 0, i = 0;
- struct hal_buffer_requirements *bufreq;
-
- if (!inst || !f)
- return -EINVAL;
-
- /*
- * Firmware expects driver to always set the minimum buffer
- * size negotiated with the v4l2 client. Firmware will use this
- * size to check for buffer sufficiency in dynamic buffer mode.
- */
- for (i = 0; i < num_planes; ++i) {
- enum hal_buffer type = msm_comm_get_hal_output_buffer(inst);
-
- if (EXTRADATA_IDX(num_planes) &&
- i == EXTRADATA_IDX(num_planes))
- continue;
-
- bufreq = get_buff_req_buffer(inst, type);
- if (!bufreq)
- goto exit;
-
- if (f->fmt.pix_mp.plane_fmt[i].sizeimage >=
- bufreq->buffer_size) {
- rc = set_buffer_size(inst,
- f->fmt.pix_mp.plane_fmt[i].sizeimage, type);
- if (rc)
- goto exit;
- }
- }
-
- /*
- * Set min buffer size for DPB buffers as well.
- * Firmware mandates setting of minimum buffer size
- * and actual buffer count for both OUTPUT and OUTPUT2.
- * Hence we are setting back the same buffer size
- * information back to firmware.
- */
- if (msm_comm_get_stream_output_mode(inst) ==
- HAL_VIDEO_DECODER_SECONDARY) {
- bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
- if (!bufreq) {
- rc = -EINVAL;
- goto exit;
- }
-
- rc = set_buffer_size(inst, bufreq->buffer_size,
- HAL_BUFFER_OUTPUT);
- if (rc)
- goto exit;
- }
-
-exit:
- return rc;
-}
-
static int set_default_properties(struct msm_vidc_inst *inst)
{
struct hfi_device *hdev;
@@ -1370,13 +1270,9 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
- if (msm_comm_get_stream_output_mode(inst) ==
- HAL_VIDEO_DECODER_PRIMARY) {
- inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
- inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
- msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
+ msm_comm_set_color_format(inst,
+ msm_comm_get_hal_output_buffer(inst),
f->fmt.pix_mp.pixelformat);
- }
inst->fmts[fmt->type] = fmt;
if (msm_comm_get_stream_output_mode(inst) ==
@@ -1384,8 +1280,6 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
frame_sz.width = inst->prop.width[CAPTURE_PORT];
frame_sz.height = inst->prop.height[CAPTURE_PORT];
- msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2,
- f->fmt.pix_mp.pixelformat);
dprintk(VIDC_DBG,
"buffer type = %d width = %d, height = %d\n",
frame_sz.buffer_type, frame_sz.width,
@@ -1793,12 +1687,28 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
int rc = 0;
struct hfi_device *hdev;
bool slave_side_cp = inst->core->resources.slave_side_cp;
+ struct hal_buffer_size_minimum b;
+ unsigned int buffer_size;
+ struct msm_vidc_format *fmt = NULL;
+ fmt = inst->fmts[CAPTURE_PORT];
+ buffer_size = fmt->get_frame_size(0,
+ inst->prop.height[CAPTURE_PORT],
+ inst->prop.width[CAPTURE_PORT]);
hdev = inst->core->device;
if (msm_comm_get_stream_output_mode(inst) ==
- HAL_VIDEO_DECODER_SECONDARY)
+ HAL_VIDEO_DECODER_SECONDARY) {
rc = msm_vidc_check_scaling_supported(inst);
+ b.buffer_type = HAL_BUFFER_OUTPUT2;
+ } else {
+ b.buffer_type = HAL_BUFFER_OUTPUT;
+ }
+
+ b.buffer_size = buffer_size;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+ &b);
if (rc) {
dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
return -EINVAL;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c08084a54e86..55ee7e02973c 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2702,7 +2702,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
(inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_HEVC);
if (is_cont_intra_supported) {
- if (air_mbs || air_ref || cir_mbs)
+ if (ctrl->val != HAL_INTRA_REFRESH_NONE)
enable.enable = true;
else
enable.enable = false;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 1f071ba36ec1..587aa930cf9c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3010,6 +3010,7 @@ static int set_output_buffers(struct msm_vidc_inst *inst,
struct hal_buffer_requirements *output_buf, *extradata_buf;
int i;
struct hfi_device *hdev;
+ struct hal_buffer_size_minimum b;
hdev = inst->core->device;
@@ -3026,6 +3027,11 @@ static int set_output_buffers(struct msm_vidc_inst *inst,
output_buf->buffer_size);
buffer_size = output_buf->buffer_size;
+ b.buffer_type = buffer_type;
+ b.buffer_size = buffer_size;
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+ &b);
extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
if (extradata_buf) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 7976d6e8a603..1928327b60db 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -16,7 +16,11 @@
#include "vidc_hfi_api.h"
int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+EXPORT_SYMBOL(msm_vidc_debug);
+
int msm_vidc_debug_out = VIDC_OUT_PRINTK;
+EXPORT_SYMBOL(msm_vidc_debug_out);
+
int msm_vidc_fw_debug = 0x18;
int msm_vidc_fw_debug_mode = 1;
int msm_vidc_fw_low_power_mode = 1;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 2bb91ccc6c26..240dc0caf94d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -25,6 +25,7 @@
enum clock_properties {
CLOCK_PROP_HAS_SCALING = 1 << 0,
+ CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1,
};
static int msm_vidc_populate_legacy_context_bank(
struct msm_vidc_platform_resources *res);
@@ -364,6 +365,7 @@ int msm_vidc_load_u32_table(struct platform_device *pdev,
return rc;
}
+EXPORT_SYMBOL(msm_vidc_load_u32_table);
static int msm_vidc_load_platform_version_table(
struct msm_vidc_platform_resources *res)
@@ -943,6 +945,11 @@ static int msm_vidc_load_clock_table(
vc->has_scaling = false;
}
+ if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION)
+ vc->has_mem_retention = true;
+ else
+ vc->has_mem_retention = false;
+
dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name,
vc->count ? "yes" : "no");
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index c61605c7e405..734586a3f76c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -104,6 +104,7 @@ struct clock_info {
struct load_freq_table *load_freq_tbl;
u32 count;
bool has_scaling;
+ bool has_mem_retention;
};
struct clock_set {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 50c0eb351d4f..217d6a48d17a 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -738,6 +738,7 @@ bool venus_hfi_is_session_supported(unsigned long sessions_supported,
{
return __is_session_supported(sessions_supported, session_type);
}
+EXPORT_SYMBOL(venus_hfi_is_session_supported);
static int __devfreq_target(struct device *devfreq_dev,
unsigned long *freq, u32 flags)
@@ -2191,8 +2192,6 @@ static int venus_hfi_core_init(void *device)
INIT_LIST_HEAD(&dev->sess_head);
- __set_registers(dev);
-
if (!dev->hal_client) {
dev->hal_client = msm_smem_new_client(
SMEM_ION, dev->res, MSM_VIDC_UNKNOWN);
@@ -3788,6 +3787,22 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device)
if (cl->has_scaling)
clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
+ if (cl->has_mem_retention) {
+ rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed set flag NORETAIN_PERIPH %s\n",
+ cl->name);
+ }
+
+ rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed set flag NORETAIN_MEM %s\n",
+ cl->name);
+ }
+ }
+
rc = clk_prepare_enable(cl->clk);
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks\n");
@@ -4177,6 +4192,13 @@ static int __venus_power_on(struct venus_hfi_device *device)
"Failed to scale clocks, performance might be affected\n");
rc = 0;
}
+
+ /*
+ * Re-program all of the registers that get reset as a result of
+ * regulator_disable() and _enable()
+ */
+ __set_registers(device);
+
__write_register(device, VIDC_WRAPPER_INTR_MASK,
VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
device->intr_status = 0;
@@ -4291,11 +4313,6 @@ static inline int __resume(struct venus_hfi_device *device)
goto err_set_video_state;
}
- /*
- * Re-program all of the registers that get reset as a result of
- * regulator_disable() and _enable()
- */
- __set_registers(device);
__setup_ucregion_memory_map(device);
/* Wait for boot completion */
rc = __boot_firmware(device);
diff --git a/drivers/media/platform/msm/vidc/vmem/Kconfig b/drivers/media/platform/msm/vidc/vmem/Kconfig
index e602e52da383..6f54120e2d04 100644
--- a/drivers/media/platform/msm/vidc/vmem/Kconfig
+++ b/drivers/media/platform/msm/vidc/vmem/Kconfig
@@ -1,3 +1,3 @@
menuconfig MSM_VIDC_VMEM
- bool "Qualcomm Technologies Inc MSM VMEM driver"
+ tristate "Qualcomm Technologies Inc MSM VMEM driver"
depends on ARCH_QCOM && MSM_VIDC_V4L2
diff --git a/drivers/media/platform/msm/vidc/vmem/Makefile b/drivers/media/platform/msm/vidc/vmem/Makefile
index 713b92e64544..a56ad95f8b71 100644
--- a/drivers/media/platform/msm/vidc/vmem/Makefile
+++ b/drivers/media/platform/msm/vidc/vmem/Makefile
@@ -1,2 +1,7 @@
-obj-$(CONFIG_MSM_VIDC_VMEM) := vmem.o \
- vmem_debugfs.o
+ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/
+ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/vmem/
+
+msm-vidc-vmem-objs := vmem.o \
+ vmem_debugfs.o
+
+obj-$(CONFIG_MSM_VIDC_VMEM) := msm-vidc-vmem.o
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.c b/drivers/media/platform/msm/vidc/vmem/vmem.c
index 3a2ac31c6450..165c5c0b4e4b 100644
--- a/drivers/media/platform/msm/vidc/vmem/vmem.c
+++ b/drivers/media/platform/msm/vidc/vmem/vmem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/clk/msm-clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -111,6 +112,7 @@ struct vmem {
struct {
const char *name;
struct clk *clk;
+ bool has_mem_retention;
} *clocks;
int num_clocks;
struct {
@@ -186,6 +188,21 @@ static inline int __power_on(struct vmem *v)
pr_debug("Enabled regulator vdd\n");
for (c = 0; c < v->num_clocks; ++c) {
+ if (v->clocks[c].has_mem_retention) {
+ rc = clk_set_flags(v->clocks[c].clk,
+ CLKFLAG_NORETAIN_PERIPH);
+ if (rc) {
+ pr_warn("Failed set flag NORETAIN_PERIPH %s\n",
+ v->clocks[c].name);
+ }
+ rc = clk_set_flags(v->clocks[c].clk,
+ CLKFLAG_NORETAIN_MEM);
+ if (rc) {
+ pr_warn("Failed set flag NORETAIN_MEM %s\n",
+ v->clocks[c].name);
+ }
+ }
+
rc = clk_prepare_enable(v->clocks[c].clk);
if (rc) {
pr_err("Failed to enable %s clock (%d)\n",
@@ -355,6 +372,7 @@ int vmem_allocate(size_t size, phys_addr_t *addr)
exit:
return rc;
}
+EXPORT_SYMBOL(vmem_allocate);
/**
* vmem_free: - Frees the memory allocated via vmem_allocate. Undefined
@@ -384,6 +402,7 @@ void vmem_free(phys_addr_t to_free)
__power_off(vmem);
atomic_dec(&vmem->alloc_count);
}
+EXPORT_SYMBOL(vmem_free);
struct vmem_interrupt_cookie {
struct vmem *vmem;
@@ -448,6 +467,7 @@ static inline int __init_resources(struct vmem *v,
struct platform_device *pdev)
{
int rc = 0, c = 0;
+ int *clock_props = NULL;
v->irq = platform_get_irq(pdev, 0);
if (v->irq < 0) {
@@ -504,6 +524,21 @@ static inline int __init_resources(struct vmem *v,
goto exit;
}
+ clock_props = devm_kzalloc(&pdev->dev,
+ v->num_clocks * sizeof(*clock_props),
+ GFP_KERNEL);
+ if (!clock_props) {
+ pr_err("Failed to allocate clock config table\n");
+ goto exit;
+ }
+
+ rc = of_property_read_u32_array(pdev->dev.of_node, "clock-config",
+ clock_props, v->num_clocks);
+ if (rc) {
+ pr_err("Failed to read clock config\n");
+ goto exit;
+ }
+
for (c = 0; c < v->num_clocks; ++c) {
const char *name = NULL;
struct clk *temp = NULL;
@@ -519,6 +554,7 @@ static inline int __init_resources(struct vmem *v,
v->clocks[c].clk = temp;
v->clocks[c].name = name;
+ v->clocks[c].has_mem_retention = clock_props[c];
}
v->vdd = devm_regulator_get(&pdev->dev, "vdd");
@@ -699,3 +735,5 @@ static void __exit vmem_exit(void)
module_init(vmem_init);
module_exit(vmem_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.h b/drivers/media/platform/msm/vidc/vmem/vmem.h
index 751904e00755..2f3a26db086b 100644
--- a/drivers/media/platform/msm/vidc/vmem/vmem.h
+++ b/drivers/media/platform/msm/vidc/vmem/vmem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,7 +14,7 @@
#ifndef __VMEM_H__
#define __VMEM_H__
-#ifdef CONFIG_MSM_VIDC_VMEM
+#if (defined CONFIG_MSM_VIDC_VMEM) || (defined CONFIG_MSM_VIDC_VMEM_MODULE)
int vmem_allocate(size_t size, phys_addr_t *addr);
void vmem_free(phys_addr_t to_free);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 1b93c83ae98e..0c5754341991 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -741,6 +741,7 @@ static int wcd9xxx_irq_remove(struct platform_device *pdev)
wmb();
irq_domain_remove(data->domain);
kfree(data);
+ domain->host_data = NULL;
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index c63e8d6d926e..4bce44008c45 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -220,7 +220,8 @@ int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
__func__, ch_cnt, rate, WATER_MARK_VAL);
/* slim_define_ch api */
prop.prot = SLIM_AUTO_ISO;
- if (rate == 44100) {
+ if ((rate == 44100) || (rate == 88200) || (rate == 176400) ||
+ (rate == 352800)) {
prop.baser = SLIM_RATE_11025HZ;
prop.ratem = (rate/11025);
} else {
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 011e7412dcc0..f10c47dcbde5 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -101,7 +101,7 @@ static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
mask_halp ? WIL6210_IRQ_DISABLE : WIL6210_IRQ_DISABLE_NO_HALP);
}
-static void wil6210_mask_halp(struct wil6210_priv *wil)
+void wil6210_mask_halp(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -503,6 +503,13 @@ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
offsetof(struct RGF_ICR, ICR));
u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
offsetof(struct RGF_ICR, IMV));
+
+ /* HALP interrupt can be unmasked when misc interrupts are
+ * masked
+ */
+ if (icr_misc & BIT_DMA_EP_MISC_ICR_HALP)
+ return 0;
+
wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
"Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
"Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index bd8f481da44c..49bd9b45ce22 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1119,13 +1119,16 @@ void wil_halp_vote(struct wil6210_priv *wil)
if (++wil->halp.ref_cnt == 1) {
wil6210_set_halp(wil);
rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
- if (!rc)
+ if (!rc) {
wil_err(wil, "%s: HALP vote timed out\n", __func__);
- else
+ /* Mask HALP as done in case the interrupt is raised */
+ wil6210_mask_halp(wil);
+ } else {
wil_dbg_misc(wil,
"%s: HALP vote completed after %d ms\n",
__func__,
jiffies_to_msecs(to_jiffies - rc));
+ }
}
wil_dbg_misc(wil, "%s: end, HALP ref_cnt (%d)\n", __func__,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index cd0bfdf34248..16e8ba570011 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -831,6 +831,7 @@ void wil_unmask_irq(struct wil6210_priv *wil);
void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
void wil_disable_irq(struct wil6210_priv *wil);
void wil_enable_irq(struct wil6210_priv *wil);
+void wil6210_mask_halp(struct wil6210_priv *wil);
/* P2P */
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index 9b962a63c3d8..154310020997 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -63,6 +63,8 @@ struct nqx_dev {
bool nfc_ven_enabled;
/* NFC_IRQ state */
bool irq_enabled;
+ /* NFC_IRQ wake-up state */
+ bool irq_wake_up;
spinlock_t irq_enabled_lock;
unsigned int count_irq;
/* Initial CORE RESET notification */
@@ -372,6 +374,9 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
} else {
dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n");
}
+ } else {
+ dev_dbg(&nqx_dev->client->dev, "ese_gpio invalid, set en_gpio to low\n");
+ gpio_set_value(nqx_dev->en_gpio, 0);
}
r = nqx_clock_deselect(nqx_dev);
if (r < 0)
@@ -777,21 +782,29 @@ static int nqx_probe(struct i2c_client *client,
r = gpio_request(platform_data->ese_gpio,
"nfc-ese_pwr");
if (r) {
+ nqx_dev->ese_gpio = -EINVAL;
dev_err(&client->dev,
"%s: unable to request nfc ese gpio [%d]\n",
__func__, platform_data->ese_gpio);
/* ese gpio optional so we should continue */
} else {
nqx_dev->ese_gpio = platform_data->ese_gpio;
- }
- r = gpio_direction_output(platform_data->ese_gpio, 0);
- if (r) {
- dev_err(&client->dev,
- "%s: cannot set direction for nfc ese gpio [%d]\n",
- __func__, platform_data->ese_gpio);
- /* ese gpio optional so we should continue */
+ r = gpio_direction_output(platform_data->ese_gpio, 0);
+ if (r) {
+ /*
+ * free ese gpio and set invalid
+ * to avoid further use
+ */
+ gpio_free(platform_data->ese_gpio);
+ nqx_dev->ese_gpio = -EINVAL;
+ dev_err(&client->dev,
+ "%s: cannot set direction for nfc ese gpio [%d]\n",
+ __func__, platform_data->ese_gpio);
+ /* ese gpio optional so we should continue */
+ }
}
} else {
+ nqx_dev->ese_gpio = -EINVAL;
dev_err(&client->dev,
"%s: ese gpio not provided\n", __func__);
/* ese gpio optional so we should continue */
@@ -821,7 +834,6 @@ static int nqx_probe(struct i2c_client *client,
nqx_dev->en_gpio = platform_data->en_gpio;
nqx_dev->irq_gpio = platform_data->irq_gpio;
nqx_dev->firm_gpio = platform_data->firm_gpio;
- nqx_dev->ese_gpio = platform_data->ese_gpio;
nqx_dev->clkreq_gpio = platform_data->clkreq_gpio;
nqx_dev->pdata = platform_data;
@@ -889,6 +901,7 @@ static int nqx_probe(struct i2c_client *client,
device_init_wakeup(&client->dev, true);
device_set_wakeup_capable(&client->dev, true);
i2c_set_clientdata(client, nqx_dev);
+ nqx_dev->irq_wake_up = false;
dev_err(&client->dev,
"%s: probing NFCC NQxxx exited successfully\n",
@@ -909,7 +922,7 @@ err_clkreq_gpio:
gpio_free(platform_data->clkreq_gpio);
err_ese_gpio:
/* optional gpio, not sure was configured in probe */
- if (nqx_dev->ese_gpio)
+ if (nqx_dev->ese_gpio > 0)
gpio_free(platform_data->ese_gpio);
err_firm_gpio:
gpio_free(platform_data->firm_gpio);
@@ -950,7 +963,7 @@ static int nqx_remove(struct i2c_client *client)
mutex_destroy(&nqx_dev->read_mutex);
gpio_free(nqx_dev->clkreq_gpio);
/* optional gpio, not sure was configured in probe */
- if (nqx_dev->ese_gpio)
+ if (nqx_dev->ese_gpio > 0)
gpio_free(nqx_dev->ese_gpio);
gpio_free(nqx_dev->firm_gpio);
gpio_free(nqx_dev->irq_gpio);
@@ -969,17 +982,22 @@ static int nqx_suspend(struct device *device)
struct i2c_client *client = to_i2c_client(device);
struct nqx_dev *nqx_dev = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev) && nqx_dev->irq_enabled)
- enable_irq_wake(client->irq);
+ if (device_may_wakeup(&client->dev) && nqx_dev->irq_enabled) {
+ if (!enable_irq_wake(client->irq))
+ nqx_dev->irq_wake_up = true;
+ }
return 0;
}
static int nqx_resume(struct device *device)
{
struct i2c_client *client = to_i2c_client(device);
+ struct nqx_dev *nqx_dev = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(client->irq);
+ if (device_may_wakeup(&client->dev) && nqx_dev->irq_wake_up) {
+ if (!disable_irq_wake(client->irq))
+ nqx_dev->irq_wake_up = false;
+ }
return 0;
}
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 84932513f008..0acebc87ec20 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -796,14 +796,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_SERIAL_EARLYCON
-extern struct of_device_id __earlycon_of_table[];
static int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
const char *p;
int l;
- const struct of_device_id *match = __earlycon_of_table;
+ const struct earlycon_id *match;
const void *fdt = initial_boot_params;
offset = fdt_path_offset(fdt, "/chosen");
@@ -826,19 +825,20 @@ static int __init early_init_dt_scan_chosen_serial(void)
if (offset < 0)
return -ENODEV;
- while (match->compatible[0]) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
u64 addr;
- if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
- match++;
+ if (!match->compatible[0])
+ continue;
+
+ if (fdt_node_check_compatible(fdt, offset, match->compatible))
continue;
- }
addr = fdt_translate_address(fdt, offset);
if (addr == OF_BAD_ADDR)
return -ENXIO;
- of_setup_earlycon(addr, match->data);
+ of_setup_earlycon(addr, match->setup);
return 0;
}
return -ENODEV;
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 53e3af9052a9..71154ec99d3c 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -550,6 +550,7 @@ static void armpmu_init(struct arm_pmu *armpmu)
.stop = armpmu_stop,
.read = armpmu_read,
.filter_match = armpmu_filter_match,
+ .events_across_hotplug = 1,
};
}
@@ -686,31 +687,12 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
return 0;
}
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
- void *hcpu)
-{
- int cpu = (unsigned long)hcpu;
- struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb);
-
- if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
- return NOTIFY_DONE;
-
- if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
- return NOTIFY_DONE;
-
- if (pmu->reset)
- pmu->reset(pmu);
- else
- return NOTIFY_DONE;
-
- return NOTIFY_OK;
-}
+struct cpu_pm_pmu_args {
+ struct arm_pmu *armpmu;
+ unsigned long cmd;
+ int cpu;
+ int ret;
+};
#ifdef CONFIG_CPU_PM
static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
@@ -758,15 +740,19 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
}
}
-static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
- void *v)
+static void cpu_pm_pmu_common(void *info)
{
- struct arm_pmu *armpmu = container_of(b, struct arm_pmu, cpu_pm_nb);
+ struct cpu_pm_pmu_args *data = info;
+ struct arm_pmu *armpmu = data->armpmu;
+ unsigned long cmd = data->cmd;
+ int cpu = data->cpu;
struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
- if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
- return NOTIFY_DONE;
+ if (!cpumask_test_cpu(cpu, &armpmu->supported_cpus)) {
+ data->ret = NOTIFY_DONE;
+ return;
+ }
/*
* Always reset the PMU registers on power-up even if
@@ -775,8 +761,12 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
if (cmd == CPU_PM_EXIT && armpmu->reset)
armpmu->reset(armpmu);
- if (!enabled)
- return NOTIFY_OK;
+ if (!enabled) {
+ data->ret = NOTIFY_OK;
+ return;
+ }
+
+ data->ret = NOTIFY_OK;
switch (cmd) {
case CPU_PM_ENTER:
@@ -784,15 +774,29 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
cpu_pm_pmu_setup(armpmu, cmd);
break;
case CPU_PM_EXIT:
- cpu_pm_pmu_setup(armpmu, cmd);
case CPU_PM_ENTER_FAILED:
+ cpu_pm_pmu_setup(armpmu, cmd);
armpmu->start(armpmu);
break;
default:
- return NOTIFY_DONE;
+ data->ret = NOTIFY_DONE;
+ break;
}
- return NOTIFY_OK;
+ return;
+}
+
+static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
+ void *v)
+{
+ struct cpu_pm_pmu_args data = {
+ .armpmu = container_of(b, struct arm_pmu, cpu_pm_nb),
+ .cmd = cmd,
+ .cpu = smp_processor_id(),
+ };
+
+ cpu_pm_pmu_common(&data);
+ return data.ret;
}
static int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu)
@@ -808,8 +812,62 @@ static void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu)
#else
static inline int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) { return 0; }
static inline void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) { }
+static inline void cpu_pm_pmu_common(void *info) { }
#endif
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
+ void *hcpu)
+{
+ unsigned long masked_action = (action & ~CPU_TASKS_FROZEN);
+ struct cpu_pm_pmu_args data = {
+ .armpmu = container_of(b, struct arm_pmu, hotplug_nb),
+ .cpu = (unsigned long)hcpu,
+ };
+
+ if (!cpumask_test_cpu(data.cpu, &data.armpmu->supported_cpus))
+ return NOTIFY_DONE;
+
+ switch (masked_action) {
+ case CPU_STARTING:
+ data.cmd = CPU_PM_EXIT;
+ break;
+ case CPU_DYING:
+ data.cmd = CPU_PM_ENTER;
+ break;
+ case CPU_DOWN_FAILED:
+ data.cmd = CPU_PM_ENTER_FAILED;
+ break;
+ case CPU_ONLINE:
+ if (data.armpmu->plat_device) {
+ struct platform_device *pmu_device =
+ data.armpmu->plat_device;
+ int irq = platform_get_irq(pmu_device, 0);
+
+ if (irq >= 0 && irq_is_percpu(irq)) {
+ smp_call_function_single(data.cpu,
+ cpu_pmu_enable_percpu_irq, &irq, 1);
+ }
+ }
+ return NOTIFY_DONE;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ if (smp_processor_id() == data.cpu)
+ cpu_pm_pmu_common(&data);
+ else
+ smp_call_function_single(data.cpu,
+ cpu_pm_pmu_common, &data, 1);
+
+ return data.ret;
+}
+
static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
{
int err;
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index d2e31c3b0945..af1e5a70d585 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -643,6 +643,13 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl)
GSIERR("failed to register isr for %u\n", props->irq);
return -GSI_STATUS_ERROR;
}
+
+ res = enable_irq_wake(props->irq);
+ if (res)
+ GSIERR("failed to enable wake irq %u\n", props->irq);
+ else
+ GSIERR("GSI irq is wake enabled %u\n", props->irq);
+
} else {
GSIERR("do not support interrupt type %u\n", props->intr);
return -GSI_STATUS_UNSUPPORTED_OP;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index fc3d9f355da6..a2f1c5c9af27 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3613,6 +3613,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
ipa_ctx->ipa_bam_remote_mode = resource_p->ipa_bam_remote_mode;
ipa_ctx->modem_cfg_emb_pipe_flt = resource_p->modem_cfg_emb_pipe_flt;
ipa_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
+ ipa_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
ipa_ctx->use_dma_zone = resource_p->use_dma_zone;
ipa_ctx->tethered_flow_control = resource_p->tethered_flow_control;
@@ -4150,6 +4151,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->ipa_bam_remote_mode = false;
ipa_drv_res->modem_cfg_emb_pipe_flt = false;
ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
+ ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
smmu_info.disable_htw = of_property_read_bool(pdev->dev.of_node,
"qcom,smmu-disable-htw");
@@ -4172,16 +4174,27 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
IPADBG(": found ipa_drv_res->ipa_hw_mode = %d",
ipa_drv_res->ipa_hw_mode);
- /* Get IPA WAN RX pool sizee */
+ /* Get IPA WAN / LAN RX pool sizes */
result = of_property_read_u32(pdev->dev.of_node,
"qcom,wan-rx-ring-size",
&ipa_drv_res->wan_rx_ring_size);
if (result)
- IPADBG("using default for wan-rx-ring-size\n");
+ IPADBG("using default for wan-rx-ring-size = %u\n",
+ ipa_drv_res->wan_rx_ring_size);
else
IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
ipa_drv_res->wan_rx_ring_size);
+ result = of_property_read_u32(pdev->dev.of_node,
+ "qcom,lan-rx-ring-size",
+ &ipa_drv_res->lan_rx_ring_size);
+ if (result)
+ IPADBG("using default for lan-rx-ring-size = %u\n",
+ ipa_drv_res->lan_rx_ring_size);
+ else
+ IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
+ ipa_drv_res->lan_rx_ring_size);
+
ipa_drv_res->use_ipa_teth_bridge =
of_property_read_bool(pdev->dev.of_node,
"qcom,use-ipa-tethering-bridge");
@@ -4440,7 +4453,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
cb->dev = dev;
cb->mapping = arm_iommu_create_mapping(msm_iommu_get_bus(dev),
cb->va_start, cb->va_size);
- if (IS_ERR(cb->mapping)) {
+ if (IS_ERR_OR_NULL(cb->mapping)) {
IPADBG("Fail to create mapping\n");
/* assume this failure is because iommu driver is not ready */
return -EPROBE_DEFER;
@@ -4543,7 +4556,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
cb->mapping = arm_iommu_create_mapping(msm_iommu_get_bus(dev),
cb->va_start,
cb->va_size);
- if (IS_ERR(cb->mapping)) {
+ if (IS_ERR_OR_NULL(cb->mapping)) {
IPADBG("Fail to create mapping\n");
/* assume this failure is because iommu driver is not ready */
return -EPROBE_DEFER;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index 005508fdcdc1..c0ac544fa271 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -3142,7 +3142,7 @@ static int ipa_assign_policy_v2(struct ipa_sys_connect_params *in,
ipa_replenish_rx_cache;
}
sys->rx_pool_sz =
- IPA_GENERIC_RX_POOL_SZ;
+ ipa_ctx->lan_rx_ring_size;
in->ipa_ep_cfg.aggr.aggr_byte_limit =
IPA_GENERIC_AGGR_BYTE_LIMIT;
in->ipa_ep_cfg.aggr.aggr_pkt_limit =
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 5ea7a08b3135..5b8abb25cfb0 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1102,6 +1102,7 @@ struct ipa_context {
struct ipa_uc_wdi_ctx uc_wdi_ctx;
struct ipa_uc_ntn_ctx uc_ntn_ctx;
u32 wan_rx_ring_size;
+ u32 lan_rx_ring_size;
bool skip_uc_pipe_reset;
bool smmu_present;
bool smmu_s1_bypass;
@@ -1171,6 +1172,7 @@ struct ipa_plat_drv_res {
bool ipa_bam_remote_mode;
bool modem_cfg_emb_pipe_flt;
u32 wan_rx_ring_size;
+ u32 lan_rx_ring_size;
bool skip_uc_pipe_reset;
bool use_dma_zone;
bool tethered_flow_control;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 4db07bad7d93..9115e30b2b21 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3953,6 +3953,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
ipa3_ctx->ipa_wdi2 = resource_p->ipa_wdi2;
ipa3_ctx->use_64_bit_dma_mask = resource_p->use_64_bit_dma_mask;
ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size;
+ ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size;
ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
ipa3_ctx->transport_prototype = resource_p->transport_prototype;
@@ -4432,6 +4433,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->ipa_wdi2 = false;
ipa_drv_res->use_64_bit_dma_mask = false;
ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
+ ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
ipa_drv_res->apply_rg10_wa = false;
ipa_drv_res->gsi_ch20_wa = false;
@@ -4461,16 +4463,27 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
IPADBG(": found ipa_drv_res->ipa3_hw_mode = %d",
ipa_drv_res->ipa3_hw_mode);
- /* Get IPA WAN RX pool size */
+ /* Get IPA WAN / LAN RX pool size */
result = of_property_read_u32(pdev->dev.of_node,
"qcom,wan-rx-ring-size",
&ipa_drv_res->wan_rx_ring_size);
if (result)
- IPADBG("using default for wan-rx-ring-size\n");
+ IPADBG("using default for wan-rx-ring-size = %u\n",
+ ipa_drv_res->wan_rx_ring_size);
else
IPADBG(": found ipa_drv_res->wan-rx-ring-size = %u",
ipa_drv_res->wan_rx_ring_size);
+ result = of_property_read_u32(pdev->dev.of_node,
+ "qcom,lan-rx-ring-size",
+ &ipa_drv_res->lan_rx_ring_size);
+ if (result)
+ IPADBG("using default for lan-rx-ring-size = %u\n",
+ ipa_drv_res->lan_rx_ring_size);
+ else
+ IPADBG(": found ipa_drv_res->lan-rx-ring-size = %u",
+ ipa_drv_res->lan_rx_ring_size);
+
ipa_drv_res->use_ipa_teth_bridge =
of_property_read_bool(pdev->dev.of_node,
"qcom,use-ipa-tethering-bridge");
@@ -4752,7 +4765,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
cb->dev = dev;
cb->mapping = arm_iommu_create_mapping(msm_iommu_get_bus(dev),
cb->va_start, cb->va_size);
- if (IS_ERR(cb->mapping)) {
+ if (IS_ERR_OR_NULL(cb->mapping)) {
IPADBG("Fail to create mapping\n");
/* assume this failure is because iommu driver is not ready */
return -EPROBE_DEFER;
@@ -4866,7 +4879,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
cb->dev = dev;
cb->mapping = arm_iommu_create_mapping(msm_iommu_get_bus(dev),
cb->va_start, cb->va_size);
- if (IS_ERR(cb->mapping)) {
+ if (IS_ERR_OR_NULL(cb->mapping)) {
IPADBG("Fail to create mapping\n");
/* assume this failure is because iommu driver is not ready */
return -EPROBE_DEFER;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 4c600c6131e9..8f61827b50b4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -3171,7 +3171,7 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
sys->free_rx_wrapper =
ipa3_recycle_rx_wrapper;
sys->rx_pool_sz =
- IPA_GENERIC_RX_POOL_SZ;
+ ipa3_ctx->lan_rx_ring_size;
in->ipa_ep_cfg.aggr.aggr_byte_limit =
IPA_GENERIC_AGGR_BYTE_LIMIT;
in->ipa_ep_cfg.aggr.aggr_pkt_limit =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index a7587b2b9675..f9018e3f47bf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1202,6 +1202,7 @@ struct ipa3_context {
struct ipa3_uc_wdi_ctx uc_wdi_ctx;
struct ipa3_uc_ntn_ctx uc_ntn_ctx;
u32 wan_rx_ring_size;
+ u32 lan_rx_ring_size;
bool skip_uc_pipe_reset;
enum ipa_transport_type transport_prototype;
unsigned long gsi_dev_hdl;
@@ -1259,6 +1260,7 @@ struct ipa3_plat_drv_res {
bool ipa_wdi2;
bool use_64_bit_dma_mask;
u32 wan_rx_ring_size;
+ u32 lan_rx_ring_size;
bool skip_uc_pipe_reset;
enum ipa_transport_type transport_prototype;
bool apply_rg10_wa;
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index e9b0945f0782..eab0e47e7cd2 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -289,7 +289,8 @@ static ssize_t sps_set_bam_addr(struct file *file, const char __user *buf,
} else {
vir_addr = &bam->base;
num_pipes = bam->props.num_pipes;
- bam->ipc_loglevel = log_level_sel;
+ if (log_level_sel <= SPS_IPC_MAX_LOGLEVEL)
+ bam->ipc_loglevel = log_level_sel;
}
switch (reg_dump_option) {
@@ -500,7 +501,7 @@ static void sps_debugfs_init(void)
debugfs_buf_size = 0;
debugfs_buf_used = 0;
wraparound = false;
- log_level_sel = 0;
+ log_level_sel = SPS_IPC_MAX_LOGLEVEL + 1;
dent = debugfs_create_dir("sps", 0);
if (IS_ERR(dent)) {
@@ -2207,6 +2208,8 @@ int sps_register_bam_device(const struct sps_bam_props *bam_props,
if (bam_props->ipc_loglevel)
bam->ipc_loglevel = bam_props->ipc_loglevel;
+ else
+ bam->ipc_loglevel = SPS_IPC_DEFAULT_LOGLEVEL;
ok = sps_bam_device_init(bam);
mutex_unlock(&bam->lock);
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index e09d3cda1d31..1b4ca69bee16 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -52,6 +52,8 @@
#define MAX_MSG_LEN 80
#define SPS_IPC_LOGPAGES 10
#define SPS_IPC_REG_DUMP_FACTOR 3
+#define SPS_IPC_DEFAULT_LOGLEVEL 3
+#define SPS_IPC_MAX_LOGLEVEL 4
/* Connection mapping control struct */
struct sps_rm {
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 78c5c47e4e8b..9e400a9eee5c 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -5241,30 +5241,44 @@ static int cpr3_debug_closed_loop_enable_set(void *data, u64 val)
ctrl->cpr_allowed_sw = enable;
- rc = cpr3_regulator_update_ctrl_state(ctrl);
- if (rc) {
- cpr3_err(ctrl, "could not change CPR enable state=%u, rc=%d\n",
- enable, rc);
- goto done;
- }
-
- if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) {
- rc = cpr3_clock_enable(ctrl);
+ if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
+ cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
+ CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
+ ctrl->cpr_allowed_sw && ctrl->use_hw_closed_loop
+ ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
+ : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
+ } else {
+ rc = cpr3_regulator_update_ctrl_state(ctrl);
if (rc) {
- cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc);
+ cpr3_err(ctrl, "could not change CPR enable state=%u, rc=%d\n",
+ enable, rc);
goto done;
}
- ctrl->cpr_enabled = true;
- cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
- CPR3_PD_THROTTLE_DISABLE);
+ if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) {
+ rc = cpr3_clock_enable(ctrl);
+ if (rc) {
+ cpr3_err(ctrl, "clock enable failed, rc=%d\n",
+ rc);
+ goto done;
+ }
+ ctrl->cpr_enabled = true;
- cpr3_clock_disable(ctrl);
- ctrl->cpr_enabled = false;
- }
+ cpr3_write(ctrl, CPR3_REG_PD_THROTTLE,
+ CPR3_PD_THROTTLE_DISABLE);
- cpr3_debug(ctrl, "closed-loop=%s\n", enable ? "enabled" : "disabled");
+ cpr3_clock_disable(ctrl);
+ ctrl->cpr_enabled = false;
+ }
+ }
+ if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH) {
+ cpr3_debug(ctrl, "closed-loop=%s\n", enable ?
+ "enabled" : "disabled");
+ } else {
+ cpr3_debug(ctrl, "closed-loop=%s\n", enable &&
+ ctrl->use_hw_closed_loop ? "enabled" : "disabled");
+ }
done:
mutex_unlock(&ctrl->lock);
return 0;
@@ -5298,7 +5312,8 @@ DEFINE_SIMPLE_ATTRIBUTE(cpr3_debug_closed_loop_enable_fops,
* cpr3_debug_hw_closed_loop_enable_set() - debugfs callback used to change the
* value of the CPR controller use_hw_closed_loop flag which
* switches between software closed-loop and hardware closed-loop
- * operation
+ * operation for CPR3 and CPR4 controllers and between open-loop
+ * and full hardware closed-loop operation for CPRh controllers.
* @data: Pointer to private data which is equal to the CPR
* controller pointer
* @val: New value for use_hw_closed_loop
@@ -5327,7 +5342,8 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
}
}
- cpr3_ctrl_loop_disable(ctrl);
+ if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH)
+ cpr3_ctrl_loop_disable(ctrl);
ctrl->use_hw_closed_loop = use_hw_closed_loop;
@@ -5343,7 +5359,7 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
ctrl->cpr_enabled = true;
}
- if (ctrl->use_hw_closed_loop)
+ if (ctrl->use_hw_closed_loop && ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH)
cpr3_write(ctrl, CPR3_REG_IRQ_EN, 0);
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
@@ -5352,6 +5368,12 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
ctrl->use_hw_closed_loop
? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
: CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
+ } else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
+ cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
+ CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
+ ctrl->cpr_allowed_sw && ctrl->use_hw_closed_loop
+ ? CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_ENABLE
+ : CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
} else if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
cpr3_write(ctrl, CPR3_REG_HW_CLOSED_LOOP,
ctrl->use_hw_closed_loop
@@ -5365,7 +5387,7 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
ctrl->cpr_enabled = false;
}
- if (ctrl->use_hw_closed_loop && ctrl->ctrl_type != CPR_CTRL_TYPE_CPR4) {
+ if (ctrl->use_hw_closed_loop && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
rc = regulator_enable(ctrl->vdd_limit_regulator);
if (rc) {
cpr3_err(ctrl, "CPR limit regulator enable failed, rc=%d\n",
@@ -5379,7 +5401,7 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
goto done;
}
} else if (!ctrl->use_hw_closed_loop
- && ctrl->ctrl_type != CPR_CTRL_TYPE_CPR4) {
+ && ctrl->ctrl_type == CPR_CTRL_TYPE_CPR3) {
rc = regulator_disable(ctrl->vdd_limit_regulator);
if (rc) {
cpr3_err(ctrl, "CPR limit regulator disable failed, rc=%d\n",
@@ -5395,35 +5417,42 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val)
}
}
- /*
- * Due to APM and mem-acc floor restriction constraints, the closed-loop
- * voltage may be different when using software closed-loop vs hardware
- * closed-loop. Therefore, reset the cached closed-loop voltage for all
- * corners to the corresponding open-loop voltage when switching between
- * SW and HW closed-loop mode.
- */
- for (i = 0; i < ctrl->thread_count; i++) {
- for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
- vreg = &ctrl->thread[i].vreg[j];
- for (k = 0; k < vreg->corner_count; k++)
- vreg->corner[k].last_volt
+ if (ctrl->ctrl_type != CPR_CTRL_TYPE_CPRH) {
+ /*
+ * Due to APM and mem-acc floor restriction constraints,
+ * the closed-loop voltage may be different when using
+ * software closed-loop vs hardware closed-loop. Therefore,
+ * reset the cached closed-loop voltage for all corners to the
+ * corresponding open-loop voltage when switching between
+ * SW and HW closed-loop mode.
+ */
+ for (i = 0; i < ctrl->thread_count; i++) {
+ for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
+ vreg = &ctrl->thread[i].vreg[j];
+ for (k = 0; k < vreg->corner_count; k++)
+ vreg->corner[k].last_volt
= vreg->corner[k].open_loop_volt;
+ }
}
- }
-
- /* Skip last_volt caching */
- ctrl->last_corner_was_closed_loop = false;
- rc = cpr3_regulator_update_ctrl_state(ctrl);
- if (rc) {
- cpr3_err(ctrl, "could not change CPR HW closed-loop enable state=%u, rc=%d\n",
- use_hw_closed_loop, rc);
- goto done;
- }
+ /* Skip last_volt caching */
+ ctrl->last_corner_was_closed_loop = false;
- cpr3_debug(ctrl, "closed-loop mode=%s\n",
- use_hw_closed_loop ? "HW" : "SW");
+ rc = cpr3_regulator_update_ctrl_state(ctrl);
+ if (rc) {
+ cpr3_err(ctrl, "could not change CPR HW closed-loop enable state=%u, rc=%d\n",
+ use_hw_closed_loop, rc);
+ goto done;
+ }
+ cpr3_debug(ctrl, "CPR mode=%s\n",
+ use_hw_closed_loop ?
+ "HW closed-loop" : "SW closed-loop");
+ } else {
+ cpr3_debug(ctrl, "CPR mode=%s\n",
+ ctrl->cpr_allowed_sw && use_hw_closed_loop ?
+ "full HW closed-loop" : "open-loop");
+ }
done:
mutex_unlock(&ctrl->lock);
return 0;
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index dfdd6921fed5..1c444d6d2607 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -184,13 +184,25 @@ static const struct cpr3_fuse_param msmcobalt_kbss_speed_bin_param[] = {
/*
* Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v1
*/
-static const int msmcobalt_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = {
+static const int
+msmcobalt_v1_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = {
696000,
768000,
896000,
1112000,
};
+/*
+ * Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v2
+ */
+static const int
+msmcobalt_v2_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = {
+ 688000,
+ 756000,
+ 828000,
+ 1056000,
+};
+
#define MSMCOBALT_KBSS_FUSE_STEP_VOLT 10000
#define MSMCOBALT_KBSS_VOLTAGE_FUSE_SIZE 6
#define MSMCOBALT_KBSS_QUOT_OFFSET_SCALE 5
@@ -357,9 +369,10 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages(
{
struct device_node *node = vreg->of_node;
struct cprh_msmcobalt_kbss_fuses *fuse = vreg->platform_fuses;
- int i, j, rc = 0;
+ int i, j, soc_revision, rc = 0;
bool allow_interpolation;
u64 freq_low, volt_low, freq_high, volt_high;
+ const int *ref_volt;
int *fuse_volt;
int *fmax_corner;
@@ -372,9 +385,17 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages(
goto done;
}
+ soc_revision = vreg->thread->ctrl->soc_revision;
+ if (soc_revision == 1)
+ ref_volt = msmcobalt_v1_kbss_fuse_ref_volt;
+ else if (soc_revision == 2)
+ ref_volt = msmcobalt_v2_kbss_fuse_ref_volt;
+ else
+ ref_volt = msmcobalt_v2_kbss_fuse_ref_volt;
+
for (i = 0; i < vreg->fuse_corner_count; i++) {
fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(
- msmcobalt_kbss_fuse_ref_volt[i],
+ ref_volt[i],
MSMCOBALT_KBSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
MSMCOBALT_KBSS_VOLTAGE_FUSE_SIZE);
@@ -1366,14 +1387,27 @@ static int cprh_kbss_regulator_resume(struct platform_device *pdev)
return cpr3_regulator_resume(ctrl);
}
+/* Data corresponds to the SoC revision */
static struct of_device_id cprh_regulator_match_table[] = {
- { .compatible = "qcom,cprh-msmcobalt-kbss-regulator", },
+ {
+ .compatible = "qcom,cprh-msmcobalt-v1-kbss-regulator",
+ .data = (void *)(uintptr_t)1
+ },
+ {
+ .compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator",
+ .data = (void *)(uintptr_t)2
+ },
+ {
+ .compatible = "qcom,cprh-msmcobalt-kbss-regulator",
+ .data = (void *)(uintptr_t)2
+ },
{}
};
static int cprh_kbss_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
struct cpr3_controller *ctrl;
int rc;
@@ -1397,6 +1431,12 @@ static int cprh_kbss_regulator_probe(struct platform_device *pdev)
return rc;
}
+ match = of_match_node(cprh_regulator_match_table, dev->of_node);
+ if (match)
+ ctrl->soc_revision = (uintptr_t)match->data;
+ else
+ cpr3_err(ctrl, "could not find compatible string match\n");
+
rc = cpr3_map_fuse_base(ctrl, pdev);
if (rc) {
cpr3_err(ctrl, "could not map fuse base address\n");
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4d406c51d884..ab602d2ef392 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1283,7 +1283,14 @@ static void ufshcd_gate_work(struct work_struct *work)
unsigned long flags;
spin_lock_irqsave(hba->host->host_lock, flags);
- if (hba->clk_gating.is_suspended) {
+ /*
+ * In case you are here to cancel this work the gating state
+ * would be marked as REQ_CLKS_ON. In this case save time by
+ * skipping the gating work and exit after changing the clock
+ * state to CLKS_ON.
+ */
+ if (hba->clk_gating.is_suspended ||
+ (hba->clk_gating.state == REQ_CLKS_ON)) {
hba->clk_gating.state = CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -7977,6 +7984,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
hba->clk_gating.is_suspended = true;
hba->hibern8_on_idle.is_suspended = true;
+ /*
+ * Disable auto hibern8 to prevent unnecessary hibern8 enter/exit
+ * during suspend path
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ ufshcd_set_auto_hibern8_timer(hba, 0);
+
if (hba->clk_scaling.is_allowed) {
cancel_work_sync(&hba->clk_scaling.suspend_work);
cancel_work_sync(&hba->clk_scaling.resume_work);
@@ -8084,6 +8098,10 @@ enable_gating:
ufshcd_resume_clkscaling(hba);
hba->hibern8_on_idle.is_suspended = false;
hba->clk_gating.is_suspended = false;
+ /* Re-enable auto hibern8 in case of suspend failure */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ ufshcd_set_auto_hibern8_timer(hba,
+ hba->hibern8_on_idle.delay_ms);
ufshcd_release_all(hba);
out:
hba->pm_op_in_progress = 0;
@@ -8177,6 +8195,13 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (hba->clk_scaling.is_allowed)
ufshcd_resume_clkscaling(hba);
+ /*
+ * Enable auto hibern8 after successful resume to prevent
+ * unnecessary hibern8 enter/exit during resume path
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ ufshcd_set_auto_hibern8_timer(hba,
+ hba->hibern8_on_idle.delay_ms);
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release_all(hba);
goto out;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 1ca5109615fe..0509b46948cb 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -392,13 +392,13 @@ void msm_dealloc_port(struct slim_controller *ctrl, u8 pn)
if (pn >= dev->port_nums)
return;
endpoint = &dev->pipes[pn];
- if (dev->pipes[pn].connected)
- msm_slim_disconn_pipe_port(dev, pn);
- if (endpoint->sps) {
+ if (dev->pipes[pn].connected) {
struct sps_connect *config = &endpoint->config;
- msm_slim_free_endpoint(endpoint);
+ msm_slim_disconn_pipe_port(dev, pn);
msm_slim_sps_mem_free(dev, &config->desc);
}
+ if (endpoint->sps)
+ msm_slim_free_endpoint(endpoint);
}
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c45cbfa8a786..ecfa6954f1e6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -669,7 +669,7 @@ config MSM_EVENT_TIMER
config MSM_AVTIMER
tristate "Avtimer Driver"
- depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3
+ depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 || MSM_QDSP6_APRV2_GLINK
help
This driver gets the Q6 out of power collapsed state and
exposes ioctl control to read avtimer tick.
@@ -761,4 +761,13 @@ config QSEE_IPC_IRQ_BRIDGE
interrupt from a remote subsystem directed towards Qualcomm
Technologies, Inc. Secure Execution Environment(QSEE).
+config WCD_DSP_GLINK
+ tristate "WCD DSP GLINK Driver"
+ depends on MSM_GLINK
+ default y if SND_SOC_WCD934X=y
+ help
+ This option enables driver which provides communication interface
+ between MSM and WCD DSP over glink transport protocol. This driver
+ provides read and write interface via char device.
+
source "drivers/soc/qcom/memshare/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 269b72c68b68..913f5d55e53b 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -97,3 +97,4 @@ obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o system_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
+obj-$(CONFIG_WCD_DSP_GLINK) += wcd-dsp-glink.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index e8a9751fa266..bfe2072ee554 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -33,6 +33,7 @@
#include <linux/dma-mapping.h>
#include <linux/qmi_encdec.h>
#include <linux/ipc_logging.h>
+#include <linux/msm-bus.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/icnss.h>
#include <soc/qcom/msm_qmi_interface.h>
@@ -43,7 +44,6 @@
#define ICNSS_PANIC 1
#define WLFW_TIMEOUT_MS 3000
#define WLFW_SERVICE_INS_ID_V01 0
-#define SMMU_CLOCK_NAME "smmu_aggre2_noc_clk"
#define MAX_PROP_SIZE 32
#define MAX_VOLTAGE_LEVEL 2
#define VREG_ON 1
@@ -201,7 +201,10 @@ static struct icnss_data {
struct dma_iommu_mapping *smmu_mapping;
dma_addr_t smmu_iova_start;
size_t smmu_iova_len;
- struct clk *smmu_clk;
+ dma_addr_t smmu_iova_ipa_start;
+ size_t smmu_iova_ipa_len;
+ struct msm_bus_scale_pdata *bus_scale_table;
+ uint32_t bus_client;
struct qmi_handle *wlfw_clnt;
struct list_head event_list;
spinlock_t event_lock;
@@ -1727,44 +1730,120 @@ int icnss_get_irq(int ce_id)
}
EXPORT_SYMBOL(icnss_get_irq);
-static struct clk *icnss_clock_init(struct device *dev, const char *cname)
+struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev)
{
- struct clk *c;
- long rate;
+ struct icnss_data *priv = dev_get_drvdata(dev);
- if (of_property_match_string(dev->of_node, "clock-names", cname) < 0) {
- icnss_pr_err("Clock %s not found!", cname);
+ if (!priv) {
+ icnss_pr_err("Invalid drvdata: dev %p, data %p\n",
+ dev, priv);
return NULL;
}
- c = devm_clk_get(dev, cname);
- if (IS_ERR(c)) {
- icnss_pr_err("Couldn't get clock %s!", cname);
- return NULL;
+ return priv->smmu_mapping;
+}
+EXPORT_SYMBOL(icnss_smmu_get_mapping);
+
+int icnss_smmu_map(struct device *dev,
+ phys_addr_t paddr, uint32_t *iova_addr, size_t size)
+{
+ struct icnss_data *priv = dev_get_drvdata(dev);
+ unsigned long iova;
+ size_t len;
+ int ret = 0;
+
+ if (!priv) {
+ icnss_pr_err("Invalid drvdata: dev %p, data %p\n",
+ dev, priv);
+ return -EINVAL;
}
- if (clk_get_rate(c) == 0) {
- rate = clk_round_rate(c, 1000);
- clk_set_rate(c, rate);
+ if (!iova_addr) {
+ icnss_pr_err("iova_addr is NULL, paddr %pa, size %zu",
+ &paddr, size);
+ return -EINVAL;
+ }
+
+ len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE);
+ iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE);
+
+ if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) {
+ icnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu",
+ iova,
+ &priv->smmu_iova_ipa_start,
+ priv->smmu_iova_ipa_len);
+ return -ENOMEM;
}
- return c;
+ ret = iommu_map(priv->smmu_mapping->domain, iova,
+ rounddown(paddr, PAGE_SIZE), len,
+ IOMMU_READ | IOMMU_WRITE);
+ if (ret) {
+ icnss_pr_err("PA to IOVA mapping failed, ret %d!", ret);
+ return ret;
+ }
+
+ priv->smmu_iova_ipa_start = iova + len;
+ *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));
+
+ return 0;
}
+EXPORT_SYMBOL(icnss_smmu_map);
-static int icnss_clock_enable(struct clk *c)
+static int icnss_bw_vote(struct icnss_data *priv, int index)
{
int ret = 0;
- ret = clk_prepare_enable(c);
+ icnss_pr_dbg("Vote %d for msm_bus, state 0x%lx\n",
+ index, priv->state);
+ ret = msm_bus_scale_client_update_request(priv->bus_client, index);
+ if (ret)
+ icnss_pr_err("Fail to vote %d: ret %d, state 0x%lx!\n",
+ index, ret, priv->state);
- if (ret < 0)
- icnss_pr_err("Couldn't enable clock: %d!\n", ret);
return ret;
}
-static void icnss_clock_disable(struct clk *c)
+static int icnss_bw_init(struct icnss_data *priv)
+{
+ int ret = 0;
+
+ priv->bus_scale_table = msm_bus_cl_get_pdata(priv->pdev);
+ if (!priv->bus_scale_table) {
+ icnss_pr_err("Missing entry for msm_bus scale table\n");
+ return -EINVAL;
+ }
+
+ priv->bus_client = msm_bus_scale_register_client(priv->bus_scale_table);
+ if (!priv->bus_client) {
+ icnss_pr_err("Fail to register with bus_scale client\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = icnss_bw_vote(priv, 1);
+ if (ret)
+ goto out;
+
+ return 0;
+
+out:
+ msm_bus_cl_clear_pdata(priv->bus_scale_table);
+ return ret;
+}
+
+static void icnss_bw_deinit(struct icnss_data *priv)
{
- clk_disable_unprepare(c);
+ if (!priv)
+ return;
+
+ if (priv->bus_client) {
+ icnss_bw_vote(priv, 0);
+ msm_bus_scale_unregister_client(priv->bus_client);
+ }
+
+ if (priv->bus_scale_table)
+ msm_bus_cl_clear_pdata(priv->bus_scale_table);
}
static int icnss_smmu_init(struct device *dev)
@@ -2272,7 +2351,6 @@ static void icnss_debugfs_destroy(struct icnss_data *priv)
static int icnss_probe(struct platform_device *pdev)
{
int ret = 0;
- u32 smmu_iova_address[2];
struct resource *res;
int i;
struct device *dev = &pdev->dev;
@@ -2367,11 +2445,29 @@ static int icnss_probe(struct platform_device *pdev)
goto unmap_mpm_config;
}
- if (of_property_read_u32_array(pdev->dev.of_node,
- "qcom,wlan-smmu-iova-address",
- smmu_iova_address, 2) == 0) {
- penv->smmu_iova_start = smmu_iova_address[0];
- penv->smmu_iova_len = smmu_iova_address[1];
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "smmu_iova_base");
+ if (!res) {
+ icnss_pr_err("SMMU IOVA base not found\n");
+ } else {
+ penv->smmu_iova_start = res->start;
+ penv->smmu_iova_len = resource_size(res);
+ icnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n",
+ &penv->smmu_iova_start,
+ penv->smmu_iova_len);
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "smmu_iova_ipa");
+ if (!res) {
+ icnss_pr_err("SMMU IOVA IPA not found\n");
+ } else {
+ penv->smmu_iova_ipa_start = res->start;
+ penv->smmu_iova_ipa_len = resource_size(res);
+ icnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n",
+ &penv->smmu_iova_ipa_start,
+ penv->smmu_iova_ipa_len);
+ }
ret = icnss_smmu_init(&pdev->dev);
if (ret < 0) {
@@ -2381,12 +2477,9 @@ static int icnss_probe(struct platform_device *pdev)
goto err_smmu_init;
}
- penv->smmu_clk = icnss_clock_init(&pdev->dev, SMMU_CLOCK_NAME);
- if (penv->smmu_clk) {
- ret = icnss_clock_enable(penv->smmu_clk);
- if (ret < 0)
- goto err_smmu_clock_enable;
- }
+ ret = icnss_bw_init(penv);
+ if (ret)
+ goto err_bw_init;
}
penv->skip_qmi = of_property_read_bool(dev->of_node,
@@ -2399,7 +2492,7 @@ static int icnss_probe(struct platform_device *pdev)
if (!penv->event_wq) {
icnss_pr_err("Workqueue creation failed\n");
ret = -EFAULT;
- goto err_smmu_clock_enable;
+ goto err_alloc_workqueue;
}
INIT_WORK(&penv->event_work, icnss_driver_event_work);
@@ -2424,7 +2517,9 @@ static int icnss_probe(struct platform_device *pdev)
err_qmi:
if (penv->event_wq)
destroy_workqueue(penv->event_wq);
-err_smmu_clock_enable:
+err_alloc_workqueue:
+ icnss_bw_deinit(penv);
+err_bw_init:
if (penv->smmu_mapping)
icnss_smmu_remove(&pdev->dev);
err_smmu_init:
@@ -2459,11 +2554,7 @@ static int icnss_remove(struct platform_device *pdev)
if (penv->event_wq)
destroy_workqueue(penv->event_wq);
- if (penv->smmu_mapping) {
- if (penv->smmu_clk)
- icnss_clock_disable(penv->smmu_clk);
- icnss_smmu_remove(&pdev->dev);
- }
+ icnss_bw_deinit(penv);
if (penv->msa_va)
dma_free_coherent(&pdev->dev, penv->msa_mem_size,
diff --git a/drivers/soc/qcom/irq-helper.c b/drivers/soc/qcom/irq-helper.c
index 2bb71464d165..7bb371f7991e 100644
--- a/drivers/soc/qcom/irq-helper.c
+++ b/drivers/soc/qcom/irq-helper.c
@@ -72,7 +72,7 @@ static ssize_t show_deploy(struct kobject *kobj, struct attribute *attr,
{
struct irq_helper *irq = to_irq_helper(kobj);
- return snprintf(buf, sizeof(irq->deploy), "%u\n", irq->deploy);
+ return snprintf(buf, PAGE_SIZE, "%u\n", irq->deploy);
}
IRQ_HELPER_ATTR(irq_blacklist_on, 0444, show_deploy, NULL);
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index c01c225d95ab..e7dbcac064aa 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -43,11 +43,6 @@ struct mem_prot_info {
u64 size;
};
-struct info_list {
- struct mem_prot_info *list_head;
- u64 list_size;
-};
-
#define MEM_PROT_ASSIGN_ID 0x16
#define MEM_PROTECT_LOCK_ID2 0x0A
#define MEM_PROTECT_LOCK_ID2_FLAT 0x11
@@ -61,14 +56,8 @@ struct dest_vm_and_perm_info {
u32 ctx_size;
};
-struct dest_info_list {
- struct dest_vm_and_perm_info *dest_info;
- u64 list_size;
-};
-
static void *qcom_secure_mem;
#define QCOM_SECURE_MEM_SIZE (512*1024)
-#define PADDING 32
static int secure_buffer_change_chunk(u32 chunks,
u32 nchunks,
@@ -200,14 +189,22 @@ int msm_unsecure_table(struct sg_table *table)
}
-static void populate_dest_info(int *dest_vmids, int nelements,
- int *dest_perms, struct dest_info_list **list,
- void *current_qcom_secure_mem)
+static struct dest_vm_and_perm_info *
+populate_dest_info(int *dest_vmids, int nelements, int *dest_perms,
+ size_t *size_in_bytes)
{
struct dest_vm_and_perm_info *dest_info;
int i;
+ size_t size;
- dest_info = (struct dest_vm_and_perm_info *)current_qcom_secure_mem;
+ /* Ensure allocated size is less than PAGE_ALLOC_COSTLY_ORDER */
+ size = nelements * sizeof(*dest_info);
+ if (size > PAGE_SIZE)
+ return NULL;
+
+ dest_info = kzalloc(size, GFP_KERNEL);
+ if (!dest_info)
+ return NULL;
for (i = 0; i < nelements; i++) {
dest_info[i].vm = dest_vmids[i];
@@ -216,106 +213,149 @@ static void populate_dest_info(int *dest_vmids, int nelements,
dest_info[i].ctx_size = 0;
}
- *list = (struct dest_info_list *)&dest_info[i];
-
- (*list)->dest_info = dest_info;
- (*list)->list_size = nelements * sizeof(struct dest_vm_and_perm_info);
+ *size_in_bytes = size;
+ return dest_info;
}
-static void get_info_list_from_table(struct sg_table *table,
- struct info_list **list)
+/* Must hold secure_buffer_mutex while allocated buffer is in use */
+static struct mem_prot_info *get_info_list_from_table(struct sg_table *table,
+ size_t *size_in_bytes)
{
int i;
struct scatterlist *sg;
struct mem_prot_info *info;
+ size_t size;
+
+ size = table->nents * sizeof(*info);
+
+ if (size >= QCOM_SECURE_MEM_SIZE) {
+ pr_err("%s: Not enough memory allocated. Required size %zd\n",
+ __func__, size);
+ return NULL;
+ }
+
+ if (!qcom_secure_mem) {
+ pr_err("%s is not functional as qcom_secure_mem is not allocated.\n",
+ __func__);
+ return NULL;
+ }
- info = (struct mem_prot_info *)qcom_secure_mem;
+ /* "Allocate" it */
+ info = qcom_secure_mem;
for_each_sg(table->sgl, sg, table->nents, i) {
info[i].addr = page_to_phys(sg_page(sg));
info[i].size = sg->length;
}
- *list = (struct info_list *)&(info[i]);
-
- (*list)->list_head = info;
- (*list)->list_size = table->nents * sizeof(struct mem_prot_info);
+ *size_in_bytes = size;
+ return info;
}
+#define BATCH_MAX_SIZE SZ_2M
+#define BATCH_MAX_SECTIONS 32
+
int hyp_assign_table(struct sg_table *table,
u32 *source_vm_list, int source_nelems,
int *dest_vmids, int *dest_perms,
int dest_nelems)
{
int ret;
- struct info_list *info_list = NULL;
- struct dest_info_list *dest_info_list = NULL;
struct scm_desc desc = {0};
u32 *source_vm_copy;
- void *current_qcom_secure_mem;
+ size_t source_vm_copy_size;
+ struct dest_vm_and_perm_info *dest_vm_copy;
+ size_t dest_vm_copy_size;
+ struct mem_prot_info *sg_table_copy;
+ size_t sg_table_copy_size;
- size_t reqd_size = dest_nelems * sizeof(struct dest_vm_and_perm_info) +
- table->nents * sizeof(struct mem_prot_info) +
- sizeof(dest_info_list) + sizeof(info_list) + PADDING;
-
- if (!qcom_secure_mem) {
- pr_err("%s is not functional as qcom_secure_mem is not allocated.\n",
- __func__);
- return -ENOMEM;
- }
-
- if (QCOM_SECURE_MEM_SIZE < reqd_size) {
- pr_err("%s: Not enough memory allocated. Required size %zd\n",
- __func__, reqd_size);
- return -EINVAL;
- }
+ int batch_start, batch_end;
+ u64 batch_size;
/*
* We can only pass cache-aligned sizes to hypervisor, so we need
* to kmalloc and memcpy the source_vm_list here.
*/
- source_vm_copy = kmalloc_array(
- source_nelems, sizeof(*source_vm_copy), GFP_KERNEL);
- if (!source_vm_copy) {
+ source_vm_copy_size = sizeof(*source_vm_copy) * source_nelems;
+ source_vm_copy = kzalloc(source_vm_copy_size, GFP_KERNEL);
+ if (!source_vm_copy)
return -ENOMEM;
- }
- memcpy(source_vm_copy, source_vm_list,
- sizeof(*source_vm_list) * source_nelems);
+ memcpy(source_vm_copy, source_vm_list, source_vm_copy_size);
- mutex_lock(&secure_buffer_mutex);
- get_info_list_from_table(table, &info_list);
+ dest_vm_copy = populate_dest_info(dest_vmids, dest_nelems, dest_perms,
+ &dest_vm_copy_size);
+ if (!dest_vm_copy) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
- current_qcom_secure_mem = &(info_list[1]);
- populate_dest_info(dest_vmids, dest_nelems, dest_perms,
- &dest_info_list, current_qcom_secure_mem);
+ mutex_lock(&secure_buffer_mutex);
+
+ sg_table_copy = get_info_list_from_table(table, &sg_table_copy_size);
+ if (!sg_table_copy) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
- desc.args[0] = virt_to_phys(info_list->list_head);
- desc.args[1] = info_list->list_size;
+ desc.args[0] = virt_to_phys(sg_table_copy);
+ desc.args[1] = sg_table_copy_size;
desc.args[2] = virt_to_phys(source_vm_copy);
- desc.args[3] = sizeof(*source_vm_copy) * source_nelems;
- desc.args[4] = virt_to_phys(dest_info_list->dest_info);
- desc.args[5] = dest_info_list->list_size;
+ desc.args[3] = source_vm_copy_size;
+ desc.args[4] = virt_to_phys(dest_vm_copy);
+ desc.args[5] = dest_vm_copy_size;
desc.args[6] = 0;
desc.arginfo = SCM_ARGS(7, SCM_RO, SCM_VAL, SCM_RO, SCM_VAL, SCM_RO,
SCM_VAL, SCM_VAL);
- dmac_flush_range(source_vm_copy, source_vm_copy + source_nelems);
- dmac_flush_range(info_list->list_head, info_list->list_head +
- (info_list->list_size / sizeof(*info_list->list_head)));
- dmac_flush_range(dest_info_list->dest_info, dest_info_list->dest_info +
- (dest_info_list->list_size /
- sizeof(*dest_info_list->dest_info)));
+ dmac_flush_range(source_vm_copy,
+ (void *)source_vm_copy + source_vm_copy_size);
+ dmac_flush_range(sg_table_copy,
+ (void *)sg_table_copy + sg_table_copy_size);
+ dmac_flush_range(dest_vm_copy,
+ (void *)dest_vm_copy + dest_vm_copy_size);
+
+ batch_start = 0;
+ while (batch_start < table->nents) {
+ /* Ensure no size zero batches */
+ batch_size = sg_table_copy[batch_start].size;
+ batch_end = batch_start + 1;
+ while (1) {
+ u64 size;
+
+ if (batch_end >= table->nents)
+ break;
+ if (batch_end - batch_start >= BATCH_MAX_SECTIONS)
+ break;
+
+ size = sg_table_copy[batch_end].size;
+ if (size + batch_size >= BATCH_MAX_SIZE)
+ break;
+
+ batch_size += size;
+ batch_end++;
+ }
- ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
- MEM_PROT_ASSIGN_ID), &desc);
- if (ret)
- pr_info("%s: Failed to assign memory protection, ret = %d\n",
- __func__, ret);
+ desc.args[0] = virt_to_phys(&sg_table_copy[batch_start]);
+ desc.args[1] = (batch_end - batch_start) *
+ sizeof(sg_table_copy[0]);
+
+ ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+ MEM_PROT_ASSIGN_ID), &desc);
+ if (ret) {
+ pr_info("%s: Failed to assign memory protection, ret = %d\n",
+ __func__, ret);
+ break;
+ }
+ batch_start = batch_end;
+ }
+out_unlock:
mutex_unlock(&secure_buffer_mutex);
+ kfree(dest_vm_copy);
+out_free:
kfree(source_vm_copy);
return ret;
}
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 9426e0751c4a..24018c544b06 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -208,8 +208,8 @@ static int servreg_loc_send_msg(struct msg_desc *req_desc,
static int service_locator_send_msg(struct pd_qmi_client_data *pd)
{
struct msg_desc req_desc, resp_desc;
- struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp;
- struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req;
+ struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp = NULL;
+ struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req = NULL;
int rc;
int db_rev_count = 0, domains_read = 0;
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index fc5688b4bc8c..d85046875d7a 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -1,6 +1,6 @@
/* drivers/soc/qcom/smp2p.c
*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -214,6 +214,7 @@ static struct smp2p_interrupt_config smp2p_int_cfgs[SMP2P_NUM_PROCS] = {
[SMP2P_AUDIO_PROC].name = "lpass",
[SMP2P_SENSOR_PROC].name = "dsps",
[SMP2P_WIRELESS_PROC].name = "wcnss",
+ [SMP2P_CDSP_PROC].name = "cdsp",
[SMP2P_TZ_PROC].name = "tz",
[SMP2P_REMOTE_MOCK_PROC].name = "mock",
};
@@ -333,6 +334,9 @@ static int smp2p_get_smem_item_id(int write_pid, int read_pid)
case SMP2P_WIRELESS_PROC:
ret = SMEM_SMP2P_WIRLESS_BASE + read_pid;
break;
+ case SMP2P_CDSP_PROC:
+ ret = SMEM_SMP2P_CDSP_BASE + read_pid;
+ break;
case SMP2P_POWER_PROC:
ret = SMEM_SMP2P_POWER_BASE + read_pid;
break;
diff --git a/drivers/soc/qcom/smp2p_private_api.h b/drivers/soc/qcom/smp2p_private_api.h
index 4223a2e1bc90..5bff32f8c06a 100644
--- a/drivers/soc/qcom/smp2p_private_api.h
+++ b/drivers/soc/qcom/smp2p_private_api.h
@@ -1,6 +1,6 @@
/* drivers/soc/qcom/smp2p_private_api.h
*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,7 +31,7 @@ enum {
SMP2P_AUDIO_PROC = 2,
SMP2P_SENSOR_PROC = 3,
SMP2P_WIRELESS_PROC = 4,
- SMP2P_RESERVED_PROC_2 = 5,
+ SMP2P_CDSP_PROC = 5,
SMP2P_POWER_PROC = 6,
SMP2P_TZ_PROC = 7,
/* add new processors here */
diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c
index dfebd201eeb0..04b043fbd8ec 100644
--- a/drivers/soc/qcom/smp2p_sleepstate.c
+++ b/drivers/soc/qcom/smp2p_sleepstate.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -74,6 +74,7 @@ static int smp2p_sleepstate_probe(struct platform_device *pdev)
static struct of_device_id msm_smp2p_slst_match_table[] = {
{.compatible = "qcom,smp2pgpio_sleepstate_3_out"},
+ {.compatible = "qcom,smp2pgpio-sleepstate-out"},
{},
};
diff --git a/drivers/soc/qcom/smp2p_spinlock_test.c b/drivers/soc/qcom/smp2p_spinlock_test.c
index d188bf0702c5..74aac52b5285 100644
--- a/drivers/soc/qcom/smp2p_spinlock_test.c
+++ b/drivers/soc/qcom/smp2p_spinlock_test.c
@@ -373,6 +373,11 @@ static void smp2p_ut_remote_spinlock_wcnss(struct seq_file *s)
smp2p_ut_remote_spinlock_pid(s, SMP2P_WIRELESS_PROC, false);
}
+static void smp2p_ut_remote_spinlock_cdsp(struct seq_file *s)
+{
+ smp2p_ut_remote_spinlock_pid(s, SMP2P_CDSP_PROC, false);
+}
+
static void smp2p_ut_remote_spinlock_tz(struct seq_file *s)
{
smp2p_ut_remote_spinlock_pid(s, SMP2P_TZ_PROC, false);
@@ -752,6 +757,11 @@ static void smp2p_ut_remote_spinlock_track_wcnss(struct seq_file *s)
smp2p_ut_remote_spinlock_track(s, SMP2P_WIRELESS_PROC);
}
+static void smp2p_ut_remote_spinlock_track_cdsp(struct seq_file *s)
+{
+ smp2p_ut_remote_spinlock_track(s, SMP2P_CDSP_PROC);
+}
+
static void smp2p_ut_remote_spinlock_track_tz(struct seq_file *s)
{
smp2p_ut_remote_spinlock_track(s, SMP2P_TZ_PROC);
@@ -782,6 +792,8 @@ static int __init smp2p_debugfs_init(void)
smp2p_ut_remote_spinlock_dsps);
smp2p_debug_create("ut_remote_spinlock_wcnss",
smp2p_ut_remote_spinlock_wcnss);
+ smp2p_debug_create("ut_remote_spinlock_cdsp",
+ smp2p_ut_remote_spinlock_cdsp);
smp2p_debug_create("ut_remote_spinlock_tz",
smp2p_ut_remote_spinlock_tz);
smp2p_debug_create("ut_remote_spinlock_rpm",
@@ -798,6 +810,8 @@ static int __init smp2p_debugfs_init(void)
&smp2p_ut_remote_spinlock_track_dsps);
smp2p_debug_create("ut_remote_spinlock_track_wcnss",
&smp2p_ut_remote_spinlock_track_wcnss);
+ smp2p_debug_create("ut_remote_spinlock_track_cdsp",
+ &smp2p_ut_remote_spinlock_track_cdsp);
smp2p_debug_create("ut_remote_spinlock_track_tz",
&smp2p_ut_remote_spinlock_track_tz);
return 0;
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 45af4b601634..30eff96fc27d 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -1920,10 +1920,20 @@ static int spcom_device_release(struct inode *inode, struct file *filp)
pr_debug("Close file [%s].\n", name);
+ if (strcmp(name, DEVICE_NAME) == 0) {
+ pr_debug("root dir skipped.\n");
+ return 0;
+ }
+
+ if (strcmp(name, "sp_ssr") == 0) {
+ pr_debug("sp_ssr dev node skipped.\n");
+ return 0;
+ }
+
ch = filp->private_data;
if (!ch) {
- pr_err("ch is NULL, file name %s.\n", file_to_filename(filp));
+ pr_debug("ch is NULL, file name %s.\n", file_to_filename(filp));
return -ENODEV;
}
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
new file mode 100644
index 000000000000..310903b10a98
--- /dev/null
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -0,0 +1,948 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <soc/qcom/glink.h>
+#include "sound/wcd-dsp-glink.h"
+
+#define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink"
+#define WDSP_MAX_WRITE_SIZE (512 * 1024)
+#define WDSP_MAX_READ_SIZE (4 * 1024)
+
+#define MINOR_NUMBER_COUNT 1
+#define WDSP_EDGE "wdsp"
+#define RESP_QUEUE_SIZE 3
+#define QOS_PKT_SIZE 1024
+
+struct wdsp_glink_dev {
+ struct class *cls;
+ struct device *dev;
+ struct cdev cdev;
+ dev_t dev_num;
+};
+
+struct wdsp_glink_rsp_que {
+ /* Size of valid data in buffer */
+ u32 buf_size;
+
+ /* Response buffer */
+ u8 buf[WDSP_MAX_READ_SIZE];
+};
+
+struct wdsp_glink_tx_buf {
+ struct work_struct tx_work;
+
+ /* Glink channel information */
+ struct wdsp_glink_ch *ch;
+
+ /* Tx buffer to send to glink */
+ u8 buf[0];
+};
+
+struct wdsp_glink_ch {
+ struct wdsp_glink_priv *wpriv;
+
+ /* Glink channel handle */
+ void *handle;
+
+ /* Channel states like connect, disconnect */
+ int channel_state;
+ struct mutex mutex;
+
+ /* To free up the channel memory */
+ bool free_mem;
+
+ /* Glink channel configuration */
+ struct wdsp_glink_ch_cfg ch_cfg;
+};
+
+struct wdsp_glink_state {
+ /* Glink link state information */
+ enum glink_link_state link_state;
+ void *handle;
+};
+
+struct wdsp_glink_priv {
+ /* Respone buffer related */
+ u8 rsp_cnt;
+ struct wdsp_glink_rsp_que rsp[RESP_QUEUE_SIZE];
+ struct completion rsp_complete;
+ struct mutex rsp_mutex;
+
+ /* Glink channel related */
+ struct wdsp_glink_state glink_state;
+ struct wdsp_glink_ch **ch;
+ u8 no_of_channels;
+ struct work_struct ch_open_cls_wrk;
+ struct workqueue_struct *work_queue;
+
+ struct device *dev;
+};
+
+static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch);
+static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch);
+
+/*
+ * wdsp_glink_notify_rx - Glink notify rx callback for responses
+ * handle: Opaque Channel handle returned by GLink
+ * priv: Private pointer to the channel
+ * pkt_priv: Private pointer to the packet
+ * ptr: Pointer to the Rx data
+ * size: Size of the Rx data
+ */
+static void wdsp_glink_notify_rx(void *handle, const void *priv,
+ const void *pkt_priv, const void *ptr,
+ size_t size)
+{
+ u8 *rx_buf;
+ u8 rsp_cnt;
+ struct wdsp_glink_ch *ch;
+ struct wdsp_glink_priv *wpriv;
+
+ if (!ptr || !priv) {
+ pr_err("%s: Invalid parameters\n", __func__);
+ return;
+ }
+
+ ch = (struct wdsp_glink_ch *)priv;
+ wpriv = ch->wpriv;
+ rx_buf = (u8 *)ptr;
+ if (size > WDSP_MAX_READ_SIZE) {
+ dev_err(wpriv->dev, "%s: Size %zd is greater than allowed %d\n",
+ __func__, size, WDSP_MAX_READ_SIZE);
+ size = WDSP_MAX_READ_SIZE;
+ }
+
+ mutex_lock(&wpriv->rsp_mutex);
+ rsp_cnt = wpriv->rsp_cnt;
+ if (rsp_cnt >= RESP_QUEUE_SIZE) {
+ dev_err(wpriv->dev, "%s: Resp Queue is Full\n", __func__);
+ rsp_cnt = 0;
+ }
+ dev_dbg(wpriv->dev, "%s: copy into buffer %d\n", __func__, rsp_cnt);
+
+ memcpy(wpriv->rsp[rsp_cnt].buf, rx_buf, size);
+ wpriv->rsp[rsp_cnt].buf_size = size;
+ wpriv->rsp_cnt = ++rsp_cnt;
+ mutex_unlock(&wpriv->rsp_mutex);
+
+ complete(&wpriv->rsp_complete);
+ glink_rx_done(handle, ptr, true);
+}
+
+/*
+ * wdsp_glink_notify_tx_done - Glink notify tx done callback to
+ * free tx buffer
+ * handle: Opaque Channel handle returned by GLink
+ * priv: Private pointer to the channel
+ * pkt_priv: Private pointer to the packet
+ * ptr: Pointer to the Tx data
+ */
+static void wdsp_glink_notify_tx_done(void *handle, const void *priv,
+ const void *pkt_priv, const void *ptr)
+{
+ if (!pkt_priv) {
+ pr_err("%s: Invalid parameter\n", __func__);
+ return;
+ }
+ /* Free tx pkt */
+ kfree(pkt_priv);
+}
+
+/*
+ * wdsp_glink_notify_rx_intent_req - Glink notify rx intent request callback
+ * to queue buffer to receive from remote client
+ * handle: Opaque channel handle returned by GLink
+ * priv: Private pointer to the channel
+ * req_size: Size of intent to be queued
+ */
+static bool wdsp_glink_notify_rx_intent_req(void *handle, const void *priv,
+ size_t req_size)
+{
+ struct wdsp_glink_priv *wpriv;
+ struct wdsp_glink_ch *ch;
+ int rc = 0;
+ bool ret = false;
+
+ if (!priv) {
+ pr_err("%s: Invalid priv\n", __func__);
+ goto done;
+ }
+ if (req_size > WDSP_MAX_READ_SIZE) {
+ pr_err("%s: Invalid req_size %zd\n", __func__, req_size);
+ goto done;
+ }
+
+ ch = (struct wdsp_glink_ch *)priv;
+ wpriv = ch->wpriv;
+
+ dev_dbg(wpriv->dev, "%s: intent size %zd requested for ch name %s",
+ __func__, req_size, ch->ch_cfg.name);
+
+ mutex_lock(&ch->mutex);
+ rc = glink_queue_rx_intent(ch->handle, ch, req_size);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(wpriv->dev, "%s: Failed to queue rx intent\n",
+ __func__);
+ mutex_unlock(&ch->mutex);
+ goto done;
+ }
+ mutex_unlock(&ch->mutex);
+ ret = true;
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_notify_state - Glink channel state information event callback
+ * handle: Opaque Channel handle returned by GLink
+ * priv: Private pointer to the channel
+ * event: channel state event
+ */
+static void wdsp_glink_notify_state(void *handle, const void *priv,
+ unsigned event)
+{
+ struct wdsp_glink_priv *wpriv;
+ struct wdsp_glink_ch *ch;
+ int i, ret = 0;
+
+ if (!priv) {
+ pr_err("%s: Invalid priv\n", __func__);
+ return;
+ }
+
+ ch = (struct wdsp_glink_ch *)priv;
+ wpriv = ch->wpriv;
+
+ mutex_lock(&ch->mutex);
+ ch->channel_state = event;
+ if (event == GLINK_CONNECTED) {
+ dev_dbg(wpriv->dev, "%s: glink channel: %s connected\n",
+ __func__, ch->ch_cfg.name);
+
+ for (i = 0; i < ch->ch_cfg.no_of_intents; i++) {
+ dev_dbg(wpriv->dev, "%s: intent_size = %d\n", __func__,
+ ch->ch_cfg.intents_size[i]);
+ ret = glink_queue_rx_intent(ch->handle, ch,
+ ch->ch_cfg.intents_size[i]);
+ if (IS_ERR_VALUE(ret))
+ dev_warn(wpriv->dev, "%s: Failed to queue intent %d of size %d\n",
+ __func__, i,
+ ch->ch_cfg.intents_size[i]);
+ }
+
+ ret = glink_qos_latency(ch->handle, ch->ch_cfg.latency_in_us,
+ QOS_PKT_SIZE);
+ if (IS_ERR_VALUE(ret))
+ dev_warn(wpriv->dev, "%s: Failed to request qos %d for ch %s\n",
+ __func__, ch->ch_cfg.latency_in_us,
+ ch->ch_cfg.name);
+
+ mutex_unlock(&ch->mutex);
+ } else if (event == GLINK_LOCAL_DISCONNECTED) {
+ /*
+ * Don't use dev_dbg here as dev may not be valid if channel
+ * closed from driver close.
+ */
+ pr_debug("%s: channel: %s disconnected locally\n",
+ __func__, ch->ch_cfg.name);
+ mutex_unlock(&ch->mutex);
+
+ if (ch->free_mem) {
+ kfree(ch);
+ ch = NULL;
+ }
+ } else if (event == GLINK_REMOTE_DISCONNECTED) {
+ dev_dbg(wpriv->dev, "%s: remote channel: %s disconnected remotely\n",
+ __func__, ch->ch_cfg.name);
+ mutex_unlock(&ch->mutex);
+ /*
+ * If remote disconnect happens, local side also has
+ * to close the channel and reopen again as per glink
+ */
+ if (!wdsp_glink_close_ch(ch))
+ wdsp_glink_open_ch(ch);
+ }
+}
+
+/*
+ * wdsp_glink_close_ch - Internal function to close glink channel
+ * ch: Glink Channel structure.
+ */
+static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch)
+{
+ struct wdsp_glink_priv *wpriv = ch->wpriv;
+ int ret = 0;
+
+
+ mutex_lock(&ch->mutex);
+
+ dev_dbg(wpriv->dev, "%s: ch %s closing\n", __func__, ch->ch_cfg.name);
+ ret = glink_close(ch->handle);
+ if (IS_ERR_VALUE(ret))
+ dev_err(wpriv->dev, "%s: glink_close is failed, ret = %d\n",
+ __func__, ret);
+
+ mutex_unlock(&ch->mutex);
+
+ return ret;
+}
+
+/*
+ * wdsp_glink_open_ch - Internal function to open glink channel
+ * ch: Glink Channel structure.
+ */
+static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch)
+{
+ struct wdsp_glink_priv *wpriv = ch->wpriv;
+ struct glink_open_config open_cfg;
+ int ret = 0;
+
+ memset(&open_cfg, 0, sizeof(open_cfg));
+ open_cfg.options = GLINK_OPT_INITIAL_XPORT;
+ open_cfg.edge = WDSP_EDGE;
+ open_cfg.notify_rx = wdsp_glink_notify_rx;
+ open_cfg.notify_tx_done = wdsp_glink_notify_tx_done;
+ open_cfg.notify_state = wdsp_glink_notify_state;
+ open_cfg.notify_rx_intent_req = wdsp_glink_notify_rx_intent_req;
+ open_cfg.priv = ch;
+ open_cfg.name = ch->ch_cfg.name;
+
+ dev_dbg(wpriv->dev, "%s: ch->ch_cfg.name = %s, latency_in_us = %d, intents = %d\n",
+ __func__, ch->ch_cfg.name, ch->ch_cfg.latency_in_us,
+ ch->ch_cfg.no_of_intents);
+
+ mutex_lock(&ch->mutex);
+ ch->handle = glink_open(&open_cfg);
+ if (IS_ERR_OR_NULL(ch->handle)) {
+ dev_err(wpriv->dev, "%s: glink_open failed %s\n",
+ __func__, ch->ch_cfg.name);
+ ch->handle = NULL;
+ ret = -EINVAL;
+ }
+ mutex_unlock(&ch->mutex);
+
+ return ret;
+}
+
+/*
+ * wdsp_glink_close_all_ch - Internal function to close all glink channels
+ * wpriv: Wdsp_glink private structure
+ */
+static void wdsp_glink_close_all_ch(struct wdsp_glink_priv *wpriv)
+{
+ int i;
+
+ for (i = 0; i < wpriv->no_of_channels; i++)
+ if (wpriv->ch[i])
+ wdsp_glink_close_ch(wpriv->ch[i]);
+}
+
+/*
+ * wdsp_glink_open_all_ch - Internal function to open all glink channels
+ * wpriv: Wdsp_glink private structure
+ */
+static int wdsp_glink_open_all_ch(struct wdsp_glink_priv *wpriv)
+{
+ int ret = 0, i, j;
+
+ for (i = 0; i < wpriv->no_of_channels; i++) {
+ if (wpriv->ch && wpriv->ch[i]) {
+ ret = wdsp_glink_open_ch(wpriv->ch[i]);
+ if (IS_ERR_VALUE(ret))
+ goto err_open;
+ }
+ }
+ goto done;
+
+err_open:
+ for (j = 0; j < i; j++)
+ if (wpriv->ch[i])
+ wdsp_glink_close_ch(wpriv->ch[j]);
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_ch_open_wq - Work function to open glink channels
+ * work: Work structure
+ */
+static void wdsp_glink_ch_open_cls_wrk(struct work_struct *work)
+{
+ struct wdsp_glink_priv *wpriv;
+
+ wpriv = container_of(work, struct wdsp_glink_priv,
+ ch_open_cls_wrk);
+
+ if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
+ dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_DOWN\n",
+ __func__);
+
+ wdsp_glink_close_all_ch(wpriv);
+ } else if (wpriv->glink_state.link_state == GLINK_LINK_STATE_UP) {
+ dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_UP\n",
+ __func__);
+
+ wdsp_glink_open_all_ch(wpriv);
+ }
+}
+
+/*
+ * wdsp_glink_link_state_cb - Glink link state callback to inform
+ * about link states
+ * cb_info: Glink link state callback information structure
+ * priv: Private structure of link state passed while register
+ */
+static void wdsp_glink_link_state_cb(struct glink_link_state_cb_info *cb_info,
+ void *priv)
+{
+ struct wdsp_glink_priv *wpriv;
+
+ if (!cb_info || !priv) {
+ pr_err("%s: Invalid parameters\n", __func__);
+ return;
+ }
+
+ wpriv = (struct wdsp_glink_priv *)priv;
+ wpriv->glink_state.link_state = cb_info->link_state;
+ queue_work(wpriv->work_queue, &wpriv->ch_open_cls_wrk);
+}
+
+/*
+ * wdsp_glink_ch_info_init- Internal function to allocate channel memory
+ * and register with glink
+ * wpriv: Wdsp_glink private structure.
+ * pkt: Glink registration packet contains glink channel information.
+ */
+static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
+ struct wdsp_reg_pkt *pkt)
+{
+ int ret = 0, i, j;
+ struct glink_link_info link_info;
+ struct wdsp_glink_ch_cfg *ch_cfg;
+ struct wdsp_glink_ch **ch;
+ u8 no_of_channels;
+ u8 *payload;
+ u32 ch_size, ch_cfg_size;
+
+ payload = (u8 *)pkt->payload;
+ no_of_channels = pkt->no_of_channels;
+
+ ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
+ GFP_KERNEL);
+ if (!ch) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < no_of_channels; i++) {
+ ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
+ ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
+ (sizeof(u32) * ch_cfg->no_of_intents);
+ ch_size = sizeof(struct wdsp_glink_ch) +
+ (sizeof(u32) * ch_cfg->no_of_intents);
+
+ dev_dbg(wpriv->dev, "%s: channels = %d, ch_cfg_size %d",
+ __func__, no_of_channels, ch_cfg_size);
+
+ ch[i] = kzalloc(ch_size, GFP_KERNEL);
+ if (!ch[i]) {
+ ret = -ENOMEM;
+ goto err_ch_mem;
+ }
+ ch[i]->channel_state = GLINK_LOCAL_DISCONNECTED;
+ memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size);
+ payload += ch_cfg_size;
+
+ mutex_init(&ch[i]->mutex);
+ ch[i]->wpriv = wpriv;
+ }
+ wpriv->ch = ch;
+ wpriv->no_of_channels = no_of_channels;
+
+ INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk);
+
+ /* Register glink link_state notification */
+ link_info.glink_link_state_notif_cb = wdsp_glink_link_state_cb;
+ link_info.transport = NULL;
+ link_info.edge = WDSP_EDGE;
+
+ wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
+ wpriv->glink_state.handle = glink_register_link_state_cb(&link_info,
+ wpriv);
+ if (!wpriv->glink_state.handle) {
+ dev_err(wpriv->dev, "%s: Unable to register wdsp link state\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_ch_mem;
+ }
+ goto done;
+
+err_ch_mem:
+ for (j = 0; j < i; j++) {
+ mutex_destroy(&ch[j]->mutex);
+ kfree(wpriv->ch[j]);
+ wpriv->ch[j] = NULL;
+ }
+ kfree(wpriv->ch);
+ wpriv->ch = NULL;
+ wpriv->no_of_channels = 0;
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_tx_buf_work - Work queue function to send tx buffer to glink
+ * work: Work structure
+ */
+static void wdsp_glink_tx_buf_work(struct work_struct *work)
+{
+ struct wdsp_glink_priv *wpriv;
+ struct wdsp_glink_ch *ch;
+ struct wdsp_glink_tx_buf *tx_buf;
+ struct wdsp_write_pkt *wpkt;
+ struct wdsp_cmd_pkt *cpkt;
+ int ret = 0;
+
+ tx_buf = container_of(work, struct wdsp_glink_tx_buf,
+ tx_work);
+ ch = tx_buf->ch;
+ wpriv = ch->wpriv;
+ wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
+ cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
+ dev_dbg(wpriv->dev, "%s: ch name = %s, payload size = %d\n",
+ __func__, cpkt->ch_name, cpkt->payload_size);
+
+ mutex_lock(&tx_buf->ch->mutex);
+ if (ch->channel_state == GLINK_CONNECTED) {
+ ret = glink_tx(ch->handle, tx_buf,
+ cpkt->payload, cpkt->payload_size,
+ GLINK_TX_REQ_INTENT);
+ if (IS_ERR_VALUE(ret))
+ dev_err(wpriv->dev, "%s: glink tx failed, ret = %d\n",
+ __func__, ret);
+ } else {
+ dev_err(wpriv->dev, "%s: channel %s is not in connected state\n",
+ __func__, ch->ch_cfg.name);
+ }
+ mutex_unlock(&tx_buf->ch->mutex);
+
+}
+
+/*
+ * wdsp_glink_read - Read API to send the data to userspace
+ * file: Pointer to the file structure
+ * buf: Pointer to the userspace buffer
+ * count: Number bytes to read from the file
+ * ppos: Pointer to the position into the file
+ */
+static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0, ret1 = 0;
+ struct wdsp_glink_rsp_que *rsp;
+ struct wdsp_glink_priv *wpriv;
+
+ wpriv = (struct wdsp_glink_priv *)file->private_data;
+ if (!wpriv) {
+ pr_err("%s: Invalid private data\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (count > WDSP_MAX_READ_SIZE) {
+ dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
+ __func__, count);
+ count = WDSP_MAX_READ_SIZE;
+ }
+ /*
+ * This is unblocked only from glink rx notification callback
+ * or from flush API.
+ */
+ wait_for_completion(&wpriv->rsp_complete);
+
+ mutex_lock(&wpriv->rsp_mutex);
+ if (wpriv->rsp_cnt) {
+ wpriv->rsp_cnt--;
+ dev_dbg(wpriv->dev, "%s: read from buffer %d\n",
+ __func__, wpriv->rsp_cnt);
+
+ rsp = &wpriv->rsp[wpriv->rsp_cnt];
+ if (count < rsp->buf_size) {
+ ret1 = copy_to_user(buf, &rsp->buf, count);
+ /* Return the number of bytes copied */
+ ret = count;
+ } else {
+ ret1 = copy_to_user(buf, &rsp->buf, rsp->buf_size);
+ /* Return the number of bytes copied */
+ ret = rsp->buf_size;
+ }
+
+ if (ret1) {
+ mutex_unlock(&wpriv->rsp_mutex);
+ dev_err(wpriv->dev, "%s: copy_to_user failed %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /*
+ * This will execute only if flush API is called or
+ * something wrong with ref_cnt
+ */
+ dev_dbg(wpriv->dev, "%s: resp count = %d\n", __func__,
+ wpriv->rsp_cnt);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&wpriv->rsp_mutex);
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_write - Write API to receive the data from userspace
+ * file: Pointer to the file structure
+ * buf: Pointer to the userspace buffer
+ * count: Number bytes to read from the file
+ * ppos: Pointer to the position into the file
+ */
+static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0, i, tx_buf_size;
+ struct wdsp_write_pkt *wpkt;
+ struct wdsp_cmd_pkt *cpkt;
+ struct wdsp_glink_tx_buf *tx_buf;
+ struct wdsp_glink_priv *wpriv;
+
+ wpriv = (struct wdsp_glink_priv *)file->private_data;
+ if (!wpriv) {
+ pr_err("%s: Invalid private data\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
+
+ if (count > WDSP_MAX_WRITE_SIZE) {
+ dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_WRITE_SIZE\n",
+ __func__, count);
+ count = WDSP_MAX_WRITE_SIZE;
+ }
+
+ tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
+ tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
+ if (!tx_buf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = copy_from_user(tx_buf->buf, buf, count);
+ if (ret) {
+ dev_err(wpriv->dev, "%s: copy_from_user failed %d\n",
+ __func__, ret);
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
+ switch (wpkt->pkt_type) {
+ case WDSP_REG_PKT:
+ ret = wdsp_glink_ch_info_init(wpriv,
+ (struct wdsp_reg_pkt *)wpkt->payload);
+ if (IS_ERR_VALUE(ret))
+ dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n",
+ __func__, ret);
+ kfree(tx_buf);
+ break;
+ case WDSP_CMD_PKT:
+ cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
+ dev_dbg(wpriv->dev, "%s: requested ch_name: %s\n", __func__,
+ cpkt->ch_name);
+ for (i = 0; i < wpriv->no_of_channels; i++) {
+ if (wpriv->ch && wpriv->ch[i] &&
+ (!strcmp(cpkt->ch_name,
+ wpriv->ch[i]->ch_cfg.name))) {
+ tx_buf->ch = wpriv->ch[i];
+ break;
+ }
+ }
+ if (!tx_buf->ch) {
+ dev_err(wpriv->dev, "%s: Failed to get glink channel\n",
+ __func__);
+ ret = -EINVAL;
+ goto free_buf;
+ }
+ INIT_WORK(&tx_buf->tx_work, wdsp_glink_tx_buf_work);
+ queue_work(wpriv->work_queue, &tx_buf->tx_work);
+ break;
+ default:
+ dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__);
+ ret = -EINVAL;
+ kfree(tx_buf);
+ break;
+ }
+ goto done;
+
+free_buf:
+ kfree(tx_buf);
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_open - Open API to initialize private data
+ * inode: Pointer to the inode structure
+ * file: Pointer to the file structure
+ */
+static int wdsp_glink_open(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ struct wdsp_glink_priv *wpriv;
+ struct wdsp_glink_dev *wdev;
+
+ if (!inode->i_cdev) {
+ pr_err("%s: cdev is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ wdev = container_of(inode->i_cdev, struct wdsp_glink_dev, cdev);
+
+ wpriv = kzalloc(sizeof(struct wdsp_glink_priv), GFP_KERNEL);
+ if (!wpriv) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wpriv->dev = wdev->dev;
+ wpriv->work_queue = create_singlethread_workqueue("wdsp_glink_wq");
+ if (!wpriv->work_queue) {
+ dev_err(wpriv->dev, "%s: Error creating wdsp_glink_wq\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_wq;
+ }
+
+ init_completion(&wpriv->rsp_complete);
+ mutex_init(&wpriv->rsp_mutex);
+ file->private_data = wpriv;
+
+ goto done;
+
+err_wq:
+ kfree(wpriv);
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_flush - Flush API to unblock read.
+ * file: Pointer to the file structure
+ * id: Lock owner ID
+ */
+static int wdsp_glink_flush(struct file *file, fl_owner_t id)
+{
+ struct wdsp_glink_priv *wpriv;
+
+ wpriv = (struct wdsp_glink_priv *)file->private_data;
+ if (!wpriv) {
+ pr_err("%s: Invalid private data\n", __func__);
+ return -EINVAL;
+ }
+
+ complete(&wpriv->rsp_complete);
+
+ return 0;
+}
+
+/*
+ * wdsp_glink_release - Release API to clean up resources.
+ * Whenever a file structure is shared across multiple threads,
+ * release won't be invoked until all copies are closed
+ * (file->f_count.counter should be 0). If we need to flush pending
+ * data when any copy is closed, you should implement the flush method.
+ *
+ * inode: Pointer to the inode structure
+ * file: Pointer to the file structure
+ */
+static int wdsp_glink_release(struct inode *inode, struct file *file)
+{
+ int i, ret = 0;
+ struct wdsp_glink_priv *wpriv;
+
+ wpriv = (struct wdsp_glink_priv *)file->private_data;
+ if (!wpriv) {
+ pr_err("%s: Invalid private data\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ flush_workqueue(wpriv->work_queue);
+ /*
+ * Clean up glink channel memory in channel state
+ * callback only if close channels are called from here.
+ */
+ if (wpriv->ch) {
+ for (i = 0; i < wpriv->no_of_channels; i++)
+ if (wpriv->ch[i])
+ wpriv->ch[i]->free_mem = true;
+
+ wdsp_glink_close_all_ch(wpriv);
+ kfree(wpriv->ch);
+ wpriv->ch = NULL;
+ }
+
+ if (wpriv->glink_state.handle)
+ glink_unregister_link_state_cb(wpriv->glink_state.handle);
+
+ mutex_destroy(&wpriv->rsp_mutex);
+ if (wpriv->work_queue)
+ destroy_workqueue(wpriv->work_queue);
+
+ kfree(wpriv);
+ file->private_data = NULL;
+
+done:
+ return ret;
+}
+
+static const struct file_operations wdsp_glink_fops = {
+ .owner = THIS_MODULE,
+ .open = wdsp_glink_open,
+ .read = wdsp_glink_read,
+ .write = wdsp_glink_write,
+ .flush = wdsp_glink_flush,
+ .release = wdsp_glink_release,
+};
+
+/*
+ * wdsp_glink_probe - Driver probe to expose char device
+ * pdev: Pointer to device tree data.
+ */
+static int wdsp_glink_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct wdsp_glink_dev *wdev;
+
+ wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
+ if (!wdev) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = alloc_chrdev_region(&wdev->dev_num, 0, MINOR_NUMBER_COUNT,
+ WDSP_GLINK_DRIVER_NAME);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(&pdev->dev, "%s: Failed to alloc char dev, err = %d\n",
+ __func__, ret);
+ goto err_chrdev;
+ }
+
+ wdev->cls = class_create(THIS_MODULE, WDSP_GLINK_DRIVER_NAME);
+ if (IS_ERR(wdev->cls)) {
+ ret = PTR_ERR(wdev->cls);
+ dev_err(&pdev->dev, "%s: Failed to create class, err = %d\n",
+ __func__, ret);
+ goto err_class;
+ }
+
+ wdev->dev = device_create(wdev->cls, NULL, wdev->dev_num,
+ NULL, WDSP_GLINK_DRIVER_NAME);
+ if (IS_ERR(wdev->dev)) {
+ ret = PTR_ERR(wdev->dev);
+ dev_err(&pdev->dev, "%s: Failed to create device, err = %d\n",
+ __func__, ret);
+ goto err_dev_create;
+ }
+
+ cdev_init(&wdev->cdev, &wdsp_glink_fops);
+ ret = cdev_add(&wdev->cdev, wdev->dev_num, MINOR_NUMBER_COUNT);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(&pdev->dev, "%s: Failed to register char dev, err = %d\n",
+ __func__, ret);
+ goto err_cdev_add;
+ }
+ platform_set_drvdata(pdev, wdev);
+ goto done;
+
+err_cdev_add:
+ device_destroy(wdev->cls, wdev->dev_num);
+
+err_dev_create:
+ class_destroy(wdev->cls);
+
+err_class:
+ unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
+
+err_chrdev:
+ devm_kfree(&pdev->dev, wdev);
+
+done:
+ return ret;
+}
+
+/*
+ * wdsp_glink_remove - Driver remove to handle cleanup
+ * pdev: Pointer to device tree data.
+ */
+static int wdsp_glink_remove(struct platform_device *pdev)
+{
+ struct wdsp_glink_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev) {
+ cdev_del(&wdev->cdev);
+ device_destroy(wdev->cls, wdev->dev_num);
+ class_destroy(wdev->cls);
+ unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
+ devm_kfree(&pdev->dev, wdev);
+ } else {
+ dev_err(&pdev->dev, "%s: Invalid device data\n", __func__);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id wdsp_glink_of_match[] = {
+ {.compatible = "qcom,wcd-dsp-glink"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, wdsp_glink_of_match);
+
+static struct platform_driver wdsp_glink_driver = {
+ .probe = wdsp_glink_probe,
+ .remove = wdsp_glink_remove,
+ .driver = {
+ .name = WDSP_GLINK_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = wdsp_glink_of_match,
+ },
+};
+
+module_platform_driver(wdsp_glink_driver);
+
+MODULE_DESCRIPTION("SoC WCD_DSP GLINK Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.c b/drivers/soc/qcom/wlan_firmware_service_v01.c
index b33575116c18..b40e0671c691 100644
--- a/drivers/soc/qcom/wlan_firmware_service_v01.c
+++ b/drivers/soc/qcom/wlan_firmware_service_v01.c
@@ -1364,3 +1364,189 @@ struct elem_info wlfw_ini_resp_msg_v01_ei[] = {
.is_array = QMI_COMMON_TLV_TYPE,
},
};
+
+struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_vbatt_req_msg_v01,
+ voltage_uv),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_vbatt_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.h b/drivers/soc/qcom/wlan_firmware_service_v01.h
index bf47da7cdecb..b994762db7af 100644
--- a/drivers/soc/qcom/wlan_firmware_service_v01.h
+++ b/drivers/soc/qcom/wlan_firmware_service_v01.h
@@ -26,9 +26,11 @@
#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
#define QMI_WLFW_FW_READY_IND_V01 0x0021
@@ -39,8 +41,12 @@
#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
@@ -371,4 +377,48 @@ struct wlfw_ini_resp_msg_v01 {
#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_ini_resp_msg_v01_ei[];
+struct wlfw_athdiag_read_req_msg_v01 {
+ uint32_t offset;
+ uint32_t mem_type;
+ uint32_t data_len;
+};
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ uint8_t data_valid;
+ uint32_t data_len;
+ uint8_t data[QMI_WLFW_MAX_DATA_SIZE_V01];
+};
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+ uint32_t offset;
+ uint32_t mem_type;
+ uint32_t data_len;
+ uint8_t data[QMI_WLFW_MAX_DATA_SIZE_V01];
+};
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+ uint64_t voltage_uv;
+};
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
#endif
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index 2cb60c11e212..266091486bf1 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -325,6 +325,7 @@ static int swrm_set_ch_map(struct swr_mstr_ctrl *swrm, void *data)
GFP_KERNEL);
if (!swrm->mstr_port->port) {
kfree(swrm->mstr_port);
+ swrm->mstr_port = NULL;
return -ENOMEM;
}
memcpy(swrm->mstr_port->port, pinfo->port, pinfo->num_port);
@@ -476,7 +477,7 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr,
{
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int ret = 0;
- int val = 0;
+ int val;
u8 *reg_val = (u8 *)buf;
if (!swrm) {
@@ -1474,7 +1475,9 @@ static int swrm_remove(struct platform_device *pdev)
swrm, SWR_IRQ_FREE);
if (swrm->mstr_port) {
kfree(swrm->mstr_port->port);
+ swrm->mstr_port->port = NULL;
kfree(swrm->mstr_port);
+ swrm->mstr_port = NULL;
}
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index d549d6271d89..513d015a5ace 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -54,8 +54,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool,
__free_pages(page, pool->order);
}
-static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page,
- bool prefetch)
+static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
{
mutex_lock(&pool->mutex);
if (PageHighMem(page)) {
@@ -65,15 +64,11 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page,
list_add_tail(&page->lru, &pool->low_items);
pool->low_count++;
}
- if (!prefetch)
- pool->nr_unreserved++;
-
mutex_unlock(&pool->mutex);
return 0;
}
-static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high,
- bool prefetch)
+static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
{
struct page *page;
@@ -87,13 +82,6 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high,
pool->low_count--;
}
- if (prefetch) {
- BUG_ON(!pool->nr_unreserved);
- pool->nr_unreserved--;
- }
- pool->nr_unreserved = min_t(int, pool->high_count + pool->low_count,
- pool->nr_unreserved);
-
list_del(&page->lru);
return page;
}
@@ -108,9 +96,9 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool)
if (mutex_trylock(&pool->mutex)) {
if (pool->high_count)
- page = ion_page_pool_remove(pool, true, false);
+ page = ion_page_pool_remove(pool, true);
else if (pool->low_count)
- page = ion_page_pool_remove(pool, false, false);
+ page = ion_page_pool_remove(pool, false);
mutex_unlock(&pool->mutex);
}
if (!page) {
@@ -120,27 +108,6 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool)
return page;
}
-void *ion_page_pool_prefetch(struct ion_page_pool *pool, bool *from_pool)
-{
- struct page *page = NULL;
-
- BUG_ON(!pool);
-
- *from_pool = true;
-
- if (mutex_trylock(&pool->mutex)) {
- if (pool->high_count && pool->nr_unreserved > 0)
- page = ion_page_pool_remove(pool, true, true);
- else if (pool->low_count && pool->nr_unreserved > 0)
- page = ion_page_pool_remove(pool, false, true);
- mutex_unlock(&pool->mutex);
- }
- if (!page) {
- page = ion_page_pool_alloc_pages(pool);
- *from_pool = false;
- }
- return page;
-}
/*
* Tries to allocate from only the specified Pool and returns NULL otherwise
*/
@@ -152,24 +119,20 @@ void *ion_page_pool_alloc_pool_only(struct ion_page_pool *pool)
if (mutex_trylock(&pool->mutex)) {
if (pool->high_count)
- page = ion_page_pool_remove(pool, true, false);
+ page = ion_page_pool_remove(pool, true);
else if (pool->low_count)
- page = ion_page_pool_remove(pool, false, false);
+ page = ion_page_pool_remove(pool, false);
mutex_unlock(&pool->mutex);
}
return page;
}
-void ion_page_pool_free(struct ion_page_pool *pool, struct page *page,
- bool prefetch)
+void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
{
int ret;
- BUG_ON(pool->order != compound_order(page));
-
- ret = ion_page_pool_add(pool, page, prefetch);
- /* FIXME? For a secure page, not hyp unassigned in this err path */
+ ret = ion_page_pool_add(pool, page);
if (ret)
ion_page_pool_free_pages(pool, page);
}
@@ -208,9 +171,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
mutex_lock(&pool->mutex);
if (pool->low_count) {
- page = ion_page_pool_remove(pool, false, false);
+ page = ion_page_pool_remove(pool, false);
} else if (high && pool->high_count) {
- page = ion_page_pool_remove(pool, true, false);
+ page = ion_page_pool_remove(pool, true);
} else {
mutex_unlock(&pool->mutex);
break;
@@ -233,10 +196,9 @@ struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask,
pool->dev = dev;
pool->high_count = 0;
pool->low_count = 0;
- pool->nr_unreserved = 0;
INIT_LIST_HEAD(&pool->low_items);
INIT_LIST_HEAD(&pool->high_items);
- pool->gfp_mask = gfp_mask | __GFP_COMP;
+ pool->gfp_mask = gfp_mask;
pool->order = order;
mutex_init(&pool->mutex);
plist_node_init(&pool->list, order);
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index 4f383661258a..b687675be02f 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -415,8 +415,6 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
* struct ion_page_pool - pagepool struct
* @high_count: number of highmem items in the pool
* @low_count: number of lowmem items in the pool
- * @nr_unreserved: number of items in the pool which have not been reserved
- * by a prefetch allocation
* @high_items: list of highmem items
* @low_items: list of lowmem items
* @mutex: lock protecting this struct and especially the count
@@ -433,7 +431,6 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
struct ion_page_pool {
int high_count;
int low_count;
- int nr_unreserved;
struct list_head high_items;
struct list_head low_items;
struct mutex mutex;
@@ -448,10 +445,10 @@ struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask,
void ion_page_pool_destroy(struct ion_page_pool *);
void *ion_page_pool_alloc(struct ion_page_pool *, bool *from_pool);
void *ion_page_pool_alloc_pool_only(struct ion_page_pool *);
-void ion_page_pool_free(struct ion_page_pool *, struct page *, bool prefetch);
+void ion_page_pool_free(struct ion_page_pool *, struct page *);
void ion_page_pool_free_immediate(struct ion_page_pool *, struct page *);
int ion_page_pool_total(struct ion_page_pool *pool, bool high);
-void *ion_page_pool_prefetch(struct ion_page_pool *pool, bool *from_pool);
+size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap, int vmid);
#ifdef CONFIG_ION_POOL_CACHE_POLICY
static inline void ion_page_pool_alloc_set_cache_policy
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index ff75e1690f59..fd4d45ad8db2 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -63,6 +63,8 @@ struct ion_system_heap {
struct ion_page_pool **uncached_pools;
struct ion_page_pool **cached_pools;
struct ion_page_pool **secure_pools[VMID_LAST];
+ /* Prevents unnecessary page splitting */
+ struct mutex split_page_mutex;
};
struct page_info {
@@ -72,13 +74,37 @@ struct page_info {
struct list_head list;
};
+/*
+ * Used by ion_system_secure_heap only
+ * Since no lock is held, results are approximate.
+ */
+size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap,
+ int vmid_flags)
+{
+ struct ion_system_heap *sys_heap;
+ struct ion_page_pool *pool;
+ size_t total = 0;
+ int vmid, i;
+
+ sys_heap = container_of(heap, struct ion_system_heap, heap);
+ vmid = get_secure_vmid(vmid_flags);
+ if (!is_secure_vmid_valid(vmid))
+ return 0;
+
+ for (i = 0; i < num_orders; i++) {
+ pool = sys_heap->secure_pools[vmid][i];
+ total += ion_page_pool_total(pool, true);
+ }
+
+ return total << PAGE_SHIFT;
+}
+
static struct page *alloc_buffer_page(struct ion_system_heap *heap,
struct ion_buffer *buffer,
unsigned long order,
bool *from_pool)
{
bool cached = ion_buffer_cached(buffer);
- bool prefetch = buffer->flags & ION_FLAG_POOL_PREFETCH;
struct page *page;
struct ion_page_pool *pool;
int vmid = get_secure_vmid(buffer->flags);
@@ -92,10 +118,7 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
else
pool = heap->cached_pools[order_to_index(order)];
- if (prefetch)
- page = ion_page_pool_prefetch(pool, from_pool);
- else
- page = ion_page_pool_alloc(pool, from_pool);
+ page = ion_page_pool_alloc(pool, from_pool);
} else {
gfp_t gfp_mask = low_order_gfp_flags;
if (order)
@@ -119,7 +142,6 @@ static void free_buffer_page(struct ion_system_heap *heap,
unsigned int order)
{
bool cached = ion_buffer_cached(buffer);
- bool prefetch = buffer->flags & ION_FLAG_POOL_PREFETCH;
int vmid = get_secure_vmid(buffer->flags);
if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)) {
@@ -134,12 +156,65 @@ static void free_buffer_page(struct ion_system_heap *heap,
if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)
ion_page_pool_free_immediate(pool, page);
else
- ion_page_pool_free(pool, page, prefetch);
+ ion_page_pool_free(pool, page);
} else {
__free_pages(page, order);
}
}
+static struct page *alloc_from_secure_pool_order(struct ion_system_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long order)
+{
+ int vmid = get_secure_vmid(buffer->flags);
+ struct ion_page_pool *pool;
+
+ if (!is_secure_vmid_valid(vmid))
+ return NULL;
+
+ pool = heap->secure_pools[vmid][order_to_index(order)];
+ return ion_page_pool_alloc_pool_only(pool);
+}
+
+static struct page *split_page_from_secure_pool(struct ion_system_heap *heap,
+ struct ion_buffer *buffer)
+{
+ int i, j;
+ struct page *page;
+ unsigned int order;
+
+ mutex_lock(&heap->split_page_mutex);
+
+ /*
+ * Someone may have just split a page and returned the unused portion
+ * back to the pool, so try allocating from the pool one more time
+ * before splitting. We want to maintain large pages sizes when
+ * possible.
+ */
+ page = alloc_from_secure_pool_order(heap, buffer, 0);
+ if (page)
+ goto got_page;
+
+ for (i = num_orders - 2; i >= 0; i--) {
+ order = orders[i];
+ page = alloc_from_secure_pool_order(heap, buffer, order);
+ if (!page)
+ continue;
+
+ split_page(page, order);
+ break;
+ }
+ /* Return the remaining order-0 pages to the pool */
+ if (page)
+ for (j = 1; j < (1 << order); j++)
+ free_buffer_page(heap, buffer, page + j, 0);
+
+got_page:
+ mutex_unlock(&heap->split_page_mutex);
+
+ return page;
+}
+
static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
struct ion_buffer *buffer,
unsigned long size,
@@ -174,6 +249,49 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
return NULL;
}
+
+static struct page_info *alloc_from_pool_preferred(
+ struct ion_system_heap *heap, struct ion_buffer *buffer,
+ unsigned long size, unsigned int max_order)
+{
+ struct page *page;
+ struct page_info *info;
+ int i;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return NULL;
+
+ for (i = 0; i < num_orders; i++) {
+ if (size < order_to_size(orders[i]))
+ continue;
+ if (max_order < orders[i])
+ continue;
+
+ page = alloc_from_secure_pool_order(heap, buffer, orders[i]);
+ if (!page)
+ continue;
+
+ info->page = page;
+ info->order = orders[i];
+ info->from_pool = true;
+ INIT_LIST_HEAD(&info->list);
+ return info;
+ }
+
+ page = split_page_from_secure_pool(heap, buffer);
+ if (page) {
+ info->page = page;
+ info->order = 0;
+ info->from_pool = true;
+ INIT_LIST_HEAD(&info->list);
+ return info;
+ }
+
+ kfree(info);
+ return alloc_largest_available(heap, buffer, size, max_order);
+}
+
static unsigned int process_info(struct page_info *info,
struct scatterlist *sg,
struct scatterlist *sg_sync,
@@ -236,9 +354,17 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
data.size = 0;
INIT_LIST_HEAD(&pages);
INIT_LIST_HEAD(&pages_from_pool);
+
while (size_remaining > 0) {
- info = alloc_largest_available(sys_heap, buffer, size_remaining,
- max_order);
+ if (is_secure_vmid_valid(vmid))
+ info = alloc_from_pool_preferred(
+ sys_heap, buffer, size_remaining,
+ max_order);
+ else
+ info = alloc_largest_available(
+ sys_heap, buffer, size_remaining,
+ max_order);
+
if (!info)
goto err;
@@ -452,7 +578,7 @@ out1:
/* Restore pages to secure pool */
list_for_each_entry_safe(page, tmp, &pages, lru) {
list_del(&page->lru);
- ion_page_pool_free(pool, page, false);
+ ion_page_pool_free(pool, page);
}
return 0;
out2:
@@ -692,6 +818,8 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data)
if (ion_system_heap_create_pools(dev, heap->cached_pools))
goto err_create_cached_pools;
+ mutex_init(&heap->split_page_mutex);
+
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c
index 5c0225cd4e24..ec09f9f12b47 100644
--- a/drivers/staging/android/ion/ion_system_secure_heap.c
+++ b/drivers/staging/android/ion/ion_system_secure_heap.c
@@ -29,15 +29,24 @@ struct ion_system_secure_heap {
spinlock_t work_lock;
bool destroy_heap;
struct list_head prefetch_list;
- struct work_struct prefetch_work;
+ struct delayed_work prefetch_work;
};
struct prefetch_info {
struct list_head list;
int vmid;
size_t size;
+ bool shrink;
};
+/*
+ * The video client may not hold the last reference count on the
+ * ion_buffer(s). Delay for a short time after the video client sends
+ * the IOC_DRAIN event to increase the chance that the reference
+ * count drops to zero. Time in milliseconds.
+ */
+#define SHRINK_DELAY 1000
+
static bool is_cp_flag_present(unsigned long flags)
{
return flags && (ION_FLAG_CP_TOUCH ||
@@ -124,55 +133,97 @@ static int ion_system_secure_heap_allocate(struct ion_heap *heap,
return ret;
}
+static void process_one_prefetch(struct ion_heap *sys_heap,
+ struct prefetch_info *info)
+{
+ struct ion_buffer buffer;
+ struct sg_table *sg_table;
+ int ret;
+
+ buffer.heap = sys_heap;
+ buffer.flags = 0;
+
+ ret = sys_heap->ops->allocate(sys_heap, &buffer, info->size,
+ PAGE_SIZE, buffer.flags);
+ if (ret) {
+ pr_debug("%s: Failed to prefetch 0x%zx, ret = %d\n",
+ __func__, info->size, ret);
+ return;
+ }
+
+ sg_table = sys_heap->ops->map_dma(sys_heap, &buffer);
+ if (IS_ERR_OR_NULL(sg_table))
+ goto out;
+
+ ret = ion_system_secure_heap_assign_sg(sg_table,
+ get_secure_vmid(info->vmid));
+ if (ret)
+ goto unmap;
+
+ /* Now free it to the secure heap */
+ buffer.heap = sys_heap;
+ buffer.flags = info->vmid;
+
+unmap:
+ sys_heap->ops->unmap_dma(sys_heap, &buffer);
+out:
+ sys_heap->ops->free(&buffer);
+}
+
+static void process_one_shrink(struct ion_heap *sys_heap,
+ struct prefetch_info *info)
+{
+ struct ion_buffer buffer;
+ size_t pool_size, size;
+ int ret;
+
+ buffer.heap = sys_heap;
+ buffer.flags = info->vmid;
+
+ pool_size = ion_system_heap_secure_page_pool_total(sys_heap,
+ info->vmid);
+ size = min(pool_size, info->size);
+ ret = sys_heap->ops->allocate(sys_heap, &buffer, size, PAGE_SIZE,
+ buffer.flags);
+ if (ret) {
+ pr_debug("%s: Failed to shrink 0x%zx, ret = %d\n",
+ __func__, info->size, ret);
+ return;
+ }
+
+ buffer.private_flags = ION_PRIV_FLAG_SHRINKER_FREE;
+ sys_heap->ops->free(&buffer);
+}
+
static void ion_system_secure_heap_prefetch_work(struct work_struct *work)
{
struct ion_system_secure_heap *secure_heap = container_of(work,
struct ion_system_secure_heap,
- prefetch_work);
+ prefetch_work.work);
struct ion_heap *sys_heap = secure_heap->sys_heap;
struct prefetch_info *info, *tmp;
- unsigned long flags, size;
- struct ion_buffer *buffer;
- int ret;
- int vmid_flags;
-
- buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (!buffer)
- return;
+ unsigned long flags;
spin_lock_irqsave(&secure_heap->work_lock, flags);
list_for_each_entry_safe(info, tmp,
&secure_heap->prefetch_list, list) {
list_del(&info->list);
spin_unlock_irqrestore(&secure_heap->work_lock, flags);
- size = info->size;
- vmid_flags = info->vmid;
- kfree(info);
- /* buffer->heap used by free() */
- buffer->heap = &secure_heap->heap;
- buffer->flags = ION_FLAG_POOL_PREFETCH;
- buffer->flags |= vmid_flags;
- ret = sys_heap->ops->allocate(sys_heap, buffer, size,
- PAGE_SIZE, 0);
- if (ret) {
- pr_debug("%s: Failed to get %zx allocation for %s, ret = %d\n",
- __func__, info->size, secure_heap->heap.name,
- ret);
- spin_lock_irqsave(&secure_heap->work_lock, flags);
- continue;
- }
-
- ion_system_secure_heap_free(buffer);
+ if (info->shrink)
+ process_one_shrink(sys_heap, info);
+ else
+ process_one_prefetch(sys_heap, info);
+
+ kfree(info);
spin_lock_irqsave(&secure_heap->work_lock, flags);
}
spin_unlock_irqrestore(&secure_heap->work_lock, flags);
- kfree(buffer);
}
static int alloc_prefetch_info(
struct ion_prefetch_regions __user *user_regions,
- struct list_head *items)
+ bool shrink, struct list_head *items)
{
struct prefetch_info *info;
size_t __user *user_sizes;
@@ -188,6 +239,9 @@ static int alloc_prefetch_info(
if (!is_secure_vmid_valid(get_secure_vmid(vmid)))
return -EINVAL;
+ if (nr_sizes > 0x10)
+ return -EINVAL;
+
for (i = 0; i < nr_sizes; i++) {
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
@@ -198,6 +252,7 @@ static int alloc_prefetch_info(
goto out_free;
info->vmid = vmid;
+ info->shrink = shrink;
INIT_LIST_HEAD(&info->list);
list_add_tail(&info->list, items);
}
@@ -207,7 +262,8 @@ out_free:
return err;
}
-int ion_system_secure_heap_prefetch(struct ion_heap *heap, void *ptr)
+static int __ion_system_secure_heap_resize(struct ion_heap *heap, void *ptr,
+ bool shrink)
{
struct ion_system_secure_heap *secure_heap = container_of(heap,
struct ion_system_secure_heap,
@@ -221,8 +277,11 @@ int ion_system_secure_heap_prefetch(struct ion_heap *heap, void *ptr)
if ((int)heap->type != ION_HEAP_TYPE_SYSTEM_SECURE)
return -EINVAL;
+ if (data->nr_regions > 0x10)
+ return -EINVAL;
+
for (i = 0; i < data->nr_regions; i++) {
- ret = alloc_prefetch_info(&data->regions[i], &items);
+ ret = alloc_prefetch_info(&data->regions[i], shrink, &items);
if (ret)
goto out_free;
}
@@ -233,7 +292,8 @@ int ion_system_secure_heap_prefetch(struct ion_heap *heap, void *ptr)
goto out_free;
}
list_splice_init(&items, &secure_heap->prefetch_list);
- schedule_work(&secure_heap->prefetch_work);
+ schedule_delayed_work(&secure_heap->prefetch_work,
+ shrink ? msecs_to_jiffies(SHRINK_DELAY) : 0);
spin_unlock_irqrestore(&secure_heap->work_lock, flags);
return 0;
@@ -246,6 +306,16 @@ out_free:
return ret;
}
+int ion_system_secure_heap_prefetch(struct ion_heap *heap, void *ptr)
+{
+ return __ion_system_secure_heap_resize(heap, ptr, false);
+}
+
+int ion_system_secure_heap_drain(struct ion_heap *heap, void *ptr)
+{
+ return __ion_system_secure_heap_resize(heap, ptr, true);
+}
+
static struct sg_table *ion_system_secure_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
@@ -326,7 +396,8 @@ struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused)
heap->destroy_heap = false;
heap->work_lock = __SPIN_LOCK_UNLOCKED(heap->work_lock);
INIT_LIST_HEAD(&heap->prefetch_list);
- INIT_WORK(&heap->prefetch_work, ion_system_secure_heap_prefetch_work);
+ INIT_DELAYED_WORK(&heap->prefetch_work,
+ ion_system_secure_heap_prefetch_work);
return &heap->heap;
}
@@ -345,7 +416,7 @@ void ion_system_secure_heap_destroy(struct ion_heap *heap)
list_splice_init(&secure_heap->prefetch_list, &items);
spin_unlock_irqrestore(&secure_heap->work_lock, flags);
- cancel_work_sync(&secure_heap->prefetch_work);
+ cancel_delayed_work_sync(&secure_heap->prefetch_work);
list_for_each_entry_safe(info, tmp, &items, list) {
list_del(&info->list);
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 46d7aae9b1c4..cd420c429031 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -768,6 +768,14 @@ long msm_ion_custom_ioctl(struct ion_client *client,
if (ret)
return ret;
+
+ ret = ion_walk_heaps(client, data.prefetch_data.heap_id,
+ ION_HEAP_TYPE_SYSTEM_SECURE,
+ (void *)&data.prefetch_data,
+ ion_system_secure_heap_drain);
+
+ if (ret)
+ return ret;
break;
}
diff --git a/drivers/staging/android/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h
index 7ffab548313d..d6b58ad53c01 100644
--- a/drivers/staging/android/ion/msm_ion_priv.h
+++ b/drivers/staging/android/ion/msm_ion_priv.h
@@ -52,6 +52,7 @@ void ion_cp_heap_destroy(struct ion_heap *);
struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *);
void ion_system_secure_heap_destroy(struct ion_heap *);
int ion_system_secure_heap_prefetch(struct ion_heap *heap, void *data);
+int ion_system_secure_heap_drain(struct ion_heap *heap, void *data);
struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *);
void ion_cma_secure_heap_destroy(struct ion_heap *);
diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h
index 73b4d1edcaad..b3c29826834e 100644
--- a/drivers/staging/android/uapi/msm_ion.h
+++ b/drivers/staging/android/uapi/msm_ion.h
@@ -110,8 +110,6 @@ enum cp_mem_usage {
*/
#define ION_FLAG_POOL_FORCE_ALLOC (1 << 16)
-#define ION_FLAG_POOL_PREFETCH (1 << 27)
-
/**
* Deprecated! Please use the corresponding ION_FLAG_*
*/
@@ -176,7 +174,6 @@ struct ion_prefetch_regions {
struct ion_prefetch_data {
int heap_id;
unsigned long len;
- /* Is unsigned long bad? 32bit compiler vs 64 bit compiler*/
struct ion_prefetch_regions __user *regions;
unsigned int nr_regions;
};
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 899a77187bde..2a2975c352f4 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2227,7 +2227,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
device->con->write = pl011_early_write;
return 0;
}
-EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 03ebe401fff7..3a1de5c87cb4 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
dev->con->write = arc_early_serial_write;
return 0;
}
-EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index b5b2f2be6be7..4d2e3e7a40bb 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -19,7 +19,6 @@
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
-#include <linux/mod_devicetable.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@@ -37,13 +36,6 @@ static struct earlycon_device early_console_dev = {
.con = &early_con,
};
-extern struct earlycon_id __earlycon_table[];
-static const struct earlycon_id __earlycon_table_sentinel
- __used __section(__earlycon_table_end);
-
-static const struct of_device_id __earlycon_of_table_sentinel
- __used __section(__earlycon_of_table_end);
-
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
@@ -159,7 +151,7 @@ int __init setup_earlycon(char *buf)
if (early_con.flags & CON_ENABLED)
return -EALREADY;
- for (match = __earlycon_table; match->name[0]; match++) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
size_t len = strlen(match->name);
if (strncmp(buf, match->name, len))
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index edd66bb7bd4c..670eda466438 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -19,33 +19,147 @@
# define SUPPORT_SYSRQ
#endif
+#include <linux/kernel.h>
#include <linux/atomic.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/hrtimer.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/ioport.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
-#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
-
-#include "msm_serial.h"
-
-#define UARTDM_BURST_SIZE 16 /* in bytes */
-#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
-#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
-#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
+#include <linux/wait.h>
+
+#define UART_MR1 0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
+#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
+#define UART_MR1_RX_RDY_CTL BIT(7)
+#define UART_MR1_CTS_CTL BIT(6)
+
+#define UART_MR2 0x0004
+#define UART_MR2_ERROR_MODE BIT(6)
+#define UART_MR2_BITS_PER_CHAR 0x30
+#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE 0x0
+#define UART_MR2_PARITY_MODE_ODD 0x1
+#define UART_MR2_PARITY_MODE_EVEN 0x2
+#define UART_MR2_PARITY_MODE_SPACE 0x3
+#define UART_MR2_PARITY_MODE 0x3
+
+#define UART_CSR 0x0008
+
+#define UART_TF 0x000C
+#define UARTDM_TF 0x0070
+
+#define UART_CR 0x0010
+#define UART_CR_CMD_NULL (0 << 4)
+#define UART_CR_CMD_RESET_RX (1 << 4)
+#define UART_CR_CMD_RESET_TX (2 << 4)
+#define UART_CR_CMD_RESET_ERR (3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
+#define UART_CR_CMD_START_BREAK (5 << 4)
+#define UART_CR_CMD_STOP_BREAK (6 << 4)
+#define UART_CR_CMD_RESET_CTS (7 << 4)
+#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
+#define UART_CR_CMD_PACKET_MODE (9 << 4)
+#define UART_CR_CMD_MODE_RESET (12 << 4)
+#define UART_CR_CMD_SET_RFR (13 << 4)
+#define UART_CR_CMD_RESET_RFR (14 << 4)
+#define UART_CR_CMD_PROTECTION_EN (16 << 4)
+#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
+#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
+#define UART_CR_CMD_FORCE_STALE (4 << 8)
+#define UART_CR_CMD_RESET_TX_READY (3 << 8)
+#define UART_CR_TX_DISABLE BIT(3)
+#define UART_CR_TX_ENABLE BIT(2)
+#define UART_CR_RX_DISABLE BIT(1)
+#define UART_CR_RX_ENABLE BIT(0)
+#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
+
+#define UART_IMR 0x0014
+#define UART_IMR_TXLEV BIT(0)
+#define UART_IMR_RXSTALE BIT(3)
+#define UART_IMR_RXLEV BIT(4)
+#define UART_IMR_DELTA_CTS BIT(5)
+#define UART_IMR_CURRENT_CTS BIT(6)
+#define UART_IMR_RXBREAK_START BIT(10)
+
+#define UART_IPR_RXSTALE_LAST 0x20
+#define UART_IPR_STALE_LSB 0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
+#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
+
+#define UART_IPR 0x0018
+#define UART_TFWR 0x001C
+#define UART_RFWR 0x0020
+#define UART_HCR 0x0024
+
+#define UART_MREG 0x0028
+#define UART_NREG 0x002C
+#define UART_DREG 0x0030
+#define UART_MNDREG 0x0034
+#define UART_IRDA 0x0038
+#define UART_MISR_MODE 0x0040
+#define UART_MISR_RESET 0x0044
+#define UART_MISR_EXPORT 0x0048
+#define UART_MISR_VAL 0x004C
+#define UART_TEST_CTRL 0x0050
+
+#define UART_SR 0x0008
+#define UART_SR_HUNT_CHAR BIT(7)
+#define UART_SR_RX_BREAK BIT(6)
+#define UART_SR_PAR_FRAME_ERR BIT(5)
+#define UART_SR_OVERRUN BIT(4)
+#define UART_SR_TX_EMPTY BIT(3)
+#define UART_SR_TX_READY BIT(2)
+#define UART_SR_RX_FULL BIT(1)
+#define UART_SR_RX_READY BIT(0)
+
+#define UART_RF 0x000C
+#define UARTDM_RF 0x0070
+#define UART_MISR 0x0010
+#define UART_ISR 0x0014
+#define UART_ISR_TX_READY BIT(7)
+
+#define UARTDM_RXFS 0x50
+#define UARTDM_RXFS_BUF_SHIFT 0x7
+#define UARTDM_RXFS_BUF_MASK 0x7
+
+#define UARTDM_DMEN 0x3C
+#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
+#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
+
+#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
+#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
+
+#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
+#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
+
+#define UARTDM_DMRX 0x34
+#define UARTDM_NCF_TX 0x40
+#define UARTDM_RX_TOTAL_SNAP 0x38
+
+#define UARTDM_BURST_SIZE 16 /* in bytes */
+#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
+#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
+#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
enum {
UARTDM_1P1 = 1,
@@ -78,10 +192,65 @@ struct msm_port {
struct msm_dma rx_dma;
};
+#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart)
+
+static
+void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
+{
+ writel_relaxed(val, port->membase + off);
+}
+
+static
+unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+ return readl_relaxed(port->membase + off);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock.
+ */
+static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
+{
+ msm_write(port, 0x06, UART_MREG);
+ msm_write(port, 0xF1, UART_NREG);
+ msm_write(port, 0x0F, UART_DREG);
+ msm_write(port, 0x1A, UART_MNDREG);
+ port->uartclk = 1843200;
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock divided by 4.
+ */
+static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
+{
+ msm_write(port, 0x18, UART_MREG);
+ msm_write(port, 0xF6, UART_NREG);
+ msm_write(port, 0x0F, UART_DREG);
+ msm_write(port, 0x0A, UART_MNDREG);
+ port->uartclk = 1843200;
+}
+
+static void msm_serial_set_mnd_regs(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ /*
+ * These registers don't exist so we change the clk input rate
+ * on uartdm hardware instead
+ */
+ if (msm_port->is_uartdm)
+ return;
+
+ if (port->uartclk == 19200000)
+ msm_serial_set_mnd_regs_tcxo(port);
+ else if (port->uartclk == 4800000)
+ msm_serial_set_mnd_regs_tcxoby4(port);
+}
+
static void msm_handle_tx(struct uart_port *port);
static void msm_start_rx_dma(struct msm_port *msm_port);
-void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
+static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
{
struct device *dev = port->dev;
unsigned int mapped;
@@ -388,10 +557,6 @@ static void msm_complete_rx_dma(void *args)
val &= ~dma->enable_bit;
msm_write(port, val, UARTDM_DMEN);
- /* Restore interrupts */
- msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
- msm_write(port, msm_port->imr, UART_IMR);
-
if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
port->icount.overrun++;
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
@@ -726,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port)
return;
}
- pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
dma_min = 1; /* Always DMA */
@@ -861,37 +1026,72 @@ struct msm_baud_map {
};
static const struct msm_baud_map *
-msm_find_best_baud(struct uart_port *port, unsigned int baud)
+msm_find_best_baud(struct uart_port *port, unsigned int baud,
+ unsigned long *rate)
{
- unsigned int i, divisor;
- const struct msm_baud_map *entry;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ unsigned int divisor, result;
+ unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX;
+ const struct msm_baud_map *entry, *end, *best;
static const struct msm_baud_map table[] = {
- { 1536, 0x00, 1 },
- { 768, 0x11, 1 },
- { 384, 0x22, 1 },
- { 192, 0x33, 1 },
- { 96, 0x44, 1 },
- { 48, 0x55, 1 },
- { 32, 0x66, 1 },
- { 24, 0x77, 1 },
- { 16, 0x88, 1 },
- { 12, 0x99, 6 },
- { 8, 0xaa, 6 },
- { 6, 0xbb, 6 },
- { 4, 0xcc, 6 },
- { 3, 0xdd, 8 },
- { 2, 0xee, 16 },
{ 1, 0xff, 31 },
- { 0, 0xff, 31 },
+ { 2, 0xee, 16 },
+ { 3, 0xdd, 8 },
+ { 4, 0xcc, 6 },
+ { 6, 0xbb, 6 },
+ { 8, 0xaa, 6 },
+ { 12, 0x99, 6 },
+ { 16, 0x88, 1 },
+ { 24, 0x77, 1 },
+ { 32, 0x66, 1 },
+ { 48, 0x55, 1 },
+ { 96, 0x44, 1 },
+ { 192, 0x33, 1 },
+ { 384, 0x22, 1 },
+ { 768, 0x11, 1 },
+ { 1536, 0x00, 1 },
};
- divisor = uart_get_divisor(port, baud);
+ best = table; /* Default to smallest divider */
+ target = clk_round_rate(msm_port->clk, 16 * baud);
+ divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+
+ end = table + ARRAY_SIZE(table);
+ entry = table;
+ while (entry < end) {
+ if (entry->divisor <= divisor) {
+ result = target / entry->divisor / 16;
+ diff = abs(result - baud);
+
+ /* Keep track of best entry */
+ if (diff < best_diff) {
+ best_diff = diff;
+ best = entry;
+ best_rate = target;
+ }
- for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
- if (entry->divisor <= divisor)
- break;
+ if (result == baud)
+ break;
+ } else if (entry->divisor > divisor) {
+ old = target;
+ target = clk_round_rate(msm_port->clk, old + 1);
+ /*
+ * The rate didn't get any faster so we can't do
+ * better at dividing it down
+ */
+ if (target == old)
+ break;
- return entry; /* Default to smallest divider */
+ /* Start the divisor search over at this new rate */
+ entry = table;
+ divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+ continue;
+ }
+ entry++;
+ }
+
+ *rate = best_rate;
+ return best;
}
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
@@ -900,22 +1100,20 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
unsigned int rxstale, watermark, mask;
struct msm_port *msm_port = UART_TO_MSM(port);
const struct msm_baud_map *entry;
- unsigned long flags;
-
- entry = msm_find_best_baud(port, baud);
-
- msm_write(port, entry->code, UART_CSR);
-
- if (baud > 460800)
- port->uartclk = baud * 16;
+ unsigned long flags, rate;
flags = *saved_flags;
spin_unlock_irqrestore(&port->lock, flags);
- clk_set_rate(msm_port->clk, port->uartclk);
+ entry = msm_find_best_baud(port, baud, &rate);
+ clk_set_rate(msm_port->clk, rate);
+ baud = rate / 16 / entry->divisor;
spin_lock_irqsave(&port->lock, flags);
*saved_flags = flags;
+ port->uartclk = rate;
+
+ msm_write(port, entry->code, UART_CSR);
/* RX stale watermark */
rxstale = entry->rxstale;
@@ -1480,7 +1678,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
device->con->write = msm_serial_early_write;
return 0;
}
-EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
msm_serial_early_console_setup);
@@ -1502,7 +1699,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
device->con->write = msm_serial_early_write_dm;
return 0;
}
-EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
msm_serial_early_console_setup_dm);
@@ -1581,8 +1777,6 @@ static int msm_serial_probe(struct platform_device *pdev)
msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(msm_port->pclk))
return PTR_ERR(msm_port->pclk);
-
- clk_set_rate(msm_port->clk, 1843200);
}
port->uartclk = clk_get_rate(msm_port->clk);
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
deleted file mode 100644
index dfdf73707e9d..000000000000
--- a/drivers/tty/serial/msm_serial.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Author: Robert Love <rlove@google.com>
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
-#define __DRIVERS_SERIAL_MSM_SERIAL_H
-
-#define UART_MR1 0x0000
-
-#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
-#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
-#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
-#define UART_MR1_RX_RDY_CTL BIT(7)
-#define UART_MR1_CTS_CTL BIT(6)
-
-#define UART_MR2 0x0004
-#define UART_MR2_ERROR_MODE BIT(6)
-#define UART_MR2_BITS_PER_CHAR 0x30
-#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
-#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
-#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
-#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
-#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
-#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
-#define UART_MR2_PARITY_MODE_NONE 0x0
-#define UART_MR2_PARITY_MODE_ODD 0x1
-#define UART_MR2_PARITY_MODE_EVEN 0x2
-#define UART_MR2_PARITY_MODE_SPACE 0x3
-#define UART_MR2_PARITY_MODE 0x3
-
-#define UART_CSR 0x0008
-
-#define UART_TF 0x000C
-#define UARTDM_TF 0x0070
-
-#define UART_CR 0x0010
-#define UART_CR_CMD_NULL (0 << 4)
-#define UART_CR_CMD_RESET_RX (1 << 4)
-#define UART_CR_CMD_RESET_TX (2 << 4)
-#define UART_CR_CMD_RESET_ERR (3 << 4)
-#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
-#define UART_CR_CMD_START_BREAK (5 << 4)
-#define UART_CR_CMD_STOP_BREAK (6 << 4)
-#define UART_CR_CMD_RESET_CTS (7 << 4)
-#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
-#define UART_CR_CMD_PACKET_MODE (9 << 4)
-#define UART_CR_CMD_MODE_RESET (12 << 4)
-#define UART_CR_CMD_SET_RFR (13 << 4)
-#define UART_CR_CMD_RESET_RFR (14 << 4)
-#define UART_CR_CMD_PROTECTION_EN (16 << 4)
-#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
-#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
-#define UART_CR_CMD_FORCE_STALE (4 << 8)
-#define UART_CR_CMD_RESET_TX_READY (3 << 8)
-#define UART_CR_TX_DISABLE BIT(3)
-#define UART_CR_TX_ENABLE BIT(2)
-#define UART_CR_RX_DISABLE BIT(1)
-#define UART_CR_RX_ENABLE BIT(0)
-#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
-
-#define UART_IMR 0x0014
-#define UART_IMR_TXLEV BIT(0)
-#define UART_IMR_RXSTALE BIT(3)
-#define UART_IMR_RXLEV BIT(4)
-#define UART_IMR_DELTA_CTS BIT(5)
-#define UART_IMR_CURRENT_CTS BIT(6)
-#define UART_IMR_RXBREAK_START BIT(10)
-
-#define UART_IPR_RXSTALE_LAST 0x20
-#define UART_IPR_STALE_LSB 0x1F
-#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
-#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
-
-#define UART_IPR 0x0018
-#define UART_TFWR 0x001C
-#define UART_RFWR 0x0020
-#define UART_HCR 0x0024
-
-#define UART_MREG 0x0028
-#define UART_NREG 0x002C
-#define UART_DREG 0x0030
-#define UART_MNDREG 0x0034
-#define UART_IRDA 0x0038
-#define UART_MISR_MODE 0x0040
-#define UART_MISR_RESET 0x0044
-#define UART_MISR_EXPORT 0x0048
-#define UART_MISR_VAL 0x004C
-#define UART_TEST_CTRL 0x0050
-
-#define UART_SR 0x0008
-#define UART_SR_HUNT_CHAR BIT(7)
-#define UART_SR_RX_BREAK BIT(6)
-#define UART_SR_PAR_FRAME_ERR BIT(5)
-#define UART_SR_OVERRUN BIT(4)
-#define UART_SR_TX_EMPTY BIT(3)
-#define UART_SR_TX_READY BIT(2)
-#define UART_SR_RX_FULL BIT(1)
-#define UART_SR_RX_READY BIT(0)
-
-#define UART_RF 0x000C
-#define UARTDM_RF 0x0070
-#define UART_MISR 0x0010
-#define UART_ISR 0x0014
-#define UART_ISR_TX_READY BIT(7)
-
-#define UARTDM_RXFS 0x50
-#define UARTDM_RXFS_BUF_SHIFT 0x7
-#define UARTDM_RXFS_BUF_MASK 0x7
-
-#define UARTDM_DMEN 0x3C
-#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
-#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
-
-#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
-#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
-
-#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
-#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
-
-#define UARTDM_DMRX 0x34
-#define UARTDM_NCF_TX 0x40
-#define UARTDM_RX_TOTAL_SNAP 0x38
-
-#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
-
-static inline
-void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
-{
- writel_relaxed_no_log(val, port->membase + off);
-}
-
-static inline
-unsigned int msm_read(struct uart_port *port, unsigned int off)
-{
- return readl_relaxed_no_log(port->membase + off);
-}
-
-/*
- * Setup the MND registers to use the TCXO clock.
- */
-static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
-{
- msm_write(port, 0x06, UART_MREG);
- msm_write(port, 0xF1, UART_NREG);
- msm_write(port, 0x0F, UART_DREG);
- msm_write(port, 0x1A, UART_MNDREG);
- port->uartclk = 1843200;
-}
-
-/*
- * Setup the MND registers to use the TCXO clock divided by 4.
- */
-static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
-{
- msm_write(port, 0x18, UART_MREG);
- msm_write(port, 0xF6, UART_NREG);
- msm_write(port, 0x0F, UART_DREG);
- msm_write(port, 0x0A, UART_MNDREG);
- port->uartclk = 1843200;
-}
-
-static inline
-void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
-{
- if (port->uartclk == 19200000)
- msm_serial_set_mnd_regs_tcxo(port);
- else if (port->uartclk == 4800000)
- msm_serial_set_mnd_regs_tcxoby4(port);
-}
-
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
-
-#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d72cd736bdc6..fd9c47f2f29f 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -2451,7 +2451,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
-EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
@@ -2470,9 +2469,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
@@ -2489,8 +2485,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
-EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
-EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
#endif
MODULE_ALIAS("platform:samsung-uart");
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 9dbae01d41ce..9ae182a54784 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -624,8 +624,6 @@ static int __init sprd_early_console_setup(
device->con->write = sprd_early_write;
return 0;
}
-
-EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
sprd_early_console_setup);
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 7bc6b5340dd7..b011efe189e7 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -11,6 +11,7 @@
*/
#include <linux/delay.h>
+#include <linux/hrtimer.h>
#include <linux/ipc_logging.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -158,14 +159,15 @@ static void *usbpd_ipc_log;
/* Timeouts (in ms) */
#define ERROR_RECOVERY_TIME 25
-#define SENDER_RESPONSE_TIME 30
+#define SENDER_RESPONSE_TIME 26
#define SINK_WAIT_CAP_TIME 620
-#define PS_TRANSITION_TIME 550
+#define PS_TRANSITION_TIME 450
#define SRC_CAP_TIME 120
#define SRC_TRANSITION_TIME 25
-#define PS_HARD_RESET_TIME 35
+#define SRC_RECOVER_TIME 660
+#define PS_HARD_RESET_TIME 25
#define PS_SOURCE_ON 400
-#define PS_SOURCE_OFF 900
+#define PS_SOURCE_OFF 750
#define VDM_BUSY_TIME 50
#define PD_CAPS_COUNT 50
@@ -240,9 +242,6 @@ static void *usbpd_ipc_log;
static int min_sink_current = 900;
module_param(min_sink_current, int, S_IRUSR | S_IWUSR);
-static int max_sink_current = 3000;
-module_param(max_sink_current, int, S_IRUSR | S_IWUSR);
-
static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */
static const u32 default_snk_caps[] = { 0x2601905A, /* 5V @ 900mA */
@@ -258,7 +257,8 @@ struct vdm_tx {
struct usbpd {
struct device dev;
struct workqueue_struct *wq;
- struct delayed_work sm_work;
+ struct work_struct sm_work;
+ struct hrtimer timer;
struct extcon_dev *extcon;
@@ -406,8 +406,8 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
static int pd_select_pdo(struct usbpd *pd, int pdo_pos)
{
- int curr = min_sink_current;
- int max_current = max_sink_current;
+ int curr;
+ int max_current;
bool mismatch = false;
u32 pdo = pd->received_pdos[pdo_pos - 1];
@@ -417,18 +417,19 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos)
return -ENOTSUPP;
}
+ curr = max_current = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10;
+
/*
* Check if the PDO has enough current, otherwise set the
* Capability Mismatch flag
*/
- if ((PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10) < curr) {
+ if (curr < min_sink_current) {
mismatch = true;
- max_current = curr;
- curr = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10;
+ max_current = min_sink_current;
}
pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000;
- pd->requested_current = max_current;
+ pd->requested_current = curr;
pd->requested_pdo = pdo_pos;
pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10,
max_current / 10);
@@ -485,7 +486,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
pd->hard_reset = true;
- mod_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
}
static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
@@ -533,7 +534,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
pd->rx_msg_len = PD_MSG_HDR_COUNT(header);
memcpy(&pd->rx_payload, buf, len);
- mod_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
}
static void phy_shutdown(struct usbpd *pd)
@@ -541,6 +542,16 @@ static void phy_shutdown(struct usbpd *pd)
usbpd_dbg(&pd->dev, "shutdown");
}
+static enum hrtimer_restart pd_timeout(struct hrtimer *timer)
+{
+ struct usbpd *pd = container_of(timer, struct usbpd, timer);
+
+ usbpd_dbg(&pd->dev, "timeout");
+ queue_work(pd->wq, &pd->sm_work);
+
+ return HRTIMER_NORESTART;
+}
+
/* Enters new state and executes actions on entry */
static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
{
@@ -564,8 +575,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */
pd->in_pr_swap = false;
set_power_role(pd, PR_NONE);
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(ERROR_RECOVERY_TIME));
+ pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
+ queue_work(pd->wq, &pd->sm_work);
break;
/* Source states */
@@ -611,7 +622,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
/* fall-through */
case PE_SRC_SEND_CAPABILITIES:
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
break;
case PE_SRC_NEGOTIATE_CAPABILITY:
@@ -638,16 +649,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break;
}
- /*
- * we only support VSafe5V so Aceept right away as there is
- * nothing more to prepare from the power supply
- */
- pd->current_state = PE_SRC_TRANSITION_SUPPLY;
- usbpd_dbg(&pd->dev, "Enter %s\n",
- usbpd_state_strings[pd->current_state]);
- /* fall-through */
-
- case PE_SRC_TRANSITION_SUPPLY:
+ /* PE_SRC_TRANSITION_SUPPLY pseudo-state */
ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending Accept\n");
@@ -655,8 +657,23 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break;
}
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SRC_TRANSITION_TIME));
+ /* tSrcTransition required after ACCEPT */
+ usleep_range(SRC_TRANSITION_TIME * USEC_PER_MSEC,
+ (SRC_TRANSITION_TIME + 5) * USEC_PER_MSEC);
+
+ /*
+ * Normally a voltage change should occur within tSrcReady
+ * but since we only support VSafe5V there is nothing more to
+ * prepare from the power supply so send PS_RDY right away.
+ */
+ ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
+ if (ret) {
+ usbpd_err(&pd->dev, "Error sending PS_RDY\n");
+ usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
+ break;
+ }
+
+ usbpd_set_state(pd, PE_SRC_READY);
break;
case PE_SRC_READY:
@@ -685,7 +702,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd_phy_update_roles(pd->current_dr, pd->current_pr);
}
- msleep(1000); /* tSrcRecover */
+ msleep(SRC_RECOVER_TIME);
ret = regulator_enable(pd->vbus);
if (ret)
@@ -705,7 +722,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_HARD_RESET:
case PE_SNK_HARD_RESET:
/* hard reset may sleep; handle it in the workqueue */
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
break;
case PE_SRC_SEND_SOFT_RESET:
@@ -723,8 +740,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
/* wait for ACCEPT */
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
+ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
+ HRTIMER_MODE_REL);
break;
/* Sink states */
@@ -773,8 +790,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (!pd->vbus_present) {
/* can get here during a hard reset and we lost vbus */
pd->current_state = PE_SNK_DISCOVERY;
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(2000));
+ hrtimer_start(&pd->timer, ms_to_ktime(2000),
+ HRTIMER_MODE_REL);
break;
}
@@ -787,10 +804,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_WAIT_FOR_CAPABILITIES:
if (pd->rx_msg_len && pd->rx_msg_type)
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
else
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SINK_WAIT_CAP_TIME));
+ hrtimer_start(&pd->timer,
+ ms_to_ktime(SINK_WAIT_CAP_TIME),
+ HRTIMER_MODE_REL);
break;
case PE_SNK_EVALUATE_CAPABILITY:
@@ -812,14 +830,14 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
usbpd_err(&pd->dev, "Error sending Request\n");
/* wait for ACCEPT */
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
+ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
+ HRTIMER_MODE_REL);
break;
case PE_SNK_TRANSITION_SINK:
/* wait for PS_RDY */
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(PS_TRANSITION_TIME));
+ hrtimer_start(&pd->timer, ms_to_ktime(PS_TRANSITION_TIME),
+ HRTIMER_MODE_REL);
break;
case PE_SNK_READY:
@@ -912,7 +930,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)
/* VDM will get sent in PE_SRC/SNK_READY state handling */
list_add_tail(&vdm_tx->entry, &pd->vdm_tx_queue);
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
return 0;
}
@@ -1094,8 +1112,8 @@ static void handle_vdm_rx(struct usbpd *pd)
/* wait tVDMBusy, then retry */
list_move(&pd->vdm_tx_retry->entry, &pd->vdm_tx_queue);
pd->vdm_tx_retry = NULL;
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(VDM_BUSY_TIME));
+ hrtimer_start(&pd->timer, ms_to_ktime(VDM_BUSY_TIME),
+ HRTIMER_MODE_REL);
break;
default:
break;
@@ -1197,7 +1215,7 @@ static void dr_swap(struct usbpd *pd)
/* Handles current state and determines transitions */
static void usbpd_sm(struct work_struct *w)
{
- struct usbpd *pd = container_of(w, struct usbpd, sm_work.work);
+ struct usbpd *pd = container_of(w, struct usbpd, sm_work);
union power_supply_propval val = {0};
int ret;
enum usbpd_control_msg_type ctrl_recvd = 0;
@@ -1206,6 +1224,8 @@ static void usbpd_sm(struct work_struct *w)
usbpd_dbg(&pd->dev, "handle state %s\n",
usbpd_state_strings[pd->current_state]);
+ hrtimer_cancel(&pd->timer);
+
if (pd->rx_msg_len)
data_recvd = pd->rx_msg_type;
else
@@ -1251,12 +1271,18 @@ static void usbpd_sm(struct work_struct *w)
reset_vdm_state(pd);
+ if (pd->current_state == PE_ERROR_RECOVERY)
+ /* forced disconnect, wait before resetting to DRP */
+ usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
+ (ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
+
/* Set CC back to DRP toggle */
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
pd->current_state = PE_UNKNOWN;
+
return;
}
@@ -1327,8 +1353,8 @@ static void usbpd_sm(struct work_struct *w)
break;
}
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SRC_CAP_TIME));
+ hrtimer_start(&pd->timer, ms_to_ktime(SRC_CAP_TIME),
+ HRTIMER_MODE_REL);
break;
}
@@ -1343,8 +1369,8 @@ static void usbpd_sm(struct work_struct *w)
/* wait for REQUEST */
pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT;
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
+ hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
+ HRTIMER_MODE_REL);
break;
case PE_SRC_SEND_CAPABILITIES_WAIT:
@@ -1356,17 +1382,6 @@ static void usbpd_sm(struct work_struct *w)
}
break;
- case PE_SRC_TRANSITION_SUPPLY:
- ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
- if (ret) {
- usbpd_err(&pd->dev, "Error sending PS_RDY\n");
- usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
- break;
- }
-
- usbpd_set_state(pd, PE_SRC_READY);
- break;
-
case PE_SRC_READY:
if (ctrl_recvd == MSG_GET_SOURCE_CAP) {
ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES,
@@ -1405,7 +1420,7 @@ static void usbpd_sm(struct work_struct *w)
}
pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF;
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
break;
} else {
if (data_recvd == MSG_VDM)
@@ -1420,7 +1435,8 @@ static void usbpd_sm(struct work_struct *w)
pd->in_explicit_contract = false;
reset_vdm_state(pd);
- msleep(PS_HARD_RESET_TIME);
+ usleep_range(PS_HARD_RESET_TIME * USEC_PER_MSEC,
+ (PS_HARD_RESET_TIME + 5) * USEC_PER_MSEC);
usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
break;
@@ -1431,7 +1447,7 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_TYPE, &val);
if (val.intval == POWER_SUPPLY_TYPEC_NONE) {
pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
}
break;
}
@@ -1559,8 +1575,8 @@ static void usbpd_sm(struct work_struct *w)
pd->current_pr = PR_SRC;
pd_phy_update_roles(pd->current_dr, pd->current_pr);
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(PS_SOURCE_OFF));
+ hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF),
+ HRTIMER_MODE_REL);
break;
} else {
if (data_recvd == MSG_VDM)
@@ -1661,8 +1677,8 @@ static void usbpd_sm(struct work_struct *w)
}
pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON;
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(PS_SOURCE_ON));
+ hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_ON),
+ HRTIMER_MODE_REL);
break;
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
@@ -1690,8 +1706,8 @@ static void usbpd_sm(struct work_struct *w)
pd->current_pr = PR_SRC;
pd_phy_update_roles(pd->current_dr, pd->current_pr);
- queue_delayed_work(pd->wq, &pd->sm_work,
- msecs_to_jiffies(PS_SOURCE_OFF));
+ hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF),
+ HRTIMER_MODE_REL);
break;
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
@@ -1821,7 +1837,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
switch (typec_mode) {
/* Disconnect */
case POWER_SUPPLY_TYPEC_NONE:
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
break;
/* Sink states */
@@ -1831,7 +1847,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Source connected\n");
if (pd->current_pr != PR_SINK) {
pd->current_pr = PR_SINK;
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
}
break;
@@ -1841,7 +1857,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Sink connected\n");
if (pd->current_pr != PR_SRC) {
pd->current_pr = PR_SRC;
- queue_delayed_work(pd->wq, &pd->sm_work, 0);
+ queue_work(pd->wq, &pd->sm_work);
}
break;
@@ -2284,7 +2300,9 @@ struct usbpd *usbpd_create(struct device *parent)
ret = -ENOMEM;
goto del_pd;
}
- INIT_DELAYED_WORK(&pd->sm_work, usbpd_sm);
+ INIT_WORK(&pd->sm_work, usbpd_sm);
+ hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pd->timer.function = pd_timeout;
pd->usb_psy = power_supply_get_by_name("usb");
if (!pd->usb_psy) {
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 70bb916d863f..8cf294306efd 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -58,6 +58,12 @@
#define USB_PDPHY_RX_ACKNOWLEDGE 0x4B
#define RX_BUFFER_TOKEN BIT(0)
+#define USB_PDPHY_BIST_MODE 0x4E
+#define BIST_MODE_MASK 0xF
+#define BIST_ENABLE BIT(7)
+#define PD_MSG_BIST 0x3
+#define PD_BIST_TEST_DATA_MODE 0x8
+
#define USB_PDPHY_TX_BUFFER_HDR 0x60
#define USB_PDPHY_TX_BUFFER_DATA 0x62
@@ -95,6 +101,7 @@ struct usb_pdphy {
bool is_opened;
int tx_status;
u8 frame_filter_val;
+ bool in_test_data_mode;
enum data_role data_role;
enum power_role power_role;
@@ -233,7 +240,8 @@ void pdphy_enable_irq(struct usb_pdphy *pdphy, bool enable)
enable_irq(pdphy->sig_tx_irq);
enable_irq(pdphy->sig_rx_irq);
enable_irq(pdphy->msg_tx_irq);
- enable_irq(pdphy->msg_rx_irq);
+ if (!pdphy->in_test_data_mode)
+ enable_irq(pdphy->msg_rx_irq);
enable_irq(pdphy->msg_tx_failed_irq);
enable_irq(pdphy->msg_tx_discarded_irq);
enable_irq(pdphy->msg_rx_discarded_irq);
@@ -243,7 +251,8 @@ void pdphy_enable_irq(struct usb_pdphy *pdphy, bool enable)
disable_irq(pdphy->sig_tx_irq);
disable_irq(pdphy->sig_rx_irq);
disable_irq(pdphy->msg_tx_irq);
- disable_irq(pdphy->msg_rx_irq);
+ if (!pdphy->in_test_data_mode)
+ disable_irq(pdphy->msg_rx_irq);
disable_irq(pdphy->msg_tx_failed_irq);
disable_irq(pdphy->msg_tx_discarded_irq);
disable_irq(pdphy->msg_rx_discarded_irq);
@@ -523,6 +532,9 @@ void pd_phy_close(void)
wake_up_all(&pdphy->tx_waitq);
+ pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);
+ pdphy->in_test_data_mode = false;
+
ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0);
if (ret)
return;
@@ -600,6 +612,9 @@ static irqreturn_t pdphy_sig_tx_irq_thread(int irq, void *data)
{
struct usb_pdphy *pdphy = data;
+ /* in case of exit from BIST Carrier Mode 2, clear BIST_MODE */
+ pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);
+
pdphy->sig_tx_cnt++;
pdphy->tx_status = 0;
wake_up(&pdphy->tx_waitq);
@@ -607,10 +622,24 @@ static irqreturn_t pdphy_sig_tx_irq_thread(int irq, void *data)
return IRQ_HANDLED;
}
+static int pd_phy_bist_mode(u8 bist_mode)
+{
+ struct usb_pdphy *pdphy = __pdphy;
+
+ dev_dbg(pdphy->dev, "%s: enter BIST mode %d\n", __func__, bist_mode);
+
+ pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);
+
+ udelay(5);
+
+ return pdphy_masked_write(pdphy, USB_PDPHY_BIST_MODE,
+ BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
+}
+
static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
{
u8 size, rx_status, frame_type;
- u8 *buf = NULL;
+ u8 buf[32];
int ret;
struct usb_pdphy *pdphy = data;
@@ -620,9 +649,8 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
if (ret)
goto done;
- if (!size) {
- dev_err(pdphy->dev, "%s: incorrect size 1byte\n",
- __func__);
+ if (!size || size > 31) {
+ dev_err(pdphy->dev, "%s: invalid size %d\n", __func__, size);
goto done;
}
@@ -637,25 +665,33 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
goto done;
}
- buf = kmalloc(size + 1, GFP_KERNEL);
- if (!buf)
- goto done;
-
ret = pdphy_reg_read(pdphy, buf, USB_PDPHY_RX_BUFFER, size + 1);
if (ret)
goto done;
- /* ack to change ownership of rx buffer back to PDPHY RX HW */
- pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);
+ if (((buf[0] & 0xf) == PD_MSG_BIST) && size >= 5) { /* BIST */
+ u8 mode = buf[5] >> 4; /* [31:28] of 1st data object */
+
+ pd_phy_bist_mode(mode);
+ pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);
+
+ if (mode == PD_BIST_TEST_DATA_MODE) {
+ pdphy->in_test_data_mode = true;
+ disable_irq_nosync(irq);
+ }
+ goto done;
+ }
if (pdphy->msg_rx_cb)
pdphy->msg_rx_cb(pdphy->usbpd, frame_type, buf, size + 1);
+ /* ack to change ownership of rx buffer back to PDPHY RX HW */
+ pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);
+
print_hex_dump_debug("rx msg:", DUMP_PREFIX_NONE, 32, 4, buf, size + 1,
false);
pdphy->rx_bytes += size + 1;
done:
- kfree(buf);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 794bc2e33695..529e4ea76a96 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -465,6 +465,9 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend)
else
msm_ssusb_qmp_enable_autonomous(phy, 1);
+ /* Make sure above write completed with PHY */
+ wmb();
+
clk_disable_unprepare(phy->cfg_ahb_clk);
clk_disable_unprepare(phy->aux_clk);
clk_disable_unprepare(phy->pipe_clk);
@@ -494,6 +497,10 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend)
} else {
msm_ssusb_qmp_enable_autonomous(phy, 0);
}
+
+ /* Make sure that above write completed with PHY */
+ wmb();
+
phy->in_suspend = false;
dev_dbg(uphy->dev, "QMP PHY is resumed\n");
}
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 61e99f47f02f..4724f4378e23 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -277,6 +277,8 @@ struct mdss_data_type {
struct regulator *fs;
struct regulator *venus;
struct regulator *vdd_cx;
+ u32 vdd_cx_min_uv;
+ u32 vdd_cx_max_uv;
bool batfet_required;
struct regulator *batfet;
bool en_svs_high;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 0ac5ef4f750c..e0dd3f5d5635 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -42,43 +42,6 @@
#define VDDA_UA_ON_LOAD 100000 /* uA units */
#define VDDA_UA_OFF_LOAD 100 /* uA units */
-static char edid_buf1[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
- 0x22, 0xf0, 0x52, 0x29, 0x01, 0x01, 0x01, 0x01,
- 0x16, 0x16, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78,
- 0x2e, 0xee, 0x95, 0xa3, 0x54, 0x4c, 0x99, 0x26,
- 0x0f, 0x50, 0x54, 0xa1, 0x08, 0x00, 0xd1, 0xc0,
- 0x81, 0xc0, 0xa9, 0xc0, 0xb3, 0x00, 0x95, 0x00,
- 0x81, 0x40, 0x81, 0x80, 0x01, 0x01, 0x02, 0x3a,
- 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
- 0x45, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00, 0x1e,
- 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, 0x4c, 0x18,
- 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x48,
- 0x50, 0x20, 0x5a, 0x52, 0x32, 0x32, 0x34, 0x30,
- 0x77, 0x0a, 0x20, 0x20, 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x43, 0x4e, 0x34, 0x32, 0x32, 0x32, 0x30,
- 0x30, 0x33, 0x46, 0x0a, 0x20, 0x20, 0x01, 0xb1,
-
- 0x02, 0x03, 0x17, 0xb1, 0x4c, 0x90, 0x1f, 0x05,
- 0x14, 0x04, 0x13, 0x03, 0x02, 0x07, 0x06, 0x12,
- 0x01, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x02,
- 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58,
- 0x2c, 0x45, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00,
- 0x1e, 0x02, 0x3a, 0x80, 0xd0, 0x72, 0x38, 0x2d,
- 0x40, 0x10, 0x2c, 0x45, 0x80, 0xdb, 0x0b, 0x11,
- 0x00, 0x00, 0x1e, 0x01, 0x1d, 0x00, 0x72, 0x51,
- 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 0xdb,
- 0x0b, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d, 0x00,
- 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28, 0x55,
- 0x40, 0xdb, 0x0b, 0x11, 0x00, 0x00, 0x1e, 0x8c,
- 0x0a, 0xd0, 0x8a, 0x20, 0xe0, 0x2d, 0x10, 0x10,
- 0x3e, 0x96, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b
-};
-
-
static void mdss_dp_put_dt_clk_data(struct device *dev,
struct dss_module_power *module_power)
{
@@ -945,9 +908,6 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
pr_err("Unabled to start core clocks\n");
return ret;
}
- mdss_dp_phy_reset(&dp_drv->ctrl_io);
- mdss_dp_aux_reset(&dp_drv->ctrl_io);
- mdss_dp_aux_ctrl(&dp_drv->ctrl_io, true);
mdss_dp_hpd_configure(&dp_drv->ctrl_io, true);
orientation = usbpd_get_plug_orientation(dp_drv->pd);
@@ -971,11 +931,6 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
if (dp_drv->new_vic && (dp_drv->new_vic != dp_drv->vic))
dp_init_panel_info(dp_drv, dp_drv->new_vic);
- mdss_dp_phy_aux_setup(&dp_drv->phy_io);
-
- mdss_dp_irq_enable(dp_drv);
- pr_debug("irq enabled\n");
- mdss_dp_dpcd_cap_read(dp_drv);
dp_drv->link_rate =
mdss_dp_gen_link_clk(&dp_drv->panel_data.panel_info,
dp_drv->dpcd.max_lane_count);
@@ -1143,9 +1098,10 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
return -ENODEV;
}
- /* Use the existing EDID buffer for 1080p */
- memcpy(edid_init_data.buf, edid_buf1, sizeof(edid_buf1));
dp_drv->panel_data.panel_info.edid_data = edid_data;
+ /* initialize EDID buffer pointers */
+ dp_drv->edid_buf = edid_init_data.buf;
+ dp_drv->edid_buf_size = edid_init_data.buf_size;
return 0;
}
@@ -1189,17 +1145,30 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
mdss_dp_get_ctrl_hw_version(&dp_drv->ctrl_io),
mdss_dp_get_phy_hw_version(&dp_drv->phy_io));
+ mdss_dp_phy_aux_setup(&dp_drv->phy_io);
+
+ mdss_dp_irq_enable(dp_drv);
+ pr_debug("irq enabled\n");
+ mdss_dp_dpcd_cap_read(dp_drv);
+
+ ret = mdss_dp_edid_read(dp_drv);
+ if (ret)
+ goto edid_error;
+
+ pr_debug("edid_read success. buf_size=%d\n",
+ dp_drv->edid_buf_size);
+
ret = hdmi_edid_parser(dp_drv->panel_data.panel_info.edid_data);
if (ret) {
DEV_ERR("%s: edid parse failed\n", __func__);
- goto edid_parser_error;
+ goto edid_error;
}
mdss_dp_send_cable_notification(dp_drv, true);
return ret;
-edid_parser_error:
+edid_error:
mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
clk_error:
mdss_dp_regulator_ctrl(dp_drv, false);
@@ -1422,7 +1391,7 @@ static void mdss_dp_event_work(struct work_struct *work)
switch (todo) {
case EV_EDID_READ:
- mdss_dp_edid_read(dp, 0);
+ mdss_dp_edid_read(dp);
break;
case EV_DPCD_CAP_READ:
mdss_dp_dpcd_cap_read(dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 03646cd7cc65..4a80c25dd157 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -106,15 +106,6 @@
#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2)
-struct edp_cmd {
- char read; /* 1 == read, 0 == write */
- char i2c; /* 1 == i2c cmd, 0 == native cmd */
- u32 addr; /* 20 bits */
- char *datap;
- int len; /* len to be tx OR len to be rx for read */
- char next; /* next command */
-};
-
struct edp_buf {
char *start; /* buffer start addr */
char *end; /* buffer end addr */
@@ -378,6 +369,8 @@ struct mdss_dp_drv_pdata {
char train_link_rate; /* X 27000000 for real rate */
char train_lane_cnt;
+ u8 *edid_buf;
+ u32 edid_buf_size;
struct edp_edid edid;
struct dpcd_cap dpcd;
@@ -464,7 +457,7 @@ void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp);
void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *dp);
-void mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp, int block);
+int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp);
int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp);
void dp_aux_i2c_handler(struct mdss_dp_drv_pdata *dp, u32 isr);
void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr);
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 7b14a7efb9dc..7e9510cf08c7 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -228,6 +228,11 @@ static int dp_aux_write_cmds(struct mdss_dp_drv_pdata *ep,
return ret;
}
+int dp_aux_write(void *ep, struct edp_cmd *cmd)
+{
+ return dp_aux_write_cmds(ep, cmd);
+}
+
static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep,
struct edp_cmd *cmds)
{
@@ -275,12 +280,20 @@ static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep,
else
ret = ep->aux_error_num;
+ if (cmds->out_buf)
+ memcpy(cmds->out_buf, rp->data, cmds->len);
+
ep->aux_cmd_busy = 0;
mutex_unlock(&ep->aux_mutex);
return ret;
}
+int dp_aux_read(void *ep, struct edp_cmd *cmds)
+{
+ return dp_aux_read_cmds(ep, cmds);
+}
+
void dp_aux_native_handler(struct mdss_dp_drv_pdata *ep, u32 isr)
{
@@ -665,7 +678,7 @@ static int dp_aux_chan_ready(struct mdss_dp_drv_pdata *ep)
char data = 0;
for (cnt = 5; cnt; cnt--) {
- ret = dp_aux_write_buf(ep, 0x50, &data, 1, 1);
+ ret = dp_aux_write_buf(ep, EDID_START_ADDRESS, &data, 1, 1);
pr_debug("ret=%d\n", ret);
if (ret >= 0)
break;
@@ -680,43 +693,85 @@ static int dp_aux_chan_ready(struct mdss_dp_drv_pdata *ep)
return 0;
}
-static int dp_sink_edid_read(struct mdss_dp_drv_pdata *ep, int block)
+int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
{
struct edp_buf *rp;
int cnt, rlen;
int ret = 0;
+ int blk_num = 0;
- ret = dp_aux_chan_ready(ep);
+ ret = dp_aux_chan_ready(dp);
if (ret) {
pr_err("aux chan NOT ready\n");
return ret;
}
for (cnt = 5; cnt; cnt--) {
- rlen = dp_aux_read_buf(ep, 0x50, 128, 1);
+ rlen = dp_aux_read_buf
+ (dp, EDID_START_ADDRESS, EDID_BLOCK_SIZE, 1);
if (rlen > 0) {
- pr_debug("rlen=%d\n", rlen);
+ pr_debug("cnt=%d, block=%d, rlen=%d\n",
+ cnt, blk_num, rlen);
- rp = &ep->rxp;
+ rp = &dp->rxp;
if (!dp_edid_buf_error(rp->data, rp->len))
break;
}
}
- if (cnt <= 0) {
- pr_err("Failed\n");
+ if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) {
+ pr_err("Read failed. rlen=%d\n", rlen);
return -EINVAL;
}
- dp_extract_edid_manufacturer(&ep->edid, rp->data);
- dp_extract_edid_product(&ep->edid, rp->data);
- dp_extract_edid_version(&ep->edid, rp->data);
- dp_extract_edid_ext_block_cnt(&ep->edid, rp->data);
- dp_extract_edid_video_support(&ep->edid, rp->data);
- dp_extract_edid_feature(&ep->edid, rp->data);
- dp_extract_edid_detailed_timing_description(&ep->edid, rp->data);
+ rp = &dp->rxp;
+
+ dp_extract_edid_manufacturer(&dp->edid, rp->data);
+ dp_extract_edid_product(&dp->edid, rp->data);
+ dp_extract_edid_version(&dp->edid, rp->data);
+ dp_extract_edid_ext_block_cnt(&dp->edid, rp->data);
+ dp_extract_edid_video_support(&dp->edid, rp->data);
+ dp_extract_edid_feature(&dp->edid, rp->data);
+ dp_extract_edid_detailed_timing_description(&dp->edid, rp->data);
+ /* for the first block initialize the edid buffer size */
+ dp->edid_buf_size = 0;
+
+ pr_debug("edid extension = %d\n",
+ dp->edid.ext_block_cnt);
+
+ memcpy(dp->edid_buf, rp->data, EDID_BLOCK_SIZE);
+ dp->edid_buf_size += EDID_BLOCK_SIZE;
- return 128;
+ if (!dp->edid.ext_block_cnt)
+ return 0;
+
+ for (blk_num = 1; blk_num <= dp->edid.ext_block_cnt;
+ blk_num++) {
+ for (cnt = 5; cnt; cnt--) {
+ rlen = dp_aux_read_buf
+ (dp, EDID_START_ADDRESS +
+ (blk_num * EDID_BLOCK_SIZE),
+ EDID_BLOCK_SIZE, 1);
+ if (rlen > 0) {
+ pr_debug("cnt=%d, blk_num=%d, rlen=%d\n",
+ cnt, blk_num, rlen);
+ rp = &dp->rxp;
+ if (!dp_edid_buf_error(rp->data, rp->len))
+ break;
+ }
+ }
+
+ if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) {
+ pr_err("Read failed. rlen=%d\n", rlen);
+ return -EINVAL;
+ }
+
+ memcpy(dp->edid_buf + (blk_num * EDID_BLOCK_SIZE),
+ rp->data, EDID_BLOCK_SIZE);
+ dp->edid_buf_size += EDID_BLOCK_SIZE;
+ }
+
+ return 0;
}
static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
@@ -1357,11 +1412,6 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep)
}
-void mdss_dp_edid_read(struct mdss_dp_drv_pdata *ep, int block)
-{
- dp_sink_edid_read(ep, block);
-}
-
int mdss_dp_link_train(struct mdss_dp_drv_pdata *ep)
{
int ret;
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h
index 8ef00dd7248e..a2649b8c1611 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.h
+++ b/drivers/video/fbdev/msm/mdss_dp_util.h
@@ -86,6 +86,33 @@
#define TXn_TX_DRV_LVL 0x001C
#define TCSR_USB3_DP_PHYMODE 0x48
+#define EDID_START_ADDRESS 0x50
+
+/* DP HDCP 1.3 registers */
+#define DP_HDCP_CTRL (0x0A0)
+#define DP_HDCP_STATUS (0x0A4)
+#define DP_HDCP_SW_UPPER_AKSV (0x298)
+#define DP_HDCP_SW_LOWER_AKSV (0x29C)
+#define DP_HDCP_ENTROPY_CTRL0 (0x750)
+#define DP_HDCP_ENTROPY_CTRL1 (0x75C)
+#define DP_HDCP_SHA_STATUS (0x0C8)
+#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
+#define DP_HDCP_RCVPORT_DATA3 (0x2A4)
+#define DP_HDCP_RCVPORT_DATA4 (0x2A8)
+#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
+#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
+
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+
+#define DP_INTERRUPT_STATUS_2 (0x024)
struct lane_mapping {
char lane0;
@@ -94,6 +121,18 @@ struct lane_mapping {
char lane3;
};
+struct edp_cmd {
+ char read; /* 1 == read, 0 == write */
+ char i2c; /* 1 == i2c cmd, 0 == native cmd */
+ u32 addr; /* 20 bits */
+ char *datap;
+ char *out_buf;
+ int len; /* len to be tx OR len to be rx for read */
+ char next; /* next command */
+};
+
+int dp_aux_read(void *ep, struct edp_cmd *cmds);
+int dp_aux_write(void *ep, struct edp_cmd *cmd);
void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data);
u32 mdss_dp_get_ctrl_hw_version(struct dss_io_data *ctrl_io);
u32 mdss_dp_get_phy_hw_version(struct dss_io_data *phy_io);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
index 6256c9a99877..dad089e74934 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
@@ -15,9 +15,11 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/iopoll.h>
#include <soc/qcom/scm.h>
#include <linux/hdcp_qseecom.h>
#include "mdss_hdmi_hdcp.h"
+#include "mdss_dp_util.h"
#include "video/msm_hdmi_hdcp_mgr.h"
#define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state))
@@ -36,15 +38,188 @@
#define HDCP_REG_ENABLE 0x01
#define HDCP_REG_DISABLE 0x00
-#define HDCP_INT_CLR (BIT(1) | BIT(5) | BIT(7) | BIT(9) | BIT(13))
+#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \
+ isr->auth_fail_info_ack | isr->tx_req_ack | \
+ isr->encryption_ready_ack | \
+ isr->encryption_not_ready | isr->tx_req_done_ack)
+
+#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \
+ isr->encryption_ready_mask | \
+ isr->encryption_not_ready_mask)
+
+#define HDCP_POLL_SLEEP_US (20 * 1000)
+#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 1000)
+
+#define reg_set_data(x) \
+ (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \
+ reg_set->data##x)
+
+struct hdcp_sink_addr {
+ char *name;
+ u32 addr;
+ u32 len;
+};
struct hdmi_hdcp_reg_data {
u32 reg_id;
- u32 off;
- char *name;
- u32 reg_val;
+ struct hdcp_sink_addr *sink;
+};
+
+struct hdcp_sink_addr_map {
+ /* addresses to read from sink */
+ struct hdcp_sink_addr bcaps;
+ struct hdcp_sink_addr bksv;
+ struct hdcp_sink_addr r0;
+ struct hdcp_sink_addr bstatus;
+ struct hdcp_sink_addr ksv_fifo;
+ struct hdcp_sink_addr v_h0;
+ struct hdcp_sink_addr v_h1;
+ struct hdcp_sink_addr v_h2;
+ struct hdcp_sink_addr v_h3;
+ struct hdcp_sink_addr v_h4;
+
+ /* addresses to write to sink */
+ struct hdcp_sink_addr an;
+ struct hdcp_sink_addr aksv;
+ struct hdcp_sink_addr rep;
+};
+
+struct hdcp_int_set {
+ /* interrupt register */
+ u32 int_reg;
+
+ /* interrupt enable/disable masks */
+ u32 auth_success_mask;
+ u32 auth_fail_mask;
+ u32 encryption_ready_mask;
+ u32 encryption_not_ready_mask;
+ u32 tx_req_mask;
+ u32 tx_req_done_mask;
+
+ /* interrupt acknowledgment */
+ u32 auth_success_ack;
+ u32 auth_fail_ack;
+ u32 auth_fail_info_ack;
+ u32 encryption_ready_ack;
+ u32 encryption_not_ready_ack;
+ u32 tx_req_ack;
+ u32 tx_req_done_ack;
+
+ /* interrupt status */
+ u32 auth_success_int;
+ u32 auth_fail_int;
+ u32 encryption_ready;
+ u32 encryption_not_ready;
+ u32 tx_req_int;
+ u32 tx_req_done_int;
+};
+
+struct hdcp_reg_set {
+ u32 status;
+ u32 keys_offset;
+ u32 r0_offset;
+ u32 v_offset;
+ u32 ctrl;
+ u32 aksv_lsb;
+ u32 aksv_msb;
+ u32 entropy_ctrl0;
+ u32 entropy_ctrl1;
+ u32 sha_ctrl;
+ u32 sec_sha_ctrl;
+ u32 sha_status;
+
+ u32 data0;
+ u32 data1;
+ u32 data2_0;
+ u32 data3;
+ u32 data4;
+ u32 data5;
+ u32 data6;
+ u32 data7;
+ u32 data8;
+ u32 data9;
+ u32 data10;
+ u32 data11;
+ u32 data12;
+
+ u32 sec_data0;
+ u32 sec_data1;
+ u32 sec_data7;
+ u32 sec_data8;
+ u32 sec_data9;
+ u32 sec_data10;
+ u32 sec_data11;
+ u32 sec_data12;
+
+ u32 reset;
};
+#define HDCP_REG_SET_CLIENT_HDMI \
+ {HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \
+ HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \
+ HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \
+ HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \
+ HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \
+ HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \
+ HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \
+ HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \
+ HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \
+ HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
+ HDMI_HDCP_RESET}
+
+#define HDCP_REG_SET_CLIENT_DP \
+ {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
+ DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
+ DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
+ 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \
+ DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
+ DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
+ 0, 0, 0, 0, 0, 0, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, 0}
+
+#define HDCP_HDMI_SINK_ADDR_MAP \
+ {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
+ {"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \
+ {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \
+ {"v_h4", 0x30, 4}, {"an", 0x16, 8}, {"aksv", 0x10, 5}, \
+ {"repater", 0x00, 0} }
+
+#define HDCP_DP_SINK_ADDR_MAP \
+ {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
+ {"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \
+ {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \
+ {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \
+ {"aksv", 0x68007, 5}, {"repater", 0x68028, 1} }
+
+#define HDCP_HDMI_INT_SET \
+ {HDMI_HDCP_INT_CTRL, \
+ BIT(2), BIT(6), 0, 0, 0, 0, \
+ BIT(1), BIT(5), BIT(7), 0, 0, 0, 0, \
+ BIT(0), BIT(4), 0, 0, 0, 0}
+
+#define HDCP_DP_INT_SET \
+ {DP_INTERRUPT_STATUS_2, \
+ BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \
+ BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \
+ BIT(15), BIT(18), BIT(22), BIT(25), 0, 0}
+
struct hdmi_hdcp_ctrl {
u32 auth_retries;
u32 tp_msgid;
@@ -57,7 +232,9 @@ struct hdmi_hdcp_ctrl {
struct completion r0_checked;
struct hdmi_hdcp_init_data init_data;
struct hdmi_hdcp_ops *ops;
- bool hdmi_tx_ver_4;
+ struct hdcp_reg_set reg_set;
+ struct hdcp_int_set int_set;
+ struct hdcp_sink_addr_map sink_addr;
};
const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state)
@@ -256,6 +433,7 @@ static int hdmi_hdcp_load_keys(void *input)
struct dss_io_data *io;
struct dss_io_data *qfprom_io;
struct hdmi_hdcp_ctrl *hdcp_ctrl = input;
+ struct hdcp_reg_set *reg_set;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
!hdcp_ctrl->init_data.qfprom_io) {
@@ -274,6 +452,7 @@ static int hdmi_hdcp_load_keys(void *input)
io = hdcp_ctrl->init_data.core_io;
qfprom_io = hdcp_ctrl->init_data.qfprom_io;
+ reg_set = &hdcp_ctrl->reg_set;
/* On compatible hardware, use SW keys */
reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION);
@@ -297,7 +476,7 @@ static int hdmi_hdcp_load_keys(void *input)
ksv_lsb_addr = HDCP_KSV_LSB;
ksv_msb_addr = HDCP_KSV_MSB;
- if (hdcp_ctrl->hdmi_tx_ver_4) {
+ if (hdcp_ctrl->init_data.sec_access) {
ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
}
@@ -322,27 +501,121 @@ static int hdmi_hdcp_load_keys(void *input)
goto end;
}
- DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, aksv_lsb);
- DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, aksv_msb);
+ DSS_REG_W(io, reg_set->aksv_lsb, aksv_lsb);
+ DSS_REG_W(io, reg_set->aksv_msb, aksv_msb);
/* Setup seed values for random number An */
- DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
- DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
-
- /* Disable the RngCipher state */
- DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL,
- DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2)));
+ DSS_REG_W(io, reg_set->entropy_ctrl0, 0xB1FFB0FF);
+ DSS_REG_W(io, reg_set->entropy_ctrl1, 0xF00DFACE);
/* make sure hw is programmed */
wmb();
- DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0));
+ /* enable hdcp engine */
+ DSS_REG_W(io, reg_set->ctrl, 0x1);
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
end:
return rc;
}
+static int hdmi_hdcp_read(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+ struct hdcp_sink_addr *sink,
+ u8 *buf, bool realign)
+{
+ u32 rc = 0;
+ struct hdmi_tx_ddc_data ddc_data;
+
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ reset_hdcp_ddc_failures(hdcp_ctrl);
+
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = sink->addr;
+ ddc_data.data_buf = buf;
+ ddc_data.data_len = sink->len;
+ ddc_data.request_len = sink->len;
+ ddc_data.retry = 5;
+ ddc_data.what = sink->name;
+ ddc_data.retry_align = realign;
+
+ hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
+
+ rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
+ if (rc)
+ DEV_ERR("%s: %s: %s read failed\n", __func__,
+ HDCP_STATE_NAME, sink->name);
+ } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
+ hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ struct edp_cmd cmd = {0};
+
+ cmd.read = 1;
+ cmd.addr = sink->addr;
+ cmd.out_buf = buf;
+ cmd.len = sink->len;
+
+ rc = dp_aux_read(hdcp_ctrl->init_data.dp_data, &cmd);
+ if (rc)
+ DEV_ERR("%s: %s: %s read failed\n", __func__,
+ HDCP_STATE_NAME, sink->name);
+ }
+
+ return rc;
+}
+
+static int hdmi_hdcp_write(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+ u32 offset, u32 len, u8 *buf, char *name)
+{
+ int rc = 0;
+ struct hdmi_tx_ddc_data ddc_data;
+
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ memset(&ddc_data, 0, sizeof(ddc_data));
+
+ ddc_data.dev_addr = 0x74;
+ ddc_data.offset = offset;
+ ddc_data.data_buf = buf;
+ ddc_data.data_len = len;
+ ddc_data.what = name;
+ hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
+
+ rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl);
+ if (rc)
+ DEV_ERR("%s: %s: %s write failed\n", __func__,
+ HDCP_STATE_NAME, name);
+ } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
+ hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ struct edp_cmd cmd = {0};
+
+ cmd.addr = offset;
+ cmd.len = len;
+ cmd.datap = buf;
+
+ rc = dp_aux_write(hdcp_ctrl->init_data.dp_data, &cmd);
+ if (rc)
+ DEV_ERR("%s: %s: %s read failed\n", __func__,
+ HDCP_STATE_NAME, name);
+ }
+
+ return rc;
+}
+
+static void hdmi_hdcp_enable_interrupts(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ u32 intr_reg;
+ struct dss_io_data *io;
+ struct hdcp_int_set *isr;
+
+ io = hdcp_ctrl->init_data.core_io;
+ isr = &hdcp_ctrl->int_set;
+
+ intr_reg = DSS_REG_R(io, isr->int_reg);
+
+ intr_reg |= HDCP_INT_CLR | HDCP_INT_EN;
+
+ DSS_REG_W(io, isr->int_reg, intr_reg);
+}
+
static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
int rc;
@@ -353,13 +626,12 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
bool is_match;
struct dss_io_data *io;
struct dss_io_data *hdcp_io;
+ struct hdcp_reg_set *reg_set;
u8 aksv[5], *bksv = NULL;
u8 an[8];
u8 bcaps;
- struct hdmi_tx_ddc_data ddc_data;
- u32 link0_status, an_ready, keys_state;
+ u32 link0_status;
u8 buf[0xFF];
-
struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
u32 ret = 0;
@@ -376,6 +648,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
bksv = hdcp_ctrl->current_tp.bksv;
io = hdcp_ctrl->init_data.core_io;
hdcp_io = hdcp_ctrl->init_data.hdcp_io;
+ reg_set = &hdcp_ctrl->reg_set;
if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
DEV_ERR("%s: %s: invalid state. returning\n", __func__,
@@ -384,32 +657,14 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
goto error;
}
- /* Clear any DDC failures from previous tries */
- reset_hdcp_ddc_failures(hdcp_ctrl);
-
- /*
- * Read BCAPS
- * We need to first try to read an HDCP register on the sink to see if
- * the sink is ready for HDCP authentication
- */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x40;
- ddc_data.data_buf = &bcaps;
- ddc_data.data_len = 1;
- ddc_data.request_len = 1;
- ddc_data.retry = 5;
- ddc_data.what = "Bcaps";
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
- HDCP_STATE_NAME);
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
+ &bcaps, false);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading bcaps\n", __func__);
goto error;
}
- DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps);
+
+ hdmi_hdcp_enable_interrupts(hdcp_ctrl);
/* receiver (0), repeater (1) */
hdcp_ctrl->current_tp.ds_type =
@@ -419,7 +674,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
if (hdcp_ctrl->tz_hdcp) {
memset(scm_buf, 0x00, sizeof(scm_buf));
- scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12;
+ scm_buf[0].addr = phy_addr + reg_set->data12;
scm_buf[0].val = bcaps;
ret = hdcp_scm_call(scm_buf, &resp);
@@ -429,30 +684,19 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
- DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
- bcaps);
+ } else if (hdcp_ctrl->init_data.sec_access) {
+ DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps);
} else {
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps);
+ DSS_REG_W(io, reg_set->data12, bcaps);
}
/* Wait for HDCP keys to be checked and validated */
- timeout_count = 100;
- keys_state = (link0_status >> 28) & 0x7;
- while ((keys_state != HDCP_KEYS_STATE_VALID) &&
- --timeout_count) {
- link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
- keys_state = (link0_status >> 28) & 0x7;
- DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
- __func__, HDCP_STATE_NAME, timeout_count,
- keys_state, link0_status);
- msleep(20);
- }
-
- if (!timeout_count) {
- DEV_ERR("%s: %s: Invalid Keys State: %d\n", __func__,
- HDCP_STATE_NAME, keys_state);
- rc = -EINVAL;
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ ((link0_status >> reg_set->keys_offset) & 0x7)
+ == HDCP_KEYS_STATE_VALID,
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: key not ready\n", __func__);
goto error;
}
@@ -460,39 +704,39 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
* 1.1_Features turned off by default.
* No need to write AInfo since 1.1_Features is disabled.
*/
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA4, 0);
+ DSS_REG_W(io, reg_set->data4, 0);
/* Wait for An0 and An1 bit to be ready */
- timeout_count = 100;
- do {
- link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
- an_ready = (link0_status & BIT(8)) && (link0_status & BIT(9));
- if (!an_ready) {
- DEV_DBG("%s: %s: An not ready(%d). l0_status=0x%08x\n",
- __func__, HDCP_STATE_NAME, timeout_count,
- link0_status);
- msleep(20);
- }
- } while (!an_ready && --timeout_count);
-
- if (!timeout_count) {
- rc = -ETIMEDOUT;
- DEV_ERR("%s: %s: timedout, An0=%ld, An1=%ld\n", __func__,
- HDCP_STATE_NAME, (link0_status & BIT(8)) >> 8,
- (link0_status & BIT(9)) >> 9);
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ (link0_status & (BIT(8) | BIT(9))),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: An not ready\n", __func__);
goto error;
}
/* As per hardware recommendations, wait before reading An */
msleep(20);
- /* Read An0 and An1 */
- link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5);
- link0_an_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA6);
+ /*
+ * As per hardware recommendation, for DP, read AN0 and AN1 again
+ * with a delay of 1 micro second each.
+ */
+ link0_an_0 = DSS_REG_R(io, reg_set->data5);
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ link0_an_0 = DSS_REG_R(io, reg_set->data5);
+ }
+
+ link0_an_1 = DSS_REG_R(io, reg_set->data6);
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ udelay(1);
+ link0_an_0 = DSS_REG_R(io, reg_set->data6);
+ }
/* Read AKSV */
- link0_aksv_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA3);
- link0_aksv_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA4);
+ link0_aksv_0 = DSS_REG_R(io, reg_set->data3);
+ link0_aksv_1 = DSS_REG_R(io, reg_set->data4);
/* Copy An and AKSV to byte arrays for transmission */
aksv[0] = link0_aksv_0 & 0xFF;
@@ -510,55 +754,21 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
an[6] = (link0_an_1 >> 16) & 0xFF;
an[7] = (link0_an_1 >> 24) & 0xFF;
- /* Write An to offset 0x18 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x18;
- ddc_data.data_buf = an;
- ddc_data.data_len = 8;
- ddc_data.what = "An";
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: An write failed\n", __func__, HDCP_STATE_NAME);
+ rc = hdmi_hdcp_write(hdcp_ctrl, 0x18, 8, an, "an");
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error writing an to sink\n", __func__);
goto error;
}
- /* Write AKSV to offset 0x10 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x10;
- ddc_data.data_buf = aksv;
- ddc_data.data_len = 5;
- ddc_data.what = "Aksv";
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: AKSV write failed\n", __func__,
- HDCP_STATE_NAME);
+ rc = hdmi_hdcp_write(hdcp_ctrl, 0x10, 5, aksv, "aksv");
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error writing aksv to sink\n", __func__);
goto error;
}
- DEV_DBG("%s: %s: Link0-AKSV=%02x%08x\n", __func__,
- HDCP_STATE_NAME, link0_aksv_1 & 0xFF, link0_aksv_0);
-
- /* Read BKSV at offset 0x00 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x00;
- ddc_data.data_buf = bksv;
- ddc_data.data_len = 5;
- ddc_data.request_len = 5;
- ddc_data.retry = 5;
- ddc_data.what = "Bksv";
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: BKSV read failed\n", __func__,
- HDCP_STATE_NAME);
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading bksv from sink\n", __func__);
goto error;
}
@@ -584,9 +794,9 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
if (hdcp_ctrl->tz_hdcp) {
memset(scm_buf, 0x00, sizeof(scm_buf));
- scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA0;
+ scm_buf[0].addr = phy_addr + reg_set->data0;
scm_buf[0].val = link0_bksv_0;
- scm_buf[1].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA1;
+ scm_buf[1].addr = phy_addr + reg_set->data1;
scm_buf[1].val = link0_bksv_1;
ret = hdcp_scm_call(scm_buf, &resp);
@@ -597,52 +807,45 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
- DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0,
- link0_bksv_0);
- DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1,
- link0_bksv_1);
+ } else if (hdcp_ctrl->init_data.sec_access) {
+ DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
+ DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
} else {
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA0, link0_bksv_0);
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA1, link0_bksv_1);
+ DSS_REG_W(io, reg_set->data0, link0_bksv_0);
+ DSS_REG_W(io, reg_set->data1, link0_bksv_1);
}
- /* Enable HDCP interrupts and ack/clear any stale interrupts */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0xE6);
-
/*
* HDCP Compliace Test case 1A-01:
* Wait here at least 100ms before reading R0'
*/
msleep(125);
- /* Read R0' at offset 0x08 */
+ /* Wait for HDCP R0 computation to be completed */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ link0_status & BIT(reg_set->r0_offset),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: R0 not ready\n", __func__);
+ goto error;
+ }
+
memset(buf, 0, sizeof(buf));
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x08;
- ddc_data.data_buf = buf;
- ddc_data.data_len = 2;
- ddc_data.request_len = 2;
- ddc_data.retry = 5;
- ddc_data.what = "R0'";
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: R0' read failed\n", __func__, HDCP_STATE_NAME);
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading R0' from sink\n", __func__);
goto error;
}
+
DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME,
buf[1], buf[0]);
/* Write R0' to HDCP registers and check to see if it is a match */
reinit_completion(&hdcp_ctrl->r0_checked);
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA2_0, (((u32)buf[1]) << 8) | buf[0]);
+ DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
timeout_count = wait_for_completion_timeout(
&hdcp_ctrl->r0_checked, HZ*2);
- link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
+ link0_status = DSS_REG_R(io, reg_set->status);
is_match = link0_status & BIT(12);
if (!is_match) {
DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__,
@@ -663,166 +866,108 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
}
error:
- if (rc) {
+ if (rc)
DEV_ERR("%s: %s: Authentication Part I failed\n", __func__,
hdcp_ctrl ? HDCP_STATE_NAME : "???");
- } else {
- /* Enable HDCP Encryption */
- DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0) | BIT(8));
+ else
DEV_INFO("%s: %s: Authentication Part I successful\n",
__func__, HDCP_STATE_NAME);
- }
return rc;
} /* hdmi_hdcp_authentication_part1 */
-#define READ_WRITE_V_H(io, off, name, reg, wr) \
-do { \
- ddc_data.offset = (off); \
- memset(what, 0, sizeof(what)); \
- snprintf(what, sizeof(what), (name)); \
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; \
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); \
- if (rc) { \
- DEV_ERR("%s: %s: Read %s failed\n", __func__, HDCP_STATE_NAME, \
- what); \
- goto error; \
- } \
- DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", \
- __func__, HDCP_STATE_NAME, what, buf[0], buf[1], \
- buf[2], buf[3]); \
- if (wr) { \
- DSS_REG_W((io), (reg), \
- (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); \
- } \
-} while (0);
+static int hdmi_hdcp_set_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+ struct hdmi_hdcp_reg_data *rd, u8 *buf)
+{
+ int rc;
+ struct dss_io_data *io;
+
+ if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access)
+ io = hdcp_ctrl->init_data.hdcp_io;
+ else
+ io = hdcp_ctrl->init_data.core_io;
+
+ rc = hdmi_hdcp_read(hdcp_ctrl, rd->sink, buf, false);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name);
+ goto end;
+ }
+
+ DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n",
+ __func__, HDCP_STATE_NAME, rd->sink->name, buf[0], buf[1],
+ buf[2], buf[3]);
+
+ if (!hdcp_ctrl->tz_hdcp)
+ DSS_REG_W(io, rd->reg_id,
+ (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]));
+end:
+ return rc;
+}
static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
- char what[20];
int rc = 0;
u8 buf[4];
- struct hdmi_tx_ddc_data ddc_data;
- struct dss_io_data *io;
-
struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
-
+ struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set;
struct hdmi_hdcp_reg_data reg_data[] = {
- {HDMI_HDCP_RCVPORT_DATA7, 0x20, "V' H0"},
- {HDMI_HDCP_RCVPORT_DATA8, 0x24, "V' H1"},
- {HDMI_HDCP_RCVPORT_DATA9, 0x28, "V' H2"},
- {HDMI_HDCP_RCVPORT_DATA10, 0x2C, "V' H3"},
- {HDMI_HDCP_RCVPORT_DATA11, 0x30, "V' H4"},
+ {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0},
+ {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1},
+ {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2},
+ {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3},
+ {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4},
};
- u32 size = sizeof(reg_data)/sizeof(reg_data[0]);
- u32 iter = 0;
- u32 ret = 0;
- u32 resp = 0;
-
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
+ u32 size = ARRAY_SIZE(reg_data);
+ u32 iter = 0, ret = 0, resp = 0;
phy_addr = hdcp_ctrl->init_data.phy_addr;
- io = hdcp_ctrl->init_data.core_io;
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.data_buf = buf;
- ddc_data.data_len = 4;
- ddc_data.request_len = 4;
- ddc_data.retry = 5;
- ddc_data.what = what;
-
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
+ memset(scm_buf, 0x00, sizeof(scm_buf));
- for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) {
- struct hdmi_hdcp_reg_data *rd = reg_data + iter;
+ for (iter = 0; iter < size; iter++) {
+ struct hdmi_hdcp_reg_data *rd = reg_data + iter;
- READ_WRITE_V_H(io, rd->off, rd->name, 0, false);
+ memset(buf, 0, sizeof(buf));
+ hdmi_hdcp_set_v_h(hdcp_ctrl, rd, buf);
- rd->reg_val = buf[3] << 24 | buf[2] << 16 |
+ if (hdcp_ctrl->tz_hdcp) {
+ u32 reg_val = buf[3] << 24 | buf[2] << 16 |
buf[1] << 8 | buf[0];
scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id;
- scm_buf[iter].val = reg_data[iter].reg_val;
- }
+ scm_buf[iter].val = reg_val;
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
+ ret = hdcp_scm_call(scm_buf, &resp);
+ if (ret || resp) {
+ DEV_ERR("%s: scm err: ret=%d, resp=%d\n",
+ __func__, ret, resp);
+ rc = -EINVAL;
+ goto error;
+ }
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
- struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;
-
- /* Read V'.HO 4 Byte at offset 0x20 */
- READ_WRITE_V_H(hdcp_io, 0x20, "V' H0",
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true);
-
- /* Read V'.H1 4 Byte at offset 0x24 */
- READ_WRITE_V_H(hdcp_io, 0x24, "V' H1",
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true);
-
- /* Read V'.H2 4 Byte at offset 0x28 */
- READ_WRITE_V_H(hdcp_io, 0x28, "V' H2",
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true);
-
- /* Read V'.H3 4 Byte at offset 0x2C */
- READ_WRITE_V_H(hdcp_io, 0x2C, "V' H3",
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true);
-
- /* Read V'.H4 4 Byte at offset 0x30 */
- READ_WRITE_V_H(hdcp_io, 0x30, "V' H4",
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true);
- } else {
- /* Read V'.HO 4 Byte at offset 0x20 */
- READ_WRITE_V_H(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7,
- true);
-
- /* Read V'.H1 4 Byte at offset 0x24 */
- READ_WRITE_V_H(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8,
- true);
-
- /* Read V'.H2 4 Byte at offset 0x28 */
- READ_WRITE_V_H(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9,
- true);
-
- /* Read V'.H3 4 Byte at offset 0x2C */
- READ_WRITE_V_H(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10,
- true);
-
- /* Read V'.H4 4 Byte at offset 0x30 */
- READ_WRITE_V_H(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11,
- true);
}
-
error:
return rc;
}
static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
- int rc, cnt, i;
- struct hdmi_tx_ddc_data ddc_data;
+ int rc, i;
u32 timeout_count, down_stream_devices = 0;
u32 repeater_cascade_depth = 0;
u8 buf[0xFF];
u8 *ksv_fifo = NULL;
- u8 bcaps;
- u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0;
- u32 link0_status;
+ u8 bcaps = 0;
+ u16 bstatus = 0, max_devs_exceeded = 0, max_cascade_exceeded = 0;
+ u32 status = 0, sha_status = 0;
u32 ksv_bytes;
struct dss_io_data *io;
-
+ struct hdcp_reg_set *reg_set;
struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
u32 ret = 0;
u32 resp = 0;
+ u32 ksv_read_retry = 20;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -831,6 +976,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
}
phy_addr = hdcp_ctrl->init_data.phy_addr;
+ reg_set = &hdcp_ctrl->reg_set;
if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
DEV_DBG("%s: %s: invalid state. returning\n", __func__,
@@ -844,8 +990,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
io = hdcp_ctrl->init_data.core_io;
memset(buf, 0, sizeof(buf));
- memset(ksv_fifo, 0,
- sizeof(hdcp_ctrl->current_tp.ksv_list));
+ memset(ksv_fifo, 0, sizeof(hdcp_ctrl->current_tp.ksv_list));
/*
* Wait until READY bit is set in BCAPS, as per HDCP specifications
@@ -853,48 +998,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
*/
timeout_count = 50;
do {
- timeout_count--;
- /* Read BCAPS at offset 0x40 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x40;
- ddc_data.data_buf = &bcaps;
- ddc_data.data_len = 1;
- ddc_data.request_len = 1;
- ddc_data.retry = 5;
- ddc_data.what = "Bcaps";
- ddc_data.retry_align = true;
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
- HDCP_STATE_NAME);
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
+ &bcaps, true);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading bcaps\n", __func__);
goto error;
}
msleep(100);
- } while (!(bcaps & BIT(5)) && timeout_count);
-
- /* Read BSTATUS at offset 0x41 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x41;
- ddc_data.data_buf = buf;
- ddc_data.data_len = 2;
- ddc_data.request_len = 2;
- ddc_data.retry = 5;
- ddc_data.what = "Bstatuss";
- ddc_data.retry_align = true;
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: BSTATUS read failed\n", __func__,
- HDCP_STATE_NAME);
+ } while (!(bcaps & BIT(5)) && --timeout_count);
+
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
+ buf, true);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: error reading bstatus\n", __func__);
goto error;
}
+
bstatus = buf[1];
bstatus = (bstatus << 8) | buf[0];
@@ -902,7 +1021,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
memset(scm_buf, 0x00, sizeof(scm_buf));
/* Write BSTATUS and BCAPS to HDCP registers */
- scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12;
+ scm_buf[0].addr = phy_addr + reg_set->data12;
scm_buf[0].val = bcaps | (bstatus << 8);
ret = hdcp_scm_call(scm_buf, &resp);
@@ -912,12 +1031,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
+ } else if (hdcp_ctrl->init_data.sec_access) {
DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
- bcaps | (bstatus << 8));
+ reg_set->sec_data12,
+ bcaps | (bstatus << 8));
} else {
- DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps | (bstatus << 8));
+ DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8));
}
down_stream_devices = bstatus & 0x7F;
@@ -972,37 +1091,28 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
* HDCP Repeaters (REPEATER == 0).
*/
ksv_bytes = 5 * down_stream_devices;
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x43;
- ddc_data.data_buf = ksv_fifo;
- ddc_data.data_len = ksv_bytes;
- ddc_data.request_len = ksv_bytes;
- ddc_data.retry = 5;
- ddc_data.what = "KSV FIFO";
-
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
-
- cnt = 0;
+ hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes;
+
do {
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
- if (rc) {
- DEV_ERR("%s: %s: KSV FIFO read failed\n", __func__,
- HDCP_STATE_NAME);
+ rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo,
+ ksv_fifo, false);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_DBG("%s: could not read ksv fifo (%d)\n",
+ __func__, ksv_read_retry);
/*
* HDCP Compliace Test case 1B-01:
* Wait here until all the ksv bytes have been
* read from the KSV FIFO register.
*/
msleep(25);
- } else {
- break;
+
}
- cnt++;
- } while (cnt != 20);
+ } while (rc && --ksv_read_retry);
- if (cnt == 20)
+ if (rc) {
+ DEV_ERR("%s: error reading ksv_fifo\n", __func__);
goto error;
+ }
rc = hdmi_hdcp_transfer_v_h(hdcp_ctrl);
if (rc)
@@ -1019,9 +1129,9 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
if (hdcp_ctrl->tz_hdcp) {
memset(scm_buf, 0x00, sizeof(scm_buf));
- scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_CTRL;
+ scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
scm_buf[0].val = HDCP_REG_ENABLE;
- scm_buf[1].addr = phy_addr + HDMI_HDCP_SHA_CTRL;
+ scm_buf[1].addr = phy_addr + reg_set->sha_ctrl;
scm_buf[1].val = HDCP_REG_DISABLE;
ret = hdcp_scm_call(scm_buf, &resp);
@@ -1031,16 +1141,16 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
+ } else if (hdcp_ctrl->init_data.sec_access) {
DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL,
+ reg_set->sec_sha_ctrl,
HDCP_REG_ENABLE);
DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL,
+ reg_set->sec_sha_ctrl,
HDCP_REG_DISABLE);
} else {
- DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_ENABLE);
- DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_DISABLE);
+ DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE);
+ DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE);
}
for (i = 0; i < ksv_bytes - 1; i++) {
@@ -1048,7 +1158,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
if (hdcp_ctrl->tz_hdcp) {
memset(scm_buf, 0x00, sizeof(scm_buf));
- scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA;
+ scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
scm_buf[0].val = ksv_fifo[i] << 16;
ret = hdcp_scm_call(scm_buf, &resp);
@@ -1058,12 +1168,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
+ } else if (hdcp_ctrl->init_data.sec_access) {
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA,
+ reg_set->sec_sha_ctrl,
ksv_fifo[i] << 16);
} else {
- DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, ksv_fifo[i] << 16);
+ DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16);
}
/*
@@ -1071,31 +1181,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
* HDCP_SHA_BLOCK_DONE before writing any further
*/
if (i && !((i + 1) % 64)) {
- timeout_count = 100;
- while (!(DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) & BIT(0))
- && (--timeout_count)) {
- DEV_DBG("%s: %s: Wrote 64 bytes KSV FIFO\n",
- __func__, HDCP_STATE_NAME);
- DEV_DBG("%s: %s: HDCP_SHA_STATUS=%08x\n",
- __func__, HDCP_STATE_NAME,
- DSS_REG_R(io, HDMI_HDCP_SHA_STATUS));
- msleep(20);
- }
- if (!timeout_count) {
- rc = -ETIMEDOUT;
- DEV_ERR("%s: %s: Write KSV FIFO timedout",
- __func__, HDCP_STATE_NAME);
+ rc = readl_poll_timeout(io->base + reg_set->sha_status,
+ sha_status, sha_status & BIT(0),
+ HDCP_POLL_SLEEP_US,
+ HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: block not done\n", __func__);
goto error;
}
}
-
}
/* Write l to DONE bit[0] */
if (hdcp_ctrl->tz_hdcp) {
memset(scm_buf, 0x00, sizeof(scm_buf));
- scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA;
+ scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1;
ret = hdcp_scm_call(scm_buf, &resp);
@@ -1105,43 +1206,32 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl)
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->hdmi_tx_ver_4) {
+ } else if (hdcp_ctrl->init_data.sec_access) {
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA,
+ reg_set->sec_sha_ctrl,
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
} else {
- DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA,
+ DSS_REG_W_ND(io, reg_set->sha_ctrl,
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
}
/* Now wait for HDCP_SHA_COMP_DONE */
- timeout_count = 100;
- while ((0x10 != (DSS_REG_R(io, HDMI_HDCP_SHA_STATUS)
- & 0xFFFFFF10)) && --timeout_count)
- msleep(20);
- if (!timeout_count) {
- rc = -ETIMEDOUT;
- DEV_ERR("%s: %s: SHA computation timedout", __func__,
- HDCP_STATE_NAME);
+ rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
+ sha_status & BIT(4),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: comp not done\n", __func__);
goto error;
}
/* Wait for V_MATCHES */
- timeout_count = 100;
- link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
- while (((link0_status & BIT(20)) != BIT(20)) && --timeout_count) {
- DEV_DBG("%s: %s: Waiting for V_MATCHES(%d). l0_status=0x%08x\n",
- __func__, HDCP_STATE_NAME, timeout_count, link0_status);
- msleep(20);
- link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
- }
- if (!timeout_count) {
- rc = -ETIMEDOUT;
- DEV_ERR("%s: %s: HDCP V Match timedout", __func__,
- HDCP_STATE_NAME);
+ rc = readl_poll_timeout(io->base + reg_set->status, status,
+ status & BIT(reg_set->v_offset),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ DEV_ERR("%s: V not ready\n", __func__);
goto error;
}
-
error:
if (rc)
DEV_ERR("%s: %s: Authentication Part II failed\n", __func__,
@@ -1236,7 +1326,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work)
io = hdcp_ctrl->init_data.core_io;
/* Enabling Software DDC */
- DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
HDMI_DDC_ARBITRATION) & ~(BIT(4)));
rc = hdmi_hdcp_authentication_part1(hdcp_ctrl);
@@ -1258,7 +1349,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work)
}
/* Disabling software DDC before going into part3 to make sure
* there is no Arbitration between software and hardware for DDC */
- DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
HDMI_DDC_ARBITRATION) | (BIT(4)));
error:
@@ -1314,12 +1406,17 @@ int hdmi_hdcp_authenticate(void *input)
DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__,
HDCP_STATE_NAME);
- if (!hdmi_hdcp_load_keys(input))
+ if (!hdmi_hdcp_load_keys(input)) {
+ flush_delayed_work(&hdcp_ctrl->hdcp_auth_work);
+
queue_delayed_work(hdcp_ctrl->init_data.workq,
&hdcp_ctrl->hdcp_auth_work, HZ/2);
- else
+ } else {
+ flush_work(&hdcp_ctrl->hdcp_int_work);
+
queue_work(hdcp_ctrl->init_data.workq,
&hdcp_ctrl->hdcp_int_work);
+ }
return 0;
} /* hdmi_hdcp_authenticate */
@@ -1328,6 +1425,8 @@ int hdmi_hdcp_reauthenticate(void *input)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
struct dss_io_data *io;
+ struct hdcp_reg_set *reg_set;
+ struct hdcp_int_set *isr;
u32 hdmi_hw_version;
u32 ret = 0;
@@ -1337,6 +1436,8 @@ int hdmi_hdcp_reauthenticate(void *input)
}
io = hdcp_ctrl->init_data.core_io;
+ reg_set = &hdcp_ctrl->reg_set;
+ isr = &hdcp_ctrl->int_set;
if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
DEV_DBG("%s: %s: invalid state. returning\n", __func__,
@@ -1344,22 +1445,25 @@ int hdmi_hdcp_reauthenticate(void *input)
return 0;
}
- hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
- if (hdmi_hw_version >= 0x30030000) {
- DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1));
- DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0);
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
+ if (hdmi_hw_version >= 0x30030000) {
+ DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1));
+ DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0);
+ }
+
+ /* Wait to be clean on DDC HW engine */
+ hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
}
/* Disable HDCP interrupts */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
-
- DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
- /* Wait to be clean on DDC HW engine */
- hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
+ if (reg_set->reset)
+ DSS_REG_W(io, reg_set->reset, BIT(0));
/* Disable encryption and disable the HDCP block */
- DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
+ DSS_REG_W(io, reg_set->ctrl, 0);
if (!hdmi_hdcp_load_keys(input))
queue_delayed_work(hdcp_ctrl->init_data.workq,
@@ -1375,6 +1479,8 @@ void hdmi_hdcp_off(void *input)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
struct dss_io_data *io;
+ struct hdcp_reg_set *reg_set;
+ struct hdcp_int_set *isr;
int rc = 0;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
@@ -1383,6 +1489,8 @@ void hdmi_hdcp_off(void *input)
}
io = hdcp_ctrl->init_data.core_io;
+ reg_set = &hdcp_ctrl->reg_set;
+ isr = &hdcp_ctrl->int_set;
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
DEV_DBG("%s: %s: inactive. returning\n", __func__,
@@ -1396,7 +1504,8 @@ void hdmi_hdcp_off(void *input)
* reauth works will know that the HDCP session has been turned off.
*/
mutex_lock(hdcp_ctrl->init_data.mutex);
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
+ DSS_REG_W(io, isr->int_reg,
+ DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
mutex_unlock(hdcp_ctrl->init_data.mutex);
@@ -1415,10 +1524,11 @@ void hdmi_hdcp_off(void *input)
DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__,
HDCP_STATE_NAME);
- DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ if (reg_set->reset)
+ DSS_REG_W(io, reg_set->reset, BIT(0));
/* Disable encryption and disable the HDCP block */
- DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
+ DSS_REG_W(io, reg_set->ctrl, 0);
DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
} /* hdmi_hdcp_off */
@@ -1429,6 +1539,8 @@ int hdmi_hdcp_isr(void *input)
int rc = 0;
struct dss_io_data *io;
u32 hdcp_int_val;
+ struct hdcp_reg_set *reg_set;
+ struct hdcp_int_set *isr;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -1437,28 +1549,33 @@ int hdmi_hdcp_isr(void *input)
}
io = hdcp_ctrl->init_data.core_io;
+ reg_set = &hdcp_ctrl->reg_set;
+ isr = &hdcp_ctrl->int_set;
- hdcp_int_val = DSS_REG_R(io, HDMI_HDCP_INT_CTRL);
+ hdcp_int_val = DSS_REG_R(io, isr->int_reg);
/* Ignore HDCP interrupts if HDCP is disabled */
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, HDCP_INT_CLR);
+ DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR);
return 0;
}
- if (hdcp_int_val & BIT(0)) {
+ if (hdcp_int_val & isr->auth_success_int) {
/* AUTH_SUCCESS_INT */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(1)));
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_success_ack));
DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__,
HDCP_STATE_NAME);
if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state)
complete_all(&hdcp_ctrl->r0_checked);
}
- if (hdcp_int_val & BIT(4)) {
+ if (hdcp_int_val & isr->auth_fail_int) {
/* AUTH_FAIL_INT */
- u32 link_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(5)));
+ u32 link_status = DSS_REG_R(io, reg_set->status);
+
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_ack));
DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
__func__, HDCP_STATE_NAME, link_status);
if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
@@ -1471,23 +1588,42 @@ int hdmi_hdcp_isr(void *input)
}
/* Clear AUTH_FAIL_INFO as well */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(7)));
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->auth_fail_info_ack));
}
- if (hdcp_int_val & BIT(8)) {
+ if (hdcp_int_val & isr->tx_req_int) {
/* DDC_XFER_REQ_INT */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(9)));
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_ack));
DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__,
HDCP_STATE_NAME);
}
- if (hdcp_int_val & BIT(12)) {
+ if (hdcp_int_val & isr->tx_req_done_int) {
/* DDC_XFER_DONE_INT */
- DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(13)));
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->tx_req_done_ack));
DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__,
HDCP_STATE_NAME);
}
+ if (hdcp_int_val & isr->encryption_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_ready_ack));
+ DEV_INFO("%s: %s: encryption ready received\n", __func__,
+ HDCP_STATE_NAME);
+ }
+
+ if (hdcp_int_val & isr->encryption_not_ready) {
+ /* Encryption enabled */
+ DSS_REG_W(io, isr->int_reg,
+ (hdcp_int_val | isr->encryption_not_ready_ack));
+ DEV_INFO("%s: %s: encryption not ready received\n", __func__,
+ HDCP_STATE_NAME);
+ }
+
error:
return rc;
} /* hdmi_hdcp_isr */
@@ -1605,6 +1741,27 @@ void hdmi_hdcp_deinit(void *input)
kfree(hdcp_ctrl);
} /* hdmi_hdcp_deinit */
+static void hdmi_hdcp_update_client_reg_set(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_HDMI;
+ struct hdcp_sink_addr_map sink_addr = HDCP_HDMI_SINK_ADDR_MAP;
+ struct hdcp_int_set isr = HDCP_HDMI_INT_SET;
+
+ hdcp_ctrl->reg_set = reg_set;
+ hdcp_ctrl->sink_addr = sink_addr;
+ hdcp_ctrl->int_set = isr;
+ } else if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP;
+ struct hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP;
+ struct hdcp_int_set isr = HDCP_DP_INT_SET;
+
+ hdcp_ctrl->reg_set = reg_set;
+ hdcp_ctrl->sink_addr = sink_addr;
+ hdcp_ctrl->int_set = isr;
+ }
+}
+
void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL;
@@ -1624,9 +1781,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
goto error;
}
- if (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4
- && !init_data->hdcp_io) {
- DEV_ERR("%s: hdcp_io required for HDMI Tx Ver 4\n", __func__);
+ if (init_data->sec_access && !init_data->hdcp_io) {
+ DEV_ERR("%s: hdcp_io required\n", __func__);
goto error;
}
@@ -1638,8 +1794,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
hdcp_ctrl->init_data = *init_data;
hdcp_ctrl->ops = &ops;
- hdcp_ctrl->hdmi_tx_ver_4 =
- (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4);
+
+ hdmi_hdcp_update_client_reg_set(hdcp_ctrl);
if (sysfs_create_group(init_data->sysfs_kobj,
&hdmi_hdcp_fs_attr_group)) {
@@ -1653,7 +1809,7 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data)
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
init_completion(&hdcp_ctrl->r0_checked);
- if (!hdcp_ctrl->hdmi_tx_ver_4) {
+ if (!hdcp_ctrl->init_data.sec_access) {
ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP);
if (ret <= 0) {
DEV_ERR("%s: secure hdcp service unavailable, ret = %d",
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
index 7dda3ff5c67d..4f2bdc4bfd3d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,11 @@
#include <video/msm_hdmi_modes.h>
#include <soc/qcom/scm.h>
+enum hdcp_client_id {
+ HDCP_CLIENT_HDMI,
+ HDCP_CLIENT_DP,
+};
+
enum hdmi_hdcp_state {
HDCP_STATE_INACTIVE,
HDCP_STATE_AUTHENTICATING,
@@ -37,10 +42,13 @@ struct hdmi_hdcp_init_data {
void *cb_data;
void (*notify_status)(void *cb_data, enum hdmi_hdcp_state status);
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+ void *dp_data;
u32 phy_addr;
u32 hdmi_tx_ver;
struct msm_hdmi_mode_timing_info *timing;
bool tethered;
+ bool sec_access;
+ enum hdcp_client_id client_id;
};
struct hdmi_hdcp_ops {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index cd3017219005..050c4a4cecdf 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -1801,6 +1801,7 @@ static int hdmi_tx_init_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl)
hdcp_init_data.notify_status = hdmi_tx_hdcp_cb;
hdcp_init_data.cb_data = (void *)hdmi_ctrl;
hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version;
+ hdcp_init_data.sec_access = true;
hdcp_init_data.timing = &hdmi_ctrl->timing;
if (hdmi_ctrl->hdcp14_present) {
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 518b84fbad51..e1aa004e14e6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1454,6 +1454,35 @@ end:
}
/**
+ * mdss_mdp_retention_init() - initialize retention setting
+ * @mdata: pointer to the global mdss data structure.
+ */
+static int mdss_mdp_retention_init(struct mdss_data_type *mdata)
+{
+ struct clk *mdss_axi_clk = mdss_mdp_get_clk(MDSS_CLK_AXI);
+ int rc;
+
+ if (!mdss_axi_clk) {
+ pr_err("failed to get AXI clock\n");
+ return -EINVAL;
+ }
+
+ rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_MEM);
+ if (rc) {
+ pr_err("failed to set AXI no memory retention %d\n", rc);
+ return rc;
+ }
+
+ rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_PERIPH);
+ if (rc) {
+ pr_err("failed to set AXI no periphery retention %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/**
* mdss_bus_bandwidth_ctrl() -- place bus bandwidth request
* @enable: value of enable or disable
*
@@ -1703,6 +1732,24 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
pr_debug("unable to get CX reg. rc=%d\n",
PTR_RET(mdata->vdd_cx));
mdata->vdd_cx = NULL;
+ } else {
+ /* Parse CX voltage settings */
+ ret = of_property_read_u32(mdata->pdev->dev.of_node,
+ "vdd-cx-min-uV", &mdata->vdd_cx_min_uv);
+ if (ret) {
+ pr_err("min uV for vdd-cx not specified. rc=%d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(mdata->pdev->dev.of_node,
+ "vdd-cx-max-uV", &mdata->vdd_cx_max_uv);
+ if (ret) {
+ pr_err("max uV for vdd-cx not specified. rc=%d\n", ret);
+ return ret;
+ }
+
+ pr_debug("vdd_cx [min_uV, max_uV] = [%d %d]\n",
+ mdata->vdd_cx_min_uv, mdata->vdd_cx_max_uv);
}
mdata->reg_bus_clt = mdss_reg_bus_vote_client_create("mdp\0");
@@ -1947,7 +1994,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_mdp_init_default_prefill_factors(mdata);
mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
- mdss_set_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
@@ -2718,6 +2764,12 @@ static int mdss_mdp_probe(struct platform_device *pdev)
goto probe_done;
}
+ rc = mdss_mdp_retention_init(mdata);
+ if (rc) {
+ pr_err("unable to initialize mdss mdp retention\n");
+ goto probe_done;
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS);
if (mdata->idle_pc_enabled)
pm_runtime_use_autosuspend(&pdev->dev);
@@ -4744,8 +4796,8 @@ static int mdss_mdp_cx_ctrl(struct mdss_data_type *mdata, int enable)
if (enable) {
rc = regulator_set_voltage(
mdata->vdd_cx,
- RPM_REGULATOR_CORNER_SVS_SOC,
- RPM_REGULATOR_CORNER_SUPER_TURBO);
+ mdata->vdd_cx_min_uv,
+ mdata->vdd_cx_max_uv);
if (rc < 0)
goto vreg_set_voltage_fail;
@@ -4764,8 +4816,8 @@ static int mdss_mdp_cx_ctrl(struct mdss_data_type *mdata, int enable)
}
rc = regulator_set_voltage(
mdata->vdd_cx,
- RPM_REGULATOR_CORNER_NONE,
- RPM_REGULATOR_CORNER_SUPER_TURBO);
+ 0,
+ mdata->vdd_cx_max_uv);
if (rc < 0)
goto vreg_set_voltage_fail;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 3a39d4fdc895..600701041309 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -347,10 +347,7 @@ static void __update_avr_info(struct mdss_mdp_ctl *ctl,
*/
static bool __layer_needs_src_split(struct mdp_input_layer *layer)
{
- struct mdss_data_type *mdata = mdss_mdp_get_mdata();
-
- return (layer->flags & MDP_LAYER_ASYNC) ||
- mdss_has_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS);
+ return (layer->flags & MDP_LAYER_ASYNC);
}
static int __async_update_position_check(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index bcb4867b4ffd..8cfb8e46777c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -2690,6 +2690,16 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
if (pipe->scaler.enable)
mdss_mdp_pipe_program_pixel_extn(pipe);
+
+ ret = mdss_mdp_pipe_pp_setup(pipe, &opmode);
+ if (ret) {
+ pr_err("pipe pp setup error for pnum=%d\n", pipe->num);
+
+ MDSS_XLOG(pipe->num, pipe->mixer_left->num,
+ pipe->play_cnt, 0xbad);
+
+ goto done;
+ }
}
if ((!(pipe->flags & MDP_VPU_PIPE) && (src_data == NULL)) ||
@@ -2708,12 +2718,6 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
if (params_changed) {
pipe->params_changed = 0;
- ret = mdss_mdp_pipe_pp_setup(pipe, &opmode);
- if (ret) {
- pr_err("pipe pp setup error for pnum=%d\n", pipe->num);
- goto done;
- }
-
ret = mdss_mdp_image_setup(pipe, src_data);
if (ret) {
pr_err("image setup error for pnum=%d\n", pipe->num);
diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c
index 5474df66eefb..a21242870a35 100644
--- a/drivers/video/fbdev/msm/msm_ext_display.c
+++ b/drivers/video/fbdev/msm/msm_ext_display.c
@@ -360,10 +360,13 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
ext_disp->current_disp = data->type;
} else if ((state == EXT_DISPLAY_CABLE_DISCONNECT) &&
!ext_disp->ack_enabled) {
- ext_disp->ops->audio_info_setup = NULL;
- ext_disp->ops->get_audio_edid_blk = NULL;
- ext_disp->ops->cable_status = NULL;
- ext_disp->ops->get_intf_id = NULL;
+ if (ext_disp->ops) {
+ ext_disp->ops->audio_info_setup = NULL;
+ ext_disp->ops->get_audio_edid_blk = NULL;
+ ext_disp->ops->cable_status = NULL;
+ ext_disp->ops->get_intf_id = NULL;
+ }
+
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
}
@@ -451,7 +454,7 @@ static int msm_ext_disp_notify(struct platform_device *pdev,
if (ret)
goto end;
- if (new_state == EXT_DISPLAY_CABLE_CONNECT) {
+ if (new_state == EXT_DISPLAY_CABLE_CONNECT && ext_disp->ops) {
ext_disp->ops->audio_info_setup =
data->codec_ops.audio_info_setup;
ext_disp->ops->get_audio_edid_blk =
@@ -524,10 +527,13 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack)
* empty.
*/
if (!ack_hpd) {
- ext_disp->ops->audio_info_setup = NULL;
- ext_disp->ops->get_audio_edid_blk = NULL;
- ext_disp->ops->cable_status = NULL;
- ext_disp->ops->get_intf_id = NULL;
+ if (ext_disp->ops) {
+ ext_disp->ops->audio_info_setup = NULL;
+ ext_disp->ops->get_audio_edid_blk = NULL;
+ ext_disp->ops->cable_status = NULL;
+ ext_disp->ops->get_intf_id = NULL;
+ }
+
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
}