0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/module.h>
0011 #include <linux/devfreq-event.h>
0012 #include <linux/kernel.h>
0013 #include <linux/of_address.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016
0017 #include "exynos-nocp.h"
0018
0019 struct exynos_nocp {
0020 struct devfreq_event_dev *edev;
0021 struct devfreq_event_desc desc;
0022
0023 struct device *dev;
0024
0025 struct regmap *regmap;
0026 struct clk *clk;
0027 };
0028
0029
0030
0031
0032 static int exynos_nocp_set_event(struct devfreq_event_dev *edev)
0033 {
0034 struct exynos_nocp *nocp = devfreq_event_get_drvdata(edev);
0035 int ret;
0036
0037
0038 ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
0039 NOCP_MAIN_CTL_STATEN_MASK, 0);
0040 if (ret < 0) {
0041 dev_err(nocp->dev, "failed to disable the NoC probe device\n");
0042 return ret;
0043 }
0044
0045
0046 ret = regmap_write(nocp->regmap, NOCP_STAT_PERIOD, 0x0);
0047 if (ret < 0)
0048 goto out;
0049
0050
0051 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_0_SRC,
0052 NOCP_CNT_SRC_INTEVENT_MASK,
0053 NOCP_CNT_SRC_INTEVENT_BYTE_MASK);
0054 if (ret < 0)
0055 goto out;
0056
0057 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_1_SRC,
0058 NOCP_CNT_SRC_INTEVENT_MASK,
0059 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK);
0060 if (ret < 0)
0061 goto out;
0062
0063 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_2_SRC,
0064 NOCP_CNT_SRC_INTEVENT_MASK,
0065 NOCP_CNT_SRC_INTEVENT_CYCLE_MASK);
0066 if (ret < 0)
0067 goto out;
0068
0069 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_3_SRC,
0070 NOCP_CNT_SRC_INTEVENT_MASK,
0071 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK);
0072 if (ret < 0)
0073 goto out;
0074
0075
0076
0077 ret = regmap_write(nocp->regmap, NOCP_STAT_ALARM_MIN, 0x0);
0078 if (ret < 0)
0079 goto out;
0080
0081 ret = regmap_write(nocp->regmap, NOCP_STAT_ALARM_MAX, 0x0);
0082 if (ret < 0)
0083 goto out;
0084
0085
0086 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_0_ALARM_MODE,
0087 NOCP_CNT_ALARM_MODE_MASK,
0088 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
0089 if (ret < 0)
0090 goto out;
0091
0092 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_1_ALARM_MODE,
0093 NOCP_CNT_ALARM_MODE_MASK,
0094 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
0095 if (ret < 0)
0096 goto out;
0097
0098 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_2_ALARM_MODE,
0099 NOCP_CNT_ALARM_MODE_MASK,
0100 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
0101 if (ret < 0)
0102 goto out;
0103
0104 ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_3_ALARM_MODE,
0105 NOCP_CNT_ALARM_MODE_MASK,
0106 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
0107 if (ret < 0)
0108 goto out;
0109
0110
0111 ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
0112 NOCP_MAIN_CTL_STATEN_MASK | NOCP_MAIN_CTL_ALARMEN_MASK,
0113 NOCP_MAIN_CTL_STATEN_MASK | NOCP_MAIN_CTL_ALARMEN_MASK);
0114 if (ret < 0)
0115 goto out;
0116
0117
0118 ret = regmap_update_bits(nocp->regmap, NOCP_CFG_CTL,
0119 NOCP_CFG_CTL_GLOBALEN_MASK,
0120 NOCP_CFG_CTL_GLOBALEN_MASK);
0121 if (ret < 0)
0122 goto out;
0123
0124
0125 ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
0126 NOCP_MAIN_CTL_STATEN_MASK,
0127 NOCP_MAIN_CTL_STATEN_MASK);
0128 if (ret < 0)
0129 goto out;
0130
0131 return 0;
0132
0133 out:
0134
0135 if (regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
0136 NOCP_MAIN_CTL_STATEN_MASK, 0)) {
0137 dev_err(nocp->dev, "Failed to reset NoC probe device\n");
0138 }
0139
0140 return ret;
0141 }
0142
0143 static int exynos_nocp_get_event(struct devfreq_event_dev *edev,
0144 struct devfreq_event_data *edata)
0145 {
0146 struct exynos_nocp *nocp = devfreq_event_get_drvdata(edev);
0147 unsigned int counter[4];
0148 int ret;
0149
0150
0151 ret = regmap_read(nocp->regmap, NOCP_COUNTERS_0_VAL, &counter[0]);
0152 if (ret < 0)
0153 goto out;
0154
0155 ret = regmap_read(nocp->regmap, NOCP_COUNTERS_1_VAL, &counter[1]);
0156 if (ret < 0)
0157 goto out;
0158
0159 ret = regmap_read(nocp->regmap, NOCP_COUNTERS_2_VAL, &counter[2]);
0160 if (ret < 0)
0161 goto out;
0162
0163 ret = regmap_read(nocp->regmap, NOCP_COUNTERS_3_VAL, &counter[3]);
0164 if (ret < 0)
0165 goto out;
0166
0167 edata->load_count = ((counter[1] << 16) | counter[0]);
0168 edata->total_count = ((counter[3] << 16) | counter[2]);
0169
0170 dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
0171 edata->load_count, edata->total_count);
0172
0173 return 0;
0174
0175 out:
0176 dev_err(nocp->dev, "Failed to read the counter of NoC probe device\n");
0177
0178 return ret;
0179 }
0180
0181 static const struct devfreq_event_ops exynos_nocp_ops = {
0182 .set_event = exynos_nocp_set_event,
0183 .get_event = exynos_nocp_get_event,
0184 };
0185
0186 static const struct of_device_id exynos_nocp_id_match[] = {
0187 { .compatible = "samsung,exynos5420-nocp", },
0188 { },
0189 };
0190 MODULE_DEVICE_TABLE(of, exynos_nocp_id_match);
0191
0192 static struct regmap_config exynos_nocp_regmap_config = {
0193 .reg_bits = 32,
0194 .val_bits = 32,
0195 .reg_stride = 4,
0196 .max_register = NOCP_COUNTERS_3_VAL,
0197 };
0198
0199 static int exynos_nocp_parse_dt(struct platform_device *pdev,
0200 struct exynos_nocp *nocp)
0201 {
0202 struct device *dev = nocp->dev;
0203 struct device_node *np = dev->of_node;
0204 struct resource *res;
0205 void __iomem *base;
0206
0207 if (!np) {
0208 dev_err(dev, "failed to find devicetree node\n");
0209 return -EINVAL;
0210 }
0211
0212 nocp->clk = devm_clk_get(dev, "nocp");
0213 if (IS_ERR(nocp->clk))
0214 nocp->clk = NULL;
0215
0216
0217 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0218 base = devm_ioremap_resource(dev, res);
0219 if (IS_ERR(base))
0220 return PTR_ERR(base);
0221
0222 exynos_nocp_regmap_config.max_register = resource_size(res) - 4;
0223
0224 nocp->regmap = devm_regmap_init_mmio(dev, base,
0225 &exynos_nocp_regmap_config);
0226 if (IS_ERR(nocp->regmap)) {
0227 dev_err(dev, "failed to initialize regmap\n");
0228 return PTR_ERR(nocp->regmap);
0229 }
0230
0231 return 0;
0232 }
0233
0234 static int exynos_nocp_probe(struct platform_device *pdev)
0235 {
0236 struct device *dev = &pdev->dev;
0237 struct device_node *np = dev->of_node;
0238 struct exynos_nocp *nocp;
0239 int ret;
0240
0241 nocp = devm_kzalloc(&pdev->dev, sizeof(*nocp), GFP_KERNEL);
0242 if (!nocp)
0243 return -ENOMEM;
0244
0245 nocp->dev = &pdev->dev;
0246
0247
0248 ret = exynos_nocp_parse_dt(pdev, nocp);
0249 if (ret < 0) {
0250 dev_err(&pdev->dev,
0251 "failed to parse devicetree for resource\n");
0252 return ret;
0253 }
0254
0255
0256 nocp->desc.ops = &exynos_nocp_ops;
0257 nocp->desc.driver_data = nocp;
0258 nocp->desc.name = np->full_name;
0259 nocp->edev = devm_devfreq_event_add_edev(&pdev->dev, &nocp->desc);
0260 if (IS_ERR(nocp->edev)) {
0261 dev_err(&pdev->dev,
0262 "failed to add devfreq-event device\n");
0263 return PTR_ERR(nocp->edev);
0264 }
0265 platform_set_drvdata(pdev, nocp);
0266
0267 ret = clk_prepare_enable(nocp->clk);
0268 if (ret) {
0269 dev_err(&pdev->dev, "failed to prepare ppmu clock\n");
0270 return ret;
0271 }
0272
0273 pr_info("exynos-nocp: new NoC Probe device registered: %s\n",
0274 dev_name(dev));
0275
0276 return 0;
0277 }
0278
0279 static int exynos_nocp_remove(struct platform_device *pdev)
0280 {
0281 struct exynos_nocp *nocp = platform_get_drvdata(pdev);
0282
0283 clk_disable_unprepare(nocp->clk);
0284
0285 return 0;
0286 }
0287
0288 static struct platform_driver exynos_nocp_driver = {
0289 .probe = exynos_nocp_probe,
0290 .remove = exynos_nocp_remove,
0291 .driver = {
0292 .name = "exynos-nocp",
0293 .of_match_table = exynos_nocp_id_match,
0294 },
0295 };
0296 module_platform_driver(exynos_nocp_driver);
0297
0298 MODULE_DESCRIPTION("Exynos NoC (Network on Chip) Probe driver");
0299 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
0300 MODULE_LICENSE("GPL");