diff --git a/include/linux/sde_io_util.h b/include/linux/sde_io_util.h index c759d45865a4..312488fce55f 100644 --- a/include/linux/sde_io_util.h +++ b/include/linux/sde_io_util.h @@ -85,7 +85,12 @@ struct dss_module_power { int msm_dss_ioremap_byname(struct platform_device *pdev, struct dss_io_data *io_data, const char *name); void msm_dss_iounmap(struct dss_io_data *io_data); - +int msm_dss_get_io_mem(struct platform_device *pdev, + struct list_head *mem_list); +void msm_dss_clean_io_mem(struct list_head *mem_list); +int msm_dss_get_io_irq(struct platform_device *pdev, + struct list_head *irq_list, u32 label); +void msm_dss_clean_io_irq(struct list_head *irq_list); int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable); int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable); diff --git a/include/linux/sde_vm_event.h b/include/linux/sde_vm_event.h index 04cd6eed6eec..0fa15eac1b6c 100644 --- a/include/linux/sde_vm_event.h +++ b/include/linux/sde_vm_event.h @@ -12,17 +12,53 @@ #include #include +/** + * struct - msm_io_irq_entry - define irq item + * @label: hh_irq_label for the irq + * @irq_num: linux mapped irq num + * @list: list head pointer + */ +struct msm_io_irq_entry { + u32 label; + u32 irq_num; + struct list_head list; +}; + +/** + * struct - msm_io_mem_entry - define io memory item + * @base: reg base + * @size: size of the reg range + * @list: list head pointer + */ +struct msm_io_mem_entry { + phys_addr_t base; + phys_addr_t size; + struct list_head list; +}; + +/** + * struct - msm_io_res - represents the hw resources for vm sharing + * @irq: list of IRQ's of all the dislay sub-devices + * @mem: list of IO memory ranges of all the display sub-devices + */ +struct msm_io_res { + struct list_head irq; + struct list_head mem; +}; + /** * struct msm_vm_ops - hooks for communication with vm clients * @vm_pre_hw_release: invoked before releasing the HW * @vm_post_hw_acquire: invoked before pushing the first commit * @vm_check: invoked to check the readiness of the vm_clients * before releasing the HW + * @vm_get_io_resources: invoked to collect HW resources */ struct msm_vm_ops { int (*vm_pre_hw_release)(void *priv_data); int (*vm_post_hw_acquire)(void *priv_data); int (*vm_check)(void *priv_data); + int (*vm_get_io_resources)(struct msm_io_res *io_res, void *priv_data); }; /** diff --git a/msm/sde_io_util.c b/msm/sde_io_util.c index 088a6850da51..d86bcacfdb22 100644 --- a/msm/sde_io_util.c +++ b/msm/sde_io_util.c @@ -9,6 +9,7 @@ #include #include #include +#include #define MAX_I2C_CMDS 16 void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug) @@ -129,6 +130,127 @@ void msm_dss_iounmap(struct dss_io_data *io_data) } /* msm_dss_iounmap */ EXPORT_SYMBOL(msm_dss_iounmap); +int msm_dss_get_io_mem(struct platform_device *pdev, struct list_head *mem_list) +{ + struct list_head temp_head; + struct msm_io_mem_entry *io_mem; + struct resource *res = NULL; + const char *reg_name, *exclude_reg_name; + int i, j, rc = 0; + int num_entry, num_exclude_entry; + + INIT_LIST_HEAD(&temp_head); + + num_entry = of_property_count_strings(pdev->dev.of_node, + "reg-names"); + if (num_entry < 0) + num_entry = 0; + + /* + * check the dt property to know whether the platform device wants + * to exclude any reg ranges from the IO list + */ + num_exclude_entry = of_property_count_strings(pdev->dev.of_node, + "qcom,sde-vm-exclude-reg-names"); + if (num_exclude_entry < 0) + num_exclude_entry = 0; + + for (i = 0; i < num_entry; i++) { + bool exclude = false; + + of_property_read_string_index(pdev->dev.of_node, + "reg-names", i, ®_name); + + for (j = 0; j < num_exclude_entry; j++) { + of_property_read_string_index(pdev->dev.of_node, + "qcom,sde-vm-exclude-reg-names", j, + &exclude_reg_name); + + if (!strcmp(reg_name, exclude_reg_name)) { + exclude = true; + break; + } + } + + if (exclude) + continue; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + reg_name); + if (!res) + break; + + io_mem = kzalloc(sizeof(*io_mem), GFP_KERNEL); + if (!io_mem) { + msm_dss_clean_io_mem(&temp_head); + rc = -ENOMEM; + goto parse_fail; + } + + io_mem->base = res->start; + io_mem->size = resource_size(res); + + list_add(&io_mem->list, &temp_head); + } + + list_splice(&temp_head, mem_list); + + return 0; + +parse_fail: + msm_dss_clean_io_mem(&temp_head); + + return rc; +} +EXPORT_SYMBOL(msm_dss_get_io_mem); + +void msm_dss_clean_io_mem(struct list_head *mem_list) +{ + struct msm_io_mem_entry *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, mem_list, list) { + list_del(&pos->list); + kzfree(pos); + } +} +EXPORT_SYMBOL(msm_dss_clean_io_mem); + +int msm_dss_get_io_irq(struct platform_device *pdev, struct list_head *irq_list, + u32 label) +{ + struct msm_io_irq_entry *io_irq; + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + pr_err("invalid IRQ\n"); + return irq; + } + + io_irq = kzalloc(sizeof(*io_irq), GFP_KERNEL); + if (!io_irq) + return -ENOMEM; + + io_irq->label = label; + io_irq->irq_num = irq; + + list_add(&io_irq->list, irq_list); + + return 0; +} +EXPORT_SYMBOL(msm_dss_get_io_irq); + +void msm_dss_clean_io_irq(struct list_head *irq_list) +{ + struct msm_io_irq_entry *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, irq_list, list) { + list_del(&pos->list); + kzfree(pos); + } +} +EXPORT_SYMBOL(msm_dss_clean_io_irq); + int msm_dss_get_vreg(struct device *dev, struct dss_vreg *in_vreg, int num_vreg, int enable) {