Merge "drm/msm/dp: add support for dp aux" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/board-id.txt b/Documentation/devicetree/bindings/arm/msm/board-id.txt
new file mode 100644
index 0000000..e07a1c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/board-id.txt
@@ -0,0 +1,64 @@
+* BOARD-ID
+
+The qcom,board-id entry specifies the MSM platform and subtype revision.
+It can optionally be an array of these to indicate multiple hardware that use
+the same device tree. It is expected that the bootloader will use this
+information at boot-up to decide which device tree to use when given multiple
+device trees, some of which may not be compatible with the actual hardware. It
+is the bootloader's responsibility to pass the correct device tree to the kernel.
+
+Legacy format:
+
+It is expected that the qcom,board-id entry be at the top level of the device
+tree structure. The format of the entry is:
+
+ qcom,board-id = <platform_id, subtype_id> [, <p2, s2> ...]
+
+where platform_id and subtype_id are the numeric values for the platform and
+subtype of the current hardware.
+
+The "subtype_id" cell is a 32-bit integer whose bit values are defined as follows:
+ bits 31-20 = Reserved bits
+ bits 19-16 = Boot Device Type.
+ MSM:
+ 0: default (eMMC)
+ 2: EMMC_SDC1
+ 4: BOOT_UFS
+ MDM:
+ 0: default (NAND)
+ 3: EMMC_SDC1
+ bits 15-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, default value as 0x0
+ bits 7-0 = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Modern format:
+The cell layout of the qcom,board-id property is as follows:
+
+ qcom,board-id = <board_id, reserved>
+
+where board_id is a 32-bit integer whose bit values are defined as follows:
+ bits 31-24 = Platform Subtype ID
+ bits 23-16 = Platform Version (Major)
+ bits 15-8 = Platform Version (Minor)
+ bits 7-0 = Platform Type ID
+
+and the 'reserved' cell is a 32-bit integer whose bit values are defined as follows:
+ bits 31-13 = Reserved Bits
+ bits 12-11 = Panel Detection. 00 - limit to HD, 01 - limit to 720p,
+ 10 - limit to qHD, 11 - limit to FWVGA
+ bits 10-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1,
+ default value as 0x0
+ bits 7-0 = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Example:
+ qcom,board-id = <15 0>;
+ qcom,board-id = <0x01040708, 0>;
+ qcom,board-id = <0x01ffff08, 0>;
+ qcom,board-id = <8, 0x100>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
new file mode 100644
index 0000000..c243154
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
@@ -0,0 +1,33 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset, platform, hardware revision
+and optional manufactured foundry. It can optionally be an array of these to
+indicate multiple hardware that use the same device tree. It is expected that
+the bootloader will use this information at boot-up to decide which device tree
+to use when given multiple device trees, some of which may not be compatible
+with the actual hardware. It is the bootloader's responsibility to pass the
+correct device tree to the kernel.
+
+Format:
+
+It is expected that the qcom,msm-id entry be at the top level of the device
+tree structure. The format can take one of the two forms below:
+
+ qcom,msm-id = <chipset_foundry_id, platform_id, rev_id> [, <c2, p2, r2> ...]
+ qcom,msm-id = <chipset_foundry_id, rev_id> [, <c2, r2> ...]
+
+If the second format is used one must also define the board-id.
+
+The "chipset_foundry_id" consists of three fields as below:
+
+ bits 0-15 = The unique MSM chipset id.
+ bits 16-23 = The optional foundry id. If bootloader doesn't find a device
+ tree which has exact matching foundry-id with hardware it
+ chooses the device tree with foundry-id = 0.
+ bits 24-31 = Reserved.
+
+Example:
+ qcom,msm-id = <0x1007e 15 0>;
+
+ qcom,board-id= <15 2>;
+ qcom,msm-id = <0x1007e 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 79ac3b1..7ae63af 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -425,10 +425,44 @@
2003 1675>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
- <100000 100000 100000>;
+ /* Speed bin 0 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 1 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
- <100000 100000 100000>;
+ /* Speed bin 0 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 1 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 6818615..5f1b4ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1011,6 +1011,35 @@
interrupts = <1 5 4>;
};
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 1708800 762 >;
+ cpu-to-dev-map-4 =
+ < 2035200 762 >,
+ < 2092800 2597 >;
+ };
+ };
+
clock_rpmh: qcom,rpmhclk {
compatible = "qcom,rpmh-clk-sdm845";
#clock-cells = <1>;
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 3a38d37..7f56fb6 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -174,6 +174,7 @@
struct clk_regmap clkr;
u8 flags;
#define FORCE_ENABLE_RCG BIT(0)
+#define DFS_ENABLE_RCG BIT(1)
};
#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
@@ -187,4 +188,6 @@
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_dp_ops;
+extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
+ struct device *dev, u8 rcg_flags);
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 3d101ac..6bdea53 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -18,6 +18,7 @@
#include <linux/export.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/rational.h>
#include <linux/math64.h>
@@ -50,6 +51,14 @@
#define N_REG 0xc
#define D_REG 0x10
+/* Dynamic Frequency Scaling */
+#define MAX_PERF_LEVEL 16
+#define SE_CMD_DFSR_OFFSET 0x14
+#define SE_CMD_DFS_EN BIT(0)
+#define SE_PERF_DFSR(level) (0x1c + 0x4 * (level))
+#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level))
+#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level))
+
static struct freq_tbl cxo_f = {
.freq = 19200000,
.src = 0,
@@ -127,6 +136,9 @@
int ret;
u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return 0;
+
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
CFG_SRC_SEL_MASK, cfg);
if (ret)
@@ -236,6 +248,9 @@
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return rcg->current_freq;
+
if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
if (!rcg->current_freq)
rcg->current_freq = cxo_f.freq;
@@ -333,6 +348,9 @@
struct clk_hw *hw = &rcg->clkr.hw;
int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
+ if (rcg->flags & DFS_ENABLE_RCG)
+ return -EPERM;
+
if (index < 0)
return index;
@@ -461,7 +479,7 @@
}
ret = clk_rcg2_configure(rcg, f);
- if (ret)
+ if (ret && ret != -EPERM)
return ret;
if (rcg->flags & FORCE_ENABLE_RCG) {
@@ -1170,3 +1188,167 @@
.list_registers = clk_rcg2_list_registers,
};
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+
+/* Common APIs to be used for DFS based RCGR */
+static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
+ u32 *mode, u32 *pre_div)
+{
+ struct clk_rcg2 *rcg;
+ int num_parents = clk_hw_get_num_parents(hw);
+ u32 cfg, mask;
+ int i, ret;
+
+ if (!hw)
+ return -EINVAL;
+
+ rcg = to_clk_rcg2(hw);
+
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
+ if (ret)
+ goto err;
+
+ mask = BIT(rcg->hid_width) - 1;
+ *pre_div = cfg & mask ? (cfg & mask) : 1;
+
+ *mode = cfg & CFG_MODE_MASK;
+ *mode >>= CFG_MODE_SHIFT;
+
+ cfg &= CFG_SRC_SEL_MASK;
+ cfg >>= CFG_SRC_SEL_SHIFT;
+
+ for (i = 0; i < num_parents; i++)
+ if (cfg == rcg->parent_map[i].cfg)
+ return i;
+err:
+ pr_debug("%s: Clock %s has invalid parent, using default.\n",
+ __func__, clk_hw_get_name(hw));
+ return 0;
+}
+
+static int calculate_m_and_n(struct clk_hw *hw, u32 m_offset, u32 n_offset,
+ u32 mode, u32 *m, u32 *n)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 val, mask;
+ int ret = 0;
+
+ if (!hw)
+ return -EINVAL;
+
+ *m = *n = 0;
+
+ if (mode) {
+ /* Calculate M & N values */
+ mask = BIT(rcg->mnd_width) - 1;
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_offset,
+ &val);
+ if (ret) {
+ pr_err("Failed to read M offset register\n");
+ goto err;
+ }
+
+ val &= mask;
+ *m = val;
+
+ ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_offset,
+ &val);
+ if (ret) {
+ pr_err("Failed to read N offset register\n");
+ goto err;
+ }
+
+ /* val ~(N-M) */
+ val = ~val;
+ val &= mask;
+ val += *m;
+ *n = val;
+ }
+err:
+ return ret;
+}
+
+int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, struct device *dev,
+ u8 rcg_flags)
+{
+ int i, j, index, ret = 0;
+ unsigned long calc_freq, prate;
+ u32 val, pre_div = 0, mode = 0, m = 0, n = 0;
+ struct freq_tbl *dfs_freq_tbl;
+ struct clk_hw *phw;
+
+ if (!clk)
+ return -EINVAL;
+
+ /* Check for DFS_EN */
+ ret = regmap_read(clk->clkr.regmap, clk->cmd_rcgr + SE_CMD_DFSR_OFFSET,
+ &val);
+ if (ret) {
+ dev_err(dev, "Failed to read DFS enable register\n");
+ return -EINVAL;
+ }
+
+ if (!(val & SE_CMD_DFS_EN))
+ return ret;
+
+ dfs_freq_tbl = devm_kzalloc(dev, MAX_PERF_LEVEL *
+ sizeof(struct freq_tbl), GFP_KERNEL);
+ if (!dfs_freq_tbl)
+ return -ENOMEM;
+
+ /* Populate the Perf Level */
+ for (i = 0; i < MAX_PERF_LEVEL; i++) {
+ /* Get parent index and mode */
+ index = clk_parent_index_pre_div_and_mode(&clk->clkr.hw,
+ SE_PERF_DFSR(i), &mode,
+ &pre_div);
+ if (index < 0) {
+ pr_err("Failed to get parent index & mode %d\n", index);
+ return index;
+ }
+
+ /* clock pre_div */
+ dfs_freq_tbl[i].pre_div = pre_div;
+
+ /* Fill the parent src */
+ dfs_freq_tbl[i].src = clk->parent_map[index].src;
+
+ /* Get the parent clock and parent rate */
+ phw = clk_hw_get_parent_by_index(&clk->clkr.hw, index);
+ prate = clk_hw_get_rate(phw);
+
+ ret = calculate_m_and_n(&clk->clkr.hw, SE_PERF_M_DFSR(i),
+ SE_PERF_N_DFSR(i), mode, &m, &n);
+ if (ret)
+ goto err;
+
+ dfs_freq_tbl[i].m = m;
+ dfs_freq_tbl[i].n = n;
+
+ /* calculate the final frequency */
+ calc_freq = calc_rate(prate, dfs_freq_tbl[i].m,
+ dfs_freq_tbl[i].n, mode,
+ dfs_freq_tbl[i].pre_div);
+
+ /* Check for duplicate frequencies */
+ for (j = 0; j < i; j++) {
+ if (dfs_freq_tbl[j].freq == calc_freq)
+ goto done;
+ }
+
+ dfs_freq_tbl[i].freq = calc_freq;
+ }
+done:
+ j = i;
+
+ for (i = 0; i < j; i++)
+ pr_debug("Index[%d]\tfreq_table.freq %ld\tfreq_table.src %d\t"
+ "freq_table.pre_div %d\tfreq_table.m %d\tfreq_table.n %d\t"
+ "RCG flags %x\n", i, dfs_freq_tbl[i].freq, dfs_freq_tbl[i].src,
+ dfs_freq_tbl[i].pre_div, dfs_freq_tbl[i].m,
+ dfs_freq_tbl[i].n, rcg_flags);
+
+ clk->flags |= rcg_flags;
+ clk->freq_tbl = dfs_freq_tbl;
+err:
+ return ret;
+}
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index fffcbaf..b2ff04a 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2017, The Linux Foundation. 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
@@ -275,4 +275,26 @@
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
+int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+ const struct qcom_cc_dfs_desc *desc)
+{
+ struct clk_dfs *clks = desc->clks;
+ size_t num_clks = desc->num_clks;
+ int i, ret = 0;
+
+ for (i = 0; i < num_clks; i++) {
+ ret = clk_rcg2_get_dfs_clock_rate(clks[i].rcg, &pdev->dev,
+ clks[i].rcg_flags);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed calculating DFS frequencies for %s\n",
+ clk_hw_get_name(&(clks[i].rcg)->clkr.hw));
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_cc_register_rcg_dfs);
+
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index e728dec..5e26763 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -14,6 +14,7 @@
#define __QCOM_CLK_COMMON_H__
#include <linux/reset-controller.h>
+#include "clk-rcg.h"
struct platform_device;
struct regmap_config;
@@ -40,6 +41,16 @@
unsigned long rrate;
};
+struct clk_dfs {
+ struct clk_rcg2 *rcg;
+ u8 rcg_flags;
+};
+
+struct qcom_cc_dfs_desc {
+ struct clk_dfs *clks;
+ size_t num_clks;
+};
+
extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
unsigned long rate);
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
@@ -56,6 +67,10 @@
struct regmap *regmap);
extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
+
+extern int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+ const struct qcom_cc_dfs_desc *desc);
+
extern struct clk_ops clk_dummy_ops;
#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 228f716..b38bfb0 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -3509,6 +3509,31 @@
[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
};
+/* List of RCG clocks and corresponding flags requested for DFS Mode */
+static struct clk_dfs gcc_dfs_clocks[] = {
+ { &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG },
+ { &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG },
+};
+
+static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = {
+ .clks = gcc_dfs_clocks,
+ .num_clks = ARRAY_SIZE(gcc_dfs_clocks),
+};
+
static const struct regmap_config gcc_sdm845_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -3599,10 +3624,10 @@
clk_prepare_enable(gcc_camera_ahb_clk.clkr.hw.clk);
clk_prepare_enable(gcc_video_ahb_clk.clkr.hw.clk);
- /*
- * TODO:
- * 1. QUPv3 support
- */
+ /* DFS clock registration */
+ ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register with DFS!\n");
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index dcf3c08..a3a3d28 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3054,6 +3054,11 @@
state->crtc_h);
seq_printf(s, "\tmultirect: mode: %d index: %d\n",
pstate->multirect_mode, pstate->multirect_index);
+
+ seq_printf(s, "\texcl_rect: x:%4d y:%4d w:%4d h:%4d\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
+
seq_puts(s, "\n");
}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 3a6de75..ad207d6 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2447,7 +2447,7 @@
pstate->excl_rect.h != old_pstate->excl_rect.h ||
pstate->excl_rect.x != old_pstate->excl_rect.x ||
pstate->excl_rect.y != old_pstate->excl_rect.y) {
- SDE_DEBUG_PLANE(psde, "excl rect updated\n");
+ SDE_DEBUG_PLANE(psde, "excl_rect updated\n");
pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
}
@@ -2660,6 +2660,9 @@
(char *)&fmt->base.pixel_format);
ret = -EINVAL;
}
+ SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
}
modeset_update:
@@ -3480,20 +3483,24 @@
}
if (!usr_ptr) {
- SDE_DEBUG_PLANE(psde, "excl rect data removed\n");
+ SDE_DEBUG_PLANE(psde, "invalid excl_rect user data\n");
return;
}
if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) {
- SDE_ERROR_PLANE(psde, "failed to copy excl rect data\n");
+ SDE_ERROR_PLANE(psde, "failed to copy excl_rect data\n");
return;
}
/* populate from user space */
pstate->excl_rect.x = excl_rect_v1.x1;
pstate->excl_rect.y = excl_rect_v1.y1;
- pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1 + 1;
- pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1 + 1;
+ pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1;
+ pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1;
+
+ SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+ pstate->excl_rect.x, pstate->excl_rect.y,
+ pstate->excl_rect.w, pstate->excl_rect.h);
}
static int sde_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index bf3a91a..2e92335 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1509,8 +1509,7 @@
PERFCOUNTER_FLAG_KERNEL);
if (ret) {
- KGSL_DRV_ERR(device,
- "Unable to get the perf counters for DCVS\n");
+ WARN_ONCE(1, "Unable to get perf counters for DCVS\n");
adreno_dev->perfctr_pwr_lo = 0;
}
}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 24b5faa..e157e7b 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -813,12 +813,12 @@
t = jiffies + msecs_to_jiffies(timeout);
- while (!time_after(jiffies, t)) {
+ do {
kgsl_gmu_regread(device, offset, &value);
if ((value & mask) == expected_ret)
return 0;
cpu_relax();
- }
+ } while (!time_after(jiffies, t));
return -EINVAL;
}
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 54659fc..8de1a7e 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1438,7 +1438,7 @@
if (hfi->hfi_interrupt_num) {
devm_free_irq(&gmu->pdev->dev,
- hfi->hfi_interrupt_num, gmu);
+ hfi->hfi_interrupt_num, hfi);
hfi->hfi_interrupt_num = 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 8906027..14eb3ab 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -86,7 +86,6 @@
};
static const char *const hevc_tier_level[] = {
- "Level unknown"
"Main Tier Level 1",
"Main Tier Level 2",
"Main Tier Level 2.1",
@@ -113,6 +112,7 @@
"High Tier Level 6",
"High Tier Level 6.1",
"High Tier Level 6.2",
+ "Level unknown",
};
static const char *const hevc_profile[] = {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 2289b23..05d6d63 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1267,10 +1267,9 @@
return -EINVAL;
}
if (*num_buffers < bufreq->buffer_count_min_host) {
- dprintk(VIDC_ERR,
- "Invalid parameters : Req = %d Act = %d\n",
+ dprintk(VIDC_DBG,
+ "Client passed num buffers %d less than the min_host count %d\n",
*num_buffers, bufreq->buffer_count_min_host);
- return -EINVAL;
}
*num_planes = inst->bufq[OUTPUT_PORT].num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
@@ -1299,11 +1298,10 @@
if (inst->session_type != MSM_VIDC_DECODER &&
inst->state > MSM_VIDC_LOAD_RESOURCES_DONE) {
if (*num_buffers < bufreq->buffer_count_min_host) {
- dprintk(VIDC_ERR,
- "Invalid parameters : Req = %d Act = %d\n",
+ dprintk(VIDC_DBG,
+ "Client passed num buffers %d less than the min_host count %d\n",
*num_buffers,
bufreq->buffer_count_min_host);
- return -EINVAL;
}
}
*num_planes = inst->bufq[CAPTURE_PORT].num_planes;
@@ -1890,16 +1888,30 @@
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ inst->profile);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
- ctrl->val = inst->profile;
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+ inst->profile);
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ inst->level);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
- case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ inst->level);
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
- ctrl->val = inst->level;
+ ctrl->val = msm_comm_hal_to_v4l2(
+ V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+ inst->level);
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index c0bbfbb..058af0e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -199,6 +199,8 @@
return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
case HAL_H264_LEVEL_51:
return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+ case HAL_H264_LEVEL_52:
+ return V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
default:
goto unknown_value;
}
@@ -212,7 +214,91 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+ switch (value) {
+ case HAL_HEVC_PROFILE_MAIN:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN;
+ case HAL_HEVC_PROFILE_MAIN10:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10;
+ case HAL_HEVC_PROFILE_MAIN_STILL_PIC:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC;
+ default:
+ goto unknown_value;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+ switch (value) {
+ case HAL_HEVC_MAIN_TIER_LEVEL_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2;
+ case HAL_HEVC_MAIN_TIER_LEVEL_2_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_3:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3;
+ case HAL_HEVC_MAIN_TIER_LEVEL_3_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_4:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4;
+ case HAL_HEVC_MAIN_TIER_LEVEL_4_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_5_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1;
+ case HAL_HEVC_MAIN_TIER_LEVEL_6_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_2_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_3:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3;
+ case HAL_HEVC_HIGH_TIER_LEVEL_3_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_4:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4;
+ case HAL_HEVC_HIGH_TIER_LEVEL_4_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_5_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6_1:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1;
+ case HAL_HEVC_HIGH_TIER_LEVEL_6_2:
+ return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
+ return HAL_HEVC_TIER_LEVEL_UNKNOWN;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ switch (value) {
+ case HAL_VPX_LEVEL_VERSION_0:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0;
+ case HAL_VPX_LEVEL_VERSION_1:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1;
+ case HAL_VPX_LEVEL_VERSION_2:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2;
+ case HAL_VPX_LEVEL_VERSION_3:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3;
+ case HAL_VPX_LEVEL_UNUSED:
+ return V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
/*
@@ -396,6 +482,8 @@
return HAL_HEVC_HIGH_TIER_LEVEL_6;
case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+ case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2:
+ return HAL_HEVC_HIGH_TIER_LEVEL_6_2;
case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
return HAL_HEVC_TIER_LEVEL_UNKNOWN;
default:
@@ -1463,15 +1551,9 @@
* ptr[4] = colour space
*/
- inst->entropy_mode = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
- event_notify->entropy_mode);
- inst->profile = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- event_notify->profile);
- inst->level = msm_comm_hal_to_v4l2(
- V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- event_notify->level);
+ inst->entropy_mode = event_notify->entropy_mode;
+ inst->profile = event_notify->profile;
+ inst->level = event_notify->level;
ptr = (u32 *)seq_changed_event.u.data;
ptr[0] = event_notify->height;
@@ -2342,7 +2424,7 @@
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
- vbuf->flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+ vbuf->flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bcc29c0..da18377 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -377,11 +377,11 @@
};
enum hal_vpx_level {
+ HAL_VPX_LEVEL_UNUSED = 0x00000000,
HAL_VPX_LEVEL_VERSION_0 = 0x00000001,
HAL_VPX_LEVEL_VERSION_1 = 0x00000002,
HAL_VPX_LEVEL_VERSION_2 = 0x00000004,
HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
- HAL_VPX_LEVEL_UNUSED = 0x10000000,
};
struct hal_frame_rate {
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 4d2f54d..a9b78d5 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -74,6 +74,12 @@
#define DCC_RD_MOD_WR_DESCRIPTOR (BIT(31))
#define DCC_LINK_DESCRIPTOR (BIT(31) | BIT(30))
+#define DCC_READ_IND 0x00
+#define DCC_WRITE_IND (BIT(28))
+
+#define DCC_AHB_IND 0x00
+#define DCC_APB_IND BIT(29)
+
#define DCC_MAX_LINK_LIST 5
#define DCC_INVALID_LINK_LIST 0xFF
@@ -92,6 +98,13 @@
DCC_DATA_SINK_ATB
};
+enum dcc_descriptor_type {
+ DCC_ADDR_TYPE,
+ DCC_LOOP_TYPE,
+ DCC_READ_WRITE_TYPE,
+ DCC_WRITE_TYPE
+};
+
static const char * const str_dcc_data_sink[] = {
[DCC_DATA_SINK_SRAM] = "sram",
[DCC_DATA_SINK_ATB] = "atb",
@@ -103,15 +116,16 @@
};
struct dcc_config_entry {
- uint32_t base;
- uint32_t offset;
- uint32_t len;
- uint32_t index;
- uint32_t loop_cnt;
- uint32_t rd_mod_wr;
- uint32_t mask;
- bool rd_wr_entry;
- struct list_head list;
+ uint32_t base;
+ uint32_t offset;
+ uint32_t len;
+ uint32_t index;
+ uint32_t loop_cnt;
+ uint32_t write_val;
+ uint32_t mask;
+ bool apb_bus;
+ enum dcc_descriptor_type desc_type;
+ struct list_head list;
};
struct dcc_drvdata {
@@ -189,7 +203,7 @@
mutex_lock(&drvdata->mutex);
if (!dcc_ready(drvdata)) {
- dev_err(drvdata->dev, "DCC is not ready!\n");
+ dev_err(drvdata->dev, "DCC is not ready\n");
ret = -EBUSY;
goto err;
}
@@ -224,7 +238,7 @@
uint32_t loop_off = 0;
uint32_t link;
uint32_t pos, total_len = 0, loop_len = 0;
- uint32_t loop, loop_cnt;
+ uint32_t loop, loop_cnt = 0;
bool loop_start = false;
struct dcc_config_entry *entry;
@@ -233,7 +247,9 @@
link = 0;
list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) {
- if (entry->rd_wr_entry) {
+ switch (entry->desc_type) {
+ case DCC_READ_WRITE_TYPE:
+ {
if (link) {
/* write new offset = 1 to continue
* processing the list
@@ -255,12 +271,14 @@
dcc_sram_writel(drvdata, entry->mask, sram_offset);
sram_offset += 4;
- dcc_sram_writel(drvdata, entry->rd_mod_wr, sram_offset);
+ dcc_sram_writel(drvdata, entry->write_val, sram_offset);
sram_offset += 4;
- continue;
+ addr = 0;
+ break;
}
- if (entry->loop_cnt) {
+ case DCC_LOOP_TYPE:
+ {
/* Check if we need to write link of prev entry */
if (link) {
dcc_sram_writel(drvdata, link, sram_offset);
@@ -292,73 +310,130 @@
prev_off = 0;
prev_addr = addr;
- continue;
+ break;
}
- /* Address type */
- addr = (entry->base >> 4) & BM(0, 27);
- addr |= DCC_ADDR_DESCRIPTOR;
- off = entry->offset/4;
- total_len += entry->len * 4;
-
- if (!prev_addr || prev_addr != addr || prev_off > off) {
- /* Check if we need to write link of prev entry */
+ case DCC_WRITE_TYPE:
+ {
if (link) {
+ /* write new offset = 1 to continue
+ * processing the list
+ */
+ link |= ((0x1 << 8) & BM(8, 14));
dcc_sram_writel(drvdata, link, sram_offset);
sram_offset += 4;
+ /* Reset link and prev_off */
+ addr = 0x00;
+ prev_off = 0;
+ prev_addr = addr;
}
- dev_err(drvdata->dev,
- "DCC: sram address.%d\n", sram_offset);
- /* Write address */
+ off = entry->offset/4;
+ /* write new offset-length pair to correct position */
+ link |= ((off & BM(0, 7)) | BIT(15) |
+ ((entry->len << 8) & BM(8, 14)));
+ link |= DCC_LINK_DESCRIPTOR;
+
+ /* Address type */
+ addr = (entry->base >> 4) & BM(0, 27);
+ if (entry->apb_bus)
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+ | DCC_APB_IND;
+ else
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+ | DCC_AHB_IND;
+
dcc_sram_writel(drvdata, addr, sram_offset);
- sram_offset += 4;
+ sram_offset += 4;
- /* Reset link and prev_off */
- link = 0;
- prev_off = 0;
- }
-
- if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) {
- dev_err(drvdata->dev,
- "DCC: Progamming error! Base: 0x%x, offset 0x%x.\n",
- entry->base, entry->offset);
- ret = -EINVAL;
- goto err;
- }
-
- if (link) {
- /*
- * link already has one offset-length so new
- * offset-length needs to be placed at bits [29:15]
- */
- pos = 15;
-
- /* Clear bits [31:16] */
- link &= BM(0, 14);
- } else {
- /*
- * link is empty, so new offset-length needs to be
- * placed at bits [15:0]
- */
- pos = 0;
- link = 1 << 15;
- }
-
- /* write new offset-length pair to correct position */
- link |= (((off-prev_off) & BM(0, 7)) |
- ((entry->len << 8) & BM(8, 14))) << pos;
-
- link |= DCC_LINK_DESCRIPTOR;
-
- if (pos) {
dcc_sram_writel(drvdata, link, sram_offset);
- sram_offset += 4;
+ sram_offset += 4;
+
+ dcc_sram_writel(drvdata, entry->write_val, sram_offset);
+ sram_offset += 4;
+ addr = 0x00;
link = 0;
+ break;
}
- prev_off = off;
- prev_addr = addr;
+ default:
+ {
+ /* Address type */
+ addr = (entry->base >> 4) & BM(0, 27);
+ if (entry->apb_bus)
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+ | DCC_APB_IND;
+ else
+ addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+ | DCC_AHB_IND;
+
+ off = entry->offset/4;
+ total_len += entry->len * 4;
+
+ if (!prev_addr || prev_addr != addr || prev_off > off) {
+ /* Check if we need to write prev link entry */
+ if (link) {
+ dcc_sram_writel(drvdata,
+ link, sram_offset);
+ sram_offset += 4;
+ }
+ dev_dbg(drvdata->dev,
+ "DCC: sram address 0x%x\n",
+ sram_offset);
+
+ /* Write address */
+ dcc_sram_writel(drvdata, addr, sram_offset);
+ sram_offset += 4;
+
+ /* Reset link and prev_off */
+ link = 0;
+ prev_off = 0;
+ }
+
+ if ((off - prev_off) > 0xFF ||
+ entry->len > MAX_DCC_LEN) {
+ dev_err(drvdata->dev,
+ "DCC: Progamming error Base: 0x%x, offset 0x%x\n",
+ entry->base, entry->offset);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (link) {
+ /*
+ * link already has one offset-length so new
+ * offset-length needs to be placed at
+ * bits [29:15]
+ */
+ pos = 15;
+
+ /* Clear bits [31:16] */
+ link &= BM(0, 14);
+ } else {
+ /*
+ * link is empty, so new offset-length needs
+ * to be placed at bits [15:0]
+ */
+ pos = 0;
+ link = 1 << 15;
+ }
+
+ /* write new offset-length pair to correct position */
+ link |= (((off-prev_off) & BM(0, 7)) |
+ ((entry->len << 8) & BM(8, 14))) << pos;
+
+ link |= DCC_LINK_DESCRIPTOR;
+
+ if (pos) {
+ dcc_sram_writel(drvdata, link, sram_offset);
+ sram_offset += 4;
+ link = 0;
+ }
+
+ prev_off = off;
+ prev_addr = addr;
+ }
+ }
}
if (link) {
@@ -368,7 +443,7 @@
if (loop_start) {
dev_err(drvdata->dev,
- "DCC: Progamming error! Loop unterminated.\n");
+ "DCC: Progamming error: Loop unterminated\n");
ret = -EINVAL;
goto err;
}
@@ -457,7 +532,7 @@
*/
for (i = 0; i < 2; i++) {
if (!dcc_ready(drvdata))
- dev_err(drvdata->dev, "DCC is not ready!\n");
+ dev_err(drvdata->dev, "DCC is not ready\n");
dcc_writel(drvdata, 1,
DCC_LL_SW_TRIGGER(drvdata->curr_list));
@@ -476,13 +551,13 @@
return -EINVAL;
if (drvdata->enable[curr_list]) {
- dev_err(drvdata->dev, "DCC is already enabled!\n");
+ dev_err(drvdata->dev, "DCC is already enabled\n");
return -EINVAL;
}
lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(curr_list));
if (lock_reg & 0x1) {
- dev_err(drvdata->dev, "DCC is already enabled!\n");
+ dev_err(drvdata->dev, "DCC is already enabled\n");
return -EINVAL;
}
@@ -565,7 +640,7 @@
mutex_lock(&drvdata->mutex);
if (!dcc_ready(drvdata))
- dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n");
+ dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n");
for (curr_list = 0; curr_list < DCC_MAX_LINK_LIST; curr_list++) {
if (!drvdata->enable[curr_list])
@@ -600,7 +675,7 @@
mutex_lock(&drvdata->mutex);
lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val));
if (lock_reg & 0x1) {
- dev_err(drvdata->dev, "DCC linked list is already configured!\n");
+ dev_err(drvdata->dev, "DCC linked list is already configured\n");
mutex_unlock(&drvdata->mutex);
return -EINVAL;
}
@@ -783,25 +858,36 @@
mutex_lock(&drvdata->mutex);
list_for_each_entry(entry,
&drvdata->cfg_head[drvdata->curr_list], list) {
- if (entry->rd_wr_entry)
+ switch (entry->desc_type) {
+ case DCC_READ_WRITE_TYPE:
len = snprintf(local_buf, 64,
"Index: 0x%x, mask: 0x%x, val: 0x%x\n",
entry->index, entry->mask,
- entry->rd_mod_wr);
- else if (entry->loop_cnt)
+ entry->write_val);
+ break;
+ case DCC_LOOP_TYPE:
len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n",
entry->index, entry->loop_cnt);
- else
- len = snprintf(local_buf, 64,
- "Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n",
- entry->index, entry->base,
- entry->offset, entry->len);
-
- if ((count + len) > PAGE_SIZE) {
- dev_err(dev, "DCC: Couldn't write complete config!\n");
break;
+ case DCC_WRITE_TYPE:
+ len = snprintf(local_buf, 64,
+ "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base,
+ entry->offset, entry->len,
+ entry->apb_bus);
+ break;
+ default:
+ len = snprintf(local_buf, 64,
+ "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base,
+ entry->offset, entry->len,
+ entry->apb_bus);
}
+ if ((count + len) > PAGE_SIZE) {
+ dev_err(dev, "DCC: Couldn't write complete config\n");
+ break;
+ }
strlcat(buf, local_buf, PAGE_SIZE);
count += len;
}
@@ -812,7 +898,7 @@
}
static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
- unsigned int len)
+ unsigned int len, int apb_bus)
{
int ret;
struct dcc_config_entry *entry, *pentry;
@@ -821,7 +907,7 @@
mutex_lock(&drvdata->mutex);
if (!len) {
- dev_err(drvdata->dev, "DCC: Invalid length!\n");
+ dev_err(drvdata->dev, "DCC: Invalid length\n");
ret = -EINVAL;
goto err;
}
@@ -883,6 +969,8 @@
entry->offset = offset;
entry->len = min_t(uint32_t, len, MAX_DCC_LEN);
entry->index = drvdata->nr_config[drvdata->curr_list]++;
+ entry->desc_type = DCC_ADDR_TYPE;
+ entry->apb_bus = apb_bus;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list,
&drvdata->cfg_head[drvdata->curr_list]);
@@ -902,24 +990,30 @@
struct device_attribute *attr,
const char *buf, size_t size)
{
- int ret, len;
+ int ret, len, apb_bus;
unsigned int base;
struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
int nval;
- nval = sscanf(buf, "%x %i", &base, &len);
- if (nval <= 0 || nval > 2)
+ nval = sscanf(buf, "%x %i %d", &base, &len, &apb_bus);
+ if (nval <= 0 || nval > 3)
return -EINVAL;
- if (nval == 1)
- len = 1;
-
if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
dev_err(dev, "Select link list to program using curr_list\n");
return -EINVAL;
}
- ret = dcc_config_add(drvdata, base, len);
+ if (nval == 1) {
+ len = 1;
+ apb_bus = 0;
+ } else if (nval == 2) {
+ apb_bus = 0;
+ } else {
+ apb_bus = 1;
+ }
+
+ ret = dcc_config_add(drvdata, base, len, apb_bus);
if (ret)
return ret;
@@ -1087,7 +1181,7 @@
}
if (list_empty(&drvdata->cfg_head[drvdata->curr_list])) {
- dev_err(drvdata->dev, "DCC: No read address programmed!\n");
+ dev_err(drvdata->dev, "DCC: No read address programmed\n");
ret = -EPERM;
goto err;
}
@@ -1098,9 +1192,9 @@
goto err;
}
- entry->rd_wr_entry = true;
+ entry->desc_type = DCC_READ_WRITE_TYPE;
entry->mask = mask;
- entry->rd_mod_wr = val;
+ entry->write_val = val;
entry->index = drvdata->nr_config[drvdata->curr_list]++;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
@@ -1110,6 +1204,54 @@
}
static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr);
+static ssize_t dcc_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = size;
+ int nval;
+ unsigned int addr, write_val;
+ int apb_bus;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ struct dcc_config_entry *entry;
+
+ mutex_lock(&drvdata->mutex);
+
+ nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
+
+ if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ return -EINVAL;
+ }
+
+ if (nval <= 1 || nval > 3) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (nval == 3)
+ entry->apb_bus = true;
+
+ entry->desc_type = DCC_WRITE_TYPE;
+ entry->base = addr & BM(4, 31);
+ entry->offset = addr - entry->base;
+ entry->write_val = write_val;
+ entry->index = drvdata->nr_config[drvdata->curr_list]++;
+ entry->len = 1;
+ INIT_LIST_HEAD(&entry->list);
+ list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+static DEVICE_ATTR(config_write, 0200, NULL, dcc_write);
+
static const struct device_attribute *dcc_attrs[] = {
&dev_attr_func_type,
&dev_attr_data_sink,
@@ -1123,6 +1265,7 @@
&dev_attr_loop,
&dev_attr_rd_mod_wr,
&dev_attr_curr_list,
+ &dev_attr_config_write,
NULL,
};
@@ -1134,7 +1277,7 @@
for (i = 0; attrs[i] != NULL; i++) {
ret = device_create_file(dev, attrs[i]);
if (ret) {
- dev_err(dev, "DCC: Couldn't create sysfs attribute: %s!\n",
+ dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n",
attrs[i]->attr.name);
break;
}
@@ -1173,7 +1316,7 @@
if (copy_to_user(data, buf, len)) {
dev_err(drvdata->dev,
- "DCC: Couldn't copy all data to user!\n");
+ "DCC: Couldn't copy all data to user\n");
kfree(buf);
return -EFAULT;
}
@@ -1372,7 +1515,7 @@
}
if (i == ARRAY_SIZE(str_dcc_data_sink)) {
- dev_err(dev, "Unknown sink type for DCC! Using '%s' as data sink\n",
+ dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n",
str_dcc_data_sink[drvdata->data_sink]);
}
}