1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/bitfield.h> 7 #include <linux/clk.h> 8 #include <linux/interconnect-provider.h> 9 #include <linux/io.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/of_device.h> 13 #include <linux/platform_device.h> 14 15 #include <dt-bindings/interconnect/qcom,osm-l3.h> 16 17 #include "sc7180.h" 18 #include "sdm845.h" 19 20 #define LUT_MAX_ENTRIES 40U 21 #define LUT_SRC GENMASK(31, 30) 22 #define LUT_L_VAL GENMASK(7, 0) 23 #define LUT_ROW_SIZE 32 24 #define CLK_HW_DIV 2 25 26 /* Register offsets */ 27 #define REG_ENABLE 0x0 28 #define REG_FREQ_LUT 0x110 29 #define REG_PERF_STATE 0x920 30 31 #define OSM_L3_MAX_LINKS 1 32 33 #define to_qcom_provider(_provider) \ 34 container_of(_provider, struct qcom_osm_l3_icc_provider, provider) 35 36 struct qcom_osm_l3_icc_provider { 37 void __iomem *base; 38 unsigned int max_state; 39 unsigned long lut_tables[LUT_MAX_ENTRIES]; 40 struct icc_provider provider; 41 }; 42 43 /** 44 * struct qcom_icc_node - Qualcomm specific interconnect nodes 45 * @name: the node name used in debugfs 46 * @links: an array of nodes where we can go next while traversing 47 * @id: a unique node identifier 48 * @num_links: the total number of @links 49 * @buswidth: width of the interconnect between a node and the bus 50 */ 51 struct qcom_icc_node { 52 const char *name; 53 u16 links[OSM_L3_MAX_LINKS]; 54 u16 id; 55 u16 num_links; 56 u16 buswidth; 57 }; 58 59 struct qcom_icc_desc { 60 struct qcom_icc_node **nodes; 61 size_t num_nodes; 62 }; 63 64 #define DEFINE_QNODE(_name, _id, _buswidth, ...) \ 65 static struct qcom_icc_node _name = { \ 66 .name = #_name, \ 67 .id = _id, \ 68 .buswidth = _buswidth, \ 69 .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ 70 .links = { __VA_ARGS__ }, \ 71 } 72 73 DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3); 74 DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16); 75 76 static struct qcom_icc_node *sdm845_osm_l3_nodes[] = { 77 [MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3, 78 [SLAVE_OSM_L3] = &sdm845_osm_l3, 79 }; 80 81 const static struct qcom_icc_desc sdm845_icc_osm_l3 = { 82 .nodes = sdm845_osm_l3_nodes, 83 .num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes), 84 }; 85 86 DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3); 87 DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16); 88 89 static struct qcom_icc_node *sc7180_osm_l3_nodes[] = { 90 [MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3, 91 [SLAVE_OSM_L3] = &sc7180_osm_l3, 92 }; 93 94 const static struct qcom_icc_desc sc7180_icc_osm_l3 = { 95 .nodes = sc7180_osm_l3_nodes, 96 .num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes), 97 }; 98 99 static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) 100 { 101 struct qcom_osm_l3_icc_provider *qp; 102 struct icc_provider *provider; 103 struct qcom_icc_node *qn; 104 struct icc_node *n; 105 unsigned int index; 106 u32 agg_peak = 0; 107 u32 agg_avg = 0; 108 u64 rate; 109 110 qn = src->data; 111 provider = src->provider; 112 qp = to_qcom_provider(provider); 113 114 list_for_each_entry(n, &provider->nodes, node_list) 115 provider->aggregate(n, 0, n->avg_bw, n->peak_bw, 116 &agg_avg, &agg_peak); 117 118 rate = max(agg_avg, agg_peak); 119 rate = icc_units_to_bps(rate); 120 do_div(rate, qn->buswidth); 121 122 for (index = 0; index < qp->max_state - 1; index++) { 123 if (qp->lut_tables[index] >= rate) 124 break; 125 } 126 127 writel_relaxed(index, qp->base + REG_PERF_STATE); 128 129 return 0; 130 } 131 132 static int qcom_osm_l3_remove(struct platform_device *pdev) 133 { 134 struct qcom_osm_l3_icc_provider *qp = platform_get_drvdata(pdev); 135 136 icc_nodes_remove(&qp->provider); 137 return icc_provider_del(&qp->provider); 138 } 139 140 static int qcom_osm_l3_probe(struct platform_device *pdev) 141 { 142 u32 info, src, lval, i, prev_freq = 0, freq; 143 static unsigned long hw_rate, xo_rate; 144 struct qcom_osm_l3_icc_provider *qp; 145 const struct qcom_icc_desc *desc; 146 struct icc_onecell_data *data; 147 struct icc_provider *provider; 148 struct qcom_icc_node **qnodes; 149 struct icc_node *node; 150 size_t num_nodes; 151 struct clk *clk; 152 int ret; 153 154 clk = clk_get(&pdev->dev, "xo"); 155 if (IS_ERR(clk)) 156 return PTR_ERR(clk); 157 158 xo_rate = clk_get_rate(clk); 159 clk_put(clk); 160 161 clk = clk_get(&pdev->dev, "alternate"); 162 if (IS_ERR(clk)) 163 return PTR_ERR(clk); 164 165 hw_rate = clk_get_rate(clk) / CLK_HW_DIV; 166 clk_put(clk); 167 168 qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); 169 if (!qp) 170 return -ENOMEM; 171 172 qp->base = devm_platform_ioremap_resource(pdev, 0); 173 if (IS_ERR(qp->base)) 174 return PTR_ERR(qp->base); 175 176 /* HW should be in enabled state to proceed */ 177 if (!(readl_relaxed(qp->base + REG_ENABLE) & 0x1)) { 178 dev_err(&pdev->dev, "error hardware not enabled\n"); 179 return -ENODEV; 180 } 181 182 for (i = 0; i < LUT_MAX_ENTRIES; i++) { 183 info = readl_relaxed(qp->base + REG_FREQ_LUT + 184 i * LUT_ROW_SIZE); 185 src = FIELD_GET(LUT_SRC, info); 186 lval = FIELD_GET(LUT_L_VAL, info); 187 if (src) 188 freq = xo_rate * lval; 189 else 190 freq = hw_rate; 191 192 /* Two of the same frequencies signify end of table */ 193 if (i > 0 && prev_freq == freq) 194 break; 195 196 dev_dbg(&pdev->dev, "index=%d freq=%d\n", i, freq); 197 198 qp->lut_tables[i] = freq; 199 prev_freq = freq; 200 } 201 qp->max_state = i; 202 203 desc = device_get_match_data(&pdev->dev); 204 if (!desc) 205 return -EINVAL; 206 207 qnodes = desc->nodes; 208 num_nodes = desc->num_nodes; 209 210 data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); 211 if (!data) 212 return -ENOMEM; 213 214 provider = &qp->provider; 215 provider->dev = &pdev->dev; 216 provider->set = qcom_icc_set; 217 provider->aggregate = icc_std_aggregate; 218 provider->xlate = of_icc_xlate_onecell; 219 INIT_LIST_HEAD(&provider->nodes); 220 provider->data = data; 221 222 ret = icc_provider_add(provider); 223 if (ret) { 224 dev_err(&pdev->dev, "error adding interconnect provider\n"); 225 return ret; 226 } 227 228 for (i = 0; i < num_nodes; i++) { 229 size_t j; 230 231 node = icc_node_create(qnodes[i]->id); 232 if (IS_ERR(node)) { 233 ret = PTR_ERR(node); 234 goto err; 235 } 236 237 node->name = qnodes[i]->name; 238 node->data = qnodes[i]; 239 icc_node_add(node, provider); 240 241 for (j = 0; j < qnodes[i]->num_links; j++) 242 icc_link_create(node, qnodes[i]->links[j]); 243 244 data->nodes[i] = node; 245 } 246 data->num_nodes = num_nodes; 247 248 platform_set_drvdata(pdev, qp); 249 250 return 0; 251 err: 252 icc_nodes_remove(provider); 253 icc_provider_del(provider); 254 255 return ret; 256 } 257 258 static const struct of_device_id osm_l3_of_match[] = { 259 { .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 }, 260 { .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 }, 261 { } 262 }; 263 MODULE_DEVICE_TABLE(of, osm_l3_of_match); 264 265 static struct platform_driver osm_l3_driver = { 266 .probe = qcom_osm_l3_probe, 267 .remove = qcom_osm_l3_remove, 268 .driver = { 269 .name = "osm-l3", 270 .of_match_table = osm_l3_of_match, 271 }, 272 }; 273 module_platform_driver(osm_l3_driver); 274 275 MODULE_DESCRIPTION("Qualcomm OSM L3 interconnect driver"); 276 MODULE_LICENSE("GPL v2"); 277