Loading Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt +20 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,24 @@ Required Parameters: register address of the CX IPEAK LM hardware and 'b' is the size of the peripheral address space. - qcom,thermal-client-offset: Usage: Optional Value type: <value in hex> Definition: This property is required for CX IP LM v1.1 and above hardware. Must contain offset from CX IPEAK LM reg base for thermal client voting. If this property is not defined, then CX IPEAK cooling device will use legacy CXIP LM hardware offset registers. - qcom,bypass-client-list: Usage: Optional Value type: <value in hex> Definition: This property is required for CX IP LM v1.1 and above hardware. Must contain array of offsets from CX IPEAK LM reg base for clients those are not participating voting to CXIP LM hardware. This property makes sense only when thermal-client is defined. - #cooling-cells: Usage: required Value type: <integer> Loading @@ -29,5 +47,7 @@ Example: cxip_cdev: cxip-cdev@1fed000 { compatible = "qcom,cxip-lm-cooling-device"; reg = <0x1fed000 0x24>; qcom,thermal-client-offset = <0x8000>; qcom,bypass-client-list = <0x2004 0x3004>; #cooling-cells = <2>; }; drivers/thermal/qcom/cx_ipeak_cdev.c +82 −14 Original line number Diff line number Diff line Loading @@ -35,27 +35,49 @@ struct cxip_lm_cooling_device { struct thermal_cooling_device *cool_dev; char cdev_name[THERMAL_NAME_LENGTH]; void *cx_ip_reg_base; unsigned int therm_clnt; unsigned int *bypass_clnts; unsigned int bypass_clnt_cnt; bool state; }; static void cxip_lm_therm_vote_apply(void *reg_base, bool vote) static void cxip_lm_therm_vote_apply(struct cxip_lm_cooling_device *cxip_dev, bool vote) { writel_relaxed(CXIP_LM_THERM_VOTE_VAL, reg_base + (vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR)); int vote_offset = 0, val = 0, sts_offset = 0; if (!cxip_dev->therm_clnt) { vote_offset = vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR; val = CXIP_LM_THERM_VOTE_VAL; sts_offset = CXIP_LM_VOTE_STATUS; } else { vote_offset = cxip_dev->therm_clnt; val = vote ? 0x1 : 0x0; sts_offset = vote_offset; } pr_debug("%s vote for cxip_lm. Agg.vote:0x%x\n", writel_relaxed(val, cxip_dev->cx_ip_reg_base + vote_offset); pr_debug("%s vote for cxip_lm. vote:0x%x\n", vote ? "Applied" : "Cleared", readl_relaxed(reg_base + CXIP_LM_VOTE_STATUS)); readl_relaxed(cxip_dev->cx_ip_reg_base + sts_offset)); } static void cxip_lm_initialize_cxip_hw(void *reg_base) static void cxip_lm_initialize_cxip_hw(struct cxip_lm_cooling_device *cxip_dev) { /* Enable CXIP LM HW */ writel_relaxed(CXIP_LM_FEATURE_EN_VAL, reg_base + CXIP_LM_FEATURE_EN); int i = 0; /* Set CXIP LM proxy vote for clients who are not participating */ writel_relaxed(CXIP_LM_BYPASS_VAL, reg_base + CXIP_LM_BYPASS); if (cxip_dev->bypass_clnt_cnt) for (i = 0; i < cxip_dev->bypass_clnt_cnt; i++) writel_relaxed(0x1, cxip_dev->cx_ip_reg_base + cxip_dev->bypass_clnts[i]); else if (!cxip_dev->therm_clnt) writel_relaxed(CXIP_LM_BYPASS_VAL, cxip_dev->cx_ip_reg_base + CXIP_LM_BYPASS); /* Enable CXIP LM HW */ writel_relaxed(CXIP_LM_FEATURE_EN_VAL, cxip_dev->cx_ip_reg_base + CXIP_LM_FEATURE_EN); } static int cxip_lm_get_max_state(struct thermal_cooling_device *cdev, Loading @@ -78,7 +100,7 @@ static int cxip_lm_set_cur_state(struct thermal_cooling_device *cdev, if (cxip_dev->state == state) return 0; cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, state); cxip_lm_therm_vote_apply(cxip_dev, state); cxip_dev->state = state; return ret; Loading Loading @@ -117,6 +139,49 @@ static int cxip_lm_cdev_remove(struct platform_device *pdev) return 0; } static int cxip_lm_get_devicetree_data(struct platform_device *pdev, struct cxip_lm_cooling_device *cxip_dev, struct device_node *np) { int ret = 0; ret = of_property_read_u32(np, "qcom,thermal-client-offset", &cxip_dev->therm_clnt); if (ret) { dev_dbg(&pdev->dev, "error for qcom,thermal-client-offset. ret:%d\n", ret); cxip_dev->therm_clnt = 0; ret = 0; return ret; } ret = of_property_count_u32_elems(np, "qcom,bypass-client-list"); if (ret <= 0) { dev_dbg(&pdev->dev, "Invalid number of clients err:%d\n", ret); ret = 0; return ret; } cxip_dev->bypass_clnt_cnt = ret; cxip_dev->bypass_clnts = devm_kcalloc(&pdev->dev, cxip_dev->bypass_clnt_cnt, sizeof(*cxip_dev->bypass_clnts), GFP_KERNEL); if (!cxip_dev->bypass_clnts) return -ENOMEM; ret = of_property_read_u32_array(np, "qcom,bypass-client-list", cxip_dev->bypass_clnts, cxip_dev->bypass_clnt_cnt); if (ret) { dev_dbg(&pdev->dev, "bypass client list err:%d, cnt:%d\n", ret, cxip_dev->bypass_clnt_cnt); cxip_dev->bypass_clnt_cnt = 0; ret = 0; } return ret; } static int cxip_lm_cdev_probe(struct platform_device *pdev) { struct cxip_lm_cooling_device *cxip_dev = NULL; Loading @@ -135,6 +200,10 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) if (!cxip_dev) return -ENOMEM; ret = cxip_lm_get_devicetree_data(pdev, cxip_dev, np); if (ret) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, Loading @@ -149,12 +218,11 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) return -ENOMEM; } cxip_lm_initialize_cxip_hw(cxip_dev->cx_ip_reg_base); cxip_lm_initialize_cxip_hw(cxip_dev); /* Set thermal vote till we get first vote from TF */ cxip_dev->state = true; cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, cxip_dev->state); cxip_lm_therm_vote_apply(cxip_dev, cxip_dev->state); strlcpy(cxip_dev->cdev_name, np->name, THERMAL_NAME_LENGTH); cxip_dev->cool_dev = thermal_of_cooling_device_register( Loading Loading
Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt +20 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,24 @@ Required Parameters: register address of the CX IPEAK LM hardware and 'b' is the size of the peripheral address space. - qcom,thermal-client-offset: Usage: Optional Value type: <value in hex> Definition: This property is required for CX IP LM v1.1 and above hardware. Must contain offset from CX IPEAK LM reg base for thermal client voting. If this property is not defined, then CX IPEAK cooling device will use legacy CXIP LM hardware offset registers. - qcom,bypass-client-list: Usage: Optional Value type: <value in hex> Definition: This property is required for CX IP LM v1.1 and above hardware. Must contain array of offsets from CX IPEAK LM reg base for clients those are not participating voting to CXIP LM hardware. This property makes sense only when thermal-client is defined. - #cooling-cells: Usage: required Value type: <integer> Loading @@ -29,5 +47,7 @@ Example: cxip_cdev: cxip-cdev@1fed000 { compatible = "qcom,cxip-lm-cooling-device"; reg = <0x1fed000 0x24>; qcom,thermal-client-offset = <0x8000>; qcom,bypass-client-list = <0x2004 0x3004>; #cooling-cells = <2>; };
drivers/thermal/qcom/cx_ipeak_cdev.c +82 −14 Original line number Diff line number Diff line Loading @@ -35,27 +35,49 @@ struct cxip_lm_cooling_device { struct thermal_cooling_device *cool_dev; char cdev_name[THERMAL_NAME_LENGTH]; void *cx_ip_reg_base; unsigned int therm_clnt; unsigned int *bypass_clnts; unsigned int bypass_clnt_cnt; bool state; }; static void cxip_lm_therm_vote_apply(void *reg_base, bool vote) static void cxip_lm_therm_vote_apply(struct cxip_lm_cooling_device *cxip_dev, bool vote) { writel_relaxed(CXIP_LM_THERM_VOTE_VAL, reg_base + (vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR)); int vote_offset = 0, val = 0, sts_offset = 0; if (!cxip_dev->therm_clnt) { vote_offset = vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR; val = CXIP_LM_THERM_VOTE_VAL; sts_offset = CXIP_LM_VOTE_STATUS; } else { vote_offset = cxip_dev->therm_clnt; val = vote ? 0x1 : 0x0; sts_offset = vote_offset; } pr_debug("%s vote for cxip_lm. Agg.vote:0x%x\n", writel_relaxed(val, cxip_dev->cx_ip_reg_base + vote_offset); pr_debug("%s vote for cxip_lm. vote:0x%x\n", vote ? "Applied" : "Cleared", readl_relaxed(reg_base + CXIP_LM_VOTE_STATUS)); readl_relaxed(cxip_dev->cx_ip_reg_base + sts_offset)); } static void cxip_lm_initialize_cxip_hw(void *reg_base) static void cxip_lm_initialize_cxip_hw(struct cxip_lm_cooling_device *cxip_dev) { /* Enable CXIP LM HW */ writel_relaxed(CXIP_LM_FEATURE_EN_VAL, reg_base + CXIP_LM_FEATURE_EN); int i = 0; /* Set CXIP LM proxy vote for clients who are not participating */ writel_relaxed(CXIP_LM_BYPASS_VAL, reg_base + CXIP_LM_BYPASS); if (cxip_dev->bypass_clnt_cnt) for (i = 0; i < cxip_dev->bypass_clnt_cnt; i++) writel_relaxed(0x1, cxip_dev->cx_ip_reg_base + cxip_dev->bypass_clnts[i]); else if (!cxip_dev->therm_clnt) writel_relaxed(CXIP_LM_BYPASS_VAL, cxip_dev->cx_ip_reg_base + CXIP_LM_BYPASS); /* Enable CXIP LM HW */ writel_relaxed(CXIP_LM_FEATURE_EN_VAL, cxip_dev->cx_ip_reg_base + CXIP_LM_FEATURE_EN); } static int cxip_lm_get_max_state(struct thermal_cooling_device *cdev, Loading @@ -78,7 +100,7 @@ static int cxip_lm_set_cur_state(struct thermal_cooling_device *cdev, if (cxip_dev->state == state) return 0; cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, state); cxip_lm_therm_vote_apply(cxip_dev, state); cxip_dev->state = state; return ret; Loading Loading @@ -117,6 +139,49 @@ static int cxip_lm_cdev_remove(struct platform_device *pdev) return 0; } static int cxip_lm_get_devicetree_data(struct platform_device *pdev, struct cxip_lm_cooling_device *cxip_dev, struct device_node *np) { int ret = 0; ret = of_property_read_u32(np, "qcom,thermal-client-offset", &cxip_dev->therm_clnt); if (ret) { dev_dbg(&pdev->dev, "error for qcom,thermal-client-offset. ret:%d\n", ret); cxip_dev->therm_clnt = 0; ret = 0; return ret; } ret = of_property_count_u32_elems(np, "qcom,bypass-client-list"); if (ret <= 0) { dev_dbg(&pdev->dev, "Invalid number of clients err:%d\n", ret); ret = 0; return ret; } cxip_dev->bypass_clnt_cnt = ret; cxip_dev->bypass_clnts = devm_kcalloc(&pdev->dev, cxip_dev->bypass_clnt_cnt, sizeof(*cxip_dev->bypass_clnts), GFP_KERNEL); if (!cxip_dev->bypass_clnts) return -ENOMEM; ret = of_property_read_u32_array(np, "qcom,bypass-client-list", cxip_dev->bypass_clnts, cxip_dev->bypass_clnt_cnt); if (ret) { dev_dbg(&pdev->dev, "bypass client list err:%d, cnt:%d\n", ret, cxip_dev->bypass_clnt_cnt); cxip_dev->bypass_clnt_cnt = 0; ret = 0; } return ret; } static int cxip_lm_cdev_probe(struct platform_device *pdev) { struct cxip_lm_cooling_device *cxip_dev = NULL; Loading @@ -135,6 +200,10 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) if (!cxip_dev) return -ENOMEM; ret = cxip_lm_get_devicetree_data(pdev, cxip_dev, np); if (ret) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, Loading @@ -149,12 +218,11 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) return -ENOMEM; } cxip_lm_initialize_cxip_hw(cxip_dev->cx_ip_reg_base); cxip_lm_initialize_cxip_hw(cxip_dev); /* Set thermal vote till we get first vote from TF */ cxip_dev->state = true; cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, cxip_dev->state); cxip_lm_therm_vote_apply(cxip_dev, cxip_dev->state); strlcpy(cxip_dev->cdev_name, np->name, THERMAL_NAME_LENGTH); cxip_dev->cool_dev = thermal_of_cooling_device_register( Loading