Merge changes Ifc63c2cf,I688b711e into msm-3.4
* changes:
defconfig: msm8960: Enable HCIUART for AR3002 support
msm: 8960: Add AR3002 Bluetooth Support
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
new file mode 100644
index 0000000..6db1150
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -0,0 +1,140 @@
+Qualcomm mdss-dsi-panel
+
+mdss-dsi-panel is a dsi panel driver which supports panels that
+are compatable with MIPI display serial interface specification.
+
+Required properties:
+- compatible: Must be "qcom,mdss-dsi-panel"
+- status: A string that has to be set to "okay/ok" to enable
+ the panel driver. By default this property will be
+ set to "disable". Will be set to "ok/okay" status
+ for specific platforms.
+- qcom,mdss-pan-res: A two dimensional array that specifies the panel
+ resolution.
+- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. Default value is 24(rgb888).
+ 18 = for rgb666
+ 16 = for rgb565
+- qcom,mdss-panel-on-cmds: An array of variable length that lists the init commands
+ of the panel. Each command will have the format specified
+ as below:
+ --> data type of the command
+ --> specifies whether this command packet is last.
+ --> virtual channel
+ --> Needs acknowledge from the panel or not.
+ --> wait time after the command is transmitter.
+ --> size of payload
+ --> payload.
+- qcom,mdss-panel-off-cmds: An array of variable length that lists the panel off
+ commands. Each command will have the format specified
+ as below:
+ --> data type of the command
+ --> specifies whether this command packet is last.
+ --> virtual channel
+ --> Needs acknowledge from the panel or not.
+ --> wait time after the command is transmitter.
+ --> size of payload
+ --> payload.
+
+Required structure:
+- A qcom,mdss-dsi-panel node must be a child of an mdss-dsi controller node that links to
+ one of the two DSI controllers.
+
+
+Optional properties:
+- label: A string used as a descriptive name of the panel
+- qcom,mdss-pan-porch-values: An array of size 6 that specifies the panel blanking values.
+- qcom,mdss-pan-underflow-clr: Specifies the controller settings for the panel underflow clear
+ settings. Default value is 0xff.
+- qcom,mdss-pan-bl-levels: Specifies the backlight levels supported by the panel.
+ Default range is 1 to 255.
+
+- qcom,mdss-pan-dsi-mode: Specifies the panel operating mode.
+ 0 = enable video mode(default mode).
+ 1 = enable command mode.
+- qcom,mdss-pan-dsi-h-pulse-mode: Specifies the pulse mode option for the panel.
+ 0 = Don't send hsa/he following vs/ve packet(default)
+ 1 = Send hsa/he following vs/ve packet
+- qcom,mdss-pan-dsi-h-power-stop: An Array of size 3 that specifies the power mode
+ during horizontal porch and sync periods of the panel.
+ 0 = high speed mode(default mode).
+ 1 = Low power mode for horizontal porches and sync pulse.
+- qcom,mdss-pan-dsi-bllp-power-stop: An Array of size 2 that specifies the power mode
+ during blanking period and after EOF(end of frame).
+ 0 = high speed mode(default mode).
+ 1 = Low power mode during blanking and EOF.
+- qcom,mdss-pan-dsi-traffic-mode: Specifies the panel traffic mode.
+ 0 = non burst with sync pulses (default mode).
+ 1 = non burst with sync start event.
+ 2 = burst mode.
+- qcom,mdss-pan-dsi-dst-format: Specifies the destination format.
+ 0 = DSI_VIDEO_DST_FORMAT_RGB565.
+ 1 = DSI_VIDEO_DST_FORMAT_RGB666.
+ 2 = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE.
+ 3 = DSI_VIDEO_DST_FORMAT_RGB888 (Default format)
+ 6 = DSI_CMD_DST_FORMAT_RGB565
+ 7 = DSI_CMD_DST_FORMAT_RGB666
+ 8 = DSI_CMD_DST_FORMAT_RGB888
+- qcom,mdss-pan-dsi-vc: Specifies the virtual channel identefier.
+ 0 = default value.
+- qcom,mdss-pan-dsi-rgb-swap: Specifies the R, G and B channel ordering.
+ 0 = DSI_RGB_SWAP_RGB (default value)
+ 1 = DSI_RGB_SWAP_RBG
+ 2 = DSI_RGB_SWAP_BGR
+ 3 = DSI_RGB_SWAP_BRG
+ 4 = DSI_RGB_SWAP_GRB
+ 5 = DSI_RGB_SWAP_GBR
+- qcom,mdss-pan-dsi-data-lanes: An array that specifies the data lanes enabled.
+ <1 1 0 0> = data lanes 1 and 2 are enabled.(default).
+- qcom,mdss-pan-dsi-t-clk: An array that specifies the byte clock cycles
+ before and after each mode switch.
+- qcom,mdss-pan-dsi-stream: Specifies the packet stream to be used.
+ 0 = stream 0 (default)
+ 1 = stream 1
+- qcom,mdss-pan-dsi-mdp-tr: Specifies the trigger mechanism to be used for MDP path.
+ 0 = no trigger
+ 2 = Tear check signal line used for trigger
+ 4 = Triggered by software (default mode)
+ 6 = Software trigger and TE
+- qcom,mdss-pan-dsi-dma-tr: Specifies the trigger mechanism to be used for DMA path.
+ 0 = no trigger
+ 2 = Tear check signal line used for trigger
+ 4 = Triggered by software (default mode)
+ 5 = Software trigger and start/end of frame trigger.
+ 6 = Software trigger and TE
+- qcom,mdss-pan-dsi-frame-rate: Specifies the frame rate for the panel.
+ 60 = 60 frames per second (default)
+
+Note, if a given optional qcom,* binding is not present, then the driver will configure
+the default values specified.
+
+Example:
+ qcom,mdss_dsi@fd922800 {
+
+ qcom,mdss_dsi_sim_video {
+ compatible = "qcom,mdss-dsi-panel";
+ label = "simulator video mode dsi panel";
+ status = "disable";
+ qcom,mdss-pan-res = <640 480>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-porch-values = <6 2 6 6 2 6>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 15>;
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+ qcom,mdss-pan-dsi-h-power-stop = <1 1 1>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <0>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-t-clk = <0x24 0x03>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x04>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-frame-rate = <60>;
+ qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+ qcom,panel-off-cmds = [22 01 00 00 00 00 00];
+ };
+
+ };
diff --git a/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
index 1549f10..e212aca 100644
--- a/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
+++ b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
@@ -18,6 +18,7 @@
"ocmem_irq" corresponds to OCMEM Error Interrupt.
"dm_irq" corresponds to DM Interrupt.
- qcom,ocmem-num-regions: The number of OCMEM hardware memory regions.
+- qcom,resource-type: The hardware resource type of the OCMEM core.
In addition to the information on the OCMEM core, the
device tree contains additional information describing partitions
@@ -51,6 +52,7 @@
interrupts = <0 76 0 0 77 0>;
interrupt-names = "ocmem_irq", "dm_irq";
qcom,ocmem-num-regions = <0x3>;
+ qcom,resource-type = <0x706d636f>
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0xfec00000 0x180000>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 70c85c6..f144421 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -216,6 +216,7 @@
interrupts = <0 163 0 0 164 0>;
interrupt-names = "slimbus_irq", "slimbus_bam_irq";
qcom,min-clk-gear = <10>;
+ qcom,rxreg-access;
};
spmi_bus: qcom,spmi@fc4c0000 {
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 314f91b..00325c9 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -218,7 +218,6 @@
# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
CONFIG_DIAG_CHAR=y
# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index aad13b8..5c5a152 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -238,7 +238,6 @@
CONFIG_SERIAL_MSM_HS=y
CONFIG_DIAG_CHAR=y
# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 5d19237..0efe658 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -282,7 +282,6 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
-CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 28d6e60..ca3e996 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -651,7 +651,8 @@
cpumask_copy(&mask, cpu_online_mask);
cpumask_clear_cpu(smp_processor_id(), &mask);
- smp_cross_call(&mask, IPI_CPU_STOP);
+ if (!cpumask_empty(&mask))
+ smp_cross_call(&mask, IPI_CPU_STOP);
/* Wait up to one second for other CPUs to stop */
timeout = USEC_PER_SEC;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 54f3292..1665abd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2298,6 +2298,33 @@
Enable support for On-Chip Memory available on certain MSM chipsets.
OCMEM is a low latency, high performance pool shared by subsystems.
+config MSM_OCMEM_LOCAL_POWER_CTRL
+ bool "OCMEM Local Power Control"
+ depends on MSM_OCMEM
+ help
+ Enable direct power management of the OCMEM core by the
+ OCMEM driver. By default power management is delegated to
+ the RPM. Selecting this option causes the OCMEM driver to
+ directly handle the various macro power transitions.
+
+config MSM_OCMEM_DEBUG
+ bool "OCMEM Debug Support"
+ depends on MSM_OCMEM
+ help
+ Enable debug options for On-chip Memory (OCMEM) driver.
+ Various debug options include memory, power and latency.
+ Choosing one of these options allows debugging of each
+ individual subsystem separately.
+
+config MSM_OCMEM_POWER_DEBUG
+ bool "OCMEM Power Debug Support"
+ depends on MSM_OCMEM_DEBUG
+ help
+ Enable debug support for OCMEM power management.
+ This adds support for verifying all power management
+ related operations of OCMEM. Both local power management
+ and RPM assisted power management operations are supported.
+
config MSM_RTB
bool "Register tracing"
help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index b6ce351..b96ccec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -336,7 +336,7 @@
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
-obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 639cc94..09a1be7 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -249,14 +249,16 @@
/* 8625 PLL4 @ 1209MHz with GSM capable modem */
static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1209[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
- { 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 1, 61440 },
- { 1, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 2, 61440 },
- { 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
- { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
- { 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+ { 0, 61440, ACPU_PLL_1, 1, 3, 7680, 3, 0, 61440 },
+ { 0, 122880, ACPU_PLL_1, 1, 1, 15360, 3, 1, 61440 },
+ { 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 1, 61440 },
+ { 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 2, 122880 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+ { 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+ { 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+ { 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+ { 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
{ 0 }
};
@@ -264,13 +266,14 @@
static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1209[] = {
{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
{ 0, 65536, ACPU_PLL_1, 1, 3, 8192, 3, 1, 49152 },
- { 1, 98304, ACPU_PLL_1, 1, 1, 12288, 3, 2, 49152 },
+ { 0, 98304, ACPU_PLL_1, 1, 1, 12288, 3, 2, 49152 },
{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
- { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
- { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
- { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
- { 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+ { 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+ { 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+ { 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+ { 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+ { 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
{ 0 }
};
@@ -725,7 +728,7 @@
if ((delta > drv_state.max_speed_delta_khz)
|| (strt_s->pll == ACPU_PLL_4 &&
tgt_s->pll == ACPU_PLL_4))
- clk_disable_unprepare(pll_clk[backup_s->pll].clk);
+ clk_disable(pll_clk[backup_s->pll].clk);
goto done;
}
@@ -959,17 +962,31 @@
}
}
+ if (acpu_freq_tbl == NULL) {
+ pr_crit("Unknown PLL configuration!\n");
+ BUG();
+ }
+
/*
- * When PLL4 can run max @ 1401.6MHz, we have to support
- * dynamic reprograming of PLL4.
- *
+ * Turn ON the dynamic reprogramming method
+ * if one of the table entry has pll_rate defined.
+ */
+ for ( ; t->tbl->a11clk_khz; t->tbl++) {
+ if (t->tbl->pll_rate) {
+ if (!dynamic_reprogram) {
+ dynamic_reprogram = 1;
+ pr_info("Dynamic reprogramming is ON\n");
+ }
+ }
+ }
+
+ /*
* Also find the backup pll used during PLL4 reprogramming.
* We are using PLL2@600MHz as backup PLL, since 800MHz jump
* is fine.
*/
- if (t->pll4_rate == 1401) {
- dynamic_reprogram = 1;
- for ( ; t->tbl->a11clk_khz; t->tbl++) {
+ if (dynamic_reprogram) {
+ for (t->tbl = acpu_freq_tbl; t->tbl->a11clk_khz; t->tbl++) {
if (t->tbl->pll == ACPU_PLL_2 &&
t->tbl->a11clk_src_div == 1) {
backup_s = t->tbl;
@@ -977,11 +994,6 @@
}
}
}
-
- if (acpu_freq_tbl == NULL) {
- pr_crit("Unknown PLL configuration!\n");
- BUG();
- }
}
/*
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index d6217022..da849c8 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2264,7 +2264,6 @@
&msm_bus_8064_cpss_fpb,
&apq8064_msm_device_vidc,
&msm_pil_dsps,
- &msm_8960_riva,
&msm_8960_q6_lpass,
&msm_pil_vidc,
&msm_gss,
@@ -2954,7 +2953,10 @@
platform_device_register(&apq8064_slim_ctrl);
slim_register_board_info(apq8064_slim_devices,
ARRAY_SIZE(apq8064_slim_devices));
- apq8064_init_dsps();
+ if (!PLATFORM_IS_MPQ8064()) {
+ apq8064_init_dsps();
+ platform_device_register(&msm_8960_riva);
+ }
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 658b3dc..7dd3829 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4960,14 +4960,19 @@
CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_clk_src.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_clk_src.c,
+ "msm-dai-q6.4106"),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
+ CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
+ "msm-dai-q6.4106"),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk_src", audio_core_lpaif_pcmoe_clk_src.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcmoe_clk.c, ""),
+ CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
+ "msm-dai-q6.4106"),
+ CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
+ "msm-dai-q6.4106"),
CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, "pil-q6v5-mss"),
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 8a5d0e8..a6473c6 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -26,7 +26,7 @@
#include <mach/dma.h>
#include <mach/board.h>
#include <asm/clkdev.h>
-
+#include <linux/ion.h>
#include "devices.h"
#include "footswitch.h"
@@ -963,8 +963,8 @@
};
struct msm_vidc_platform_data vidc_platform_data = {
- .memtype = MEMTYPE_EBI0,
- .enable_ion = 0,
+ .memtype = ION_CAMERA_HEAP_ID,
+ .enable_ion = 1,
.disable_dmx = 0,
.cont_mode_dpb_count = 8
};
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 2a5aa97..8566e7f 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -25,12 +25,16 @@
enum msm_pm_sleep_mode mode_nr;
};
-#ifdef CONFIG_CPU_IDLE
+#ifdef CONFIG_PM
s32 msm_cpuidle_get_deep_idle_latency(void);
+#else
+static inline s32 msm_cpuidle_get_deep_idle_latency(void) { return 0; }
+#endif
+
+#ifdef CONFIG_CPU_IDLE
int msm_cpuidle_init(void);
#else
static inline int msm_cpuidle_init(void) { return -ENOSYS; }
-static inline s32 msm_cpuidle_get_deep_idle_latency(void) { return 0; }
#endif
#ifdef CONFIG_MSM_SLEEP_STATS
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 415f8ed..904de5e 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -47,6 +47,24 @@
struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
};
+enum ocmem_power_state {
+ OCMEM_OFF = 0x0,
+ OCMEM_RETENTION,
+ OCMEM_ON,
+ OCMEM_MAX = OCMEM_ON,
+};
+
+struct ocmem_resource {
+ unsigned resource_id;
+ unsigned num_keys;
+ unsigned int *keys;
+};
+
+struct ocmem_vectors {
+ unsigned num_resources;
+ struct ocmem_resource *r;
+};
+
/* List of clients that allocate/interact with OCMEM */
/* Must be in sync with client_names */
enum ocmem_client {
@@ -120,4 +138,14 @@
int ocmem_evict(int client_id);
int ocmem_restore(int client_id);
+
+/* Power Control APIs */
+int ocmem_set_power_state(int client_id, struct ocmem_buf *buf,
+ enum ocmem_power_state new_state);
+
+enum ocmem_power_state ocmem_get_power_state(int client_id,
+ struct ocmem_buf *buf);
+
+struct ocmem_vectors *ocmem_get_vectors(int client_id,
+ struct ocmem_buf *buf);
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 70b5a45..49e283d 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -16,11 +16,11 @@
/** All interfaces in this header should only be used by OCMEM driver
* Client drivers should use wrappers available in ocmem.h
**/
-
-#include "ocmem.h"
-#include <mach/msm_iomap.h>
-#include <asm/io.h>
#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <mach/msm_iomap.h>
+#include "ocmem.h"
+
#define OCMEM_PHYS_BASE 0xFEC00000
#define OCMEM_PHYS_SIZE 0x180000
@@ -62,6 +62,13 @@
SCHED_DUMP,
};
+/* Operational modes of each region */
+enum region_mode {
+ WIDE_MODE = 0x0,
+ THIN_MODE,
+ MODE_DEFAULT = WIDE_MODE,
+};
+
struct ocmem_plat_data {
void __iomem *vbase;
unsigned long size;
@@ -77,6 +84,8 @@
int ocmem_irq;
int dm_irq;
bool interleaved;
+ bool rpm_pwr_ctrl;
+ unsigned rpm_rsc_type;
};
struct ocmem_eviction_data {
@@ -113,6 +122,8 @@
unsigned long req_start;
unsigned long req_end;
unsigned long req_sz;
+ /* Request Power State */
+ unsigned power_state;
struct ocmem_eviction_data *edata;
};
@@ -154,6 +165,18 @@
return NULL;
}
+/* Simple wrappers which will have debug features added later */
+static inline int ocmem_read(void *at)
+{
+ return readl_relaxed(at);
+}
+
+static inline int ocmem_write(unsigned long val, void *at)
+{
+ writel_relaxed(val, at);
+ return 0;
+}
+
struct ocmem_zone *get_zone(unsigned);
unsigned long offset_to_phys(unsigned long);
unsigned long phys_to_offset(unsigned long);
@@ -170,6 +193,7 @@
int ocmem_sched_init(void);
int ocmem_rdm_init(struct platform_device *);
+int ocmem_core_init(struct platform_device *);
int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
unsigned long, bool, bool);
int process_free(int, struct ocmem_handle *);
@@ -180,4 +204,6 @@
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
unsigned long process_quota(int);
+int ocmem_memory_off(int, unsigned long, unsigned long);
+int ocmem_memory_on(int, unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index e74af2e..07f3efc 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -44,7 +44,7 @@
#define MDM_PBLRDY_CNT 20
-static int mdm_debug_on;
+static int mdm_debug_mask;
static int power_on_count;
static int hsic_peripheral_status;
static DEFINE_MUTEX(hsic_status_lock);
@@ -234,7 +234,7 @@
static void debug_state_changed(int value)
{
- mdm_debug_on = value;
+ mdm_debug_mask = value;
}
static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index d1865e4..6ca9045 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -49,10 +49,11 @@
#define MDM_RDUMP_TIMEOUT 120000L
#define MDM2AP_STATUS_TIMEOUT_MS 60000L
-static int mdm_debug_on;
+static unsigned int mdm_debug_mask;
static struct workqueue_struct *mdm_queue;
static struct workqueue_struct *mdm_sfr_queue;
static unsigned int dump_timeout_ms;
+static int vddmin_gpios_sent;
#define EXTERNAL_MODEM "external_modem"
@@ -100,6 +101,7 @@
if (!vddmin_res)
return;
+ pr_info("Enabling vddmin logging\n");
req.id = vddmin_res->rpm_id;
req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
<< 16;
@@ -108,7 +110,7 @@
msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
- /* Monitor low power gpio from mdm */
+ /* Start monitoring low power gpio from mdm */
irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
if (irq < 0) {
pr_err("%s: could not get LPM POWER IRQ resource.\n",
@@ -478,23 +480,33 @@
.name = EXTERNAL_MODEM,
};
-static int mdm_debug_on_set(void *data, u64 val)
+/* Once the gpios are sent to RPM and debugging
+ * starts, there is no way to stop it without
+ * rebooting the device.
+ */
+static int mdm_debug_mask_set(void *data, u64 val)
{
- mdm_debug_on = val;
+ if (!vddmin_gpios_sent &&
+ (val & MDM_DEBUG_MASK_VDDMIN_SETUP)) {
+ mdm_setup_vddmin_gpios();
+ vddmin_gpios_sent = 1;
+ }
+
+ mdm_debug_mask = val;
if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+ mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
return 0;
}
-static int mdm_debug_on_get(void *data, u64 *val)
+static int mdm_debug_mask_get(void *data, u64 *val)
{
- *val = mdm_debug_on;
+ *val = mdm_debug_mask;
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
- mdm_debug_on_get,
- mdm_debug_on_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_mask_fops,
+ mdm_debug_mask_get,
+ mdm_debug_mask_set, "%llu\n");
static int mdm_debugfs_init(void)
{
@@ -504,8 +516,8 @@
if (IS_ERR(dent))
return PTR_ERR(dent);
- debugfs_create_file("debug_on", 0644, dent, NULL,
- &mdm_debug_on_fops);
+ debugfs_create_file("debug_mask", 0644, dent, NULL,
+ &mdm_debug_mask_fops);
return 0;
}
@@ -601,7 +613,7 @@
mdm_modem_initialize_data(pdev, p_mdm_cb);
if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+ mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
@@ -737,8 +749,6 @@
*/
if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
- /* Register VDDmin gpios with RPM */
- mdm_setup_vddmin_gpios();
/* Perform early powerup of the external modem in order to
* allow tabla devices to be found.
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 7aba83d..d1e85d3 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -13,6 +13,7 @@
#ifndef _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
+#define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
struct mdm_modem_drv;
struct mdm_ops {
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 753f6fb..a9c3f4c 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -24,14 +24,8 @@
#include <linux/seq_file.h>
#include <mach/ocmem_priv.h>
-/* This code is to temporarily work around the default state of OCMEM
- regions in Virtio. These registers will be read from DT in a subsequent
- patch which initializes the regions to appropriate default state.
-*/
-
#define OCMEM_REGION_CTL_BASE 0xFDD0003C
#define OCMEM_REGION_CTL_SIZE 0xFD0
-#define REGION_ENABLE 0x00003333
#define GRAPHICS_REGION_CTL (0x17F000)
struct ocmem_partition {
@@ -269,6 +263,30 @@
return i;
}
+#if defined(CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL)
+static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
+ struct device_node *node)
+{
+ pdata->rpm_pwr_ctrl = false;
+ pdata->rpm_rsc_type = ~0x0;
+ return 0;
+}
+#else
+static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
+ struct device_node *node)
+{
+ unsigned rsc_type = ~0x0;
+ pdata->rpm_pwr_ctrl = false;
+ if (of_property_read_u32(node, "qcom,resource-type",
+ &rsc_type))
+ return -EINVAL;
+ pdata->rpm_pwr_ctrl = true;
+ pdata->rpm_rsc_type = rsc_type;
+ return 0;
+
+}
+#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -393,6 +411,11 @@
} else
dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
+ if (parse_power_ctrl_config(pdata, node)) {
+ dev_err(dev, "No OCMEM RPM Resource specified\n");
+ return NULL;
+ }
+
pdata->nr_parts = nr_parts;
pdata->parts = parts;
pdata->nr_regions = nr_regions;
@@ -516,6 +539,9 @@
platform_set_drvdata(pdev, ocmem_pdata);
+ if (ocmem_core_init(pdev))
+ return -EBUSY;
+
if (ocmem_zone_init(pdev))
return -EBUSY;
@@ -529,10 +555,7 @@
OCMEM_REGION_CTL_SIZE);
if (!ocmem_region_vbase)
return -EBUSY;
- /* Enable all the 3 regions until we have support for power features */
- writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
- writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
- writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
+
/* Enable the ocmem graphics mpU as a workaround in Virtio */
/* This will be programmed by TZ after TZ support is integrated */
writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index bb32fca..a5aed5e 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -399,3 +399,22 @@
mutex_unlock(&ocmem_eviction_lock);
return ret;
}
+
+/* Wrappers until power control is transitioned to clients */
+enum ocmem_power_state ocmem_get_power_state(int client_id,
+ struct ocmem_buf *buffer)
+{
+ return 0;
+}
+
+int ocmem_set_power_state(int client_id, struct ocmem_buf *buffer,
+ enum ocmem_power_state new_state)
+{
+ return 0;
+}
+
+struct ocmem_vectors *ocmem_get_vectors(int client_id,
+ struct ocmem_buf *buffer)
+{
+ return NULL;
+}
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
new file mode 100644
index 0000000..019f59f
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -0,0 +1,708 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/debugfs.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <mach/ocmem_priv.h>
+#include <mach/rpm-smd.h>
+
+static unsigned num_regions;
+static unsigned num_macros;
+static unsigned num_ports;
+static unsigned num_banks;
+
+static unsigned long macro_size;
+static unsigned long region_size;
+
+static bool rpm_power_control;
+
+struct ocmem_hw_macro {
+ atomic_t m_on[OCMEM_CLIENT_MAX];
+ atomic_t m_retain[OCMEM_CLIENT_MAX];
+ unsigned m_state;
+};
+
+struct ocmem_hw_region {
+ unsigned psgsc_ctrl;
+ bool interleaved;
+ unsigned int mode;
+ unsigned int num_macros;
+ struct ocmem_hw_macro *macro;
+ struct msm_rpm_request *rpm_req;
+ unsigned r_state;
+};
+
+static struct ocmem_hw_region *region_ctrl;
+static struct mutex region_ctrl_lock;
+static void *ocmem_base;
+
+#define OCMEM_V1_REGIONS 3
+#define OCMEM_V1_MACROS 8
+
+#define OC_HW_VERS (0x0)
+#define OC_HW_PROFILE (0x4)
+#define OC_GEN_STATUS (0xC)
+#define OC_PSGSC_STATUS (0x38)
+#define OC_PSGSC_CTL (0x3C)
+#define OC_REGION_CTL (0x1000)
+
+#define NUM_PORTS_MASK (0xF << 0)
+#define NUM_PORTS_SHIFT (0)
+
+#define NUM_MACROS_MASK (0xF << 8)
+#define NUM_MACROS_SHIFT (8)
+
+#define INTERLEAVING_MASK (0x1 << 17)
+#define INTERLEAVING_SHIFT (17)
+
+/* Power states of each memory macro */
+#define PASSTHROUGH (0x0)
+#define CORE_ON (0x2)
+#define PERI_ON (0x1)
+#define CLK_OFF (0x4)
+#define MACRO_ON (CORE_ON|PERI_ON)
+#define MACRO_SLEEP_RETENTION (CLK_OFF|CORE_ON)
+#define MACRO_SLEEP_RETENTION_PERI_ON (CLK_OFF|MACRO_ON)
+#define MACRO_OFF (CLK_OFF)
+
+#define M_PSCGC_CTL_n(x) (0x7 << (x * 4))
+
+#define PSCGC_CTL_IDX(x) ((x) * 0x4)
+#define PSCGC_CTL_n(x) (OC_PSGSC_CTL + (PSCGC_CTL_IDX(x)))
+
+/* Power states of each ocmem region */
+#define REGION_NORMAL_PASSTHROUGH 0x00000000
+#define REGION_FORCE_PERI_ON 0x00001111
+#define REGION_FORCE_CORE_ON 0x00002222
+#define REGION_FORCE_ALL_ON 0x00003333
+#define REGION_SLEEP_NO_RETENTION 0x00004444
+#define REGION_SLEEP_PERI_OFF 0x00006666
+#define REGION_SLEEP_PERI_ON 0x00007777
+
+#define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
+#define REGION_DEFAULT_ON REGION_FORCE_ALL_ON
+#define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
+
+enum rpm_macro_state {
+ rpm_macro_off = 0x0,
+ rpm_macro_retain,
+ rpm_macro_on,
+};
+
+static int rpm_write(unsigned long val, unsigned id);
+
+static inline unsigned hw_macro_state(unsigned region_state)
+{
+ unsigned macro_state;
+
+ switch (region_state) {
+ case REGION_DEFAULT_ON:
+ macro_state = MACRO_ON;
+ break;
+ case REGION_DEFAULT_OFF:
+ macro_state = MACRO_OFF;
+ break;
+ case REGION_DEFAULT_RETENTION:
+ macro_state = MACRO_SLEEP_RETENTION;
+ break;
+ default:
+ macro_state = MACRO_OFF;
+ break;
+ }
+ return macro_state;
+}
+
+static inline unsigned rpm_macro_state(unsigned hw_macro_state)
+{
+ unsigned macro_state;
+
+ switch (hw_macro_state) {
+ case MACRO_ON:
+ macro_state = rpm_macro_on;
+ break;
+ case MACRO_OFF:
+ macro_state = rpm_macro_off;
+ break;
+ case MACRO_SLEEP_RETENTION:
+ macro_state = rpm_macro_retain;
+ break;
+ default:
+ macro_state = rpm_macro_off;
+ break;
+ }
+ return macro_state;
+}
+
+/* Generic wrapper that sets the region state either
+ by a direct write or through appropriate RPM call
+*/
+/* Must be called with region mutex held */
+static int commit_region_state(unsigned region_num)
+{
+ int rc = -1;
+ unsigned new_state;
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ new_state = region_ctrl[region_num].r_state;
+ pr_debug("ocmem: commit region (%d) new state %x\n", region_num,
+ new_state);
+ if (rpm_power_control)
+ rc = rpm_write(new_state, region_num);
+ else
+ rc = ocmem_write(new_state,
+ ocmem_base + PSCGC_CTL_n(region_num));
+ return 0;
+}
+
+/* Returns the current state of a OCMEM region */
+/* Must be called with region mutex held */
+static int read_region_state(unsigned region_num)
+{
+ int state;
+
+ pr_debug("rpm_get_region_state: #: %d\n", region_num);
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ if (rpm_power_control)
+ state = region_ctrl[region_num].r_state;
+ else
+ state = ocmem_read(ocmem_base + PSCGC_CTL_n(region_num));
+
+ pr_debug("ocmem: region (%d) state %x\n", region_num, state);
+
+ return state;
+}
+
+/* Returns the current state of a OCMEM macro that belongs to a region */
+static int read_macro_state(unsigned region_num, unsigned macro_num)
+{
+ int state;
+
+ if (macro_num >= num_banks)
+ return -EINVAL;
+
+ state = read_region_state(region_num);
+
+ if (state < 0)
+ return -EINVAL;
+
+ state &= M_PSCGC_CTL_n(macro_num);
+ state = state >> (macro_num * 4);
+
+ pr_debug("rpm_get_macro_state: macro (%d) region (%d) state %x\n",
+ macro_num, region_num, state);
+
+ return state;
+}
+
+static int apply_macro_vote(int id, unsigned region_num,
+ unsigned macro_num, int new_state)
+{
+ struct ocmem_hw_macro *m = NULL;
+ struct ocmem_hw_region *region = NULL;
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ if (macro_num >= num_banks)
+ return -EINVAL;
+
+ region = ®ion_ctrl[region_num];
+
+ m = ®ion->macro[macro_num];
+
+ pr_debug("m (%d): curr state %x votes (on: %d retain %d) new state %x\n",
+ macro_num, m->m_state,
+ atomic_read(&m->m_on[id]),
+ atomic_read(&m->m_retain[id]),
+ new_state);
+
+ switch (m->m_state) {
+ case MACRO_OFF:
+ if (new_state == MACRO_ON)
+ atomic_inc(&m->m_on[id]);
+ break;
+ case MACRO_ON:
+ if (new_state == MACRO_OFF) {
+ atomic_dec(&m->m_on[id]);
+ } else if (new_state == MACRO_SLEEP_RETENTION) {
+ atomic_inc(&m->m_retain[id]);
+ atomic_dec(&m->m_on[id]);
+ }
+ break;
+ case MACRO_SLEEP_RETENTION:
+ if (new_state == MACRO_OFF) {
+ atomic_dec(&m->m_retain[id]);
+ } else if (new_state == MACRO_ON) {
+ atomic_inc(&m->m_on[id]);
+ atomic_dec(&m->m_retain[id]);
+ }
+ break;
+ }
+
+ pr_debug("macro (%d) region (%d) votes for %d (on: %d retain %d)\n",
+ region_num, macro_num, id,
+ atomic_read(&m->m_on[id]),
+ atomic_read(&m->m_retain[id]));
+ return 0;
+}
+
+static int aggregate_macro_state(unsigned region_num, unsigned macro_num)
+{
+ struct ocmem_hw_macro *m = NULL;
+ struct ocmem_hw_region *region = NULL;
+ int i = 0;
+ /* The default is for the macro to be OFF */
+ unsigned m_state = MACRO_OFF;
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ if (macro_num >= num_banks)
+ return -EINVAL;
+
+ region = ®ion_ctrl[region_num];
+ m = ®ion->macro[macro_num];
+
+ for (i = 0; i < OCMEM_CLIENT_MAX; i++) {
+ if (atomic_read(&m->m_on[i]) > 0) {
+ /* atleast one client voted for ON state */
+ m_state = MACRO_ON;
+ goto done_aggregation;
+ } else if (atomic_read(&m->m_retain[i]) > 0) {
+ m_state = MACRO_SLEEP_RETENTION;
+ /* continue and examine votes of other clients */
+ }
+ }
+done_aggregation:
+ m->m_state = m_state;
+ pr_debug("macro (%d) region (%d) aggregated state %x", macro_num,
+ region_num, m->m_state);
+ return 0;
+}
+
+static int aggregate_region_state(unsigned region_num)
+{
+ struct ocmem_hw_region *region = NULL;
+ unsigned r_state;
+ unsigned i = 0;
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ region = ®ion_ctrl[region_num];
+ r_state = REGION_DEFAULT_OFF;
+
+ /* In wide mode all macros must have the same state */
+ if (region->mode == WIDE_MODE) {
+ for (i = 0; i < region->num_macros; i++) {
+ if (region->macro[i].m_state == MACRO_ON) {
+ r_state = REGION_DEFAULT_ON;
+ break;
+ } else if (region->macro[i].m_state ==
+ MACRO_SLEEP_RETENTION) {
+ r_state = REGION_DEFAULT_RETENTION;
+ }
+ }
+ } else {
+ /* In narrow mode each macro is allowed to be in a different state */
+ /* The region mode is simply the collection of all macro states */
+ for (i = 0; i < region->num_macros; i++) {
+ r_state &= ~M_PSCGC_CTL_n(i);
+ r_state |= region->macro[i].m_state << (i * 4);
+ }
+ }
+
+ pr_debug("region (%d) curr state (%x) aggregated state (%x)\n",
+ region_num, region->r_state, r_state);
+ region->r_state = r_state;
+ return 0;
+}
+
+static int rpm_write(unsigned long val, unsigned id)
+{
+ int i = 0;
+ int ret = 0;
+ struct ocmem_hw_region *region;
+
+ region = ®ion_ctrl[id];
+
+ for (i = 0; i < region->num_macros; i++) {
+ unsigned macro_state;
+ unsigned rpm_state;
+
+ macro_state = read_macro_state(id, i);
+ rpm_state = rpm_macro_state(macro_state);
+
+ if (val == REGION_DEFAULT_ON) {
+ pr_debug("macro (%d) region (%d) -> active\n",
+ i, id);
+ rpm_state = rpm_macro_on;
+ }
+
+ if (val == REGION_DEFAULT_OFF) {
+ pr_debug("macro (%d) region (%d) -> off\n",
+ i, id);
+ rpm_state = rpm_macro_off;
+ }
+
+ ret = msm_rpm_add_kvp_data(region->rpm_req, i,
+ (u8 *) &rpm_state, 4);
+
+ if (ret < 0) {
+ pr_err("ocmem: Error adding key %d val %d on rsc %d\n",
+ i, rpm_state, id);
+ return -EINVAL;
+ }
+ }
+
+ ret = msm_rpm_send_request(region->rpm_req);
+
+ if (ret < 0) {
+ pr_err("ocmem: Error sending RPM request\n");
+ return -EINVAL;
+ }
+
+ pr_debug("Transmit request to rpm for region %d\n", id);
+ return 0;
+}
+
+
+#if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
+
+static int read_hw_region_state(unsigned region_num)
+{
+ int state;
+
+ pr_debug("rpm_get_region_state: #: %d\n", region_num);
+
+ if (region_num >= num_regions)
+ return -EINVAL;
+
+ state = ocmem_read(ocmem_base + PSCGC_CTL_n(region_num));
+
+ pr_debug("ocmem: region (%d) state %x\n", region_num, state);
+
+ return state;
+}
+
+int ocmem_region_toggle(unsigned int r_num)
+{
+ unsigned reboot_state = ~0x0;
+ unsigned m_num = 0;
+
+ mutex_lock(®ion_ctrl_lock);
+ /* Turn on each macro at boot for quick hw sanity check */
+ reboot_state = read_hw_region_state(r_num);
+
+ if (reboot_state != REGION_DEFAULT_OFF) {
+ pr_err("Region %d not in power off state (%x)\n",
+ r_num, reboot_state);
+ goto toggle_fail;
+ }
+
+ for (m_num = 0; m_num < num_banks; m_num++) {
+ apply_macro_vote(0, r_num, m_num, MACRO_ON);
+ aggregate_macro_state(r_num, m_num);
+ }
+
+ aggregate_region_state(r_num);
+ commit_region_state(r_num);
+
+ reboot_state = read_hw_region_state(r_num);
+
+ if (reboot_state != REGION_DEFAULT_ON) {
+ pr_err("Failed to power on Region %d(state:%x)\n",
+ r_num, reboot_state);
+ goto toggle_fail;
+ }
+
+ /* Turn off all memory macros again */
+
+ for (m_num = 0; m_num < num_banks; m_num++) {
+ apply_macro_vote(0, r_num, m_num, MACRO_OFF);
+ aggregate_macro_state(r_num, m_num);
+ }
+
+ aggregate_region_state(r_num);
+ commit_region_state(r_num);
+
+ reboot_state = read_hw_region_state(r_num);
+
+ if (reboot_state != REGION_DEFAULT_OFF) {
+ pr_err("Failed to power off Region %d(state:%x)\n",
+ r_num, reboot_state);
+ goto toggle_fail;
+ }
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+
+toggle_fail:
+ mutex_unlock(®ion_ctrl_lock);
+ return -EINVAL;
+}
+
+int memory_is_off(unsigned int num)
+{
+ if (read_hw_region_state(num) == REGION_DEFAULT_OFF)
+ return 1;
+ else
+ return 0;
+}
+
+#else
+int ocmem_region_toggle(unsigned int region_num)
+{
+ return 0;
+}
+
+int memory_is_off(unsigned int num)
+{
+ return 0;
+}
+#endif /* CONFIG_MSM_OCMEM_POWER_DEBUG */
+
+/* Memory Macro Power Transition Sequences
+ * Normal to Sleep With Retention:
+ REGION_DEFAULT_ON -> REGION_DEFAULT_RETENTION
+ * Sleep With Retention to Normal:
+ REGION_DEFAULT_RETENTION -> REGION_FORCE_CORE_ON -> REGION_DEFAULT_ON
+ * Normal to OFF:
+ REGION_DEFAULT_ON -> REGION_DEFAULT_OFF
+ * OFF to Normal:
+ REGION_DEFAULT_OFF -> REGION_DEFAULT_ON
+**/
+
+static int switch_power_state(int id, unsigned long offset, unsigned long len,
+ unsigned new_state)
+{
+ unsigned region_start = num_regions;
+ unsigned region_end = num_regions;
+ unsigned curr_state = 0x0;
+ int i = 0;
+ int j = 0;
+ unsigned start_m = num_banks;
+ unsigned end_m = num_banks;
+ unsigned long region_offset = 0;
+
+ if (offset < 0)
+ return -EINVAL;
+
+ if (len < macro_size)
+ return -EINVAL;
+
+
+ pr_debug("ocmem: power_transition to %x for client %d\n", new_state,
+ id);
+
+ region_start = offset / region_size;
+ region_end = (offset + len - 1) / region_size;
+
+ pr_debug("ocmem: region start %u end %u\n", region_start, region_end);
+
+ if (region_start >= num_regions ||
+ (region_end >= num_regions))
+ return -EINVAL;
+
+ mutex_lock(®ion_ctrl_lock);
+
+ for (i = region_start; i <= region_end; i++) {
+
+ curr_state = read_region_state(i);
+
+ switch (curr_state) {
+ case REGION_DEFAULT_OFF:
+ if (new_state != REGION_DEFAULT_ON)
+ goto invalid_transition;
+ break;
+ case REGION_DEFAULT_RETENTION:
+ if (new_state != REGION_DEFAULT_ON)
+ goto invalid_transition;
+ break;
+ default:
+ break;
+ }
+
+ if (len >= region_size) {
+ pr_debug("switch: entire region (%d)\n", i);
+ start_m = 0;
+ end_m = num_banks;
+ } else {
+ region_offset = offset - (i * region_size);
+ start_m = region_offset / macro_size;
+ end_m = (region_offset + len - 1) / macro_size;
+ pr_debug("switch: macro (%u to %u)\n", start_m, end_m);
+ }
+
+ for (j = start_m; j <= end_m; j++) {
+ pr_debug("vote: macro (%d) region (%d)\n", j, i);
+ apply_macro_vote(id, i, j,
+ hw_macro_state(new_state));
+ aggregate_macro_state(i, j);
+ }
+ aggregate_region_state(i);
+ commit_region_state(i);
+ len -= region_size;
+
+ /* If we voted ON/retain the banks must never be OFF */
+ if (new_state != REGION_DEFAULT_OFF) {
+ if (memory_is_off(i)) {
+ pr_err("ocmem: Accessing memory during sleep\n");
+ WARN_ON(1);
+ }
+ }
+
+ }
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+invalid_transition:
+ mutex_unlock(®ion_ctrl_lock);
+ pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
+ pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
+ offset, len, curr_state, new_state);
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+/* Interfaces invoked from the scheduler */
+int ocmem_memory_off(int id, unsigned long offset, unsigned long len)
+{
+ return switch_power_state(id, offset, len, REGION_DEFAULT_OFF);
+}
+
+int ocmem_memory_on(int id, unsigned long offset, unsigned long len)
+{
+ return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
+}
+
+int ocmem_memory_retain(int id, unsigned long offset, unsigned long len)
+{
+ return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
+}
+
+int ocmem_core_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ocmem_plat_data *pdata = NULL;
+ unsigned hw_ver;
+ bool interleaved;
+ unsigned i, j, k;
+ unsigned rsc_type = 0;
+
+ pdata = platform_get_drvdata(pdev);
+ ocmem_base = pdata->reg_base;
+
+ hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);
+
+ if (pdata->nr_regions != OCMEM_V1_REGIONS) {
+ pr_err("Invalid number of regions (%d)\n", pdata->nr_regions);
+ goto hw_not_supported;
+ }
+
+ num_macros = (hw_ver & NUM_MACROS_MASK) >> NUM_MACROS_SHIFT;
+ num_ports = (hw_ver & NUM_PORTS_MASK) >> NUM_PORTS_SHIFT;
+
+ if (num_macros != OCMEM_V1_MACROS) {
+ pr_err("Invalid number of macros (%d)\n", pdata->nr_macros);
+ goto hw_not_supported;
+ }
+
+ interleaved = (hw_ver & INTERLEAVING_MASK) >> INTERLEAVING_SHIFT;
+
+ if (interleaved == false) {
+ pr_err("Interleaving is disabled\n");
+ goto hw_not_supported;
+ }
+
+ num_regions = pdata->nr_regions;
+
+ pdata->interleaved = true;
+ pdata->nr_macros = num_macros;
+ pdata->nr_ports = num_ports;
+ macro_size = SZ_64K;
+ region_size = macro_size * num_ports;
+ num_banks = num_ports / 2;
+ rsc_type = pdata->rpm_rsc_type;
+
+ pr_debug("ocmem_core: ports %d regions %d macros %d interleaved %d\n",
+ num_ports, num_regions, num_macros,
+ interleaved);
+
+ region_ctrl = devm_kzalloc(dev, sizeof(struct ocmem_hw_region)
+ * num_regions, GFP_KERNEL);
+
+ if (!region_ctrl) {
+ pr_err("ocmem: Unable to allocate memory\n");
+ return -EINVAL;
+ }
+
+ mutex_init(®ion_ctrl_lock);
+
+ for (i = 0 ; i < num_regions; i++) {
+ struct ocmem_hw_region *region = ®ion_ctrl[i];
+ struct msm_rpm_request *req = NULL;
+ region->interleaved = interleaved;
+ region->mode = MODE_DEFAULT;
+ region->r_state = REGION_DEFAULT_OFF;
+ region->num_macros = num_banks;
+
+ region->macro = devm_kzalloc(dev,
+ sizeof(struct ocmem_hw_macro) *
+ num_banks, GFP_KERNEL);
+ if (!region->macro) {
+ pr_err("ocmem: Unable to allocate memory\n");
+ return -EINVAL;
+ }
+
+ for (j = 0; j < num_banks; j++) {
+ struct ocmem_hw_macro *m = ®ion->macro[j];
+ m->m_state = MACRO_OFF;
+ for (k = 0; k < OCMEM_CLIENT_MAX; k++) {
+ atomic_set(&m->m_on[k], 0);
+ atomic_set(&m->m_retain[k], 0);
+ }
+ }
+
+ if (pdata->rpm_pwr_ctrl) {
+ rpm_power_control = true;
+ req = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET,
+ rsc_type, i, num_banks);
+
+ if (!req) {
+ pr_err("Unable to create RPM request\n");
+ return -EINVAL;
+ }
+
+ pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
+ rsc_type, i, num_banks);
+
+ region->rpm_req = req;
+ }
+
+ if (ocmem_region_toggle(i)) {
+ pr_err("Failed to verify region %d\n", i);
+ goto hw_not_supported;
+ }
+
+ }
+ return 0;
+hw_not_supported:
+ pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
+ return -EINVAL;
+}
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 6b93d04..5649021 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -109,19 +109,6 @@
unsigned int ctrl;
} dm_table[RDM_MAX_ENTRIES];
-/* Wrapper that will shadow these values later */
-static int ocmem_read(void *at)
-{
- return readl_relaxed(at);
-}
-
-/* Wrapper that will shadow these values later */
-static int ocmem_write(unsigned long val, void *at)
-{
- writel_relaxed(val, at);
- return 0;
-}
-
static inline int client_ctrl_id(int id)
{
return (id == OCMEM_SENSORS) ? 1 : 0;
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index f6d066d..70e6860 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1083,6 +1083,7 @@
static int process_grow(struct ocmem_req *req)
{
int rc = 0;
+ unsigned long offset = 0;
/* Attempt to grow the region */
rc = do_grow(req);
@@ -1097,6 +1098,15 @@
return -EINVAL;
}
+ offset = phys_to_offset(req->req_start);
+
+ rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+ if (rc < 0) {
+ pr_err("Failed to switch ON memory macros\n");
+ goto power_ctl_error;
+ }
+
/* Notify the client about the buffer growth */
rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
if (rc < 0) {
@@ -1105,6 +1115,8 @@
BUG();
}
return 0;
+power_ctl_error:
+ return -EINVAL;
}
static int do_shrink(struct ocmem_req *req, unsigned long shrink_size)
@@ -1187,6 +1199,7 @@
{
struct ocmem_req *req = NULL;
struct ocmem_buf *buffer = NULL;
+ unsigned long offset = 0;
int rc = 0;
if (is_blocked(id)) {
@@ -1211,6 +1224,20 @@
return -EINVAL;
}
+
+ if (req->req_sz != 0) {
+
+ offset = phys_to_offset(req->req_start);
+
+ rc = ocmem_memory_off(req->owner, offset, req->req_sz);
+
+ if (rc < 0) {
+ pr_err("Failed to switch OFF memory macros\n");
+ return -EINVAL;
+ }
+
+ }
+
rc = do_free(req);
if (rc < 0)
@@ -1244,7 +1271,6 @@
event = (rc == 0) ? OCMEM_MAP_DONE : OCMEM_MAP_FAIL;
else
event = (rc == 0) ? OCMEM_UNMAP_DONE : OCMEM_UNMAP_FAIL;
-
up_write(&req->rw_sem);
kfree(work_data);
dispatch_notification(id, event, buffer);
@@ -1300,6 +1326,7 @@
goto transfer_out_error;
}
+
return 0;
transfer_out_error:
@@ -1538,6 +1565,7 @@
struct ocmem_req *req = NULL;
struct ocmem_buf *buffer = NULL;
int rc = 0;
+ unsigned long offset = 0;
/* sanity checks */
if (is_blocked(id)) {
@@ -1579,8 +1607,21 @@
goto map_error;
}
+ if (req->req_sz != 0) {
+
+ offset = phys_to_offset(req->req_start);
+
+ rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+ if (rc < 0) {
+ pr_err("Failed to switch ON memory macros\n");
+ goto power_ctl_error;
+ }
+ }
+
return 0;
+power_ctl_error:
map_error:
handle->req = NULL;
do_free(req);
@@ -1595,6 +1636,7 @@
struct ocmem_handle *handle = NULL;
int rc = 0;
int id = req->owner;
+ unsigned long offset = 0;
handle = req_to_handle(req);
BUG_ON(handle == NULL);
@@ -1611,6 +1653,18 @@
goto map_error;
}
+ if (req->req_sz != 0) {
+
+ offset = phys_to_offset(req->req_start);
+
+ rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+ if (rc < 0) {
+ pr_err("Failed to switch ON memory macros\n");
+ goto power_ctl_error;
+ }
+ }
+
/* Notify the client about the buffer growth */
rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
if (rc < 0) {
@@ -1620,6 +1674,7 @@
}
return 0;
+power_ctl_error:
map_error:
handle->req = NULL;
do_free(req);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 86fe3f5..5ba3778 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1822,7 +1822,8 @@
if (state) {
adreno_regwrite(device, REG_RBBM_INT_CNTL, RBBM_INT_MASK);
adreno_regwrite(device, REG_CP_INT_CNTL, CP_INT_MASK);
- adreno_regwrite(device, MH_INTERRUPT_MASK, KGSL_MMU_INT_MASK);
+ adreno_regwrite(device, MH_INTERRUPT_MASK,
+ kgsl_mmu_get_int_mask());
} else {
adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
adreno_regwrite(device, REG_CP_INT_CNTL, 0);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index bc6ec8e..5293d66 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -299,4 +299,14 @@
(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
}
+static inline unsigned int kgsl_mmu_get_int_mask(void)
+{
+ /* Dont enable gpummu interrupts, if iommu is enabled */
+ if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype())
+ return KGSL_MMU_INT_MASK;
+ else
+ return (MH_INTERRUPT_MASK__AXI_READ_ERROR |
+ MH_INTERRUPT_MASK__AXI_WRITE_ERROR);
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 6efba45..3504dfc 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -892,7 +892,8 @@
if (state) {
z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 3);
- z180_regwrite(device, MH_INTERRUPT_MASK, KGSL_MMU_INT_MASK);
+ z180_regwrite(device, MH_INTERRUPT_MASK,
+ kgsl_mmu_get_int_mask());
} else {
z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0);
z180_regwrite(device, MH_INTERRUPT_MASK, 0);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index e87b4bd..352e60e 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -76,12 +76,29 @@
if (psy->set_property)
return psy->set_property(psy, POWER_SUPPLY_PROP_SCOPE,
&ret);
-
return -ENXIO;
}
EXPORT_SYMBOL_GPL(power_supply_set_scope);
/**
+ * power_supply_set_supply_type - set type of the power supply
+ * @psy: the power supply to control
+ * @supply_type: sets type property of power supply
+ */
+int power_supply_set_supply_type(struct power_supply *psy,
+ enum power_supply_type supply_type)
+{
+ const union power_supply_propval ret = {supply_type,};
+
+ if (psy->set_property)
+ return psy->set_property(psy, POWER_SUPPLY_PROP_TYPE,
+ &ret);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_supply_type);
+
+/**
* power_supply_set_charge_type - set charge type of the power supply
* @psy: the power supply to control
* @enable: sets charge type property of power supply
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index ac88636..49d7c0f 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -99,7 +99,7 @@
char *dev_name;
struct device_attribute **attributes;
- /* for android_dev.enabled_functions */
+ /* for android_conf.enabled_functions */
struct list_head enabled_list;
struct android_dev *android_dev;
@@ -127,8 +127,8 @@
};
struct android_dev {
+ const char *name;
struct android_usb_function **functions;
- struct list_head enabled_functions;
struct usb_composite_dev *cdev;
struct device *dev;
@@ -143,9 +143,23 @@
struct pm_qos_request pm_qos_req_dma;
struct work_struct work;
+ /* A list of struct android_configuration */
+ struct list_head configs;
+ int configs_num;
+
+ /* A list node inside the android_dev_list */
struct list_head list_item;
- struct usb_configuration config;
+};
+
+struct android_configuration {
+ struct usb_configuration usb_config;
+
+ /* A list of the functions supported by this config */
+ struct list_head enabled_functions;
+
+ /* A list node inside the struct android_dev.configs list */
+ struct list_head list_item;
};
static struct class *android_class;
@@ -154,6 +168,10 @@
static int android_bind_config(struct usb_configuration *c);
static void android_unbind_config(struct usb_configuration *c);
static struct android_dev *cdev_to_android_dev(struct usb_composite_dev *cdev);
+static struct android_configuration *alloc_android_config
+ (struct android_dev *dev);
+static void free_android_config(struct android_dev *dev,
+ struct android_configuration *conf);
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
@@ -296,13 +314,17 @@
static void android_enable(struct android_dev *dev)
{
struct usb_composite_dev *cdev = dev->cdev;
+ struct android_configuration *conf;
if (WARN_ON(!dev->disable_depth))
return;
if (--dev->disable_depth == 0) {
- usb_add_config(cdev, &dev->config,
- android_bind_config);
+
+ list_for_each_entry(conf, &dev->configs, list_item)
+ usb_add_config(cdev, &conf->usb_config,
+ android_bind_config);
+
usb_gadget_connect(cdev->gadget);
}
}
@@ -310,12 +332,15 @@
static void android_disable(struct android_dev *dev)
{
struct usb_composite_dev *cdev = dev->cdev;
+ struct android_configuration *conf;
if (dev->disable_depth++ == 0) {
usb_gadget_disconnect(cdev->gadget);
/* Cancel pending control requests */
usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
- usb_remove_config(cdev, &dev->config);
+
+ list_for_each_entry(conf, &dev->configs, list_item)
+ usb_remove_config(cdev, &conf->usb_config);
}
}
@@ -1555,9 +1580,11 @@
struct usb_configuration *c)
{
struct android_usb_function *f;
+ struct android_configuration *conf =
+ container_of(c, struct android_configuration, usb_config);
int ret;
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
ret = f->bind_config(f, c);
if (ret) {
pr_err("%s: %s failed", __func__, f->name);
@@ -1572,25 +1599,30 @@
struct usb_configuration *c)
{
struct android_usb_function *f;
+ struct android_configuration *conf =
+ container_of(c, struct android_configuration, usb_config);
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
if (f->unbind_config)
f->unbind_config(f, c);
}
}
-static int android_enable_function(struct android_dev *dev, char *name)
+static int android_enable_function(struct android_dev *dev,
+ struct android_configuration *conf,
+ char *name)
{
struct android_usb_function **functions = dev->functions;
struct android_usb_function *f;
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {
if (f->android_dev)
- pr_err("%s cannot be enabled on two devices\n",
+ pr_err("%s already enabled in other " \
+ "configuration or device\n",
f->name);
else {
list_add_tail(&f->enabled_list,
- &dev->enabled_functions);
+ &conf->enabled_functions);
f->android_dev = dev;
return 0;
}
@@ -1606,9 +1638,20 @@
struct device_attribute *attr, char *buf)
{
struct android_dev *dev = dev_get_drvdata(pdev);
+ struct android_configuration *conf;
+
+ /*
+ * Show the wakeup attribute of the first configuration,
+ * since all configurations have the same wakeup attribute
+ */
+ if (dev->configs_num == 0)
+ return 0;
+ conf = list_entry(dev->configs.next,
+ struct android_configuration,
+ list_item);
return snprintf(buf, PAGE_SIZE, "%d\n",
- !!(dev->config.bmAttributes &
+ !!(conf->usb_config.bmAttributes &
USB_CONFIG_ATT_WAKEUP));
}
@@ -1616,6 +1659,7 @@
struct device_attribute *attr, const char *buff, size_t size)
{
struct android_dev *dev = dev_get_drvdata(pdev);
+ struct android_configuration *conf;
int enable = 0;
sscanf(buff, "%d", &enable);
@@ -1623,10 +1667,13 @@
pr_debug("android_usb: %s remote wakeup\n",
enable ? "enabling" : "disabling");
- if (enable)
- dev->config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- else
- dev->config.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+ list_for_each_entry(conf, &dev->configs, list_item)
+ if (enable)
+ conf->usb_config.bmAttributes |=
+ USB_CONFIG_ATT_WAKEUP;
+ else
+ conf->usb_config.bmAttributes &=
+ ~USB_CONFIG_ATT_WAKEUP;
return size;
}
@@ -1635,13 +1682,18 @@
functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
{
struct android_dev *dev = dev_get_drvdata(pdev);
+ struct android_configuration *conf;
struct android_usb_function *f;
char *buff = buf;
mutex_lock(&dev->mutex);
- list_for_each_entry(f, &dev->enabled_functions, enabled_list)
- buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+ list_for_each_entry(conf, &dev->configs, list_item) {
+ if (buff != buf)
+ *(buff-1) = ':';
+ list_for_each_entry(f, &conf->enabled_functions, enabled_list)
+ buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+ }
mutex_unlock(&dev->mutex);
@@ -1656,6 +1708,9 @@
{
struct android_dev *dev = dev_get_drvdata(pdev);
struct android_usb_function *f;
+ struct list_head *curr_conf = &dev->configs;
+ struct android_configuration *conf;
+ char *conf_str;
char *name;
char buf[256], *b;
int err;
@@ -1668,21 +1723,45 @@
}
/* Clear previous enabled list */
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- f->android_dev = NULL;
+ list_for_each_entry(conf, &dev->configs, list_item) {
+ list_for_each_entry(f, &conf->enabled_functions, enabled_list)
+ f->android_dev = NULL;
+ INIT_LIST_HEAD(&conf->enabled_functions);
}
- INIT_LIST_HEAD(&dev->enabled_functions);
strlcpy(buf, buff, sizeof(buf));
b = strim(buf);
while (b) {
- name = strsep(&b, ",");
- if (name) {
- err = android_enable_function(dev, name);
- if (err)
- pr_err("android_usb: Cannot enable '%s'", name);
+ conf_str = strsep(&b, ":");
+ if (conf_str) {
+ /* If the next not equal to the head, take it */
+ if (curr_conf->next != &dev->configs)
+ conf = list_entry(curr_conf->next,
+ struct android_configuration,
+ list_item);
+ else
+ conf = alloc_android_config(dev);
+
+ curr_conf = curr_conf->next;
}
+
+ while (conf_str) {
+ name = strsep(&conf_str, ",");
+ if (name) {
+ err = android_enable_function(dev, conf, name);
+ if (err)
+ pr_err("android_usb: Cannot enable %s",
+ name);
+ }
+ }
+ }
+
+ /* Free uneeded configurations if exists */
+ while (curr_conf->next != &dev->configs) {
+ conf = list_entry(curr_conf->next,
+ struct android_configuration, list_item);
+ free_android_config(dev, conf);
}
mutex_unlock(&dev->mutex);
@@ -1704,6 +1783,7 @@
struct android_dev *dev = dev_get_drvdata(pdev);
struct usb_composite_dev *cdev = dev->cdev;
struct android_usb_function *f;
+ struct android_configuration *conf;
int enabled = 0;
if (!cdev)
@@ -1723,18 +1803,22 @@
cdev->desc.bDeviceClass = device_desc.bDeviceClass;
cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- if (f->enable)
- f->enable(f);
- }
+ list_for_each_entry(conf, &dev->configs, list_item)
+ list_for_each_entry(f, &conf->enabled_functions,
+ enabled_list) {
+ if (f->enable)
+ f->enable(f);
+ }
android_enable(dev);
dev->enabled = true;
} else if (!enabled && dev->enabled) {
android_disable(dev);
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- if (f->disable)
- f->disable(f);
- }
+ list_for_each_entry(conf, &dev->configs, list_item)
+ list_for_each_entry(f, &conf->enabled_functions,
+ enabled_list) {
+ if (f->disable)
+ f->disable(f);
+ }
dev->enabled = false;
} else {
pr_err("android_usb: already %s\n",
@@ -1890,6 +1974,7 @@
{
struct android_dev *dev;
struct usb_gadget *gadget = cdev->gadget;
+ struct android_configuration *conf;
int gcnum, id, ret;
/* Bind to the last android_dev that was probed */
@@ -1938,7 +2023,8 @@
device_desc.iSerialNumber = id;
if (gadget_is_otg(cdev->gadget))
- dev->config.descriptors = otg_desc;
+ list_for_each_entry(conf, &dev->configs, list_item)
+ conf->usb_config.descriptors = otg_desc;
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
@@ -1979,6 +2065,7 @@
struct android_dev *dev = cdev_to_android_dev(cdev);
struct usb_request *req = cdev->req;
struct android_usb_function *f;
+ struct android_configuration *conf;
int value = -EOPNOTSUPP;
unsigned long flags;
@@ -1987,13 +2074,16 @@
req->length = 0;
gadget->ep0->driver_data = cdev;
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- if (f->ctrlrequest) {
- value = f->ctrlrequest(f, cdev, c);
- if (value >= 0)
- break;
- }
- }
+ list_for_each_entry(conf, &dev->configs, list_item)
+ if (&conf->usb_config == cdev->config)
+ list_for_each_entry(f,
+ &conf->enabled_functions,
+ enabled_list)
+ if (f->ctrlrequest) {
+ value = f->ctrlrequest(f, cdev, c);
+ if (value >= 0)
+ break;
+ }
/* Special case the accessory function.
* It needs to handle control requests before it is enabled.
@@ -2084,6 +2174,38 @@
return dev;
}
+static struct android_configuration *alloc_android_config
+ (struct android_dev *dev)
+{
+ struct android_configuration *conf;
+
+ conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+ if (!conf) {
+ pr_err("%s(): Failed to alloc memory for android conf\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dev->configs_num++;
+ conf->usb_config.label = dev->name;
+ conf->usb_config.unbind = android_unbind_config;
+ conf->usb_config.bConfigurationValue = dev->configs_num;
+
+ INIT_LIST_HEAD(&conf->enabled_functions);
+
+ list_add_tail(&conf->list_item, &dev->configs);
+
+ return conf;
+}
+
+static void free_android_config(struct android_dev *dev,
+ struct android_configuration *conf)
+{
+ list_del(&conf->list_item);
+ dev->configs_num--;
+ kfree(conf);
+}
+
static int __devinit android_probe(struct platform_device *pdev)
{
struct android_usb_platform_data *pdata = pdev->dev.platform_data;
@@ -2104,12 +2226,11 @@
goto err_alloc;
}
- android_dev->config.label = pdev->name;
- android_dev->config.unbind = android_unbind_config;
- android_dev->config.bConfigurationValue = 1;
+ android_dev->name = pdev->name;
android_dev->disable_depth = 1;
android_dev->functions = supported_functions;
- INIT_LIST_HEAD(&android_dev->enabled_functions);
+ android_dev->configs_num = 0;
+ INIT_LIST_HEAD(&android_dev->configs);
INIT_WORK(&android_dev->work, android_work);
mutex_init(&android_dev->mutex);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 75d92f1..5879530 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2928,30 +2928,32 @@
int mdp4_overlay_wait4vsync(struct fb_info *info, long long *vtime)
{
- if (info->node == 0) {
+ if (!hdmi_prim_display && info->node == 0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
mdp4_dsi_video_wait4vsync(0, vtime);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_wait4vsync(0, vtime);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_wait4vsync(0, vtime);
- } else if (info->node == 1)
+ } else if (hdmi_prim_display || info->node == 1) {
mdp4_dtv_wait4vsync(0, vtime);
+ }
return 0;
}
int mdp4_overlay_vsync_ctrl(struct fb_info *info, int enable)
{
- if (info->node == 0) {
+ if (!hdmi_prim_display && info->node == 0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
mdp4_dsi_video_vsync_ctrl(0, enable);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_vsync_ctrl(0, enable);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_vsync_ctrl(0, enable);
- } else if (info->node == 1)
+ } else if (hdmi_prim_display || info->node == 1) {
mdp4_dtv_vsync_ctrl(0, enable);
+ }
return 0;
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 16c5278..6445ec1 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -455,6 +455,7 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ vctrl->fake_vsync = 1;
/* mdp clock on */
mdp_clk_ctrl(1);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f857ac8..f3d9e2c 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -73,6 +73,7 @@
int dmae_wait_cnt;
int wait_vsync_cnt;
int blt_change;
+ int fake_vsync;
struct mutex update_lock;
struct completion dmae_comp;
struct completion vsync_comp;
@@ -236,6 +237,11 @@
vctrl = &vsync_ctrl_db[cndx];
+ if (vctrl->fake_vsync) {
+ vctrl->fake_vsync = 0;
+ schedule_work(&vctrl->vsync_work);
+ }
+
if (vctrl->vsync_irq_enabled == enable)
return;
@@ -521,6 +527,7 @@
return -EINVAL;
vctrl->dev = mfd->fbi->dev;
+ vctrl->fake_vsync = 1;
mdp_footswitch_ctrl(TRUE);
/* Mdp clock enable */
@@ -587,6 +594,7 @@
ret = panel_next_off(pdev);
mdp_footswitch_ctrl(FALSE);
+ vctrl->fake_vsync = 1;
/* Mdp clock disable */
mdp_clk_ctrl(0);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 2d5025b..79bb7c5 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -460,6 +460,7 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ vctrl->fake_vsync = 1;
/* mdp clock on */
mdp_clk_ctrl(1);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 492437e..b6294f4 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,4 +7,10 @@
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
+mdss-dsi-objs += mdss_dsi_panel.o
+mdss-dsi-objs += msm_mdss_io_8974.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
+
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index a58c3e6..6145d67 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -22,6 +22,7 @@
#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
extern unsigned char *mdss_reg_base;
+extern spinlock_t dsi_clk_lock;
enum mdss_mdp_clk_type {
MDSS_CLK_AHB,
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
new file mode 100644
index 0000000..d051828
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -0,0 +1,383 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+
+#include "mdss.h"
+#include "mdss_panel.h"
+#include "mdss_dsi.h"
+
+static struct mdss_panel_common_pdata *panel_pdata;
+
+static unsigned char *mdss_dsi_base;
+
+static int mdss_dsi_off(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo;
+
+ pinfo = &pdata->panel_info;
+
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+ mdss_dsi_controller_cfg(0, pdata);
+
+ mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+
+ ret = panel_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
+
+ spin_lock_bh(&dsi_clk_lock);
+ mdss_dsi_clk_disable();
+
+ /* disable dsi engine */
+ MIPI_OUTP(mdss_dsi_base + 0x0004, 0);
+
+ spin_unlock_bh(&dsi_clk_lock);
+
+ mdss_dsi_unprepare_clocks();
+
+ pr_debug("%s-:\n", __func__);
+
+ return ret;
+}
+
+static int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ u32 clk_rate;
+ struct mdss_panel_info *pinfo;
+ struct mipi_panel_info *mipi;
+ u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
+ u32 ystride, bpp, data;
+ u32 dummy_xres, dummy_yres;
+
+ pinfo = &pdata->panel_info;
+
+ cont_splash_clk_ctrl(0);
+ mdss_dsi_prepare_clocks();
+
+ spin_lock_bh(&dsi_clk_lock);
+
+ MIPI_OUTP(mdss_dsi_base + 0x118, 1);
+ MIPI_OUTP(mdss_dsi_base + 0x118, 0);
+
+ mdss_dsi_clk_enable();
+ spin_unlock_bh(&dsi_clk_lock);
+
+ clk_rate = pdata->panel_info.clk_rate;
+ clk_rate = min(clk_rate, pdata->panel_info.clk_max);
+
+ hbp = pdata->panel_info.lcdc.h_back_porch;
+ hfp = pdata->panel_info.lcdc.h_front_porch;
+ vbp = pdata->panel_info.lcdc.v_back_porch;
+ vfp = pdata->panel_info.lcdc.v_front_porch;
+ hspw = pdata->panel_info.lcdc.h_pulse_width;
+ vspw = pdata->panel_info.lcdc.v_pulse_width;
+ width = pdata->panel_info.xres;
+ height = pdata->panel_info.yres;
+
+ mipi = &pdata->panel_info.mipi;
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ dummy_xres = pdata->panel_info.lcdc.xres_pad;
+ dummy_yres = pdata->panel_info.lcdc.yres_pad;
+
+ MIPI_OUTP(mdss_dsi_base + 0x24,
+ ((hspw + hbp + width + dummy_xres) << 16 |
+ (hspw + hbp)));
+ MIPI_OUTP(mdss_dsi_base + 0x28,
+ ((vspw + vbp + height + dummy_yres) << 16 |
+ (vspw + vbp)));
+ MIPI_OUTP(mdss_dsi_base + 0x2C,
+ (vspw + vbp + height + dummy_yres +
+ vfp - 1) << 16 | (hspw + hbp +
+ width + dummy_xres + hfp - 1));
+
+ MIPI_OUTP(mdss_dsi_base + 0x30, (hspw << 16));
+ MIPI_OUTP(mdss_dsi_base + 0x34, 0);
+ MIPI_OUTP(mdss_dsi_base + 0x38, (vspw << 16));
+
+ } else { /* command mode */
+ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
+ bpp = 3;
+ else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
+ bpp = 3;
+ else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
+ bpp = 2;
+ else
+ bpp = 3; /* Default format set to RGB888 */
+
+ ystride = width * bpp + 1;
+
+ /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
+ data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
+ MIPI_OUTP(mdss_dsi_base + 0x60, data);
+ MIPI_OUTP(mdss_dsi_base + 0x58, data);
+
+ /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
+ data = height << 16 | width;
+ MIPI_OUTP(mdss_dsi_base + 0x64, data);
+ MIPI_OUTP(mdss_dsi_base + 0x5C, data);
+ }
+
+ mdss_dsi_host_init(mipi, pdata);
+
+ if (mipi->force_clk_lane_hs) {
+ u32 tmp;
+
+ tmp = MIPI_INP(mdss_dsi_base + 0xac);
+ tmp |= (1<<28);
+ MIPI_OUTP(mdss_dsi_base + 0xac, tmp);
+ wmb();
+ }
+
+ ret = panel_pdata->on(pdata);
+ if (ret) {
+ pr_err("%s: unable to initialize the panel\n", __func__);
+ return ret;
+ }
+
+ mdss_dsi_op_mode_config(mipi->mode, pdata);
+
+ pr_debug("%s-:\n", __func__);
+ return ret;
+}
+
+unsigned char *mdss_dsi_get_base_adr(void)
+{
+ return mdss_dsi_base;
+}
+
+unsigned char *mdss_dsi_get_clk_base(void)
+{
+ return mdss_dsi_base;
+}
+
+static int mdss_dsi_resource_initialized;
+
+static int __devinit mdss_dsi_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ pr_debug("%s\n", __func__);
+
+ if (pdev->dev.of_node && !mdss_dsi_resource_initialized) {
+ struct resource *mdss_dsi_mres;
+ pdev->id = 1;
+ mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mdss_dsi_mres) {
+ pr_err("%s:%d unable to get the MDSS resources",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+ if (mdss_dsi_mres) {
+ mdss_dsi_base = ioremap(mdss_dsi_mres->start,
+ resource_size(mdss_dsi_mres));
+ if (!mdss_dsi_base) {
+ pr_err("%s:%d unable to remap dsi resources",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+ }
+
+ if (mdss_dsi_clk_init(pdev)) {
+ iounmap(mdss_dsi_base);
+ return -EPERM;
+ }
+
+ rc = of_platform_populate(pdev->dev.of_node,
+ NULL, NULL, &pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: failed to add child nodes, rc=%d\n",
+ __func__, rc);
+ iounmap(mdss_dsi_base);
+ return rc;
+ }
+
+ mdss_dsi_resource_initialized = 1;
+ }
+
+ if (!mdss_dsi_resource_initialized)
+ return -EPERM;
+
+ return 0;
+}
+
+static int __devexit mdss_dsi_remove(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+ iounmap(mdss_dsi_base);
+ return 0;
+}
+
+struct device dsi_dev;
+
+int dsi_panel_device_register(struct platform_device *pdev,
+ struct mdss_panel_common_pdata *panel_data)
+{
+ struct mipi_panel_info *mipi;
+ int rc;
+ u8 lanes = 0, bpp;
+ u32 h_period, v_period, dsi_pclk_rate;
+ struct mdss_panel_data *pdata = NULL;
+
+ panel_pdata = panel_data;
+
+ h_period = ((panel_pdata->panel_info.lcdc.h_pulse_width)
+ + (panel_pdata->panel_info.lcdc.h_back_porch)
+ + (panel_pdata->panel_info.xres)
+ + (panel_pdata->panel_info.lcdc.h_front_porch));
+
+ v_period = ((panel_pdata->panel_info.lcdc.v_pulse_width)
+ + (panel_pdata->panel_info.lcdc.v_back_porch)
+ + (panel_pdata->panel_info.yres)
+ + (panel_pdata->panel_info.lcdc.v_front_porch));
+
+ mipi = &panel_pdata->panel_info.mipi;
+
+ panel_pdata->panel_info.type =
+ ((mipi->mode == DSI_VIDEO_MODE)
+ ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
+
+ if (mipi->data_lane3)
+ lanes += 1;
+ if (mipi->data_lane2)
+ lanes += 1;
+ if (mipi->data_lane1)
+ lanes += 1;
+ if (mipi->data_lane0)
+ lanes += 1;
+
+
+ if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
+ || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
+ || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
+ bpp = 3;
+ else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
+ || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
+ bpp = 2;
+ else
+ bpp = 3; /* Default format set to RGB888 */
+
+ if (panel_pdata->panel_info.type == MIPI_VIDEO_PANEL &&
+ !panel_pdata->panel_info.clk_rate) {
+ h_period += panel_pdata->panel_info.lcdc.xres_pad;
+ v_period += panel_pdata->panel_info.lcdc.yres_pad;
+
+ if (lanes > 0) {
+ panel_pdata->panel_info.clk_rate =
+ ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
+ / lanes);
+ } else {
+ pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+ panel_pdata->panel_info.clk_rate =
+ (h_period * v_period
+ * (mipi->frame_rate) * bpp * 8);
+ }
+ }
+ pll_divider_config.clk_rate = panel_pdata->panel_info.clk_rate;
+
+ rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
+ if (rc) {
+ pr_err("%s: unable to initialize the clk dividers\n", __func__);
+ return rc;
+ }
+
+ if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+ dsi_pclk_rate = 35000000;
+ mipi->dsi_pclk_rate = dsi_pclk_rate;
+
+ /*
+ * data chain
+ */
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->on = mdss_dsi_on;
+ pdata->off = mdss_dsi_off;
+ memcpy(&(pdata->panel_info), &(panel_pdata->panel_info),
+ sizeof(struct mdss_panel_info));
+
+ pdata->dsi_base = mdss_dsi_base;
+
+ /*
+ * register in mdp driver
+ */
+ rc = mdss_register_panel(pdata);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
+ devm_kfree(&pdev->dev, pdata);
+ return rc;
+ }
+
+ pr_debug("%s: Panal data initialized\n", __func__);
+ return 0;
+}
+
+static const struct of_device_id msm_mdss_dsi_dt_match[] = {
+ {.compatible = "qcom,msm-mdss-dsi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_mdss_dsi_dt_match);
+
+static struct platform_driver mdss_dsi_driver = {
+ .probe = mdss_dsi_probe,
+ .remove = __devexit_p(mdss_dsi_remove),
+ .shutdown = NULL,
+ .driver = {
+ .name = "mdss_dsi",
+ .of_match_table = msm_mdss_dsi_dt_match,
+ },
+};
+
+static int mdss_dsi_register_driver(void)
+{
+ return platform_driver_register(&mdss_dsi_driver);
+}
+
+static int __init mdss_dsi_driver_init(void)
+{
+ int ret;
+
+ mdss_dsi_init();
+
+ ret = mdss_dsi_register_driver();
+ if (ret) {
+ pr_err("mdss_dsi_register_driver() failed!\n");
+ return ret;
+ }
+
+ return ret;
+}
+module_init(mdss_dsi_driver_init);
+
+static void __exit mdss_dsi_driver_cleanup(void)
+{
+ iounmap(mdss_dsi_base);
+ platform_driver_unregister(&mdss_dsi_driver);
+}
+module_exit(mdss_dsi_driver_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DSI controller driver");
+MODULE_AUTHOR("Chandan Uddaraju <chandanu@codeaurora.org>");
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
new file mode 100644
index 0000000..57fce1a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -0,0 +1,294 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_DSI_H
+#define MDSS_DSI_H
+
+#include <linux/list.h>
+#include <mach/scm-io.h>
+
+#include "mdss_panel.h"
+
+#define MMSS_MDSS_CC_BASE_PHY 0xFD8C2300 /* mmss clcok control */
+#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
+
+#define MIPI_OUTP(addr, data) writel_relaxed((data), (addr))
+#define MIPI_INP(addr) readl_relaxed(addr)
+
+#ifdef CONFIG_MSM_SECURE_IO
+#define MIPI_OUTP_SECURE(addr, data) secure_writel((data), (addr))
+#define MIPI_INP_SECURE(addr) secure_readl(addr)
+#else
+#define MIPI_OUTP_SECURE(addr, data) writel_relaxed((data), (addr))
+#define MIPI_INP_SECURE(addr) readl_relaxed(addr)
+#endif
+
+#define MIPI_DSI_PRIM 1
+#define MIPI_DSI_SECD 2
+
+#define MIPI_DSI_PANEL_VGA 0
+#define MIPI_DSI_PANEL_WVGA 1
+#define MIPI_DSI_PANEL_WVGA_PT 2
+#define MIPI_DSI_PANEL_FWVGA_PT 3
+#define MIPI_DSI_PANEL_WSVGA_PT 4
+#define MIPI_DSI_PANEL_QHD_PT 5
+#define MIPI_DSI_PANEL_WXGA 6
+#define MIPI_DSI_PANEL_WUXGA 7
+#define MIPI_DSI_PANEL_720P_PT 8
+#define DSI_PANEL_MAX 8
+
+enum { /* mipi dsi panel */
+ DSI_VIDEO_MODE,
+ DSI_CMD_MODE,
+};
+
+enum {
+ ST_DSI_CLK_OFF,
+ ST_DSI_SUSPEND,
+ ST_DSI_RESUME,
+ ST_DSI_PLAYING,
+ ST_DSI_NUM
+};
+
+enum {
+ EV_DSI_UPDATE,
+ EV_DSI_DONE,
+ EV_DSI_TOUT,
+ EV_DSI_NUM
+};
+
+enum {
+ LANDSCAPE = 1,
+ PORTRAIT = 2,
+};
+
+enum dsi_trigger_type {
+ DSI_CMD_MODE_DMA,
+ DSI_CMD_MODE_MDP,
+};
+
+#define DSI_NON_BURST_SYNCH_PULSE 0
+#define DSI_NON_BURST_SYNCH_EVENT 1
+#define DSI_BURST_MODE 2
+
+#define DSI_RGB_SWAP_RGB 0
+#define DSI_RGB_SWAP_RBG 1
+#define DSI_RGB_SWAP_BGR 2
+#define DSI_RGB_SWAP_BRG 3
+#define DSI_RGB_SWAP_GRB 4
+#define DSI_RGB_SWAP_GBR 5
+
+#define DSI_VIDEO_DST_FORMAT_RGB565 0
+#define DSI_VIDEO_DST_FORMAT_RGB666 1
+#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE 2
+#define DSI_VIDEO_DST_FORMAT_RGB888 3
+
+#define DSI_CMD_DST_FORMAT_RGB111 0
+#define DSI_CMD_DST_FORMAT_RGB332 3
+#define DSI_CMD_DST_FORMAT_RGB444 4
+#define DSI_CMD_DST_FORMAT_RGB565 6
+#define DSI_CMD_DST_FORMAT_RGB666 7
+#define DSI_CMD_DST_FORMAT_RGB888 8
+
+#define DSI_INTR_ERROR_MASK BIT(25)
+#define DSI_INTR_ERROR BIT(24)
+#define DSI_INTR_VIDEO_DONE_MASK BIT(17)
+#define DSI_INTR_VIDEO_DONE BIT(16)
+#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9)
+#define DSI_INTR_CMD_MDP_DONE BIT(8)
+#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1)
+#define DSI_INTR_CMD_DMA_DONE BIT(0)
+
+#define DSI_CMD_TRIGGER_NONE 0x0 /* mdp trigger */
+#define DSI_CMD_TRIGGER_TE 0x02
+#define DSI_CMD_TRIGGER_SW 0x04
+#define DSI_CMD_TRIGGER_SW_SEOF 0x05 /* cmd dma only */
+#define DSI_CMD_TRIGGER_SW_TE 0x06
+
+extern struct device dsi_dev;
+extern int mdss_dsi_clk_on;
+extern u32 dsi_irq;
+
+struct dsiphy_pll_divider_config {
+ u32 clk_rate;
+ u32 fb_divider;
+ u32 ref_divider_ratio;
+ u32 bit_clk_divider; /* oCLK1 */
+ u32 byte_clk_divider; /* oCLK2 */
+ u32 analog_posDiv;
+ u32 digital_posDiv;
+};
+
+extern struct dsiphy_pll_divider_config pll_divider_config;
+
+struct dsi_clk_mnd_table {
+ u8 lanes;
+ u8 bpp;
+ u8 pll_digital_posDiv;
+ u8 pclk_m;
+ u8 pclk_n;
+ u8 pclk_d;
+};
+
+static const struct dsi_clk_mnd_table mnd_table[] = {
+ { 1, 2, 8, 1, 1, 0},
+ { 1, 3, 12, 1, 1, 0},
+ { 2, 2, 4, 1, 1, 0},
+ { 2, 3, 6, 1, 1, 0},
+ { 3, 2, 1, 3, 8, 4},
+ { 3, 3, 4, 1, 1, 0},
+ { 4, 2, 2, 1, 1, 0},
+ { 4, 3, 3, 1, 1, 0},
+};
+
+struct dsi_clk_desc {
+ u32 src;
+ u32 m;
+ u32 n;
+ u32 d;
+ u32 mnd_mode;
+ u32 pre_div_func;
+};
+
+#define DSI_HOST_HDR_SIZE 4
+#define DSI_HDR_LAST BIT(31)
+#define DSI_HDR_LONG_PKT BIT(30)
+#define DSI_HDR_BTA BIT(29)
+#define DSI_HDR_VC(vc) (((vc) & 0x03) << 22)
+#define DSI_HDR_DTYPE(dtype) (((dtype) & 0x03f) << 16)
+#define DSI_HDR_DATA2(data) (((data) & 0x0ff) << 8)
+#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
+#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
+
+#define DSI_BUF_SIZE 1024
+#define MDSS_DSI_MRPS 0x04 /* Maximum Return Packet Size */
+
+#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
+
+struct dsi_buf {
+ u32 *hdr; /* dsi host header */
+ char *start; /* buffer start addr */
+ char *end; /* buffer end addr */
+ int size; /* size of buffer */
+ char *data; /* buffer */
+ int len; /* data length */
+ dma_addr_t dmap; /* mapped dma addr */
+};
+
+/* dcs read/write */
+#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */
+#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */
+#define DTYPE_DCS_READ 0x06 /* read */
+#define DTYPE_DCS_LWRITE 0x39 /* long write */
+
+/* generic read/write */
+#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */
+#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */
+#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */
+#define DTYPE_GEN_LWRITE 0x29 /* long write */
+#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */
+#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */
+#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */
+
+#define DTYPE_TEAR_ON 0x35 /* set tear on */
+#define DTYPE_MAX_PKTSIZE 0x37 /* set max packet size */
+#define DTYPE_NULL_PKT 0x09 /* null packet, no data */
+#define DTYPE_BLANK_PKT 0x19 /* blankiing packet, no data */
+
+#define DTYPE_CM_ON 0x02 /* color mode off */
+#define DTYPE_CM_OFF 0x12 /* color mode on */
+#define DTYPE_PERIPHERAL_OFF 0x22
+#define DTYPE_PERIPHERAL_ON 0x32
+
+/*
+ * dcs response
+ */
+#define DTYPE_ACK_ERR_RESP 0x02
+#define DTYPE_EOT_RESP 0x08 /* end of tx */
+#define DTYPE_GEN_READ1_RESP 0x11 /* 1 parameter, short */
+#define DTYPE_GEN_READ2_RESP 0x12 /* 2 parameter, short */
+#define DTYPE_GEN_LREAD_RESP 0x1a
+#define DTYPE_DCS_LREAD_RESP 0x1c
+#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */
+#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */
+
+struct dsi_cmd_desc {
+ int dtype;
+ int last;
+ int vc;
+ int ack; /* ask ACK from peripheral */
+ int wait;
+ int dlen;
+ char *payload;
+};
+
+struct dsi_kickoff_action {
+ struct list_head act_entry;
+ void (*action) (void *);
+ void *data;
+};
+
+struct mdss_panel_common_pdata {
+ struct mdss_panel_info panel_info;
+ int (*on) (struct mdss_panel_data *pdata);
+ int (*off) (struct mdss_panel_data *pdata);
+};
+
+int dsi_panel_device_register(struct platform_device *pdev,
+ struct mdss_panel_common_pdata *panel_data);
+
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
+char *mdss_dsi_buf_init(struct dsi_buf *dp);
+void mdss_dsi_init(void);
+int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
+int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
+ struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
+
+int mdss_dsi_cmd_dma_tx(struct dsi_buf *dp,
+ struct mdss_panel_data *pdata);
+int mdss_dsi_cmd_reg_tx(u32 data,
+ struct mdss_panel_data *pdata);
+int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
+ struct dsi_buf *tp, struct dsi_buf *rp,
+ struct dsi_cmd_desc *cmds, int len);
+int mdss_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen,
+ struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
+ struct mdss_panel_data *pdata);
+void mdss_dsi_op_mode_config(int mode,
+ struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_mode_ctrl(int enable);
+void mdp4_dsi_cmd_trigger(void);
+void mdss_dsi_cmd_mdp_start(void);
+void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
+void mdss_dsi_ack_err_status(unsigned char *dsi_base);
+void mdss_dsi_clk_enable(void);
+void mdss_dsi_clk_disable(void);
+void mdss_dsi_controller_cfg(int enable,
+ struct mdss_panel_data *pdata);
+void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
+
+irqreturn_t mdss_dsi_isr(int irq, void *ptr);
+
+void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
+int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
+ u32 *expected_dsi_pclk);
+int mdss_dsi_clk_init(struct platform_device *pdev);
+void mdss_dsi_clk_deinit(struct device *dev);
+void mdss_dsi_prepare_clocks(void);
+void mdss_dsi_unprepare_clocks(void);
+void cont_splash_clk_ctrl(int enable);
+unsigned char *mdss_dsi_get_base_adr(void);
+
+#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
new file mode 100644
index 0000000..7bc0105
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -0,0 +1,1259 @@
+
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/iopoll.h>
+
+#include "mdss.h"
+#include "mdss_dsi.h"
+
+static struct completion dsi_dma_comp;
+static int dsi_irq_enabled;
+static spinlock_t dsi_irq_lock;
+static spinlock_t dsi_mdp_lock;
+static int dsi_mdp_busy;
+
+spinlock_t dsi_clk_lock;
+
+struct mdss_hw mdss_dsi_hw = {
+ .hw_ndx = MDSS_HW_DSI0,
+ .irq_handler = mdss_dsi_isr,
+};
+
+void mdss_dsi_init(void)
+{
+ init_completion(&dsi_dma_comp);
+ spin_lock_init(&dsi_irq_lock);
+ spin_lock_init(&dsi_mdp_lock);
+ spin_lock_init(&dsi_clk_lock);
+}
+
+void mdss_dsi_enable_irq(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dsi_irq_lock, flags);
+ if (dsi_irq_enabled) {
+ pr_debug("%s: IRQ aleady enabled\n", __func__);
+ spin_unlock_irqrestore(&dsi_irq_lock, flags);
+ return;
+ }
+ mdss_enable_irq(&mdss_dsi_hw);
+ dsi_irq_enabled = 1;
+ /* TO DO: Check whether MDSS IRQ is enabled */
+ spin_unlock_irqrestore(&dsi_irq_lock, flags);
+}
+
+void mdss_dsi_disable_irq(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dsi_irq_lock, flags);
+ if (dsi_irq_enabled == 0) {
+ pr_debug("%s: IRQ already disabled\n", __func__);
+ spin_unlock_irqrestore(&dsi_irq_lock, flags);
+ return;
+ }
+ mdss_disable_irq(&mdss_dsi_hw);
+ dsi_irq_enabled = 0;
+ /* TO DO: Check whether MDSS IRQ is Disabled */
+ spin_unlock_irqrestore(&dsi_irq_lock, flags);
+}
+
+/*
+ * mdss_dsi_disale_irq_nosync() should be called
+ * from interrupt context
+ */
+void mdss_dsi_disable_irq_nosync(void)
+{
+ spin_lock(&dsi_irq_lock);
+ if (dsi_irq_enabled == 0) {
+ pr_debug("%s: IRQ cannot be disabled\n", __func__);
+ spin_unlock(&dsi_irq_lock);
+ return;
+ }
+
+ dsi_irq_enabled = 0;
+ spin_unlock(&dsi_irq_lock);
+}
+
+/*
+ * mipi dsi buf mechanism
+ */
+char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len)
+{
+ dp->data += len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len)
+{
+ dp->data -= len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_push(struct dsi_buf *dp, int len)
+{
+ dp->data -= len;
+ dp->len += len;
+ return dp->data;
+}
+
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
+{
+ dp->hdr = (u32 *)dp->data;
+ return mdss_dsi_buf_reserve(dp, hlen);
+}
+
+char *mdss_dsi_buf_init(struct dsi_buf *dp)
+{
+ int off;
+
+ dp->data = dp->start;
+ off = (int)dp->data;
+ /* 8 byte align */
+ off &= 0x07;
+ if (off)
+ off = 8 - off;
+ dp->data += off;
+ dp->len = 0;
+ return dp->data;
+}
+
+int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
+{
+
+ dp->start = kmalloc(size, GFP_KERNEL);
+ if (dp->start == NULL) {
+ pr_err("%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ dp->end = dp->start + size;
+ dp->size = size;
+
+ if ((int)dp->start & 0x07)
+ pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+
+ dp->data = dp->start;
+ dp->len = 0;
+ return size;
+}
+
+/*
+ * mipi dsi generic long write
+ */
+static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ char *bp;
+ u32 *hp;
+ int i, len;
+
+ bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+ /* fill up payload */
+ if (cm->payload) {
+ len = cm->dlen;
+ len += 3;
+ len &= ~0x03; /* multipled by 4 */
+ for (i = 0; i < cm->dlen; i++)
+ *bp++ = cm->payload[i];
+
+ /* append 0xff to the end */
+ for (; i < len; i++)
+ *bp++ = 0xff;
+
+ dp->len += len;
+ }
+
+ /* fill up header */
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(cm->dlen);
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len;
+}
+
+/*
+ * mipi dsi generic short write with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+ int len;
+
+ if (cm->dlen && cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+
+ len = (cm->dlen > 2) ? 2 : cm->dlen;
+
+ if (len == 1) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(0);
+ } else if (len == 2) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+ } else {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
+ *hp |= DSI_HDR_DATA1(0);
+ *hp |= DSI_HDR_DATA2(0);
+ }
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+/*
+ * mipi dsi gerneric read with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+ int len;
+
+ if (cm->dlen && cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_BTA;
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ len = (cm->dlen > 2) ? 2 : cm->dlen;
+
+ if (len == 1) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(0);
+ } else if (len == 2) {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+ } else {
+ *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
+ *hp |= DSI_HDR_DATA1(0);
+ *hp |= DSI_HDR_DATA2(0);
+ }
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return dp->len; /* 4 bytes */
+}
+
+/*
+ * mipi dsi dcs long write
+ */
+static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ char *bp;
+ u32 *hp;
+ int i, len;
+
+ bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+ /*
+ * fill up payload
+ * dcs command byte (first byte) followed by payload
+ */
+ if (cm->payload) {
+ len = cm->dlen;
+ len += 3;
+ len &= ~0x03; /* multipled by 4 */
+ for (i = 0; i < cm->dlen; i++)
+ *bp++ = cm->payload[i];
+
+ /* append 0xff to the end */
+ for (; i < len; i++)
+ *bp++ = 0xff;
+
+ dp->len += len;
+ }
+
+ /* fill up header */
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(cm->dlen);
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len;
+}
+
+/*
+ * mipi dsi dcs short write with 0 parameters
+ */
+static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+ int len;
+
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_BTA;
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ len = (cm->dlen > 1) ? 1 : cm->dlen;
+
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
+ *hp |= DSI_HDR_DATA2(0);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+ return dp->len;
+}
+
+/*
+ * mipi dsi dcs short write with 1 parameters
+ */
+static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ if (cm->dlen < 2 || cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_BTA;
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */
+ *hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len;
+}
+/*
+ * mipi dsi dcs read with 0 parameters
+ */
+
+static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return -EINVAL;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_BTA;
+ *hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
+ *hp |= DSI_HDR_DATA2(0);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ if (cm->payload == 0) {
+ pr_err("%s: NO payload error\n", __func__);
+ return 0;
+ }
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ *hp |= DSI_HDR_DATA1(cm->payload[0]);
+ *hp |= DSI_HDR_DATA2(cm->payload[1]);
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(cm->dlen);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ u32 *hp;
+
+ mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+ hp = dp->hdr;
+ *hp = 0;
+ *hp = DSI_HDR_WC(cm->dlen);
+ *hp |= DSI_HDR_LONG_PKT;
+ *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
+ if (cm->last)
+ *hp |= DSI_HDR_LAST;
+
+ mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+ return dp->len; /* 4 bytes */
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+ int len = 0;
+
+ switch (cm->dtype) {
+ case DTYPE_GEN_WRITE:
+ case DTYPE_GEN_WRITE1:
+ case DTYPE_GEN_WRITE2:
+ len = mdss_dsi_generic_swrite(dp, cm);
+ break;
+ case DTYPE_GEN_LWRITE:
+ len = mdss_dsi_generic_lwrite(dp, cm);
+ break;
+ case DTYPE_GEN_READ:
+ case DTYPE_GEN_READ1:
+ case DTYPE_GEN_READ2:
+ len = mdss_dsi_generic_read(dp, cm);
+ break;
+ case DTYPE_DCS_LWRITE:
+ len = mdss_dsi_dcs_lwrite(dp, cm);
+ break;
+ case DTYPE_DCS_WRITE:
+ len = mdss_dsi_dcs_swrite(dp, cm);
+ break;
+ case DTYPE_DCS_WRITE1:
+ len = mdss_dsi_dcs_swrite1(dp, cm);
+ break;
+ case DTYPE_DCS_READ:
+ len = mdss_dsi_dcs_read(dp, cm);
+ break;
+ case DTYPE_MAX_PKTSIZE:
+ len = mdss_dsi_set_max_pktsize(dp, cm);
+ break;
+ case DTYPE_NULL_PKT:
+ len = mdss_dsi_null_pkt(dp, cm);
+ break;
+ case DTYPE_BLANK_PKT:
+ len = mdss_dsi_blank_pkt(dp, cm);
+ break;
+ case DTYPE_CM_ON:
+ len = mdss_dsi_cm_on(dp, cm);
+ break;
+ case DTYPE_CM_OFF:
+ len = mdss_dsi_cm_off(dp, cm);
+ break;
+ case DTYPE_PERIPHERAL_ON:
+ len = mdss_dsi_peripheral_on(dp, cm);
+ break;
+ case DTYPE_PERIPHERAL_OFF:
+ len = mdss_dsi_peripheral_off(dp, cm);
+ break;
+ default:
+ pr_debug("%s: dtype=%x NOT supported\n",
+ __func__, cm->dtype);
+ break;
+
+ }
+
+ return len;
+}
+
+/*
+ * mdss_dsi_short_read1_resp: 1 parameter
+ */
+static int mdss_dsi_short_read1_resp(struct dsi_buf *rp)
+{
+ /* strip out dcs type */
+ rp->data++;
+ rp->len = 1;
+ return rp->len;
+}
+
+/*
+ * mdss_dsi_short_read2_resp: 2 parameter
+ */
+static int mdss_dsi_short_read2_resp(struct dsi_buf *rp)
+{
+ /* strip out dcs type */
+ rp->data++;
+ rp->len = 2;
+ return rp->len;
+}
+
+static int mdss_dsi_long_read_resp(struct dsi_buf *rp)
+{
+ short len;
+
+ len = rp->data[2];
+ len <<= 8;
+ len |= rp->data[1];
+ /* strip out dcs header */
+ rp->data += 4;
+ rp->len -= 4;
+ /* strip out 2 bytes of checksum */
+ rp->len -= 2;
+ return len;
+}
+
+void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
+ struct mdss_panel_data *pdata)
+{
+ u32 dsi_ctrl, intr_ctrl;
+ u32 data;
+
+ pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
+
+ if (pinfo->mode == DSI_VIDEO_MODE) {
+ data = 0;
+ if (pinfo->pulse_mode_hsa_he)
+ data |= BIT(28);
+ if (pinfo->hfp_power_stop)
+ data |= BIT(24);
+ if (pinfo->hbp_power_stop)
+ data |= BIT(20);
+ if (pinfo->hsa_power_stop)
+ data |= BIT(16);
+ if (pinfo->eof_bllp_power_stop)
+ data |= BIT(15);
+ if (pinfo->bllp_power_stop)
+ data |= BIT(12);
+ data |= ((pinfo->traffic_mode & 0x03) << 8);
+ data |= ((pinfo->dst_format & 0x03) << 4); /* 2 bits */
+ data |= (pinfo->vc & 0x03);
+ MIPI_OUTP((pdata->dsi_base) + 0x0010, data);
+
+ data = 0;
+ data |= ((pinfo->rgb_swap & 0x07) << 12);
+ if (pinfo->b_sel)
+ data |= BIT(8);
+ if (pinfo->g_sel)
+ data |= BIT(4);
+ if (pinfo->r_sel)
+ data |= BIT(0);
+ MIPI_OUTP((pdata->dsi_base) + 0x0020, data);
+ } else if (pinfo->mode == DSI_CMD_MODE) {
+ data = 0;
+ data |= ((pinfo->interleave_max & 0x0f) << 20);
+ data |= ((pinfo->rgb_swap & 0x07) << 16);
+ if (pinfo->b_sel)
+ data |= BIT(12);
+ if (pinfo->g_sel)
+ data |= BIT(8);
+ if (pinfo->r_sel)
+ data |= BIT(4);
+ data |= (pinfo->dst_format & 0x0f); /* 4 bits */
+ MIPI_OUTP((pdata->dsi_base) + 0x003c, data);
+
+ /* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
+ data = pinfo->wr_mem_continue & 0x0ff;
+ data <<= 8;
+ data |= (pinfo->wr_mem_start & 0x0ff);
+ if (pinfo->insert_dcs_cmd)
+ data |= BIT(16);
+ MIPI_OUTP((pdata->dsi_base) + 0x0044, data);
+ } else
+ pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode);
+
+ dsi_ctrl = BIT(8) | BIT(2); /* clock enable & cmd mode */
+ intr_ctrl = 0;
+ intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_CMD_MDP_DONE_MASK);
+
+ if (pinfo->crc_check)
+ dsi_ctrl |= BIT(24);
+ if (pinfo->ecc_check)
+ dsi_ctrl |= BIT(20);
+ if (pinfo->data_lane3)
+ dsi_ctrl |= BIT(7);
+ if (pinfo->data_lane2)
+ dsi_ctrl |= BIT(6);
+ if (pinfo->data_lane1)
+ dsi_ctrl |= BIT(5);
+ if (pinfo->data_lane0)
+ dsi_ctrl |= BIT(4);
+
+ /* from frame buffer, low power mode */
+ /* DSI_COMMAND_MODE_DMA_CTRL */
+ MIPI_OUTP((pdata->dsi_base) + 0x3C, 0x14000000);
+
+ data = 0;
+ if (pinfo->te_sel)
+ data |= BIT(31);
+ data |= pinfo->mdp_trigger << 4;/* cmd mdp trigger */
+ data |= pinfo->dma_trigger; /* cmd dma trigger */
+ data |= (pinfo->stream & 0x01) << 8;
+ MIPI_OUTP((pdata->dsi_base) + 0x0084, data); /* DSI_TRIG_CTRL */
+
+ /* DSI_LAN_SWAP_CTRL */
+ MIPI_OUTP((pdata->dsi_base) + 0x00b0, pinfo->dlane_swap);
+
+ /* clock out ctrl */
+ data = pinfo->t_clk_post & 0x3f; /* 6 bits */
+ data <<= 8;
+ data |= pinfo->t_clk_pre & 0x3f; /* 6 bits */
+ /* DSI_CLKOUT_TIMING_CTRL */
+ MIPI_OUTP((pdata->dsi_base) + 0xc4, data);
+
+ data = 0;
+ if (pinfo->rx_eot_ignore)
+ data |= BIT(4);
+ if (pinfo->tx_eot_append)
+ data |= BIT(0);
+ MIPI_OUTP((pdata->dsi_base) + 0x00cc, data); /* DSI_EOT_PACKET_CTRL */
+
+
+ /* allow only ack-err-status to generate interrupt */
+ /* DSI_ERR_INT_MASK0 */
+ MIPI_OUTP((pdata->dsi_base) + 0x010c, 0x13ff3fe0);
+
+ intr_ctrl |= DSI_INTR_ERROR_MASK;
+ MIPI_OUTP((pdata->dsi_base) + 0x0110, intr_ctrl); /* DSI_INTL_CTRL */
+
+ /* turn esc, byte, dsi, pclk, sclk, hclk on */
+ MIPI_OUTP((pdata->dsi_base) + 0x11c, 0x23f); /* DSI_CLK_CTRL */
+
+ dsi_ctrl |= BIT(0); /* enable dsi */
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+
+ wmb();
+}
+
+void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+{
+ u32 data = MIPI_INP((pdata->dsi_base) + 0x3c);
+
+ if (mode == 0)
+ data &= ~BIT(26);
+ else
+ data |= BIT(26);
+
+ MIPI_OUTP((pdata->dsi_base) + 0x3c, data);
+}
+
+void mdss_dsi_sw_reset(struct mdss_panel_data *pdata)
+{
+ MIPI_OUTP((pdata->dsi_base) + 0x118, 0x01);
+ wmb();
+ MIPI_OUTP((pdata->dsi_base) + 0x118, 0x00);
+ wmb();
+}
+
+void mdss_dsi_controller_cfg(int enable,
+ struct mdss_panel_data *pdata)
+{
+
+ u32 dsi_ctrl;
+ u32 status;
+ u32 sleep_us = 1000;
+ u32 timeout_us = 16000;
+
+ /* Check for CMD_MODE_DMA_BUSY */
+ if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+ status,
+ ((status & 0x02) == 0),
+ sleep_us, timeout_us))
+ pr_info("%s: DSI status=%x failed\n", __func__, status);
+
+ /* Check for x_HS_FIFO_EMPTY */
+ if (readl_poll_timeout(((pdata->dsi_base) + 0x000c),
+ status,
+ ((status & 0x11111000) == 0x11111000),
+ sleep_us, timeout_us))
+ pr_info("%s: FIFO status=%x failed\n", __func__, status);
+
+ dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+ if (enable)
+ dsi_ctrl |= 0x01;
+ else
+ dsi_ctrl &= ~0x01;
+
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+ wmb();
+}
+
+void mdss_dsi_op_mode_config(int mode,
+ struct mdss_panel_data *pdata)
+{
+
+ u32 dsi_ctrl, intr_ctrl;
+
+ dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+ dsi_ctrl &= ~0x07;
+ if (mode == DSI_VIDEO_MODE) {
+ dsi_ctrl |= 0x03;
+ intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
+ } else { /* command mode */
+ dsi_ctrl |= 0x05;
+ intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
+ DSI_INTR_CMD_MDP_DONE_MASK;
+ }
+
+ pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
+
+ MIPI_OUTP((pdata->dsi_base) + 0x0110, intr_ctrl); /* DSI_INTL_CTRL */
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+ wmb();
+}
+
+void mdss_dsi_cmd_mdp_start(void)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ mdss_dsi_enable_irq();
+ dsi_mdp_busy = true;
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+}
+
+
+void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
+{
+ u32 status;
+ int timeout_us = 10000;
+
+ MIPI_OUTP((pdata->dsi_base) + 0x098, 0x01); /* trigger */
+ wmb();
+
+ /* Check for CMD_MODE_DMA_BUSY */
+ if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+ status, ((status & 0x0010) == 0),
+ 0, timeout_us))
+ pr_info("%s: DSI status=%x failed\n", __func__, status);
+
+ mdss_dsi_ack_err_status((pdata->dsi_base));
+
+ pr_debug("%s: BTA done, status = %d\n", __func__, status);
+}
+
+int mdss_dsi_cmd_reg_tx(u32 data,
+ struct mdss_panel_data *pdata)
+{
+ int i;
+ char *bp;
+
+ bp = (char *)&data;
+ pr_debug("%s: ", __func__);
+ for (i = 0; i < 4; i++)
+ pr_debug("%x ", *bp++);
+
+ pr_debug("\n");
+
+ MIPI_OUTP((pdata->dsi_base) + 0x0084, 0x04);/* sw trigger */
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, 0x135);
+
+ wmb();
+
+ MIPI_OUTP((pdata->dsi_base) + 0x03c, data);
+ wmb();
+ MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01); /* trigger */
+ wmb();
+
+ udelay(300);
+
+ return 4;
+}
+
+/*
+ * mdss_dsi_cmds_tx:
+ * ov_mutex need to be acquired before call this function.
+ */
+int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
+ struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+{
+ struct dsi_cmd_desc *cm;
+ u32 dsi_ctrl, ctrl;
+ int i, video_mode;
+ unsigned long flag;
+
+ /* turn on cmd mode
+ * for video mode, do not send cmds more than
+ * one pixel line, since it only transmit it
+ * during BLLP.
+ */
+ dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+ video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ if (video_mode) {
+ ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, ctrl);
+ }
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ mdss_dsi_enable_irq();
+ dsi_mdp_busy = true;
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ cm = cmds;
+ mdss_dsi_buf_init(tp);
+ for (i = 0; i < cnt; i++) {
+ mdss_dsi_buf_init(tp);
+ mdss_dsi_cmd_dma_add(tp, cm);
+ mdss_dsi_cmd_dma_tx(tp, pdata);
+ if (cm->wait)
+ msleep(cm->wait);
+ cm++;
+ }
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ dsi_mdp_busy = false;
+ mdss_dsi_disable_irq();
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ if (video_mode)
+ MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl); /* restore */
+
+ return cnt;
+}
+
+/* MDSS_DSI_MRPS, Maximum Return Packet Size */
+static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
+
+static struct dsi_cmd_desc pkt_size_cmd[] = {
+ {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
+ sizeof(max_pktsize), max_pktsize}
+};
+
+/*
+ * DSI panel reply with MAX_RETURN_PACKET_SIZE bytes of data
+ * plus DCS header, ECC and CRC for DCS long read response
+ * mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
+ * hold data per transaction.
+ * MDSS_DSI_LEN equal to 8
+ * len should be either 4 or 8
+ * any return data more than MDSS_DSI_LEN need to be break down
+ * to multiple transactions.
+ *
+ * ov_mutex need to be acquired before call this function.
+ */
+int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
+ struct dsi_buf *tp, struct dsi_buf *rp,
+ struct dsi_cmd_desc *cmds, int rlen)
+{
+ int cnt, len, diff, pkt_size;
+ unsigned long flag;
+ char cmd;
+
+ if (pdata->panel_info.mipi.no_max_pkt_size)
+ rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
+
+ len = rlen;
+ diff = 0;
+
+ if (len <= 2)
+ cnt = 4; /* short read */
+ else {
+ if (len > MDSS_DSI_LEN)
+ len = MDSS_DSI_LEN; /* 8 bytes at most */
+
+ len = ALIGN(len, 4); /* len 4 bytes align */
+ diff = len - rlen;
+ /*
+ * add extra 2 bytes to len to have overall
+ * packet size is multipe by 4. This also make
+ * sure 4 bytes dcs headerlocates within a
+ * 32 bits register after shift in.
+ * after all, len should be either 6 or 10.
+ */
+ len += 2;
+ cnt = len + 6; /* 4 bytes header + 2 bytes crc */
+ }
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ mdss_dsi_enable_irq();
+ dsi_mdp_busy = true;
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ if (!pdata->panel_info.mipi.no_max_pkt_size) {
+ /* packet size need to be set at every read */
+ pkt_size = len;
+ max_pktsize[0] = pkt_size;
+ mdss_dsi_buf_init(tp);
+ mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
+ mdss_dsi_cmd_dma_tx(tp, pdata);
+ }
+
+ mdss_dsi_buf_init(tp);
+ mdss_dsi_cmd_dma_add(tp, cmds);
+
+ /* transmit read comamnd to client */
+ mdss_dsi_cmd_dma_tx(tp, pdata);
+ /*
+ * once cmd_dma_done interrupt received,
+ * return data from client is ready and stored
+ * at RDBK_DATA register already
+ */
+ mdss_dsi_buf_init(rp);
+ if (pdata->panel_info.mipi.no_max_pkt_size) {
+ /*
+ * expect rlen = n * 4
+ * short alignement for start addr
+ */
+ rp->data += 2;
+ }
+
+ mdss_dsi_cmd_dma_rx(rp, cnt, pdata);
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ dsi_mdp_busy = false;
+ mdss_dsi_disable_irq();
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ if (pdata->panel_info.mipi.no_max_pkt_size) {
+ /*
+ * remove extra 2 bytes from previous
+ * rx transaction at shift register
+ * which was inserted during copy
+ * shift registers to rx buffer
+ * rx payload start from long alignment addr
+ */
+ rp->data += 2;
+ }
+
+ cmd = rp->data[0];
+ switch (cmd) {
+ case DTYPE_ACK_ERR_RESP:
+ pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+ break;
+ case DTYPE_GEN_READ1_RESP:
+ case DTYPE_DCS_READ1_RESP:
+ mdss_dsi_short_read1_resp(rp);
+ break;
+ case DTYPE_GEN_READ2_RESP:
+ case DTYPE_DCS_READ2_RESP:
+ mdss_dsi_short_read2_resp(rp);
+ break;
+ case DTYPE_GEN_LREAD_RESP:
+ case DTYPE_DCS_LREAD_RESP:
+ mdss_dsi_long_read_resp(rp);
+ rp->len -= 2; /* extra 2 bytes added */
+ rp->len -= diff; /* align bytes */
+ break;
+ default:
+ break;
+ }
+
+ return rp->len;
+}
+
+int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
+ struct mdss_panel_data *pdata)
+{
+ int len;
+ int i;
+ char *bp;
+
+ bp = tp->data;
+
+ pr_debug("%s: ", __func__);
+ for (i = 0; i < tp->len; i++)
+ pr_debug("%x ", *bp++);
+
+ pr_debug("\n");
+
+ len = tp->len;
+ len += 3;
+ len &= ~0x03; /* multipled by 4 */
+
+ tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&dsi_dev, tp->dmap))
+ pr_err("%s: dmap mapp failed\n", __func__);
+
+ INIT_COMPLETION(dsi_dma_comp);
+
+ MIPI_OUTP((pdata->dsi_base) + 0x048, tp->dmap);
+ MIPI_OUTP((pdata->dsi_base) + 0x04c, len);
+ wmb();
+
+ MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01); /* trigger */
+ wmb();
+
+ wait_for_completion(&dsi_dma_comp);
+
+ dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE);
+ tp->dmap = 0;
+ return tp->len;
+}
+
+int mdss_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen,
+ struct mdss_panel_data *pdata)
+{
+ u32 *lp, data;
+ int i, off, cnt;
+
+ lp = (u32 *)rp->data;
+ cnt = rlen;
+ cnt += 3;
+ cnt >>= 2;
+
+ if (cnt > 4)
+ cnt = 4; /* 4 x 32 bits registers only */
+
+ off = 0x06c; /* DSI_RDBK_DATA0 */
+ off += ((cnt - 1) * 4);
+
+
+ for (i = 0; i < cnt; i++) {
+ data = (u32)MIPI_INP((pdata->dsi_base) + off);
+ *lp++ = ntohl(data); /* to network byte order */
+ off -= 4;
+ rp->len += sizeof(*lp);
+ }
+
+ return rlen;
+}
+
+void mdss_dsi_ack_err_status(unsigned char *dsi_base)
+{
+ u32 status;
+
+ status = MIPI_INP(dsi_base + 0x0068);/* DSI_ACK_ERR_STATUS */
+
+ if (status) {
+ MIPI_OUTP(dsi_base + 0x0068, status);
+ pr_debug("%s: status=%x\n", __func__, status);
+ }
+}
+
+void mdss_dsi_timeout_status(unsigned char *dsi_base)
+{
+ u32 status;
+
+ status = MIPI_INP(dsi_base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+ if (status & 0x0111) {
+ MIPI_OUTP(dsi_base + 0x00c0, status);
+ pr_debug("%s: status=%x\n", __func__, status);
+ }
+}
+
+void mdss_dsi_dln0_phy_err(unsigned char *dsi_base)
+{
+ u32 status;
+
+ status = MIPI_INP(dsi_base + 0x00b4);/* DSI_DLN0_PHY_ERR */
+
+ if (status & 0x011111) {
+ MIPI_OUTP(dsi_base + 0x00b4, status);
+ pr_debug("%s: status=%x\n", __func__, status);
+ }
+}
+
+void mdss_dsi_fifo_status(unsigned char *dsi_base)
+{
+ u32 status;
+
+ status = MIPI_INP(dsi_base + 0x000c);/* DSI_FIFO_STATUS */
+
+ if (status & 0x44444489) {
+ MIPI_OUTP(dsi_base + 0x000c, status);
+ pr_debug("%s: status=%x\n", __func__, status);
+ }
+}
+
+void mdss_dsi_status(unsigned char *dsi_base)
+{
+ u32 status;
+
+ status = MIPI_INP(dsi_base + 0x0008);/* DSI_STATUS */
+
+ if (status & 0x80000000) {
+ MIPI_OUTP(dsi_base + 0x0008, status);
+ pr_debug("%s: status=%x\n", __func__, status);
+ }
+}
+
+void mdss_dsi_error(unsigned char *dsi_base)
+{
+ /* DSI_ERR_INT_MASK0 */
+ mdss_dsi_ack_err_status(dsi_base); /* mask0, 0x01f */
+ mdss_dsi_timeout_status(dsi_base); /* mask0, 0x0e0 */
+ mdss_dsi_fifo_status(dsi_base); /* mask0, 0x133d00 */
+ mdss_dsi_status(dsi_base); /* mask0, 0xc0100 */
+ mdss_dsi_dln0_phy_err(dsi_base); /* mask0, 0x3e00000 */
+}
+
+
+irqreturn_t mdss_dsi_isr(int irq, void *ptr)
+{
+ u32 isr;
+ unsigned char *dsi_base;
+
+ dsi_base = mdss_dsi_get_base_adr();
+ if (!dsi_base)
+ pr_err("%s:%d DSI base adr no Initialized",
+ __func__, __LINE__);
+
+ isr = MIPI_INP(dsi_base + 0x0110);/* DSI_INTR_CTRL */
+ MIPI_OUTP(dsi_base + 0x0110, isr);
+
+ if (isr & DSI_INTR_ERROR)
+ mdss_dsi_error(dsi_base);
+
+ if (isr & DSI_INTR_VIDEO_DONE) {
+ /*
+ * do something here
+ */
+ }
+
+ if (isr & DSI_INTR_CMD_DMA_DONE)
+ complete(&dsi_dma_comp);
+
+ if (isr & DSI_INTR_CMD_MDP_DONE) {
+ spin_lock(&dsi_mdp_lock);
+ dsi_mdp_busy = false;
+ mdss_dsi_disable_irq_nosync();
+ spin_unlock(&dsi_mdp_lock);
+ }
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
new file mode 100644
index 0000000..bfb7fae
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "mdss_dsi.h"
+
+#define DT_CMD_HDR 6
+
+static struct dsi_buf dsi_panel_tx_buf;
+static struct dsi_buf dsi_panel_rx_buf;
+
+static struct dsi_cmd_desc *dsi_panel_on_cmds;
+static struct dsi_cmd_desc *dsi_panel_off_cmds;
+static int num_of_on_cmds;
+static int num_of_off_cmds;
+static char *on_cmds, *off_cmds;
+
+static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
+{
+ struct mipi_panel_info *mipi;
+
+ mipi = &pdata->panel_info.mipi;
+
+ pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
+ mipi->mode);
+
+ if (mipi->mode == DSI_VIDEO_MODE) {
+ mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
+ num_of_on_cmds);
+ } else {
+ pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
+{
+ struct mipi_panel_info *mipi;
+
+ mipi = &pdata->panel_info.mipi;
+
+ pr_debug("%s:%d, debug info\n", __func__, __LINE__);
+
+ if (mipi->mode == DSI_VIDEO_MODE) {
+ mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_off_cmds,
+ num_of_off_cmds);
+ } else {
+ pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mdss_panel_parse_dt(struct platform_device *pdev,
+ struct mdss_panel_common_pdata *panel_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 res[6], tmp;
+ int rc, i, len;
+ int cmd_plen, data_offset;
+ const char *data;
+
+ rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
+ if (rc) {
+ pr_err("%s:%d, panel resolution not specified\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.xres = (!rc ? res[0] : 640);
+ panel_data->panel_info.yres = (!rc ? res[1] : 480);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
+ if (rc) {
+ pr_err("%s:%d, panel bpp not specified\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.bpp = (!rc ? tmp : 24);
+
+ rc = of_property_read_u32_array(np,
+ "qcom,mdss-pan-porch-values", res, 6);
+ panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6);
+ panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2);
+ panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6);
+ panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6);
+ panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2);
+ panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-underflow-clr", &tmp);
+ panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+
+ rc = of_property_read_u32_array(np,
+ "qcom,mdss-pan-bl-levels", res, 2);
+ panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
+ panel_data->panel_info.bl_max = (!rc ? res[1] : 255);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
+ panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
+ panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
+
+ rc = of_property_read_u32_array(np,
+ "qcom,mdss-pan-dsi-h-power-stop", res, 3);
+ panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false);
+ panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false);
+ panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false);
+
+ rc = of_property_read_u32_array(np,
+ "qcom,mdss-pan-dsi-bllp-power-stop", res, 2);
+ panel_data->panel_info.mipi.bllp_power_stop =
+ (!rc ? res[0] : false);
+ panel_data->panel_info.mipi.eof_bllp_power_stop =
+ (!rc ? res[1] : false);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-dsi-traffic-mode", &tmp);
+ panel_data->panel_info.mipi.traffic_mode =
+ (!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
+
+ rc = of_property_read_u32(np,
+ "qcom,mdss-pan-dsi-dst-format", &tmp);
+ panel_data->panel_info.mipi.dst_format =
+ (!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp);
+ panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp);
+ panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+
+ rc = of_property_read_u32_array(np,
+ "qcom,mdss-pan-dsi-data-lanes", res, 4);
+ panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true);
+ panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false);
+ panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false);
+ panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false);
+
+ rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2);
+ panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24);
+ panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp);
+ panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp);
+ panel_data->panel_info.mipi.mdp_trigger =
+ (!rc ? tmp : DSI_CMD_TRIGGER_SW);
+ if (panel_data->panel_info.mipi.mdp_trigger > 6) {
+ pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
+ __func__, __LINE__);
+ panel_data->panel_info.mipi.mdp_trigger =
+ DSI_CMD_TRIGGER_SW;
+ }
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp);
+ panel_data->panel_info.mipi.dma_trigger =
+ (!rc ? tmp : DSI_CMD_TRIGGER_SW);
+ if (panel_data->panel_info.mipi.dma_trigger > 6) {
+ pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
+ __func__, __LINE__);
+ panel_data->panel_info.mipi.dma_trigger =
+ DSI_CMD_TRIGGER_SW;
+ }
+
+ rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
+ panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+
+ data = of_get_property(np, "qcom,panel-on-cmds", &len);
+ if (!data) {
+ pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
+ goto error;
+ }
+
+ on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+ if (!on_cmds)
+ return -ENOMEM;
+
+ memcpy(on_cmds, data, len);
+
+ data_offset = 0;
+ cmd_plen = 0;
+ while ((len - data_offset) >= DT_CMD_HDR) {
+ data_offset += (DT_CMD_HDR - 1);
+ cmd_plen = on_cmds[data_offset++];
+ data_offset += cmd_plen;
+ num_of_on_cmds++;
+ }
+ if (!num_of_on_cmds) {
+ pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
+ goto error;
+ }
+
+ dsi_panel_on_cmds =
+ kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
+ GFP_KERNEL);
+ if (!dsi_panel_on_cmds)
+ return -ENOMEM;
+
+ data_offset = 0;
+ for (i = 0; i < num_of_on_cmds; i++) {
+ dsi_panel_on_cmds[i].dtype = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].last = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].vc = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].ack = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].wait = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].dlen = on_cmds[data_offset++];
+ dsi_panel_on_cmds[i].payload = &on_cmds[data_offset];
+ data_offset += (dsi_panel_on_cmds[i].dlen);
+ }
+
+ if (data_offset != len) {
+ pr_err("%s:%d, Incorrect ON command entries",
+ __func__, __LINE__);
+ goto error;
+ }
+
+ data = of_get_property(np, "qcom,panel-off-cmds", &len);
+ if (!data) {
+ pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
+ goto error;
+ }
+
+ off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+ if (!off_cmds)
+ return -ENOMEM;
+
+ memcpy(off_cmds, data, len);
+
+ data_offset = 0;
+ cmd_plen = 0;
+ while ((len - data_offset) >= DT_CMD_HDR) {
+ data_offset += (DT_CMD_HDR - 1);
+ cmd_plen = off_cmds[data_offset++];
+ data_offset += cmd_plen;
+ num_of_off_cmds++;
+ }
+ if (!num_of_off_cmds) {
+ pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
+ goto error;
+ }
+
+ dsi_panel_off_cmds = kzalloc(num_of_off_cmds
+ * sizeof(struct dsi_cmd_desc),
+ GFP_KERNEL);
+ if (!dsi_panel_off_cmds)
+ return -ENOMEM;
+
+ data_offset = 0;
+ for (i = 0; i < num_of_off_cmds; i++) {
+ dsi_panel_off_cmds[i].dtype = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].last = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].vc = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].ack = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].wait = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].dlen = off_cmds[data_offset++];
+ dsi_panel_off_cmds[i].payload = &off_cmds[data_offset];
+ data_offset += (dsi_panel_off_cmds[i].dlen);
+ }
+
+ if (data_offset != len) {
+ pr_err("%s:%d, Incorrect OFF command entries",
+ __func__, __LINE__);
+ goto error;
+ }
+
+ return 0;
+error:
+ kfree(dsi_panel_on_cmds);
+ kfree(dsi_panel_off_cmds);
+ kfree(on_cmds);
+ kfree(off_cmds);
+
+ return -EINVAL;
+}
+
+static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct mdss_panel_common_pdata *vendor_pdata = NULL;
+ static const char *panel_name;
+
+ if (pdev->dev.parent == NULL) {
+ pr_err("%s: parent device missing\n", __func__);
+ return -ENODEV;
+ }
+
+ pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
+ if (!panel_name)
+ pr_info("%s:%d, panel name not specified\n",
+ __func__, __LINE__);
+ else
+ pr_info("%s: Panel Name = %s\n", __func__, panel_name);
+
+ vendor_pdata = devm_kzalloc(&pdev->dev,
+ sizeof(*vendor_pdata), GFP_KERNEL);
+ if (!vendor_pdata)
+ return -ENOMEM;
+
+ rc = mdss_panel_parse_dt(pdev, vendor_pdata);
+ if (rc) {
+ devm_kfree(&pdev->dev, vendor_pdata);
+ vendor_pdata = NULL;
+ return rc;
+ }
+ vendor_pdata->on = mdss_dsi_panel_on;
+ vendor_pdata->off = mdss_dsi_panel_off;
+
+ rc = dsi_panel_device_register(pdev, vendor_pdata);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static const struct of_device_id mdss_dsi_panel_match[] = {
+ {.compatible = "qcom,mdss-dsi-panel"},
+ {}
+};
+
+static struct platform_driver this_driver = {
+ .probe = mdss_dsi_panel_probe,
+ .driver = {
+ .name = "dsi_panel",
+ .of_match_table = mdss_dsi_panel_match,
+ },
+};
+
+static int __init mdss_dsi_panel_init(void)
+{
+ mdss_dsi_buf_alloc(&dsi_panel_tx_buf, DSI_BUF_SIZE);
+ mdss_dsi_buf_alloc(&dsi_panel_rx_buf, DSI_BUF_SIZE);
+
+ return platform_driver_register(&this_driver);
+}
+module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4ca1dce..8825cc6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -375,6 +375,7 @@
#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
+#define MDSS_MDP_PANEL_FORMAT_RGB888 0x213F
enum mdss_mdp_pingpong_index {
MDSS_MDP_PINGPONG0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 21ef290..2f0a1f5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -135,6 +135,8 @@
p->hsync_skew);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_POLARITY_CTL,
polarity_ctl);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_PANEL_FORMAT,
+ MDSS_MDP_PANEL_FORMAT_RGB888);
return 0;
}
@@ -297,14 +299,14 @@
itp.underflow_clr = pinfo->lcdc.underflow_clr;
itp.hsync_skew = pinfo->lcdc.hsync_skew;
- itp.xres = fbi->var.xres;
- itp.yres = fbi->var.yres;
- itp.h_back_porch = fbi->var.left_margin;
- itp.h_front_porch = fbi->var.right_margin;
- itp.v_back_porch = fbi->var.upper_margin;
- itp.v_front_porch = fbi->var.lower_margin;
- itp.hsync_pulse_width = fbi->var.hsync_len;
- itp.vsync_pulse_width = fbi->var.vsync_len;
+ itp.xres = pinfo->xres;
+ itp.yres = pinfo->yres;
+ itp.h_back_porch = pinfo->lcdc.h_back_porch;
+ itp.h_front_porch = pinfo->lcdc.h_front_porch;
+ itp.v_back_porch = pinfo->lcdc.v_back_porch;
+ itp.v_front_porch = pinfo->lcdc.h_front_porch;
+ itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
+ itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
pr_err("unable to get timing parameters\n");
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 0411d8e..3ec3a5d 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -167,6 +167,7 @@
struct mdss_panel_data {
struct mdss_panel_info panel_info;
void (*set_backlight) (u32 bl_level);
+ unsigned char *dsi_base;
/* function entry chain */
int (*on) (struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
new file mode 100644
index 0000000..c766ec7
--- /dev/null
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/clk.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+
+#include "mdss_dsi.h"
+
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+#define PWRDN_B BIT(7)
+
+static struct dsi_clk_desc dsi_pclk;
+
+static struct clk *dsi_byte_div_clk;
+static struct clk *dsi_esc_clk;
+
+int mdss_dsi_clk_on;
+
+int mdss_dsi_clk_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ dsi_byte_div_clk = clk_get(dev, "byte_clk");
+ if (IS_ERR(dsi_byte_div_clk)) {
+ pr_err("can't find dsi_byte_div_clk\n");
+ dsi_byte_div_clk = NULL;
+ goto mdss_dsi_clk_err;
+ }
+
+ dsi_esc_clk = clk_get(dev, "core_clk");
+ if (IS_ERR(dsi_esc_clk)) {
+ printk(KERN_ERR "can't find dsi_esc_clk\n");
+ dsi_esc_clk = NULL;
+ goto mdss_dsi_clk_err;
+ }
+
+ return 0;
+
+mdss_dsi_clk_err:
+ mdss_dsi_clk_deinit(dev);
+ return -EPERM;
+}
+
+void mdss_dsi_clk_deinit(struct device *dev)
+{
+ if (dsi_byte_div_clk)
+ clk_put(dsi_byte_div_clk);
+ if (dsi_esc_clk)
+ clk_put(dsi_esc_clk);
+}
+
+#define PREF_DIV_RATIO 27
+struct dsiphy_pll_divider_config pll_divider_config;
+
+int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
+ u32 *expected_dsi_pclk)
+{
+ u32 fb_divider, rate, vco;
+ u32 div_ratio = 0;
+ u32 pll_analog_posDiv = 1;
+ struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
+ if (pll_divider_config.clk_rate == 0)
+ pll_divider_config.clk_rate = 454000000;
+
+ rate = (pll_divider_config.clk_rate / 2)
+ / 1000000; /* Half Bit Clock In Mhz */
+
+ if (rate < 43) {
+ vco = rate * 16;
+ div_ratio = 16;
+ pll_analog_posDiv = 8;
+ } else if (rate < 85) {
+ vco = rate * 8;
+ div_ratio = 8;
+ pll_analog_posDiv = 4;
+ } else if (rate < 170) {
+ vco = rate * 4;
+ div_ratio = 4;
+ pll_analog_posDiv = 2;
+ } else if (rate < 340) {
+ vco = rate * 2;
+ div_ratio = 2;
+ pll_analog_posDiv = 1;
+ } else {
+ /* DSI PLL Direct path configuration */
+ vco = rate * 1;
+ div_ratio = 1;
+ pll_analog_posDiv = 1;
+ }
+
+ /* find the mnd settings from mnd_table entry */
+ for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
+ if (((mnd_entry->lanes) == lanes) &&
+ ((mnd_entry->bpp) == bpp))
+ break;
+ }
+
+ if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) {
+ pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n",
+ __func__, lanes, bpp);
+ return -EINVAL;
+ }
+ fb_divider = ((vco * PREF_DIV_RATIO) / 27);
+ pll_divider_config.fb_divider = fb_divider;
+ pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO;
+ pll_divider_config.bit_clk_divider = div_ratio;
+ pll_divider_config.byte_clk_divider =
+ pll_divider_config.bit_clk_divider * 8;
+ pll_divider_config.analog_posDiv = pll_analog_posDiv;
+ pll_divider_config.digital_posDiv =
+ (mnd_entry->pll_digital_posDiv) * div_ratio;
+
+ if ((mnd_entry->pclk_d == 0)
+ || (mnd_entry->pclk_m == 1)) {
+ dsi_pclk.mnd_mode = 0;
+ dsi_pclk.src = 0x3;
+ dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1);
+ } else {
+ dsi_pclk.mnd_mode = 2;
+ dsi_pclk.src = 0x3;
+ dsi_pclk.m = mnd_entry->pclk_m;
+ dsi_pclk.n = mnd_entry->pclk_n;
+ dsi_pclk.d = mnd_entry->pclk_d;
+ }
+ *expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
+ / (8 * bpp));
+
+ return 0;
+}
+
+void cont_splash_clk_ctrl(int enable)
+{
+ static int cont_splash_clks_enabled;
+ if (enable && !cont_splash_clks_enabled) {
+ clk_prepare_enable(dsi_byte_div_clk);
+ clk_prepare_enable(dsi_esc_clk);
+ cont_splash_clks_enabled = 1;
+ } else if (!enable && cont_splash_clks_enabled) {
+ clk_disable_unprepare(dsi_byte_div_clk);
+ clk_disable_unprepare(dsi_esc_clk);
+ cont_splash_clks_enabled = 0;
+ }
+}
+
+void mdss_dsi_prepare_clocks(void)
+{
+ clk_prepare(dsi_byte_div_clk);
+ clk_prepare(dsi_esc_clk);
+}
+
+void mdss_dsi_unprepare_clocks(void)
+{
+ clk_unprepare(dsi_esc_clk);
+ clk_unprepare(dsi_byte_div_clk);
+}
+
+void mdss_dsi_clk_enable(void)
+{
+ if (mdss_dsi_clk_on) {
+ pr_info("%s: mdss_dsi_clks already ON\n", __func__);
+ return;
+ }
+
+ if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */
+ pr_err("%s: dsi_byte_div_clk - clk_set_rate failed\n",
+ __func__);
+ if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */
+ pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
+ __func__);
+ clk_enable(dsi_byte_div_clk);
+ clk_enable(dsi_esc_clk);
+ mdss_dsi_clk_on = 1;
+}
+
+void mdss_dsi_clk_disable(void)
+{
+ if (mdss_dsi_clk_on == 0) {
+ pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
+ return;
+ }
+ clk_disable(dsi_esc_clk);
+ clk_disable(dsi_byte_div_clk);
+ mdss_dsi_clk_on = 0;
+}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b6f4874..a984637 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1438,10 +1438,22 @@
/* cursor memory allocation */
if (mfd->cursor_update) {
+ unsigned long cursor_buf_iommu = 0;
mfd->cursor_buf = dma_alloc_coherent(NULL,
MDP_CURSOR_SIZE,
(dma_addr_t *) &mfd->cursor_buf_phys,
GFP_KERNEL);
+
+ msm_iommu_map_contig_buffer((unsigned long)mfd->cursor_buf_phys,
+ DISPLAY_READ_DOMAIN,
+ GEN_POOL,
+ MDP_CURSOR_SIZE,
+ SZ_4K,
+ 0,
+ &cursor_buf_iommu);
+ if (cursor_buf_iommu)
+ mfd->cursor_buf_phys = (void *)cursor_buf_iommu;
+
if (!mfd->cursor_buf)
mfd->cursor_update = 0;
}
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index 02b2369..a144e06 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -42,8 +42,17 @@
}
DDL_MEMSET(ddl_context, 0, sizeof(struct ddl_context));
-
DDL_BUSY(ddl_context);
+
+ if (res_trk_get_enable_ion()) {
+ VIDC_LOGERR_STRING("ddl_dev_init: ION framework enabled");
+ ddl_context->video_ion_client =
+ res_trk_get_ion_client();
+ if (!ddl_context->video_ion_client) {
+ VIDC_LOGERR_STRING("ION client create failed");
+ return VCD_ERR_ILLEGAL_OP;
+ }
+ }
ddl_context->memtype = res_trk_get_mem_type();
if (ddl_context->memtype == -1) {
VIDC_LOGERR_STRING("ddl_dev_init:Invalid Memtype");
@@ -161,7 +170,7 @@
VIDC_LOG_STRING("FW_ENDDONE");
ddl_release_context_buffers(ddl_context);
-
+ ddl_context->video_ion_client = NULL;
DDL_IDLE(ddl_context);
return VCD_S_SUCCESS;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
index e1407c8..e6d3527 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012 Code Aurora Forum. 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
@@ -77,6 +77,7 @@
u32 *align_physical_addr;
u32 *align_virtual_addr;
struct msm_mapped_buffer *mapped_buffer;
+ struct ion_handle *alloc_handle;
u32 buffer_size;
enum ddl_mem_area mem_type;
};
@@ -225,6 +226,7 @@
struct ddl_buf_addr dbg_core_dump;
u32 enable_dbg_core_dump;
struct ddl_client_context *ddl_clients[VCD_MAX_NO_CLIENT];
+ struct ion_client *video_ion_client;
u32 device_state;
u32 ddl_busy;
u32 intr_status;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index aa0d4b8..21f01d1 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -13,6 +13,7 @@
#include <linux/memory_alloc.h>
#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
+#include "vcd_res_tracker_api.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
@@ -91,103 +92,178 @@
u32 alloc_size, flags = 0;
struct ddl_context *ddl_context;
struct msm_mapped_buffer *mapped_buffer = NULL;
+ unsigned long *kernel_vaddr = NULL;
+ ion_phys_addr_t phyaddr = 0;
+ size_t len = 0;
+ int ret = -EINVAL;
if (!buff_addr) {
- ERR("\n%s() Invalid Parameters", __func__);
+ ERR("\n%s() Invalid Parameters\n", __func__);
return;
}
-
- DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
-
if (align == DDL_LINEAR_BUFFER_ALIGN_BYTES) {
-
guard_bytes = 31;
align_mask = 0xFFFFFFE0U;
-
} else {
-
guard_bytes = DDL_TILE_BUF_ALIGN_GUARD_BYTES;
align_mask = DDL_TILE_BUF_ALIGN_MASK;
}
ddl_context = ddl_get_context();
alloc_size = sz + guard_bytes;
+ if (res_trk_get_enable_ion()) {
+ if (!ddl_context->video_ion_client)
+ ddl_context->video_ion_client =
+ res_trk_get_ion_client();
+ if (!ddl_context->video_ion_client) {
+ ERR("\n%s(): DDL ION Client Invalid handle\n",
+ __func__);
+ goto bailout;
+ }
+ buff_addr->mem_type = res_trk_get_mem_type();
+ buff_addr->alloc_handle = ion_alloc(
+ ddl_context->video_ion_client,
+ alloc_size,
+ SZ_4K,
+ buff_addr->mem_type);
+ if (!buff_addr->alloc_handle) {
+ ERR("\n%s(): DDL ION alloc failed\n",
+ __func__);
+ goto bailout;
+ }
+ ret = ion_phys(ddl_context->video_ion_client,
+ buff_addr->alloc_handle,
+ &phyaddr,
+ &len);
+ if (ret || !phyaddr) {
+ ERR("\n%s(): DDL ION client physical failed\n",
+ __func__);
+ goto free_ion_buffer;
+ }
+ buff_addr->physical_base_addr = (u32 *)phyaddr;
+ kernel_vaddr = (unsigned long *) ion_map_kernel(
+ ddl_context->video_ion_client,
+ buff_addr->alloc_handle,
+ UNCACHED);
+ if (IS_ERR_OR_NULL(kernel_vaddr)) {
+ ERR("\n%s(): DDL ION map failed\n", __func__);
+ goto unmap_ion_buffer;
+ }
+ buff_addr->virtual_base_addr = (u32 *)kernel_vaddr;
+ DBG("ddl_ion_alloc: handle(0x%x), mem_type(0x%x), "\
+ "phys(0x%x), virt(0x%x), size(%u), align(%u), "\
+ "alloced_len(%u)", (u32)buff_addr->alloc_handle,
+ (u32)buff_addr->mem_type,
+ (u32)buff_addr->physical_base_addr,
+ (u32)buff_addr->virtual_base_addr,
+ alloc_size, align, len);
+ } else {
+ physical_addr = (u32)
+ allocate_contiguous_memory_nomap(alloc_size,
+ ddl_context->memtype, SZ_4K);
+ if (!physical_addr) {
+ ERR("\n%s(): DDL pmem allocate failed\n",
+ __func__);
+ goto bailout;
+ }
+ buff_addr->physical_base_addr = (u32 *) physical_addr;
+ flags = MSM_SUBSYSTEM_MAP_KADDR;
+ buff_addr->mapped_buffer =
+ msm_subsystem_map_buffer((unsigned long)physical_addr,
+ alloc_size, flags, NULL, 0);
+ if (IS_ERR(buff_addr->mapped_buffer)) {
+ ERR("\n%s() buffer map failed\n", __func__);
+ goto free_pmem_buffer;
+ }
+ mapped_buffer = buff_addr->mapped_buffer;
+ if (!mapped_buffer->vaddr) {
+ ERR("\n%s() mapped virtual address is NULL\n",
+ __func__);
+ goto unmap_pmem_buffer;
+ }
+ buff_addr->virtual_base_addr = mapped_buffer->vaddr;
+ DBG("ddl_pmem_alloc: mem_type(0x%x), phys(0x%x),"\
+ " virt(0x%x), sz(%u), align(%u)",
+ (u32)buff_addr->mem_type,
+ (u32)buff_addr->physical_base_addr,
+ (u32)buff_addr->virtual_base_addr,
+ alloc_size, SZ_4K);
+ }
- physical_addr = (u32)
- allocate_contiguous_memory_nomap(alloc_size,
- ddl_context->memtype, SZ_4K);
-
- if (!physical_addr) {
- pr_err("%s(): could not allocate kernel pmem buffers\n",
- __func__);
- goto bailout;
- }
- buff_addr->physical_base_addr = (u32 *) physical_addr;
- flags = MSM_SUBSYSTEM_MAP_KADDR;
- buff_addr->mapped_buffer =
- msm_subsystem_map_buffer((unsigned long)physical_addr,
- alloc_size, flags, NULL, 0);
- if (IS_ERR(buff_addr->mapped_buffer)) {
- pr_err(" %s() buffer map failed", __func__);
- goto free_acm_alloc;
- }
- mapped_buffer = buff_addr->mapped_buffer;
- if (!mapped_buffer->vaddr) {
- pr_err("%s() mapped virtual address is NULL", __func__);
- goto free_map_buffers;
- }
- buff_addr->virtual_base_addr = mapped_buffer->vaddr;
memset(buff_addr->virtual_base_addr, 0 , sz + guard_bytes);
buff_addr->buffer_size = sz;
-
- buff_addr->align_physical_addr =
- (u32 *) ((physical_addr + guard_bytes) & align_mask);
-
- align_offset =
- (u32) (buff_addr->align_physical_addr) - physical_addr;
-
+ buff_addr->align_physical_addr = (u32 *)
+ (((u32)buff_addr->physical_base_addr + guard_bytes) &
+ align_mask);
+ align_offset = (u32) (buff_addr->align_physical_addr) -
+ (u32)buff_addr->physical_base_addr;
buff_addr->align_virtual_addr =
(u32 *) ((u32) (buff_addr->virtual_base_addr)
+ align_offset);
-
- DBG_PMEM("\n%s() OUT: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
- buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
- buff_addr->buffer_size);
-
+ DBG("%s(): phys(0x%x) align_phys(0x%x), virt(0x%x),"\
+ " align_virt(0x%x)", __func__,
+ (u32)buff_addr->physical_base_addr,
+ (u32)buff_addr->align_physical_addr,
+ (u32)buff_addr->virtual_base_addr,
+ (u32)buff_addr->align_virtual_addr);
return;
-free_map_buffers:
- msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
-free_acm_alloc:
- free_contiguous_memory_by_paddr(
- (unsigned long) physical_addr);
+
+unmap_pmem_buffer:
+ if (buff_addr->mapped_buffer)
+ msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
+free_pmem_buffer:
+ if (buff_addr->physical_base_addr)
+ free_contiguous_memory_by_paddr((unsigned long)
+ buff_addr->physical_base_addr);
+ memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
+ return;
+
+unmap_ion_buffer:
+ if (ddl_context->video_ion_client) {
+ if (buff_addr->alloc_handle)
+ ion_unmap_kernel(ddl_context->video_ion_client,
+ buff_addr->alloc_handle);
+ }
+free_ion_buffer:
+ if (ddl_context->video_ion_client) {
+ if (buff_addr->alloc_handle)
+ ion_free(ddl_context->video_ion_client,
+ buff_addr->alloc_handle);
+ }
bailout:
- buff_addr->physical_base_addr = NULL;
- buff_addr->virtual_base_addr = NULL;
- buff_addr->buffer_size = 0;
- buff_addr->mapped_buffer = NULL;
+ memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
}
void ddl_pmem_free(struct ddl_buf_addr *buff_addr)
{
+ struct ddl_context *ddl_context;
+ ddl_context = ddl_get_context();
if (!buff_addr) {
ERR("\n %s() invalid arguments %p", __func__, buff_addr);
return;
}
- DBG_PMEM("\n%s() IN: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
- buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
+ DBG("ddl_pmem_free: phys(0x%x) align_phys(0x%x), "\
+ "virt(0x%x), align_virt(0x%x), size(%u)",
+ (u32)buff_addr->physical_base_addr,
+ (u32)buff_addr->align_physical_addr,
+ (u32)buff_addr->virtual_base_addr,
+ (u32)buff_addr->align_virtual_addr,
buff_addr->buffer_size);
-
- if (buff_addr->mapped_buffer)
- msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
- if (buff_addr->physical_base_addr)
- free_contiguous_memory_by_paddr(
- (unsigned long) buff_addr->physical_base_addr);
- DBG_PMEM("\n%s() OUT: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
- buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
- buff_addr->buffer_size);
- buff_addr->buffer_size = 0;
- buff_addr->physical_base_addr = NULL;
- buff_addr->virtual_base_addr = NULL;
- buff_addr->mapped_buffer = NULL;
+ if (ddl_context->video_ion_client) {
+ if (buff_addr->alloc_handle) {
+ ion_unmap_kernel(ddl_context->video_ion_client,
+ buff_addr->alloc_handle);
+ ion_free(ddl_context->video_ion_client,
+ buff_addr->alloc_handle);
+ }
+ } else {
+ if (buff_addr->mapped_buffer)
+ msm_subsystem_unmap_buffer(
+ buff_addr->mapped_buffer);
+ if (buff_addr->physical_base_addr)
+ free_contiguous_memory_by_paddr((unsigned long)
+ buff_addr->physical_base_addr);
+ }
+ memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
}
#endif
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index e51bf45..aee9dfe 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -677,8 +677,16 @@
return false;
}
+static struct ion_client *res_trk_create_ion_client(void){
+ struct ion_client *video_client;
+ VCDRES_MSG_LOW("%s", __func__);
+ video_client = msm_ion_client_create(-1, "video_client");
+ return video_client;
+}
+
void res_trk_init(struct device *device, u32 irq)
{
+ VCDRES_MSG_LOW("%s", __func__);
if (resource_context.device || resource_context.irq_num ||
!device) {
VCDRES_MSG_ERROR("%s() Resource Tracker Init error\n",
@@ -695,9 +703,27 @@
(struct msm_vidc_platform_data *) device->platform_data;
if (resource_context.vidc_platform_data) {
resource_context.memtype =
- resource_context.vidc_platform_data->memtype;
+ resource_context.vidc_platform_data->memtype;
+ VCDRES_MSG_LOW("%s(): resource_context.memtype = 0x%x",
+ __func__, (u32)resource_context.memtype);
+ if (resource_context.vidc_platform_data->enable_ion) {
+ resource_context.res_ion_client =
+ res_trk_create_ion_client();
+ if (!(resource_context.res_ion_client)) {
+ VCDRES_MSG_ERROR("%s()ION createfail\n",
+ __func__);
+ return;
+ }
+ VCDRES_MSG_LOW("%s(): ion_client = 0x%x", __func__,
+ (u32)resource_context.res_ion_client);
+ } else {
+ VCDRES_MSG_ERROR("%s(): ION not disabled\n",
+ __func__);
+ }
} else {
resource_context.memtype = -1;
+ VCDRES_MSG_ERROR("%s(): vidc_platform_data is NULL",
+ __func__);
}
}
@@ -705,18 +731,23 @@
return resource_context.core_type;
}
-u32 res_trk_get_mem_type(void){
- return resource_context.memtype;
-}
-
u32 res_trk_get_enable_ion(void)
{
- return 0;
+ if (resource_context.vidc_platform_data->enable_ion)
+ return 1;
+ else
+ return 0;
}
struct ion_client *res_trk_get_ion_client(void)
{
- return NULL;
+ return resource_context.res_ion_client;
+}
+
+u32 res_trk_get_mem_type(void)
+{
+ u32 mem_type = ION_HEAP(resource_context.memtype);
+ return mem_type;
}
void res_trk_set_mem_type(enum ddl_mem_area mem_type)
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
index 2b92a42..f8d9053 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
@@ -13,6 +13,7 @@
#ifndef _VIDEO_720P_RESOURCE_TRACKER_H_
#define _VIDEO_720P_RESOURCE_TRACKER_H_
#include <mach/board.h>
+#include <linux/ion.h>
#include "vcd_res_tracker_api.h"
#define VCD_RESTRK_MIN_PERF_LEVEL 37900
@@ -36,6 +37,8 @@
u32 core_type;
int memtype;
u32 secure_session;
+ struct ion_client *res_ion_client;
+ enum ddl_mem_area res_mem_type;
};
#if DEBUG
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index c3803b1..927f19b 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -915,7 +915,8 @@
__func__);
goto import_ion_error;
}
- if (res_trk_check_for_sec_session()) {
+ if (res_trk_check_for_sec_session() ||
+ (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
rc = ion_phys(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
(unsigned long *) (&(vcd_h264_mv_buffer->
@@ -1038,7 +1039,8 @@
if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
- if (!res_trk_check_for_sec_session()) {
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 9450ee7..50cccbb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1844,7 +1844,8 @@
__func__);
goto import_ion_error;
}
- if (res_trk_check_for_sec_session()) {
+ if (res_trk_check_for_sec_session() ||
+ (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
rc = ion_phys(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i],
&phy_addr, &ion_len);
@@ -1945,7 +1946,8 @@
if (client_ctx->recon_buffer_ion_handle[i]) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i]);
- if (!res_trk_check_for_sec_session()) {
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i],
VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index dcacb3c..c884cf5 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -432,7 +432,9 @@
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle);
- if (!res_trk_check_for_sec_session()) {
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() !=
+ (u32)VCD_CORE_720P)) {
ion_unmap_iommu(
client_ctx->user_ion_client,
buf_addr_table[i].
@@ -456,7 +458,8 @@
if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
- if (!res_trk_check_for_sec_session()) {
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
VIDEO_DOMAIN,
@@ -652,7 +655,8 @@
*kernel_vaddr = (unsigned long)NULL;
goto ion_free_error;
}
- if (res_trk_check_for_sec_session()) {
+ if (res_trk_check_for_sec_session() ||
+ (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
if (ion_phys(client_ctx->user_ion_client,
buff_ion_handle,
&phys_addr, &ion_len)) {
@@ -780,7 +784,7 @@
*num_of_buffers = *num_of_buffers + 1;
DBG("%s() : client_ctx = %p, user_virt_addr = 0x%08lx, "
"kernel_vaddr = 0x%08lx inserted!", __func__,
- client_ctx, user_vaddr, *kernel_vaddr);
+ client_ctx, user_vaddr, kernel_vaddr);
}
mutex_unlock(&client_ctx->enrty_queue_lock);
return true;
@@ -833,7 +837,8 @@
if (buf_addr_table[i].buff_ion_handle) {
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle);
- if (!res_trk_check_for_sec_session()) {
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
ion_unmap_iommu(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle,
VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index c11ac30..28ea453 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -41,6 +41,8 @@
unsigned long buffer_size = 0;
int ret = 0;
unsigned long ionflag = 0;
+ ion_phys_addr_t phyaddr = 0;
+ size_t len = 0;
if (!kernel_vaddr || !phy_addr || !cctxt) {
pr_err("\n%s: Invalid parameters", __func__);
@@ -84,6 +86,9 @@
}
*phy_addr = (u8 *) mapped_buffer->iova[0];
*kernel_vaddr = (u8 *) mapped_buffer->vaddr;
+ VCD_MSG_LOW("vcd_pmem_alloc: phys(0x%x), virt(0x%x), "\
+ "sz(%u), flags(0x%x)", (u32)*phy_addr,
+ (u32)*kernel_vaddr, sz, (u32)flags);
} else {
map_buffer->alloc_handle = ion_alloc(
cctxt->vcd_ion_client, sz, SZ_4K,
@@ -106,7 +111,8 @@
pr_err("%s() ION map failed", __func__);
goto ion_free_bailout;
}
- ret = ion_map_iommu(cctxt->vcd_ion_client,
+ if (res_trk_get_core_type() != (u32)VCD_CORE_720P) {
+ ret = ion_map_iommu(cctxt->vcd_ion_client,
map_buffer->alloc_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL,
@@ -115,18 +121,32 @@
(unsigned long *)&iova,
(unsigned long *)&buffer_size,
UNCACHED, 0);
- if (ret) {
- pr_err("%s() ION iommu map failed", __func__);
- goto ion_map_bailout;
+ if (ret) {
+ pr_err("%s() ION iommu map failed", __func__);
+ goto ion_map_bailout;
+ }
+ map_buffer->phy_addr = iova;
+ } else {
+ ret = ion_phys(cctxt->vcd_ion_client,
+ map_buffer->alloc_handle,
+ &phyaddr,
+ &len);
+ if (ret) {
+ pr_err("%s() ion_phys failed", __func__);
+ goto ion_map_bailout;
+ }
+ map_buffer->phy_addr = phyaddr;
}
- map_buffer->phy_addr = iova;
if (!map_buffer->phy_addr) {
pr_err("%s() acm alloc failed", __func__);
goto free_map_table;
}
- *phy_addr = (u8 *)iova;
+ *phy_addr = (u8 *)map_buffer->phy_addr;
mapped_buffer = NULL;
map_buffer->mapped_buffer = NULL;
+ VCD_MSG_LOW("vcd_ion_alloc: phys(0x%x), virt(0x%x), "\
+ "sz(%u), ionflags(0x%x)", (u32)*phy_addr,
+ (u32)*kernel_vaddr, sz, (u32)ionflag);
}
return 0;
@@ -176,10 +196,13 @@
if (map_buffer->mapped_buffer)
msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
if (cctxt->vcd_enable_ion) {
+ VCD_MSG_LOW("vcd_ion_free: phys(0x%x), virt(0x%x)",
+ (u32)phy_addr, (u32)kernel_vaddr);
if (map_buffer->alloc_handle) {
ion_unmap_kernel(cctxt->vcd_ion_client,
map_buffer->alloc_handle);
- ion_unmap_iommu(cctxt->vcd_ion_client,
+ if (res_trk_get_core_type() != (u32)VCD_CORE_720P)
+ ion_unmap_iommu(cctxt->vcd_ion_client,
map_buffer->alloc_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
@@ -187,6 +210,8 @@
map_buffer->alloc_handle);
}
} else {
+ VCD_MSG_LOW("vcd_pmem_free: phys(0x%x), virt(0x%x)",
+ (u32)phy_addr, (u32)kernel_vaddr);
free_contiguous_memory_by_paddr(
(unsigned long)map_buffer->phy_addr);
}
diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
index 8e8c55b..4dd618f 100644
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -497,8 +497,16 @@
if (ret_val == YAFFS_OK) {
if (target) {
- drop_nlink(new_dentry->d_inode);
- mark_inode_dirty(new_dentry->d_inode);
+ /*
+ * We have identified target to be a
+ * valid directory earlier. If it is
+ * not the case throw a warning.
+ */
+ WARN_ON(!new_dentry->d_inode);
+ if (new_dentry->d_inode) {
+ drop_nlink(new_dentry->d_inode);
+ mark_inode_dirty(new_dentry->d_inode);
+ }
}
update_dir_time(old_dir);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 32d8ec2..cb56293 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -210,6 +210,7 @@
int use_for_apm;
};
+#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
extern struct power_supply *power_supply_get_by_name(char *name);
extern void power_supply_changed(struct power_supply *psy);
extern int power_supply_am_i_supplied(struct power_supply *psy);
@@ -218,10 +219,31 @@
extern int power_supply_set_online(struct power_supply *psy, bool enable);
extern int power_supply_set_scope(struct power_supply *psy, int scope);
extern int power_supply_set_charge_type(struct power_supply *psy, int type);
-
-#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
+extern int power_supply_set_supply_type(struct power_supply *psy,
+ enum power_supply_type supply_type);
extern int power_supply_is_system_supplied(void);
#else
+static inline struct power_supply *power_supply_get_by_name(char *name)
+ { return -ENOSYS; }
+static inline int power_supply_am_i_supplied(struct power_supply *psy)
+ { return -ENOSYS; }
+static inline int power_supply_set_battery_charged(struct power_supply *psy)
+ { return -ENOSYS; }
+static inline int power_supply_set_current_limit(struct power_supply *psy,
+ int limit)
+ { return -ENOSYS; }
+static inline int power_supply_set_online(struct power_supply *psy,
+ bool enable)
+ { return -ENOSYS; }
+static inline int power_supply_set_scope(struct power_supply *psy,
+ int scope)
+ { return -ENOSYS; }
+static inline int power_supply_set_charge_type(struct power_supply *psy,
+ int type)
+ { return -ENOSYS; }
+static inline int power_supply_set_supply_type(struct power_supply *psy,
+ enum power_supply_type supply_type);
+ { return -ENOSYS; }
static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 99fd1d3..485569b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -40,7 +40,11 @@
union afe_port_config port_config;
};
-static struct clk *pcm_clk;
+static struct clk *pcm_src_clk;
+static struct clk *pcm_branch_clk;
+static struct clk *pcm_oe_src_clk;
+static struct clk *pcm_oe_branch_clk;
+
static DEFINE_MUTEX(aux_pcm_mutex);
static int aux_pcm_count;
@@ -120,6 +124,9 @@
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+ clk_disable_unprepare(pcm_branch_clk);
+ clk_disable_unprepare(pcm_oe_branch_clk);
+
mutex_unlock(&aux_pcm_mutex);
}
@@ -127,8 +134,11 @@
struct snd_soc_dai *dai)
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
int rc = 0;
+ auxpcm_pdata = dai->dev->platform_data;
+
mutex_lock(&aux_pcm_mutex);
if (aux_pcm_count == 2) {
@@ -170,12 +180,37 @@
* assert/deasset and afe_open sequence is not followed.
*/
+ rc = clk_set_rate(pcm_src_clk, auxpcm_pdata->pcm_clk_rate);
+ if (rc < 0) {
+ pr_err("%s: clk_set_rate failed\n", __func__);
+ goto fail;
+ }
+
+ rc = clk_prepare_enable(pcm_branch_clk);
+ if (rc) {
+ pr_err("%s: clk enable failed\n", __func__);
+ goto fail;
+ }
+
+ rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
+ if (rc < 0) {
+ pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
+ goto fail;
+ }
+
+ rc = clk_prepare_enable(pcm_oe_branch_clk);
+ if (rc) {
+ pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
+ goto fail;
+ }
+
afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
mutex_unlock(&aux_pcm_mutex);
+fail:
return rc;
}
@@ -217,6 +252,7 @@
auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)
dev_get_drvdata(dai->dev);
dai->dev->platform_data = auxpcm_pdata;
+ dai->id = dai->dev->id;
mutex_lock(&aux_pcm_mutex);
@@ -225,9 +261,41 @@
* data to the cpu driver, since cpu drive is unaware of any
* boarc specific configuration.
*/
- if (!pcm_clk)
- pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+ if ((!pcm_src_clk) || (!pcm_branch_clk)) {
+ pcm_src_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+ if (IS_ERR(pcm_src_clk)) {
+ pr_err("%s: could not get pcm_src_clk\n", __func__);
+ pcm_src_clk = NULL;
+ return -ENODEV;
+ }
+
+ pcm_branch_clk = clk_get(dai->dev, "ibit_clk");
+
+ if (IS_ERR(pcm_branch_clk)) {
+ pr_err("%s: could not get pcm_branch_clk\n", __func__);
+ pcm_branch_clk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ if ((!pcm_oe_src_clk) || (!pcm_oe_branch_clk)) {
+
+ pcm_oe_src_clk = clk_get(dai->dev, "core_oe_src_clk");
+
+ if (IS_ERR(pcm_oe_src_clk)) {
+ pr_err("%s: could not get pcm_oe_src_clk\n", __func__);
+ pcm_oe_src_clk = NULL;
+ return -ENODEV;
+ }
+
+ pcm_oe_branch_clk = clk_get(dai->dev, "core_oe_clk");
+ if (IS_ERR(pcm_oe_branch_clk)) {
+ pr_err("%s: could not get pcm_oe_clk\n", __func__);
+ pcm_oe_branch_clk = NULL;
+ return -ENODEV;
+ }
+ }
mutex_unlock(&aux_pcm_mutex);
dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
@@ -813,7 +881,7 @@
.remove = msm_dai_q6_dai_remove,
};
-static int msm_auxpcm_dev_probe(struct platform_device *pdev)
+static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
{
int id;
void *plat_data;
@@ -837,6 +905,7 @@
dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
dev_set_drvdata(&pdev->dev, plat_data);
+ pdev->dev.id = id;
switch (id) {
case AFE_PORT_ID_PRIMARY_PCM_RX:
@@ -855,7 +924,7 @@
return rc;
}
-static int msm_auxpcm_resource_probe(
+static int __devinit msm_auxpcm_resource_probe(
struct platform_device *pdev)
{
int rc = 0;
@@ -950,13 +1019,13 @@
return rc;
}
-static int msm_auxpcm_dev_remove(struct platform_device *pdev)
+static int __devexit msm_auxpcm_dev_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&pdev->dev);
return 0;
}
-static int msm_auxpcm_resource_remove(
+static int __devexit msm_auxpcm_resource_remove(
struct platform_device *pdev)
{
void *auxpcm_pdata;
@@ -967,22 +1036,20 @@
return 0;
}
-static const struct of_device_id msm_auxpcm_resource_dt_match[] = {
+static struct of_device_id msm_auxpcm_resource_dt_match[] = {
{ .compatible = "qcom,msm-auxpcm-resource", },
{}
};
-MODULE_DEVICE_TABLE(of, msm_auxpcm_resource_dt_match);
-static const struct of_device_id msm_auxpcm_dev_dt_match[] = {
+static struct of_device_id msm_auxpcm_dev_dt_match[] = {
{ .compatible = "qcom,msm-auxpcm-dev", },
{}
};
-MODULE_DEVICE_TABLE(of, msm_auxpcm_dev_dt_match);
-static struct platform_driver msm_auxpcm_dev = {
+static struct platform_driver msm_auxpcm_dev_driver = {
.probe = msm_auxpcm_dev_probe,
- .remove = msm_auxpcm_dev_remove,
+ .remove = __devexit_p(msm_auxpcm_dev_remove),
.driver = {
.name = "msm-auxpcm-dev",
.owner = THIS_MODULE,
@@ -990,9 +1057,9 @@
},
};
-static struct platform_driver msm_auxpcm_resource = {
+static struct platform_driver msm_auxpcm_resource_driver = {
.probe = msm_auxpcm_resource_probe,
- .remove = msm_auxpcm_resource_remove,
+ .remove = __devexit_p(msm_auxpcm_resource_remove),
.driver = {
.name = "msm-auxpcm-resource",
.owner = THIS_MODULE,
@@ -1134,22 +1201,23 @@
{
int rc;
- rc = platform_driver_register(&msm_auxpcm_dev);
+ rc = platform_driver_register(&msm_auxpcm_dev_driver);
if (rc)
goto fail;
- rc = platform_driver_register(&msm_auxpcm_resource);
+ rc = platform_driver_register(&msm_auxpcm_resource_driver);
+
if (rc) {
pr_err("%s: fail to register cpu dai driver\n", __func__);
- platform_driver_unregister(&msm_auxpcm_dev);
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
goto fail;
}
rc = platform_driver_register(&msm_dai_q6);
if (rc) {
pr_err("%s: fail to register dai q6 driver", __func__);
- platform_driver_unregister(&msm_auxpcm_dev);
- platform_driver_unregister(&msm_auxpcm_resource);
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
+ platform_driver_unregister(&msm_auxpcm_resource_driver);
goto fail;
}
@@ -1157,8 +1225,8 @@
if (rc) {
pr_err("%s: fail to register dai q6 dev driver", __func__);
platform_driver_unregister(&msm_dai_q6);
- platform_driver_unregister(&msm_auxpcm_dev);
- platform_driver_unregister(&msm_auxpcm_resource);
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
+ platform_driver_unregister(&msm_auxpcm_resource_driver);
goto fail;
}
fail:
@@ -1170,8 +1238,8 @@
{
platform_driver_unregister(&msm_dai_q6_dev);
platform_driver_unregister(&msm_dai_q6);
- platform_driver_unregister(&msm_auxpcm_dev);
- platform_driver_unregister(&msm_auxpcm_resource);
+ platform_driver_unregister(&msm_auxpcm_dev_driver);
+ platform_driver_unregister(&msm_auxpcm_resource_driver);
}
module_exit(msm_dai_q6_exit);