Merge "msm_serial_hs_lite: Increase TX path timeout" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a33d833..d8784db 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,7 @@
- qcom,saw2-spm-cmd-ret: The Retention command sequence
- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
Example:
qcom,spm@f9089000 {
@@ -56,11 +57,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 0d0c587..a926aa3 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -155,7 +155,7 @@
};
pm8941_l13: regulator@4c00 {
- regulator-min-microvolt = <2950000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 0da3200..79cb95c 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -27,11 +27,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -49,11 +49,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -71,11 +71,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -93,11 +93,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -123,12 +123,12 @@
qcom,vctl-timeout-us = <50>;
qcom,vctl-port = <0x0>; /* TODO: */
qcom,phase-port = <0x1>; /* TODO: */
- qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
- qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
- 78 80 44 22 50 3b 60 02 32
- 50 0f];
- qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
- 07 01 b0 78 80 12 44 a0 50
+ qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 42 07
+ 78 80 44 22 50 3b 60 02 32
+ 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
+ 42 07 01 b0 78 80 12 44 a0 50
3b 60 02 32 a0 50 0f];
};
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3043b78..eb9dc0a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -331,6 +331,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
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/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index cb8903c..5bee8a2 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -485,7 +485,7 @@
RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
RPM_LDO(L17, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
RPM_LDO(L18, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
- RPM_LDO(L20, 1, 1, 0, 1200000, 1200000, "8038_s2", 10000, 10000),
+ RPM_LDO(L20, 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
RPM_LDO(L22, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000),
RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 338cb84..8df37f7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -786,13 +786,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -850,13 +850,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 8740186..3da68ad 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -577,90 +577,98 @@
};
#endif
-static int evb_backlight_control(int level)
+static int evb_backlight_control(int level, int mode)
{
int i = 0;
- int remainder;
+ int remainder, ret = 0;
+
/* device address byte = 0x72 */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ if (!mode) {
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* t-EOS and t-start */
- gpio_set_value(96, 0);
- ndelay(4200);
- gpio_set_value(96, 1);
- ndelay(9000);
+ /* t-EOS and t-start */
+ gpio_set_value(96, 0);
+ ndelay(4200);
+ gpio_set_value(96, 1);
+ ndelay(9000);
- /* data byte */
- /* RFA = 0 */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* data byte */
+ /* RFA = 0 */
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* Address bits */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* Address bits */
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* Data bits */
- for (i = 0; i < 5; i++) {
- remainder = (level) & (16);
- if (remainder) {
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- } else {
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* Data bits */
+ for (i = 0; i < 5; i++) {
+ remainder = (level) & (16);
+ if (remainder) {
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ } else {
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ }
+ level = level << 1;
}
- level = level << 1;
+
+ /* t-EOS */
+ gpio_set_value(96, 0);
+ ndelay(12000);
+ gpio_set_value(96, 1);
+ } else {
+ ret = pmapp_disp_backlight_set_brightness(level);
+ if (ret)
+ pr_err("%s: can't set lcd backlight!\n", __func__);
}
- /* t-EOS */
- gpio_set_value(96, 0);
- ndelay(12000);
- gpio_set_value(96, 1);
- return 0;
+ return ret;
}
static int mipi_NT35510_rotate_panel(void)
@@ -685,7 +693,7 @@
};
static struct msm_panel_common_pdata mipi_NT35510_pdata = {
- .pmic_backlight = evb_backlight_control,
+ .backlight = evb_backlight_control,
.rotate_panel = mipi_NT35510_rotate_panel,
};
@@ -698,7 +706,7 @@
};
static struct msm_panel_common_pdata mipi_NT35516_pdata = {
- .pmic_backlight = evb_backlight_control,
+ .backlight = evb_backlight_control,
};
static struct platform_device mipi_dsi_NT35516_panel_device = {
@@ -1141,6 +1149,7 @@
static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
if (!qrd3_dsi_gpio_initialized) {
+ pmapp_disp_backlight_init();
rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
"qrd3_gpio_bkl_en");
if (rc < 0)
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 50d2060..e5ad312 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -27,10 +27,6 @@
sub r4, r4, r5 @ determine virtual/phys offsets
add r6, r6, r4 @ apply
pen:
- wfe
- dsb @ ensure subsequent access is
- @ after event
-
ldr r7, [r6] @ pen_rel has cpu to remove from reset
cmp r7, r0 @ are we lucky?
bne pen
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 8c1d5b7..243b488 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -389,6 +389,7 @@
int (*backlight_level)(int level, int max, int min);
int (*pmic_backlight)(int level);
int (*rotate_panel)(void);
+ int (*backlight) (int level, int mode);
int (*panel_num)(void);
void (*panel_config_gpio)(int);
int (*vga_switch)(int select_vga);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index bf7c338..b0475ed 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -41,7 +41,7 @@
};
struct ocmem_map_list {
- int num_chunks;
+ unsigned num_chunks;
struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
};
@@ -84,9 +84,14 @@
int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+/* Obtain the maximum quota for the client */
+unsigned long get_max_quota(int client_id);
+
/* Allocation APIs */
struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size);
+
struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index dd3a318..dd976ea 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -24,6 +24,9 @@
#define OCMEM_PHYS_BASE 0xFEC00000
#define OCMEM_PHYS_SIZE 0x180000
+#define TO_OCMEM 0x1
+#define TO_DDR 0x2
+
struct ocmem_zone;
struct ocmem_zone_ops {
@@ -45,6 +48,19 @@
struct ocmem_zone_ops *z_ops;
};
+enum op_code {
+ SCHED_NOP = 0x0,
+ SCHED_ALLOCATE,
+ SCHED_FREE,
+ SCHED_GROW,
+ SCHED_SHRINK,
+ SCHED_MAP,
+ SCHED_UNMAP,
+ SCHED_EVICT,
+ SCHED_RESTORE,
+ SCHED_DUMP,
+};
+
struct ocmem_req {
struct rw_semaphore rw_sem;
/* Chain in sched queue */
@@ -60,6 +76,8 @@
/* reverse pointers */
struct ocmem_zone *zone;
struct ocmem_buf *buffer;
+ struct ocmem_map_list *mlist;
+ enum op_code op;
unsigned long state;
/* Request assignments */
unsigned long req_start;
@@ -73,7 +91,41 @@
struct ocmem_req *req;
};
+static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+ if (handle)
+ return &handle->buffer;
+ else
+ return NULL;
+}
+
+static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+ if (buffer)
+ return container_of(buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
+static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+ if (handle)
+ return handle->req;
+ else
+ return NULL;
+}
+
+static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+ if (req && req->buffer)
+ return container_of(req->buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
struct ocmem_zone *get_zone(unsigned);
+unsigned long offset_to_phys(unsigned long);
+unsigned long phys_to_offset(unsigned long);
unsigned long allocate_head(struct ocmem_zone *, unsigned long);
int free_head(struct ocmem_zone *, unsigned long, unsigned long);
unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
@@ -82,4 +134,12 @@
int ocmem_notifier_init(void);
int check_notifier(int);
int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
+
+int ocmem_sched_init(void);
+int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
+ unsigned long, bool, bool);
+int process_free(int, struct ocmem_handle *);
+int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *,
+ int direction);
+unsigned long process_quota(int);
#endif
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
index d92098b..2f4f6af 100644
--- a/arch/arm/mach-msm/modem_notifier.c
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -193,8 +193,15 @@
}
#endif
-static int __init init_modem_notifier_list(void)
+int __init msm_init_modem_notifier_list(void)
{
+ static bool registered;
+
+ if (registered)
+ return 0;
+
+ registered = true;
+
srcu_init_notifier_head(&modem_notifier_list);
modem_notifier_debugfs_init();
#if defined(DEBUG)
@@ -210,4 +217,4 @@
return 0;
}
-module_init(init_modem_notifier_list);
+module_init(msm_init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
index 1bd2d6d..e39c163 100644
--- a/arch/arm/mach-msm/modem_notifier.h
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -30,5 +30,6 @@
extern void modem_queue_start_reset_notify(void);
extern void modem_queue_end_reset_notify(void);
extern void modem_queue_smsm_init_notify(void);
+extern int __init msm_init_modem_notifier_list(void);
#endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index ddfc906..ae1d6f2 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -97,6 +97,25 @@
return -EINVAL;
}
+inline unsigned long phys_to_offset(unsigned long addr)
+{
+ if (!ocmem_pdata)
+ return 0;
+ if (addr < ocmem_pdata->base ||
+ addr > (ocmem_pdata->base + ocmem_pdata->size))
+ return 0;
+ return addr - ocmem_pdata->base;
+}
+
+inline unsigned long offset_to_phys(unsigned long offset)
+{
+ if (!ocmem_pdata)
+ return 0;
+ if (offset > ocmem_pdata->size)
+ return 0;
+ return offset + ocmem_pdata->base;
+}
+
static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
{
struct ocmem_plat_data *pdata = NULL;
@@ -276,6 +295,8 @@
if (ocmem_notifier_init())
return -EBUSY;
+ if (ocmem_sched_init())
+ return -EBUSY;
dev_info(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
new file mode 100644
index 0000000..bed13de
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -0,0 +1,327 @@
+/* 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/slab.h>
+#include <mach/ocmem_priv.h>
+
+static inline int check_id(int id)
+{
+ return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+static struct ocmem_handle *generate_handle(void)
+{
+ struct ocmem_handle *handle = NULL;
+
+ handle = kzalloc(sizeof(struct ocmem_handle), GFP_KERNEL);
+ if (!handle) {
+ pr_err("ocmem: Unable to generate buffer handle\n");
+ return NULL;
+ }
+ mutex_init(&handle->handle_mutex);
+ return handle;
+}
+
+static int free_handle(struct ocmem_handle *handle)
+{
+ if (!handle)
+ return -EINVAL;
+
+ mutex_destroy(&handle->handle_mutex);
+ kfree(handle);
+ handle = NULL;
+ return 0;
+}
+
+static int __ocmem_free(int id, struct ocmem_buf *buf)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = buffer_to_handle(buf);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_free(id, handle);
+ mutex_unlock(&handle->handle_mutex);
+
+ if (ret)
+ return -EINVAL;
+
+ free_handle(handle);
+ return 0;
+}
+
+static struct ocmem_buf *__ocmem_allocate_range(int id, unsigned long min,
+ unsigned long max, unsigned long step, bool block, bool wait)
+{
+ struct ocmem_handle *handle = NULL;
+ int ret = 0;
+
+ handle = generate_handle();
+ if (!handle) {
+ pr_err("ocmem: Unable to generate handle\n");
+ return NULL;
+ }
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_allocate(id, handle, min, max, step, block, wait);
+ mutex_unlock(&handle->handle_mutex);
+ if (ret) {
+ pr_err("ocmem allocation failed\n");
+ free_handle(handle);
+ return NULL;
+ } else
+ return handle_to_buffer(handle);
+}
+
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size)
+{
+ bool can_block = false;
+ bool can_wait = true;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, size, size,
+ size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
+{
+ bool can_block = false;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+ return __ocmem_allocate_range(client_id, size, size,
+ size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+ unsigned long goal, unsigned long step)
+{
+ bool can_block = true;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return NULL;
+ }
+
+ if (min < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested min size %lx must be at least %x\n",
+ min, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(min | goal | step, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, min, goal,
+ step, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
+{
+ bool can_block = true;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, 0, size, size,
+ can_block, can_wait);
+
+}
+
+int ocmem_free(int client_id, struct ocmem_buf *buffer)
+{
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ return __ocmem_free(client_id, buffer);
+}
+
+int pre_validate_chunk_list(struct ocmem_map_list *list)
+{
+ int i = 0;
+ struct ocmem_chunk *chunks;
+
+ if (!list)
+ return -EINVAL;
+
+ if (list->num_chunks > OCMEM_MAX_CHUNKS || list->num_chunks == 0)
+ return -EINVAL;
+
+ chunks = list->chunks;
+
+ if (!chunks)
+ return -EINVAL;
+
+ for (i = 0; i < list->num_chunks; i++) {
+ if (!chunks[i].ddr_paddr ||
+ chunks[i].size < MIN_CHUNK_SIZE)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ if (!pre_validate_chunk_list(list))
+ return -EINVAL;
+
+ handle = buffer_to_handle(buffer);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_xfer(client_id, handle, list, TO_OCMEM);
+ mutex_unlock(&handle->handle_mutex);
+ return ret;
+}
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+
+ int ret = 0;
+ struct ocmem_handle *handle = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ if (!pre_validate_chunk_list(list))
+ return -EINVAL;
+
+ handle = buffer_to_handle(buffer);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_xfer(client_id, handle, list, TO_DDR);
+ mutex_unlock(&handle->handle_mutex);
+ return ret;
+}
+
+unsigned long get_max_quota(int client_id)
+{
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return 0x0;
+ }
+ return process_quota(client_id);
+}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
new file mode 100644
index 0000000..10a267c
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -0,0 +1,1255 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
+
+enum request_states {
+ R_FREE = 0x0, /* request is not allocated */
+ R_PENDING, /* request has a pending operation */
+ R_ALLOCATED, /* request has been allocated */
+ R_MUST_GROW, /* request must grow as a part of pending operation */
+ R_MUST_SHRINK, /* request must shrink as a part of pending operation */
+ R_MUST_MAP, /* request must be mapped before being used */
+ R_MUST_UNMAP, /* request must be unmapped when not being used */
+ R_MAPPED, /* request is mapped and actively used by client */
+ R_UNMAPPED, /* request is not mapped, so it's not in active use */
+ R_EVICTED, /* request is evicted and must be restored */
+};
+
+#define SET_STATE(x, val) (set_bit((val), &(x)->state))
+#define CLEAR_STATE(x, val) (clear_bit((val), &(x)->state))
+#define TEST_STATE(x, val) (test_bit((val), &(x)->state))
+
+enum op_res {
+ OP_COMPLETE = 0x0,
+ OP_RESCHED,
+ OP_PARTIAL,
+ OP_FAIL = ~0x0,
+};
+
+/* Represents various client priorities */
+/* Note: More than one client can share a priority level */
+enum client_prio {
+ MIN_PRIO = 0x0,
+ NO_PRIO = MIN_PRIO,
+ PRIO_SENSORS = 0x1,
+ PRIO_BLAST = 0x1,
+ PRIO_LP_AUDIO = 0x1,
+ PRIO_HP_AUDIO = 0x2,
+ PRIO_VOICE = 0x3,
+ PRIO_GFX_GROWTH = 0x4,
+ PRIO_VIDEO = 0x5,
+ PRIO_GFX = 0x6,
+ PRIO_OCMEM = 0x7,
+ MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
+};
+
+static struct list_head sched_queue[MAX_OCMEM_PRIO];
+static struct mutex sched_queue_mutex;
+
+/* The duration in msecs before a pending operation is scheduled
+ * This allows an idle window between use case boundaries where various
+ * hardware state changes can occur. The value will be tweaked on actual
+ * hardware.
+*/
+#define SCHED_DELAY 10
+
+/* OCMEM Operational modes */
+enum ocmem_client_modes {
+ OCMEM_PERFORMANCE = 1,
+ OCMEM_PASSIVE,
+ OCMEM_LOW_POWER,
+ OCMEM_MODE_MAX = OCMEM_LOW_POWER
+};
+
+/* OCMEM Addressing modes */
+enum ocmem_interconnects {
+ OCMEM_BLOCKED = 0,
+ OCMEM_PORT = 1,
+ OCMEM_OCMEMNOC = 2,
+ OCMEM_SYSNOC = 3,
+};
+
+/**
+ * Primary OCMEM Arbitration Table
+ **/
+struct ocmem_table {
+ int client_id;
+ int priority;
+ int mode;
+ int hw_interconnect;
+} ocmem_client_table[OCMEM_CLIENT_MAX] = {
+ {OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
+ {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
+ {OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
+ {OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+ {OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+ {OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+};
+
+static struct rb_root sched_tree;
+static struct mutex sched_mutex;
+
+/* A region represents a continuous interval in OCMEM address space */
+struct ocmem_region {
+ /* Chain in Interval Tree */
+ struct rb_node region_rb;
+ /* Hash map of requests */
+ struct idr region_idr;
+ unsigned long r_start;
+ unsigned long r_end;
+ unsigned long r_sz;
+ /* Highest priority of all requests served by this region */
+ int max_prio;
+};
+
+/* Is OCMEM tightly coupled to the client ?*/
+static inline int is_tcm(int id)
+{
+ if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
+ ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_blocked(int id)
+{
+ return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
+}
+
+/* Returns the address that can be used by a device core to access OCMEM */
+static unsigned long device_address(int id, unsigned long addr)
+{
+ int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+ unsigned long ret_addr = 0x0;
+
+ switch (hw_interconnect) {
+ case OCMEM_PORT:
+ ret_addr = phys_to_offset(addr);
+ break;
+ case OCMEM_OCMEMNOC:
+ case OCMEM_SYSNOC:
+ ret_addr = addr;
+ break;
+ case OCMEM_BLOCKED:
+ ret_addr = 0x0;
+ break;
+ }
+ return ret_addr;
+}
+
+/* Returns the address as viewed by the core */
+static unsigned long core_address(int id, unsigned long addr)
+{
+ int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+ unsigned long ret_addr = 0x0;
+
+ switch (hw_interconnect) {
+ case OCMEM_PORT:
+ ret_addr = offset_to_phys(addr);
+ break;
+ case OCMEM_OCMEMNOC:
+ case OCMEM_SYSNOC:
+ ret_addr = addr;
+ break;
+ case OCMEM_BLOCKED:
+ ret_addr = 0x0;
+ break;
+ }
+ return ret_addr;
+}
+
+static int insert_region(struct ocmem_region *region)
+{
+
+ struct rb_root *root = &sched_tree;
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct ocmem_region *tmp = NULL;
+ unsigned long addr = region->r_start;
+
+ while (*p) {
+ parent = *p;
+ tmp = rb_entry(parent, struct ocmem_region, region_rb);
+
+ if (tmp->r_end > addr) {
+ if (tmp->r_start <= addr)
+ break;
+ p = &(*p)->rb_left;
+ } else if (tmp->r_end <= addr)
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(®ion->region_rb, parent, p);
+ rb_insert_color(®ion->region_rb, root);
+ return 0;
+}
+
+static int remove_region(struct ocmem_region *region)
+{
+ struct rb_root *root = &sched_tree;
+ rb_erase(®ion->region_rb, root);
+ return 0;
+}
+
+static struct ocmem_req *ocmem_create_req(void)
+{
+ struct ocmem_req *p = NULL;
+
+ p = kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ INIT_LIST_HEAD(&p->zone_list);
+ INIT_LIST_HEAD(&p->sched_list);
+ init_rwsem(&p->rw_sem);
+ SET_STATE(p, R_FREE);
+ return p;
+}
+
+static int ocmem_destroy_req(struct ocmem_req *req)
+{
+ kfree(req);
+ return 0;
+}
+
+static struct ocmem_region *create_region(void)
+{
+ struct ocmem_region *p = NULL;
+
+ p = kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ idr_init(&p->region_idr);
+ p->r_start = p->r_end = p->r_sz = 0x0;
+ p->max_prio = NO_PRIO;
+ return p;
+}
+
+static int destroy_region(struct ocmem_region *region)
+{
+ kfree(region);
+ return 0;
+}
+
+static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+ int ret, id;
+
+ while (1) {
+ if (idr_pre_get(®ion->region_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ ret = idr_get_new_above(®ion->region_idr, req, 1, &id);
+
+ if (ret != -EAGAIN)
+ break;
+ }
+
+ if (!ret) {
+ req->req_id = id;
+ pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
+ req, id, region);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+ idr_remove(®ion->region_idr, req->req_id);
+ return 0;
+}
+
+static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
+{
+ region->r_start = req->req_start;
+ region->r_end = req->req_end;
+ region->r_sz = req->req_end - req->req_start + 1;
+ return 0;
+}
+
+static int region_req_count(int id, void *ptr, void *data)
+{
+ int *count = data;
+ *count = *count + 1;
+ return 0;
+}
+
+static int req_count(struct ocmem_region *region)
+{
+ int count = 0;
+ idr_for_each(®ion->region_idr, region_req_count, &count);
+ return count;
+}
+
+static int compute_max_prio(int id, void *ptr, void *data)
+{
+ int *max = data;
+ struct ocmem_req *req = ptr;
+
+ if (req->prio > *max)
+ *max = req->prio;
+ return 0;
+}
+
+static int update_region_prio(struct ocmem_region *region)
+{
+ int max_prio;
+ if (req_count(region) != 0) {
+ idr_for_each(®ion->region_idr, compute_max_prio, &max_prio);
+ region->max_prio = max_prio;
+ } else {
+ region->max_prio = NO_PRIO;
+ }
+ pr_debug("ocmem: Updating prio of region %p as %d\n",
+ region, max_prio);
+
+ return 0;
+}
+
+static struct ocmem_region *find_region(unsigned long addr)
+{
+ struct ocmem_region *region = NULL;
+ struct rb_node *rb_node = NULL;
+
+ rb_node = sched_tree.rb_node;
+
+ while (rb_node) {
+ struct ocmem_region *tmp_region = NULL;
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+ if (tmp_region->r_end > addr) {
+ region = tmp_region;
+ if (tmp_region->r_start <= addr)
+ break;
+ rb_node = rb_node->rb_left;
+ } else {
+ rb_node = rb_node->rb_right;
+ }
+ }
+ return region;
+}
+
+static struct ocmem_region *find_region_intersection(unsigned long start,
+ unsigned long end)
+{
+
+ struct ocmem_region *region = NULL;
+ region = find_region(start);
+ if (region && end <= region->r_start)
+ region = NULL;
+ return region;
+}
+
+static struct ocmem_region *find_region_match(unsigned long start,
+ unsigned long end)
+{
+
+ struct ocmem_region *region = NULL;
+ region = find_region(start);
+ if (region && start == region->r_start && end == region->r_end)
+ return region;
+ return NULL;
+}
+
+static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
+{
+ struct ocmem_req *req = NULL;
+
+ if (!region)
+ return NULL;
+
+ req = idr_find(®ion->region_idr, owner);
+
+ return req;
+}
+
+/* Must be called with req->sem held */
+static inline int is_mapped(struct ocmem_req *req)
+{
+ return TEST_STATE(req, R_MAPPED);
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_unmap(struct ocmem_req *req)
+{
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ if (!is_mapped(req)) {
+ pr_err("Request is not currently mapped");
+ goto invalid_op_error;
+ }
+
+ /* Update the request state */
+ CLEAR_STATE(req, R_MAPPED);
+ SET_STATE(req, R_MUST_MAP);
+
+ return OP_COMPLETE;
+
+invalid_op_error:
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_map(struct ocmem_req *req)
+{
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ /* Update the request state */
+ CLEAR_STATE(req, R_MUST_MAP);
+ SET_STATE(req, R_MAPPED);
+
+ return OP_COMPLETE;
+
+invalid_op_error:
+ return OP_FAIL;
+}
+
+static int do_map(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ mutex_lock(&sched_mutex);
+ rc = __sched_map(req);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int do_unmap(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ mutex_lock(&sched_mutex);
+ rc = __sched_unmap(req);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* process map is a wrapper where power control will be added later */
+static int process_map(struct ocmem_req *req, unsigned long start,
+ unsigned long end)
+{
+ return do_map(req);
+}
+
+/* process unmap is a wrapper where power control will be added later */
+static int process_unmap(struct ocmem_req *req, unsigned long start,
+ unsigned long end)
+{
+ return do_unmap(req);
+}
+
+static int __sched_grow(struct ocmem_req *req, bool can_block)
+{
+ unsigned long min = req->req_min;
+ unsigned long max = req->req_max;
+ unsigned long step = req->req_step;
+ int owner = req->owner;
+ unsigned long curr_sz = 0;
+ unsigned long growth_sz = 0;
+ unsigned long curr_start = 0;
+ enum client_prio prio = req->prio;
+ unsigned long alloc_addr = 0x0;
+ bool retry;
+ struct ocmem_region *spanned_r = NULL;
+ struct ocmem_region *overlap_r = NULL;
+
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+ struct ocmem_region *region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ curr_sz = matched_req->req_sz;
+ curr_start = matched_req->req_start;
+ growth_sz = matched_req->req_max - matched_req->req_sz;
+
+ pr_debug("Attempting to grow req %p from %lx to %lx\n",
+ req, matched_req->req_sz, matched_req->req_max);
+
+ retry = false;
+
+ pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
+
+retry_next_step:
+
+ spanned_r = NULL;
+ overlap_r = NULL;
+
+ spanned_r = find_region(zone->z_head);
+ overlap_r = find_region_intersection(zone->z_head,
+ zone->z_head + growth_sz);
+
+ if (overlap_r == NULL) {
+ /* no conflicting regions, schedule this region */
+ zone->z_ops->free(zone, curr_start, curr_sz);
+ alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+
+ if (alloc_addr < 0) {
+ pr_err("ocmem: zone allocation operation failed\n");
+ goto internal_error;
+ }
+
+ curr_sz += growth_sz;
+ /* Detach the region from the interval tree */
+ /* This is to guarantee that any change in size
+ * causes the tree to be rebalanced if required */
+
+ detach_req(matched_region, req);
+ if (req_count(matched_region) == 0) {
+ remove_region(matched_region);
+ region = matched_region;
+ } else {
+ region = create_region();
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto region_error;
+ }
+ }
+
+ /* update the request */
+ req->req_start = alloc_addr;
+ /* increment the size to reflect new length */
+ req->req_sz = curr_sz;
+ req->req_end = alloc_addr + req->req_sz - 1;
+
+ /* update request state */
+ CLEAR_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_MUST_MAP);
+ req->op = SCHED_MAP;
+
+ /* update the region with new req */
+ attach_req(region, req);
+ populate_region(region, req);
+ update_region_prio(region);
+
+ /* update the tree with new region */
+ if (insert_region(region)) {
+ pr_err("ocmem: Failed to insert the region\n");
+ goto region_error;
+ }
+
+ if (retry) {
+ SET_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_PENDING);
+ req->op = SCHED_GROW;
+ return OP_PARTIAL;
+ }
+ } else if (spanned_r != NULL && overlap_r != NULL) {
+ /* resolve conflicting regions based on priority */
+ if (overlap_r->max_prio < prio) {
+ /* Growth cannot be triggered unless a previous
+ * client of lower priority was evicted */
+ pr_err("ocmem: Invalid growth scheduled\n");
+ /* This is serious enough to fail */
+ BUG();
+ return OP_FAIL;
+ } else if (overlap_r->max_prio > prio) {
+ if (min == max) {
+ /* Cannot grow at this time, try later */
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ } else {
+ /* Try to grow in steps */
+ growth_sz -= step;
+ /* We are OOM at this point so need to retry */
+ if (growth_sz <= curr_sz) {
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ }
+ retry = true;
+ pr_debug("ocmem: Attempting with reduced size %lx\n",
+ growth_sz);
+ goto retry_next_step;
+ }
+ } else {
+ pr_err("ocmem: grow: New Region %p Existing %p\n",
+ matched_region, overlap_r);
+ pr_err("ocmem: Undetermined behavior\n");
+ /* This is serious enough to fail */
+ BUG();
+ }
+ } else if (spanned_r == NULL && overlap_r != NULL) {
+ goto err_not_supported;
+ }
+
+ return OP_COMPLETE;
+
+err_not_supported:
+ pr_err("ocmem: Scheduled unsupported operation\n");
+ return OP_FAIL;
+region_error:
+ zone->z_ops->free(zone, alloc_addr, curr_sz);
+ detach_req(region, req);
+ update_region_prio(region);
+ /* req is going to be destroyed by the caller anyways */
+internal_error:
+ destroy_region(region);
+invalid_op_error:
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_free(struct ocmem_req *req)
+{
+ int owner = req->owner;
+ int ret = 0;
+
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+
+ BUG_ON(!zone);
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req)
+ goto invalid_op_error;
+ if (matched_req != req)
+ goto invalid_op_error;
+
+ ret = zone->z_ops->free(zone,
+ matched_req->req_start, matched_req->req_sz);
+
+ if (ret < 0)
+ goto err_op_fail;
+
+ detach_req(matched_region, matched_req);
+ update_region_prio(matched_region);
+ if (req_count(matched_region) == 0) {
+ remove_region(matched_region);
+ destroy_region(matched_region);
+ }
+
+ /* Update the request */
+ req->req_start = 0x0;
+ req->req_sz = 0x0;
+ req->req_end = 0x0;
+ SET_STATE(req, R_FREE);
+ return OP_COMPLETE;
+invalid_op_error:
+ pr_err("ocmem: free: Failed to find matching region\n");
+err_op_fail:
+ pr_err("ocmem: free: Failed\n");
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_allocate(struct ocmem_req *req, bool can_block,
+ bool can_wait)
+{
+ unsigned long min = req->req_min;
+ unsigned long max = req->req_max;
+ unsigned long step = req->req_step;
+ int owner = req->owner;
+ unsigned long sz = max;
+ enum client_prio prio = req->prio;
+ unsigned long alloc_addr = 0x0;
+ bool retry;
+
+ struct ocmem_region *spanned_r = NULL;
+ struct ocmem_region *overlap_r = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+ struct ocmem_region *region = NULL;
+
+ BUG_ON(!zone);
+
+ if (min > (zone->z_end - zone->z_start)) {
+ pr_err("ocmem: requested minimum size exceeds quota\n");
+ goto invalid_op_error;
+ }
+
+ if (max > (zone->z_end - zone->z_start)) {
+ pr_err("ocmem: requested maximum size exceeds quota\n");
+ goto invalid_op_error;
+ }
+
+ if (min > zone->z_free) {
+ pr_err("ocmem: out of memory for zone %d\n", owner);
+ goto invalid_op_error;
+ }
+
+ region = create_region();
+
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto invalid_op_error;
+ }
+
+ retry = false;
+
+ pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+
+retry_next_step:
+
+ spanned_r = NULL;
+ overlap_r = NULL;
+
+ spanned_r = find_region(zone->z_head);
+ overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
+
+ if (overlap_r == NULL) {
+ /* no conflicting regions, schedule this region */
+ alloc_addr = zone->z_ops->allocate(zone, sz);
+
+ if (alloc_addr < 0) {
+ pr_err("Zone Allocation operation failed\n");
+ goto internal_error;
+ }
+
+ /* update the request */
+ req->req_start = alloc_addr;
+ req->req_end = alloc_addr + sz - 1;
+ req->req_sz = sz;
+ req->zone = zone;
+
+ /* update request state */
+ CLEAR_STATE(req, R_FREE);
+ SET_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_MUST_MAP);
+ req->op = SCHED_NOP;
+
+ /* attach the request to the region */
+ attach_req(region, req);
+ populate_region(region, req);
+ update_region_prio(region);
+
+ /* update the tree with new region */
+ if (insert_region(region)) {
+ pr_err("ocmem: Failed to insert the region\n");
+ zone->z_ops->free(zone, alloc_addr, sz);
+ detach_req(region, req);
+ update_region_prio(region);
+ /* req will be destroyed by the caller */
+ goto internal_error;
+ }
+
+ if (retry) {
+ SET_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_PENDING);
+ req->op = SCHED_GROW;
+ return OP_PARTIAL;
+ }
+ } else if (spanned_r != NULL && overlap_r != NULL) {
+ /* resolve conflicting regions based on priority */
+ if (overlap_r->max_prio < prio) {
+ if (min == max) {
+ pr_err("ocmem: Requires eviction support\n");
+ goto err_not_supported;
+ } else {
+ /* Try to allocate atleast >= 'min' immediately */
+ sz -= step;
+ if (sz < min)
+ goto err_out_of_mem;
+ retry = true;
+ pr_debug("ocmem: Attempting with reduced size %lx\n",
+ sz);
+ goto retry_next_step;
+ }
+ } else if (overlap_r->max_prio > prio) {
+ if (can_block == true) {
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ } else {
+ if (min == max) {
+ pr_err("Cannot allocate %lx synchronously\n",
+ sz);
+ goto err_out_of_mem;
+ } else {
+ sz -= step;
+ if (sz < min)
+ goto err_out_of_mem;
+ retry = true;
+ pr_debug("ocmem: Attempting reduced size %lx\n",
+ sz);
+ goto retry_next_step;
+ }
+ }
+ } else {
+ pr_err("ocmem: Undetermined behavior\n");
+ pr_err("ocmem: New Region %p Existing %p\n", region,
+ overlap_r);
+ /* This is serious enough to fail */
+ BUG();
+ }
+ } else if (spanned_r == NULL && overlap_r != NULL)
+ goto err_not_supported;
+
+ return OP_COMPLETE;
+
+err_not_supported:
+ pr_err("ocmem: Scheduled unsupported operation\n");
+ return OP_FAIL;
+
+err_out_of_mem:
+ pr_err("ocmem: Out of memory during allocation\n");
+internal_error:
+ destroy_region(region);
+invalid_op_error:
+ return OP_FAIL;
+}
+
+static int sched_enqueue(struct ocmem_req *priv)
+{
+ struct ocmem_req *next = NULL;
+ mutex_lock(&sched_queue_mutex);
+ list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
+ pr_debug("enqueued req %p\n", priv);
+ list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
+ pr_debug("pending requests for client %p\n", next);
+ }
+ mutex_unlock(&sched_queue_mutex);
+ return 0;
+}
+
+static struct ocmem_req *ocmem_fetch_req(void)
+{
+ int i;
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+
+ mutex_lock(&sched_queue_mutex);
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+ if (list_empty(&sched_queue[i]))
+ continue;
+ list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
+ {
+ if (req) {
+ pr_debug("ocmem: Fetched pending request %p\n",
+ req);
+ list_del(&req->sched_list);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&sched_queue_mutex);
+ return req;
+}
+
+int process_xfer(int id, struct ocmem_handle *handle,
+ struct ocmem_map_list *list, int direction)
+{
+
+ return 0;
+}
+
+unsigned long process_quota(int id)
+{
+ struct ocmem_zone *zone = NULL;
+
+ if (is_blocked(id))
+ return 0;
+
+ zone = get_zone(id);
+
+ if (zone && zone->z_pool)
+ return zone->z_end - zone->z_start;
+ else
+ return 0;
+}
+
+static int do_grow(struct ocmem_req *req)
+{
+ struct ocmem_buf *buffer = NULL;
+ bool can_block = true;
+ int rc = 0;
+
+ down_write(&req->rw_sem);
+ buffer = req->buffer;
+
+ /* Take the scheduler mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_grow(req, can_block);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ goto err_op_fail;
+
+ if (rc == OP_RESCHED) {
+ pr_debug("ocmem: Enqueue this allocation");
+ sched_enqueue(req);
+ }
+
+ else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_op_fail:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
+static int process_grow(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ /* Attempt to grow the region */
+ rc = do_grow(req);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ /* Map the newly grown region */
+ if (is_tcm(req->owner)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ /* Notify the client about the buffer growth */
+ rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
+ if (rc < 0) {
+ pr_err("No notifier callback to cater for req %p event: %d\n",
+ req, OCMEM_ALLOC_GROW);
+ BUG();
+ }
+ return 0;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work);
+DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
+
+static int ocmem_schedule_pending(void)
+{
+ schedule_delayed_work(&ocmem_sched_thread,
+ msecs_to_jiffies(SCHED_DELAY));
+ return 0;
+}
+
+static int do_free(struct ocmem_req *req)
+{
+ int rc = 0;
+ struct ocmem_buf *buffer = req->buffer;
+
+ down_write(&req->rw_sem);
+
+ if (is_mapped(req)) {
+ pr_err("ocmem: Buffer needs to be unmapped before free\n");
+ goto err_free_fail;
+ }
+
+ /* Grab the sched mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_free(req);
+ mutex_unlock(&sched_mutex);
+
+ switch (rc) {
+
+ case OP_COMPLETE:
+ buffer->addr = 0x0;
+ buffer->len = 0x0;
+ break;
+ case OP_FAIL:
+ default:
+ goto err_free_fail;
+ break;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_free_fail:
+ up_write(&req->rw_sem);
+ pr_err("ocmem: freeing req %p failed\n", req);
+ return -EINVAL;
+}
+
+int process_free(int id, struct ocmem_handle *handle)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf *buffer = NULL;
+ int rc = 0;
+
+ if (is_blocked(id)) {
+ pr_err("Client %d cannot request free\n", id);
+ return -EINVAL;
+ }
+
+ req = handle_to_req(handle);
+ buffer = handle_to_buffer(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (req->req_start != core_address(id, buffer->addr)) {
+ pr_err("Invalid buffer handle passed for free\n");
+ return -EINVAL;
+ }
+
+ if (is_tcm(req->owner)) {
+ rc = process_unmap(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ rc = do_free(req);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ ocmem_destroy_req(req);
+ handle->req = NULL;
+
+ ocmem_schedule_pending();
+ return 0;
+}
+
+static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
+{
+ int rc = 0;
+ struct ocmem_buf *buffer = req->buffer;
+
+ down_write(&req->rw_sem);
+
+ /* Take the scheduler mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_allocate(req, can_block, can_wait);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ goto err_allocate_fail;
+
+ if (rc == OP_RESCHED) {
+ buffer->addr = 0x0;
+ buffer->len = 0x0;
+ pr_debug("ocmem: Enqueuing req %p\n", req);
+ sched_enqueue(req);
+ } else if (rc == OP_PARTIAL) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ pr_debug("ocmem: Enqueuing req %p\n", req);
+ sched_enqueue(req);
+ } else if (rc == OP_COMPLETE) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_allocate_fail:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
+
+int process_allocate(int id, struct ocmem_handle *handle,
+ unsigned long min, unsigned long max,
+ unsigned long step, bool can_block, bool can_wait)
+{
+
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf *buffer = NULL;
+ int rc = 0;
+
+ /* sanity checks */
+ if (is_blocked(id)) {
+ pr_err("Client %d cannot request allocation\n", id);
+ return -EINVAL;
+ }
+
+ if (handle->req != NULL) {
+ pr_err("Invalid handle passed in\n");
+ return -EINVAL;
+ }
+
+ buffer = handle_to_buffer(handle);
+ BUG_ON(buffer == NULL);
+
+ /* prepare a request structure to represent this transaction */
+ req = ocmem_create_req();
+ if (!req)
+ return -ENOMEM;
+
+ req->owner = id;
+ req->req_min = min;
+ req->req_max = max;
+ req->req_step = step;
+ req->prio = ocmem_client_table[id].priority;
+ req->op = SCHED_ALLOCATE;
+ req->buffer = buffer;
+
+ rc = do_allocate(req, can_block, can_wait);
+
+ if (rc < 0)
+ goto do_allocate_error;
+
+ handle->req = req;
+
+ if (is_tcm(id)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ goto map_error;
+ }
+
+ return 0;
+
+map_error:
+ handle->req = NULL;
+ do_free(req);
+do_allocate_error:
+ ocmem_destroy_req(req);
+ return -EINVAL;
+}
+
+int process_delayed_allocate(struct ocmem_req *req)
+{
+
+ struct ocmem_handle *handle = NULL;
+ int rc = 0;
+ int id = req->owner;
+
+ handle = req_to_handle(req);
+ BUG_ON(handle == NULL);
+
+ rc = do_allocate(req, true, false);
+
+ if (rc < 0)
+ goto do_allocate_error;
+
+ if (is_tcm(id)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ goto map_error;
+ }
+
+ /* Notify the client about the buffer growth */
+ rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
+ if (rc < 0) {
+ pr_err("No notifier callback to cater for req %p event: %d\n",
+ req, OCMEM_ALLOC_GROW);
+ BUG();
+ }
+ return 0;
+
+map_error:
+ handle->req = NULL;
+ do_free(req);
+do_allocate_error:
+ ocmem_destroy_req(req);
+ return -EINVAL;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work)
+{
+
+ struct ocmem_buf *buffer = NULL;
+ struct ocmem_handle *handle = NULL;
+ struct ocmem_req *req = ocmem_fetch_req();
+
+ if (!req) {
+ pr_debug("No Pending Requests found\n");
+ return;
+ }
+
+ pr_debug("ocmem: sched_wk pending req %p\n", req);
+ handle = req_to_handle(req);
+ buffer = handle_to_buffer(handle);
+ BUG_ON(req->op == SCHED_NOP);
+
+ switch (req->op) {
+ case SCHED_GROW:
+ process_grow(req);
+ break;
+ case SCHED_ALLOCATE:
+ process_delayed_allocate(req);
+ break;
+ default:
+ pr_err("ocmem: Unknown operation encountered\n");
+ break;
+ }
+ return;
+}
+
+int ocmem_sched_init(void)
+{
+ int i = 0;
+ sched_tree = RB_ROOT;
+ mutex_init(&sched_mutex);
+ mutex_init(&sched_queue_mutex);
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
+ INIT_LIST_HEAD(&sched_queue[i]);
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index b40c0c7..49e63aa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -202,8 +202,6 @@
pen_release = cpu_logical_map(cpu);
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
- __asm__("sev");
- mb();
/*
* Send the secondary CPU a soft interrupt, thereby causing
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2980811..6e81be6 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -282,14 +282,22 @@
uint32_t notify_rpm;
};
- struct mode_of mode_of_data[] = {
- {"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
- {"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
- {"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
- {"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+ struct mode_of of_cpu_modes[] = {
+ {"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+ {"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+ {"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
};
- BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+ struct mode_of of_l2_modes[] = {
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
+ {"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
+ {"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
+ };
+
+ struct mode_of *mode_of_data;
+ int num_modes;
+
memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
memset(&modes, 0,
(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
@@ -339,7 +347,22 @@
spm_data.reg_init_values[spm_of_data[i].id] = val;
}
- for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+ /*
+ * Device with id 0..NR_CPUS are SPM for apps cores
+ * Device with id 0xFFFF is for L2 SPM.
+ */
+ if (cpu >= 0 && cpu < num_possible_cpus()) {
+ mode_of_data = of_cpu_modes;
+ num_modes = ARRAY_SIZE(of_cpu_modes);
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+ } else {
+ mode_of_data = of_l2_modes;
+ num_modes = ARRAY_SIZE(of_l2_modes);
+ dev = &msm_spm_l2_device;
+ }
+
+ for (i = 0; i < num_modes; i++) {
key = mode_of_data[i].key;
modes[mode_count].cmd =
(uint8_t *)of_get_property(node, key, &len);
@@ -353,16 +376,8 @@
spm_data.modes = modes;
spm_data.num_modes = mode_count;
- /*
- * Device with id 0..NR_CPUS are SPM for apps cores
- * Device with id 0xFFFF is for L2 SPM.
- */
- if (cpu >= 0 && cpu < num_possible_cpus())
- dev = &per_cpu(msm_cpu_spm_device, cpu);
- else
- dev = &msm_spm_l2_device;
-
ret = msm_spm_dev_init(dev, &spm_data);
+
if (ret < 0)
pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3de3af9..615c7ad 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1354,7 +1354,7 @@
* get an interrupt */
cmds[0] = cp_type3_packet(CP_NOP, 1);
cmds[1] = 0;
- adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+ adreno_ringbuffer_issuecmds_intr(device, context,
&cmds[0], 2);
}
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index feaa36f..df5f0f9 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -27,8 +27,8 @@
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
-#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
-#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
+#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000002
+#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD 0x00000004
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 600e04f..e258072 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2409,30 +2409,29 @@
static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
{
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_device *device = &adreno_dev->dev;
if (irq == A3XX_INT_CP_RB_INT) {
unsigned int context_id;
- kgsl_sharedmem_readl(&adreno_dev->dev.memstore,
- &context_id,
+ kgsl_sharedmem_readl(&device->memstore, &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
if (context_id < KGSL_MEMSTORE_MAX) {
- kgsl_sharedmem_writel(&rb->device->memstore,
+ kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), 0);
wmb();
}
- KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
+ KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n");
}
- wake_up_interruptible_all(&rb->device->wait_queue);
+ wake_up_interruptible_all(&device->wait_queue);
/* Schedule work to free mem and issue ibs */
- queue_work(rb->device->work_queue, &rb->device->ts_expired_ws);
+ queue_work(device->work_queue, &device->ts_expired_ws);
- atomic_notifier_call_chain(&rb->device->ts_notifier_list,
- rb->device->id, NULL);
+ atomic_notifier_call_chain(&device->ts_notifier_list,
+ device->id, NULL);
}
#define A3XX_IRQ_CALLBACK(_c) { .func = _c }
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 49d035f..76122ae 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -147,6 +147,7 @@
{
struct adreno_context *drawctxt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
int ret;
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
@@ -157,6 +158,7 @@
drawctxt->pagetable = pagetable;
drawctxt->bin_base_offset = 0;
drawctxt->id = context->id;
+ rb->timestamp[context->id] = 0;
if (flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
@@ -174,6 +176,12 @@
kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
context->devctxt = drawctxt;
return 0;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 3d46221..8bc933a 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -453,7 +453,7 @@
* error checking if needed
*/
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
- total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
+ total_sizedwords += context ? 7 : 0;
total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
if (adreno_is_a3xx(adreno_dev))
@@ -498,9 +498,10 @@
/* always increment the global timestamp. once. */
rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
- if (context) {
+
+ if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
if (context_id == KGSL_MEMSTORE_GLOBAL)
- rb->timestamp[context_id] =
+ rb->timestamp[context->id] =
rb->timestamp[KGSL_MEMSTORE_GLOBAL];
else
rb->timestamp[context_id]++;
@@ -530,7 +531,7 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
+ KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
/* end-of-pipeline timestamp */
@@ -538,14 +539,14 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
+ KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)));
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu,
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
} else {
@@ -553,13 +554,11 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
}
- if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
+ if (context) {
/* Conditional execution based on memory values */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
@@ -592,6 +591,30 @@
}
void
+adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+ struct kgsl_context *k_ctxt,
+ unsigned int *cmds,
+ int sizedwords)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct adreno_context *a_ctxt = NULL;
+
+ if (!k_ctxt)
+ return;
+
+ a_ctxt = k_ctxt->devctxt;
+
+ if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
+ a_ctxt == NULL ||
+ device->state & KGSL_STATE_HUNG)
+ return;
+
+ adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
+ cmds, sizedwords);
+}
+
+void
adreno_ringbuffer_issuecmds(struct kgsl_device *device,
unsigned int flags,
unsigned int *cmds,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index ae2e4c7..6ad85ad 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -108,6 +108,11 @@
unsigned int *cmdaddr,
int sizedwords);
+void adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+ struct kgsl_context *k_ctxt,
+ unsigned int *cmdaddr,
+ int sizedwords);
+
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
void kgsl_cp_intrcallback(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e789733..81de64f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2523,7 +2523,7 @@
}
status = kgsl_allocate_contiguous(&device->memstore,
- sizeof(struct kgsl_devmemstore));
+ KGSL_MEMSTORE_SIZE);
if (status != 0) {
KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 67da5ea..9ed6cca 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_MSM_CAMERA) += io/
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
- EXTRA_CFLAGS += -Idrivers/media/video/msm/io
EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 7c4021d..54c59f8 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -17,15 +17,16 @@
#include <linux/pwm.h>
#include <linux/pmic8058-pwm.h>
#include <linux/hrtimer.h>
-#include <linux/i2c.h>
#include <linux/export.h>
#include <mach/pmic.h>
#include <mach/camera.h>
#include <mach/gpio.h>
+#include "msm_camera_i2c.h"
struct i2c_client *sx150x_client;
struct timer_list timer_flash;
static struct msm_camera_sensor_info *sensor_data;
+static struct msm_camera_i2c_client i2c_client;
enum msm_cam_flash_stat{
MSM_CAM_FLASH_OFF,
MSM_CAM_FLASH_ON,
@@ -33,47 +34,6 @@
static struct i2c_client *sc628a_client;
-static int32_t flash_i2c_txdata(struct i2c_client *client,
- unsigned char *txdata, int length)
-{
- struct i2c_msg msg[] = {
- {
- .addr = client->addr >> 1,
- .flags = 0,
- .len = length,
- .buf = txdata,
- },
- };
- if (i2c_transfer(client->adapter, msg, 1) < 0) {
- CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
- return -EIO;
- }
-
- return 0;
-}
-
-static int32_t flash_i2c_write_b(struct i2c_client *client,
- uint8_t baddr, uint8_t bdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[2];
- if (!client)
- return -ENOTSUPP;
-
- memset(buf, 0, sizeof(buf));
- buf[0] = baddr;
- buf[1] = bdata;
-
- rc = flash_i2c_txdata(client, buf, 2);
- if (rc < 0) {
- CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- baddr, bdata);
- }
- usleep_range(4000, 5000);
-
- return rc;
-}
-
static const struct i2c_device_id sc628a_i2c_id[] = {
{"sc628a", 0},
{ }
@@ -128,8 +88,10 @@
}
tps61310_client = client;
-
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
tps61310_client = NULL;
goto probe_failure;
@@ -431,10 +393,18 @@
break;
case MSM_CAMERA_LED_OFF:
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
gpio_set_value_cansleep(external->led_en, 0);
gpio_set_value_cansleep(external->led_flash_en, 0);
break;
@@ -443,20 +413,36 @@
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
usleep_range(2000, 3000);
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x06,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x86,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
break;
case MSM_CAMERA_LED_HIGH:
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
usleep_range(2000, 3000);
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x49,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x8B,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
break;
default:
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index 64df7fb..611eecd 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -1,9 +1,9 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o
EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o msm_camera_i2c.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c_mux.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 65bcb08..b6a2ffb 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -78,6 +78,11 @@
pr_info(x); \
} while (0)
+#define SMUX_PWR(x...) do { \
+ if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
+ pr_info(x); \
+} while (0)
+
#define SMUX_LOG_PKT_RX(pkt) do { \
if (smux_debug_mask & MSM_SMUX_PKT) \
smux_log_pkt(pkt, 1); \
@@ -1005,7 +1010,6 @@
pkt->hdr.cmd = SMUX_CMD_BYTE;
pkt->hdr.flags = ch;
pkt->hdr.lcid = SMUX_BROADCAST_LCID;
- pkt->hdr.flags = ch;
list_add_tail(&pkt->list, &smux.power_queue);
queue_work(smux_tx_wq, &smux_tx_work);
@@ -1601,7 +1605,7 @@
/* local sleep request ack */
if (smux.power_state == SMUX_PWR_TURNING_OFF) {
/* Power-down complete, turn off UART */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1625,7 +1629,7 @@
|| smux.power_state == SMUX_PWR_TURNING_OFF) {
ack_pkt = smux_alloc_pkt();
if (ack_pkt) {
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
@@ -1658,24 +1662,44 @@
*/
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
{
- int ret;
+ int ret = -ENXIO;
SMUX_LOG_PKT_RX(pkt);
switch (pkt->hdr.cmd) {
case SMUX_CMD_OPEN_LCH:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_open_cmd(pkt);
break;
case SMUX_CMD_DATA:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_data_cmd(pkt);
break;
case SMUX_CMD_CLOSE_LCH:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_close_cmd(pkt);
break;
case SMUX_CMD_STATUS:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_status_cmd(pkt);
break;
@@ -1705,7 +1729,6 @@
static int smux_deserialize(unsigned char *data, int len)
{
struct smux_pkt_t recv;
- uint8_t lcid;
smux_init_pkt(&recv);
@@ -1720,12 +1743,6 @@
return -EINVAL;
}
- lcid = recv.hdr.lcid;
- if (smux_assert_lch_id(lcid)) {
- pr_err("%s: invalid channel id %d\n", __func__, lcid);
- return -ENXIO;
- }
-
if (recv.hdr.payload_len)
recv.payload = data + sizeof(struct smux_hdr_t);
@@ -1743,7 +1760,7 @@
if (smux.power_state == SMUX_PWR_OFF
|| smux.power_state == SMUX_PWR_TURNING_ON) {
/* wakeup system */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1767,7 +1784,7 @@
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_TURNING_ON) {
/* received response to wakeup request */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_tx_work);
@@ -2201,7 +2218,7 @@
/* start power-down sequence */
pkt = smux_alloc_pkt();
if (pkt) {
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF);
smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2228,9 +2245,9 @@
if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
/* ready to power-down the UART */
- smux.power_state = SMUX_PWR_OFF;
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF);
+ smux.power_state = SMUX_PWR_OFF;
/* if data is pending, schedule a new wakeup */
if (!list_empty(&smux.lch_tx_ready_list) ||
@@ -2455,7 +2472,7 @@
!list_empty(&smux.power_queue)) {
/* data to transmit, do wakeup */
smux.pwr_wakeup_delay_us = 1;
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_ON);
smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2492,7 +2509,7 @@
if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
(pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -3115,7 +3132,7 @@
/* Power-down UART */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state != SMUX_PWR_OFF) {
- SMUX_DBG("%s: SSR - turning off UART\n", __func__);
+ SMUX_PWR("%s: SSR - turning off UART\n", __func__);
smux.power_state = SMUX_PWR_OFF;
power_off_uart = 1;
}
@@ -3173,7 +3190,7 @@
/* power-down the UART if we are idle */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF) {
- SMUX_DBG("%s: powering off uart\n", __func__);
+ SMUX_PWR("%s: powering off uart\n", __func__);
smux.power_state = SMUX_PWR_OFF_FLUSH;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
queue_work(smux_tx_wq, &smux_inactivity_work);
diff --git a/drivers/tty/smux_loopback.c b/drivers/tty/smux_loopback.c
index bf6d50b..c4374bb 100644
--- a/drivers/tty/smux_loopback.c
+++ b/drivers/tty/smux_loopback.c
@@ -174,13 +174,15 @@
}
lcid = pkt->hdr.lcid;
- if (smux_assert_lch_id(lcid)) {
- pr_err("%s: invalid channel id %d\n", __func__, lcid);
- return;
- }
switch (pkt->hdr.cmd) {
case SMUX_CMD_OPEN_LCH:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
break;
@@ -207,6 +209,12 @@
break;
case SMUX_CMD_CLOSE_LCH:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
break;
@@ -232,6 +240,12 @@
break;
case SMUX_CMD_DATA:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
/* Echo back received data */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
@@ -245,6 +259,12 @@
break;
case SMUX_CMD_STATUS:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
/* Echo back received status */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
@@ -260,7 +280,7 @@
case SMUX_CMD_PWR_CTL:
/* reply with ack */
smux_init_pkt(&reply_pkt);
- reply_pkt.hdr.lcid = lcid;
+ reply_pkt.hdr.lcid = SMUX_BROADCAST_LCID;
reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_ACK;
reply_pkt.hdr.payload_len = 0;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..742beef 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -3,7 +3,6 @@
depends on (USB && USB_GADGET)
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
- select USB_GADGET_SUPERSPEED
select USB_XHCI_PLATFORM
help
Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 81ce143..5a79cae 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -82,6 +82,12 @@
#define DBM_MAX_EPS 4
+/* DBM TRB configurations */
+#define DBM_TRB_BIT 0x80000000
+#define DBM_TRB_DATA_SRC 0x40000000
+#define DBM_TRB_DMA 0x20000000
+#define DBM_TRB_EP_NUM(ep) (ep<<24)
+
struct dwc3_msm_req_complete {
struct list_head list_item;
struct usb_request *req;
@@ -507,19 +513,12 @@
*/
static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb_hw *trb_link_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
+ struct dwc3_trb *trb_link;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret = 0;
- if ((req->request.udc_priv & MSM_IS_FINITE_TRANSFER) &&
- (req->request.length > 0)) {
- /* Map the request to a DMA. */
- dwc3_map_buffer_to_dma(req);
- }
-
/* We push the request to the dep->req_queued list to indicate that
* this request is issued with start transfer. The request will be out
* from this list in 2 cases. The first is that the transfer will be
@@ -531,31 +530,26 @@
list_add_tail(&req->list, &dep->req_queued);
/* First, prepare a normal TRB, point to the fake buffer */
- trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
dep->free_slot++;
- memset(&trb, 0, sizeof(trb));
+ memset(trb, 0, sizeof(*trb));
- req->trb = trb_hw;
-
- trb.bplh = req->request.dma;
- trb.lst = 0;
- trb.trbctl = DWC3_TRBCTL_NORMAL;
- trb.length = req->request.length;
- trb.hwo = true;
-
- dwc3_trb_to_hw(&trb, trb_hw);
- req->trb_dma = dep->trb_pool_dma;
+ req->trb = trb;
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+ trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+ DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+ trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
+ trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
/* Second, prepare a Link TRB that points to the first TRB*/
- trb_link_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
dep->free_slot++;
- memset(&trb, 0, sizeof(trb));
- trb.bplh = dep->trb_pool_dma;
- trb.trbctl = DWC3_TRBCTL_LINK_TRB;
- trb.hwo = true;
-
- dwc3_trb_to_hw(&trb, trb_link_hw);
+ trb_link->bpl = lower_32_bits(req->trb_dma);
+ trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+ DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+ trb_link->size = 0;
+ trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
/*
* Now start the transfer
@@ -570,7 +564,6 @@
"%s: failed to send STARTTRANSFER command\n",
__func__);
- dwc3_unmap_buffer_from_dma(req);
list_del(&req->list);
return ret;
}
@@ -1115,7 +1108,7 @@
goto disable_hs_ldo;
}
- dwc3 = platform_device_alloc("dwc3-msm", -1);
+ dwc3 = platform_device_alloc("dwc3", -1);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
ret = -ENODEV;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe9..a988c43 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -313,7 +313,7 @@
} while (1);
}
-static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..662682e 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,8 @@
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+ struct dwc3_trb *trb);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 14b07e5..95f11c1 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -506,6 +506,32 @@
dynamically linked module called "ci13xxx_msm_hsic" and force all
gadget drivers to also be dynamically linked.
+config USB_DWC3_MSM
+ tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+ depends on ARCH_MSM
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SELECTED
+ help
+ The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ integrated into the Qualcomm MSM chipset series, supporting host,
+ device and otg modes of operation. For more information please
+ refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+ tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+ depends on ARCH_OMAP
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ select USB_GADGET_SELECTED
+ help
+ DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ which can be configured for peripheral-only, host-only, hub-only
+ and Dual-Role operation. This Controller was first integrated into
+ the OMAP5 series of processors. More information about the OMAP5
+ version of this controller, refer to http://www.ti.com/omap5.
+
#
# LAST -- dummy/emulated controller
#
@@ -556,8 +582,15 @@
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
- bool
+ bool "Operate as superspeed"
+ depends on USB_GADGET
depends on USB_GADGET_DUALSPEED
+ default n
+ help
+ When a superspeed peripheral controller is selected
+ (for example DesignWare USB3.0 controller), use this flag to
+ indicate if the device should operate in superspeed(=y)
+ or not.
#
# USB Gadget Drivers
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fb86874..8cdc2e9 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1720,6 +1720,7 @@
if (!mReq->req.no_interrupt)
mReq->ptr->token |= MSM_ETD_IOC;
}
+ mReq->req.dma = 0;
}
mReq->ptr->page[0] = mReq->req.dma;
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 37b4e53..8b762a2 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -428,7 +428,7 @@
dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
dev->ifc = NULL;
diag_bridge_debugfs_cleanup();
kref_put(&dev->kref, diag_bridge_delete);
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 044af3a..e685233 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -703,7 +703,7 @@
free_inturb:
usb_free_urb(dev->inturb);
pdev_del:
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
nomem:
kfree(dev);
@@ -716,7 +716,7 @@
dev_dbg(&dev->intf->dev, "%s:\n", __func__);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
kfree(dev->in_ctlreq);
kfree(dev->readbuf);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 26be973..db2f40a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -918,12 +918,12 @@
return -EINVAL;
}
- udev = interface_to_usbdev(iface);
- usb_get_dev(udev);
-
if (!test_bit(iface_num, &id->driver_info))
return -ENODEV;
+ udev = interface_to_usbdev(iface);
+ usb_get_dev(udev);
+
numends = iface->cur_altsetting->desc.bNumEndpoints;
for (i = 0; i < numends; i++) {
endpoint = iface->cur_altsetting->endpoint + i;
@@ -965,7 +965,7 @@
return 0;
free_data_bridge:
- platform_device_del(__dev[ch_id]->pdev);
+ platform_device_unregister(__dev[ch_id]->pdev);
usb_set_intfdata(iface, NULL);
kfree(__dev[ch_id]);
__dev[ch_id] = NULL;
@@ -989,7 +989,7 @@
ch_id--;
ctrl_bridge_disconnect(ch_id);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
usb_set_intfdata(intf, NULL);
__dev[ch_id] = NULL;
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index de8d490..9811a82 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -53,6 +53,7 @@
u8 *out_buffer[N_OUT_URB];
unsigned long out_busy; /* Bit vector of URBs in use */
int opened;
+ struct usb_anchor submitted;
struct usb_anchor delayed;
/* Settings for the port */
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 519af39..0c58554 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -252,10 +252,12 @@
} else {
intfdata->in_flight++;
spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+ usb_anchor_urb(this_urb, &portdata->submitted);
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
dbg("usb_submit_urb %p (write bulk) failed "
"(%d)", this_urb, err);
+ usb_unanchor_urb(this_urb);
clear_bit(i, &portdata->out_busy);
spin_lock_irqsave(&intfdata->susp_lock, flags);
intfdata->in_flight--;
@@ -281,6 +283,7 @@
{
int err;
int endpoint;
+ struct usb_wwan_port_private *portdata;
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -290,6 +293,7 @@
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
+ portdata = usb_get_serial_port_data(port);
if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
@@ -308,8 +312,10 @@
/* Resubmit urb so we continue receiving */
if (status != -ESHUTDOWN) {
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
+ usb_unanchor_urb(urb);
if (err != -EPERM) {
printk(KERN_ERR "%s: resubmit read urb failed. "
"(%d)", __func__, err);
@@ -418,8 +424,10 @@
urb = portdata->in_urbs[i];
if (!urb)
continue;
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
+ usb_unanchor_urb(urb);
dbg("%s: submit urb %d failed (%d) %d",
__func__, i, err, urb->transfer_buffer_length);
}
@@ -551,6 +559,7 @@
return 1;
}
init_usb_anchor(&portdata->delayed);
+ init_usb_anchor(&portdata->submitted);
for (j = 0; j < N_IN_URB; j++) {
buffer = kmalloc(IN_BUFLEN, GFP_KERNEL);
@@ -590,7 +599,7 @@
static void stop_read_write_urbs(struct usb_serial *serial)
{
- int i, j;
+ int i;
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
@@ -598,10 +607,7 @@
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
- for (j = 0; j < N_IN_URB; j++)
- usb_kill_urb(portdata->in_urbs[j]);
- for (j = 0; j < N_OUT_URB; j++)
- usb_kill_urb(portdata->out_urbs[j]);
+ usb_kill_anchored_urbs(&portdata->submitted);
}
}
@@ -694,10 +700,12 @@
portdata = usb_get_serial_port_data(port);
data = port->serial->private;
while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (!err) {
data->in_flight++;
} else {
+ usb_unanchor_urb(urb);
/* we have to throw away the rest */
do {
unbusy_queued_urb(urb, portdata);
@@ -736,33 +744,32 @@
spin_lock_irq(&intfdata->susp_lock);
intfdata->suspended = 0;
- spin_unlock_irq(&intfdata->susp_lock);
-
for (i = 0; i < serial->num_ports; i++) {
/* walk all ports */
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
/* skip closed ports */
- spin_lock_irq(&intfdata->susp_lock);
- if (!portdata->opened) {
- spin_unlock_irq(&intfdata->susp_lock);
+ if (!portdata->opened)
continue;
- }
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
err("%s: Error %d for bulk URB %d",
__func__, err, i);
+ usb_unanchor_urb(urb);
+ intfdata->suspended = 1;
spin_unlock_irq(&intfdata->susp_lock);
goto err_out;
}
}
play_delayed(port);
- spin_unlock_irq(&intfdata->susp_lock);
}
+ spin_unlock_irq(&intfdata->susp_lock);
+
err_out:
return err;
}
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index edbc952..e605aed 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -19,6 +19,8 @@
static struct dsi_buf nt35510_tx_buf;
static struct dsi_buf nt35510_rx_buf;
+static int mipi_nt35510_bl_ctrl;
+
#define NT35510_SLEEP_OFF_DELAY 150
#define NT35510_DISPLAY_ON_DELAY 150
@@ -528,8 +530,63 @@
return 0;
}
+static ssize_t mipi_nt35510_wta_bl_ctrl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err;
+
+ err = kstrtoint(buf, 0, &mipi_nt35510_bl_ctrl);
+ if (err)
+ return ret;
+
+ pr_info("%s: bl ctrl set to %d\n", __func__, mipi_nt35510_bl_ctrl);
+
+ return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_nt35510_wta_bl_ctrl);
+
+static struct attribute *mipi_nt35510_fs_attrs[] = {
+ &dev_attr_bl_ctrl.attr,
+ NULL,
+};
+
+static struct attribute_group mipi_nt35510_fs_attr_group = {
+ .attrs = mipi_nt35510_fs_attrs,
+};
+
+static int mipi_nt35510_create_sysfs(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (!mfd) {
+ pr_err("%s: mfd not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi) {
+ pr_err("%s: mfd->fbi not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi->dev) {
+ pr_err("%s: mfd->fbi->dev not found\n", __func__);
+ return -ENODEV;
+ }
+ rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+ &mipi_nt35510_fs_attr_group);
+ if (rc) {
+ pr_err("%s: sysfs group creation failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
{
+ struct platform_device *pthisdev = NULL;
pr_debug("%s\n", __func__);
if (pdev->id == 0) {
@@ -539,7 +596,8 @@
return 0;
}
- msm_fb_add_device(pdev);
+ pthisdev = msm_fb_add_device(pdev);
+ mipi_nt35510_create_sysfs(pthisdev);
return 0;
}
@@ -551,6 +609,8 @@
},
};
+static int old_bl_level;
+
static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
@@ -558,11 +618,33 @@
bl_level = mfd->bl_level;
if (mipi_nt35510_pdata->bl_lock) {
- spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags);
- mipi_nt35510_pdata->pmic_backlight(bl_level);
- spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags);
- } else
- mipi_nt35510_pdata->pmic_backlight(bl_level);
+ if (!mipi_nt35510_bl_ctrl) {
+ /* Level received is of range 1 to bl_max,
+ We need to convert the levels to 1
+ to 31 */
+ bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+ /(2 * mfd->panel_info.bl_max);
+ if (bl_level == old_bl_level)
+ return;
+
+ if (bl_level == 0)
+ mipi_nt35510_pdata->backlight(0, 1);
+
+ if (old_bl_level == 0)
+ mipi_nt35510_pdata->backlight(50, 1);
+
+ spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock,
+ flags);
+ mipi_nt35510_pdata->backlight(bl_level, 0);
+ spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock,
+ flags);
+ old_bl_level = bl_level;
+ } else {
+ mipi_nt35510_pdata->backlight(bl_level, 1);
+ }
+ } else {
+ mipi_nt35510_pdata->backlight(bl_level, mipi_nt35510_bl_ctrl);
+ }
}
static struct msm_fb_panel_data nt35510_panel_data = {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index f052e93..1524ce6 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 4e97d99..8a364ba 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
delayed from VSYNC active edge */
pinfo.lcdc.hsync_skew = 0;
pinfo.clk_rate = 499000000;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 7f5ac70..2ebfad4 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -93,7 +93,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 100;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index e826773..144d9ff 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -105,7 +105,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 100;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 4107161..dd446b9 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,7 +21,7 @@
int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
#define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
#define MIPI_TOSHIBA_PWM_LEVEL 255
#define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index e465d46..98b24b1 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -19,6 +19,8 @@
static struct dsi_buf truly_tx_buf;
static struct dsi_buf truly_rx_buf;
+static int mipi_truly_bl_ctrl;
+
#define TRULY_CMD_DELAY 0
#define MIPI_SETTING_DELAY 10
#define TRULY_SLEEP_OFF_DELAY 150
@@ -720,8 +722,64 @@
return 0;
}
+static ssize_t mipi_truly_wta_bl_ctrl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err;
+
+ err = kstrtoint(buf, 0, &mipi_truly_bl_ctrl);
+ if (err)
+ return ret;
+
+ pr_info("%s: bl ctrl set to %d\n", __func__, mipi_truly_bl_ctrl);
+
+ return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_truly_wta_bl_ctrl);
+
+static struct attribute *mipi_truly_fs_attrs[] = {
+ &dev_attr_bl_ctrl.attr,
+ NULL,
+};
+
+static struct attribute_group mipi_truly_fs_attr_group = {
+ .attrs = mipi_truly_fs_attrs,
+};
+
+static int mipi_truly_create_sysfs(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (!mfd) {
+ pr_err("%s: mfd not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi) {
+ pr_err("%s: mfd->fbi not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi->dev) {
+ pr_err("%s: mfd->fbi->dev not found\n", __func__);
+ return -ENODEV;
+ }
+ rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+ &mipi_truly_fs_attr_group);
+ if (rc) {
+ pr_err("%s: sysfs group creation failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+
static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
{
+ struct platform_device *pthisdev = NULL;
int rc = 0;
if (pdev->id == 0) {
@@ -731,7 +789,8 @@
return rc;
}
- msm_fb_add_device(pdev);
+ pthisdev = msm_fb_add_device(pdev);
+ mipi_truly_create_sysfs(pthisdev);
return rc;
}
@@ -743,6 +802,8 @@
},
};
+static int old_bl_level;
+
static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
@@ -750,11 +811,33 @@
bl_level = mfd->bl_level;
if (mipi_truly_pdata->bl_lock) {
- spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags);
- mipi_truly_pdata->pmic_backlight(bl_level);
- spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags);
- } else
- mipi_truly_pdata->pmic_backlight(bl_level);
+ if (!mipi_truly_bl_ctrl) {
+ /* Level received is of range 1 to bl_max,
+ We need to convert the levels to 1
+ to 31 */
+ bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+ /(2 * mfd->panel_info.bl_max);
+ if (bl_level == old_bl_level)
+ return;
+
+ if (bl_level == 0)
+ mipi_truly_pdata->backlight(0, 1);
+
+ if (old_bl_level == 0)
+ mipi_truly_pdata->backlight(50, 1);
+
+ spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock,
+ flags);
+ mipi_truly_pdata->backlight(bl_level, 0);
+ spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock,
+ flags);
+ old_bl_level = bl_level;
+ } else {
+ mipi_truly_pdata->backlight(bl_level, 1);
+ }
+ } else {
+ mipi_truly_pdata->backlight(bl_level, mipi_truly_bl_ctrl);
+ }
}
static struct msm_fb_panel_data truly_panel_data = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index de98177..3423241 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -56,7 +56,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
index ea2ff47..3c0c0b7 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -59,7 +59,7 @@
pinfo.lcdc.hsync_skew = 0;
pinfo.clk_rate = 699000000;
pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index b71212c..dcdbf28 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -745,7 +745,8 @@
return VCD_ERR_ILLEGAL_PARM;
}
if (buf_entry->in_use) {
- VCD_MSG_ERROR("\n Buffer is in use and is not flushed");
+ VCD_MSG_ERROR("Buffer is in use and is not flushed: %p, %d\n",
+ buf_entry, buf_entry->in_use);
return VCD_ERR_ILLEGAL_OP;
}
@@ -1043,6 +1044,7 @@
{
u32 rc = VCD_S_SUCCESS;
struct vcd_buffer_entry *buf_entry;
+ struct vcd_buffer_entry *orig_frame = NULL;
VCD_MSG_LOW("vcd_flush_buffers:");
@@ -1066,9 +1068,19 @@
vcd_frame_data),
cctxt,
cctxt->client_data);
+ orig_frame = vcd_find_buffer_pool_entry(
+ &cctxt->in_buf_pool,
+ buf_entry->virtual);
}
- buf_entry->in_use = false;
+ if (orig_frame) {
+ orig_frame->in_use--;
+ if (orig_frame != buf_entry)
+ kfree(buf_entry);
+ } else {
+ buf_entry->in_use = false;
+ VCD_MSG_ERROR("Original frame not found in buffer pool\n");
+ }
VCD_BUFFERPOOL_INUSE_DECREMENT(
cctxt->in_buf_pool.in_use);
buf_entry = NULL;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 271079e..bcd0afb 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -605,6 +605,7 @@
struct ion_allocation_data ion_alloc;
struct ion_fd_data fd_data;
+ int ion_dev_fd;
};
enum msm_st_frame_packing {
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 363635f..90d8723 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -39,8 +39,8 @@
#define MDM9615_SLIM_0_RX_MAX_CHANNELS 2
#define MDM9615_SLIM_0_TX_MAX_CHANNELS 4
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
#define BOTTOM_SPK_AMP_POS 0x1
#define BOTTOM_SPK_AMP_NEG 0x2
@@ -261,9 +261,11 @@
static int mdm9615_slim_0_rx_ch = 1;
static int mdm9615_slim_0_tx_ch = 1;
-static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+static int mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
static int mdm9615_btsco_ch = 1;
+static int mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
static struct clk *codec_clk;
static int clk_users;
@@ -679,6 +681,11 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static const char * const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum mdm9615_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -730,19 +737,49 @@
{
switch (ucontrol->value.integer.value[0]) {
case 0:
- mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
break;
case 1:
- mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_16KHZ;
break;
default:
- mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
break;
}
pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
return 0;
}
+static int mdm9615_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: mdm9615_auxpcm_rate = %d", __func__,
+ mdm9615_auxpcm_rate);
+ ucontrol->value.integer.value[0] = mdm9615_auxpcm_rate;
+ return 0;
+}
+
+static int mdm9615_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ case 1:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_16KHZ;
+ break;
+ default:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: mdm9615_auxpcm_rate = %d\n"
+ "ucontrol->value.integer.value[0] = %d\n", __func__,
+ mdm9615_auxpcm_rate,
+ (int)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
mdm9615_set_spk),
@@ -752,6 +789,8 @@
mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", mdm9615_auxpcm_enum[0],
+ mdm9615_auxpcm_rate_get, mdm9615_auxpcm_rate_put),
};
static void *def_tabla_mbhc_cal(void)
@@ -1554,8 +1593,8 @@
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
+ rate->min = rate->max = mdm9615_auxpcm_rate;
+ /* PCM only supports mono output */
channels->min = channels->max = 1;
return 0;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 9395e8f..4ecd8df 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1062,7 +1062,8 @@
.cpu_dai_name = "MultiMedia1",
.platform_name = "msm-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1075,7 +1076,8 @@
.cpu_dai_name = "MultiMedia2",
.platform_name = "msm-multi-ch-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1088,7 +1090,8 @@
.cpu_dai_name = "CS-VOICE",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1102,7 +1105,8 @@
.cpu_dai_name = "VoIP",
.platform_name = "msm-voip-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1115,7 +1119,8 @@
.cpu_dai_name = "MultiMedia3",
.platform_name = "msm-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1129,7 +1134,8 @@
.cpu_dai_name = "SLIMBUS0_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1142,7 +1148,8 @@
.cpu_dai_name = "INT_FM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1178,7 +1185,8 @@
.cpu_dai_name = "MultiMedia4",
.platform_name = "msm-compr-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1191,7 +1199,8 @@
.cpu_dai_name = "VOICE_STUB",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1205,7 +1214,8 @@
.cpu_dai_name = "HDMI_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1219,7 +1229,8 @@
.cpu_dai_name = "MI2S_TX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.codec_dai_name = "snd-soc-dummy-dai",
@@ -1232,7 +1243,8 @@
.cpu_dai_name = "SEC_I2S_RX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e137a66..4e1ce52 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -2316,6 +2316,8 @@
{"BE_OUT", NULL, "PCM_RX"},
{"PCM_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "STUB_RX"},
+ {"STUB_TX", NULL, "BE_IN"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,