Merge "msm: vidc: Add support for thumbnail mode"
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 0b30c26..380fde1 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -127,7 +127,7 @@
struct list_head req_list;
struct work_struct work;
int prio;
- int pending;
+ atomic_t pending;
bool passive;
};
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 5a85eec..3d9639f 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -404,7 +404,7 @@
if (offset < 0)
return -EINVAL;
- if (len < region_size)
+ if (len < OCMEM_MIN_ALLOC)
return -EINVAL;
pr_debug("ocmem: mode_transistion to %x\n", new_mode);
@@ -425,7 +425,7 @@
/* Set the region to its new mode */
region->mode = new_mode;
atomic_inc(®ion->mode_counter);
- pr_debug("Region (%d) switching to mode %d\n",
+ pr_debug("Region (%d) switching to mode %d\n",
i, new_mode);
continue;
} else if (region->mode != new_mode) {
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4aba69c..818a20a 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -58,6 +58,7 @@
#define BR_CLIENT_n_IDX(x) ((x) * 0x4)
#define BR_CLIENT_n_ctrl(x) (BR_CLIENT_BASE + (BR_CLIENT_n_IDX(x)))
#define BR_STATUS (0x14)
+#define BR_LAST_ADDR (0x18)
/* 16 entries per client are supported */
/* Use entries 0 - 15 for client0 */
#define BR_CLIENT0_MASK (0x1000)
@@ -76,7 +77,7 @@
#define BR_TBL_ENTRY_ENABLE 0x1
#define BR_TBL_START 0x0
#define BR_TBL_END 0x8
-#define BR_RW_SHIFT 0x2
+#define BR_RW_SHIFT 0x1
#define DM_TBL_START 0x10
#define DM_TBL_END 0x18
@@ -134,13 +135,13 @@
pr_debug("irq:dm_status %x irq_status %x\n", status, irq_status);
if (irq_status & BIT(0)) {
pr_debug("Data mover completed\n");
- irq_status &= ~BIT(0);
- ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ ocmem_write(BIT(0), dm_base + DM_INTR_CLR);
+ pr_debug("Last re-mapped address block %x\n",
+ ocmem_read(br_base + BR_LAST_ADDR));
complete(&dm_transfer_event);
} else if (irq_status & BIT(1)) {
pr_debug("Data clear engine completed\n");
- irq_status &= ~BIT(1);
- ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ ocmem_write(BIT(1), dm_base + DM_INTR_CLR);
complete(&dm_clear_event);
} else {
BUG_ON(1);
@@ -259,6 +260,7 @@
pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
wait_for_completion(&dm_transfer_event);
+ pr_debug("Completed transferring %d segments\n", num_chunks);
ocmem_disable_core_clock();
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index c380c54..38813e1 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -45,6 +45,7 @@
OP_COMPLETE = 0x0,
OP_RESCHED,
OP_PARTIAL,
+ OP_EVICT,
OP_FAIL = ~0x0,
};
@@ -74,7 +75,8 @@
* hardware state changes can occur. The value will be tweaked on actual
* hardware.
*/
-#define SCHED_DELAY 10
+/* Delay in ms for switching to low power mode for OCMEM */
+#define SCHED_DELAY 5000
static struct list_head rdm_queue;
static struct mutex rdm_mutex;
@@ -128,6 +130,7 @@
static struct rb_root sched_tree;
static struct mutex sched_mutex;
+static struct mutex allocation_mutex;
/* A region represents a continuous interval in OCMEM address space */
struct ocmem_region {
@@ -307,6 +310,7 @@
INIT_LIST_HEAD(&p->sched_list);
init_rwsem(&p->rw_sem);
SET_STATE(p, R_FREE);
+ pr_debug("request %p created\n", p);
return p;
}
@@ -594,6 +598,16 @@
if (rc < 0)
goto br_clock_fail;
+
+ rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
+ get_mode(req->owner));
+
+ if (rc < 0) {
+ pr_err("ocmem: Failed to secure request %p for %d\n", req,
+ req->owner);
+ goto lock_failed;
+ }
+
rc = do_map(req);
if (rc < 0) {
@@ -602,19 +616,12 @@
goto process_map_fail;
}
-
- if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
- get_mode(req->owner))) {
- pr_err("ocmem: Failed to secure request %p for %d\n", req,
- req->owner);
- rc = -EINVAL;
- goto lock_failed;
- }
-
+ pr_debug("ocmem: Mapped request %p\n", req);
return 0;
-lock_failed:
- do_unmap(req);
+
process_map_fail:
+ ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
+lock_failed:
ocmem_disable_br_clock();
br_clock_fail:
ocmem_disable_iface_clock();
@@ -630,22 +637,24 @@
{
int rc = 0;
- if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
- req->req_sz)) {
- pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
- req->owner);
- rc = -EINVAL;
- goto unlock_failed;
- }
-
rc = do_unmap(req);
if (rc < 0)
goto process_unmap_fail;
+ rc = ocmem_unlock(req->owner, phys_to_offset(req->req_start),
+ req->req_sz);
+
+ if (rc < 0) {
+ pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
+ req->owner);
+ goto unlock_failed;
+ }
+
ocmem_disable_br_clock();
ocmem_disable_iface_clock();
ocmem_disable_core_clock();
+ pr_debug("ocmem: Unmapped request %p\n", req);
return 0;
unlock_failed:
@@ -1009,7 +1018,8 @@
retry = false;
- pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+ pr_debug("ocmem: do_allocate: %s request size %lx\n",
+ get_name(owner), sz);
retry_next_step:
@@ -1036,6 +1046,7 @@
/* update request state */
CLEAR_STATE(req, R_FREE);
+ CLEAR_STATE(req, R_PENDING);
SET_STATE(req, R_ALLOCATED);
SET_STATE(req, R_MUST_MAP);
req->op = SCHED_NOP;
@@ -1065,8 +1076,11 @@
/* 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;
+ req->req_start = zone->z_head;
+ req->req_end = zone->z_head + sz - 1;
+ req->req_sz = 0x0;
+ req->edata = NULL;
+ goto trigger_eviction;
} else {
/* Try to allocate atleast >= 'min' immediately */
sz -= step;
@@ -1109,6 +1123,11 @@
return OP_COMPLETE;
+trigger_eviction:
+ pr_debug("Trigger eviction of region %p\n", overlap_r);
+ destroy_region(region);
+ return OP_EVICT;
+
err_not_supported:
pr_err("ocmem: Scheduled unsupported operation\n");
return OP_FAIL;
@@ -1219,12 +1238,9 @@
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;
- }
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
offset = phys_to_offset(req->req_start);
@@ -1281,8 +1297,23 @@
static int ocmem_schedule_pending(void)
{
- schedule_delayed_work(&ocmem_sched_thread,
- msecs_to_jiffies(SCHED_DELAY));
+
+ bool need_sched = false;
+ int i = 0;
+
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+ if (!list_empty(&sched_queue[i])) {
+ need_sched = true;
+ break;
+ }
+ }
+
+ if (need_sched == true) {
+ cancel_delayed_work(&ocmem_sched_thread);
+ schedule_delayed_work(&ocmem_sched_thread,
+ msecs_to_jiffies(SCHED_DELAY));
+ pr_debug("ocmem: Scheduled delayed work\n");
+ }
return 0;
}
@@ -1298,6 +1329,8 @@
goto err_free_fail;
}
+ pr_debug("ocmem: do_free: client %s req %p\n", get_name(req->owner),
+ req);
/* Grab the sched mutex */
mutex_lock(&sched_mutex);
rc = __sched_free(req);
@@ -1346,10 +1379,15 @@
return -EINVAL;
}
- if (is_tcm(req->owner)) {
+ if (!TEST_STATE(req, R_FREE)) {
+
rc = process_unmap(req, req->req_start, req->req_end);
if (rc < 0)
return -EINVAL;
+
+ rc = do_free(req);
+ if (rc < 0)
+ return -EINVAL;
}
if (req->req_sz != 0) {
@@ -1365,10 +1403,6 @@
}
- rc = do_free(req);
- if (rc < 0)
- return -EINVAL;
-
inc_ocmem_stat(zone_of(req), NR_FREES);
ocmem_destroy_req(req);
@@ -1437,18 +1471,10 @@
return -EINVAL;
if (!is_mapped(req)) {
- pr_err("Buffer is not already mapped\n");
+ pr_err("Buffer is not currently mapped\n");
goto transfer_out_error;
}
- rc = process_unmap(req, req->req_start, req->req_end);
- if (rc < 0) {
- pr_err("Unmapping the buffer failed\n");
- goto transfer_out_error;
- }
-
- inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
-
rc = queue_transfer(req, handle, list, TO_DDR);
if (rc < 0) {
@@ -1457,6 +1483,7 @@
goto transfer_out_error;
}
+ inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
return 0;
transfer_out_error:
@@ -1474,19 +1501,14 @@
if (!req)
return -EINVAL;
- if (is_mapped(req)) {
- pr_err("Buffer is already mapped\n");
+
+ if (!is_mapped(req)) {
+ pr_err("Buffer is not already mapped for transfer\n");
goto transfer_in_error;
}
- rc = process_map(req, req->req_start, req->req_end);
- if (rc < 0) {
- pr_err("Mapping the buffer failed\n");
- goto transfer_in_error;
- }
inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
-
rc = queue_transfer(req, handle, list, TO_OCMEM);
if (rc < 0) {
@@ -1525,13 +1547,21 @@
edata = req->edata;
- if (is_tcm(req->owner))
- do_unmap(req);
+ if (!edata) {
+ pr_err("Unable to find eviction data\n");
+ return -EINVAL;
+ }
+
+ pr_debug("Found edata %p in request %p\n", edata, req);
inc_ocmem_stat(zone_of(req), NR_SHRINKS);
if (size == 0) {
- pr_info("req %p being shrunk to zero\n", req);
+ pr_debug("req %p being shrunk to zero\n", req);
+ if (is_mapped(req))
+ rc = process_unmap(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
rc = do_free(req);
if (rc < 0)
return -EINVAL;
@@ -1541,9 +1571,12 @@
return -EINVAL;
}
- edata->pending--;
- if (edata->pending == 0) {
- pr_debug("All regions evicted");
+ req->edata = NULL;
+ CLEAR_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_FREE);
+
+ if (atomic_dec_and_test(&edata->pending)) {
+ pr_debug("ocmem: All conflicting allocations were shrunk\n");
complete(&edata->completion);
}
@@ -1567,82 +1600,313 @@
return rc;
}
-int ocmem_eviction_thread(struct work_struct *work)
+static struct ocmem_eviction_data *init_eviction(int id)
{
+ struct ocmem_eviction_data *edata = NULL;
+ int prio = ocmem_client_table[id].priority;
+
+ edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+
+ if (!edata) {
+ pr_err("ocmem: Could not allocate eviction data\n");
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&edata->victim_list);
+ INIT_LIST_HEAD(&edata->req_list);
+ edata->prio = prio;
+ atomic_set(&edata->pending, 0);
+ return edata;
+}
+
+static void free_eviction(struct ocmem_eviction_data *edata)
+{
+
+ if (!edata)
+ return;
+
+ if (!list_empty(&edata->req_list))
+ pr_err("ocmem: Eviction data %p not empty\n", edata);
+
+ kfree(edata);
+ edata = NULL;
+}
+
+static bool is_overlapping(struct ocmem_req *new, struct ocmem_req *old)
+{
+
+ if (!new || !old)
+ return false;
+
+ pr_debug("check overlap [%lx -- %lx] on [%lx -- %lx]\n",
+ new->req_start, new->req_end,
+ old->req_start, old->req_end);
+
+ if ((new->req_start < old->req_start &&
+ new->req_end >= old->req_start) ||
+ (new->req_start >= old->req_start &&
+ new->req_start <= old->req_end &&
+ new->req_end >= old->req_end)) {
+ pr_debug("request %p overlaps with existing req %p\n",
+ new, old);
+ return true;
+ }
+ return false;
+}
+
+static int __evict_common(struct ocmem_eviction_data *edata,
+ struct ocmem_req *req)
+{
+ struct rb_node *rb_node = NULL;
+ struct ocmem_req *e_req = NULL;
+ bool needs_eviction = false;
+ int j = 0;
+
+ for (rb_node = rb_first(&sched_tree); rb_node;
+ rb_node = rb_next(rb_node)) {
+
+ struct ocmem_region *tmp_region = NULL;
+
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+ if (tmp_region->max_prio < edata->prio) {
+ for (j = edata->prio - 1; j > NO_PRIO; j--) {
+ needs_eviction = false;
+ e_req = find_req_match(j, tmp_region);
+ if (!e_req)
+ continue;
+ if (edata->passive == true) {
+ needs_eviction = true;
+ } else {
+ needs_eviction = is_overlapping(req,
+ e_req);
+ }
+
+ if (needs_eviction) {
+ pr_debug("adding %p in region %p to eviction list\n",
+ e_req, tmp_region);
+ list_add_tail(
+ &e_req->eviction_list,
+ &edata->req_list);
+ atomic_inc(&edata->pending);
+ e_req->edata = edata;
+ }
+ }
+ } else {
+ pr_debug("Skipped region %p\n", tmp_region);
+ }
+ }
+
+ pr_debug("%d requests will be evicted\n", atomic_read(&edata->pending));
+
+ if (!atomic_read(&edata->pending))
+ return -EINVAL;
return 0;
}
+static void trigger_eviction(struct ocmem_eviction_data *edata)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+ struct ocmem_buf buffer;
+
+ if (!edata)
+ return;
+
+ BUG_ON(atomic_read(&edata->pending) == 0);
+
+ init_completion(&edata->completion);
+
+ list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+ {
+ if (req) {
+ pr_debug("ocmem: Evicting request %p\n", req);
+ buffer.addr = req->req_start;
+ buffer.len = 0x0;
+ dispatch_notification(req->owner, OCMEM_ALLOC_SHRINK,
+ &buffer);
+ }
+ }
+ return;
+}
+
int process_evict(int id)
{
struct ocmem_eviction_data *edata = NULL;
- int prio = ocmem_client_table[id].priority;
- struct rb_node *rb_node = NULL;
- struct ocmem_req *req = NULL;
- struct ocmem_buf buffer;
- int j = 0;
+ int rc = 0;
- edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+ edata = init_eviction(id);
- INIT_LIST_HEAD(&edata->victim_list);
- INIT_LIST_HEAD(&edata->req_list);
- edata->prio = prio;
- edata->pending = 0;
- edata->passive = 1;
- evictions[id] = edata;
+ if (!edata)
+ return -EINVAL;
+
+ edata->passive = true;
mutex_lock(&sched_mutex);
- for (rb_node = rb_first(&sched_tree); rb_node;
- rb_node = rb_next(rb_node)) {
- struct ocmem_region *tmp_region = NULL;
- tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
- if (tmp_region->max_prio < prio) {
- for (j = id - 1; j > NO_PRIO; j--) {
- req = find_req_match(j, tmp_region);
- if (req) {
- pr_info("adding %p to eviction list\n",
- tmp_region);
- list_add_tail(
- &tmp_region->eviction_list,
- &edata->victim_list);
- list_add_tail(
- &req->eviction_list,
- &edata->req_list);
- edata->pending++;
- req->edata = edata;
- buffer.addr = req->req_start;
- buffer.len = 0x0;
- inc_ocmem_stat(zone_of(req),
- NR_EVICTIONS);
- dispatch_notification(req->owner,
- OCMEM_ALLOC_SHRINK, &buffer);
- }
- }
- } else {
- pr_info("skipping %p from eviction\n", tmp_region);
+ rc = __evict_common(edata, NULL);
+
+ if (rc < 0)
+ goto skip_eviction;
+
+ trigger_eviction(edata);
+
+ evictions[id] = edata;
+
+ mutex_unlock(&sched_mutex);
+
+ wait_for_completion(&edata->completion);
+
+ return 0;
+
+skip_eviction:
+ evictions[id] = NULL;
+ mutex_unlock(&sched_mutex);
+ return 0;
+}
+
+static int run_evict(struct ocmem_req *req)
+{
+ struct ocmem_eviction_data *edata = NULL;
+ int rc = 0;
+
+ if (!req)
+ return -EINVAL;
+
+ edata = init_eviction(req->owner);
+
+ if (!edata)
+ return -EINVAL;
+
+ edata->passive = false;
+
+ rc = __evict_common(edata, req);
+
+ if (rc < 0)
+ goto skip_eviction;
+
+ trigger_eviction(edata);
+
+ pr_debug("ocmem: attaching eviction %p to request %p", edata, req);
+ req->edata = edata;
+
+ wait_for_completion(&edata->completion);
+
+ pr_debug("ocmem: eviction completed successfully\n");
+ return 0;
+
+skip_eviction:
+ pr_err("ocmem: Unable to run eviction\n");
+ free_eviction(edata);
+ return -EINVAL;
+}
+
+static int __restore_common(struct ocmem_eviction_data *edata)
+{
+
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+
+ if (!edata)
+ return -EINVAL;
+
+ list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+ {
+ if (req) {
+ pr_debug("ocmem: restoring evicted request %p\n",
+ req);
+ list_del(&req->eviction_list);
+ req->op = SCHED_ALLOCATE;
+ sched_enqueue(req);
+ inc_ocmem_stat(zone_of(req), NR_RESTORES);
}
}
- mutex_unlock(&sched_mutex);
- pr_debug("Waiting for all regions to be shrunk\n");
- if (edata->pending > 0) {
- init_completion(&edata->completion);
- wait_for_completion(&edata->completion);
+
+ pr_debug("Scheduled all evicted regions\n");
+
+ return 0;
+}
+
+static int sched_restore(struct ocmem_req *req)
+{
+
+ int rc = 0;
+
+ if (!req)
+ return -EINVAL;
+
+ if (!req->edata)
+ return 0;
+
+ rc = __restore_common(req->edata);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ free_eviction(req->edata);
+ return 0;
+}
+
+int process_restore(int id)
+{
+ struct ocmem_eviction_data *edata = evictions[id];
+ int rc = 0;
+
+ if (!edata)
+ return -EINVAL;
+
+ rc = __restore_common(edata);
+
+ if (rc < 0) {
+ pr_err("Failed to restore evicted requests\n");
+ return -EINVAL;
}
+
+ free_eviction(edata);
+ evictions[id] = NULL;
+ ocmem_schedule_pending();
return 0;
}
static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
{
int rc = 0;
+ int ret = 0;
struct ocmem_buf *buffer = req->buffer;
down_write(&req->rw_sem);
+ mutex_lock(&allocation_mutex);
+retry_allocate:
+
/* Take the scheduler mutex */
mutex_lock(&sched_mutex);
rc = __sched_allocate(req, can_block, can_wait);
mutex_unlock(&sched_mutex);
+ if (rc == OP_EVICT) {
+
+ ret = run_evict(req);
+
+ if (ret == 0) {
+ rc = sched_restore(req);
+ if (rc < 0) {
+ pr_err("Failed to restore for req %p\n", req);
+ goto err_allocate_fail;
+ }
+ req->edata = NULL;
+
+ pr_debug("Attempting to re-allocate req %p\n", req);
+ req->req_start = 0x0;
+ req->req_end = 0x0;
+ goto retry_allocate;
+ } else {
+ goto err_allocate_fail;
+ }
+ }
+
+ mutex_unlock(&allocation_mutex);
+
if (rc == OP_FAIL) {
inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
goto err_allocate_fail;
@@ -1667,6 +1931,7 @@
up_write(&req->rw_sem);
return 0;
err_allocate_fail:
+ mutex_unlock(&allocation_mutex);
up_write(&req->rw_sem);
return -EINVAL;
}
@@ -1699,33 +1964,6 @@
return -EINVAL;
}
-int process_restore(int id)
-{
- struct ocmem_req *req = NULL;
- struct ocmem_req *next = NULL;
- struct ocmem_eviction_data *edata = evictions[id];
-
- if (!edata)
- return 0;
-
- list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
- {
- if (req) {
- pr_debug("ocmem: Fetched evicted request %p\n",
- req);
- list_del(&req->sched_list);
- req->op = SCHED_ALLOCATE;
- sched_enqueue(req);
- inc_ocmem_stat(zone_of(req), NR_RESTORES);
- }
- }
- kfree(edata);
- evictions[id] = NULL;
- pr_debug("Restore all evicted regions\n");
- ocmem_schedule_pending();
- return 0;
-}
-
int process_allocate(int id, struct ocmem_handle *handle,
unsigned long min, unsigned long max,
unsigned long step, bool can_block, bool can_wait)
@@ -1774,13 +2012,11 @@
handle->req = req;
- if (is_tcm(id)) {
+ if (req->req_sz != 0) {
+
rc = process_map(req, req->req_start, req->req_end);
if (rc < 0)
goto map_error;
- }
-
- if (req->req_sz != 0) {
offset = phys_to_offset(req->req_start);
@@ -1795,6 +2031,7 @@
return 0;
power_ctl_error:
+ process_unmap(req, req->req_start, req->req_end);
map_error:
handle->req = NULL;
do_free(req);
@@ -1819,15 +2056,18 @@
if (rc < 0)
goto do_allocate_error;
+ /* The request can still be pending */
+ if (TEST_STATE(req, R_PENDING))
+ return 0;
+
inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
- if (is_tcm(id)) {
+ if (req->req_sz != 0) {
+
rc = process_map(req, req->req_start, req->req_end);
if (rc < 0)
goto map_error;
- }
- if (req->req_sz != 0) {
offset = phys_to_offset(req->req_start);
@@ -1849,6 +2089,7 @@
return 0;
power_ctl_error:
+ process_unmap(req, req->req_start, req->req_end);
map_error:
handle->req = NULL;
do_free(req);
@@ -1965,6 +2206,7 @@
sched_tree = RB_ROOT;
pdata = platform_get_drvdata(pdev);
+ mutex_init(&allocation_mutex);
mutex_init(&sched_mutex);
mutex_init(&sched_queue_mutex);
ocmem_vaddr = pdata->vbase;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3ca2163..62085f6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -272,6 +272,7 @@
/* 9625 IDs */
[134] = MSM_CPU_9625,
+ [152] = MSM_CPU_9625,
/* 8960AB IDs */
[138] = MSM_CPU_8960AB,
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 77922e2..48ce577 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -426,6 +426,10 @@
stats.aec.buff = stats.buffer;
stats.aec.fd = stats.fd;
break;
+ case MSG_ID_STATS_BE:
+ stats.be.buff = stats.buffer;
+ stats.be.fd = stats.fd;
+ break;
case MSG_ID_STATS_AF:
case MSG_ID_STATS_BF:
stats.af.buff = stats.buffer;
@@ -514,6 +518,7 @@
CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
switch (cfgcmd.cmd_type) {
case CMD_STATS_BG_ENABLE:
+ case CMD_STATS_BE_ENABLE:
case CMD_STATS_BF_ENABLE:
case CMD_STATS_BHIST_ENABLE:
case CMD_STATS_AF_ENABLE:
@@ -611,6 +616,8 @@
cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
else if (buf.type == STAT_BG)
cfgcmd.cmd_type = CMD_STATS_BG_BUF_RELEASE;
+ else if (buf.type == STAT_BE)
+ cfgcmd.cmd_type = CMD_STATS_BE_BUF_RELEASE;
else if (buf.type == STAT_BF)
cfgcmd.cmd_type = CMD_STATS_BF_BUF_RELEASE;
else if (buf.type == STAT_BHIST)
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 1875df2..e131193 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -210,6 +210,7 @@
case MSM_PMEM_SKIN:
case MSM_PMEM_AEC_AWB:
case MSM_PMEM_BAYER_GRID:
+ case MSM_PMEM_BAYER_EXPOSURE:
case MSM_PMEM_BAYER_FOCUS:
case MSM_PMEM_BAYER_HIST:
rc = msm_pmem_table_add(ptype, pinfo, client, domain_num);
@@ -241,6 +242,7 @@
case MSM_PMEM_SKIN:
case MSM_PMEM_AEC_AWB:
case MSM_PMEM_BAYER_GRID:
+ case MSM_PMEM_BAYER_EXPOSURE:
case MSM_PMEM_BAYER_FOCUS:
case MSM_PMEM_BAYER_HIST:
hlist_for_each_entry_safe(region, node, n,
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 6091a0d..287c77c 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -254,6 +254,8 @@
V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
[161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
+ [163] = {VFE_CMD_STATS_BE_START, V40_STATS_BE_LEN, V40_STATS_BE_OFF},
+ [164] = {VFE_CMD_STATS_BE_STOP},
};
static const uint32_t vfe40_AXI_WM_CFG[] = {
@@ -818,29 +820,34 @@
CDBG("%s: Use bayer stats = %d\n", __func__,
vfe40_use_bayer_stats(vfe40_ctrl));
- msm_camera_io_w(0x8350001F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_HIST_WR_UB_CFG);
- msm_camera_io_w(0x8370002F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_BG_WR_UB_CFG);
- msm_camera_io_w(0x83A0002F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_BF_WR_UB_CFG);
- msm_camera_io_w(0x83D0000F,
+ msm_camera_io_w(0x82F80007,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_UB_CFG);
- msm_camera_io_w(0x83E00007,
+ msm_camera_io_w(0x8300000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_UB_CFG);
- msm_camera_io_w(0x83E80007,
+
+ msm_camera_io_w(0x8310003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BG_WR_UB_CFG);
+ msm_camera_io_w(0x8350003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_UB_CFG);
+ msm_camera_io_w(0x8390003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BF_WR_UB_CFG);
+
+ msm_camera_io_w(0x83D0000F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_UB_CFG);
+ msm_camera_io_w(0x83E0000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_SKIN_WR_UB_CFG);
+
msm_camera_io_w(0x83F0000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_UB_CFG);
-
/* stats frame subsample config*/
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -850,6 +857,9 @@
VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -873,6 +883,9 @@
VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -894,13 +907,16 @@
struct vfe40_ctrl_type *vfe40_ctrl)
{
/* Stats control variables. */
- memset(&(vfe40_ctrl->afbfStatsControl), 0,
+ memset(&(vfe40_ctrl->bfStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->awbStatsControl), 0,
sizeof(struct vfe_stats_control));
- memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+ memset(&(vfe40_ctrl->bgStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->beStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->bhistStatsControl), 0,
@@ -1086,7 +1102,6 @@
{
uint32_t addr;
unsigned long flags;
-
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1111,7 +1126,40 @@
return 0;
}
-static uint32_t vfe_stats_aec_bg_buf_init(
+static uint32_t vfe_stats_be_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t addr;
+ unsigned long flags;
+ uint32_t stats_type;
+
+ stats_type = MSM_STATS_TYPE_BE;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq BE ping buf from free buf queue\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq BE pong buf from free buf queue\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_PONG_ADDR);
+ return 0;
+}
+
+static uint32_t vfe_stats_bg_buf_init(
struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
@@ -1144,7 +1192,7 @@
return 0;
}
-static int vfe_stats_af_bf_buf_init(
+static int vfe_stats_bf_buf_init(
struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
@@ -1189,7 +1237,6 @@
{
uint32_t addr;
unsigned long flags;
-
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1856,7 +1903,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bg_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AEC",
__func__);
@@ -1890,7 +1937,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bf_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AF",
__func__);
@@ -2030,15 +2077,25 @@
break;
case VFE_CMD_STATS_BG_START:
+ case VFE_CMD_STATS_BE_START:
case VFE_CMD_STATS_BF_START:
case VFE_CMD_STATS_BHIST_START: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
module_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
- if (VFE_CMD_STATS_BG_START == cmd->id) {
+
+ if (VFE_CMD_STATS_BE_START == cmd->id) {
+ module_val |= BE_ENABLE_MASK;
+ rc = vfe_stats_be_buf_init(vfe40_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of BG",
+ __func__);
+ goto proc_general_done;
+ }
+ } else if (VFE_CMD_STATS_BG_START == cmd->id) {
module_val |= BG_ENABLE_MASK;
- rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bg_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of BG",
__func__);
@@ -2046,7 +2103,7 @@
}
} else if (VFE_CMD_STATS_BF_START == cmd->id) {
module_val |= BF_ENABLE_MASK;
- rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bf_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of BF",
__func__);
@@ -2679,11 +2736,6 @@
break;
case VFE_CMD_STATS_AWB_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~AWB_ENABLE_MASK;
@@ -2691,29 +2743,36 @@
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
- case VFE_CMD_STATS_AE_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
+ case VFE_CMD_STATS_BG_STOP: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
- old_val &= BG_ENABLE_MASK;
+ old_val &= ~BG_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
- case VFE_CMD_STATS_AF_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
+ case VFE_CMD_STATS_BF_STOP: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~BF_ENABLE_MASK;
msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+ MSM_STATS_TYPE_BF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case VFE_CMD_STATS_BE_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~BE_ENABLE_MASK;
+ msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
@@ -2745,8 +2804,6 @@
}
break;
- case VFE_CMD_STATS_BG_STOP:
- case VFE_CMD_STATS_BF_STOP:
case VFE_CMD_STATS_BHIST_STOP: {
if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
/* Error */
@@ -2761,15 +2818,6 @@
msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
- if (VFE_CMD_STATS_BF_STOP == cmd->id) {
- rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
- MSM_STATS_TYPE_BF);
- if (rc < 0) {
- pr_err("%s: dq stats buf err = %d",
- __func__, rc);
- return -EINVAL;
- }
- }
}
break;
@@ -4015,6 +4063,16 @@
vfe40_ctrl->stats_ops.client);
}
break;
+ case statsBeNum:{
+ msgStats.id = MSG_ID_STATS_BE;
+ stats_type = MSM_STATS_TYPE_BE;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ stats_type, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
case statsBfNum:{
msgStats.id = MSG_ID_STATS_BF;
stats_type = MSM_STATS_TYPE_BF;
@@ -4101,9 +4159,9 @@
msgStats.status_bits = status_bits;
- msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
+ msgStats.aec.buff = vfe40_ctrl->bgStatsControl.bufToRender;
msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
- msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
+ msgStats.af.buff = vfe40_ctrl->bfStatsControl.bufToRender;
msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -4118,6 +4176,29 @@
&msgStats);
}
+static void vfe40_process_stats_be_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ uint32_t stats_type;
+ stats_type = MSM_STATS_TYPE_BE;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->beStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsBeNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->beStatsControl.bufToRender, statsBeNum);
+ } else{
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount);
+ }
+}
+
static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
{
unsigned long flags;
@@ -4128,16 +4209,16 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (addr) {
- vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_ctrl->bgStatsControl.bufToRender =
vfe40_process_stats_irq_common(vfe40_ctrl, statsBgNum,
addr);
vfe_send_stats_msg(vfe40_ctrl,
- vfe40_ctrl->aecbgStatsControl.bufToRender, statsBgNum);
+ vfe40_ctrl->bgStatsControl.bufToRender, statsBgNum);
} else{
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount);
}
}
@@ -4172,16 +4253,16 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (addr) {
- vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_ctrl->bfStatsControl.bufToRender =
vfe40_process_stats_irq_common(vfe40_ctrl, statsBfNum,
addr);
vfe_send_stats_msg(vfe40_ctrl,
- vfe40_ctrl->afbfStatsControl.bufToRender, statsBfNum);
+ vfe40_ctrl->bfStatsControl.bufToRender, statsBfNum);
} else{
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount);
}
}
@@ -4282,22 +4363,39 @@
CDBG("%s, stats = 0x%x\n", __func__, status_bits);
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- stats_type = MSM_STATS_TYPE_BG;
+ stats_type = MSM_STATS_TYPE_BE;
+ if (status_bits & VFE_IRQ_STATUS0_STATS_BE) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ stats_type);
+ if (addr) {
+ vfe40_ctrl->beStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsBeNum, addr);
+ process_stats = true;
+ } else{
+ vfe40_ctrl->beStatsControl.bufToRender = 0;
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe40_ctrl->beStatsControl.bufToRender = 0;
+ }
+
+ stats_type = MSM_STATS_TYPE_BG;
if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
stats_type);
if (addr) {
- vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_ctrl->bgStatsControl.bufToRender =
vfe40_process_stats_irq_common(
vfe40_ctrl, statsBgNum, addr);
process_stats = true;
} else{
- vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bgStatsControl.bufToRender = 0;
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
}
} else {
- vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+ vfe40_ctrl->bgStatsControl.bufToRender = 0;
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
@@ -4322,17 +4420,17 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
stats_type);
if (addr) {
- vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_ctrl->bfStatsControl.bufToRender =
vfe40_process_stats_irq_common(
vfe40_ctrl, statsBfNum,
addr);
process_stats = true;
} else {
- vfe40_ctrl->afbfStatsControl.bufToRender = 0;
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bfStatsControl.bufToRender = 0;
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
}
} else {
- vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+ vfe40_ctrl->bfStatsControl.bufToRender = 0;
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
@@ -4441,6 +4539,10 @@
CDBG("Stats BG irq occured.\n");
vfe40_process_stats_bg_irq(vfe40_ctrl);
break;
+ case VFE_IRQ_STATUS0_STATS_BE:
+ CDBG("Stats BE irq occured.\n");
+ vfe40_process_stats_be_irq(vfe40_ctrl);
+ break;
case VFE_IRQ_STATUS0_STATS_BF:
CDBG("Stats BF irq occured.\n");
vfe40_process_stats_bf_irq(vfe40_ctrl);
@@ -4522,6 +4624,8 @@
(qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_BG) |
(qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BE) |
+ (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB) |
(qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_BF) |
@@ -4610,6 +4714,12 @@
(void *)VFE_IRQ_STATUS0_STATS_BG);
if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BE)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_BE);
+
+ if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
@@ -4879,6 +4989,7 @@
cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_BE_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
@@ -4922,6 +5033,7 @@
(cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_AEC_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BG_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_BE_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BF_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
struct axidata *axid;
@@ -4945,6 +5057,7 @@
switch (cmd->cmd_type) {
case CMD_STATS_AEC_ENABLE:
case CMD_STATS_BG_ENABLE:
+ case CMD_STATS_BE_ENABLE:
case CMD_STATS_BF_ENABLE:
case CMD_STATS_BHIST_ENABLE:
case CMD_STATS_AWB_ENABLE:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 6363bfb..4acc7e4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -796,7 +796,7 @@
#define VFE_BUS_STATS_BE_WR_PING_ADDR 0x00000168
#define VFE_BUS_STATS_BE_WR_PONG_ADDR 0x0000016C
#define VFE_BUS_STATS_BE_WR_ADDR_CFG 0x00000170
-#define VFE_BUS_STATS_BE_UB_CFG 0x00000174
+#define VFE_BUS_STATS_BE_WR_UB_CFG 0x00000174
#define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN 0x00000178
#define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
@@ -1014,9 +1014,10 @@
uint32_t sync_timer_number;
struct msm_ver_num_info ver_num;
- struct vfe_stats_control afbfStatsControl;
+ struct vfe_stats_control beStatsControl;
+ struct vfe_stats_control bfStatsControl;
struct vfe_stats_control awbStatsControl;
- struct vfe_stats_control aecbgStatsControl;
+ struct vfe_stats_control bgStatsControl;
struct vfe_stats_control ihistStatsControl;
struct vfe_stats_control rsStatsControl;
struct vfe_stats_control csStatsControl;
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index e1a0994..7d44fea 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -442,12 +442,13 @@
struct buffer_info {
struct list_head list;
int type;
- int fd;
- int buff_off;
- int size;
- u32 uvaddr;
- u32 device_addr;
- struct msm_smem *handle;
+ int num_planes;
+ int fd[VIDEO_MAX_PLANES];
+ int buff_off[VIDEO_MAX_PLANES];
+ int size[VIDEO_MAX_PLANES];
+ u32 uvaddr[VIDEO_MAX_PLANES];
+ u32 device_addr[VIDEO_MAX_PLANES];
+ struct msm_smem *handle[VIDEO_MAX_PLANES];
};
struct msm_v4l2_vid_inst {
@@ -472,26 +473,37 @@
}
struct buffer_info *get_registered_buf(struct list_head *list,
- int fd, u32 buff_off, u32 size)
+ int fd, u32 buff_off, u32 size, int *plane)
{
struct buffer_info *temp;
struct buffer_info *ret = NULL;
- if (!list || fd < 0) {
+ int i;
+ if (!list || fd < 0 || !plane) {
dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
+ *plane = 0;
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
- if (temp && temp->fd == fd &&
- (CONTAINS(temp->buff_off, temp->size, buff_off)
- || CONTAINS(buff_off, size, temp->buff_off)
- || OVERLAPS(buff_off, size,
- temp->buff_off, temp->size))) {
- dprintk(VIDC_INFO,
- "This memory region is already mapped\n");
- ret = temp;
- break;
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd &&
+ (CONTAINS(temp->buff_off[i],
+ temp->size[i], buff_off)
+ || CONTAINS(buff_off,
+ size, temp->buff_off[i])
+ || OVERLAPS(buff_off, size,
+ temp->buff_off[i],
+ temp->size[i]))) {
+ dprintk(VIDC_DBG,
+ "This memory region is already mapped\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
}
+ if (ret)
+ break;
}
}
err_invalid_input:
@@ -499,25 +511,62 @@
}
struct buffer_info *get_same_fd_buffer(struct list_head *list,
- int fd)
+ int fd, int *plane)
{
struct buffer_info *temp;
struct buffer_info *ret = NULL;
- if (!list || fd < 0) {
+ int i;
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+ *plane = 0;
+ if (!list_empty(list)) {
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+{
+ struct buffer_info *temp;
+ u32 uvaddr = 0;
+ int i;
+ if (!list || !device_addr) {
dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
- if (temp && temp->fd == fd) {
- dprintk(VIDC_INFO, "Found same fd buffer\n");
- ret = temp;
- break;
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->device_addr[i]
+ == device_addr) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ uvaddr = temp->uvaddr[i];
+ break;
+ }
}
+ if (uvaddr)
+ break;
}
}
err_invalid_input:
- return ret;
+ return uvaddr;
}
static int msm_v4l2_open(struct file *filp)
@@ -567,23 +616,27 @@
struct list_head *ptr, *next;
struct buffer_info *bi;
struct v4l2_buffer buffer_info;
- struct v4l2_plane plane;
+ struct v4l2_plane plane[VIDEO_MAX_PLANES];
int rc = 0;
+ int i;
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
buffer_info.type = bi->type;
- plane.reserved[0] = bi->fd;
- plane.reserved[1] = bi->buff_off;
- plane.length = bi->size;
- plane.m.userptr = bi->device_addr;
- buffer_info.m.planes = &plane;
- buffer_info.length = 1;
- dprintk(VIDC_DBG,
- "Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ plane[i].reserved[0] = bi->fd[i];
+ plane[i].reserved[1] = bi->buff_off[i];
+ plane[i].length = bi->size[i];
+ plane[i].m.userptr = bi->device_addr[i];
+ buffer_info.m.planes = plane;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[i].reserved[0],
+ buffer_info.m.planes[i].reserved[1],
+ buffer_info.m.planes[i].length);
+ }
+ buffer_info.length = bi->num_planes;
rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
&buffer_info);
if (rc)
@@ -593,11 +646,13 @@
buffer_info.m.planes[0].reserved[1],
buffer_info.m.planes[0].length);
list_del(&bi->list);
- if (bi->handle)
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle);
- kfree(bi);
+ for (i = 0; i < bi->num_planes; i++) {
+ if (bi->handle[i])
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle[i]);
}
+ kfree(bi);
+ }
}
return rc;
}
@@ -609,6 +664,7 @@
struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
+ int i;
vidc_inst = get_vidc_inst(filp, NULL);
v4l2_inst = get_v4l2_inst(filp, NULL);
rc = msm_v4l2_release_output_buffers(v4l2_inst);
@@ -620,9 +676,12 @@
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
list_del(&bi->list);
- if (bi->handle)
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (bi->handle[i])
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle[i]);
+ }
kfree(bi);
}
}
@@ -696,6 +755,7 @@
struct buffer_info *temp;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
+ int plane = 0;
int i, rc = 0;
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
@@ -704,34 +764,41 @@
rc = -ENOMEM;
goto exit;
}
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+ b->length, VIDEO_MAX_PLANES);
+ rc = -EINVAL;
+ goto exit;
+ }
for (i = 0; i < b->length; ++i) {
- binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ temp = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- if (binfo) {
- dprintk(VIDC_INFO,
+ b->m.planes[i].length, &plane);
+ if (temp) {
+ dprintk(VIDC_DBG,
"This memory region has already been prepared\n");
rc = -EINVAL;
- goto exit;
- }
- binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
- if (!binfo) {
- dprintk(VIDC_ERR, "Out of memory\n");
- rc = -ENOMEM;
+ kfree(binfo);
goto exit;
}
temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0]);
+ b->m.planes[i].reserved[0], &plane);
if (temp) {
binfo->type = b->type;
- binfo->fd = b->m.planes[i].reserved[0];
- binfo->buff_off = b->m.planes[i].reserved[1];
- binfo->size = b->m.planes[i].length;
- binfo->uvaddr = b->m.planes[i].m.userptr;
- binfo->device_addr =
- temp->handle->device_addr + binfo->buff_off;
- binfo->handle = NULL;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->device_addr[i] =
+ temp->handle[plane]->device_addr + binfo->buff_off[i];
+ binfo->handle[i] = NULL;
} else {
handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
b->m.planes[i].reserved[0],
@@ -745,21 +812,22 @@
goto exit;
}
binfo->type = b->type;
- binfo->fd = b->m.planes[i].reserved[0];
- binfo->buff_off = b->m.planes[i].reserved[1];
- binfo->size = b->m.planes[i].length;
- binfo->uvaddr = b->m.planes[i].m.userptr;
- binfo->device_addr =
- handle->device_addr + binfo->buff_off;
- binfo->handle = handle;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->device_addr[i] =
+ handle->device_addr + binfo->buff_off[i];
+ binfo->handle[i] = handle;
dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
b->m.planes[i].length);
}
- list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
- b->m.planes[i].m.userptr = binfo->device_addr;
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
}
+ binfo->num_planes = b->length;
+ list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
exit:
return rc;
@@ -771,15 +839,21 @@
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
struct buffer_info *binfo;
+ int plane = 0;
int rc = 0;
int i;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+ b->length);
+ return -EINVAL;
+ }
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
for (i = 0; i < b->length; ++i) {
binfo = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
- b->m.planes[i].length);
+ b->m.planes[i].length, &plane);
if (!binfo) {
dprintk(VIDC_ERR,
"This buffer is not registered: %d, %d, %d\n",
@@ -789,12 +863,12 @@
rc = -EINVAL;
goto err_invalid_buff;
}
- b->m.planes[i].m.userptr = binfo->device_addr;
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
- binfo->device_addr);
- if (binfo->handle) {
+ binfo->device_addr[i]);
+ if (binfo->handle[i]) {
rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
- binfo->handle);
+ binfo->handle[i]);
if (rc) {
dprintk(VIDC_ERR,
"Failed to clean caches: %d\n", rc);
@@ -810,8 +884,37 @@
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
+ int rc = 0;
+ int i;
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- return msm_vidc_dqbuf((void *)vidc_inst, b);
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+ v4l2_inst = get_v4l2_inst(file, fh);
+ rc = msm_vidc_dqbuf((void *)vidc_inst, b);
+ if (rc) {
+ dprintk(VIDC_DBG,
+ "Failed to dqbuf, capability: %d, rc: %d\n",
+ b->type, rc);
+ goto fail_dq_buf;
+ }
+ for (i = 0; i < b->length; i++) {
+ b->m.planes[i].m.userptr = device_to_uvaddr(
+ &v4l2_inst->registered_bufs,
+ b->m.planes[i].m.userptr);
+ if (!b->m.planes[i].m.userptr) {
+ dprintk(VIDC_ERR,
+ "Failed to find user virtual address, 0x%lx, %d, %d\n",
+ b->m.planes[i].m.userptr, b->type, i);
+ rc = -EINVAL;
+ goto fail_dq_buf;
+ }
+ }
+fail_dq_buf:
+ return rc;
}
int msm_v4l2_streamon(struct file *file, void *fh,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index bd9cfb2..058c835 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -20,7 +20,6 @@
#include "msm_vidc_debug.h"
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
-#define MAX_PLANES 1
#define DEFAULT_HEIGHT 720
#define DEFAULT_WIDTH 1280
#define MAX_SUPPORTED_WIDTH 1920
@@ -186,11 +185,6 @@
size = ALIGN(size, SZ_4K);
return size;
}
-static u32 get_frame_size_nv21(int plane,
- u32 height, u32 width)
-{
- return height * width * 2;
-}
static u32 get_frame_size_compressed(int plane,
u32 height, u32 width)
@@ -203,7 +197,7 @@
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_nv12,
.type = CAPTURE_PORT,
},
@@ -264,14 +258,6 @@
.type = OUTPUT_PORT,
},
{
- .name = "YCrCb Semiplanar 4:2:0",
- .description = "Y/CrCb 4:2:0",
- .fourcc = V4L2_PIX_FMT_NV21,
- .num_planes = 1,
- .get_frame_size = get_frame_size_nv21,
- .type = CAPTURE_PORT,
- },
- {
.name = "DIVX 311",
.description = "DIVX 311 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX_311,
@@ -332,45 +318,48 @@
struct v4l2_buffer *b)
{
int rc = 0;
- int i;
struct vidc_buffer_addr_info buffer_info;
+ int extra_idx = 0;
+ int i;
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG, "device_addr = %ld, size = %d\n",
- b->m.planes[i].m.userptr,
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; (i < b->length)
+ && (i < VIDEO_MAX_PLANES); ++i) {
+ dprintk(VIDC_DBG,
+ "prepare plane: %d, device_addr = 0x%lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- if (!inst->extradata_handle) {
- inst->extradata_handle =
- msm_smem_alloc(inst->mem_client,
- 4096 * 1024, 1, SMEM_UNCACHED,
- inst->core->resources.io_map[NS_MAP].domain,
- 0, 0);
- if (!inst->extradata_handle) {
- dprintk(VIDC_ERR,
- "Failed to allocate extradata memory\n");
- rc = -ENOMEM;
- break;
- }
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG,
+ "extradata: 0x%lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
}
- buffer_info.extradata_addr =
- inst->extradata_handle->device_addr;
- buffer_info.extradata_size = 4096 * 1024;
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
- if (rc) {
+ if (rc)
dprintk(VIDC_ERR,
- "vidc_hal_session_set_buffers failed\n");
- break;
- }
- }
+ "vidc_hal_session_set_buffers failed");
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -383,9 +372,10 @@
struct v4l2_buffer *b)
{
int rc = 0;
- int i;
struct vidc_buffer_addr_info buffer_info;
struct msm_vidc_core *core = inst->core;
+ int extra_idx = 0;
+ int i;
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
@@ -393,28 +383,40 @@
core);
goto exit;
}
+
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG,
- "Release device_addr = %ld, size = %d\n",
- b->m.planes[i].m.userptr,
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; i < b->length; ++i) {
+ dprintk(VIDC_DBG,
+ "Release plane: %d device_addr = 0x%lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_addr =
- inst->extradata_handle->device_addr;
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
- "vidc_hal_session_release_buffers failed\n");
- }
+ "vidc_hal_session_release_buffers failed");
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -486,7 +488,10 @@
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ struct hal_frame_size frame_sz;
+ int extra_idx = 0;
int rc = 0;
+ int ret;
int i;
if (!inst || !f) {
dprintk(VIDC_ERR,
@@ -500,21 +505,41 @@
if (fmt) {
f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
if (inst->in_reconfig == true) {
inst->prop.height = inst->reconfig_height;
inst->prop.width = inst->reconfig_width;
}
f->fmt.pix_mp.height = inst->prop.height;
f->fmt.pix_mp.width = inst->prop.width;
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i, inst->prop.height,
- inst->prop.width);
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ ret = ret || msm_comm_try_get_bufreqs(inst);
+ if (ret || (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ }
}
} else {
- dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
- f->type);
+ dprintk(VIDC_ERR,
+ "Buf type not recognized, type = %d\n",
+ f->type);
rc = -EINVAL;
}
return rc;
@@ -523,7 +548,10 @@
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ struct hal_frame_size frame_sz;
+ int extra_idx = 0;
int rc = 0;
+ int ret = 0;
int i;
if (!inst || !f) {
dprintk(VIDC_ERR,
@@ -536,64 +564,67 @@
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
- if (fmt && fmt->type != CAPTURE_PORT) {
+ if (!fmt || (fmt && fmt->type != CAPTURE_PORT)) {
dprintk(VIDC_ERR,
- "Format: %d not supported on CAPTURE"
- "port\n", f->fmt.pix_mp.pixelformat);
- rc = -EINVAL;
- goto err_invalid_fmt;
- }
-
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
-
- frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
- dprintk(VIDC_DBG,
- "width = %d, height = %d\n",
- frame_sz.width, frame_sz.height);
- rc = vidc_hal_session_set_property((void *)inst->session,
- HAL_PARAM_FRAME_SIZE, &frame_sz);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to set hal property for framesize\n");
- goto err_invalid_fmt;
- }
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
- fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
- ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
- OUTPUT_PORT);
- if (fmt && fmt->type != OUTPUT_PORT) {
- dprintk(VIDC_ERR,
- "Format: %d not supported on OUTPUT port\n",
+ "Format: %d not supported on CAPTURE port\n",
f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
- }
-
- if (fmt) {
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i, f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
- }
inst->fmts[fmt->type] = fmt;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to open instance\n");
- goto err_invalid_fmt;
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ ret = ret || msm_comm_try_get_bufreqs(inst);
+ if (ret) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[1].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
}
}
- } else {
- dprintk(VIDC_ERR,
- "Buf type not recognized, type = %d\n", f->type);
- rc = -EINVAL;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->prop.width = f->fmt.pix_mp.width;
+ inst->prop.height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats),
+ f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (!fmt || fmt->type != OUTPUT_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ inst->fmts[fmt->type] = fmt;
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ fmt->get_frame_size(0, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
}
err_invalid_fmt:
return rc;
@@ -657,14 +688,17 @@
struct msm_vidc_inst *inst;
unsigned long flags;
struct hal_buffer_requirements *bufreq;
- if (!q || !q->drv_priv) {
- dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ int extra_idx = 0;
+ if (!q || !num_buffers || !num_planes
+ || !sizes || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
+ q, num_buffers, num_planes);
return -EINVAL;
}
inst = q->drv_priv;
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- *num_planes = 1;
+ *num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
@@ -675,6 +709,7 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+ *num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -686,7 +721,6 @@
"Failed to get buffer requirements: %d\n", rc);
break;
}
- *num_planes = 1;
spin_lock_irqsave(&inst->lock, flags);
if (*num_buffers && *num_buffers >
inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
@@ -711,11 +745,13 @@
inst->buff_req.buffer[1].buffer_count_actual,
inst->buff_req.buffer[1].buffer_size,
inst->buff_req.buffer[1].buffer_alignment);
- for (i = 0; i < *num_planes; i++) {
- sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ sizes[0] = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ sizes[extra_idx] =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
}
-
break;
default:
dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index ed234b9..54c3d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -685,7 +685,7 @@
struct vb2_buffer *vb;
struct vidc_hal_fbd *fill_buf_done;
if (!response) {
- pr_err("Invalid response from vidc_hal\n");
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
}
inst = (struct msm_vidc_inst *)response->session_id;
@@ -1545,14 +1545,14 @@
dprintk(VIDC_DBG, "Sent etb to HAL\n");
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
struct vidc_seq_hdr seq_hdr;
+ int extra_idx = 0;
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
- if (inst->extradata_handle) {
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx)
frame_data.extradata_addr =
- inst->extradata_handle->device_addr;
- } else {
- frame_data.extradata_addr = 0;
- }
+ vb->v4l2_planes[extra_idx].m.userptr;
dprintk(VIDC_DBG,
"Sending ftb to hal: Alloc: %d :filled: %d",
frame_data.alloc_len, frame_data.filled_len);
@@ -1596,6 +1596,12 @@
{
int rc = 0;
mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR,
+ "Not in proper state to query buffer requirements\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
rc = vidc_hal_session_get_buf_req((void *) inst->session);
@@ -1721,6 +1727,29 @@
return rc;
}
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata)
+{
+ int rc = 0;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", inst);
+ return -EINVAL;
+ }
+ mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR, "Not in proper state to set property\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ ptype, pdata);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 20b4bc2..7562058 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -27,6 +27,8 @@
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 0f6740f..f288cc6 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -74,6 +74,8 @@
uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
buf_size = y_buf_size + uv_buf_size; }
+#define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
+
enum vidc_ports {
OUTPUT_PORT,
CAPTURE_PORT,
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index fef3dd5..d3fa1d0 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -359,7 +359,7 @@
HAL_BUFFER_EXTRADATA_OUTPUT2,
HAL_BUFFER_INTERNAL_SCRATCH,
HAL_BUFFER_INTERNAL_PERSIST,
- HAL_UNUSED_BUFFER = 0x10000000,
+ HAL_BUFFER_MAX
};
struct hal_frame_rate {
@@ -942,7 +942,7 @@
};
struct buffer_requirements {
- struct hal_buffer_requirements buffer[8];
+ struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
/* VIDC_HAL CORE API's */
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 103c1a3..53e965c 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -218,6 +218,8 @@
if (ret < 0) {
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
+ dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
+ disable_irq_nosync(wcd9xxx->irq);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ca5f890..b711fd9 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -81,6 +81,42 @@
unsigned long arg);
static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+void mdss_fb_no_update_notify_timer_cb(unsigned long data)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+ if (!mfd)
+ pr_err("%s mfd NULL\n", __func__);
+ complete(&mfd->no_update.comp);
+}
+
+static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
+ unsigned long *argp)
+{
+ int ret, notify;
+
+ ret = copy_from_user(¬ify, argp, sizeof(int));
+ if (ret) {
+ pr_err("%s:ioctl failed\n", __func__);
+ return ret;
+ }
+
+ if (notify > NOTIFY_UPDATE_STOP)
+ return -EINVAL;
+
+ if (notify == NOTIFY_UPDATE_START) {
+ INIT_COMPLETION(mfd->update.comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->update.comp, 4 * HZ);
+ } else {
+ INIT_COMPLETION(mfd->no_update.comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->no_update.comp, 4 * HZ);
+ }
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ return (ret > 0) ? 0 : ret;
+}
+
#define MAX_BACKLIGHT_BRIGHTNESS 255
static int lcd_backlight_registered;
@@ -101,7 +137,9 @@
if (!bl_lvl && value)
bl_lvl = 1;
+ mutex_lock(&mfd->lock);
mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->lock);
}
static struct led_classdev backlight_led = {
@@ -209,6 +247,8 @@
mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
mfd->panel_info.frame_count = 0;
mfd->bl_level = 0;
+ mfd->bl_scale = 1024;
+ mfd->bl_min_lvl = 30;
mfd->fb_imgType = MDP_RGBA_8888;
mfd->pdev = pdev;
@@ -269,6 +309,11 @@
pr_err("msm_fb_remove: can't stop the device %d\n",
mfd->index);
+ if (mfd->no_update.timer.function)
+ del_timer(&mfd->no_update.timer);
+ complete(&mfd->no_update.comp);
+ complete(&mfd->update.comp);
+
/* remove /dev/fb* */
unregister_framebuffer(mfd->fbi);
@@ -416,9 +461,46 @@
static int unset_bl_level, bl_updated;
static int bl_level_old;
+static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
+ struct mdp_bl_scale_data *data)
+{
+ int ret = 0;
+ int curr_bl;
+ mutex_lock(&mfd->lock);
+ curr_bl = mfd->bl_level;
+ mfd->bl_scale = data->scale;
+ mfd->bl_min_lvl = data->min_lvl;
+ pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+ mfd->bl_min_lvl);
+
+ /* update current backlight to use new scaling*/
+ mdss_fb_set_backlight(mfd, curr_bl);
+ mutex_unlock(&mfd->lock);
+ return ret;
+}
+
+static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
+{
+ u32 temp = *bl_lvl;
+ pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
+ if (temp >= mfd->bl_min_lvl) {
+ /* bl_scale is the numerator of scaling fraction (x/1024)*/
+ temp = (temp * mfd->bl_scale) / 1024;
+
+ /*if less than minimum level, use min level*/
+ if (temp < mfd->bl_min_lvl)
+ temp = mfd->bl_min_lvl;
+ }
+ pr_debug("output = %d", temp);
+
+ (*bl_lvl) = temp;
+}
+
+/* must call this function from within mfd->lock */
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
{
struct mdss_panel_data *pdata;
+ u32 temp = bkl_lvl;
if (!mfd->panel_power_on || !bl_updated) {
unset_bl_level = bkl_lvl;
@@ -430,15 +512,22 @@
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mutex_lock(&mfd->lock);
- if (bl_level_old == bkl_lvl) {
- mutex_unlock(&mfd->lock);
+ mdss_fb_scale_bl(mfd, &temp);
+ /*
+ * Even though backlight has been scaled, want to show that
+ * backlight has been set to bkl_lvl to those that read from
+ * sysfs node. Thus, need to set bl_level even if it appears
+ * the backlight has already been set to the level it is at,
+ * as well as setting bl_level to bkl_lvl even though the
+ * backlight has been set to the scaled value.
+ */
+ if (bl_level_old == temp) {
+ mfd->bl_level = bkl_lvl;
return;
}
+ pdata->set_backlight(pdata, temp);
mfd->bl_level = bkl_lvl;
- pdata->set_backlight(pdata, mfd->bl_level);
- bl_level_old = mfd->bl_level;
- mutex_unlock(&mfd->lock);
+ bl_level_old = temp;
}
}
@@ -822,6 +911,13 @@
mfd->op_enable = true;
+ mutex_init(&mfd->no_update.lock);
+ init_timer(&mfd->no_update.timer);
+ mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
+ mfd->no_update.timer.data = (unsigned long)mfd;
+ init_completion(&mfd->update.comp);
+ init_completion(&mfd->no_update.comp);
+
if (mfd->lut_update) {
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -1124,7 +1220,8 @@
return 0;
}
-static int mdss_fb_handle_pp_ioctl(void __user *argp)
+static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
+ void __user *argp)
{
int ret;
struct msmfb_mdp_pp mdp_pp;
@@ -1179,6 +1276,10 @@
ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
©back);
break;
+ case mdp_bl_scale_cfg:
+ ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+ &mdp_pp.data.bl_scale_data);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1256,7 +1357,11 @@
break;
case MSMFB_MDP_PP:
- ret = mdss_fb_handle_pp_ioctl(argp);
+ ret = mdss_fb_handle_pp_ioctl(mfd, argp);
+ break;
+
+ case MSMFB_NOTIFY_UPDATE:
+ ret = mdss_fb_notify_update(mfd, argp);
break;
default:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 25c39f6..78f2b9a 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -41,6 +41,13 @@
int panel_power_on;
};
+struct disp_info_notify {
+ int type;
+ struct timer_list timer;
+ struct completion comp;
+ struct mutex lock;
+};
+
struct msm_fb_data_type {
u32 key;
u32 index;
@@ -83,6 +90,8 @@
unsigned long cursor_buf_iova;
u32 bl_level;
+ u32 bl_scale;
+ u32 bl_min_lvl;
struct mutex lock;
struct platform_device *pdev;
@@ -98,6 +107,8 @@
struct list_head overlay_list;
struct list_head pipes_used;
struct list_head pipes_cleanup;
+ struct disp_info_notify update;
+ struct disp_info_notify no_update;
};
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 452ebdc..d52df66 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -406,6 +406,15 @@
if (IS_ERR_VALUE(ret))
return ret;
+ complete(&mfd->update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ if (mfd->no_update.timer.function)
+ del_timer(&(mfd->no_update.timer));
+
+ mfd->no_update.timer.expires = jiffies + (2 * HZ);
+ add_timer(&mfd->no_update.timer);
+ mutex_unlock(&mfd->no_update.lock);
+
mutex_lock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
list_del(&pipe->cleanup_list);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6e04124..e4be407 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -99,6 +99,7 @@
u32 hist_cnt_read;
u32 hist_cnt_sent;
u32 frame_cnt;
+ u32 is_kick_ready;
struct completion comp;
u32 data[HIST_V_SIZE];
};
@@ -365,6 +366,7 @@
struct pp_hist_col_info *hist_info;
struct pp_sts_type *pp_sts;
u32 data, tbl_idx, col_state;
+ unsigned long flag;
int i;
dspp_num = mixer->num;
/* no corresponding dspp */
@@ -377,20 +379,19 @@
/* HIST_EN & AUTO_CLEAR */
opmode |= (1 << 16) | (1 << 17);
mutex_lock(&mdss_mdp_hist_mutex);
- if (hist_info->col_state == HIST_READY)
- pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
- 0x1C, hist_info);
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
col_state = hist_info->col_state;
- if ((col_state == HIST_IDLE) ||
- (col_state == HIST_READY) ||
- (col_state == HIST_START)) {
+ if (hist_info->is_kick_ready &&
+ ((col_state == HIST_IDLE) ||
+ ((false == hist_info->read_request) &&
+ col_state == HIST_READY))) {
/* Kick off collection */
MDSS_MDP_REG_WRITE(base +
MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
hist_info->col_state = HIST_START;
}
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mutex_unlock(&mdss_mdp_hist_mutex);
}
@@ -1263,6 +1264,7 @@
int i, ret = 0;
u32 disp_num, dspp_num = 0;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(req->block >= MDP_BLOCK_MAX))
@@ -1296,7 +1298,7 @@
__func__, dspp_num);
goto hist_start_exit;
}
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
hist_info->frame_cnt = req->frame_cnt;
init_completion(&hist_info->comp);
hist_info->hist_cnt_read = 0;
@@ -1304,7 +1306,8 @@
hist_info->read_request = false;
hist_info->col_state = HIST_RESET;
hist_info->col_en = true;
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = false;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mdss_pp_res->hist_col[disp_num][i] =
&mdss_pp_res->dspp_hist[dspp_num];
mdss_mdp_hist_irq_enable(3 << done_shift_bit);
@@ -1329,6 +1332,7 @@
u32 dspp_num, disp_num, ctl_base, done_bit;
struct pp_hist_col_info *hist_info;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
(block >= MDP_BLOCK_MAX))
@@ -1362,10 +1366,11 @@
goto hist_stop_exit;
}
complete_all(&hist_info->comp);
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
hist_info->col_en = false;
hist_info->col_state = HIST_UNKNOWN;
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = false;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mdss_mdp_hist_irq_disable(done_bit);
MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
}
@@ -1386,6 +1391,7 @@
struct pp_hist_col_info *hist_info;
u32 dspp_num, disp_num, ctl_base;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(hist->block >= MDP_BLOCK_MAX))
@@ -1418,55 +1424,50 @@
ret = -EINVAL;
goto hist_collect_exit;
}
- spin_lock(&mdss_hist_lock);
- if ((hist_info->col_state == HIST_READY) ||
- (hist_info->hist_cnt_read == 0)) {
- /* wait for hist done if cache has no data */
- if ((hist_info->col_state != HIST_READY) &&
- (hist_info->hist_cnt_read == 0)) {
- hist_info->read_request = true;
- spin_unlock(&mdss_hist_lock);
- timeout = HIST_WAIT_TIMEOUT *
- hist_info->frame_cnt;
- mutex_unlock(&mdss_mdp_hist_mutex);
- wait_ret = wait_for_completion_killable_timeout(
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ /* wait for hist done if cache has no data */
+ if (hist_info->col_state != HIST_READY) {
+ hist_info->read_request = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ timeout = HIST_WAIT_TIMEOUT *
+ hist_info->frame_cnt;
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
- mutex_lock(&mdss_mdp_hist_mutex);
- hist_info->read_request = false;
- if (wait_ret == 0) {
- ret = -ETIMEDOUT;
- pr_debug("%s: bin collection timedout",
+ mutex_lock(&mdss_mdp_hist_mutex);
+ if (wait_ret == 0) {
+ ret = -ETIMEDOUT;
+ pr_debug("%s: bin collection timedout",
__func__);
- goto hist_collect_exit;
- } else if (wait_ret < 0) {
- ret = -EINTR;
- pr_debug("%s: bin collection interrupted",
+ goto hist_collect_exit;
+ } else if (wait_ret < 0) {
+ ret = -EINTR;
+ pr_debug("%s: bin collection interrupted",
__func__);
- goto hist_collect_exit;
- }
- if (hist_info->col_state != HIST_READY) {
- ret = -EBUSY;
- pr_err("%s: collection state is not ready: %d",
- __func__, hist_info->col_state);
- goto hist_collect_exit;
- }
- } else {
- spin_unlock(&mdss_hist_lock);
+ goto hist_collect_exit;
}
- if (hist_info->col_state == HIST_READY) {
- v_base = ctl_base + 0x1C;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pp_hist_read(v_base, hist_info);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- spin_lock(&mdss_hist_lock);
- hist_info->col_state = HIST_IDLE;
- spin_unlock(&mdss_hist_lock);
+ if (hist_info->col_state != HIST_READY) {
+ ret = -ENODATA;
+ pr_debug("%s: collection state is not ready: %d",
+ __func__, hist_info->col_state);
+ goto hist_collect_exit;
}
} else {
- spin_unlock(&mdss_hist_lock);
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
}
- hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ if (hist_info->col_state == HIST_READY) {
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ v_base = ctl_base + 0x1C;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ pp_hist_read(v_base, hist_info);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ hist_info->read_request = false;
+ hist_info->col_state = HIST_IDLE;
+ }
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
}
if (mixer_cnt > 1) {
memset(&mdss_pp_res->hist_data[disp_num][0],
@@ -1482,7 +1483,7 @@
} else {
*hist_data_addr = (u32)hist_info->data;
}
-
+ hist_info->hist_cnt_sent++;
hist_collect_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
return ret;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 1cdc434..98050ce 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -399,7 +399,7 @@
uint32_t block;
uint8_t frame_cnt;
uint8_t bit_mask;
- uint8_t num_bins;
+ uint16_t num_bins;
};
/*
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 6658b8c..9af15e3 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -536,6 +536,8 @@
#define CMD_STATS_BHIST_BUF_RELEASE 58
#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59
#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
+#define CMD_STATS_BE_ENABLE 61
+#define CMD_STATS_BE_BUF_RELEASE 62
#define CMD_AXI_CFG_PRIM BIT(8)
#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9)
@@ -599,7 +601,8 @@
#define MSM_PMEM_BAYER_GRID 20
#define MSM_PMEM_BAYER_FOCUS 21
#define MSM_PMEM_BAYER_HIST 22
-#define MSM_PMEM_MAX 23
+#define MSM_PMEM_BAYER_EXPOSURE 23
+#define MSM_PMEM_MAX 24
#define STAT_AEAW 0
#define STAT_AEC 1
@@ -611,8 +614,9 @@
#define STAT_SKIN 7
#define STAT_BG 8
#define STAT_BF 9
-#define STAT_BHIST 10
-#define STAT_MAX 11
+#define STAT_BE 10
+#define STAT_BHIST 11
+#define STAT_MAX 12
#define FRAME_PREVIEW_OUTPUT1 0
#define FRAME_PREVIEW_OUTPUT2 1
@@ -631,6 +635,7 @@
MSM_STATS_TYPE_SKIN, /* legacy based SKIN */
MSM_STATS_TYPE_BG, /* Bayer Grids */
MSM_STATS_TYPE_BF, /* Bayer Focus */
+ MSM_STATS_TYPE_BE, /* Bayer Exposure*/
MSM_STATS_TYPE_BHIST, /* Bayer Hist */
MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/
MSM_STATS_TYPE_COMP, /* Composite stats */
@@ -807,6 +812,7 @@
struct stats_buff aec;
struct stats_buff awb;
struct stats_buff af;
+ struct stats_buff be;
struct stats_buff ihist;
struct stats_buff rs;
struct stats_buff cs;
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index faaa522..8b4ae19 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -70,6 +70,7 @@
#define MSG_ID_RDI2_UPDATE_ACK 51
#define MSG_ID_PIX0_UPDATE_ACK 52
#define MSG_ID_PREV_STOP_ACK 53
+#define MSG_ID_STATS_BE 54
/* ISP command IDs */
@@ -236,7 +237,8 @@
#define VFE_CMD_COLORXFORM_ENC_UPDATE 160
#define VFE_CMD_COLORXFORM_VIEW_UPDATE 161
#define VFE_CMD_TEST_GEN_CFG 162
-
+#define VFE_CMD_STATS_BE_START 163
+#define VFE_CMD_STATS_BE_STOP 164
struct msm_isp_cmd {
int32_t id;
uint16_t length;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 956e4cd..db37b7c 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4467,6 +4467,9 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+ /* TX VHIGH comparator */
+ TAIKO_REG_VAL(TAIKO_A_TX_SUP_SWITCH_CTRL_2, 0x90),
};
static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 30a0214..653effa 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -68,7 +68,7 @@
#define FW_READ_ATTEMPTS 15
#define FW_READ_TIMEOUT 2000000
-#define BUTTON_POLLING_SUPPORTED false
+#define BUTTON_POLLING_SUPPORTED true
#define MCLK_RATE_12288KHZ 12288000
#define MCLK_RATE_9600KHZ 9600000
@@ -564,9 +564,21 @@
return;
pr_debug("%s: Setting up %s detection\n", __func__,
ins ? "insert" : "removal");
- /* Enable interrupt and insertion detection */
+ /* Disable detection to avoid glitch */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
+ /* Override mbhc power switch to avoid false IRQs */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_1_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_2_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_3_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_4_MBHC, 1 << 2,
+ !ins << 2);
snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
- (0x69 | (ins ? (1 << 1) : 0)));
+ (0x68 | (ins ? (1 << 1) : 0)));
+ /* Re-enable detection */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
}
/* called under codec_resource_lock acquisition */