^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * CPU idle for DaVinci SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Texas Instruments Incorporated. https://www.ti.com/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Derived from Marvell Kirkwood CPU idle code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * (arch/arm/mach-kirkwood/cpuidle.c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cpuidle.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/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/cpuidle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "cpuidle.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "ddr2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define DAVINCI_CPUIDLE_MAX_STATES 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static void __iomem *ddr2_reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static bool ddr2_pdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static void davinci_save_ddr_power(int enter, bool pdown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (enter) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (pdown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) val |= DDR2_SRPD_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) val &= ~DDR2_SRPD_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) val |= DDR2_LPMODEN_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Actual code that puts the SoC in different idle states */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int davinci_enter_idle(struct cpuidle_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct cpuidle_driver *drv, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) davinci_save_ddr_power(1, ddr2_pdown);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) cpu_do_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) davinci_save_ddr_power(0, ddr2_pdown);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static struct cpuidle_driver davinci_idle_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .name = "cpuidle-davinci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .states[0] = ARM_CPUIDLE_WFI_STATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .states[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .enter = davinci_enter_idle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .exit_latency = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .target_residency = 10000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .name = "DDR SR",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .desc = "WFI and DDR Self Refresh",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .state_count = DAVINCI_CPUIDLE_MAX_STATES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int __init davinci_cpuidle_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (!pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) dev_err(&pdev->dev, "cannot get platform data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ddr2_reg_base = pdata->ddr2_ctlr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ddr2_pdown = pdata->ddr2_pdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return cpuidle_register(&davinci_idle_driver, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static struct platform_driver davinci_cpuidle_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .name = "cpuidle-davinci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int __init davinci_cpuidle_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return platform_driver_probe(&davinci_cpuidle_driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) davinci_cpuidle_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) device_initcall(davinci_cpuidle_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)