Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
0004  *      http://www.samsung.com
0005  *
0006  * CPU frequency scaling for S5PC110/S5PV210
0007 */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/types.h>
0012 #include <linux/kernel.h>
0013 #include <linux/init.h>
0014 #include <linux/err.h>
0015 #include <linux/clk.h>
0016 #include <linux/io.h>
0017 #include <linux/cpufreq.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/reboot.h>
0022 #include <linux/regulator/consumer.h>
0023 
0024 static void __iomem *clk_base;
0025 static void __iomem *dmc_base[2];
0026 
0027 #define S5P_CLKREG(x)       (clk_base + (x))
0028 
0029 #define S5P_APLL_LOCK       S5P_CLKREG(0x00)
0030 #define S5P_APLL_CON        S5P_CLKREG(0x100)
0031 #define S5P_CLK_SRC0        S5P_CLKREG(0x200)
0032 #define S5P_CLK_SRC2        S5P_CLKREG(0x208)
0033 #define S5P_CLK_DIV0        S5P_CLKREG(0x300)
0034 #define S5P_CLK_DIV2        S5P_CLKREG(0x308)
0035 #define S5P_CLK_DIV6        S5P_CLKREG(0x318)
0036 #define S5P_CLKDIV_STAT0    S5P_CLKREG(0x1000)
0037 #define S5P_CLKDIV_STAT1    S5P_CLKREG(0x1004)
0038 #define S5P_CLKMUX_STAT0    S5P_CLKREG(0x1100)
0039 #define S5P_CLKMUX_STAT1    S5P_CLKREG(0x1104)
0040 
0041 #define S5P_ARM_MCS_CON     S5P_CLKREG(0x6100)
0042 
0043 /* CLKSRC0 */
0044 #define S5P_CLKSRC0_MUX200_SHIFT    (16)
0045 #define S5P_CLKSRC0_MUX200_MASK     (0x1 << S5P_CLKSRC0_MUX200_SHIFT)
0046 #define S5P_CLKSRC0_MUX166_MASK     (0x1<<20)
0047 #define S5P_CLKSRC0_MUX133_MASK     (0x1<<24)
0048 
0049 /* CLKSRC2 */
0050 #define S5P_CLKSRC2_G3D_SHIFT           (0)
0051 #define S5P_CLKSRC2_G3D_MASK            (0x3 << S5P_CLKSRC2_G3D_SHIFT)
0052 #define S5P_CLKSRC2_MFC_SHIFT           (4)
0053 #define S5P_CLKSRC2_MFC_MASK            (0x3 << S5P_CLKSRC2_MFC_SHIFT)
0054 
0055 /* CLKDIV0 */
0056 #define S5P_CLKDIV0_APLL_SHIFT      (0)
0057 #define S5P_CLKDIV0_APLL_MASK       (0x7 << S5P_CLKDIV0_APLL_SHIFT)
0058 #define S5P_CLKDIV0_A2M_SHIFT       (4)
0059 #define S5P_CLKDIV0_A2M_MASK        (0x7 << S5P_CLKDIV0_A2M_SHIFT)
0060 #define S5P_CLKDIV0_HCLK200_SHIFT   (8)
0061 #define S5P_CLKDIV0_HCLK200_MASK    (0x7 << S5P_CLKDIV0_HCLK200_SHIFT)
0062 #define S5P_CLKDIV0_PCLK100_SHIFT   (12)
0063 #define S5P_CLKDIV0_PCLK100_MASK    (0x7 << S5P_CLKDIV0_PCLK100_SHIFT)
0064 #define S5P_CLKDIV0_HCLK166_SHIFT   (16)
0065 #define S5P_CLKDIV0_HCLK166_MASK    (0xF << S5P_CLKDIV0_HCLK166_SHIFT)
0066 #define S5P_CLKDIV0_PCLK83_SHIFT    (20)
0067 #define S5P_CLKDIV0_PCLK83_MASK     (0x7 << S5P_CLKDIV0_PCLK83_SHIFT)
0068 #define S5P_CLKDIV0_HCLK133_SHIFT   (24)
0069 #define S5P_CLKDIV0_HCLK133_MASK    (0xF << S5P_CLKDIV0_HCLK133_SHIFT)
0070 #define S5P_CLKDIV0_PCLK66_SHIFT    (28)
0071 #define S5P_CLKDIV0_PCLK66_MASK     (0x7 << S5P_CLKDIV0_PCLK66_SHIFT)
0072 
0073 /* CLKDIV2 */
0074 #define S5P_CLKDIV2_G3D_SHIFT           (0)
0075 #define S5P_CLKDIV2_G3D_MASK            (0xF << S5P_CLKDIV2_G3D_SHIFT)
0076 #define S5P_CLKDIV2_MFC_SHIFT           (4)
0077 #define S5P_CLKDIV2_MFC_MASK            (0xF << S5P_CLKDIV2_MFC_SHIFT)
0078 
0079 /* CLKDIV6 */
0080 #define S5P_CLKDIV6_ONEDRAM_SHIFT       (28)
0081 #define S5P_CLKDIV6_ONEDRAM_MASK        (0xF << S5P_CLKDIV6_ONEDRAM_SHIFT)
0082 
0083 static struct clk *dmc0_clk;
0084 static struct clk *dmc1_clk;
0085 static DEFINE_MUTEX(set_freq_lock);
0086 
0087 /* APLL M,P,S values for 1G/800Mhz */
0088 #define APLL_VAL_1000   ((1 << 31) | (125 << 16) | (3 << 8) | 1)
0089 #define APLL_VAL_800    ((1 << 31) | (100 << 16) | (3 << 8) | 1)
0090 
0091 /* Use 800MHz when entering sleep mode */
0092 #define SLEEP_FREQ  (800 * 1000)
0093 
0094 /* Tracks if CPU frequency can be updated anymore */
0095 static bool no_cpufreq_access;
0096 
0097 /*
0098  * DRAM configurations to calculate refresh counter for changing
0099  * frequency of memory.
0100  */
0101 struct dram_conf {
0102     unsigned long freq; /* HZ */
0103     unsigned long refresh;  /* DRAM refresh counter * 1000 */
0104 };
0105 
0106 /* DRAM configuration (DMC0 and DMC1) */
0107 static struct dram_conf s5pv210_dram_conf[2];
0108 
0109 enum perf_level {
0110     L0, L1, L2, L3, L4,
0111 };
0112 
0113 enum s5pv210_mem_type {
0114     LPDDR   = 0x1,
0115     LPDDR2  = 0x2,
0116     DDR2    = 0x4,
0117 };
0118 
0119 enum s5pv210_dmc_port {
0120     DMC0 = 0,
0121     DMC1,
0122 };
0123 
0124 static struct cpufreq_frequency_table s5pv210_freq_table[] = {
0125     {0, L0, 1000*1000},
0126     {0, L1, 800*1000},
0127     {0, L2, 400*1000},
0128     {0, L3, 200*1000},
0129     {0, L4, 100*1000},
0130     {0, 0, CPUFREQ_TABLE_END},
0131 };
0132 
0133 static struct regulator *arm_regulator;
0134 static struct regulator *int_regulator;
0135 
0136 struct s5pv210_dvs_conf {
0137     int arm_volt;   /* uV */
0138     int int_volt;   /* uV */
0139 };
0140 
0141 static const int arm_volt_max = 1350000;
0142 static const int int_volt_max = 1250000;
0143 
0144 static struct s5pv210_dvs_conf dvs_conf[] = {
0145     [L0] = {
0146         .arm_volt   = 1250000,
0147         .int_volt   = 1100000,
0148     },
0149     [L1] = {
0150         .arm_volt   = 1200000,
0151         .int_volt   = 1100000,
0152     },
0153     [L2] = {
0154         .arm_volt   = 1050000,
0155         .int_volt   = 1100000,
0156     },
0157     [L3] = {
0158         .arm_volt   = 950000,
0159         .int_volt   = 1100000,
0160     },
0161     [L4] = {
0162         .arm_volt   = 950000,
0163         .int_volt   = 1000000,
0164     },
0165 };
0166 
0167 static u32 clkdiv_val[5][11] = {
0168     /*
0169      * Clock divider value for following
0170      * { APLL, A2M, HCLK_MSYS, PCLK_MSYS,
0171      *   HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS,
0172      *   ONEDRAM, MFC, G3D }
0173      */
0174 
0175     /* L0 : [1000/200/100][166/83][133/66][200/200] */
0176     {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
0177 
0178     /* L1 : [800/200/100][166/83][133/66][200/200] */
0179     {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
0180 
0181     /* L2 : [400/200/100][166/83][133/66][200/200] */
0182     {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
0183 
0184     /* L3 : [200/200/100][166/83][133/66][200/200] */
0185     {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
0186 
0187     /* L4 : [100/100/100][83/83][66/66][100/100] */
0188     {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
0189 };
0190 
0191 /*
0192  * This function set DRAM refresh counter
0193  * according to operating frequency of DRAM
0194  * ch: DMC port number 0 or 1
0195  * freq: Operating frequency of DRAM(KHz)
0196  */
0197 static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
0198 {
0199     unsigned long tmp, tmp1;
0200     void __iomem *reg = NULL;
0201 
0202     if (ch == DMC0) {
0203         reg = (dmc_base[0] + 0x30);
0204     } else if (ch == DMC1) {
0205         reg = (dmc_base[1] + 0x30);
0206     } else {
0207         pr_err("Cannot find DMC port\n");
0208         return;
0209     }
0210 
0211     /* Find current DRAM frequency */
0212     tmp = s5pv210_dram_conf[ch].freq;
0213 
0214     tmp /= freq;
0215 
0216     tmp1 = s5pv210_dram_conf[ch].refresh;
0217 
0218     tmp1 /= tmp;
0219 
0220     writel_relaxed(tmp1, reg);
0221 }
0222 
0223 static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
0224 {
0225     unsigned long reg;
0226     unsigned int priv_index;
0227     unsigned int pll_changing = 0;
0228     unsigned int bus_speed_changing = 0;
0229     unsigned int old_freq, new_freq;
0230     int arm_volt, int_volt;
0231     int ret = 0;
0232 
0233     mutex_lock(&set_freq_lock);
0234 
0235     if (no_cpufreq_access) {
0236         pr_err("Denied access to %s as it is disabled temporarily\n",
0237                __func__);
0238         ret = -EINVAL;
0239         goto exit;
0240     }
0241 
0242     old_freq = policy->cur;
0243     new_freq = s5pv210_freq_table[index].frequency;
0244 
0245     /* Finding current running level index */
0246     priv_index = cpufreq_table_find_index_h(policy, old_freq, false);
0247 
0248     arm_volt = dvs_conf[index].arm_volt;
0249     int_volt = dvs_conf[index].int_volt;
0250 
0251     if (new_freq > old_freq) {
0252         ret = regulator_set_voltage(arm_regulator,
0253                 arm_volt, arm_volt_max);
0254         if (ret)
0255             goto exit;
0256 
0257         ret = regulator_set_voltage(int_regulator,
0258                 int_volt, int_volt_max);
0259         if (ret)
0260             goto exit;
0261     }
0262 
0263     /* Check if there need to change PLL */
0264     if ((index == L0) || (priv_index == L0))
0265         pll_changing = 1;
0266 
0267     /* Check if there need to change System bus clock */
0268     if ((index == L4) || (priv_index == L4))
0269         bus_speed_changing = 1;
0270 
0271     if (bus_speed_changing) {
0272         /*
0273          * Reconfigure DRAM refresh counter value for minimum
0274          * temporary clock while changing divider.
0275          * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287
0276          */
0277         if (pll_changing)
0278             s5pv210_set_refresh(DMC1, 83000);
0279         else
0280             s5pv210_set_refresh(DMC1, 100000);
0281 
0282         s5pv210_set_refresh(DMC0, 83000);
0283     }
0284 
0285     /*
0286      * APLL should be changed in this level
0287      * APLL -> MPLL(for stable transition) -> APLL
0288      * Some clock source's clock API are not prepared.
0289      * Do not use clock API in below code.
0290      */
0291     if (pll_changing) {
0292         /*
0293          * 1. Temporary Change divider for MFC and G3D
0294          * SCLKA2M(200/1=200)->(200/4=50)Mhz
0295          */
0296         reg = readl_relaxed(S5P_CLK_DIV2);
0297         reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
0298         reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
0299             (3 << S5P_CLKDIV2_MFC_SHIFT);
0300         writel_relaxed(reg, S5P_CLK_DIV2);
0301 
0302         /* For MFC, G3D dividing */
0303         do {
0304             reg = readl_relaxed(S5P_CLKDIV_STAT0);
0305         } while (reg & ((1 << 16) | (1 << 17)));
0306 
0307         /*
0308          * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX
0309          * (200/4=50)->(667/4=166)Mhz
0310          */
0311         reg = readl_relaxed(S5P_CLK_SRC2);
0312         reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
0313         reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
0314             (1 << S5P_CLKSRC2_MFC_SHIFT);
0315         writel_relaxed(reg, S5P_CLK_SRC2);
0316 
0317         do {
0318             reg = readl_relaxed(S5P_CLKMUX_STAT1);
0319         } while (reg & ((1 << 7) | (1 << 3)));
0320 
0321         /*
0322          * 3. DMC1 refresh count for 133Mhz if (index == L4) is
0323          * true refresh counter is already programmed in upper
0324          * code. 0x287@83Mhz
0325          */
0326         if (!bus_speed_changing)
0327             s5pv210_set_refresh(DMC1, 133000);
0328 
0329         /* 4. SCLKAPLL -> SCLKMPLL */
0330         reg = readl_relaxed(S5P_CLK_SRC0);
0331         reg &= ~(S5P_CLKSRC0_MUX200_MASK);
0332         reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
0333         writel_relaxed(reg, S5P_CLK_SRC0);
0334 
0335         do {
0336             reg = readl_relaxed(S5P_CLKMUX_STAT0);
0337         } while (reg & (0x1 << 18));
0338 
0339     }
0340 
0341     /* Change divider */
0342     reg = readl_relaxed(S5P_CLK_DIV0);
0343 
0344     reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK |
0345         S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK |
0346         S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK |
0347         S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
0348 
0349     reg |= ((clkdiv_val[index][0] << S5P_CLKDIV0_APLL_SHIFT) |
0350         (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT) |
0351         (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT) |
0352         (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT) |
0353         (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT) |
0354         (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT) |
0355         (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) |
0356         (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
0357 
0358     writel_relaxed(reg, S5P_CLK_DIV0);
0359 
0360     do {
0361         reg = readl_relaxed(S5P_CLKDIV_STAT0);
0362     } while (reg & 0xff);
0363 
0364     /* ARM MCS value changed */
0365     reg = readl_relaxed(S5P_ARM_MCS_CON);
0366     reg &= ~0x3;
0367     if (index >= L3)
0368         reg |= 0x3;
0369     else
0370         reg |= 0x1;
0371 
0372     writel_relaxed(reg, S5P_ARM_MCS_CON);
0373 
0374     if (pll_changing) {
0375         /* 5. Set Lock time = 30us*24Mhz = 0x2cf */
0376         writel_relaxed(0x2cf, S5P_APLL_LOCK);
0377 
0378         /*
0379          * 6. Turn on APLL
0380          * 6-1. Set PMS values
0381          * 6-2. Wait until the PLL is locked
0382          */
0383         if (index == L0)
0384             writel_relaxed(APLL_VAL_1000, S5P_APLL_CON);
0385         else
0386             writel_relaxed(APLL_VAL_800, S5P_APLL_CON);
0387 
0388         do {
0389             reg = readl_relaxed(S5P_APLL_CON);
0390         } while (!(reg & (0x1 << 29)));
0391 
0392         /*
0393          * 7. Change source clock from SCLKMPLL(667Mhz)
0394          * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX
0395          * (667/4=166)->(200/4=50)Mhz
0396          */
0397         reg = readl_relaxed(S5P_CLK_SRC2);
0398         reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
0399         reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) |
0400             (0 << S5P_CLKSRC2_MFC_SHIFT);
0401         writel_relaxed(reg, S5P_CLK_SRC2);
0402 
0403         do {
0404             reg = readl_relaxed(S5P_CLKMUX_STAT1);
0405         } while (reg & ((1 << 7) | (1 << 3)));
0406 
0407         /*
0408          * 8. Change divider for MFC and G3D
0409          * (200/4=50)->(200/1=200)Mhz
0410          */
0411         reg = readl_relaxed(S5P_CLK_DIV2);
0412         reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
0413         reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
0414             (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
0415         writel_relaxed(reg, S5P_CLK_DIV2);
0416 
0417         /* For MFC, G3D dividing */
0418         do {
0419             reg = readl_relaxed(S5P_CLKDIV_STAT0);
0420         } while (reg & ((1 << 16) | (1 << 17)));
0421 
0422         /* 9. Change MPLL to APLL in MSYS_MUX */
0423         reg = readl_relaxed(S5P_CLK_SRC0);
0424         reg &= ~(S5P_CLKSRC0_MUX200_MASK);
0425         reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
0426         writel_relaxed(reg, S5P_CLK_SRC0);
0427 
0428         do {
0429             reg = readl_relaxed(S5P_CLKMUX_STAT0);
0430         } while (reg & (0x1 << 18));
0431 
0432         /*
0433          * 10. DMC1 refresh counter
0434          * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c
0435          * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618
0436          */
0437         if (!bus_speed_changing)
0438             s5pv210_set_refresh(DMC1, 200000);
0439     }
0440 
0441     /*
0442      * L4 level needs to change memory bus speed, hence ONEDRAM clock
0443      * divider and memory refresh parameter should be changed
0444      */
0445     if (bus_speed_changing) {
0446         reg = readl_relaxed(S5P_CLK_DIV6);
0447         reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
0448         reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
0449         writel_relaxed(reg, S5P_CLK_DIV6);
0450 
0451         do {
0452             reg = readl_relaxed(S5P_CLKDIV_STAT1);
0453         } while (reg & (1 << 15));
0454 
0455         /* Reconfigure DRAM refresh counter value */
0456         if (index != L4) {
0457             /*
0458              * DMC0 : 166Mhz
0459              * DMC1 : 200Mhz
0460              */
0461             s5pv210_set_refresh(DMC0, 166000);
0462             s5pv210_set_refresh(DMC1, 200000);
0463         } else {
0464             /*
0465              * DMC0 : 83Mhz
0466              * DMC1 : 100Mhz
0467              */
0468             s5pv210_set_refresh(DMC0, 83000);
0469             s5pv210_set_refresh(DMC1, 100000);
0470         }
0471     }
0472 
0473     if (new_freq < old_freq) {
0474         regulator_set_voltage(int_regulator,
0475                 int_volt, int_volt_max);
0476 
0477         regulator_set_voltage(arm_regulator,
0478                 arm_volt, arm_volt_max);
0479     }
0480 
0481     pr_debug("Perf changed[L%d]\n", index);
0482 
0483 exit:
0484     mutex_unlock(&set_freq_lock);
0485     return ret;
0486 }
0487 
0488 static int check_mem_type(void __iomem *dmc_reg)
0489 {
0490     unsigned long val;
0491 
0492     val = readl_relaxed(dmc_reg + 0x4);
0493     val = (val & (0xf << 8));
0494 
0495     return val >> 8;
0496 }
0497 
0498 static int s5pv210_cpu_init(struct cpufreq_policy *policy)
0499 {
0500     unsigned long mem_type;
0501     int ret;
0502 
0503     policy->clk = clk_get(NULL, "armclk");
0504     if (IS_ERR(policy->clk))
0505         return PTR_ERR(policy->clk);
0506 
0507     dmc0_clk = clk_get(NULL, "sclk_dmc0");
0508     if (IS_ERR(dmc0_clk)) {
0509         ret = PTR_ERR(dmc0_clk);
0510         goto out_dmc0;
0511     }
0512 
0513     dmc1_clk = clk_get(NULL, "hclk_msys");
0514     if (IS_ERR(dmc1_clk)) {
0515         ret = PTR_ERR(dmc1_clk);
0516         goto out_dmc1;
0517     }
0518 
0519     if (policy->cpu != 0) {
0520         ret = -EINVAL;
0521         goto out_dmc1;
0522     }
0523 
0524     /*
0525      * check_mem_type : This driver only support LPDDR & LPDDR2.
0526      * other memory type is not supported.
0527      */
0528     mem_type = check_mem_type(dmc_base[0]);
0529 
0530     if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
0531         pr_err("CPUFreq doesn't support this memory type\n");
0532         ret = -EINVAL;
0533         goto out_dmc1;
0534     }
0535 
0536     /* Find current refresh counter and frequency each DMC */
0537     s5pv210_dram_conf[0].refresh = (readl_relaxed(dmc_base[0] + 0x30) * 1000);
0538     s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk);
0539 
0540     s5pv210_dram_conf[1].refresh = (readl_relaxed(dmc_base[1] + 0x30) * 1000);
0541     s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
0542 
0543     policy->suspend_freq = SLEEP_FREQ;
0544     cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
0545     return 0;
0546 
0547 out_dmc1:
0548     clk_put(dmc0_clk);
0549 out_dmc0:
0550     clk_put(policy->clk);
0551     return ret;
0552 }
0553 
0554 static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
0555                          unsigned long event, void *ptr)
0556 {
0557     int ret;
0558     struct cpufreq_policy *policy;
0559 
0560     policy = cpufreq_cpu_get(0);
0561     if (!policy) {
0562         pr_debug("cpufreq: get no policy for cpu0\n");
0563         return NOTIFY_BAD;
0564     }
0565 
0566     ret = cpufreq_driver_target(policy, SLEEP_FREQ, 0);
0567     cpufreq_cpu_put(policy);
0568 
0569     if (ret < 0)
0570         return NOTIFY_BAD;
0571 
0572     no_cpufreq_access = true;
0573     return NOTIFY_DONE;
0574 }
0575 
0576 static struct cpufreq_driver s5pv210_driver = {
0577     .flags      = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0578     .verify     = cpufreq_generic_frequency_table_verify,
0579     .target_index   = s5pv210_target,
0580     .get        = cpufreq_generic_get,
0581     .init       = s5pv210_cpu_init,
0582     .name       = "s5pv210",
0583     .suspend    = cpufreq_generic_suspend,
0584     .resume     = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
0585 };
0586 
0587 static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
0588     .notifier_call = s5pv210_cpufreq_reboot_notifier_event,
0589 };
0590 
0591 static int s5pv210_cpufreq_probe(struct platform_device *pdev)
0592 {
0593     struct device *dev = &pdev->dev;
0594     struct device_node *np;
0595     int id, result = 0;
0596 
0597     /*
0598      * HACK: This is a temporary workaround to get access to clock
0599      * and DMC controller registers directly and remove static mappings
0600      * and dependencies on platform headers. It is necessary to enable
0601      * S5PV210 multi-platform support and will be removed together with
0602      * this whole driver as soon as S5PV210 gets migrated to use
0603      * cpufreq-dt driver.
0604      */
0605     arm_regulator = regulator_get(NULL, "vddarm");
0606     if (IS_ERR(arm_regulator))
0607         return dev_err_probe(dev, PTR_ERR(arm_regulator),
0608                      "failed to get regulator vddarm\n");
0609 
0610     int_regulator = regulator_get(NULL, "vddint");
0611     if (IS_ERR(int_regulator)) {
0612         result = dev_err_probe(dev, PTR_ERR(int_regulator),
0613                        "failed to get regulator vddint\n");
0614         goto err_int_regulator;
0615     }
0616 
0617     np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
0618     if (!np) {
0619         dev_err(dev, "failed to find clock controller DT node\n");
0620         result = -ENODEV;
0621         goto err_clock;
0622     }
0623 
0624     clk_base = of_iomap(np, 0);
0625     of_node_put(np);
0626     if (!clk_base) {
0627         dev_err(dev, "failed to map clock registers\n");
0628         result = -EFAULT;
0629         goto err_clock;
0630     }
0631 
0632     for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") {
0633         id = of_alias_get_id(np, "dmc");
0634         if (id < 0 || id >= ARRAY_SIZE(dmc_base)) {
0635             dev_err(dev, "failed to get alias of dmc node '%pOFn'\n", np);
0636             of_node_put(np);
0637             result = id;
0638             goto err_clk_base;
0639         }
0640 
0641         dmc_base[id] = of_iomap(np, 0);
0642         if (!dmc_base[id]) {
0643             dev_err(dev, "failed to map dmc%d registers\n", id);
0644             of_node_put(np);
0645             result = -EFAULT;
0646             goto err_dmc;
0647         }
0648     }
0649 
0650     for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) {
0651         if (!dmc_base[id]) {
0652             dev_err(dev, "failed to find dmc%d node\n", id);
0653             result = -ENODEV;
0654             goto err_dmc;
0655         }
0656     }
0657 
0658     register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
0659 
0660     return cpufreq_register_driver(&s5pv210_driver);
0661 
0662 err_dmc:
0663     for (id = 0; id < ARRAY_SIZE(dmc_base); ++id)
0664         if (dmc_base[id]) {
0665             iounmap(dmc_base[id]);
0666             dmc_base[id] = NULL;
0667         }
0668 
0669 err_clk_base:
0670     iounmap(clk_base);
0671 
0672 err_clock:
0673     regulator_put(int_regulator);
0674 
0675 err_int_regulator:
0676     regulator_put(arm_regulator);
0677 
0678     return result;
0679 }
0680 
0681 static struct platform_driver s5pv210_cpufreq_platdrv = {
0682     .driver = {
0683         .name   = "s5pv210-cpufreq",
0684     },
0685     .probe = s5pv210_cpufreq_probe,
0686 };
0687 builtin_platform_driver(s5pv210_cpufreq_platdrv);