| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd |
|---|
| 3 | 4 | * Author: Lin Huang <hl@rock-chips.com> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | 5 | */ |
|---|
| 14 | 6 | |
|---|
| 15 | 7 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 26 | 18 | #include <linux/list.h> |
|---|
| 27 | 19 | #include <linux/of.h> |
|---|
| 28 | 20 | |
|---|
| 21 | +#include <soc/rockchip/rk3399_grf.h> |
|---|
| 22 | + |
|---|
| 29 | 23 | #define PX30_PMUGRF_OS_REG2 0x208 |
|---|
| 30 | 24 | #define PX30_PMUGRF_OS_REG3 0x20c |
|---|
| 25 | + |
|---|
| 26 | +#define RK3588_PMUGRF_OS_REG(n) (0x200 + (n) * 4) |
|---|
| 31 | 27 | |
|---|
| 32 | 28 | #define RK3128_GRF_SOC_CON0 0x140 |
|---|
| 33 | 29 | #define RK3128_GRF_OS_REG1 0x1cc |
|---|
| .. | .. |
|---|
| 60 | 56 | #define RK3528_PMUGRF_OS_REG18 0x248 |
|---|
| 61 | 57 | #define RK3528_PMUGRF_OS_REG19 0x24c |
|---|
| 62 | 58 | |
|---|
| 63 | | -#define MAX_DMC_NUM_CH 2 |
|---|
| 59 | +#define MAX_DMC_NUM_CH 4 |
|---|
| 64 | 60 | #define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7) |
|---|
| 65 | 61 | #define READ_CH_INFO(n) (((n) >> 28) & 0x3) |
|---|
| 66 | 62 | #define READ_DRAMTYPE_INFO_V3(n, m) ((((n) >> 13) & 0x7) | ((((m) >> 12) & 0x3) << 3)) |
|---|
| 67 | 63 | #define READ_SYSREG_VERSION(m) (((m) >> 28) & 0xf) |
|---|
| 64 | +#define READ_LP5_BANK_MODE(m) (((m) >> 1) & 0x3) |
|---|
| 65 | +#define READ_LP5_CKR(m) (((m) >> 0) & 0x1) |
|---|
| 68 | 66 | /* DDRMON_CTRL */ |
|---|
| 69 | 67 | #define DDRMON_CTRL 0x04 |
|---|
| 70 | | -#define CLR_DDRMON_CTRL (0x3f0000 << 0) |
|---|
| 68 | +#define CLR_DDRMON_CTRL (0xffff0000 << 0) |
|---|
| 69 | +#define LPDDR5_BANK_MODE(m) ((0x30000 | ((m) & 0x3)) << 7) |
|---|
| 70 | +#define LPDDR5_EN (0x10001 << 6) |
|---|
| 71 | 71 | #define DDR4_EN (0x10001 << 5) |
|---|
| 72 | 72 | #define LPDDR4_EN (0x10001 << 4) |
|---|
| 73 | 73 | #define HARDWARE_EN (0x10001 << 3) |
|---|
| .. | .. |
|---|
| 91 | 91 | LPDDR3 = 6, |
|---|
| 92 | 92 | LPDDR4 = 7, |
|---|
| 93 | 93 | LPDDR4X = 8, |
|---|
| 94 | + LPDDR5 = 9, |
|---|
| 95 | + DDR5 = 10, |
|---|
| 94 | 96 | UNUSED = 0xFF |
|---|
| 95 | 97 | }; |
|---|
| 96 | 98 | |
|---|
| 97 | 99 | struct dmc_usage { |
|---|
| 98 | | - u32 access; |
|---|
| 99 | | - u32 total; |
|---|
| 100 | + u64 access; |
|---|
| 101 | + u64 total; |
|---|
| 100 | 102 | }; |
|---|
| 101 | 103 | |
|---|
| 102 | 104 | /* |
|---|
| .. | .. |
|---|
| 115 | 117 | struct regmap *regmap_pmugrf; |
|---|
| 116 | 118 | struct clk *clk; |
|---|
| 117 | 119 | u32 dram_type; |
|---|
| 120 | + u32 mon_idx; |
|---|
| 118 | 121 | u32 count_rate; |
|---|
| 122 | + u32 dram_dynamic_info_reg; |
|---|
| 123 | + /* 0: BG mode, 1: 16 Bank mode, 2: 8 bank mode */ |
|---|
| 124 | + u32 lp5_bank_mode; |
|---|
| 125 | + /* 0: clk:dqs = 1:2, 1: 1:4 */ |
|---|
| 126 | + u32 lp5_ckr; |
|---|
| 119 | 127 | /* |
|---|
| 120 | 128 | * available mask, 1: available, 0: not available |
|---|
| 121 | 129 | * each bit represent a channel |
|---|
| .. | .. |
|---|
| 352 | 360 | { |
|---|
| 353 | 361 | struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); |
|---|
| 354 | 362 | void __iomem *dfi_regs = info->regs; |
|---|
| 363 | + u32 mon_idx = 0, val_6 = 0; |
|---|
| 364 | + u32 i; |
|---|
| 355 | 365 | |
|---|
| 356 | | - /* clear DDRMON_CTRL setting */ |
|---|
| 357 | | - writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); |
|---|
| 366 | + if (info->mon_idx) |
|---|
| 367 | + mon_idx = info->mon_idx; |
|---|
| 358 | 368 | |
|---|
| 359 | | - /* set ddr type to dfi */ |
|---|
| 360 | | - if (info->dram_type == LPDDR3 || info->dram_type == LPDDR2) |
|---|
| 361 | | - writel_relaxed(LPDDR2_3_EN, dfi_regs + DDRMON_CTRL); |
|---|
| 362 | | - else if (info->dram_type == LPDDR4 || info->dram_type == LPDDR4X) |
|---|
| 363 | | - writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); |
|---|
| 364 | | - else if (info->dram_type == DDR4) |
|---|
| 365 | | - writel_relaxed(DDR4_EN, dfi_regs + DDRMON_CTRL); |
|---|
| 369 | + if (info->dram_dynamic_info_reg) |
|---|
| 370 | + regmap_read(info->regmap_pmugrf, info->dram_dynamic_info_reg, &val_6); |
|---|
| 366 | 371 | |
|---|
| 367 | | - /* enable count, use software mode */ |
|---|
| 368 | | - writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); |
|---|
| 372 | + if (info->dram_type == LPDDR5) { |
|---|
| 373 | + info->lp5_bank_mode = READ_LP5_BANK_MODE(val_6); |
|---|
| 374 | + info->lp5_ckr = READ_LP5_CKR(val_6); |
|---|
| 375 | + } |
|---|
| 376 | + |
|---|
| 377 | + for (i = 0; i < MAX_DMC_NUM_CH; i++) { |
|---|
| 378 | + if (!(info->ch_msk & BIT(i))) |
|---|
| 379 | + continue; |
|---|
| 380 | + /* clear DDRMON_CTRL setting */ |
|---|
| 381 | + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 382 | + |
|---|
| 383 | + /* set ddr type to dfi */ |
|---|
| 384 | + if (info->dram_type == LPDDR3 || info->dram_type == LPDDR2) |
|---|
| 385 | + writel_relaxed(LPDDR2_3_EN, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 386 | + else if (info->dram_type == LPDDR4 || info->dram_type == LPDDR4X) |
|---|
| 387 | + writel_relaxed(LPDDR4_EN, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 388 | + else if (info->dram_type == DDR4) |
|---|
| 389 | + writel_relaxed(DDR4_EN, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 390 | + else if (info->dram_type == LPDDR5) |
|---|
| 391 | + writel_relaxed(LPDDR5_EN | LPDDR5_BANK_MODE(info->lp5_bank_mode), |
|---|
| 392 | + dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 393 | + |
|---|
| 394 | + /* enable count, use software mode */ |
|---|
| 395 | + writel_relaxed(SOFTWARE_EN, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 396 | + } |
|---|
| 369 | 397 | } |
|---|
| 370 | 398 | |
|---|
| 371 | 399 | static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) |
|---|
| 372 | 400 | { |
|---|
| 373 | 401 | struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); |
|---|
| 374 | 402 | void __iomem *dfi_regs = info->regs; |
|---|
| 403 | + u32 mon_idx = 0, i; |
|---|
| 375 | 404 | |
|---|
| 376 | | - writel_relaxed(SOFTWARE_DIS, dfi_regs + DDRMON_CTRL); |
|---|
| 405 | + if (info->mon_idx) |
|---|
| 406 | + mon_idx = info->mon_idx; |
|---|
| 407 | + |
|---|
| 408 | + for (i = 0; i < MAX_DMC_NUM_CH; i++) { |
|---|
| 409 | + if (!(info->ch_msk & BIT(i))) |
|---|
| 410 | + continue; |
|---|
| 411 | + writel_relaxed(SOFTWARE_DIS, dfi_regs + i * mon_idx + DDRMON_CTRL); |
|---|
| 412 | + } |
|---|
| 377 | 413 | } |
|---|
| 378 | 414 | |
|---|
| 379 | 415 | static int rockchip_dfi_get_busier_ch(struct devfreq_event_dev *edev) |
|---|
| .. | .. |
|---|
| 382 | 418 | u32 tmp, max = 0; |
|---|
| 383 | 419 | u32 i, busier_ch = 0; |
|---|
| 384 | 420 | void __iomem *dfi_regs = info->regs; |
|---|
| 385 | | - u32 count_rate = 1; |
|---|
| 421 | + u32 mon_idx = 0x20, count_rate = 1; |
|---|
| 386 | 422 | |
|---|
| 387 | 423 | rockchip_dfi_stop_hardware_counter(edev); |
|---|
| 388 | 424 | |
|---|
| 425 | + if (info->mon_idx) |
|---|
| 426 | + mon_idx = info->mon_idx; |
|---|
| 389 | 427 | if (info->count_rate) |
|---|
| 390 | 428 | count_rate = info->count_rate; |
|---|
| 391 | 429 | |
|---|
| .. | .. |
|---|
| 394 | 432 | if (!(info->ch_msk & BIT(i))) |
|---|
| 395 | 433 | continue; |
|---|
| 396 | 434 | |
|---|
| 435 | + /* rk3588 counter is dfi clk rate */ |
|---|
| 397 | 436 | info->ch_usage[i].total = readl_relaxed(dfi_regs + |
|---|
| 398 | | - DDRMON_CH0_COUNT_NUM + i * 20) * count_rate; |
|---|
| 437 | + DDRMON_CH0_COUNT_NUM + i * mon_idx) * count_rate; |
|---|
| 399 | 438 | |
|---|
| 400 | | - /* LPDDR4 and LPDDR4X BL = 16,other DDR type BL = 8 */ |
|---|
| 439 | + /* LPDDR5 LPDDR4 and LPDDR4X BL = 16,other DDR type BL = 8 */ |
|---|
| 401 | 440 | tmp = readl_relaxed(dfi_regs + |
|---|
| 402 | | - DDRMON_CH0_DFI_ACCESS_NUM + i * 20); |
|---|
| 441 | + DDRMON_CH0_DFI_ACCESS_NUM + i * mon_idx); |
|---|
| 403 | 442 | if (info->dram_type == LPDDR4 || info->dram_type == LPDDR4X) |
|---|
| 404 | 443 | tmp *= 8; |
|---|
| 444 | + else if (info->dram_type == LPDDR5) |
|---|
| 445 | + tmp *= 16 / (4 << info->lp5_ckr); |
|---|
| 405 | 446 | else |
|---|
| 406 | 447 | tmp *= 4; |
|---|
| 407 | 448 | info->ch_usage[i].access = tmp; |
|---|
| .. | .. |
|---|
| 473 | 514 | .get_event = rockchip_dfi_get_event, |
|---|
| 474 | 515 | .set_event = rockchip_dfi_set_event, |
|---|
| 475 | 516 | }; |
|---|
| 517 | + |
|---|
| 518 | +static __maybe_unused __init int rk3588_dfi_init(struct platform_device *pdev, |
|---|
| 519 | + struct rockchip_dfi *data, |
|---|
| 520 | + struct devfreq_event_desc *desc) |
|---|
| 521 | +{ |
|---|
| 522 | + struct device_node *np = pdev->dev.of_node; |
|---|
| 523 | + struct resource *res; |
|---|
| 524 | + u32 val_2, val_3, val_4; |
|---|
| 525 | + |
|---|
| 526 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 527 | + data->regs = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 528 | + if (IS_ERR(data->regs)) |
|---|
| 529 | + return PTR_ERR(data->regs); |
|---|
| 530 | + |
|---|
| 531 | + data->regmap_pmugrf = syscon_regmap_lookup_by_phandle(np, "rockchip,pmu_grf"); |
|---|
| 532 | + if (IS_ERR(data->regmap_pmugrf)) |
|---|
| 533 | + return PTR_ERR(data->regmap_pmugrf); |
|---|
| 534 | + |
|---|
| 535 | + regmap_read(data->regmap_pmugrf, RK3588_PMUGRF_OS_REG(2), &val_2); |
|---|
| 536 | + regmap_read(data->regmap_pmugrf, RK3588_PMUGRF_OS_REG(3), &val_3); |
|---|
| 537 | + regmap_read(data->regmap_pmugrf, RK3588_PMUGRF_OS_REG(4), &val_4); |
|---|
| 538 | + if (READ_SYSREG_VERSION(val_3) >= 0x3) |
|---|
| 539 | + data->dram_type = READ_DRAMTYPE_INFO_V3(val_2, val_3); |
|---|
| 540 | + else |
|---|
| 541 | + data->dram_type = READ_DRAMTYPE_INFO(val_2); |
|---|
| 542 | + |
|---|
| 543 | + data->mon_idx = 0x4000; |
|---|
| 544 | + if (data->dram_type == LPDDR5) |
|---|
| 545 | + data->count_rate = 1; |
|---|
| 546 | + else |
|---|
| 547 | + data->count_rate = 2; |
|---|
| 548 | + data->dram_dynamic_info_reg = RK3588_PMUGRF_OS_REG(6); |
|---|
| 549 | + data->ch_msk = READ_CH_INFO(val_2) | READ_CH_INFO(val_4) << 2; |
|---|
| 550 | + data->clk = NULL; |
|---|
| 551 | + |
|---|
| 552 | + desc->ops = &rockchip_dfi_ops; |
|---|
| 553 | + |
|---|
| 554 | + return 0; |
|---|
| 555 | +} |
|---|
| 476 | 556 | |
|---|
| 477 | 557 | static __maybe_unused __init int px30_dfi_init(struct platform_device *pdev, |
|---|
| 478 | 558 | struct rockchip_dfi *data, |
|---|
| .. | .. |
|---|
| 586 | 666 | struct devfreq_event_desc *desc) |
|---|
| 587 | 667 | { |
|---|
| 588 | 668 | struct device *dev = &pdev->dev; |
|---|
| 589 | | - struct resource *res; |
|---|
| 590 | 669 | struct device_node *np = pdev->dev.of_node, *node; |
|---|
| 591 | 670 | u32 val; |
|---|
| 592 | 671 | |
|---|
| 593 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 594 | | - data->regs = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 672 | + data->regs = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 595 | 673 | if (IS_ERR(data->regs)) |
|---|
| 596 | 674 | return PTR_ERR(data->regs); |
|---|
| 597 | 675 | |
|---|
| .. | .. |
|---|
| 605 | 683 | node = of_parse_phandle(np, "rockchip,pmu", 0); |
|---|
| 606 | 684 | if (node) { |
|---|
| 607 | 685 | data->regmap_pmu = syscon_node_to_regmap(node); |
|---|
| 686 | + of_node_put(node); |
|---|
| 608 | 687 | if (IS_ERR(data->regmap_pmu)) |
|---|
| 609 | 688 | return PTR_ERR(data->regmap_pmu); |
|---|
| 610 | 689 | } |
|---|
| .. | .. |
|---|
| 708 | 787 | #ifdef CONFIG_CPU_RK3528 |
|---|
| 709 | 788 | { .compatible = "rockchip,rk3528-dfi", .data = rk3528_dfi_init }, |
|---|
| 710 | 789 | #endif |
|---|
| 790 | +#ifdef CONFIG_CPU_RK3562 |
|---|
| 791 | + { .compatible = "rockchip,rk3562-dfi", .data = px30_dfi_init }, |
|---|
| 792 | +#endif |
|---|
| 711 | 793 | #ifdef CONFIG_CPU_RK3568 |
|---|
| 712 | 794 | { .compatible = "rockchip,rk3568-dfi", .data = px30_dfi_init }, |
|---|
| 713 | 795 | #endif |
|---|
| 796 | +#ifdef CONFIG_CPU_RK3588 |
|---|
| 797 | + { .compatible = "rockchip,rk3588-dfi", .data = rk3588_dfi_init }, |
|---|
| 798 | +#endif |
|---|
| 714 | 799 | #ifdef CONFIG_CPU_RV1126 |
|---|
| 715 | 800 | { .compatible = "rockchip,rv1126-dfi", .data = px30_dfi_init }, |
|---|
| 716 | 801 | #endif |
|---|