From bf86c72be23584217d245e052f6d424fc3e45e3f Mon Sep 17 00:00:00 2001 From: Puja Gupta Date: Tue, 6 Dec 2016 16:08:27 -0800 Subject: [PATCH 1/6] soc: qcom: pil: Initialize variable to avoid invalid access Initialize dp_fw to NULL so that we don't try to release it in the error path err_invalid_fw. CRs-Fixed: 1095243 Change-Id: I18f549102e626dc788e8fa56d6bb1ea28efe4f88 Signed-off-by: Puja Gupta --- drivers/soc/qcom/pil-msa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 00ab1ce3b6b4..26bb88c29565 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -531,7 +531,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) { struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc); struct modem_data *md = dev_get_drvdata(pil->dev); - const struct firmware *fw, *dp_fw; + const struct firmware *fw, *dp_fw = NULL; char fw_name_legacy[10] = "mba.b00"; char fw_name[10] = "mba.mbn"; char *dp_name = "msadp"; From c71cda2d1010e7c936db468b5b4d3bcb2797f1c7 Mon Sep 17 00:00:00 2001 From: Tarun Karra Date: Mon, 14 Nov 2016 16:38:27 -0800 Subject: [PATCH 2/6] msm: kgsl: Add Bind objects to dispatcher draw queue kgsl_ioctl_gpu_sparse_command() is added to for user to specify list of binds/unbinds for a memory entry and syncpoints they depend on. If user specifies both create a sync object for syncpoints and bind object for binds/unbinds and add them to dispatcher draw queue. Sync object should be inserted before the bind object in the draw queue. Once the bind object reaches the head of draw queue the corresponding binds/unbinds are performed. kgsl_ioctl_gpu_sparse_command() only accepts commands from context created with flag KGSL_CONTEXT_SPARSE, commands from all other context types will return an error. Change-Id: Ib0a2361f854ae01d0d8090cdd48cfa96308daf93 Signed-off-by: Tarun Karra --- drivers/gpu/msm/adreno_dispatch.c | 127 +++++++++++++++++++- drivers/gpu/msm/adreno_drawctxt.c | 3 +- drivers/gpu/msm/kgsl.c | 152 +++++++++++++++++++++++- drivers/gpu/msm/kgsl.h | 3 + drivers/gpu/msm/kgsl_compat.c | 2 + drivers/gpu/msm/kgsl_device.h | 15 +++ drivers/gpu/msm/kgsl_drawobj.c | 187 ++++++++++++++++++++++-------- drivers/gpu/msm/kgsl_drawobj.h | 31 ++++- drivers/gpu/msm/kgsl_ioctl.c | 2 + include/uapi/linux/msm_kgsl.h | 32 +++++ 10 files changed, 497 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index cb4108b4e1f9..18c05e930216 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -359,6 +359,13 @@ static inline void _pop_drawobj(struct adreno_context *drawctxt) drawctxt->queued--; } +static void _retire_sparseobj(struct kgsl_drawobj_sparse *sparseobj, + struct adreno_context *drawctxt) +{ + kgsl_sparse_bind(drawctxt->base.proc_priv, sparseobj); + _retire_timestamp(DRAWOBJ(sparseobj)); +} + static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj, struct adreno_context *drawctxt) { @@ -436,6 +443,8 @@ static struct kgsl_drawobj *_process_drawqueue_get_next_drawobj( return drawobj; } else if (drawobj->type == SYNCOBJ_TYPE) ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt); + else + return ERR_PTR(-EINVAL); if (ret == -EAGAIN) return ERR_PTR(-EAGAIN); @@ -670,6 +679,76 @@ static int sendcmd(struct adreno_device *adreno_dev, return 0; } + +/* + * Retires all sync objs from the sparse context + * queue and returns one of the below + * a) next sparseobj + * b) -EAGAIN for syncobj with syncpoints pending + * c) -EINVAL for unexpected drawobj + * d) NULL for no sparseobj + */ +static struct kgsl_drawobj_sparse *_get_next_sparseobj( + struct adreno_context *drawctxt) +{ + struct kgsl_drawobj *drawobj; + unsigned int i = drawctxt->drawqueue_head; + int ret = 0; + + if (drawctxt->drawqueue_head == drawctxt->drawqueue_tail) + return NULL; + + for (i = drawctxt->drawqueue_head; i != drawctxt->drawqueue_tail; + i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE)) { + + drawobj = drawctxt->drawqueue[i]; + + if (drawobj == NULL) + return NULL; + + if (drawobj->type == SYNCOBJ_TYPE) + ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt); + else if (drawobj->type == SPARSEOBJ_TYPE) + return SPARSEOBJ(drawobj); + else + return ERR_PTR(-EINVAL); + + if (ret == -EAGAIN) + return ERR_PTR(-EAGAIN); + + continue; + } + + return NULL; +} + +static int _process_drawqueue_sparse( + struct adreno_context *drawctxt) +{ + struct kgsl_drawobj_sparse *sparseobj; + int ret = 0; + unsigned int i; + + for (i = 0; i < ADRENO_CONTEXT_DRAWQUEUE_SIZE; i++) { + + spin_lock(&drawctxt->lock); + sparseobj = _get_next_sparseobj(drawctxt); + if (IS_ERR_OR_NULL(sparseobj)) { + if (IS_ERR(sparseobj)) + ret = PTR_ERR(sparseobj); + spin_unlock(&drawctxt->lock); + return ret; + } + + _pop_drawobj(drawctxt); + spin_unlock(&drawctxt->lock); + + _retire_sparseobj(sparseobj, drawctxt); + } + + return 0; +} + /** * dispatcher_context_sendcmds() - Send commands from a context to the GPU * @adreno_dev: Pointer to the adreno device struct @@ -689,6 +768,9 @@ static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev, int inflight = _drawqueue_inflight(dispatch_q); unsigned int timestamp; + if (drawctxt->base.flags & KGSL_CONTEXT_SPARSE) + return _process_drawqueue_sparse(drawctxt); + if (dispatch_q->inflight >= inflight) { spin_lock(&drawctxt->lock); _process_drawqueue_get_next_drawobj(drawctxt); @@ -1124,6 +1206,31 @@ static void _queue_drawobj(struct adreno_context *drawctxt, trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued); } +static int _queue_sparseobj(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt, struct kgsl_drawobj_sparse *sparseobj, + uint32_t *timestamp, unsigned int user_ts) +{ + struct kgsl_drawobj *drawobj = DRAWOBJ(sparseobj); + int ret; + + ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts); + if (ret) + return ret; + + /* + * See if we can fastpath this thing - if nothing is + * queued bind/unbind without queueing the context + */ + if (!drawctxt->queued) + return 1; + + drawctxt->queued_timestamp = *timestamp; + _queue_drawobj(drawctxt, drawobj); + + return 0; +} + + static int _queue_markerobj(struct adreno_device *adreno_dev, struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *markerobj, uint32_t *timestamp, unsigned int user_ts) @@ -1141,7 +1248,6 @@ static int _queue_markerobj(struct adreno_device *adreno_dev, */ if (!drawctxt->queued && kgsl_check_timestamp(drawobj->device, drawobj->context, drawctxt->queued_timestamp)) { - trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued); _retire_timestamp(drawobj); return 1; } @@ -1212,7 +1318,7 @@ static void _queue_syncobj(struct adreno_context *drawctxt, } /** - * adreno_dispactcher_queue_drawobj() - Queue a new draw object in the context + * adreno_dispactcher_queue_cmds() - Queue a new draw object in the context * @dev_priv: Pointer to the device private struct * @context: Pointer to the kgsl draw context * @drawobj: Pointer to the array of drawobj's being submitted @@ -1234,6 +1340,9 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, int ret; unsigned int i, user_ts; + if (!count) + return -EINVAL; + ret = _check_context_state(&drawctxt->base); if (ret) return ret; @@ -1283,6 +1392,20 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, _queue_syncobj(drawctxt, SYNCOBJ(drawobj[i]), timestamp); break; + case SPARSEOBJ_TYPE: + ret = _queue_sparseobj(adreno_dev, drawctxt, + SPARSEOBJ(drawobj[i]), + timestamp, user_ts); + if (ret == 1) { + spin_unlock(&drawctxt->lock); + _retire_sparseobj(SPARSEOBJ(drawobj[i]), + drawctxt); + return 0; + } else if (ret) { + spin_unlock(&drawctxt->lock); + return ret; + } + break; default: spin_unlock(&drawctxt->lock); return -EINVAL; diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 3a110ed221a8..1cbd2ef4b6b4 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -351,7 +351,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, KGSL_CONTEXT_IFH_NOP | KGSL_CONTEXT_SECURE | KGSL_CONTEXT_PREEMPT_STYLE_MASK | - KGSL_CONTEXT_NO_SNAPSHOT); + KGSL_CONTEXT_NO_SNAPSHOT | + KGSL_CONTEXT_SPARSE); /* Check for errors before trying to initialize */ diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 993f22b26294..bae3884aa277 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1439,6 +1439,17 @@ long kgsl_ioctl_device_waittimestamp_ctxtid( return result; } +static inline bool _check_context_is_sparse(struct kgsl_context *context, + uint64_t flags) +{ + if ((context->flags & KGSL_CONTEXT_SPARSE) || + (flags & KGSL_DRAWOBJ_SPARSE)) + return true; + + return false; +} + + long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -1463,6 +1474,11 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, if (context == NULL) return -EINVAL; + if (_check_context_is_sparse(context, param->flags)) { + kgsl_context_put(context); + return -EINVAL; + } + cmdobj = kgsl_drawobj_cmd_create(device, context, param->flags, CMDOBJ_TYPE); if (IS_ERR(cmdobj)) { @@ -1558,6 +1574,11 @@ long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv, if (context == NULL) return -EINVAL; + if (_check_context_is_sparse(context, param->flags)) { + kgsl_context_put(context); + return -EINVAL; + } + if (type & SYNCOBJ_TYPE) { struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create(device, context); @@ -1632,6 +1653,11 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv, if (context == NULL) return -EINVAL; + if (_check_context_is_sparse(context, param->flags)) { + kgsl_context_put(context); + return -EINVAL; + } + if (type & SYNCOBJ_TYPE) { struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create(device, context); @@ -3742,6 +3768,128 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, return ret; } +long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_gpu_sparse_command *param = data; + struct kgsl_device *device = dev_priv->device; + struct kgsl_context *context; + struct kgsl_drawobj *drawobj[2]; + struct kgsl_drawobj_sparse *sparseobj; + long result; + unsigned int i = 0; + + /* Make sure sparse and syncpoint count isn't too big */ + if (param->numsparse > KGSL_MAX_SPARSE || + param->numsyncs > KGSL_MAX_SYNCPOINTS) + return -EINVAL; + + /* Make sure there is atleast one sparse or sync */ + if (param->numsparse == 0 && param->numsyncs == 0) + return -EINVAL; + + /* Only Sparse commands are supported in this ioctl */ + if (!(param->flags & KGSL_DRAWOBJ_SPARSE) || (param->flags & + (KGSL_DRAWOBJ_SUBMIT_IB_LIST | KGSL_DRAWOBJ_MARKER + | KGSL_DRAWOBJ_SYNC))) + return -EINVAL; + + context = kgsl_context_get_owner(dev_priv, param->context_id); + if (context == NULL) + return -EINVAL; + + /* Restrict bind commands to bind context */ + if (!(context->flags & KGSL_CONTEXT_SPARSE)) { + kgsl_context_put(context); + return -EINVAL; + } + + if (param->numsyncs) { + struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create( + device, context); + if (IS_ERR(syncobj)) { + result = PTR_ERR(syncobj); + goto done; + } + + drawobj[i++] = DRAWOBJ(syncobj); + result = kgsl_drawobj_sync_add_synclist(device, syncobj, + to_user_ptr(param->synclist), + param->syncsize, param->numsyncs); + if (result) + goto done; + } + + if (param->numsparse) { + sparseobj = kgsl_drawobj_sparse_create(device, context, + param->flags); + if (IS_ERR(sparseobj)) { + result = PTR_ERR(sparseobj); + goto done; + } + + sparseobj->id = param->id; + drawobj[i++] = DRAWOBJ(sparseobj); + result = kgsl_drawobj_sparse_add_sparselist(device, sparseobj, + param->id, to_user_ptr(param->sparselist), + param->sparsesize, param->numsparse); + if (result) + goto done; + } + + result = dev_priv->device->ftbl->queue_cmds(dev_priv, context, + drawobj, i, ¶m->timestamp); + +done: + /* + * -EPROTO is a "success" error - it just tells the user that the + * context had previously faulted + */ + if (result && result != -EPROTO) + while (i--) + kgsl_drawobj_destroy(drawobj[i]); + + kgsl_context_put(context); + return result; +} + +void kgsl_sparse_bind(struct kgsl_process_private *private, + struct kgsl_drawobj_sparse *sparseobj) +{ + struct kgsl_sparseobj_node *sparse_node; + struct kgsl_mem_entry *virt_entry = NULL; + long ret = 0; + char *name; + + virt_entry = kgsl_sharedmem_find_id_flags(private, sparseobj->id, + KGSL_MEMFLAGS_SPARSE_VIRT); + if (virt_entry == NULL) + return; + + list_for_each_entry(sparse_node, &sparseobj->sparselist, node) { + if (sparse_node->obj.flags & KGSL_SPARSE_BIND) { + ret = sparse_bind_range(private, &sparse_node->obj, + virt_entry); + name = "bind"; + } else { + ret = sparse_unbind_range(&sparse_node->obj, + virt_entry); + name = "unbind"; + } + + if (ret) + KGSL_CORE_ERR("kgsl: Unable to '%s' ret %ld virt_id %d, phys_id %d, virt_offset %16.16llX, phys_offset %16.16llX, size %16.16llX, flags %16.16llX\n", + name, ret, sparse_node->virt_id, + sparse_node->obj.id, + sparse_node->obj.virtoffset, + sparse_node->obj.physoffset, + sparse_node->obj.size, sparse_node->obj.flags); + } + + kgsl_mem_entry_put(virt_entry); +} +EXPORT_SYMBOL(kgsl_sparse_bind); + long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -4656,7 +4804,7 @@ static void kgsl_core_exit(void) kgsl_driver.class = NULL; } - kgsl_drawobj_exit(); + kgsl_drawobjs_cache_exit(); kgsl_memfree_exit(); unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); @@ -4732,7 +4880,7 @@ static int __init kgsl_core_init(void) kgsl_events_init(); - result = kgsl_drawobj_init(); + result = kgsl_drawobjs_cache_init(); if (result) goto err; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index fbf9197b6d1b..2a9ac899725c 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -100,6 +100,7 @@ static inline void KGSL_STATS_ADD(uint64_t size, atomic_long_t *stat, #define KGSL_MAX_NUMIBS 100000 #define KGSL_MAX_SYNCPOINTS 32 +#define KGSL_MAX_SPARSE 1000 struct kgsl_device; struct kgsl_context; @@ -432,6 +433,8 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); long kgsl_ioctl_sparse_unbind(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); +long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); void kgsl_mem_entry_destroy(struct kref *kref); diff --git a/drivers/gpu/msm/kgsl_compat.c b/drivers/gpu/msm/kgsl_compat.c index 028a9566fa14..6b8d8d34a988 100644 --- a/drivers/gpu/msm/kgsl_compat.c +++ b/drivers/gpu/msm/kgsl_compat.c @@ -382,6 +382,8 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = { kgsl_ioctl_sparse_virt_free), KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND, kgsl_ioctl_sparse_bind), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND, + kgsl_ioctl_gpu_sparse_command), }; long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 7d68c23ad5b7..cb7ffd51460a 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -203,6 +203,18 @@ struct kgsl_memobj_node { unsigned long priv; }; +/** + * struct kgsl_sparseobj_node - Sparse object descriptor + * @node: Local list node for the sparse cmdbatch + * @virt_id: Virtual ID to bind/unbind + * @obj: struct kgsl_sparse_binding_object + */ +struct kgsl_sparseobj_node { + struct list_head node; + unsigned int virt_id; + struct kgsl_sparse_binding_object obj; +}; + struct kgsl_device { struct device *dev; const char *name; @@ -639,6 +651,9 @@ long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd, long kgsl_ioctl_copy_out(unsigned int kernel_cmd, unsigned int user_cmd, unsigned long, unsigned char *ptr); +void kgsl_sparse_bind(struct kgsl_process_private *private, + struct kgsl_drawobj_sparse *sparse); + /** * kgsl_context_put() - Release context reference count * @context: Pointer to the KGSL context to be released diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 7840daa6a3e2..f8f0e7ccb0d3 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -37,10 +37,12 @@ #include "kgsl_compat.h" /* - * Define an kmem cache for the memobj structures since we allocate and free - * them so frequently + * Define an kmem cache for the memobj & sparseobj structures since we + * allocate and free them so frequently */ static struct kmem_cache *memobjs_cache; +static struct kmem_cache *sparseobjs_cache; + static void drawobj_destroy_object(struct kref *kref) { @@ -60,6 +62,9 @@ static void drawobj_destroy_object(struct kref *kref) case MARKEROBJ_TYPE: kfree(CMDOBJ(drawobj)); break; + case SPARSEOBJ_TYPE: + kfree(SPARSEOBJ(drawobj)); + break; } } @@ -211,6 +216,18 @@ static inline void memobj_list_free(struct list_head *list) } } +static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj) +{ + struct kgsl_sparseobj_node *mem, *tmpmem; + struct list_head *list = &SPARSEOBJ(drawobj)->sparselist; + + /* Free the sparse mem here */ + list_for_each_entry_safe(mem, tmpmem, list, node) { + list_del_init(&mem->node); + kmem_cache_free(sparseobjs_cache, mem); + } +} + static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); @@ -297,6 +314,8 @@ void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj) drawobj_destroy_sync(drawobj); else if (drawobj->type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) drawobj_destroy_cmd(drawobj); + else if (drawobj->type == SPARSEOBJ_TYPE) + drawobj_destroy_sparse(drawobj); else return; @@ -610,16 +629,26 @@ int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device, return 0; } -static inline int drawobj_init(struct kgsl_device *device, - struct kgsl_context *context, struct kgsl_drawobj *drawobj, +static void *_drawobj_create(struct kgsl_device *device, + struct kgsl_context *context, unsigned int size, unsigned int type) { + void *obj = kzalloc(size, GFP_KERNEL); + struct kgsl_drawobj *drawobj; + + if (obj == NULL) + return ERR_PTR(-ENOMEM); + /* * Increase the reference count on the context so it doesn't disappear * during the lifetime of this object */ - if (!_kgsl_context_get(context)) - return -ENOENT; + if (!_kgsl_context_get(context)) { + kfree(obj); + return ERR_PTR(-ENOENT); + } + + drawobj = obj; kref_init(&drawobj->refcount); @@ -627,7 +656,28 @@ static inline int drawobj_init(struct kgsl_device *device, drawobj->context = context; drawobj->type = type; - return 0; + return obj; +} + +/** + * kgsl_drawobj_sparse_create() - Create a new sparse obj structure + * @device: Pointer to a KGSL device struct + * @context: Pointer to a KGSL context struct + * @flags: Flags for the sparse obj + * + * Allocate an new kgsl_drawobj_sparse structure + */ +struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create( + struct kgsl_device *device, + struct kgsl_context *context, unsigned int flags) +{ + struct kgsl_drawobj_sparse *sparseobj = _drawobj_create(device, + context, sizeof(*sparseobj), SPARSEOBJ_TYPE); + + if (!IS_ERR(sparseobj)) + INIT_LIST_HEAD(&sparseobj->sparselist); + + return sparseobj; } /** @@ -641,18 +691,13 @@ static inline int drawobj_init(struct kgsl_device *device, struct kgsl_drawobj_sync *kgsl_drawobj_sync_create(struct kgsl_device *device, struct kgsl_context *context) { - struct kgsl_drawobj_sync *syncobj = kzalloc(sizeof(*syncobj), - GFP_KERNEL); - if (syncobj == NULL) - return ERR_PTR(-ENOMEM); - - if (drawobj_init(device, context, DRAWOBJ(syncobj), SYNCOBJ_TYPE)) { - kfree(syncobj); - return ERR_PTR(-ENOENT); - } + struct kgsl_drawobj_sync *syncobj = _drawobj_create(device, + context, sizeof(*syncobj), SYNCOBJ_TYPE); /* Add a timer to help debug sync deadlocks */ - setup_timer(&syncobj->timer, syncobj_timer, (unsigned long) syncobj); + if (!IS_ERR(syncobj)) + setup_timer(&syncobj->timer, syncobj_timer, + (unsigned long) syncobj); return syncobj; } @@ -671,27 +716,13 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, struct kgsl_context *context, unsigned int flags, unsigned int type) { - struct kgsl_drawobj_cmd *cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL); - struct kgsl_drawobj *drawobj; + struct kgsl_drawobj_cmd *cmdobj = _drawobj_create(device, + context, sizeof(*cmdobj), + (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE))); - if (cmdobj == NULL) - return ERR_PTR(-ENOMEM); - - type &= CMDOBJ_TYPE | MARKEROBJ_TYPE; - if (type == 0) { - kfree(cmdobj); - return ERR_PTR(-EINVAL); - } - - drawobj = DRAWOBJ(cmdobj); - - if (drawobj_init(device, context, drawobj, type)) { - kfree(cmdobj); - return ERR_PTR(-ENOENT); - } - - /* sanitize our flags for drawobj's */ - drawobj->flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH + if (!IS_ERR(cmdobj)) { + /* sanitize our flags for drawobj's */ + cmdobj->base.flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH | KGSL_DRAWOBJ_MARKER | KGSL_DRAWOBJ_END_OF_FRAME | KGSL_DRAWOBJ_PWR_CONSTRAINT @@ -699,8 +730,9 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, | KGSL_DRAWOBJ_PROFILING | KGSL_DRAWOBJ_PROFILING_KTIME); - INIT_LIST_HEAD(&cmdobj->cmdlist); - INIT_LIST_HEAD(&cmdobj->memlist); + INIT_LIST_HEAD(&cmdobj->cmdlist); + INIT_LIST_HEAD(&cmdobj->memlist); + } return cmdobj; } @@ -864,7 +896,7 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, return 0; } -static int drawobj_add_object(struct list_head *head, +static int kgsl_drawobj_add_memobject(struct list_head *head, struct kgsl_command_object *obj) { struct kgsl_memobj_node *mem; @@ -884,6 +916,62 @@ static int drawobj_add_object(struct list_head *head, return 0; } +static int kgsl_drawobj_add_sparseobject(struct list_head *head, + struct kgsl_sparse_binding_object *obj, unsigned int virt_id) +{ + struct kgsl_sparseobj_node *mem; + + mem = kmem_cache_alloc(sparseobjs_cache, GFP_KERNEL); + if (mem == NULL) + return -ENOMEM; + + mem->virt_id = virt_id; + mem->obj.id = obj->id; + mem->obj.virtoffset = obj->virtoffset; + mem->obj.physoffset = obj->physoffset; + mem->obj.size = obj->size; + mem->obj.flags = obj->flags; + + list_add_tail(&mem->node, head); + return 0; +} + +int kgsl_drawobj_sparse_add_sparselist(struct kgsl_device *device, + struct kgsl_drawobj_sparse *sparseobj, unsigned int id, + void __user *ptr, unsigned int size, unsigned int count) +{ + struct kgsl_sparse_binding_object obj; + int i, ret = 0; + + ret = _verify_input_list(count, ptr, size); + if (ret <= 0) + return ret; + + for (i = 0; i < count; i++) { + memset(&obj, 0, sizeof(obj)); + + ret = _copy_from_user(&obj, ptr, sizeof(obj), size); + if (ret) + return ret; + + if (!(obj.flags & (KGSL_SPARSE_BIND | KGSL_SPARSE_UNBIND))) + return -EINVAL; + + ret = kgsl_drawobj_add_sparseobject(&sparseobj->sparselist, + &obj, id); + if (ret) + return ret; + + ptr += sizeof(obj); + } + + sparseobj->size = size; + sparseobj->count = count; + + return 0; +} + + #define CMDLIST_FLAGS \ (KGSL_CMDLIST_IB | \ KGSL_CMDLIST_CTXTSWITCH_PREAMBLE | \ @@ -922,7 +1010,7 @@ int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, return -EINVAL; } - ret = drawobj_add_object(&cmdobj->cmdlist, &obj); + ret = kgsl_drawobj_add_memobject(&cmdobj->cmdlist, &obj); if (ret) return ret; @@ -967,7 +1055,8 @@ int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, add_profiling_buffer(device, cmdobj, obj.gpuaddr, obj.size, obj.id, obj.offset); else { - ret = drawobj_add_object(&cmdobj->memlist, &obj); + ret = kgsl_drawobj_add_memobject(&cmdobj->memlist, + &obj); if (ret) return ret; } @@ -1018,19 +1107,19 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, return 0; } -void kgsl_drawobj_exit(void) +void kgsl_drawobjs_cache_exit(void) { - if (memobjs_cache != NULL) - kmem_cache_destroy(memobjs_cache); + kmem_cache_destroy(memobjs_cache); + kmem_cache_destroy(sparseobjs_cache); } -int kgsl_drawobj_init(void) +int kgsl_drawobjs_cache_init(void) { memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0); - if (memobjs_cache == NULL) { - KGSL_CORE_ERR("failed to create memobjs_cache"); + sparseobjs_cache = KMEM_CACHE(kgsl_sparseobj_node, 0); + + if (!memobjs_cache || !sparseobjs_cache) return -ENOMEM; - } return 0; } diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h index 89ed944c539a..fd9d2bc93f41 100644 --- a/drivers/gpu/msm/kgsl_drawobj.h +++ b/drivers/gpu/msm/kgsl_drawobj.h @@ -18,10 +18,13 @@ container_of(obj, struct kgsl_drawobj_sync, base) #define CMDOBJ(obj) \ container_of(obj, struct kgsl_drawobj_cmd, base) +#define SPARSEOBJ(obj) \ + container_of(obj, struct kgsl_drawobj_sparse, base) #define CMDOBJ_TYPE BIT(0) #define MARKEROBJ_TYPE BIT(1) #define SYNCOBJ_TYPE BIT(2) +#define SPARSEOBJ_TYPE BIT(3) /** * struct kgsl_drawobj - KGSL drawobj descriptor @@ -45,7 +48,7 @@ struct kgsl_drawobj { * struct kgsl_drawobj_cmd - KGSL command obj, This covers marker * cmds also since markers are special form of cmds that do not * need their cmds to be executed. - * @base: Base kgsl_drawobj + * @base: Base kgsl_drawobj, this needs to be the first entry * @priv: Internal flags * @global_ts: The ringbuffer timestamp corresponding to this * command obj @@ -123,6 +126,22 @@ struct kgsl_drawobj_sync_event { struct kgsl_device *device; }; +/** + * struct kgsl_drawobj_sparse - KGSl sparse obj descriptor + * @base: Base kgsl_obj, this needs to be the first entry + * @id: virtual id of the bind/unbind + * @sparselist: list of binds/unbinds + * @size: Size of kgsl_sparse_bind_object + * @count: Number of elements in list + */ +struct kgsl_drawobj_sparse { + struct kgsl_drawobj base; + unsigned int id; + struct list_head sparselist; + unsigned int size; + unsigned int count; +}; + #define KGSL_DRAWOBJ_FLAGS \ { KGSL_DRAWOBJ_MARKER, "MARKER" }, \ { KGSL_DRAWOBJ_CTX_SWITCH, "CTX_SWITCH" }, \ @@ -172,9 +191,15 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, struct kgsl_drawobj_sync *syncobj, struct kgsl_cmd_syncpoint *sync); +struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create( + struct kgsl_device *device, + struct kgsl_context *context, unsigned int flags); +int kgsl_drawobj_sparse_add_sparselist(struct kgsl_device *device, + struct kgsl_drawobj_sparse *sparseobj, unsigned int id, + void __user *ptr, unsigned int size, unsigned int count); -int kgsl_drawobj_init(void); -void kgsl_drawobj_exit(void); +int kgsl_drawobjs_cache_init(void); +void kgsl_drawobjs_cache_exit(void); void kgsl_dump_syncpoints(struct kgsl_device *device, struct kgsl_drawobj_sync *syncobj); diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c index 894e6a4a146b..f7876335d95e 100644 --- a/drivers/gpu/msm/kgsl_ioctl.c +++ b/drivers/gpu/msm/kgsl_ioctl.c @@ -100,6 +100,8 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = { kgsl_ioctl_sparse_virt_free), KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND, kgsl_ioctl_sparse_bind), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND, + kgsl_ioctl_gpu_sparse_command), }; long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd, diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index aac11dbe5984..71fdf6d6e9e5 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -50,6 +50,7 @@ #define KGSL_CONTEXT_IFH_NOP 0x00010000 #define KGSL_CONTEXT_SECURE 0x00020000 #define KGSL_CONTEXT_NO_SNAPSHOT 0x00040000 +#define KGSL_CONTEXT_SPARSE 0x00080000 #define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000 #define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25 @@ -89,6 +90,7 @@ #define KGSL_CMDBATCH_END_OF_FRAME KGSL_CONTEXT_END_OF_FRAME /* 0x100 */ #define KGSL_CMDBATCH_SYNC KGSL_CONTEXT_SYNC /* 0x400 */ #define KGSL_CMDBATCH_PWR_CONSTRAINT KGSL_CONTEXT_PWR_CONSTRAINT /* 0x800 */ +#define KGSL_CMDBATCH_SPARSE 0x1000 /* 0x1000 */ /* * Reserve bits [16:19] and bits [28:31] for possible bits shared between @@ -1556,4 +1558,34 @@ struct kgsl_sparse_bind { #define IOCTL_KGSL_SPARSE_BIND \ _IOW(KGSL_IOC_TYPE, 0x54, struct kgsl_sparse_bind) +/** + * struct kgsl_gpu_sparse_command - Argument for + * IOCTL_KGSL_GPU_SPARSE_COMMAND + * @flags: Current flags for the object + * @sparselist: List of kgsl_sparse_binding_object to bind/unbind + * @synclist: List of kgsl_command_syncpoints + * @sparsesize: Size of kgsl_sparse_binding_object + * @numsparse: Number of elements in list + * @sync_size: Size of kgsl_command_syncpoint structure + * @numsyncs: Number of kgsl_command_syncpoints in syncpoint list + * @context_id: Context ID submitting the kgsl_gpu_command + * @timestamp: Timestamp for the submitted commands + * @id: Virtual ID to bind/unbind + */ +struct kgsl_gpu_sparse_command { + uint64_t flags; + uint64_t __user sparselist; + uint64_t __user synclist; + unsigned int sparsesize; + unsigned int numsparse; + unsigned int syncsize; + unsigned int numsyncs; + unsigned int context_id; + unsigned int timestamp; + unsigned int id; +}; + +#define IOCTL_KGSL_GPU_SPARSE_COMMAND \ + _IOWR(KGSL_IOC_TYPE, 0x55, struct kgsl_gpu_sparse_command) + #endif /* _UAPI_MSM_KGSL_H */ From 02871aa94733cfe29d02bb36788b123a8c595535 Mon Sep 17 00:00:00 2001 From: Puja Gupta Date: Thu, 8 Dec 2016 16:59:29 -0800 Subject: [PATCH 3/6] ARM: dts: msm: Move boot_rom_ahb_clk to proxy voted for msm8998 Proxy vote for gcc_boot_rom_ahb_clk for modem pil on msm8998 instead of keeping the vote until the modem was shutdown. Change-Id: Ib32d40351179a687eca38228c4503e4a9a88c28d Signed-off-by: Puja Gupta --- arch/arm/boot/dts/qcom/msm8998.dtsi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index ef488bbe0010..39348180084a 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -2036,10 +2036,9 @@ clock-names = "xo", "iface_clk", "bus_clk", "mem_clk", "gpll0_mss_clk", "snoc_axi_clk", "mnoc_axi_clk", "qdss_clk"; - qcom,proxy-clock-names = "xo", "qdss_clk"; - qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk", - "gpll0_mss_clk", "snoc_axi_clk", - "mnoc_axi_clk"; + qcom,proxy-clock-names = "xo", "qdss_clk", "mem_clk"; + qcom,active-clock-names = "iface_clk", "bus_clk", + "gpll0_mss_clk", "snoc_axi_clk", "mnoc_axi_clk"; interrupts = <0 448 1>; vdd_cx-supply = <&pm8998_s1_level>; From 19740f9d535bdc41785b46dba450c1aa3ee69601 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 13 Dec 2016 15:39:20 +0530 Subject: [PATCH 4/6] soc: qcom: pil-q6v5: Update the reset sequence for qdspv62.1.2/1.5 Update the reset sequence to read each write while enabling QDSP6 memory bank one at a time. This will make sure whether write is complete or not. Also add logs during Mss shutdown, It will help to debug Mss restart and shutdown case. Change-Id: I9f2cb058a7e59b573fc64662ee7b5bff49b18ea7 Signed-off-by: Gaurav Kohli --- drivers/soc/qcom/pil-msa.c | 1 + drivers/soc/qcom/pil-q6v5.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 3c3ae693f615..01fc8bff1eca 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -278,6 +278,7 @@ int pil_mss_shutdown(struct pil_desc *pil) struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc); int ret = 0; + dev_info(pil->dev, "MSS is shutting down\n"); if (drv->axi_halt_base) { pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE); diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c index a1cd3b1eeaff..6bafa46a5c0b 100644 --- a/drivers/soc/qcom/pil-q6v5.c +++ b/drivers/soc/qcom/pil-q6v5.c @@ -512,6 +512,8 @@ static int __pil_q6v55_reset(struct pil_desc *pil) val |= BIT(i); writel_relaxed(val, drv->reg_base + QDSP6V6SS_MEM_PWR_CTL); + val = readl_relaxed(drv->reg_base + + QDSP6V6SS_MEM_PWR_CTL); /* * Wait for 1us for both memory peripheral and * data array to turn on. From f03bf11b398fc940c2133b55985aa92525ba327c Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 13 Dec 2016 16:58:54 +0530 Subject: [PATCH 5/6] ARM: dts: msm: Remove write of acc register for MSMFalcon/Triton/8998 Remove the write of acc strap register by default value during Q6 reset as per Hardware Programming Guide. Change-Id: Id5b8aaae0783893290e95626b394841a7d3808a3 Signed-off-by: Gaurav Kohli --- arch/arm/boot/dts/qcom/msm8998.dtsi | 1 - arch/arm/boot/dts/qcom/msmfalcon.dtsi | 1 - arch/arm/boot/dts/qcom/msmtriton.dtsi | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index c265eafcdd30..7e6fad5d8be5 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -2051,7 +2051,6 @@ qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,ssctl-instance-id = <0x12>; - qcom,override-acc; qcom,qdsp6v62-1-2; status = "ok"; memory-region = <&modem_mem>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index de0c11147c45..9ce04f8e9ac2 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -1372,7 +1372,6 @@ qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,ssctl-instance-id = <0x12>; - qcom,override-acc; qcom,qdsp6v62-1-5; memory-region = <&modem_fw_mem>; qcom,mem-protect-id = <0xF>; diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi index dfa592c16643..690e9e8870fd 100644 --- a/arch/arm/boot/dts/qcom/msmtriton.dtsi +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -902,7 +902,6 @@ qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,ssctl-instance-id = <0x12>; - qcom,override-acc; qcom,qdsp6v62-1-5; memory-region = <&modem_fw_mem>; qcom,mem-protect-id = <0xF>; From 6a21dcc9bf61ffbb511b7d58b2744ee1b8cfddef Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Fri, 18 Nov 2016 14:20:06 +0530 Subject: [PATCH 6/6] clk: qcom: add common clock framework support for MDSS PLL Model and configure MDSS DSI PLL using upstream clock framework APIs. Add changes to define and register vco, divider, mux clcoks as per common clock infrastructure. Change-Id: Idc51070e2bb36d1a757d2714d2875a99901321a7 Signed-off-by: Sandeep Panda --- drivers/clk/qcom/Kconfig | 2 + drivers/clk/qcom/Makefile | 2 + drivers/clk/qcom/mdss/Kconfig | 3 +- drivers/clk/qcom/mdss/Makefile | 9 +- ...l-8996-util.c => mdss-dsi-pll-14nm-util.c} | 344 +++++----- drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c | 614 ++++++++++++++++++ ...dss-dsi-pll-8996.h => mdss-dsi-pll-14nm.h} | 52 +- drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c | 566 ---------------- drivers/clk/qcom/mdss/mdss-dsi-pll.h | 65 +- drivers/clk/qcom/mdss/mdss-pll-util.c | 1 - drivers/clk/qcom/mdss/mdss-pll.c | 25 +- drivers/clk/qcom/mdss/mdss-pll.h | 27 +- include/dt-bindings/clock/mdss-pll-clk.h | 42 ++ 13 files changed, 895 insertions(+), 857 deletions(-) rename drivers/clk/qcom/mdss/{mdss-dsi-pll-8996-util.c => mdss-dsi-pll-14nm-util.c} (84%) create mode 100644 drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c rename drivers/clk/qcom/mdss/{mdss-dsi-pll-8996.h => mdss-dsi-pll-14nm.h} (81%) delete mode 100644 drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c create mode 100644 include/dt-bindings/clock/mdss-pll-clk.h diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 36ab5cf68740..2148dad33e87 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -218,3 +218,5 @@ config QCOM_A53 Support for the A53 clock controller on MSM devices. Say Y if you want to support CPU frequency scaling on devices such as MSM8916. + +source "drivers/clk/qcom/mdss/Kconfig" diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 595254f69db1..176dc3103cdb 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -37,3 +37,5 @@ obj-$(CONFIG_KRAITCC) += krait-cc.o obj-$(CONFIG_QCOM_A53) += clk-a53.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o + +obj-y += mdss/ diff --git a/drivers/clk/qcom/mdss/Kconfig b/drivers/clk/qcom/mdss/Kconfig index 229780e45bb8..7213e375f1ef 100644 --- a/drivers/clk/qcom/mdss/Kconfig +++ b/drivers/clk/qcom/mdss/Kconfig @@ -1,5 +1,6 @@ -config MSM_MDSS_PLL +config QCOM_MDSS_PLL bool "MDSS pll programming" + depends on COMMON_CLK_QCOM ---help--- It provides support for DSI, eDP and HDMI interface pll programming on MDSS hardware. It also handles the pll specific resources and turn them on/off when diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile index 75891dc10dda..6a0a1de1e942 100644 --- a/drivers/clk/qcom/mdss/Makefile +++ b/drivers/clk/qcom/mdss/Makefile @@ -1,5 +1,4 @@ -obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o -obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o -obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o -obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o -obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll-util.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm-util.o diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c similarity index 84% rename from drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c rename to drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c index 6d2694d5a2e9..a4044955c68f 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c @@ -16,38 +16,19 @@ #include #include #include -#include #include "mdss-pll.h" #include "mdss-dsi-pll.h" -#include "mdss-dsi-pll-8996.h" +#include "mdss-dsi-pll-14nm.h" #define DSI_PLL_POLL_MAX_READS 15 #define DSI_PLL_POLL_TIMEOUT_US 1000 #define MSM8996_DSI_PLL_REVISION_2 2 +#define VCO_REF_CLK_RATE 19200000 + #define CEIL(x, y) (((x) + ((y)-1)) / (y)) -int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel) -{ - return 0; -} - -int get_mdss_byte_mux_sel_8996(struct mux_clk *clk) -{ - return 0; -} - -int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel) -{ - return 0; -} - -int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk) -{ - return 0; -} - static int mdss_pll_read_stored_trim_codes( struct mdss_pll_resources *dsi_pll_res, s64 vco_clk_rate) { @@ -94,9 +75,9 @@ end_read: return rc; } -int post_n1_div_set_div(struct div_clk *clk, int div) +int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div) { - struct mdss_pll_resources *pll = clk->priv; + struct mdss_pll_resources *pll = context; struct dsi_pll_db *pdb; struct dsi_pll_output *pout; int rc; @@ -108,6 +89,9 @@ int post_n1_div_set_div(struct div_clk *clk, int div) return rc; } + /* in common clock framework the divider value provided is one less */ + div++; + pdb = (struct dsi_pll_db *)pll->priv; pout = &pdb->out; @@ -120,8 +104,6 @@ int post_n1_div_set_div(struct div_clk *clk, int div) * support bit_clk above 86.67Mhz */ - /* this is for vco/bit clock */ - pout->pll_postdiv = 1; /* fixed, divided by 1 */ pout->pll_n1div = div; n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); @@ -138,11 +120,15 @@ int post_n1_div_set_div(struct div_clk *clk, int div) return 0; } -int post_n1_div_get_div(struct div_clk *clk) +int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div) { - u32 div; int rc; - struct mdss_pll_resources *pll = clk->priv; + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; if (is_gdsc_disabled(pll)) return 0; @@ -159,20 +145,33 @@ int post_n1_div_get_div(struct div_clk *clk) * fot the time being, assume postdiv = 1 */ - div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); - div &= 0xF; - pr_debug("n1 div = %d\n", div); + *div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + *div &= 0xF; + + /* + * initialize n1div here, it will get updated when + * corresponding set_div is called. + */ + pout->pll_n1div = *div; + + /* common clock framework will add one to the divider value sent */ + if (*div == 0) + *div = 1; /* value of zero means div is 2 as per SWI */ + else + *div -= 1; + + pr_debug("post n1 get div = %d\n", *div); mdss_pll_resource_enable(pll, false); - return div; + return rc; } -int n2_div_set_div(struct div_clk *clk, int div) +int n2_div_set_div(void *context, unsigned int reg, unsigned int div) { int rc; u32 n2div; - struct mdss_pll_resources *pll = clk->priv; + struct mdss_pll_resources *pll = context; struct dsi_pll_db *pdb; struct dsi_pll_output *pout; struct mdss_pll_resources *slave; @@ -183,6 +182,12 @@ int n2_div_set_div(struct div_clk *clk, int div) return rc; } + /* + * in common clock framework the actual divider value + * provided is one less. + */ + div++; + pdb = (struct dsi_pll_db *)pll->priv; pout = &pdb->out; @@ -208,9 +213,9 @@ int n2_div_set_div(struct div_clk *clk, int div) return rc; } -int shadow_n2_div_set_div(struct div_clk *clk, int div) +int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div) { - struct mdss_pll_resources *pll = clk->priv; + struct mdss_pll_resources *pll = context; struct dsi_pll_db *pdb; struct dsi_pll_output *pout; u32 data; @@ -218,6 +223,12 @@ int shadow_n2_div_set_div(struct div_clk *clk, int div) pdb = pll->priv; pout = &pdb->out; + /* + * in common clock framework the actual divider value + * provided is one less. + */ + div++; + pout->pll_n2div = div; data = (pout->pll_n1div | (pout->pll_n2div << 4)); @@ -228,15 +239,20 @@ int shadow_n2_div_set_div(struct div_clk *clk, int div) return 0; } -int n2_div_get_div(struct div_clk *clk) +int n2_div_get_div(void *context, unsigned int reg, unsigned int *div) { int rc; u32 n2div; - struct mdss_pll_resources *pll = clk->priv; + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; if (is_gdsc_disabled(pll)) return 0; + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("Failed to enable mdss dsi pll=%d resources\n", @@ -247,15 +263,27 @@ int n2_div_get_div(struct div_clk *clk) n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); n2div >>= 4; n2div &= 0x0f; - + /* + * initialize n2div here, it will get updated when + * corresponding set_div is called. + */ + pout->pll_n2div = n2div; mdss_pll_resource_enable(pll, false); - pr_debug("ndx=%d div=%d\n", pll->index, n2div); + *div = n2div; - return n2div; + /* common clock framework will add one to the divider value sent */ + if (*div == 0) + *div = 1; /* value of zero means div is 2 as per SWI */ + else + *div -= 1; + + pr_debug("ndx=%d div=%d\n", pll->index, *div); + + return rc; } -static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll) +static bool pll_is_pll_locked_14nm(struct mdss_pll_resources *pll) { u32 status; bool pll_locked; @@ -286,7 +314,7 @@ static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll) return pll_locked; } -static void dsi_pll_start_8996(void __iomem *pll_base) +static void dsi_pll_start_14nm(void __iomem *pll_base) { pr_debug("start PLL at base=%p\n", pll_base); @@ -294,14 +322,14 @@ static void dsi_pll_start_8996(void __iomem *pll_base) MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1); } -static void dsi_pll_stop_8996(void __iomem *pll_base) +static void dsi_pll_stop_14nm(void __iomem *pll_base) { pr_debug("stop PLL at base=%p\n", pll_base); MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0); } -int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll) +int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll) { int rc = 0; @@ -310,14 +338,14 @@ int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll) return -EINVAL; } - dsi_pll_start_8996(pll->pll_base); + dsi_pll_start_14nm(pll->pll_base); /* * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL - * enabled at mdss_dsi_8996_phy_config() + * enabled at mdss_dsi_14nm_phy_config() */ - if (!pll_is_pll_locked_8996(pll)) { + if (!pll_is_pll_locked_14nm(pll)) { pr_err("DSI PLL ndx=%d lock failed\n", pll->index); rc = -EINVAL; goto init_lock_err; @@ -329,10 +357,10 @@ init_lock_err: return rc; } -static int dsi_pll_enable(struct clk *c) +static int dsi_pll_enable(struct clk_hw *hw) { int i, rc = 0; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; /* Try all enable sequences until one succeeds */ @@ -352,9 +380,9 @@ static int dsi_pll_enable(struct clk *c) return rc; } -static void dsi_pll_disable(struct clk *c) +static void dsi_pll_disable(struct clk_hw *hw) { - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; struct mdss_pll_resources *slave; @@ -367,7 +395,7 @@ static void dsi_pll_disable(struct clk *c) pll->handoff_resources = false; slave = pll->slave; - dsi_pll_stop_8996(pll->pll_base); + dsi_pll_stop_14nm(pll->pll_base); mdss_pll_resource_enable(pll, false); @@ -376,7 +404,7 @@ static void dsi_pll_disable(struct clk *c) pr_debug("DSI PLL ndx=%d Disabled\n", pll->index); } -static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll, +static void mdss_dsi_pll_14nm_input_init(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { pdb->in.fref = 19200000; /* 19.2 Mhz*/ @@ -414,9 +442,10 @@ static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll, pdb->in.pll_iptat_trim = 7; pdb->in.pll_c3ctrl = 2; /* 2 */ pdb->in.pll_r3ctrl = 1; /* 1 */ + pdb->out.pll_postdiv = 1; } -static void pll_8996_ssc_calc(struct mdss_pll_resources *pll, +static void pll_14nm_ssc_calc(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { u32 period, ssc_period; @@ -457,7 +486,7 @@ static void pll_8996_ssc_calc(struct mdss_pll_resources *pll, pdb->out.ssc_step_size = step_size; } -static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll, +static void pll_14nm_dec_frac_calc(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { struct dsi_pll_input *pin = &pdb->in; @@ -501,7 +530,7 @@ static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll, pout->cmn_ldo_cntrl = 0x1c; } -static u32 pll_8996_kvco_slop(u32 vrate) +static u32 pll_14nm_kvco_slop(u32 vrate) { u32 slop = 0; @@ -515,7 +544,7 @@ static u32 pll_8996_kvco_slop(u32 vrate) return slop; } -static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb, +static void pll_14nm_calc_vco_count(struct dsi_pll_db *pdb, s64 vco_clk_rate, s64 fref) { struct dsi_pll_input *pin = &pdb->in; @@ -540,7 +569,7 @@ static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb, data -= 1; pout->pll_kvco_div_ref = data; - cnt = pll_8996_kvco_slop(vco_clk_rate); + cnt = pll_14nm_kvco_slop(vco_clk_rate); cnt *= 2; do_div(cnt, 100); cnt *= pin->kvco_measure_time; @@ -659,7 +688,7 @@ static void pll_db_commit_common(struct mdss_pll_resources *pll, MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data); } -static void pll_db_commit_8996(struct mdss_pll_resources *pll, +static void pll_db_commit_14nm(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { void __iomem *pll_base = pll->pll_base; @@ -753,7 +782,7 @@ static void pll_db_commit_8996(struct mdss_pll_resources *pll, /* * pll_source_finding: * Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured - * at mdss_dsi_8996_phy_config() + * at mdss_dsi_14nm_phy_config() */ static int pll_source_finding(struct mdss_pll_resources *pll) { @@ -820,10 +849,59 @@ static void pll_source_setup(struct mdss_pll_resources *pll) other->slave = pll; } -int pll_vco_set_rate_8996(struct clk *c, unsigned long rate) +unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + u64 vco_rate, multiplier = BIT(20); + s32 div_frac_start; + u32 dec_start; + u64 ref_clk = vco->ref_clk_rate; + int rc; + + if (pll->vco_current_rate) + return (unsigned long)pll->vco_current_rate; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return rc; + } + + dec_start = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DEC_START); + dec_start &= 0x0ff; + pr_debug("dec_start = 0x%x\n", dec_start); + + div_frac_start = (MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16; + div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8; + div_frac_start |= MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff; + pr_debug("div_frac_start = 0x%x\n", div_frac_start); + + vco_rate = ref_clk * dec_start; + vco_rate += ((ref_clk * div_frac_start) / multiplier); + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(pll, false); + + pr_debug("%s: returning vco rate as %lu\n", + __func__, (unsigned long)vco_rate); + return (unsigned long)vco_rate; +} + +int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { int rc; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; struct mdss_pll_resources *slave; struct dsi_pll_db *pdb; @@ -848,30 +926,30 @@ int pll_vco_set_rate_8996(struct clk *c, unsigned long rate) pll->vco_current_rate = rate; pll->vco_ref_clk_rate = vco->ref_clk_rate; - mdss_dsi_pll_8996_input_init(pll, pdb); + mdss_dsi_pll_14nm_input_init(pll, pdb); - pll_8996_dec_frac_calc(pll, pdb); + pll_14nm_dec_frac_calc(pll, pdb); if (pll->ssc_en) - pll_8996_ssc_calc(pll, pdb); + pll_14nm_ssc_calc(pll, pdb); - pll_8996_calc_vco_count(pdb, pll->vco_current_rate, + pll_14nm_calc_vco_count(pdb, pll->vco_current_rate, pll->vco_ref_clk_rate); /* commit slave if split display is enabled */ slave = pll->slave; if (slave) - pll_db_commit_8996(slave, pdb); + pll_db_commit_14nm(slave, pdb); /* commit master itself */ - pll_db_commit_8996(pll, pdb); + pll_db_commit_14nm(pll, pdb); mdss_pll_resource_enable(pll, false); return rc; } -static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll, +static void shadow_pll_dynamic_refresh_14nm(struct mdss_pll_resources *pll, struct dsi_pll_db *pdb) { struct dsi_pll_output *pout = &pdb->out; @@ -931,10 +1009,11 @@ static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll, wmb(); } -int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate) +int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { int rc; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; struct dsi_pll_db *pdb; s64 vco_clk_rate = (s64)rate; @@ -968,14 +1047,14 @@ int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate) pll->vco_current_rate = rate; pll->vco_ref_clk_rate = vco->ref_clk_rate; - mdss_dsi_pll_8996_input_init(pll, pdb); + mdss_dsi_pll_14nm_input_init(pll, pdb); - pll_8996_dec_frac_calc(pll, pdb); + pll_14nm_dec_frac_calc(pll, pdb); - pll_8996_calc_vco_count(pdb, pll->vco_current_rate, + pll_14nm_calc_vco_count(pdb, pll->vco_current_rate, pll->vco_ref_clk_rate); - shadow_pll_dynamic_refresh_8996(pll, pdb); + shadow_pll_dynamic_refresh_14nm(pll, pdb); rc = mdss_pll_resource_enable(pll, false); if (rc) { @@ -986,53 +1065,12 @@ int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate) return rc; } -unsigned long pll_vco_get_rate_8996(struct clk *c) -{ - u64 vco_rate, multiplier = BIT(20); - s32 div_frac_start; - u32 dec_start; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); - u64 ref_clk = vco->ref_clk_rate; - int rc; - struct mdss_pll_resources *pll = vco->priv; - - if (is_gdsc_disabled(pll)) - return 0; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); - return rc; - } - - dec_start = MDSS_PLL_REG_R(pll->pll_base, - DSIPHY_PLL_DEC_START); - dec_start &= 0x0ff; - pr_debug("dec_start = 0x%x\n", dec_start); - - div_frac_start = (MDSS_PLL_REG_R(pll->pll_base, - DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16; - div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base, - DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8; - div_frac_start |= MDSS_PLL_REG_R(pll->pll_base, - DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff; - pr_debug("div_frac_start = 0x%x\n", div_frac_start); - - vco_rate = ref_clk * dec_start; - vco_rate += ((ref_clk * div_frac_start) / multiplier); - - pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); - - mdss_pll_resource_enable(pll, false); - - return (unsigned long)vco_rate; -} - -long pll_vco_round_rate_8996(struct clk *c, unsigned long rate) +long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { unsigned long rrate = rate; u32 div; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); div = vco->min_rate / rate; if (div > 15) { @@ -1046,46 +1084,14 @@ long pll_vco_round_rate_8996(struct clk *c, unsigned long rate) if (rate > vco->max_rate) rrate = vco->max_rate; + *parent_rate = rrate; return rrate; } -enum handoff pll_vco_handoff_8996(struct clk *c) -{ - int rc; - enum handoff ret = HANDOFF_DISABLED_CLK; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); - struct mdss_pll_resources *pll = vco->priv; - - if (is_gdsc_disabled(pll)) - return HANDOFF_DISABLED_CLK; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); - return ret; - } - - if (pll_is_pll_locked_8996(pll)) { - pll->handoff_resources = true; - pll->pll_on = true; - c->rate = pll_vco_get_rate_8996(c); - ret = HANDOFF_ENABLED_CLK; - } else { - mdss_pll_resource_enable(pll, false); - } - - return ret; -} - -enum handoff shadow_pll_vco_handoff_8996(struct clk *c) -{ - return HANDOFF_DISABLED_CLK; -} - -int pll_vco_prepare_8996(struct clk *c) +int pll_vco_prepare_14nm(struct clk_hw *hw) { int rc = 0; - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; if (!pll) { @@ -1101,8 +1107,9 @@ int pll_vco_prepare_8996(struct clk *c) } if ((pll->vco_cached_rate != 0) - && (pll->vco_cached_rate == c->rate)) { - rc = c->ops->set_rate(c, pll->vco_cached_rate); + && (pll->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, + pll->vco_cached_rate); if (rc) { pr_err("index=%d vco_set_rate failed. rc=%d\n", rc, pll->index); @@ -1111,7 +1118,7 @@ int pll_vco_prepare_8996(struct clk *c) } } - rc = dsi_pll_enable(c); + rc = dsi_pll_enable(hw); if (rc) { mdss_pll_resource_enable(pll, false); @@ -1122,9 +1129,9 @@ error: return rc; } -void pll_vco_unprepare_8996(struct clk *c) +void pll_vco_unprepare_14nm(struct clk_hw *hw) { - struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct dsi_pll_vco_clk *vco = to_vco_hw(hw); struct mdss_pll_resources *pll = vco->priv; if (!pll) { @@ -1132,6 +1139,17 @@ void pll_vco_unprepare_8996(struct clk *c) return; } - pll->vco_cached_rate = c->rate; - dsi_pll_disable(c); + pll->vco_cached_rate = clk_hw_get_rate(hw); + dsi_pll_disable(hw); +} + +int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val) +{ + return 0; +} + +int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val) +{ + *val = 0; + return 0; } diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c new file mode 100644 index 000000000000..667a1512d54f --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c @@ -0,0 +1,614 @@ +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include + +#include "mdss-pll.h" +#include "mdss-dsi-pll.h" +#include "mdss-dsi-pll-14nm.h" + +#define VCO_DELAY_USEC 1 + +static struct dsi_pll_db pll_db[DSI_PLL_NUM]; + +static struct regmap_config dsi_pll_14nm_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x588, +}; + +static struct regmap_bus post_n1_div_regmap_bus = { + .reg_write = post_n1_div_set_div, + .reg_read = post_n1_div_get_div, +}; + +static struct regmap_bus n2_div_regmap_bus = { + .reg_write = n2_div_set_div, + .reg_read = n2_div_get_div, +}; + +static struct regmap_bus shadow_n2_div_regmap_bus = { + .reg_write = shadow_n2_div_set_div, + .reg_read = n2_div_get_div, +}; + +static struct regmap_bus dsi_mux_regmap_bus = { + .reg_write = dsi_mux_set_parent_14nm, + .reg_read = dsi_mux_get_parent_14nm, +}; + +/* Op structures */ +static struct clk_ops clk_ops_dsi_vco = { + .recalc_rate = pll_vco_recalc_rate_14nm, + .set_rate = pll_vco_set_rate_14nm, + .round_rate = pll_vco_round_rate_14nm, + .prepare = pll_vco_prepare_14nm, + .unprepare = pll_vco_unprepare_14nm, +}; + +/* Shadow ops for dynamic refresh */ +static struct clk_ops clk_ops_shadow_dsi_vco = { + .recalc_rate = pll_vco_recalc_rate_14nm, + .set_rate = shadow_pll_vco_set_rate_14nm, + .round_rate = pll_vco_round_rate_14nm, +}; + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_vco_clk_14nm", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &clk_ops_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_vco_clk_14nm", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &clk_ops_shadow_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_vco_clk_14nm", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &clk_ops_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_vco_clk_14nm", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &clk_ops_shadow_dsi_vco, + }, +}; + +static struct clk_regmap_div dsi0pll_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_n1_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_vco_clk_14nm" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_n1_div_clk", + .parent_names = + (const char *[]){"dsi0pll_shadow_vco_clk_14nm"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_n1_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_vco_clk_14nm" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_n1_div_clk", + .parent_names = + (const char *[]){"dsi1pll_shadow_vco_clk_14nm"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_n2_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_n2_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_n2_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_n2_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pixel_clk_src", + .parent_names = (const char *[]){ "dsi0pll_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pixel_clk_src", + .parent_names = (const char *[]){ "dsi0pll_shadow_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pixel_clk_src", + .parent_names = (const char *[]){ "dsi1pll_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pixel_clk_src", + .parent_names = (const char *[]){ "dsi1pll_shadow_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_pixel_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pixel_clk_mux", + .parent_names = + (const char *[]){ "dsi0pll_pixel_clk_src", + "dsi0pll_shadow_pixel_clk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pixel_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pixel_clk_mux", + .parent_names = + (const char *[]){ "dsi1pll_pixel_clk_src", + "dsi1pll_shadow_pixel_clk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byte_clk_src", + .parent_names = (const char *[]){ "dsi0pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_byte_clk_src", + .parent_names = + (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byte_clk_src", + .parent_names = (const char *[]){ "dsi1pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_byte_clk_src", + .parent_names = + (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_byte_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byte_clk_mux", + .parent_names = + (const char *[]){"dsi0pll_byte_clk_src", + "dsi0pll_shadow_byte_clk_src"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_byte_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byte_clk_mux", + .parent_names = + (const char *[]){"dsi1pll_byte_clk_src", + "dsi1pll_shadow_byte_clk_src"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_hw *mdss_dsi_pllcc_14nm[] = { + [BYTE0_MUX_CLK] = &dsi0pll_byte_clk_mux.clkr.hw, + [BYTE0_SRC_CLK] = &dsi0pll_byte_clk_src.hw, + [PIX0_MUX_CLK] = &dsi0pll_pixel_clk_mux.clkr.hw, + [PIX0_SRC_CLK] = &dsi0pll_pixel_clk_src.hw, + [N2_DIV_0_CLK] = &dsi0pll_n2_div_clk.clkr.hw, + [POST_N1_DIV_0_CLK] = &dsi0pll_post_n1_div_clk.clkr.hw, + [VCO_CLK_0_CLK] = &dsi0pll_vco_clk.hw, + [SHADOW_BYTE0_SRC_CLK] = &dsi0pll_shadow_byte_clk_src.hw, + [SHADOW_PIX0_SRC_CLK] = &dsi0pll_shadow_pixel_clk_src.hw, + [SHADOW_N2_DIV_0_CLK] = &dsi0pll_shadow_n2_div_clk.clkr.hw, + [SHADOW_POST_N1_DIV_0_CLK] = &dsi0pll_shadow_post_n1_div_clk.clkr.hw, + [SHADOW_VCO_CLK_0_CLK] = &dsi0pll_shadow_vco_clk.hw, + [BYTE1_MUX_CLK] = &dsi1pll_byte_clk_mux.clkr.hw, + [BYTE1_SRC_CLK] = &dsi1pll_byte_clk_src.hw, + [PIX1_MUX_CLK] = &dsi1pll_pixel_clk_mux.clkr.hw, + [PIX1_SRC_CLK] = &dsi1pll_pixel_clk_src.hw, + [N2_DIV_1_CLK] = &dsi1pll_n2_div_clk.clkr.hw, + [POST_N1_DIV_1_CLK] = &dsi1pll_post_n1_div_clk.clkr.hw, + [VCO_CLK_1_CLK] = &dsi1pll_vco_clk.hw, + [SHADOW_BYTE1_SRC_CLK] = &dsi1pll_shadow_byte_clk_src.hw, + [SHADOW_PIX1_SRC_CLK] = &dsi1pll_shadow_pixel_clk_src.hw, + [SHADOW_N2_DIV_1_CLK] = &dsi1pll_shadow_n2_div_clk.clkr.hw, + [SHADOW_POST_N1_DIV_1_CLK] = &dsi1pll_shadow_post_n1_div_clk.clkr.hw, + [SHADOW_VCO_CLK_1_CLK] = &dsi1pll_shadow_vco_clk.hw, +}; + +int dsi_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx, i; + int const ssc_freq_default = 31500; /* default h/w recommended value */ + int const ssc_ppm_default = 5000; /* default h/w recommended value */ + struct dsi_pll_db *pdb; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_14nm); + + if (!pdev || !pdev->dev.of_node) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + if (!pll_res || !pll_res->pll_base) { + pr_err("Invalid PLL resources\n"); + return -EPROBE_DEFER; + } + + if (pll_res->index >= DSI_PLL_NUM) { + pr_err("pll ndx=%d is NOT supported\n", pll_res->index); + return -EINVAL; + } + + ndx = pll_res->index; + pdb = &pll_db[ndx]; + pll_res->priv = pdb; + pdb->pll = pll_res; + ndx++; + ndx %= DSI_PLL_NUM; + pdb->next = &pll_db[ndx]; + + if (pll_res->ssc_en) { + if (!pll_res->ssc_freq) + pll_res->ssc_freq = ssc_freq_default; + if (!pll_res->ssc_ppm) + pll_res->ssc_ppm = ssc_ppm_default; + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) { + devm_kfree(&pdev->dev, clk_data); + return -ENOMEM; + } + + clk_data->clk_num = num_clks; + + /* Set client data to mux, div and vco clocks. */ + if (pll_res->index == DSI_PLL_1) { + regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_post_n1_div_clk.clkr.regmap = regmap; + dsi1pll_shadow_post_n1_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_shadow_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_byte_clk_mux.clkr.regmap = regmap; + dsi1pll_pixel_clk_mux.clkr.regmap = regmap; + + dsi1pll_vco_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; + + pll_res->vco_delay = VCO_DELAY_USEC; + + for (i = BYTE1_MUX_CLK; i <= SHADOW_VCO_CLK_1_CLK; i++) { + pr_debug("register clk: %d index: %d\n", + i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } else { + regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_post_n1_div_clk.clkr.regmap = regmap; + dsi0pll_shadow_post_n1_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_shadow_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_byte_clk_mux.clkr.regmap = regmap; + dsi0pll_pixel_clk_mux.clkr.regmap = regmap; + + dsi0pll_vco_clk.priv = pll_res; + dsi0pll_shadow_vco_clk.priv = pll_res; + pll_res->vco_delay = VCO_DELAY_USEC; + + for (i = BYTE0_MUX_CLK; i <= SHADOW_VCO_CLK_0_CLK; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } + + if (!rc) { + pr_info("Registered DSI PLL ndx=%d clocks successfully\n", + pll_res->index); + return rc; + } + +clk_reg_fail: + devm_kfree(&pdev->dev, clk_data->clks); + devm_kfree(&pdev->dev, clk_data); + return rc; +} diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h similarity index 81% rename from drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h rename to drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h index 611e79101d4f..c2a3b12d8174 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#ifndef MDSS_DSI_PLL_8996_H -#define MDSS_DSI_PLL_8996_H +#ifndef MDSS_DSI_PLL_14NM_H +#define MDSS_DSI_PLL_14NM_H #define DSIPHY_CMN_CLK_CFG0 0x0010 #define DSIPHY_CMN_CLK_CFG1 0x0014 @@ -197,25 +197,31 @@ enum { PLL_MASTER }; -int pll_vco_set_rate_8996(struct clk *c, unsigned long rate); -long pll_vco_round_rate_8996(struct clk *c, unsigned long rate); -enum handoff pll_vco_handoff_8996(struct clk *c); -enum handoff shadow_pll_vco_handoff_8996(struct clk *c); -int shadow_post_n1_div_set_div(struct div_clk *clk, int div); -int shadow_post_n1_div_get_div(struct div_clk *clk); -int shadow_n2_div_set_div(struct div_clk *clk, int div); -int shadow_n2_div_get_div(struct div_clk *clk); -int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate); -int pll_vco_prepare_8996(struct clk *c); -void pll_vco_unprepare_8996(struct clk *c); -int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel); -int get_mdss_byte_mux_sel_8996(struct mux_clk *clk); -int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel); -int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk); -int post_n1_div_set_div(struct div_clk *clk, int div); -int post_n1_div_get_div(struct div_clk *clk); -int n2_div_set_div(struct div_clk *clk, int div); -int n2_div_get_div(struct div_clk *clk); -int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll); +int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate); -#endif /* MDSS_DSI_PLL_8996_H */ +int pll_vco_prepare_14nm(struct clk_hw *hw); +void pll_vco_unprepare_14nm(struct clk_hw *hw); + +int shadow_post_n1_div_set_div(void *context, + unsigned int reg, unsigned int div); +int shadow_post_n1_div_get_div(void *context, + unsigned int reg, unsigned int *div); +int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div); +int shadow_n2_div_get_div(void *context, unsigned int reg, unsigned int *div); + +int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div); +int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div); +int n2_div_set_div(void *context, unsigned int reg, unsigned int div); +int n2_div_get_div(void *context, unsigned int reg, unsigned int *div); +int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll); +int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val); +int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val); + +#endif /* MDSS_DSI_PLL_14NM_H */ diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c deleted file mode 100644 index 1de1b997a041..000000000000 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c +++ /dev/null @@ -1,566 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * 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. - * - */ - -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mdss-pll.h" -#include "mdss-dsi-pll.h" -#include "mdss-dsi-pll-8996.h" - -#define VCO_DELAY_USEC 1 - -static struct dsi_pll_db pll_db[DSI_PLL_NUM]; - -static struct clk_ops n2_clk_src_ops; -static struct clk_ops shadow_n2_clk_src_ops; -static struct clk_ops byte_clk_src_ops; -static struct clk_ops post_n1_div_clk_src_ops; -static struct clk_ops shadow_post_n1_div_clk_src_ops; - -static struct clk_ops clk_ops_gen_mux_dsi; - -/* Op structures */ -static struct clk_ops clk_ops_dsi_vco = { - .set_rate = pll_vco_set_rate_8996, - .round_rate = pll_vco_round_rate_8996, - .handoff = pll_vco_handoff_8996, - .prepare = pll_vco_prepare_8996, - .unprepare = pll_vco_unprepare_8996, -}; - -static struct clk_div_ops post_n1_div_ops = { - .set_div = post_n1_div_set_div, - .get_div = post_n1_div_get_div, -}; - -static struct clk_div_ops n2_div_ops = { /* hr_oclk3 */ - .set_div = n2_div_set_div, - .get_div = n2_div_get_div, -}; - -static struct clk_mux_ops mdss_byte_mux_ops = { - .set_mux_sel = set_mdss_byte_mux_sel_8996, - .get_mux_sel = get_mdss_byte_mux_sel_8996, -}; - -static struct clk_mux_ops mdss_pixel_mux_ops = { - .set_mux_sel = set_mdss_pixel_mux_sel_8996, - .get_mux_sel = get_mdss_pixel_mux_sel_8996, -}; - -/* Shadow ops for dynamic refresh */ -static struct clk_ops clk_ops_shadow_dsi_vco = { - .set_rate = shadow_pll_vco_set_rate_8996, - .round_rate = pll_vco_round_rate_8996, - .handoff = shadow_pll_vco_handoff_8996, -}; - -static struct clk_div_ops shadow_post_n1_div_ops = { - .set_div = post_n1_div_set_div, -}; - -static struct clk_div_ops shadow_n2_div_ops = { - .set_div = shadow_n2_div_set_div, -}; - -static struct dsi_pll_vco_clk dsi0pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1300000000UL, - .max_rate = 2600000000UL, - .pll_en_seq_cnt = 1, - .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, - .c = { - .dbg_name = "dsi0pll_vco_clk_8996", - .ops = &clk_ops_dsi_vco, - CLK_INIT(dsi0pll_vco_clk.c), - }, -}; - -static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { - .ref_clk_rate = 19200000u, - .min_rate = 1300000000u, - .max_rate = 2600000000u, - .c = { - .dbg_name = "dsi0pll_shadow_vco_clk", - .ops = &clk_ops_shadow_dsi_vco, - CLK_INIT(dsi0pll_shadow_vco_clk.c), - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1300000000UL, - .max_rate = 2600000000UL, - .pll_en_seq_cnt = 1, - .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, - .c = { - .dbg_name = "dsi1pll_vco_clk_8996", - .ops = &clk_ops_dsi_vco, - CLK_INIT(dsi1pll_vco_clk.c), - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { - .ref_clk_rate = 19200000u, - .min_rate = 1300000000u, - .max_rate = 2600000000u, - .pll_en_seq_cnt = 1, - .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, - .c = { - .dbg_name = "dsi1pll_shadow_vco_clk", - .ops = &clk_ops_shadow_dsi_vco, - CLK_INIT(dsi1pll_shadow_vco_clk.c), - }, -}; - -static struct div_clk dsi0pll_post_n1_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &post_n1_div_ops, - .c = { - .parent = &dsi0pll_vco_clk.c, - .dbg_name = "dsi0pll_post_n1_div_clk", - .ops = &post_n1_div_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_post_n1_div_clk.c), - }, -}; - -static struct div_clk dsi0pll_shadow_post_n1_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &shadow_post_n1_div_ops, - .c = { - .parent = &dsi0pll_shadow_vco_clk.c, - .dbg_name = "dsi0pll_shadow_post_n1_div_clk", - .ops = &shadow_post_n1_div_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c), - }, -}; - -static struct div_clk dsi1pll_post_n1_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &post_n1_div_ops, - .c = { - .parent = &dsi1pll_vco_clk.c, - .dbg_name = "dsi1pll_post_n1_div_clk", - .ops = &post_n1_div_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_post_n1_div_clk.c), - }, -}; - -static struct div_clk dsi1pll_shadow_post_n1_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &shadow_post_n1_div_ops, - .c = { - .parent = &dsi1pll_shadow_vco_clk.c, - .dbg_name = "dsi1pll_shadow_post_n1_div_clk", - .ops = &shadow_post_n1_div_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c), - }, -}; - -static struct div_clk dsi0pll_n2_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &n2_div_ops, - .c = { - .parent = &dsi0pll_post_n1_div_clk.c, - .dbg_name = "dsi0pll_n2_div_clk", - .ops = &n2_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_n2_div_clk.c), - }, -}; - -static struct div_clk dsi0pll_shadow_n2_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &shadow_n2_div_ops, - .c = { - .parent = &dsi0pll_shadow_post_n1_div_clk.c, - .dbg_name = "dsi0pll_shadow_n2_div_clk", - .ops = &shadow_n2_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_shadow_n2_div_clk.c), - }, -}; - -static struct div_clk dsi1pll_n2_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &n2_div_ops, - .c = { - .parent = &dsi1pll_post_n1_div_clk.c, - .dbg_name = "dsi1pll_n2_div_clk", - .ops = &n2_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_n2_div_clk.c), - }, -}; - -static struct div_clk dsi1pll_shadow_n2_div_clk = { - .data = { - .max_div = 15, - .min_div = 1, - }, - .ops = &shadow_n2_div_ops, - .c = { - .parent = &dsi1pll_shadow_post_n1_div_clk.c, - .dbg_name = "dsi1pll_shadow_n2_div_clk", - .ops = &shadow_n2_clk_src_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_shadow_n2_div_clk.c), - }, -}; - -static struct div_clk dsi0pll_pixel_clk_src = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi0pll_n2_div_clk.c, - .dbg_name = "dsi0pll_pixel_clk_src", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pixel_clk_src.c), - }, -}; - -static struct div_clk dsi0pll_shadow_pixel_clk_src = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi0pll_shadow_n2_div_clk.c, - .dbg_name = "dsi0pll_shadow_pixel_clk_src", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_shadow_pixel_clk_src.c), - }, -}; - -static struct div_clk dsi1pll_pixel_clk_src = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi1pll_n2_div_clk.c, - .dbg_name = "dsi1pll_pixel_clk_src", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pixel_clk_src.c), - }, -}; - -static struct div_clk dsi1pll_shadow_pixel_clk_src = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi1pll_shadow_n2_div_clk.c, - .dbg_name = "dsi1pll_shadow_pixel_clk_src", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_shadow_pixel_clk_src.c), - }, -}; - -static struct mux_clk dsi0pll_pixel_clk_mux = { - .num_parents = 2, - .parents = (struct clk_src[]) { - {&dsi0pll_pixel_clk_src.c, 0}, - {&dsi0pll_shadow_pixel_clk_src.c, 1}, - }, - .ops = &mdss_pixel_mux_ops, - .c = { - .parent = &dsi0pll_pixel_clk_src.c, - .dbg_name = "dsi0pll_pixel_clk_mux", - .ops = &clk_ops_gen_mux_dsi, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pixel_clk_mux.c), - } -}; - -static struct mux_clk dsi1pll_pixel_clk_mux = { - .num_parents = 2, - .parents = (struct clk_src[]) { - {&dsi1pll_pixel_clk_src.c, 0}, - {&dsi1pll_shadow_pixel_clk_src.c, 1}, - }, - .ops = &mdss_pixel_mux_ops, - .c = { - .parent = &dsi1pll_pixel_clk_src.c, - .dbg_name = "dsi1pll_pixel_clk_mux", - .ops = &clk_ops_gen_mux_dsi, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pixel_clk_mux.c), - } -}; - -static struct div_clk dsi0pll_byte_clk_src = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi0pll_post_n1_div_clk.c, - .dbg_name = "dsi0pll_byte_clk_src", - .ops = &clk_ops_div, - CLK_INIT(dsi0pll_byte_clk_src.c), - }, -}; - -static struct div_clk dsi0pll_shadow_byte_clk_src = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi0pll_shadow_post_n1_div_clk.c, - .dbg_name = "dsi0pll_shadow_byte_clk_src", - .ops = &clk_ops_div, - CLK_INIT(dsi0pll_shadow_byte_clk_src.c), - }, -}; - -static struct div_clk dsi1pll_byte_clk_src = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi1pll_post_n1_div_clk.c, - .dbg_name = "dsi1pll_byte_clk_src", - .ops = &clk_ops_div, - CLK_INIT(dsi1pll_byte_clk_src.c), - }, -}; - -static struct div_clk dsi1pll_shadow_byte_clk_src = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi1pll_shadow_post_n1_div_clk.c, - .dbg_name = "dsi1pll_shadow_byte_clk_src", - .ops = &clk_ops_div, - CLK_INIT(dsi1pll_shadow_byte_clk_src.c), - }, -}; - -static struct mux_clk dsi0pll_byte_clk_mux = { - .num_parents = 2, - .parents = (struct clk_src[]) { - {&dsi0pll_byte_clk_src.c, 0}, - {&dsi0pll_shadow_byte_clk_src.c, 1}, - }, - .ops = &mdss_byte_mux_ops, - .c = { - .parent = &dsi0pll_byte_clk_src.c, - .dbg_name = "dsi0pll_byte_clk_mux", - .ops = &clk_ops_gen_mux_dsi, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_byte_clk_mux.c), - } -}; -static struct mux_clk dsi1pll_byte_clk_mux = { - .num_parents = 2, - .parents = (struct clk_src[]) { - {&dsi1pll_byte_clk_src.c, 0}, - {&dsi1pll_shadow_byte_clk_src.c, 1}, - }, - .ops = &mdss_byte_mux_ops, - .c = { - .parent = &dsi1pll_byte_clk_src.c, - .dbg_name = "dsi1pll_byte_clk_mux", - .ops = &clk_ops_gen_mux_dsi, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_byte_clk_mux.c), - } -}; - -static struct clk_lookup mdss_dsi_pllcc_8996[] = { - CLK_LIST(dsi0pll_byte_clk_mux), - CLK_LIST(dsi0pll_byte_clk_src), - CLK_LIST(dsi0pll_pixel_clk_mux), - CLK_LIST(dsi0pll_pixel_clk_src), - CLK_LIST(dsi0pll_n2_div_clk), - CLK_LIST(dsi0pll_post_n1_div_clk), - CLK_LIST(dsi0pll_vco_clk), - CLK_LIST(dsi0pll_shadow_byte_clk_src), - CLK_LIST(dsi0pll_shadow_pixel_clk_src), - CLK_LIST(dsi0pll_shadow_n2_div_clk), - CLK_LIST(dsi0pll_shadow_post_n1_div_clk), - CLK_LIST(dsi0pll_shadow_vco_clk), -}; - -static struct clk_lookup mdss_dsi_pllcc_8996_1[] = { - CLK_LIST(dsi1pll_byte_clk_mux), - CLK_LIST(dsi1pll_byte_clk_src), - CLK_LIST(dsi1pll_pixel_clk_mux), - CLK_LIST(dsi1pll_pixel_clk_src), - CLK_LIST(dsi1pll_n2_div_clk), - CLK_LIST(dsi1pll_post_n1_div_clk), - CLK_LIST(dsi1pll_vco_clk), - CLK_LIST(dsi1pll_shadow_byte_clk_src), - CLK_LIST(dsi1pll_shadow_pixel_clk_src), - CLK_LIST(dsi1pll_shadow_n2_div_clk), - CLK_LIST(dsi1pll_shadow_post_n1_div_clk), - CLK_LIST(dsi1pll_shadow_vco_clk), -}; - -int dsi_pll_clock_register_8996(struct platform_device *pdev, - struct mdss_pll_resources *pll_res) -{ - int rc = 0, ndx; - int const ssc_freq_default = 31500; /* default h/w recommended value */ - int const ssc_ppm_default = 5000; /* default h/w recommended value */ - struct dsi_pll_db *pdb; - - if (!pdev || !pdev->dev.of_node) { - pr_err("Invalid input parameters\n"); - return -EINVAL; - } - - if (!pll_res || !pll_res->pll_base) { - pr_err("Invalid PLL resources\n"); - return -EPROBE_DEFER; - } - - if (pll_res->index >= DSI_PLL_NUM) { - pr_err("pll ndx=%d is NOT supported\n", pll_res->index); - return -EINVAL; - } - - ndx = pll_res->index; - pdb = &pll_db[ndx]; - pll_res->priv = pdb; - pdb->pll = pll_res; - ndx++; - ndx %= DSI_PLL_NUM; - pdb->next = &pll_db[ndx]; - - /* Set clock source operations */ - - /* hr_oclk3, pixel */ - n2_clk_src_ops = clk_ops_slave_div; - n2_clk_src_ops.prepare = mdss_pll_div_prepare; - - shadow_n2_clk_src_ops = clk_ops_slave_div; - - /* hr_ockl2, byte, vco pll */ - post_n1_div_clk_src_ops = clk_ops_div; - post_n1_div_clk_src_ops.prepare = mdss_pll_div_prepare; - - shadow_post_n1_div_clk_src_ops = clk_ops_div; - - byte_clk_src_ops = clk_ops_div; - byte_clk_src_ops.prepare = mdss_pll_div_prepare; - - clk_ops_gen_mux_dsi = clk_ops_gen_mux; - clk_ops_gen_mux_dsi.round_rate = parent_round_rate; - clk_ops_gen_mux_dsi.set_rate = parent_set_rate; - - if (pll_res->ssc_en) { - if (!pll_res->ssc_freq) - pll_res->ssc_freq = ssc_freq_default; - if (!pll_res->ssc_ppm) - pll_res->ssc_ppm = ssc_ppm_default; - } - - /* Set client data to mux, div and vco clocks. */ - if (pll_res->index == DSI_PLL_1) { - dsi1pll_byte_clk_src.priv = pll_res; - dsi1pll_pixel_clk_src.priv = pll_res; - dsi1pll_post_n1_div_clk.priv = pll_res; - dsi1pll_n2_div_clk.priv = pll_res; - dsi1pll_vco_clk.priv = pll_res; - - dsi1pll_shadow_byte_clk_src.priv = pll_res; - dsi1pll_shadow_pixel_clk_src.priv = pll_res; - dsi1pll_shadow_post_n1_div_clk.priv = pll_res; - dsi1pll_shadow_n2_div_clk.priv = pll_res; - dsi1pll_shadow_vco_clk.priv = pll_res; - - pll_res->vco_delay = VCO_DELAY_USEC; - rc = of_msm_clock_register(pdev->dev.of_node, - mdss_dsi_pllcc_8996_1, - ARRAY_SIZE(mdss_dsi_pllcc_8996_1)); - } else { - dsi0pll_byte_clk_src.priv = pll_res; - dsi0pll_pixel_clk_src.priv = pll_res; - dsi0pll_post_n1_div_clk.priv = pll_res; - dsi0pll_n2_div_clk.priv = pll_res; - dsi0pll_vco_clk.priv = pll_res; - - dsi0pll_shadow_byte_clk_src.priv = pll_res; - dsi0pll_shadow_pixel_clk_src.priv = pll_res; - dsi0pll_shadow_post_n1_div_clk.priv = pll_res; - dsi0pll_shadow_n2_div_clk.priv = pll_res; - dsi0pll_shadow_vco_clk.priv = pll_res; - - pll_res->vco_delay = VCO_DELAY_USEC; - rc = of_msm_clock_register(pdev->dev.of_node, - mdss_dsi_pllcc_8996, - ARRAY_SIZE(mdss_dsi_pllcc_8996)); - } - - if (!rc) { - pr_info("Registered DSI PLL ndx=%d clocks successfully\n", - pll_res->index); - } - - return rc; -} diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll.h b/drivers/clk/qcom/mdss/mdss-dsi-pll.h index 286c99e339c6..822d5181435d 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll.h +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll.h @@ -31,6 +31,8 @@ struct lpfr_cfg { }; struct dsi_pll_vco_clk { + struct clk_hw hw; + unsigned long ref_clk_rate; unsigned long min_rate; unsigned long max_rate; @@ -39,72 +41,15 @@ struct dsi_pll_vco_clk { u32 lpfr_lut_size; void *priv; - struct clk c; - int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS]) (struct mdss_pll_resources *dsi_pll_Res); }; -static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk) +static inline struct dsi_pll_vco_clk *to_vco_hw(struct clk_hw *hw) { - return container_of(clk, struct dsi_pll_vco_clk, c); + return container_of(hw, struct dsi_pll_vco_clk, hw); } -int dsi_pll_clock_register_hpm(struct platform_device *pdev, +int dsi_pll_clock_register_14nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res); -int dsi_pll_clock_register_20nm(struct platform_device *pdev, - struct mdss_pll_resources *pll_res); -int dsi_pll_clock_register_lpm(struct platform_device *pdev, - struct mdss_pll_resources *pll_res); -int dsi_pll_clock_register_8996(struct platform_device *pdev, - struct mdss_pll_resources *pll_res); -int dsi_pll_clock_register_8998(struct platform_device *pdev, - struct mdss_pll_resources *pll_res); - -int set_byte_mux_sel(struct mux_clk *clk, int sel); -int get_byte_mux_sel(struct mux_clk *clk); -int dsi_pll_mux_prepare(struct clk *c); -int fixed_4div_set_div(struct div_clk *clk, int div); -int fixed_4div_get_div(struct div_clk *clk); -int digital_set_div(struct div_clk *clk, int div); -int digital_get_div(struct div_clk *clk); -int analog_set_div(struct div_clk *clk, int div); -int analog_get_div(struct div_clk *clk); -int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res); -int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate); -unsigned long vco_get_rate(struct clk *c); -long vco_round_rate(struct clk *c, unsigned long rate); -enum handoff vco_handoff(struct clk *c); -int vco_prepare(struct clk *c); -void vco_unprepare(struct clk *c); - -/* APIs for 20nm PHY PLL */ -int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate); -int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, - unsigned long rate); -long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate); -enum handoff pll_20nm_vco_handoff(struct clk *c); -int pll_20nm_vco_prepare(struct clk *c); -void pll_20nm_vco_unprepare(struct clk *c); -int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res); - -int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel); -int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel); -int get_bypass_lp_div_mux_sel(struct mux_clk *clk); -int fixed_hr_oclk2_set_div(struct div_clk *clk, int div); -int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div); -int fixed_hr_oclk2_get_div(struct div_clk *clk); -int hr_oclk3_set_div(struct div_clk *clk, int div); -int shadow_hr_oclk3_set_div(struct div_clk *clk, int div); -int hr_oclk3_get_div(struct div_clk *clk); -int ndiv_set_div(struct div_clk *clk, int div); -int shadow_ndiv_set_div(struct div_clk *clk, int div); -int ndiv_get_div(struct div_clk *clk); -void __dsi_pll_disable(void __iomem *pll_base); - -int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel); -int get_mdss_pixel_mux_sel(struct mux_clk *clk); -int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel); -int get_mdss_byte_mux_sel(struct mux_clk *clk); - #endif diff --git a/drivers/clk/qcom/mdss/mdss-pll-util.c b/drivers/clk/qcom/mdss/mdss-pll-util.c index 690c53f30eb7..881c973ec1b6 100644 --- a/drivers/clk/qcom/mdss/mdss-pll-util.c +++ b/drivers/clk/qcom/mdss/mdss-pll-util.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 8264d2e5a3cd..b4b73ea4211a 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -19,12 +19,9 @@ #include #include #include -#include #include "mdss-pll.h" #include "mdss-dsi-pll.h" -#include "mdss-hdmi-pll.h" -#include "mdss-dp-pll.h" int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable) { @@ -175,27 +172,7 @@ static int mdss_pll_clock_register(struct platform_device *pdev, switch (pll_res->pll_interface_type) { case MDSS_DSI_PLL_8996: - rc = dsi_pll_clock_register_8996(pdev, pll_res); - break; - case MDSS_DSI_PLL_8998: - rc = dsi_pll_clock_register_8998(pdev, pll_res); - case MDSS_DP_PLL_8998: - rc = dp_pll_clock_register_8998(pdev, pll_res); - break; - case MDSS_HDMI_PLL_8996: - rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res); - break; - case MDSS_HDMI_PLL_8996_V2: - rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res); - break; - case MDSS_HDMI_PLL_8996_V3: - rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res); - break; - case MDSS_HDMI_PLL_8996_V3_1_8: - rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res); - break; - case MDSS_HDMI_PLL_8998: - rc = hdmi_8998_pll_clock_register(pdev, pll_res); + rc = dsi_pll_clock_register_14nm(pdev, pll_res); break; case MDSS_UNKNOWN_PLL: default: diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index 8fffaf30d4ec..3528dcfd0cb5 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -14,8 +14,16 @@ #define __MDSS_PLL_H #include -#include +#include #include +#include +#include +#include + +#include "../clk-regmap.h" +#include "../clk-regmap-divider.h" +#include "../clk-regmap-mux.h" +#include #define MDSS_PLL_REG_W(base, offset, data) \ writel_relaxed((data), (base) + (offset)) @@ -200,21 +208,12 @@ static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res) (!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true; } -static inline int mdss_pll_div_prepare(struct clk *c) +static inline int mdss_pll_div_prepare(struct clk_hw *hw) { - struct div_clk *div = to_div_clk(c); + struct clk_hw *parent_hw = clk_hw_get_parent(hw); /* Restore the divider's value */ - return div->ops->set_div(div, div->data.div); -} - -static inline int mdss_set_mux_sel(struct mux_clk *clk, int sel) -{ - return 0; -} - -static inline int mdss_get_mux_sel(struct mux_clk *clk) -{ - return 0; + return hw->init->ops->set_rate(hw, clk_hw_get_rate(hw), + clk_hw_get_rate(parent_hw)); } int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable); diff --git a/include/dt-bindings/clock/mdss-pll-clk.h b/include/dt-bindings/clock/mdss-pll-clk.h new file mode 100644 index 000000000000..8cd0b2a9bc98 --- /dev/null +++ b/include/dt-bindings/clock/mdss-pll-clk.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MDSS_PLL_CLK_H +#define __MDSS_PLL_CLK_H + +/* DSI PLL clocks */ +#define BYTE0_MUX_CLK 0 +#define BYTE0_SRC_CLK 1 +#define PIX0_MUX_CLK 2 +#define PIX0_SRC_CLK 3 +#define N2_DIV_0_CLK 4 +#define POST_N1_DIV_0_CLK 5 +#define VCO_CLK_0_CLK 6 +#define SHADOW_BYTE0_SRC_CLK 7 +#define SHADOW_PIX0_SRC_CLK 8 +#define SHADOW_N2_DIV_0_CLK 9 +#define SHADOW_POST_N1_DIV_0_CLK 10 +#define SHADOW_VCO_CLK_0_CLK 11 +#define BYTE1_MUX_CLK 12 +#define BYTE1_SRC_CLK 13 +#define PIX1_MUX_CLK 14 +#define PIX1_SRC_CLK 15 +#define N2_DIV_1_CLK 16 +#define POST_N1_DIV_1_CLK 17 +#define VCO_CLK_1_CLK 18 +#define SHADOW_BYTE1_SRC_CLK 19 +#define SHADOW_PIX1_SRC_CLK 20 +#define SHADOW_N2_DIV_1_CLK 21 +#define SHADOW_POST_N1_DIV_1_CLK 22 +#define SHADOW_VCO_CLK_1_CLK 23 + +#endif