uboot/drivers/clk/imx/clk-imx8qm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2018 NXP
   4 * Peng Fan <peng.fan@nxp.com>
   5 */
   6
   7#include <common.h>
   8#include <clk-uclass.h>
   9#include <dm.h>
  10#include <asm/arch/sci/sci.h>
  11#include <asm/arch/clock.h>
  12#include <dt-bindings/clock/imx8qm-clock.h>
  13#include <dt-bindings/soc/imx_rsrc.h>
  14#include <misc.h>
  15
  16#include "clk-imx8.h"
  17
  18#if CONFIG_IS_ENABLED(CMD_CLK)
  19struct imx8_clks imx8_clk_names[] = {
  20        { IMX8QM_A53_DIV, "A53_DIV" },
  21        { IMX8QM_UART0_CLK, "UART0" },
  22        { IMX8QM_UART1_CLK, "UART1" },
  23        { IMX8QM_UART2_CLK, "UART2" },
  24        { IMX8QM_UART3_CLK, "UART3" },
  25        { IMX8QM_SDHC0_CLK, "SDHC0" },
  26        { IMX8QM_SDHC1_CLK, "SDHC1" },
  27        { IMX8QM_SDHC2_CLK, "SDHC2" },
  28        { IMX8QM_ENET0_AHB_CLK, "ENET0_AHB" },
  29        { IMX8QM_ENET0_IPG_CLK, "ENET0_IPG" },
  30        { IMX8QM_ENET0_REF_DIV, "ENET0_REF" },
  31        { IMX8QM_ENET0_PTP_CLK, "ENET0_PTP" },
  32        { IMX8QM_ENET1_AHB_CLK, "ENET1_AHB" },
  33        { IMX8QM_ENET1_IPG_CLK, "ENET1_IPG" },
  34        { IMX8QM_ENET1_REF_DIV, "ENET1_REF" },
  35        { IMX8QM_ENET1_PTP_CLK, "ENET1_PTP" },
  36};
  37
  38int num_clks = ARRAY_SIZE(imx8_clk_names);
  39#endif
  40
  41ulong imx8_clk_get_rate(struct clk *clk)
  42{
  43        sc_pm_clk_t pm_clk;
  44        ulong rate;
  45        u16 resource;
  46        int ret;
  47
  48        debug("%s(#%lu)\n", __func__, clk->id);
  49
  50        switch (clk->id) {
  51        case IMX8QM_A53_DIV:
  52                resource = SC_R_A53;
  53                pm_clk = SC_PM_CLK_CPU;
  54                break;
  55        case IMX8QM_I2C0_CLK:
  56                resource = SC_R_I2C_0;
  57                pm_clk = SC_PM_CLK_PER;
  58                break;
  59        case IMX8QM_I2C1_CLK:
  60                resource = SC_R_I2C_1;
  61                pm_clk = SC_PM_CLK_PER;
  62                break;
  63        case IMX8QM_I2C2_CLK:
  64                resource = SC_R_I2C_2;
  65                pm_clk = SC_PM_CLK_PER;
  66                break;
  67        case IMX8QM_I2C3_CLK:
  68                resource = SC_R_I2C_3;
  69                pm_clk = SC_PM_CLK_PER;
  70                break;
  71        case IMX8QM_SDHC0_IPG_CLK:
  72        case IMX8QM_SDHC0_CLK:
  73        case IMX8QM_SDHC0_DIV:
  74                resource = SC_R_SDHC_0;
  75                pm_clk = SC_PM_CLK_PER;
  76                break;
  77        case IMX8QM_SDHC1_IPG_CLK:
  78        case IMX8QM_SDHC1_CLK:
  79        case IMX8QM_SDHC1_DIV:
  80                resource = SC_R_SDHC_1;
  81                pm_clk = SC_PM_CLK_PER;
  82                break;
  83        case IMX8QM_SDHC2_IPG_CLK:
  84        case IMX8QM_SDHC2_CLK:
  85        case IMX8QM_SDHC2_DIV:
  86                resource = SC_R_SDHC_2;
  87                pm_clk = SC_PM_CLK_PER;
  88                break;
  89        case IMX8QM_UART0_IPG_CLK:
  90        case IMX8QM_UART0_CLK:
  91                resource = SC_R_UART_0;
  92                pm_clk = SC_PM_CLK_PER;
  93                break;
  94        case IMX8QM_UART1_CLK:
  95                resource = SC_R_UART_1;
  96                pm_clk = SC_PM_CLK_PER;
  97                break;
  98        case IMX8QM_UART2_CLK:
  99                resource = SC_R_UART_2;
 100                pm_clk = SC_PM_CLK_PER;
 101                break;
 102        case IMX8QM_UART3_CLK:
 103                resource = SC_R_UART_3;
 104                pm_clk = SC_PM_CLK_PER;
 105                break;
 106        case IMX8QM_ENET0_IPG_CLK:
 107        case IMX8QM_ENET0_AHB_CLK:
 108        case IMX8QM_ENET0_REF_DIV:
 109        case IMX8QM_ENET0_PTP_CLK:
 110                resource = SC_R_ENET_0;
 111                pm_clk = SC_PM_CLK_PER;
 112                break;
 113        case IMX8QM_ENET1_IPG_CLK:
 114        case IMX8QM_ENET1_AHB_CLK:
 115        case IMX8QM_ENET1_REF_DIV:
 116        case IMX8QM_ENET1_PTP_CLK:
 117                resource = SC_R_ENET_1;
 118                pm_clk = SC_PM_CLK_PER;
 119                break;
 120        default:
 121                if (clk->id < IMX8QM_UART0_IPG_CLK ||
 122                    clk->id >= IMX8QM_CLK_END) {
 123                        printf("%s(Invalid clk ID #%lu)\n",
 124                               __func__, clk->id);
 125                        return -EINVAL;
 126                }
 127                return -ENOTSUPP;
 128        };
 129
 130        ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
 131                                   (sc_pm_clock_rate_t *)&rate);
 132        if (ret) {
 133                printf("%s err %d\n", __func__, ret);
 134                return ret;
 135        }
 136
 137        return rate;
 138}
 139
 140ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
 141{
 142        sc_pm_clk_t pm_clk;
 143        u32 new_rate = rate;
 144        u16 resource;
 145        int ret;
 146
 147        debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
 148
 149        switch (clk->id) {
 150        case IMX8QM_I2C0_CLK:
 151                resource = SC_R_I2C_0;
 152                pm_clk = SC_PM_CLK_PER;
 153                break;
 154        case IMX8QM_I2C1_CLK:
 155                resource = SC_R_I2C_1;
 156                pm_clk = SC_PM_CLK_PER;
 157                break;
 158        case IMX8QM_I2C2_CLK:
 159                resource = SC_R_I2C_2;
 160                pm_clk = SC_PM_CLK_PER;
 161                break;
 162        case IMX8QM_I2C3_CLK:
 163                resource = SC_R_I2C_3;
 164                pm_clk = SC_PM_CLK_PER;
 165                break;
 166        case IMX8QM_UART0_CLK:
 167                resource = SC_R_UART_0;
 168                pm_clk = SC_PM_CLK_PER;
 169                break;
 170        case IMX8QM_UART1_CLK:
 171                resource = SC_R_UART_1;
 172                pm_clk = SC_PM_CLK_PER;
 173                break;
 174        case IMX8QM_UART2_CLK:
 175                resource = SC_R_UART_2;
 176                pm_clk = SC_PM_CLK_PER;
 177                break;
 178        case IMX8QM_UART3_CLK:
 179                resource = SC_R_UART_3;
 180                pm_clk = SC_PM_CLK_PER;
 181                break;
 182        case IMX8QM_SDHC0_IPG_CLK:
 183        case IMX8QM_SDHC0_CLK:
 184        case IMX8QM_SDHC0_DIV:
 185                resource = SC_R_SDHC_0;
 186                pm_clk = SC_PM_CLK_PER;
 187                break;
 188        case IMX8QM_SDHC1_IPG_CLK:
 189        case IMX8QM_SDHC1_CLK:
 190        case IMX8QM_SDHC1_DIV:
 191                resource = SC_R_SDHC_1;
 192                pm_clk = SC_PM_CLK_PER;
 193                break;
 194        case IMX8QM_SDHC2_IPG_CLK:
 195        case IMX8QM_SDHC2_CLK:
 196        case IMX8QM_SDHC2_DIV:
 197                resource = SC_R_SDHC_2;
 198                pm_clk = SC_PM_CLK_PER;
 199                break;
 200        case IMX8QM_ENET0_IPG_CLK:
 201        case IMX8QM_ENET0_AHB_CLK:
 202        case IMX8QM_ENET0_REF_DIV:
 203        case IMX8QM_ENET0_PTP_CLK:
 204        case IMX8QM_ENET0_ROOT_DIV:
 205                resource = SC_R_ENET_0;
 206                pm_clk = SC_PM_CLK_PER;
 207                break;
 208        case IMX8QM_ENET1_IPG_CLK:
 209        case IMX8QM_ENET1_AHB_CLK:
 210        case IMX8QM_ENET1_REF_DIV:
 211        case IMX8QM_ENET1_PTP_CLK:
 212        case IMX8QM_ENET1_ROOT_DIV:
 213                resource = SC_R_ENET_1;
 214                pm_clk = SC_PM_CLK_PER;
 215                break;
 216        default:
 217                if (clk->id < IMX8QM_UART0_IPG_CLK ||
 218                    clk->id >= IMX8QM_CLK_END) {
 219                        printf("%s(Invalid clk ID #%lu)\n",
 220                               __func__, clk->id);
 221                        return -EINVAL;
 222                }
 223                return -ENOTSUPP;
 224        };
 225
 226        ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
 227        if (ret) {
 228                printf("%s err %d\n", __func__, ret);
 229                return ret;
 230        }
 231
 232        return new_rate;
 233}
 234
 235int __imx8_clk_enable(struct clk *clk, bool enable)
 236{
 237        sc_pm_clk_t pm_clk;
 238        u16 resource;
 239        int ret;
 240
 241        debug("%s(#%lu)\n", __func__, clk->id);
 242
 243        switch (clk->id) {
 244        case IMX8QM_I2C0_CLK:
 245                resource = SC_R_I2C_0;
 246                pm_clk = SC_PM_CLK_PER;
 247                break;
 248        case IMX8QM_I2C1_CLK:
 249                resource = SC_R_I2C_1;
 250                pm_clk = SC_PM_CLK_PER;
 251                break;
 252        case IMX8QM_I2C2_CLK:
 253                resource = SC_R_I2C_2;
 254                pm_clk = SC_PM_CLK_PER;
 255                break;
 256        case IMX8QM_I2C3_CLK:
 257                resource = SC_R_I2C_3;
 258                pm_clk = SC_PM_CLK_PER;
 259                break;
 260        case IMX8QM_UART0_CLK:
 261                resource = SC_R_UART_0;
 262                pm_clk = SC_PM_CLK_PER;
 263                break;
 264        case IMX8QM_UART1_CLK:
 265                resource = SC_R_UART_1;
 266                pm_clk = SC_PM_CLK_PER;
 267                break;
 268        case IMX8QM_UART2_CLK:
 269                resource = SC_R_UART_2;
 270                pm_clk = SC_PM_CLK_PER;
 271                break;
 272        case IMX8QM_UART3_CLK:
 273                resource = SC_R_UART_3;
 274                pm_clk = SC_PM_CLK_PER;
 275                break;
 276        case IMX8QM_SDHC0_IPG_CLK:
 277        case IMX8QM_SDHC0_CLK:
 278        case IMX8QM_SDHC0_DIV:
 279                resource = SC_R_SDHC_0;
 280                pm_clk = SC_PM_CLK_PER;
 281                break;
 282        case IMX8QM_SDHC1_IPG_CLK:
 283        case IMX8QM_SDHC1_CLK:
 284        case IMX8QM_SDHC1_DIV:
 285                resource = SC_R_SDHC_1;
 286                pm_clk = SC_PM_CLK_PER;
 287                break;
 288        case IMX8QM_SDHC2_IPG_CLK:
 289        case IMX8QM_SDHC2_CLK:
 290        case IMX8QM_SDHC2_DIV:
 291                resource = SC_R_SDHC_2;
 292                pm_clk = SC_PM_CLK_PER;
 293                break;
 294        case IMX8QM_ENET0_IPG_CLK:
 295        case IMX8QM_ENET0_AHB_CLK:
 296        case IMX8QM_ENET0_REF_DIV:
 297        case IMX8QM_ENET0_PTP_CLK:
 298                resource = SC_R_ENET_0;
 299                pm_clk = SC_PM_CLK_PER;
 300                break;
 301        case IMX8QM_ENET1_IPG_CLK:
 302        case IMX8QM_ENET1_AHB_CLK:
 303        case IMX8QM_ENET1_REF_DIV:
 304        case IMX8QM_ENET1_PTP_CLK:
 305                resource = SC_R_ENET_1;
 306                pm_clk = SC_PM_CLK_PER;
 307                break;
 308        default:
 309                if (clk->id < IMX8QM_UART0_IPG_CLK ||
 310                    clk->id >= IMX8QM_CLK_END) {
 311                        printf("%s(Invalid clk ID #%lu)\n",
 312                               __func__, clk->id);
 313                        return -EINVAL;
 314                }
 315                return -ENOTSUPP;
 316        }
 317
 318        ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
 319        if (ret) {
 320                printf("%s err %d\n", __func__, ret);
 321                return ret;
 322        }
 323
 324        return 0;
 325}
 326