/* Copyright (c) 2014, 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) "AXI: %s(): " fmt, __func__ #include #include #include #include #include #include #include #include #include #include #include #include "msm_bus_core.h" #include "msm_bus_adhoc.h" #define DEFAULT_QOS_FREQ 19200 #define DEFAULT_UTIL_FACT 100 #define DEFAULT_VRAIL_COMP 100 static int get_qos_mode(struct platform_device *pdev, struct device_node *node, const char *qos_mode) { const char *qos_names[] = {"fixed", "limiter", "bypass", "regulator"}; int i = 0; int ret = -1; if (!qos_mode) goto exit_get_qos_mode; for (i = 0; i < ARRAY_SIZE(qos_names); i++) { if (!strcmp(qos_mode, qos_names[i])) break; } if (i == ARRAY_SIZE(qos_names)) dev_err(&pdev->dev, "Cannot match mode qos %s using Bypass", qos_mode); else ret = i; exit_get_qos_mode: return ret; } static int *get_arr(struct platform_device *pdev, struct device_node *node, const char *prop, int *nports) { int size = 0, ret; int *arr = NULL; if (of_get_property(node, prop, &size)) { *nports = size / sizeof(int); } else { dev_dbg(&pdev->dev, "Property %s not available\n", prop); *nports = 0; return NULL; } arr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if ((size > 0) && ZERO_OR_NULL_PTR(arr)) { dev_err(&pdev->dev, "Error: Failed to alloc mem for %s\n", prop); return NULL; } ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports); if (ret) { dev_err(&pdev->dev, "Error in reading property: %s\n", prop); goto arr_err; } return arr; arr_err: devm_kfree(&pdev->dev, arr); return NULL; } static struct msm_bus_fab_device_type *get_fab_device_info( struct device_node *dev_node, struct platform_device *pdev) { struct msm_bus_fab_device_type *fab_dev; unsigned int ret; struct resource *res; const char *base_name; fab_dev = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_fab_device_type), GFP_KERNEL); if (!fab_dev) { dev_err(&pdev->dev, "Error: Unable to allocate memory for fab_dev\n"); return NULL; } ret = of_property_read_string(dev_node, "qcom,base-name", &base_name); if (ret) { dev_err(&pdev->dev, "Error: Unable to get base address name\n"); goto fab_dev_err; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, base_name); if (!res) { dev_err(&pdev->dev, "Error getting qos base addr %s\n", base_name); goto fab_dev_err; } fab_dev->pqos_base = res->start; fab_dev->qos_range = resource_size(res); fab_dev->bypass_qos_prg = of_property_read_bool(dev_node, "qcom,bypass-qos-prg"); ret = of_property_read_u32(dev_node, "qcom,base-offset", &fab_dev->base_offset); if (ret) dev_dbg(&pdev->dev, "Bus base offset is missing\n"); ret = of_property_read_u32(dev_node, "qcom,qos-off", &fab_dev->qos_off); if (ret) dev_dbg(&pdev->dev, "Bus qos off is missing\n"); ret = of_property_read_u32(dev_node, "qcom,bus-type", &fab_dev->bus_type); if (ret) { dev_warn(&pdev->dev, "Bus type is missing\n"); goto fab_dev_err; } ret = of_property_read_u32(dev_node, "qcom,qos-freq", &fab_dev->qos_freq); if (ret) { dev_dbg(&pdev->dev, "Bus qos freq is missing\n"); fab_dev->qos_freq = DEFAULT_QOS_FREQ; } ret = of_property_read_u32(dev_node, "qcom,util-fact", &fab_dev->util_fact); if (ret) { dev_info(&pdev->dev, "Util-fact is missing, default to %d\n", DEFAULT_UTIL_FACT); fab_dev->util_fact = DEFAULT_UTIL_FACT; } ret = of_property_read_u32(dev_node, "qcom,vrail-comp", &fab_dev->vrail_comp); if (ret) { dev_info(&pdev->dev, "Vrail-comp is missing, default to %d\n", DEFAULT_VRAIL_COMP); fab_dev->vrail_comp = DEFAULT_VRAIL_COMP; } return fab_dev; fab_dev_err: devm_kfree(&pdev->dev, fab_dev); fab_dev = 0; return NULL; } static void get_qos_params( struct device_node * const dev_node, struct platform_device * const pdev, struct msm_bus_node_info_type *node_info) { const char *qos_mode = NULL; unsigned int ret; unsigned int temp; ret = of_property_read_string(dev_node, "qcom,qos-mode", &qos_mode); if (ret) node_info->qos_params.mode = -1; else node_info->qos_params.mode = get_qos_mode(pdev, dev_node, qos_mode); of_property_read_u32(dev_node, "qcom,prio-lvl", &node_info->qos_params.prio_lvl); of_property_read_u32(dev_node, "qcom,prio1", &node_info->qos_params.prio1); of_property_read_u32(dev_node, "qcom,prio0", &node_info->qos_params.prio0); of_property_read_u32(dev_node, "qcom,prio-rd", &node_info->qos_params.prio_rd); of_property_read_u32(dev_node, "qcom,prio-wr", &node_info->qos_params.prio_wr); of_property_read_u32(dev_node, "qcom,gp", &node_info->qos_params.gp); of_property_read_u32(dev_node, "qcom,thmp", &node_info->qos_params.thmp); of_property_read_u32(dev_node, "qcom,ws", &node_info->qos_params.ws); ret = of_property_read_u32(dev_node, "qcom,bw_buffer", &temp); if (ret) node_info->qos_params.bw_buffer = 0; else node_info->qos_params.bw_buffer = KBTOB(temp); } static struct msm_bus_node_info_type *get_node_info_data( struct device_node * const dev_node, struct platform_device * const pdev) { struct msm_bus_node_info_type *node_info; unsigned int ret; int size; int i; struct device_node *con_node; struct device_node *bus_dev; node_info = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_node_info_type), GFP_KERNEL); if (!node_info) { dev_err(&pdev->dev, "Error: Unable to allocate memory for node_info\n"); return NULL; } ret = of_property_read_u32(dev_node, "cell-id", &node_info->id); if (ret) { dev_warn(&pdev->dev, "Bus node is missing cell-id\n"); goto node_info_err; } ret = of_property_read_string(dev_node, "label", &node_info->name); if (ret) { dev_warn(&pdev->dev, "Bus node is missing name\n"); goto node_info_err; } node_info->qport = get_arr(pdev, dev_node, "qcom,qport", &node_info->num_qports); if (of_get_property(dev_node, "qcom,connections", &size)) { node_info->num_connections = size / sizeof(int); node_info->connections = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); } else { node_info->num_connections = 0; node_info->connections = 0; } for (i = 0; i < node_info->num_connections; i++) { con_node = of_parse_phandle(dev_node, "qcom,connections", i); if (IS_ERR_OR_NULL(con_node)) goto node_info_err; if (of_property_read_u32(con_node, "cell-id", &node_info->connections[i])) goto node_info_err; of_node_put(con_node); } if (of_get_property(dev_node, "qcom,blacklist", &size)) { node_info->num_blist = size/sizeof(u32); node_info->black_listed_connections = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); } else { node_info->num_blist = 0; node_info->black_listed_connections = 0; } for (i = 0; i < node_info->num_blist; i++) { con_node = of_parse_phandle(dev_node, "qcom,blacklist", i); if (IS_ERR_OR_NULL(con_node)) goto node_info_err; if (of_property_read_u32(con_node, "cell-id", &node_info->black_listed_connections[i])) goto node_info_err; of_node_put(con_node); } bus_dev = of_parse_phandle(dev_node, "qcom,bus-dev", 0); if (!IS_ERR_OR_NULL(bus_dev)) { if (of_property_read_u32(bus_dev, "cell-id", &node_info->bus_device_id)) { dev_err(&pdev->dev, "Can't find bus device. Node %d", node_info->id); goto node_info_err; } of_node_put(bus_dev); } else dev_dbg(&pdev->dev, "Can't find bdev phandle for %d", node_info->id); node_info->is_fab_dev = of_property_read_bool(dev_node, "qcom,fab-dev"); node_info->virt_dev = of_property_read_bool(dev_node, "qcom,virt-dev"); ret = of_property_read_u32(dev_node, "qcom,buswidth", &node_info->buswidth); if (ret) { dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id); node_info->buswidth = 8; } ret = of_property_read_u32(dev_node, "qcom,mas-rpm-id", &node_info->mas_rpm_id); if (ret) { dev_dbg(&pdev->dev, "mas rpm id is missing\n"); node_info->mas_rpm_id = -1; } ret = of_property_read_u32(dev_node, "qcom,slv-rpm-id", &node_info->slv_rpm_id); if (ret) { dev_dbg(&pdev->dev, "slv rpm id is missing\n"); node_info->slv_rpm_id = -1; } ret = of_property_read_u32(dev_node, "qcom,util-fact", &node_info->util_fact); if (ret) node_info->util_fact = 0; ret = of_property_read_u32(dev_node, "qcom,vrail-comp", &node_info->vrail_comp); if (ret) node_info->vrail_comp = 0; get_qos_params(dev_node, pdev, node_info); return node_info; node_info_err: devm_kfree(&pdev->dev, node_info); node_info = 0; return NULL; } static unsigned int get_bus_node_device_data( struct device_node * const dev_node, struct platform_device * const pdev, struct msm_bus_node_device_type * const node_device) { node_device->node_info = get_node_info_data(dev_node, pdev); if (IS_ERR_OR_NULL(node_device->node_info)) { dev_err(&pdev->dev, "Error: Node info missing\n"); return -ENODATA; } node_device->ap_owned = of_property_read_bool(dev_node, "qcom,ap-owned"); if (node_device->node_info->is_fab_dev) { dev_err(&pdev->dev, "Dev %d\n", node_device->node_info->id); if (!node_device->node_info->virt_dev) { node_device->fabdev = get_fab_device_info(dev_node, pdev); if (IS_ERR_OR_NULL(node_device->fabdev)) { dev_err(&pdev->dev, "Error: Fabric device info missing\n"); devm_kfree(&pdev->dev, node_device->node_info); return -ENODATA; } } node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node, "bus_clk"); if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk)) dev_err(&pdev->dev, "%s:Failed to get bus clk for bus%d ctx%d", __func__, node_device->node_info->id, DUAL_CTX); node_device->clk[ACTIVE_CTX].clk = of_clk_get_by_name(dev_node, "bus_a_clk"); if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk)) dev_err(&pdev->dev, "Failed to get bus clk for bus%d ctx%d", node_device->node_info->id, ACTIVE_CTX); if (msmbus_coresight_init_adhoc(pdev, dev_node)) dev_warn(&pdev->dev, "Coresight support absent for bus: %d\n", node_device->node_info->id); } else { node_device->qos_clk.clk = of_clk_get_by_name(dev_node, "bus_qos_clk"); if (IS_ERR_OR_NULL(node_device->qos_clk.clk)) dev_dbg(&pdev->dev, "%s:Failed to get bus qos clk for mas%d", __func__, node_device->node_info->id); node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node, "node_clk"); if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk)) dev_dbg(&pdev->dev, "%s:Failed to get bus clk for bus%d ctx%d", __func__, node_device->node_info->id, DUAL_CTX); } return 0; } struct msm_bus_device_node_registration *msm_bus_of_to_pdata(struct platform_device *pdev) { struct device_node *of_node, *child_node; struct msm_bus_device_node_registration *pdata; unsigned int i = 0, j; unsigned int ret; if (!pdev) { pr_err("Error: Null platform device\n"); return NULL; } of_node = pdev->dev.of_node; pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_device_node_registration), GFP_KERNEL); if (!pdata) { dev_err(&pdev->dev, "Error: Memory allocation for pdata failed\n"); return NULL; } pdata->num_devices = of_get_child_count(of_node); pdata->info = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_node_device_type) * pdata->num_devices, GFP_KERNEL); if (!pdata->info) { dev_err(&pdev->dev, "Error: Memory allocation for pdata->info failed\n"); goto node_reg_err; } ret = 0; for_each_child_of_node(of_node, child_node) { ret = get_bus_node_device_data(child_node, pdev, &pdata->info[i]); if (ret) { dev_err(&pdev->dev, "Error: unable to initialize bus nodes\n"); goto node_reg_err_1; } i++; } dev_dbg(&pdev->dev, "bus topology:\n"); for (i = 0; i < pdata->num_devices; i++) { dev_dbg(&pdev->dev, "id %d\nnum_qports %d\nnum_connections %d", pdata->info[i].node_info->id, pdata->info[i].node_info->num_qports, pdata->info[i].node_info->num_connections); dev_dbg(&pdev->dev, "\nbus_device_id %d\n buswidth %d\n", pdata->info[i].node_info->bus_device_id, pdata->info[i].node_info->buswidth); for (j = 0; j < pdata->info[i].node_info->num_connections; j++) { dev_dbg(&pdev->dev, "connection[%d]: %d\n", j, pdata->info[i].node_info->connections[j]); } for (j = 0; j < pdata->info[i].node_info->num_blist; j++) { dev_dbg(&pdev->dev, "black_listed_node[%d]: %d\n", j, pdata->info[i].node_info-> black_listed_connections[j]); } if (pdata->info[i].fabdev) dev_dbg(&pdev->dev, "base_addr %zu\nbus_type %d\n", (size_t)pdata->info[i]. fabdev->pqos_base, pdata->info[i].fabdev->bus_type); } return pdata; node_reg_err_1: devm_kfree(&pdev->dev, pdata->info); node_reg_err: devm_kfree(&pdev->dev, pdata); pdata = NULL; return NULL; } static int msm_bus_of_get_ids(struct platform_device *pdev, struct device_node *dev_node, int **dev_ids, int *num_ids, char *prop_name) { int ret = 0; int size, i; struct device_node *rule_node; int *ids = NULL; if (of_get_property(dev_node, prop_name, &size)) { *num_ids = size / sizeof(int); ids = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); } else { dev_err(&pdev->dev, "No rule nodes, skipping node"); ret = -ENXIO; goto exit_get_ids; } *dev_ids = ids; for (i = 0; i < *num_ids; i++) { rule_node = of_parse_phandle(dev_node, prop_name, i); if (IS_ERR_OR_NULL(rule_node)) { dev_err(&pdev->dev, "Can't get rule node id"); ret = -ENXIO; goto err_get_ids; } if (of_property_read_u32(rule_node, "cell-id", &ids[i])) { dev_err(&pdev->dev, "Can't get rule node id"); ret = -ENXIO; goto err_get_ids; } of_node_put(rule_node); } exit_get_ids: return ret; err_get_ids: devm_kfree(&pdev->dev, ids); of_node_put(rule_node); ids = NULL; return ret; } int msm_bus_of_get_static_rules(struct platform_device *pdev, struct bus_rule_type **static_rules) { int ret = 0; struct device_node *of_node, *child_node; int num_rules = 0; int rule_idx = 0; int bw_fld = 0; int i; struct bus_rule_type *static_rule = NULL; of_node = pdev->dev.of_node; num_rules = of_get_child_count(of_node); static_rule = devm_kzalloc(&pdev->dev, sizeof(struct bus_rule_type) * num_rules, GFP_KERNEL); if (IS_ERR_OR_NULL(static_rule)) { ret = -ENOMEM; goto exit_static_rules; } *static_rules = static_rule; for_each_child_of_node(of_node, child_node) { ret = msm_bus_of_get_ids(pdev, child_node, &static_rule[rule_idx].src_id, &static_rule[rule_idx].num_src, "qcom,src-nodes"); ret = msm_bus_of_get_ids(pdev, child_node, &static_rule[rule_idx].dst_node, &static_rule[rule_idx].num_dst, "qcom,dest-node"); ret = of_property_read_u32(child_node, "qcom,src-field", &static_rule[rule_idx].src_field); if (ret) { dev_err(&pdev->dev, "src-field missing"); ret = -ENXIO; goto err_static_rules; } ret = of_property_read_u32(child_node, "qcom,src-op", &static_rule[rule_idx].op); if (ret) { dev_err(&pdev->dev, "src-op missing"); ret = -ENXIO; goto err_static_rules; } ret = of_property_read_u32(child_node, "qcom,mode", &static_rule[rule_idx].mode); if (ret) { dev_err(&pdev->dev, "mode missing"); ret = -ENXIO; goto err_static_rules; } ret = of_property_read_u32(child_node, "qcom,thresh", &bw_fld); if (ret) { dev_err(&pdev->dev, "thresh missing"); ret = -ENXIO; goto err_static_rules; } else static_rule[rule_idx].thresh = KBTOB(bw_fld); ret = of_property_read_u32(child_node, "qcom,dest-bw", &bw_fld); if (ret) static_rule[rule_idx].dst_bw = 0; else static_rule[rule_idx].dst_bw = KBTOB(bw_fld); rule_idx++; } ret = rule_idx; exit_static_rules: return ret; err_static_rules: for (i = 0; i < num_rules; i++) { if (!IS_ERR_OR_NULL(static_rule)) { if (!IS_ERR_OR_NULL(static_rule[i].src_id)) devm_kfree(&pdev->dev, static_rule[i].src_id); if (!IS_ERR_OR_NULL(static_rule[i].dst_node)) devm_kfree(&pdev->dev, static_rule[i].dst_node); devm_kfree(&pdev->dev, static_rule); } } devm_kfree(&pdev->dev, *static_rules); static_rules = NULL; return ret; }