^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This program is free software; you can redistribute it and/or modify it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * under the terms and conditions of the GNU General Public License,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * version 2, as published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This program is distributed in the hope it will be useful, but WITHOUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/devfreq-event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define EVENT_BYTE 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define EVENT_CHAIN 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define START_EN BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define GLOBAL_EN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define START_GO BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define PROBE_MAINCTL 0x0008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PROBE_CFGCTL 0x000c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PROBE_STATPERIOD 0x0024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define PROBE_STATGO 0x0028
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct nocp_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u32 counter0_src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u32 counter0_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u32 counter1_src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) u32 counter1_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct rockchip_nocp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct devfreq_event_dev *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct devfreq_event_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) const struct nocp_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ktime_t time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int rockchip_nocp_enable(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) const struct nocp_info *info = nocp->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) void __iomem *reg_base = nocp->reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) writel_relaxed(GLOBAL_EN, reg_base + PROBE_CFGCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) writel_relaxed(START_EN, reg_base + PROBE_MAINCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) writel_relaxed(0, reg_base + PROBE_STATPERIOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) writel_relaxed(EVENT_BYTE, reg_base + info->counter0_src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) writel_relaxed(EVENT_CHAIN, reg_base + info->counter1_src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) writel_relaxed(START_GO, reg_base + PROBE_STATGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) nocp->time = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int rockchip_nocp_disable(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) const struct nocp_info *info = nocp->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) void __iomem *reg_base = nocp->reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) writel_relaxed(0, reg_base + PROBE_STATGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) writel_relaxed(0, reg_base + PROBE_MAINCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) writel_relaxed(0, reg_base + PROBE_CFGCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) writel_relaxed(0, reg_base + info->counter0_src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) writel_relaxed(0, reg_base + info->counter1_src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int rockchip_nocp_get_event(struct devfreq_event_dev *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct devfreq_event_data *edata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const struct nocp_info *info = nocp->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) void __iomem *reg_base = nocp->reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u32 counter = 0, counter0 = 0, counter1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int time_ms = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) time_ms = ktime_to_ms(ktime_sub(ktime_get(), nocp->time));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) counter0 = readl_relaxed(reg_base + info->counter0_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) counter1 = readl_relaxed(reg_base + info->counter1_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) counter = (counter0 & 0xffff) | ((counter1 & 0xffff) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) counter = counter / 1000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (time_ms > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) edata->load_count = (counter * 1000) / time_ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) writel_relaxed(START_GO, reg_base + PROBE_STATGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) nocp->time = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int rockchip_nocp_set_event(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static const struct devfreq_event_ops rockchip_nocp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .disable = rockchip_nocp_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .enable = rockchip_nocp_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .get_event = rockchip_nocp_get_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .set_event = rockchip_nocp_set_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static const struct nocp_info rk3288_nocp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .counter0_src = 0x138,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .counter0_val = 0x13c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .counter1_src = 0x14c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .counter1_val = 0x150,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static const struct nocp_info rk3568_nocp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .counter0_src = 0x204,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .counter0_val = 0x20c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .counter1_src = 0x214,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .counter1_val = 0x21c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static const struct of_device_id rockchip_nocp_id_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .compatible = "rockchip,rk3288-nocp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .data = (void *)&rk3288_nocp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .compatible = "rockchip,rk3368-nocp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .data = (void *)&rk3288_nocp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .compatible = "rockchip,rk3399-nocp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .data = (void *)&rk3288_nocp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .compatible = "rockchip,rk3568-nocp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .data = (void *)&rk3568_nocp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int rockchip_nocp_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct rockchip_nocp *nocp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct devfreq_event_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) match = of_match_device(rockchip_nocp_id_match, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!match || !match->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) dev_err(&pdev->dev, "missing nocp data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) nocp = devm_kzalloc(&pdev->dev, sizeof(*nocp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!nocp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) nocp->info = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) nocp->reg_base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (IS_ERR(nocp->reg_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return PTR_ERR(nocp->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) desc->ops = &rockchip_nocp_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) desc->driver_data = nocp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) desc->name = np->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) nocp->desc = desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) nocp->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) nocp->edev = devm_devfreq_event_add_edev(&pdev->dev, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (IS_ERR(nocp->edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dev_err(&pdev->dev, "failed to add devfreq-event device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return PTR_ERR(nocp->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) platform_set_drvdata(pdev, nocp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static struct platform_driver rockchip_nocp_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .probe = rockchip_nocp_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .name = "rockchip-nocp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .of_match_table = rockchip_nocp_id_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) module_platform_driver(rockchip_nocp_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) MODULE_DESCRIPTION("Rockchip NoC (Network on Chip) Probe driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) MODULE_LICENSE("GPL v2");