0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/acpi.h>
0012 #include <linux/bug.h>
0013 #include <linux/cpuhotplug.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/irq.h>
0016 #include <linux/list.h>
0017 #include <linux/smp.h>
0018
0019 #include "hisi_uncore_pmu.h"
0020
0021
0022 #define DDRC_PERF_CTRL 0x010
0023 #define DDRC_FLUX_WR 0x380
0024 #define DDRC_FLUX_RD 0x384
0025 #define DDRC_FLUX_WCMD 0x388
0026 #define DDRC_FLUX_RCMD 0x38c
0027 #define DDRC_PRE_CMD 0x3c0
0028 #define DDRC_ACT_CMD 0x3c4
0029 #define DDRC_RNK_CHG 0x3cc
0030 #define DDRC_RW_CHG 0x3d0
0031 #define DDRC_EVENT_CTRL 0x6C0
0032 #define DDRC_INT_MASK 0x6c8
0033 #define DDRC_INT_STATUS 0x6cc
0034 #define DDRC_INT_CLEAR 0x6d0
0035 #define DDRC_VERSION 0x710
0036
0037
0038 #define DDRC_V2_INT_MASK 0x528
0039 #define DDRC_V2_INT_STATUS 0x52c
0040 #define DDRC_V2_INT_CLEAR 0x530
0041 #define DDRC_V2_EVENT_CNT 0xe00
0042 #define DDRC_V2_EVENT_CTRL 0xe70
0043 #define DDRC_V2_EVENT_TYPE 0xe74
0044 #define DDRC_V2_PERF_CTRL 0xeA0
0045
0046
0047 #define DDRC_NR_COUNTERS 0x8
0048 #define DDRC_V1_PERF_CTRL_EN 0x2
0049 #define DDRC_V2_PERF_CTRL_EN 0x1
0050 #define DDRC_V1_NR_EVENTS 0x7
0051 #define DDRC_V2_NR_EVENTS 0x90
0052
0053
0054
0055
0056
0057
0058
0059 #define GET_DDRC_EVENTID(hwc) (hwc->config_base & 0x7)
0060
0061 static const u32 ddrc_reg_off[] = {
0062 DDRC_FLUX_WR, DDRC_FLUX_RD, DDRC_FLUX_WCMD, DDRC_FLUX_RCMD,
0063 DDRC_PRE_CMD, DDRC_ACT_CMD, DDRC_RNK_CHG, DDRC_RW_CHG
0064 };
0065
0066
0067
0068
0069
0070
0071 static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
0072 {
0073 return ddrc_reg_off[cntr_idx];
0074 }
0075
0076 static u32 hisi_ddrc_pmu_v2_get_counter_offset(int cntr_idx)
0077 {
0078 return DDRC_V2_EVENT_CNT + cntr_idx * 8;
0079 }
0080
0081 static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
0082 struct hw_perf_event *hwc)
0083 {
0084 return readl(ddrc_pmu->base +
0085 hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
0086 }
0087
0088 static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
0089 struct hw_perf_event *hwc, u64 val)
0090 {
0091 writel((u32)val,
0092 ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
0093 }
0094
0095 static u64 hisi_ddrc_pmu_v2_read_counter(struct hisi_pmu *ddrc_pmu,
0096 struct hw_perf_event *hwc)
0097 {
0098 return readq(ddrc_pmu->base +
0099 hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
0100 }
0101
0102 static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu,
0103 struct hw_perf_event *hwc, u64 val)
0104 {
0105 writeq(val,
0106 ddrc_pmu->base + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
0107 }
0108
0109
0110
0111
0112
0113
0114 static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
0115 u32 type)
0116 {
0117 u32 offset;
0118
0119 if (hha_pmu->identifier >= HISI_PMU_V2) {
0120 offset = DDRC_V2_EVENT_TYPE + 4 * idx;
0121 writel(type, hha_pmu->base + offset);
0122 }
0123 }
0124
0125 static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
0126 {
0127 u32 val;
0128
0129
0130 val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
0131 val |= DDRC_V1_PERF_CTRL_EN;
0132 writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
0133 }
0134
0135 static void hisi_ddrc_pmu_v1_stop_counters(struct hisi_pmu *ddrc_pmu)
0136 {
0137 u32 val;
0138
0139
0140 val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
0141 val &= ~DDRC_V1_PERF_CTRL_EN;
0142 writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
0143 }
0144
0145 static void hisi_ddrc_pmu_v1_enable_counter(struct hisi_pmu *ddrc_pmu,
0146 struct hw_perf_event *hwc)
0147 {
0148 u32 val;
0149
0150
0151 val = readl(ddrc_pmu->base + DDRC_EVENT_CTRL);
0152 val |= (1 << GET_DDRC_EVENTID(hwc));
0153 writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
0154 }
0155
0156 static void hisi_ddrc_pmu_v1_disable_counter(struct hisi_pmu *ddrc_pmu,
0157 struct hw_perf_event *hwc)
0158 {
0159 u32 val;
0160
0161
0162 val = readl(ddrc_pmu->base + DDRC_EVENT_CTRL);
0163 val &= ~(1 << GET_DDRC_EVENTID(hwc));
0164 writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
0165 }
0166
0167 static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
0168 {
0169 struct hisi_pmu *ddrc_pmu = to_hisi_pmu(event->pmu);
0170 unsigned long *used_mask = ddrc_pmu->pmu_events.used_mask;
0171 struct hw_perf_event *hwc = &event->hw;
0172
0173 int idx = GET_DDRC_EVENTID(hwc);
0174
0175 if (test_bit(idx, used_mask))
0176 return -EAGAIN;
0177
0178 set_bit(idx, used_mask);
0179
0180 return idx;
0181 }
0182
0183 static int hisi_ddrc_pmu_v2_get_event_idx(struct perf_event *event)
0184 {
0185 return hisi_uncore_pmu_get_event_idx(event);
0186 }
0187
0188 static void hisi_ddrc_pmu_v2_start_counters(struct hisi_pmu *ddrc_pmu)
0189 {
0190 u32 val;
0191
0192 val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0193 val |= DDRC_V2_PERF_CTRL_EN;
0194 writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0195 }
0196
0197 static void hisi_ddrc_pmu_v2_stop_counters(struct hisi_pmu *ddrc_pmu)
0198 {
0199 u32 val;
0200
0201 val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0202 val &= ~DDRC_V2_PERF_CTRL_EN;
0203 writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0204 }
0205
0206 static void hisi_ddrc_pmu_v2_enable_counter(struct hisi_pmu *ddrc_pmu,
0207 struct hw_perf_event *hwc)
0208 {
0209 u32 val;
0210
0211 val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0212 val |= 1 << hwc->idx;
0213 writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0214 }
0215
0216 static void hisi_ddrc_pmu_v2_disable_counter(struct hisi_pmu *ddrc_pmu,
0217 struct hw_perf_event *hwc)
0218 {
0219 u32 val;
0220
0221 val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0222 val &= ~(1 << hwc->idx);
0223 writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0224 }
0225
0226 static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
0227 struct hw_perf_event *hwc)
0228 {
0229 u32 val;
0230
0231
0232 val = readl(ddrc_pmu->base + DDRC_INT_MASK);
0233 val &= ~(1 << hwc->idx);
0234 writel(val, ddrc_pmu->base + DDRC_INT_MASK);
0235 }
0236
0237 static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
0238 struct hw_perf_event *hwc)
0239 {
0240 u32 val;
0241
0242
0243 val = readl(ddrc_pmu->base + DDRC_INT_MASK);
0244 val |= 1 << hwc->idx;
0245 writel(val, ddrc_pmu->base + DDRC_INT_MASK);
0246 }
0247
0248 static void hisi_ddrc_pmu_v2_enable_counter_int(struct hisi_pmu *ddrc_pmu,
0249 struct hw_perf_event *hwc)
0250 {
0251 u32 val;
0252
0253 val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
0254 val &= ~(1 << hwc->idx);
0255 writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
0256 }
0257
0258 static void hisi_ddrc_pmu_v2_disable_counter_int(struct hisi_pmu *ddrc_pmu,
0259 struct hw_perf_event *hwc)
0260 {
0261 u32 val;
0262
0263 val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
0264 val |= 1 << hwc->idx;
0265 writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
0266 }
0267
0268 static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
0269 {
0270 return readl(ddrc_pmu->base + DDRC_INT_STATUS);
0271 }
0272
0273 static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
0274 int idx)
0275 {
0276 writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
0277 }
0278
0279 static u32 hisi_ddrc_pmu_v2_get_int_status(struct hisi_pmu *ddrc_pmu)
0280 {
0281 return readl(ddrc_pmu->base + DDRC_V2_INT_STATUS);
0282 }
0283
0284 static void hisi_ddrc_pmu_v2_clear_int_status(struct hisi_pmu *ddrc_pmu,
0285 int idx)
0286 {
0287 writel(1 << idx, ddrc_pmu->base + DDRC_V2_INT_CLEAR);
0288 }
0289
0290 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
0291 { "HISI0233", },
0292 { "HISI0234", },
0293 {}
0294 };
0295 MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match);
0296
0297 static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
0298 struct hisi_pmu *ddrc_pmu)
0299 {
0300
0301
0302
0303
0304 if (device_property_read_u32(&pdev->dev, "hisilicon,ch-id",
0305 &ddrc_pmu->index_id)) {
0306 dev_err(&pdev->dev, "Can not read ddrc channel-id!\n");
0307 return -EINVAL;
0308 }
0309
0310 if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
0311 &ddrc_pmu->sccl_id)) {
0312 dev_err(&pdev->dev, "Can not read ddrc sccl-id!\n");
0313 return -EINVAL;
0314 }
0315
0316 ddrc_pmu->ccl_id = -1;
0317
0318 ddrc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
0319 if (IS_ERR(ddrc_pmu->base)) {
0320 dev_err(&pdev->dev, "ioremap failed for ddrc_pmu resource\n");
0321 return PTR_ERR(ddrc_pmu->base);
0322 }
0323
0324 ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION);
0325 if (ddrc_pmu->identifier >= HISI_PMU_V2) {
0326 if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
0327 &ddrc_pmu->sub_id)) {
0328 dev_err(&pdev->dev, "Can not read sub-id!\n");
0329 return -EINVAL;
0330 }
0331 }
0332
0333 return 0;
0334 }
0335
0336 static struct attribute *hisi_ddrc_pmu_v1_format_attr[] = {
0337 HISI_PMU_FORMAT_ATTR(event, "config:0-4"),
0338 NULL,
0339 };
0340
0341 static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
0342 .name = "format",
0343 .attrs = hisi_ddrc_pmu_v1_format_attr,
0344 };
0345
0346 static struct attribute *hisi_ddrc_pmu_v2_format_attr[] = {
0347 HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
0348 NULL
0349 };
0350
0351 static const struct attribute_group hisi_ddrc_pmu_v2_format_group = {
0352 .name = "format",
0353 .attrs = hisi_ddrc_pmu_v2_format_attr,
0354 };
0355
0356 static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
0357 HISI_PMU_EVENT_ATTR(flux_wr, 0x00),
0358 HISI_PMU_EVENT_ATTR(flux_rd, 0x01),
0359 HISI_PMU_EVENT_ATTR(flux_wcmd, 0x02),
0360 HISI_PMU_EVENT_ATTR(flux_rcmd, 0x03),
0361 HISI_PMU_EVENT_ATTR(pre_cmd, 0x04),
0362 HISI_PMU_EVENT_ATTR(act_cmd, 0x05),
0363 HISI_PMU_EVENT_ATTR(rnk_chg, 0x06),
0364 HISI_PMU_EVENT_ATTR(rw_chg, 0x07),
0365 NULL,
0366 };
0367
0368 static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
0369 .name = "events",
0370 .attrs = hisi_ddrc_pmu_v1_events_attr,
0371 };
0372
0373 static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
0374 HISI_PMU_EVENT_ATTR(cycles, 0x00),
0375 HISI_PMU_EVENT_ATTR(flux_wr, 0x83),
0376 HISI_PMU_EVENT_ATTR(flux_rd, 0x84),
0377 NULL
0378 };
0379
0380 static const struct attribute_group hisi_ddrc_pmu_v2_events_group = {
0381 .name = "events",
0382 .attrs = hisi_ddrc_pmu_v2_events_attr,
0383 };
0384
0385 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
0386
0387 static struct attribute *hisi_ddrc_pmu_cpumask_attrs[] = {
0388 &dev_attr_cpumask.attr,
0389 NULL,
0390 };
0391
0392 static const struct attribute_group hisi_ddrc_pmu_cpumask_attr_group = {
0393 .attrs = hisi_ddrc_pmu_cpumask_attrs,
0394 };
0395
0396 static struct device_attribute hisi_ddrc_pmu_identifier_attr =
0397 __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
0398
0399 static struct attribute *hisi_ddrc_pmu_identifier_attrs[] = {
0400 &hisi_ddrc_pmu_identifier_attr.attr,
0401 NULL
0402 };
0403
0404 static const struct attribute_group hisi_ddrc_pmu_identifier_group = {
0405 .attrs = hisi_ddrc_pmu_identifier_attrs,
0406 };
0407
0408 static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
0409 &hisi_ddrc_pmu_v1_format_group,
0410 &hisi_ddrc_pmu_v1_events_group,
0411 &hisi_ddrc_pmu_cpumask_attr_group,
0412 &hisi_ddrc_pmu_identifier_group,
0413 NULL,
0414 };
0415
0416 static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = {
0417 &hisi_ddrc_pmu_v2_format_group,
0418 &hisi_ddrc_pmu_v2_events_group,
0419 &hisi_ddrc_pmu_cpumask_attr_group,
0420 &hisi_ddrc_pmu_identifier_group,
0421 NULL
0422 };
0423
0424 static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
0425 .write_evtype = hisi_ddrc_pmu_write_evtype,
0426 .get_event_idx = hisi_ddrc_pmu_v1_get_event_idx,
0427 .start_counters = hisi_ddrc_pmu_v1_start_counters,
0428 .stop_counters = hisi_ddrc_pmu_v1_stop_counters,
0429 .enable_counter = hisi_ddrc_pmu_v1_enable_counter,
0430 .disable_counter = hisi_ddrc_pmu_v1_disable_counter,
0431 .enable_counter_int = hisi_ddrc_pmu_v1_enable_counter_int,
0432 .disable_counter_int = hisi_ddrc_pmu_v1_disable_counter_int,
0433 .write_counter = hisi_ddrc_pmu_v1_write_counter,
0434 .read_counter = hisi_ddrc_pmu_v1_read_counter,
0435 .get_int_status = hisi_ddrc_pmu_v1_get_int_status,
0436 .clear_int_status = hisi_ddrc_pmu_v1_clear_int_status,
0437 };
0438
0439 static const struct hisi_uncore_ops hisi_uncore_ddrc_v2_ops = {
0440 .write_evtype = hisi_ddrc_pmu_write_evtype,
0441 .get_event_idx = hisi_ddrc_pmu_v2_get_event_idx,
0442 .start_counters = hisi_ddrc_pmu_v2_start_counters,
0443 .stop_counters = hisi_ddrc_pmu_v2_stop_counters,
0444 .enable_counter = hisi_ddrc_pmu_v2_enable_counter,
0445 .disable_counter = hisi_ddrc_pmu_v2_disable_counter,
0446 .enable_counter_int = hisi_ddrc_pmu_v2_enable_counter_int,
0447 .disable_counter_int = hisi_ddrc_pmu_v2_disable_counter_int,
0448 .write_counter = hisi_ddrc_pmu_v2_write_counter,
0449 .read_counter = hisi_ddrc_pmu_v2_read_counter,
0450 .get_int_status = hisi_ddrc_pmu_v2_get_int_status,
0451 .clear_int_status = hisi_ddrc_pmu_v2_clear_int_status,
0452 };
0453
0454 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
0455 struct hisi_pmu *ddrc_pmu)
0456 {
0457 int ret;
0458
0459 ret = hisi_ddrc_pmu_init_data(pdev, ddrc_pmu);
0460 if (ret)
0461 return ret;
0462
0463 ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
0464 if (ret)
0465 return ret;
0466
0467 if (ddrc_pmu->identifier >= HISI_PMU_V2) {
0468 ddrc_pmu->counter_bits = 48;
0469 ddrc_pmu->check_event = DDRC_V2_NR_EVENTS;
0470 ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v2_attr_groups;
0471 ddrc_pmu->ops = &hisi_uncore_ddrc_v2_ops;
0472 } else {
0473 ddrc_pmu->counter_bits = 32;
0474 ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
0475 ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v1_attr_groups;
0476 ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
0477 }
0478
0479 ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
0480 ddrc_pmu->dev = &pdev->dev;
0481 ddrc_pmu->on_cpu = -1;
0482
0483 return 0;
0484 }
0485
0486 static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
0487 {
0488 struct hisi_pmu *ddrc_pmu;
0489 char *name;
0490 int ret;
0491
0492 ddrc_pmu = devm_kzalloc(&pdev->dev, sizeof(*ddrc_pmu), GFP_KERNEL);
0493 if (!ddrc_pmu)
0494 return -ENOMEM;
0495
0496 platform_set_drvdata(pdev, ddrc_pmu);
0497
0498 ret = hisi_ddrc_pmu_dev_probe(pdev, ddrc_pmu);
0499 if (ret)
0500 return ret;
0501
0502 ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0503 &ddrc_pmu->node);
0504 if (ret) {
0505 dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret);
0506 return ret;
0507 }
0508
0509 if (ddrc_pmu->identifier >= HISI_PMU_V2)
0510 name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0511 "hisi_sccl%u_ddrc%u_%u",
0512 ddrc_pmu->sccl_id, ddrc_pmu->index_id,
0513 ddrc_pmu->sub_id);
0514 else
0515 name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0516 "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
0517 ddrc_pmu->index_id);
0518
0519 hisi_pmu_init(&ddrc_pmu->pmu, name, ddrc_pmu->pmu_events.attr_groups, THIS_MODULE);
0520
0521 ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1);
0522 if (ret) {
0523 dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
0524 cpuhp_state_remove_instance_nocalls(
0525 CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
0526 }
0527
0528 return ret;
0529 }
0530
0531 static int hisi_ddrc_pmu_remove(struct platform_device *pdev)
0532 {
0533 struct hisi_pmu *ddrc_pmu = platform_get_drvdata(pdev);
0534
0535 perf_pmu_unregister(&ddrc_pmu->pmu);
0536 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0537 &ddrc_pmu->node);
0538 return 0;
0539 }
0540
0541 static struct platform_driver hisi_ddrc_pmu_driver = {
0542 .driver = {
0543 .name = "hisi_ddrc_pmu",
0544 .acpi_match_table = ACPI_PTR(hisi_ddrc_pmu_acpi_match),
0545 .suppress_bind_attrs = true,
0546 },
0547 .probe = hisi_ddrc_pmu_probe,
0548 .remove = hisi_ddrc_pmu_remove,
0549 };
0550
0551 static int __init hisi_ddrc_pmu_module_init(void)
0552 {
0553 int ret;
0554
0555 ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0556 "AP_PERF_ARM_HISI_DDRC_ONLINE",
0557 hisi_uncore_pmu_online_cpu,
0558 hisi_uncore_pmu_offline_cpu);
0559 if (ret) {
0560 pr_err("DDRC PMU: setup hotplug, ret = %d\n", ret);
0561 return ret;
0562 }
0563
0564 ret = platform_driver_register(&hisi_ddrc_pmu_driver);
0565 if (ret)
0566 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
0567
0568 return ret;
0569 }
0570 module_init(hisi_ddrc_pmu_module_init);
0571
0572 static void __exit hisi_ddrc_pmu_module_exit(void)
0573 {
0574 platform_driver_unregister(&hisi_ddrc_pmu_driver);
0575 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
0576
0577 }
0578 module_exit(hisi_ddrc_pmu_module_exit);
0579
0580 MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU driver");
0581 MODULE_LICENSE("GPL v2");
0582 MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
0583 MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>");